fix(docs): validate translated README website destinations
Use the website language inventory when comparing README links. Accept the matching localized page while retaining checks for wrong locales, changed destinations, fragments and query parameters.
This commit is contained in:
parent
d981a58d7f
commit
c9136eef71
|
|
@ -1,7 +1,7 @@
|
|||
import { readFile, readdir, stat } from "node:fs/promises";
|
||||
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
||||
|
||||
const readmeLinkTargets = (content) =>
|
||||
const readmeLinkTargets = (content, language = "en") =>
|
||||
[...content.matchAll(/\]\(([^)\s]+)\)/gu)]
|
||||
.map((match) => match[1] ?? "")
|
||||
.filter(
|
||||
|
|
@ -9,6 +9,18 @@ const readmeLinkTargets = (content) =>
|
|||
!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) => {
|
||||
|
|
@ -83,10 +95,17 @@ export const documentationFactIssues = async (root, 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) ?? "")) !==
|
||||
JSON.stringify(canonicalLinks)
|
||||
JSON.stringify(
|
||||
readmeLinkTargets(readmes.get(path) ?? "", readmeLanguages.get(path)),
|
||||
) !== JSON.stringify(canonicalLinks)
|
||||
)
|
||||
issues.push(`${path}: documentation links differ from README.md`);
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ describe("canonical product catalog drift", () => {
|
|||
"README_ja.md",
|
||||
"README_ko.md",
|
||||
"README_ar.md",
|
||||
"website/locales/languages.json",
|
||||
"docs/installation.md",
|
||||
"AGENTS.md",
|
||||
".github/pull_request_template.md",
|
||||
|
|
@ -187,22 +188,40 @@ describe("canonical product catalog drift", () => {
|
|||
});
|
||||
const translatedPath = join(directory, "README_zh.md");
|
||||
const translated = await readFile(translatedPath, "utf8");
|
||||
await writeFile(
|
||||
translatedPath,
|
||||
translated.replace(
|
||||
const catalog = await createProductCatalog(root);
|
||||
await expect(documentationFactIssues(directory, catalog)).resolves.toEqual(
|
||||
[],
|
||||
);
|
||||
for (const [original, changed] of [
|
||||
[
|
||||
"(docs/installation.md#supported-agents)",
|
||||
"(docs/installation.md#missing-agents)",
|
||||
),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const issues = await documentationFactIssues(
|
||||
directory,
|
||||
await createProductCatalog(root),
|
||||
);
|
||||
expect(issues).toContain(
|
||||
"README_zh.md: documentation links differ from README.md",
|
||||
);
|
||||
],
|
||||
[
|
||||
"https://rea.tools/zh-CN/guides/native/",
|
||||
"https://rea.tools/zh-CN/missing/",
|
||||
],
|
||||
[
|
||||
"https://rea.tools/zh-CN/guides/native/",
|
||||
"https://rea.tools/zh-TW/guides/native/",
|
||||
],
|
||||
[
|
||||
"https://rea.tools/zh-CN/guides/native/",
|
||||
"https://rea.tools/zh-CN/guides/native/?other=1",
|
||||
],
|
||||
]) {
|
||||
expect(translated).toContain(original);
|
||||
await writeFile(
|
||||
translatedPath,
|
||||
translated.replace(original, changed),
|
||||
"utf8",
|
||||
);
|
||||
await expect(
|
||||
documentationFactIssues(directory, catalog),
|
||||
).resolves.toEqual([
|
||||
"README_zh.md: documentation links differ from README.md",
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it("fails check mode without rewriting a stale generated artifact", async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue