vite-plugin-vitepress-auto-sidebar-whp98
Version:
The vite plugin that automatically generates sidebar data by scanning directories, based on vitepress
171 lines (167 loc) • 4.84 kB
JavaScript
import { join } from 'path';
import { readdirSync, statSync, existsSync, readFileSync } from 'fs';
import c from 'picocolors';
const DEFAULT_IGNORE_FOLDER = ["scripts", "components", "assets", ".vitepress"];
function log(...info) {
console.log(c.bold(c.cyan("[auto-sidebar]")), ...info);
}
function removePrefix(str, identifier) {
return str.replace(identifier, "");
}
let option;
function getTitleFromFile(realFileName) {
if (!existsSync(realFileName)) {
return void 0;
}
const fileExtension = realFileName.substring(
realFileName.lastIndexOf(".") + 1
);
if (fileExtension !== "md" && fileExtension !== "MD") {
return void 0;
}
const data = readFileSync(realFileName, { encoding: "utf-8" });
const lines = data.split(/\r?\n/);
for (let index = 0; index < lines.length; index++) {
const line = lines[index];
if (line.includes("# ")) {
return line.replace("# ", "");
}
}
return void 0;
}
function createSideBarItems(targetPath, ...reset) {
const {
ignoreIndexItem,
deletePrefix,
collapsed = false,
sideBarItemsResolved,
beforeCreateSideBarItems,
ignoreList = [],
titleFromFile = false
} = option;
const rawNode = readdirSync(join(targetPath, ...reset));
const node = beforeCreateSideBarItems?.(rawNode) ?? rawNode;
const currentDir = join(targetPath, ...reset);
if (ignoreIndexItem && node.length === 1 && node[0] === "index.md") {
return [];
}
const result = [];
for (const fname of node) {
if (statSync(join(targetPath, ...reset, fname)).isDirectory()) {
if (ignoreList.includes(fname)) {
continue;
}
const items = createSideBarItems(join(targetPath), ...reset, fname);
let text = fname;
if (titleFromFile) {
const title1 = getTitleFromFile(join(currentDir, fname, "index.md"));
const title2 = getTitleFromFile(join(currentDir, fname, "index.MD"));
const title3 = getTitleFromFile(join(currentDir, fname, fname + ".md"));
if (title1) {
text = title1;
} else if (title2) {
text = title2;
} else if (title3) {
text = title3;
}
}
if (deletePrefix) {
text = removePrefix(text, deletePrefix);
}
if (items.length > 0) {
const sidebarItem = {
text,
items
};
sidebarItem.collapsed = collapsed;
result.push(sidebarItem);
}
} else {
if (ignoreIndexItem && fname === "index.md" || /^-.*\.(md|MD)$/.test(fname)) {
continue;
}
const fileName = fname.replace(/\.md$/, "");
let text = fileName;
if (deletePrefix) {
text = removePrefix(text, deletePrefix);
}
const realFileName = join(currentDir, fname);
if (titleFromFile) {
const title = getTitleFromFile(realFileName);
if (title) {
text = title;
}
}
const item = {
text,
link: "/" + [...reset, `${fileName}.html`].join("/")
};
result.push(item);
}
}
return sideBarItemsResolved?.(result) ?? result;
}
function createSideBarGroups(targetPath, folder) {
return [
{
items: createSideBarItems(targetPath, folder)
}
];
}
function createSidebarMulti(path) {
const {
ignoreList = [],
ignoreIndexItem = false,
sideBarResolved
} = option;
const il = [...DEFAULT_IGNORE_FOLDER, ...ignoreList];
const data = {};
const node = readdirSync(path).filter(
(n) => statSync(join(path, n)).isDirectory() && !il.includes(n)
);
for (const k of node) {
data[`/${k}/`] = createSideBarGroups(path, k);
}
if (ignoreIndexItem) {
for (const i in data) {
let obj = data[i];
obj = obj.filter((i2) => i2.items != null && i2.items.length > 0);
if (obj.length === 0) {
Reflect.deleteProperty(data, i);
}
}
}
return sideBarResolved?.(data) ?? data;
}
function VitePluginVitePressAutoSidebar(opt = {}) {
return {
name: "vite-plugin-vitepress-auto-sidebar",
configureServer({
watcher,
restart
}) {
const fsWatcher = watcher.add("*.md");
fsWatcher.on("all", async (event, path) => {
if (event !== "change") {
log(`${event} ${path}`);
try {
await restart();
log("update sidebar...");
} catch {
log(`${event} ${path}`);
log("update sidebar failed");
}
}
});
},
config(config) {
option = opt;
const { path = "/docs" } = option;
const docsPath = join(process.cwd(), path);
config.vitepress.site.themeConfig.sidebar = createSidebarMulti(docsPath);
log("injected sidebar data successfully");
return config;
}
};
}
export { VitePluginVitePressAutoSidebar as default };