Files
rea/scripts/lib/docs-facts.mjs
T
Matheus BreguêzandCodex ea504fac97 docs: organize canonical documentation layout (URGENTE)
Group all existing authored guides by domain and ownership, expose complete navigation, and preserve their public routes. Update physical path consumers and release configuration while retaining historical records. Document domain-based specs and ADR slugs without global numbering.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-12 18:44:55 -03:00

143 lines
4.8 KiB
JavaScript

import { readFile, readdir, stat } from "node:fs/promises";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
const readmeLinkTargets = (content, language = "en") =>
[...content.matchAll(/\]\(([^)\s]+)\)/gu)]
.map((match) => match[1] ?? "")
.filter(
(target) =>
!target.startsWith("#") &&
!/^README(?:_[A-Za-z0-9-]+)?\.md$/u.test(target),
)
.map((target) => {
if (language === "en" || !URL.canParse(target)) return target;
const url = new URL(target);
const prefix = `/${language}/`;
if (
url.origin !== "https://rea.tools" ||
!url.pathname.startsWith(prefix)
)
return target;
url.pathname = url.pathname.slice(prefix.length - 1);
return url.href;
})
.sort();
const requireText = (issues, path, content, expected) => {
if (!content.includes(expected)) issues.push(`${path}: missing ${expected}`);
};
/** Check that local Markdown references travel with an installed skill bundle. */
export const skillReferenceIssues = async (skillRoot) => {
const issues = [];
const paths = (await readdir(skillRoot, { recursive: true }))
.filter((path) => path.endsWith(".md"))
.sort();
for (const path of paths) {
const content = await readFile(join(skillRoot, path), "utf8");
for (const match of content.matchAll(/\[[^\]\n]*\]\(([^)\s]+)\)/gu)) {
const destination = match[1];
if (/^(?:https?:\/\/|mailto:|#)/u.test(destination)) continue;
const target = resolve(
dirname(join(skillRoot, path)),
destination.split("#")[0],
);
const withinBundle = relative(resolve(skillRoot), target);
if (
withinBundle === ".." ||
withinBundle.startsWith(`..${sep}`) ||
isAbsolute(withinBundle)
) {
issues.push(
`${path}: reference escapes installed skill bundle: ${destination}`,
);
continue;
}
try {
if (!(await stat(target)).isFile())
issues.push(`${path}: reference is not a file: ${destination}`);
} catch (cause) {
if (cause?.code !== "ENOENT") throw cause;
issues.push(`${path}: missing skill reference: ${destination}`);
}
}
}
return issues;
};
/** Return every caller-visible documentation mismatch against canonical facts. */
export const documentationFactIssues = async (root, catalog) => {
const issues = await skillReferenceIssues(
join(root, "skills/reverse-engineer-anything"),
);
const readmePaths = (await readdir(root))
.filter((path) => /^README(?:_[A-Za-z0-9-]+)?\.md$/u.test(path))
.sort();
const readmes = new Map();
for (const path of readmePaths) {
const content = await readFile(join(root, path), "utf8");
readmes.set(path, content);
requireText(issues, path, content, "MCP-tool_catalog");
if (path === "README.md") {
requireText(
issues,
path,
content,
"(docs/getting-started/installation.md#supported-agents)",
);
requireText(
issues,
path,
content,
"(docs/getting-started/installation.md#mcp-registry)",
);
requireText(
issues,
path,
content,
"(docs/reference/mcp-contracts.md#generated-catalog)",
);
}
}
const canonicalLinks = readmeLinkTargets(readmes.get("README.md") ?? "");
const languageInventory = JSON.parse(
await readFile(join(root, "website/locales/languages.json"), "utf8"),
);
const readmeLanguages = new Map(
languageInventory.map(({ readme, code }) => [readme, code]),
);
for (const path of readmePaths.filter((path) => path !== "README.md"))
if (
JSON.stringify(
readmeLinkTargets(readmes.get(path) ?? "", readmeLanguages.get(path)),
) !== JSON.stringify(canonicalLinks)
)
issues.push(`${path}: documentation links differ from README.md`);
const installationPath = "docs/getting-started/installation.md";
const installation = await readFile(join(root, installationPath), "utf8");
for (const client of catalog.setup_clients)
requireText(issues, installationPath, installation, client.display_name);
const agents = await readFile(join(root, "AGENTS.md"), "utf8");
requireText(issues, "AGENTS.md", agents, "docs/public/product-catalog.json");
const templatePath = ".github/pull_request_template.md";
const template = await readFile(join(root, templatePath), "utf8");
requireText(
issues,
templatePath,
template,
"docs/public/product-catalog.json",
);
return issues;
};
/** Fail once with all documentation fact mismatches. */
export const assertDocumentationFacts = async (root, catalog) => {
const issues = await documentationFactIssues(root, catalog);
if (issues.length > 0)
throw new Error(`Documentation facts drifted:\n- ${issues.join("\n- ")}`);
};