302 lines
9.4 KiB
TypeScript
302 lines
9.4 KiB
TypeScript
#!/usr/bin/env node
|
|
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { glob } from 'glob';
|
|
|
|
interface VerificationResult {
|
|
check: string;
|
|
status: 'PASS' | 'FAIL' | 'WARN';
|
|
message: string;
|
|
details?: any;
|
|
}
|
|
|
|
class IntegrityVerifier {
|
|
private vezaDocsRoot: string;
|
|
private results: VerificationResult[] = [];
|
|
|
|
constructor(vezaDocsRoot: string) {
|
|
this.vezaDocsRoot = vezaDocsRoot;
|
|
}
|
|
|
|
async verifyAll(): Promise<void> {
|
|
console.log('🔍 Vérification de l\'intégrité de la documentation...');
|
|
|
|
await this.verifyBuild();
|
|
await this.verifySidebars();
|
|
await this.verifyLinks();
|
|
await this.verifySearch();
|
|
await this.verifySitemap();
|
|
|
|
this.generateReport();
|
|
}
|
|
|
|
private async verifyBuild(): Promise<void> {
|
|
console.log('📦 Vérification du build...');
|
|
|
|
try {
|
|
const buildDir = path.join(this.vezaDocsRoot, 'build');
|
|
if (fs.existsSync(buildDir)) {
|
|
this.results.push({
|
|
check: 'Build Docusaurus',
|
|
status: 'PASS',
|
|
message: 'Build réussi, dossier build/ existe'
|
|
});
|
|
} else {
|
|
this.results.push({
|
|
check: 'Build Docusaurus',
|
|
status: 'FAIL',
|
|
message: 'Build échoué, dossier build/ manquant'
|
|
});
|
|
}
|
|
} catch (error) {
|
|
this.results.push({
|
|
check: 'Build Docusaurus',
|
|
status: 'FAIL',
|
|
message: `Erreur lors de la vérification du build: ${error}`
|
|
});
|
|
}
|
|
}
|
|
|
|
private async verifySidebars(): Promise<void> {
|
|
console.log('📋 Vérification des sidebars...');
|
|
|
|
const tracks = ['current', 'vision'];
|
|
let allPagesReferenced = true;
|
|
const unreferencedPages: string[] = [];
|
|
|
|
for (const track of tracks) {
|
|
const sidebarPath = path.join(this.vezaDocsRoot, track, 'sidebars.js');
|
|
|
|
if (!fs.existsSync(sidebarPath)) {
|
|
this.results.push({
|
|
check: `Sidebar ${track}`,
|
|
status: 'FAIL',
|
|
message: `Fichier sidebars.js manquant pour ${track}`
|
|
});
|
|
continue;
|
|
}
|
|
|
|
// Lire le contenu du sidebar
|
|
const sidebarContent = fs.readFileSync(sidebarPath, 'utf-8');
|
|
|
|
// Trouver toutes les pages dans le track
|
|
const pagesPattern = `${track}/**/*.md`;
|
|
const pages = await glob(pagesPattern, { cwd: this.vezaDocsRoot });
|
|
|
|
// Vérifier que chaque page est référencée dans le sidebar
|
|
for (const page of pages) {
|
|
const pageId = path.basename(page, '.md');
|
|
if (!sidebarContent.includes(`'${pageId}'`) && !sidebarContent.includes(`"${pageId}"`)) {
|
|
unreferencedPages.push(page);
|
|
allPagesReferenced = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (allPagesReferenced) {
|
|
this.results.push({
|
|
check: 'Couverture des sidebars',
|
|
status: 'PASS',
|
|
message: 'Toutes les pages sont référencées dans les sidebars'
|
|
});
|
|
} else {
|
|
this.results.push({
|
|
check: 'Couverture des sidebars',
|
|
status: 'WARN',
|
|
message: `${unreferencedPages.length} pages non référencées dans les sidebars`,
|
|
details: unreferencedPages
|
|
});
|
|
}
|
|
}
|
|
|
|
private async verifyLinks(): Promise<void> {
|
|
console.log('🔗 Vérification des liens...');
|
|
|
|
const buildDir = path.join(this.vezaDocsRoot, 'build');
|
|
if (!fs.existsSync(buildDir)) {
|
|
this.results.push({
|
|
check: 'Vérification des liens',
|
|
status: 'FAIL',
|
|
message: 'Impossible de vérifier les liens, build manquant'
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Compter les fichiers HTML générés
|
|
const htmlFiles = await glob('**/*.html', { cwd: buildDir });
|
|
|
|
this.results.push({
|
|
check: 'Génération des pages',
|
|
status: 'PASS',
|
|
message: `${htmlFiles.length} pages HTML générées`,
|
|
details: { htmlFiles: htmlFiles.length }
|
|
});
|
|
|
|
// Vérifier la présence des pages principales
|
|
const mainPages = [
|
|
'current/overview/index.html',
|
|
'vision/overview/index.html'
|
|
];
|
|
|
|
const missingPages = mainPages.filter(page => !fs.existsSync(path.join(buildDir, page)));
|
|
|
|
if (missingPages.length === 0) {
|
|
this.results.push({
|
|
check: 'Pages principales',
|
|
status: 'PASS',
|
|
message: 'Toutes les pages principales sont présentes'
|
|
});
|
|
} else {
|
|
this.results.push({
|
|
check: 'Pages principales',
|
|
status: 'FAIL',
|
|
message: `Pages manquantes: ${missingPages.join(', ')}`
|
|
});
|
|
}
|
|
}
|
|
|
|
private async verifySearch(): Promise<void> {
|
|
console.log('🔍 Vérification de la recherche...');
|
|
|
|
const buildDir = path.join(this.vezaDocsRoot, 'build');
|
|
const searchIndexPath = path.join(buildDir, 'search-index.json');
|
|
|
|
if (fs.existsSync(searchIndexPath)) {
|
|
const searchIndex = JSON.parse(fs.readFileSync(searchIndexPath, 'utf-8'));
|
|
const indexedPages = searchIndex.length || 0;
|
|
|
|
this.results.push({
|
|
check: 'Index de recherche',
|
|
status: 'PASS',
|
|
message: `${indexedPages} pages indexées pour la recherche`,
|
|
details: { indexedPages }
|
|
});
|
|
} else {
|
|
this.results.push({
|
|
check: 'Index de recherche',
|
|
status: 'WARN',
|
|
message: 'Index de recherche manquant (recherche locale non configurée)'
|
|
});
|
|
}
|
|
}
|
|
|
|
private async verifySitemap(): Promise<void> {
|
|
console.log('🗺️ Vérification du sitemap...');
|
|
|
|
const buildDir = path.join(this.vezaDocsRoot, 'build');
|
|
const sitemapPath = path.join(buildDir, 'sitemap.xml');
|
|
|
|
if (fs.existsSync(sitemapPath)) {
|
|
const sitemapContent = fs.readFileSync(sitemapPath, 'utf-8');
|
|
const urlCount = (sitemapContent.match(/<url>/g) || []).length;
|
|
|
|
this.results.push({
|
|
check: 'Sitemap',
|
|
status: 'PASS',
|
|
message: `Sitemap généré avec ${urlCount} URLs`,
|
|
details: { urlCount }
|
|
});
|
|
} else {
|
|
this.results.push({
|
|
check: 'Sitemap',
|
|
status: 'WARN',
|
|
message: 'Sitemap manquant'
|
|
});
|
|
}
|
|
}
|
|
|
|
private generateReport(): void {
|
|
console.log('📊 Génération du rapport de vérification...');
|
|
|
|
const reportsDir = path.join(this.vezaDocsRoot, '_reports');
|
|
if (!fs.existsSync(reportsDir)) {
|
|
fs.mkdirSync(reportsDir, { recursive: true });
|
|
}
|
|
|
|
// Rapport Markdown
|
|
let md = `# 🔍 Rapport de Vérification - Documentation Veza\n\n`;
|
|
md += `**Date** : ${new Date().toLocaleDateString('fr-FR')}\n\n`;
|
|
|
|
// Résumé
|
|
const passCount = this.results.filter(r => r.status === 'PASS').length;
|
|
const failCount = this.results.filter(r => r.status === 'FAIL').length;
|
|
const warnCount = this.results.filter(r => r.status === 'WARN').length;
|
|
|
|
md += `## 📈 Résumé\n\n`;
|
|
md += `- ✅ **Succès** : ${passCount}\n`;
|
|
md += `- ❌ **Échecs** : ${failCount}\n`;
|
|
md += `- ⚠️ **Avertissements** : ${warnCount}\n\n`;
|
|
|
|
// Détail des vérifications
|
|
md += `## 🔍 Détail des Vérifications\n\n`;
|
|
md += `| Vérification | Statut | Message |\n`;
|
|
md += `|--------------|--------|----------|\n`;
|
|
|
|
this.results.forEach(result => {
|
|
const statusIcon = result.status === 'PASS' ? '✅' : result.status === 'FAIL' ? '❌' : '⚠️';
|
|
md += `| ${result.check} | ${statusIcon} ${result.status} | ${result.message} |\n`;
|
|
});
|
|
|
|
md += `\n## 📋 Critères de Prêt au Nettoyage\n\n`;
|
|
|
|
const isReadyForCleanup = failCount === 0 && warnCount <= 2;
|
|
md += `- **Build réussi** : ${this.results.find(r => r.check === 'Build Docusaurus')?.status === 'PASS' ? '✅' : '❌'}\n`;
|
|
md += `- **Liens fonctionnels** : ${this.results.find(r => r.check === 'Vérification des liens')?.status === 'PASS' ? '✅' : '❌'}\n`;
|
|
md += `- **Sidebars complets** : ${this.results.find(r => r.check === 'Couverture des sidebars')?.status === 'PASS' ? '✅' : '⚠️'}\n`;
|
|
md += `- **Pages principales** : ${this.results.find(r => r.check === 'Pages principales')?.status === 'PASS' ? '✅' : '❌'}\n\n`;
|
|
|
|
if (isReadyForCleanup) {
|
|
md += `## ✅ **PRÊT POUR LE NETTOYAGE**\n\n`;
|
|
md += `Tous les critères sont respectés. Le nettoyage des anciens dossiers peut être effectué en toute sécurité.\n`;
|
|
} else {
|
|
md += `## ❌ **NON PRÊT POUR LE NETTOYAGE**\n\n`;
|
|
md += `Des problèmes doivent être résolus avant de procéder au nettoyage.\n`;
|
|
}
|
|
|
|
fs.writeFileSync(
|
|
path.join(reportsDir, 'verification_summary.md'),
|
|
md
|
|
);
|
|
|
|
// Rapport JSON
|
|
const jsonReport = {
|
|
scanDate: new Date().toISOString(),
|
|
summary: {
|
|
pass: passCount,
|
|
fail: failCount,
|
|
warn: warnCount,
|
|
total: this.results.length
|
|
},
|
|
isReadyForCleanup,
|
|
results: this.results
|
|
};
|
|
|
|
fs.writeFileSync(
|
|
path.join(reportsDir, 'verification_summary.json'),
|
|
JSON.stringify(jsonReport, null, 2)
|
|
);
|
|
|
|
console.log('✅ Rapport de vérification généré');
|
|
console.log(`📊 Résumé: ${passCount} ✅, ${failCount} ❌, ${warnCount} ⚠️`);
|
|
console.log(`🧹 Prêt pour le nettoyage: ${isReadyForCleanup ? 'OUI' : 'NON'}`);
|
|
}
|
|
|
|
async run(): Promise<void> {
|
|
try {
|
|
await this.verifyAll();
|
|
} catch (error) {
|
|
console.error('❌ Erreur lors de la vérification:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Exécution du script
|
|
if (require.main === module) {
|
|
const vezaDocsRoot = process.argv[2] || path.join(__dirname, '..');
|
|
const verifier = new IntegrityVerifier(vezaDocsRoot);
|
|
verifier.run();
|
|
}
|
|
|
|
export { IntegrityVerifier };
|