import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') const EXCLUDE_DIRS = new Set([ 'node_modules', '.vitepress', 'server', 'assets', 'images', '.git', '金瓶梅', '黄帝内经', '健康学习到150岁 - 人体系统调优不完全指南', '梅花', ]) type SidebarItem = { text: string link?: string collapsed?: boolean items?: SidebarItem[] } function naturalCompare(a: string, b: string) { return a.localeCompare(b, 'zh-CN', { numeric: true, sensitivity: 'base' }) } function titleFromFilename(name: string) { const base = name.replace(/\.md$/i, '') if (/^readme$/i.test(base)) return '导读' return base } function toLink(relativePath: string) { const normalized = relativePath.replace(/\\/g, '/').replace(/\.md$/i, '') if (normalized.endsWith('/README')) { return `/${normalized.slice(0, -'/README'.length)}/` } return `/${normalized}` } function collectItems(dir: string, relativeDir: string): SidebarItem[] { const entries = fs.readdirSync(dir, { withFileTypes: true }) const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith('.md')) const subdirs = entries.filter((entry) => entry.isDirectory()) const items: SidebarItem[] = files .sort((a, b) => naturalCompare(a.name, b.name)) .map((file) => ({ text: titleFromFilename(file.name), link: toLink(path.join(relativeDir, file.name)), })) for (const subdir of subdirs.sort((a, b) => naturalCompare(a.name, b.name))) { const subRelative = path.join(relativeDir, subdir.name) const subItems = collectItems(path.join(dir, subdir.name), subRelative) if (subItems.length === 0) continue items.push({ text: subdir.name, collapsed: true, items: subItems, }) } return items } export function generateSidebar(): Record { const groups: SidebarItem[] = [] const rootFiles = fs .readdirSync(root, { withFileTypes: true }) .filter( (entry) => entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'README.md' && entry.name !== 'index.md', ) .sort((a, b) => naturalCompare(a.name, b.name)) if (rootFiles.length > 0) { groups.push({ text: '典籍', collapsed: false, items: rootFiles.map((file) => ({ text: titleFromFilename(file.name), link: toLink(file.name), })), }) } const dirs = fs .readdirSync(root, { withFileTypes: true }) .filter((entry) => entry.isDirectory() && !EXCLUDE_DIRS.has(entry.name)) .sort((a, b) => naturalCompare(a.name, b.name)) for (const dir of dirs) { const items = collectItems(path.join(root, dir.name), dir.name) if (items.length === 0) continue groups.push({ text: dir.name, collapsed: false, items, }) } return { '/': groups } }