Files
projectbrain-Public/scripts/check-doc-links.mjs
T

24 lines
1.4 KiB
JavaScript

#!/usr/bin/env node
import { readFile, readdir, stat } from "node:fs/promises";
import { dirname, resolve, relative } from "node:path";
import process from "node:process";
const root = resolve(import.meta.dirname, "..");
const docsRoot = resolve(root, "docs");
const walk = async (directory) => (await Promise.all((await readdir(directory, { withFileTypes: true })).map((entry) => entry.isDirectory() ? walk(resolve(directory, entry.name)) : [resolve(directory, entry.name)]))).flat();
const files = (await walk(docsRoot)).filter((path) => path.endsWith(".md") && !path.includes(`${resolve(docsRoot, "archive")}\\`) && !path.includes(`${resolve(docsRoot, "archive")}/`));
const failures = [];
for (const file of files) {
const source = await readFile(file, "utf8");
const links = [...source.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)].map((match) => match[1].trim().replace(/^<|>$/g, ""));
for (const link of links) {
if (!link || /^(https?:|mailto:|#)/i.test(link)) continue;
const targetPart = decodeURIComponent(link.split("#")[0]);
if (!targetPart) continue;
const target = resolve(dirname(file), targetPart);
try { await stat(target); } catch { failures.push(`${relative(root, file)} -> ${link}`); }
}
}
if (failures.length) { console.error(`Broken active documentation links:\n- ${failures.join("\n- ")}`); process.exit(1); }
console.log(`Documentation link audit passed for ${files.length} active Markdown files.`);