#!/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 { 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 { 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 { 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 { 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 { 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 { 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(//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 { 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 };