docs: fix English link audits (#57039)

Merged via squash.

Prepared head SHA: d20a3b620f
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
This commit is contained in:
Radek Sienkiewicz
2026-03-30 01:21:00 +02:00
committed by GitHub
parent 6c91b27756
commit 4680335b2a
14 changed files with 301 additions and 45 deletions

View File

@@ -1,22 +1,33 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
const { normalizeRoute, resolveRoute, runDocsLinkAuditCli } =
(await import("../../scripts/docs-link-audit.mjs")) as unknown as {
normalizeRoute: (route: string) => string;
resolveRoute: (
route: string,
options?: { redirects?: Map<string, string>; routes?: Set<string> },
) => { ok: boolean; terminal: string; loop?: boolean };
runDocsLinkAuditCli: (options?: {
args?: string[];
spawnSyncImpl?: (
command: string,
args: string[],
options: { cwd: string; stdio: string },
) => { status: number | null; error?: { code?: string } };
}) => number;
};
const {
normalizeRoute,
prepareAnchorAuditDocsDir,
resolveRoute,
runDocsLinkAuditCli,
sanitizeDocsConfigForEnglishOnly,
} = (await import("../../scripts/docs-link-audit.mjs")) as unknown as {
normalizeRoute: (route: string) => string;
prepareAnchorAuditDocsDir: (sourceDir?: string) => string;
resolveRoute: (
route: string,
options?: { redirects?: Map<string, string>; routes?: Set<string> },
) => { ok: boolean; terminal: string; loop?: boolean };
runDocsLinkAuditCli: (options?: {
args?: string[];
spawnSyncImpl?: (
command: string,
args: string[],
options: { cwd: string; stdio: string },
) => { status: number | null; error?: { code?: string } };
prepareAnchorAuditDocsDirImpl?: (sourceDir?: string) => string;
cleanupAnchorAuditDocsDirImpl?: (dir: string) => void;
}) => number;
sanitizeDocsConfigForEnglishOnly: (value: unknown) => unknown;
};
describe("docs-link-audit", () => {
it("normalizes route fragments away", () => {
@@ -38,6 +49,101 @@ describe("docs-link-audit", () => {
});
});
it("sanitizes docs.json to English-only route targets", () => {
expect(
sanitizeDocsConfigForEnglishOnly({
navigation: [
{
language: "en",
tabs: [
{
tab: "Docs",
groups: [
{
group: "Keep",
pages: ["help/testing", "zh-CN/help/testing", "ja-JP/help/testing"],
},
],
},
],
},
{
language: "zh-Hans",
tabs: [{ tab: "中文", groups: [{ group: "帮助", pages: ["zh-CN/help/testing"] }] }],
},
],
redirects: [
{ source: "/help/testing", destination: "/help/testing" },
{ source: "/zh-CN/help/testing", destination: "/help/testing" },
{ source: "/help/testing", destination: "/ja-JP/help/testing" },
],
}),
).toEqual({
navigation: [
{
language: "en",
tabs: [
{
tab: "Docs",
groups: [{ group: "Keep", pages: ["help/testing"] }],
},
],
},
],
redirects: [{ source: "/help/testing", destination: "/help/testing" }],
});
});
it("builds an English-only docs tree for anchor audits", () => {
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "docs-link-audit-fixture-"));
const docsRoot = path.join(fixtureRoot, "docs");
fs.mkdirSync(path.join(docsRoot, "help"), { recursive: true });
fs.mkdirSync(path.join(docsRoot, "zh-CN", "help"), { recursive: true });
fs.writeFileSync(
path.join(docsRoot, "docs.json"),
`${JSON.stringify(
{
navigation: [
{
language: "en",
tabs: [{ tab: "Docs", groups: [{ group: "Help", pages: ["help/testing"] }] }],
},
{
language: "zh-Hans",
tabs: [{ tab: "中文", groups: [{ group: "帮助", pages: ["zh-CN/help/testing"] }] }],
},
],
},
null,
2,
)}\n`,
"utf8",
);
fs.writeFileSync(path.join(docsRoot, "help", "testing.md"), "# testing\n", "utf8");
fs.writeFileSync(path.join(docsRoot, "zh-CN", "help", "testing.md"), "# 测试\n", "utf8");
const anchorDocsDir = prepareAnchorAuditDocsDir(docsRoot);
try {
expect(fs.existsSync(path.join(anchorDocsDir, "help", "testing.md"))).toBe(true);
expect(fs.existsSync(path.join(anchorDocsDir, "zh-CN"))).toBe(false);
const sanitizedDocsJson = JSON.parse(
fs.readFileSync(path.join(anchorDocsDir, "docs.json"), "utf8"),
);
expect(sanitizedDocsJson).toEqual({
navigation: [
{
language: "en",
tabs: [{ tab: "Docs", groups: [{ group: "Help", pages: ["help/testing"] }] }],
},
],
});
} finally {
fs.rmSync(anchorDocsDir, { recursive: true, force: true });
fs.rmSync(fixtureRoot, { recursive: true, force: true });
}
});
it("prefers a local mint binary for anchor validation", () => {
let invocation:
| {
@@ -46,9 +152,17 @@ describe("docs-link-audit", () => {
options: { cwd: string; stdio: string };
}
| undefined;
let cleanedDir: string | undefined;
const anchorDocsDir = path.join(os.tmpdir(), "docs-link-audit-anchor");
const exitCode = runDocsLinkAuditCli({
args: ["--anchors"],
prepareAnchorAuditDocsDirImpl() {
return anchorDocsDir;
},
cleanupAnchorAuditDocsDirImpl(dir) {
cleanedDir = dir;
},
spawnSyncImpl(command, args, options) {
invocation = { command, args, options };
return { status: 0 };
@@ -60,7 +174,8 @@ describe("docs-link-audit", () => {
expect(invocation?.command).toBe("mint");
expect(invocation?.args).toEqual(["broken-links", "--check-anchors"]);
expect(invocation?.options.stdio).toBe("inherit");
expect(path.basename(invocation?.options.cwd ?? "")).toBe("docs");
expect(invocation?.options.cwd).toBe(anchorDocsDir);
expect(cleanedDir).toBe(anchorDocsDir);
});
it("falls back to pnpm dlx when mint is not on PATH", () => {
@@ -69,9 +184,17 @@ describe("docs-link-audit", () => {
args: string[];
options: { cwd: string; stdio: string };
}> = [];
let cleanedDir: string | undefined;
const anchorDocsDir = path.join(os.tmpdir(), "docs-link-audit-anchor");
const exitCode = runDocsLinkAuditCli({
args: ["--anchors"],
prepareAnchorAuditDocsDirImpl() {
return anchorDocsDir;
},
cleanupAnchorAuditDocsDirImpl(dir) {
cleanedDir = dir;
},
spawnSyncImpl(command, args, options) {
invocations.push({ command, args, options });
if (command === "mint") {
@@ -93,7 +216,8 @@ describe("docs-link-audit", () => {
args: ["dlx", "mint", "broken-links", "--check-anchors"],
options: { stdio: "inherit" },
});
expect(path.basename(invocations[0]?.options.cwd ?? "")).toBe("docs");
expect(path.basename(invocations[1]?.options.cwd ?? "")).toBe("docs");
expect(invocations[0]?.options.cwd).toBe(anchorDocsDir);
expect(invocations[1]?.options.cwd).toBe(anchorDocsDir);
expect(cleanedDir).toBe(anchorDocsDir);
});
});