@limy-org/vite-plugin-vitepress-auto-sidebar
Version:
Automatically generate VitePress sidebar
100 lines (97 loc) • 2.74 kB
JavaScript
import glob from 'glob';
import fs from 'fs';
import path from 'path';
const titleCache = {};
function VitePluginAutoSidebar(options = {}) {
const root = options.root || process.cwd();
return {
name: "VitePluginAutoSidebar",
config(config) {
config.vitepress.site.themeConfig.sidebar = getSidebarConfig(
root,
options
);
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 = "/" + path.relative(root, filePath);
if (!route || !title)
return;
if (title === titleCache[route])
return;
restart();
return;
}
});
}
};
}
function getSidebarConfig(root, opts) {
const paths = glob.sync("**/*.md", {
cwd: root,
ignore: opts.ignores
});
const obj = {};
const sidebar = {};
for (const path2 of paths) {
const pathSegments = path2.split("/");
if (pathSegments[0].endsWith(".md"))
continue;
const key = "/" + pathSegments[0] + "/";
const data = pathSegments.slice(1);
if (!obj[key]) {
obj[key] = [];
}
obj[key].push(data);
}
for (const key of Object.keys(obj)) {
const data = obj[key];
const result = [];
for (const pathSegments of data) {
let currentLevel = result;
for (const segment of pathSegments) {
let existingPath = currentLevel.find((item) => item.text === segment);
if (!existingPath) {
const itemConfig = {};
if (segment.endsWith(".md")) {
const route = key + pathSegments.join("/");
itemConfig.text = matchTitle(path.join(root, route));
itemConfig.link = route;
titleCache[route] = itemConfig.text;
} else {
itemConfig.text = segment;
itemConfig.collapsed = false;
itemConfig.items = [];
}
currentLevel.push(itemConfig);
existingPath = itemConfig;
}
currentLevel = existingPath.items;
}
}
sidebar[key] = result;
}
if (opts.sidebarResolved) {
opts.sidebarResolved(sidebar);
}
return sidebar;
}
function matchTitle(p) {
const content = fs.readFileSync(p, "utf-8");
return ((content.match(/^#(.*)\n?/) || [])[1] || "").trim();
}
export { VitePluginAutoSidebar as default };