Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | 1x 7x 1x 3x 3x 1x 2x 1x 1x 1x 2x 2x 1x 1x 1x 1x 1x 5x 8x 8x 4x 4x 4x 4x 5x 1x 2x 1x 1x 1x 4x 4x 1x 3x 3x 3x 3x 1x 1x 1x | import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
/** Absolute package root for Vite's local-link filesystem allowlist. */
export const arraiThemeRoot = fileURLToPath(new URL("..", import.meta.url));
const toPosixPath = (value) => value.split(path.sep).join("/");
const routeFromRelativePath = (relativePath) => {
const normalized = toPosixPath(relativePath);
if (normalized === "index.md") {
return "/";
}
if (normalized.endsWith("/index.md")) {
return `/${normalized.slice(0, -"index.md".length)}`.replace(/\/$/, "") || "/";
}
return `/${normalized.replace(/\.md$/, "")}`;
};
const frontmatterTitle = (source) => {
const frontmatter = source.match(/^---\r?\n([\s\S]*?)\r?\n---/);
if (!frontmatter) {
return null;
}
const title = frontmatter[1].match(/^title:\s*["']?(.+?)["']?\s*$/m);
return title?.[1] || null;
};
const headingTitle = (source) => source.match(/^#\s+(.+?)\s*$/m)?.[1] || null;
const walkMarkdown = (directory, found = []) => {
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
const absolutePath = path.join(directory, entry.name);
if (entry.isDirectory()) {
Eif (entry.name !== ".vitepress" && entry.name !== "node_modules") {
walkMarkdown(absolutePath, found);
}
} else Eif (entry.name.endsWith(".md")) {
found.push(absolutePath);
}
}
return found;
};
/**
* Index Markdown pages for breadcrumb labels and safe links.
*
* Virtual routes can label structural segments that have no page. They are
* non-linking by default, which prevents breadcrumb links to missing indexes.
*
* @param {object} options - Index options.
* @param {string} options.docsRoot - Absolute VitePress source directory.
* @param {(relativePath: string) => boolean} [options.exclude] - Page exclusion predicate.
* @param {(page: object) => string | null} [options.getTitle] - Custom page-title resolver.
* @param {object} [options.virtualRoutes] - Additional structural route labels.
* @returns {object} Route metadata for `themeConfig.breadcrumbs.routes`.
*/
export const buildBreadcrumbRoutes = ({ docsRoot, exclude = () => false, getTitle, virtualRoutes = {} }) => {
if (!path.isAbsolute(docsRoot)) {
throw new TypeError("docsRoot must be an absolute path.");
}
const routes = {};
for (const filePath of walkMarkdown(docsRoot)) {
const relativePath = toPosixPath(path.relative(docsRoot, filePath));
if (exclude(relativePath)) {
continue;
}
const source = fs.readFileSync(filePath, "utf8");
const route = routeFromRelativePath(relativePath);
const fallback = path.basename(filePath, ".md");
routes[route] = {
text:
getTitle?.({ filePath, relativePath, route, source }) ||
frontmatterTitle(source) ||
headingTitle(source) ||
fallback,
link: true,
};
}
for (const [route, entry] of Object.entries(virtualRoutes)) {
routes[route] = typeof entry === "string" ? { text: entry, link: false } : { link: false, ...entry };
}
return routes;
};
|