Files
2026-07-13 13:39:12 +08:00

90 lines
2.8 KiB
JavaScript

#!/usr/bin/env node
/**
* sync-llm-mirrors.mjs — keep docs/i18n/<locale>/llm.txt in lock-step with
* the root `llm.txt`. The mirrors are strict copies (no translation): they
* preserve the per-locale heading + language bar block they already have at
* the top of the file, then replace everything after the `---` separator with
* the root body (heading stripped).
*
* Usage:
* node scripts/i18n/sync-llm-mirrors.mjs
*
* Idempotent. Safe to run repeatedly. Used after any edit to `llm.txt` to
* keep `npm run check:docs-sync` green.
*/
import { promises as fs } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const ROOT = path.resolve(__dirname, "..", "..");
const I18N_DIR = path.join(ROOT, "docs", "i18n");
const ROOT_LLM = path.join(ROOT, "llm.txt");
const FILE_NAME = "llm.txt";
function stripTopHeading(content) {
return content.replace(/^# .+\r?\n+/, "");
}
async function main() {
const rootText = await fs.readFile(ROOT_LLM, "utf8");
const rootBody = stripTopHeading(rootText).replace(/\r\n/g, "\n");
const entries = await fs.readdir(I18N_DIR, { withFileTypes: true });
const locales = entries
.filter((e) => e.isDirectory())
.map((e) => e.name)
.sort();
let updated = 0;
let unchanged = 0;
let missing = 0;
for (const locale of locales) {
const target = path.join(I18N_DIR, locale, FILE_NAME);
let existing;
try {
existing = await fs.readFile(target, "utf8");
} catch {
console.warn(`[sync-llm-mirrors] skip ${locale}: ${FILE_NAME} missing`);
missing += 1;
continue;
}
// The locale header is everything up to and including the first `---`
// separator on its own line. We keep that prefix verbatim and replace
// the rest with the root body.
const sepMatch = existing.match(/^---\s*$/m);
if (!sepMatch || sepMatch.index === undefined) {
console.warn(`[sync-llm-mirrors] skip ${locale}: missing --- separator`);
missing += 1;
continue;
}
const headerEnd = sepMatch.index + sepMatch[0].length;
const header = existing.slice(0, headerEnd).replace(/\r\n/g, "\n");
const trimmedHeader = header.replace(/\n+$/, "");
const next = `${trimmedHeader}\n\n${rootBody.trimStart()}`.replace(/\r\n/g, "\n");
const normalizedExisting = existing.replace(/\r\n/g, "\n");
if (normalizedExisting === next) {
unchanged += 1;
continue;
}
await fs.writeFile(target, next, "utf8");
updated += 1;
console.log(`[sync-llm-mirrors] updated docs/i18n/${locale}/${FILE_NAME}`);
}
console.log(
`[sync-llm-mirrors] done — updated=${updated} unchanged=${unchanged} missing=${missing} (${locales.length} locales)`
);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});