UNPKG

@iminu/vitepress-plugin-auto-sidebar

Version:

Automatically generate VitePress sidebar

116 lines (113 loc) 3.31 kB
import glob from 'glob'; import fs from 'fs'; import path from 'path'; const titleCache = {}; function VitePluginAutoSidebar(options = {}) { const opts = normalizeOptions(options); return { name: "VitePluginAutoSidebar", config(config) { config.vitepress.site.themeConfig.sidebar = getSidebarConfig(opts); return config; }, configureServer: ({ watcher, restart }) => { const fsWatcher = watcher.add("*.md"); fsWatcher.on("all", (event, filePath) => { if (event === "addDir") return; if (event === "unlinkDir") return; if (event == "add") return; if (event === "unlink") { restart(); return; } if (event === "change") { const title = matchTitle(filePath); const route = getRoute(opts.root, filePath); if (!route || !title) return; if (title === titleCache[route]) return; restart(); return; } }); } }; } function getSidebarConfig(opts) { const docsPath = opts.docs; const paths = glob.sync("**/*.md", { cwd: docsPath, ignore: opts.ignores }); const basePath = path.relative(opts.root, docsPath); const sidebar = {}; paths.forEach((fullPath) => { const segments = fullPath.split("/"); const absolutePath = path.resolve(docsPath, fullPath); if (segments.length === 0) return; const topLevel = basePath ? `/${basePath}/${segments.shift()}/` : `/${segments.shift()}/`; if (topLevel.endsWith(".md")) return; if (!sidebar[topLevel]) { sidebar[topLevel] = []; } let currentLevel = sidebar[topLevel]; segments.forEach((segment) => { let curConfig = currentLevel.find((item) => item.text === segment); if (!curConfig) { const itemConfig = {}; if (segment.endsWith(".md")) { const route = getRoute(opts.root, absolutePath); itemConfig.text = matchTitle(absolutePath); itemConfig.link = route; titleCache[route] = itemConfig.text; } else { itemConfig.text = segment; itemConfig.collapsed = false; itemConfig.items = []; } currentLevel.push(itemConfig); curConfig = itemConfig; } currentLevel = curConfig.items; }); }); if (opts.sidebarResolved) { opts.sidebarResolved(sidebar); } return sidebar; } function matchTitle(p) { const content = fs.readFileSync(p, "utf-8"); return ((content.match(/^#(.*)\n?/) || [])[1] || "").trim(); } function getRoute(root, absPath) { return "/" + path.relative(root, absPath); } function normalizeOptions(options) { let root = options.root; if (!root) { const files = glob.sync("**/.vitepress/config.*", { cwd: process.cwd(), dot: true, ignore: ["node_modules/**/*"] }); if (files.length !== 1) { console.error("[WARNING] \u627E\u5230\u591A\u4E2A .vitepress/config \u914D\u7F6E\u6587\u4EF6", files); } root = path.resolve(files[0], "../.."); } return { root, docs: options.docs || root, ignores: options.ignores ?? [], sidebarResolved: options.sidebarResolved ?? function() { } }; } export { VitePluginAutoSidebar as default };