@iminu/vitepress-plugin-auto-sidebar
Version:
Automatically generate VitePress sidebar
124 lines (118 loc) • 3.69 kB
JavaScript
;
const glob = require('glob');
const fs = require('fs');
const path = require('path');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const glob__default = /*#__PURE__*/_interopDefaultCompat(glob);
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
const path__default = /*#__PURE__*/_interopDefaultCompat(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__default.sync("**/*.md", {
cwd: docsPath,
ignore: opts.ignores
});
const basePath = path__default.relative(opts.root, docsPath);
const sidebar = {};
paths.forEach((fullPath) => {
const segments = fullPath.split("/");
const absolutePath = path__default.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__default.readFileSync(p, "utf-8");
return ((content.match(/^#(.*)\n?/) || [])[1] || "").trim();
}
function getRoute(root, absPath) {
return "/" + path__default.relative(root, absPath);
}
function normalizeOptions(options) {
let root = options.root;
if (!root) {
const files = glob__default.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__default.resolve(files[0], "../..");
}
return {
root,
docs: options.docs || root,
ignores: options.ignores ?? [],
sidebarResolved: options.sidebarResolved ?? function() {
}
};
}
module.exports = VitePluginAutoSidebar;