68 lines
2.2 KiB
JavaScript
68 lines
2.2 KiB
JavaScript
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { extname, join, normalize } from "node:path";
|
|
|
|
const root = new URL("../dist/", import.meta.url);
|
|
const rootPath = root.pathname;
|
|
|
|
function walk(directory) {
|
|
return readdirSync(directory).flatMap((name) => {
|
|
const path = join(directory, name);
|
|
return statSync(path).isDirectory() ? walk(path) : [path];
|
|
});
|
|
}
|
|
|
|
function routeFile(pathname) {
|
|
const clean = decodeURIComponent(pathname).replace(/^\/+/, "");
|
|
if (!clean) return join(rootPath, "index.html");
|
|
const local = normalize(join(rootPath, clean));
|
|
if (!local.startsWith(normalize(rootPath))) return null;
|
|
if (extname(local)) return local;
|
|
return join(local, "index.html");
|
|
}
|
|
|
|
if (!existsSync(rootPath)) {
|
|
console.error("dist/ 不存在;请先运行 npm run build。");
|
|
process.exit(1);
|
|
}
|
|
|
|
const htmlFiles = walk(rootPath).filter((file) => file.endsWith(".html"));
|
|
const anchors = new Map();
|
|
for (const file of htmlFiles) {
|
|
const html = readFileSync(file, "utf8");
|
|
anchors.set(file, new Set([...html.matchAll(/\sid=["']([^"']+)["']/g)].map((match) => match[1])));
|
|
}
|
|
|
|
let references = 0;
|
|
let anchorReferences = 0;
|
|
const failures = [];
|
|
|
|
for (const source of htmlFiles) {
|
|
const html = readFileSync(source, "utf8");
|
|
const hrefs = [...html.matchAll(/\shref=["']([^"']+)["']/g)].map((match) => match[1]);
|
|
for (const href of hrefs) {
|
|
if (!href.startsWith("/") || href.startsWith("//")) continue;
|
|
references += 1;
|
|
const url = new URL(href, "https://llm-atlas.local");
|
|
const target = routeFile(url.pathname);
|
|
if (!target || !existsSync(target)) {
|
|
failures.push(`${source.replace(rootPath, "/")} → ${href}(目标不存在)`);
|
|
continue;
|
|
}
|
|
if (url.hash) {
|
|
anchorReferences += 1;
|
|
const id = decodeURIComponent(url.hash.slice(1));
|
|
if (!anchors.get(target)?.has(id)) {
|
|
failures.push(`${source.replace(rootPath, "/")} → ${href}(锚点不存在)`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
`${htmlFiles.length} 个页面,${references} 个站内引用,${anchorReferences} 个跨页锚点,${failures.length} 个失败。`,
|
|
);
|
|
if (failures.length) {
|
|
failures.forEach((failure) => console.error(`- ${failure}`));
|
|
process.exit(1);
|
|
}
|