198 lines
5.4 KiB
TypeScript
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 };
|