veza/veza-docs/scripts/build_sidebars.ts

198 lines
5.4 KiB
TypeScript

#!/usr/bin/env node
import * as fs from 'fs';
import * as path from 'path';
import { glob } from 'glob';
interface SidebarItem {
type: 'doc' | 'category';
id?: string;
label?: string;
items?: SidebarItem[];
}
interface SidebarConfig {
[key: string]: SidebarItem[];
}
class SidebarBuilder {
private docsRoot: string;
private domainOrder = ['overview', 'product', 'backend', 'frontend', 'rust', 'infra', 'security', 'ops', 'legal', 'misc'];
constructor(docsRoot: string) {
this.docsRoot = docsRoot;
}
async buildSidebars(): Promise<void> {
console.log('📚 Génération des sidebars...');
await this.buildSidebar('current');
await this.buildSidebar('vision');
console.log('✅ Sidebars générés avec succès!');
}
private async buildSidebar(track: 'current' | 'vision'): Promise<void> {
const trackPath = path.join(this.docsRoot, track);
const sidebarPath = path.join(trackPath, 'sidebars.js');
console.log(`📖 Génération de la sidebar pour ${track}...`);
const sidebar: SidebarItem[] = [];
// Ajouter la page overview
const overviewPath = path.join(trackPath, 'overview.md');
if (fs.existsSync(overviewPath)) {
sidebar.push({
type: 'doc',
id: 'overview'
});
}
// Parcourir les domaines
for (const domain of this.domainOrder) {
const domainPath = path.join(trackPath, 'domains', domain);
if (fs.existsSync(domainPath)) {
const domainItems = await this.buildDomainSidebar(domainPath, domain);
if (domainItems.length > 0) {
sidebar.push({
type: 'category',
label: this.getDomainLabel(domain),
items: domainItems
});
}
}
}
// Générer le contenu JavaScript
const sidebarContent = this.generateSidebarContent(sidebar, track);
fs.writeFileSync(sidebarPath, sidebarContent);
console.log(`✅ Sidebar ${track} générée: ${sidebarPath}`);
}
private async buildDomainSidebar(domainPath: string, domain: string): Promise<SidebarItem[]> {
const items: SidebarItem[] = [];
// Chercher tous les fichiers .md et .mdx
const patterns = ['*.md', '*.mdx'];
const allFiles: string[] = [];
for (const pattern of patterns) {
const files = await glob(pattern, { cwd: domainPath });
allFiles.push(...files);
}
// Trier les fichiers
allFiles.sort((a, b) => {
// Mettre les fichiers README en premier
if (a.toLowerCase().includes('readme')) return -1;
if (b.toLowerCase().includes('readme')) return 1;
// Puis trier alphabétiquement
return a.localeCompare(b);
});
// Créer les items de sidebar
for (const file of allFiles) {
const filePath = path.join(domainPath, file);
const content = fs.readFileSync(filePath, 'utf-8');
const frontmatter = this.extractFrontmatter(content);
const slug = path.basename(file, path.extname(file));
items.push({
type: 'doc',
id: `${domain}/${slug}`,
label: frontmatter.sidebar_label || frontmatter.title || this.generateLabelFromFilename(file)
});
}
return items;
}
private extractFrontmatter(content: string): Record<string, any> {
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
const match = content.match(frontmatterRegex);
if (!match) return {};
const frontmatterText = match[1];
const frontmatter: Record<string, any> = {};
frontmatterText.split('\n').forEach(line => {
const [key, ...valueParts] = line.split(':');
if (key && valueParts.length > 0) {
const value = valueParts.join(':').trim();
frontmatter[key.trim()] = value.replace(/^["']|["']$/g, '');
}
});
return frontmatter;
}
private generateLabelFromFilename(filename: string): string {
const baseName = path.basename(filename, path.extname(filename));
return baseName
.replace(/[-_]/g, ' ')
.replace(/\b\w/g, l => l.toUpperCase());
}
private getDomainLabel(domain: string): string {
const labels: Record<string, string> = {
'overview': '📋 Aperçu',
'product': '🎯 Produit',
'backend': '⚙️ Backend',
'frontend': '🎨 Frontend',
'rust': '🦀 Rust',
'infra': '🏗️ Infrastructure',
'security': '🔒 Sécurité',
'ops': '🔧 Opérations',
'legal': '📜 Légal',
'misc': '📁 Divers'
};
return labels[domain] || domain;
}
private generateSidebarContent(sidebar: SidebarItem[], track: string): string {
const sidebarJson = JSON.stringify(sidebar, null, 2);
return `/**
* @type {import('@docusaurus/plugin-content-docs').SidebarsConfig}
* Sidebar généré automatiquement pour ${track}
*
* Généré le: ${new Date().toISOString()}
*/
const sidebars = {
${track}Sidebar: ${sidebarJson}
};
module.exports = sidebars;
`;
}
async run(): Promise<void> {
console.log('📚 Démarrage de la génération des sidebars...');
try {
await this.buildSidebars();
console.log('✅ Génération des sidebars terminée!');
} catch (error) {
console.error('❌ Erreur lors de la génération des sidebars:', error);
process.exit(1);
}
}
}
// Exécution du script
if (require.main === module) {
const docsRoot = process.argv[2] || path.join(__dirname, '..');
const builder = new SidebarBuilder(docsRoot);
builder.run();
}
export { SidebarBuilder };