mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 13:51:33 +00:00
* docs: generate docs map at publish time * fix: canonicalize Docker pack entry path * fix: preserve package lifecycle ownership
149 lines
4.8 KiB
TypeScript
149 lines
4.8 KiB
TypeScript
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import { renderDocsHeadingMap } from "../../scripts/docs-list.js";
|
|
import {
|
|
composeDocsConfig,
|
|
parseArgs,
|
|
reportOrphanLocaleDocs,
|
|
writePublishedDocsMap,
|
|
} from "../../scripts/docs-sync-publish.mjs";
|
|
|
|
function collectPages(entry: unknown, pages: string[] = []): string[] {
|
|
if (typeof entry === "string") {
|
|
pages.push(entry);
|
|
return pages;
|
|
}
|
|
if (Array.isArray(entry)) {
|
|
for (const item of entry) {
|
|
collectPages(item, pages);
|
|
}
|
|
return pages;
|
|
}
|
|
if (!entry || typeof entry !== "object") {
|
|
return pages;
|
|
}
|
|
const record = entry as Record<string, unknown>;
|
|
if (typeof record.page === "string") {
|
|
pages.push(record.page);
|
|
}
|
|
collectPages(record.pages, pages);
|
|
collectPages(record.groups, pages);
|
|
collectPages(record.tabs, pages);
|
|
return pages;
|
|
}
|
|
|
|
describe("docs-sync-publish", () => {
|
|
it("materializes the public docs map only in the publish tree", () => {
|
|
const targetDocsDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-docs-map-publish-"));
|
|
try {
|
|
const outputPath = writePublishedDocsMap(targetDocsDir);
|
|
expect(fs.readFileSync(outputPath, "utf8")).toBe(
|
|
renderDocsHeadingMap(path.resolve(import.meta.dirname, "../../docs")),
|
|
);
|
|
} finally {
|
|
fs.rmSync(targetDocsDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("parses docs sync provenance args", () => {
|
|
expect(
|
|
parseArgs([
|
|
"--target",
|
|
"generated-docs",
|
|
"--source-repo",
|
|
"openclaw/openclaw",
|
|
"--source-sha",
|
|
"abc123",
|
|
"--clawhub-repo",
|
|
"../clawhub",
|
|
"--clawhub-source-repo",
|
|
"openclaw/clawhub",
|
|
"--clawhub-source-sha",
|
|
"def456",
|
|
]),
|
|
).toMatchObject({
|
|
clawhubRepo: "../clawhub",
|
|
clawhubSourceRepo: "openclaw/clawhub",
|
|
clawhubSourceSha: "def456",
|
|
sourceRepo: "openclaw/openclaw",
|
|
sourceSha: "abc123",
|
|
target: "generated-docs",
|
|
});
|
|
});
|
|
|
|
it("rejects missing docs sync option values", () => {
|
|
for (const flag of [
|
|
"--target",
|
|
"--source-repo",
|
|
"--source-sha",
|
|
"--clawhub-repo",
|
|
"--clawhub-source-repo",
|
|
"--clawhub-source-sha",
|
|
]) {
|
|
expect(() => parseArgs([flag])).toThrow(`${flag} requires a value`);
|
|
expect(() => parseArgs([flag, "--target", "generated-docs"])).toThrow(
|
|
`${flag} requires a value`,
|
|
);
|
|
expect(() => parseArgs([flag, "-h"])).toThrow(`${flag} requires a value`);
|
|
}
|
|
});
|
|
|
|
it("defers orphan locale deletion to translation finalization", () => {
|
|
const docsDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-docs-sync-"));
|
|
const mirroredEnglish = path.join(docsDir, "clawhub", "api.md");
|
|
const localizedMirror = path.join(docsDir, "de", "clawhub", "api.md");
|
|
const orphan = path.join(docsDir, "de", "removed.md");
|
|
|
|
fs.mkdirSync(path.dirname(mirroredEnglish), { recursive: true });
|
|
fs.mkdirSync(path.dirname(localizedMirror), { recursive: true });
|
|
fs.writeFileSync(mirroredEnglish, "# ClawHub API\n");
|
|
fs.writeFileSync(localizedMirror, "# ClawHub-API\n");
|
|
fs.writeFileSync(orphan, "# Removed\n");
|
|
|
|
try {
|
|
expect(reportOrphanLocaleDocs(docsDir)).toBe(1);
|
|
expect(fs.existsSync(localizedMirror)).toBe(true);
|
|
expect(fs.existsSync(orphan)).toBe(true);
|
|
} finally {
|
|
fs.rmSync(docsDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("keeps generated locale navigation aligned with English routes", () => {
|
|
const config = composeDocsConfig() as {
|
|
navigation: {
|
|
languages: Array<{
|
|
language: string;
|
|
tabs: Array<{ tab: string; groups?: Array<{ group: string }> }>;
|
|
}>;
|
|
};
|
|
};
|
|
const english = config.navigation.languages.find((entry) => entry.language === "en");
|
|
const simplifiedChinese = config.navigation.languages.find(
|
|
(entry) => entry.language === "zh-Hans",
|
|
);
|
|
const german = config.navigation.languages.find((entry) => entry.language === "de");
|
|
|
|
expect(english).toBeDefined();
|
|
expect(simplifiedChinese).toBeDefined();
|
|
expect(german).toBeDefined();
|
|
|
|
const englishWithoutClawHub = {
|
|
...english,
|
|
tabs: english!.tabs.filter((tab) => tab.tab !== "ClawHub"),
|
|
};
|
|
const expectedZhPages = collectPages(englishWithoutClawHub)
|
|
.map((page) => `zh-CN/${page}`)
|
|
.toSorted();
|
|
expect(collectPages(simplifiedChinese).toSorted()).toEqual(expectedZhPages);
|
|
expect(simplifiedChinese!.tabs[0]?.tab).toBe("快速开始");
|
|
expect(simplifiedChinese!.tabs[0]?.groups?.[0]?.group).toBe("首页");
|
|
|
|
expect(collectPages(german)).toHaveLength(collectPages(englishWithoutClawHub).length);
|
|
expect(german!.tabs[0]?.tab).toBe("Loslegen");
|
|
expect(german!.tabs[0]?.groups?.[0]?.group).toBe("Überblick");
|
|
});
|
|
});
|