Files
llm-atlas/scripts/check-site.mjs
T
2026-07-28 23:32:14 +08:00

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);
}