import fs from 'fs' import path from 'path' import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const docsDir = path.resolve(__dirname, '../docs') interface SidebarItem { text: string link: string } interface SidebarGroup { text: string items: SidebarItem[] } interface SidebarConfig { [path: string]: SidebarGroup[] } function getTitleFromFile(filePath: string): string { const content = fs.readFileSync(filePath, 'utf-8') const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/) if (frontmatterMatch) { const titleMatch = frontmatterMatch[1].match(/title:\s*["']?([^"'\n]+)["']?/) if (titleMatch) { return titleMatch[1].trim() } } const h1Match = content.match(/^#\s+(.+)$/m) if (h1Match) { return h1Match[1].trim() } return path.basename(filePath, '.md') } function getSidebarOrder(filePath: string, fileName: string): number { if (fileName === 'index.md') { return 0 } const content = fs.readFileSync(filePath, 'utf-8') const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/) if (frontmatterMatch) { const orderMatch = frontmatterMatch[1].match(/sidebarOrder:\s*(\d+)/) if (orderMatch) { return parseInt(orderMatch[1], 10) } } return 999 } function generateSidebar(): SidebarConfig { const sidebar: SidebarConfig = {} const entries = fs.readdirSync(docsDir, { withFileTypes: true }) for (const entry of entries) { if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === '.vitepress') { continue } const dirPath = path.join(docsDir, entry.name) const files = fs.readdirSync(dirPath) .filter(f => f.endsWith('.md')) .map(f => ({ name: f, path: path.join(dirPath, f), order: getSidebarOrder(path.join(dirPath, f), f) })) .sort((a, b) => a.order - b.order) if (files.length === 0) continue const items: SidebarItem[] = files.map(file => { let title = getTitleFromFile(file.path) if (file.name === 'index.md') { title = '概述' } const linkPath = file.name === 'index.md' ? `/${entry.name}/` : `/${entry.name}/${file.name.replace('.md', '')}` return { text: title, link: linkPath } }) const dirName = entry.name.charAt(0).toUpperCase() + entry.name.slice(1) sidebar[`/${entry.name}/`] = [ { text: `${dirName} 笔记`, items } ] } return sidebar } function generateNav(sidebar: SidebarConfig) { return Object.keys(sidebar).map(p => { const name = p.replace(/\//g, '').charAt(0).toUpperCase() + p.replace(/\//g, '').slice(1) return { text: name, link: p } }) } function formatObject(obj: unknown, indent: number = 0): string { const spaces = ' '.repeat(indent) const innerSpaces = ' '.repeat(indent + 2) if (Array.isArray(obj)) { if (obj.length === 0) return '[]' const items = obj.map(item => formatObject(item, indent + 2)) return `[\n${items.map(i => innerSpaces + i).join(',\n')}\n${spaces}]` } if (typeof obj === 'object' && obj !== null) { const entries = Object.entries(obj) if (entries.length === 0) return '{}' const items = entries.map(([key, value]) => { const formattedValue = formatObject(value, indent + 2) return `${innerSpaces}'${key}': ${formattedValue}` }) return `{\n${items.join(',\n')}\n${spaces}}` } if (typeof obj === 'string') { return `'${obj}'` } return String(obj) } function updateConfig() { const sidebar = generateSidebar() const nav = generateNav(sidebar) const configPath = path.resolve(__dirname, '../docs/.vitepress/config.mts') let config = fs.readFileSync(configPath, 'utf-8') const sidebarStr = formatObject(sidebar, 4) const navStr = formatObject(nav, 4) const sidebarRegex = /sidebar:\s*\{\s*\n\s*\}/ const navRegex = /nav:\s*\[\s*\n\s*\]/ config = config.replace(sidebarRegex, `sidebar: ${sidebarStr}`) config = config.replace(navRegex, `nav: ${navStr}`) fs.writeFileSync(configPath, config) console.log('Sidebar config updated:') console.log(JSON.stringify(sidebar, null, 2)) console.log('\nNav config updated:') console.log(JSON.stringify(nav, null, 2)) } updateConfig()