Files
RingBRP/tools/update-readme.mjs
T
slaguru666andClaude Opus 5 4ded53f9b5 Fix: npm run build has never worked on Windows
Both spawners built their argument with a file URL's .pathname, which on Windows is
"/C:/Users/...". Node resolves that against the drive root, so the build spawned
"C:\C:\Users\...\check-rules.mjs" and aborted on a module it could not find.

update-readme.mjs had the same bug and swallowed it in a bare catch, so instead of
failing it silently wrote a README whose guard box was empty — "0 guard lines" where
there should be four. A Windows build therefore could not happen, and if it had, it
would have quietly deleted the guard output from the README.

Same root as the packs/ CRLF bug: this repository has only ever been built on macOS and
Linux, where .pathname happens to be a usable path.

Also adds check-creatures to the pre-build guards, which it was missing, so the build
and npm run check now refuse the same things.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 21:15:33 +01:00

72 lines
3.7 KiB
JavaScript

/**
* Rewrite the README's counted sections from the real data.
*
* Those tables have been wrong three times, because a catalogue that grows every
* session and a number typed by hand are not the same kind of thing. A stale count in
* a README is the same defect as a stale comment in the engine: a claim nothing checks.
*
* Only the marked regions are touched; the prose around them is left alone.
*/
import { readFile, writeFile } from "node:fs/promises";
import { execFileSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import { SKILL_CATALOGUE, WEAPONS, ARMOURS, GEAR, VEHICLES, NPCS, TALENTS }
from "./content.mjs";
import { ROLES, TRADES } from "../postings.mjs";
import { ICON_MAP } from "./icons.mjs";
import { RULES_PAGES } from "./rules-text.mjs";
const root = new URL("../", import.meta.url);
const readme = new URL("README.md", root);
let text = await readFile(readme, "utf8");
const items = WEAPONS.length + ARMOURS.length + GEAR.length + VEHICLES.length;
// The guard lines are quoted from the guards themselves rather than paraphrased.
const runGuard = name => {
try {
return execFileSync(process.execPath, [fileURLToPath(new URL(name, import.meta.url))],
{ encoding: "utf8" }).split("\n").find(l => l.startsWith(name.replace(".mjs", "")));
} catch { return null; }
};
const guardLines = ["check-rules.mjs", "check-kits.mjs", "check-lang.mjs",
"check-behaviour.mjs"].map(runGuard).filter(Boolean);
const box = `| | |
|---|---|
| **Postings** | ${Object.keys(ROLES).length}, each with a key characteristic, trained skills, talents and its own kit |
| **Trades** | ${Object.keys(TRADES).length} ordinary jobs the department recruits from, plus induction |
| **Catalogue** | ${items} items — ${GEAR.length} gear, ${WEAPONS.length} weapons, ${ARMOURS.length} armour, ${VEHICLES.length} vehicles |
| **Skills / talents** | ${SKILL_CATALOGUE.length} skills, ${TALENTS.length} talents |
| **Bestiary** | ${NPCS.length} statblocks across folklore, horror and the far side |
| **Eras** | modern, antique, future, anomalous — the agency is old and never abolishes anything |
| **Icons** | ${Object.keys(ICON_MAP).length}, all generated from \`tools/icons.mjs\`; no external art |
| **Starter scenario** | **BLACK PLATFORM**, a six-player action starter, importable as a single Adventure |
| **Compendia** | pregens, NPCs, skills, weapons, armour, gear, vehicles, powers, tables, rules, the starter |
| **Rules journal** | ${RULES_PAGES.length} pages, generated from \`rules.mjs\` so the book cannot drift from the code |`;
const replaceRegion = (src, marker, body) => {
const open = `<!-- ${marker}:start -->`, close = `<!-- ${marker}:end -->`;
const i = src.indexOf(open), j = src.indexOf(close);
if (i < 0 || j < 0) return null;
return src.slice(0, i + open.length) + "\n" + body + "\n" + src.slice(j);
};
// First run: wrap the existing hand-written regions in markers.
if (!text.includes("<!-- box:start -->")) {
text = text.replace(/\| \| \|\n\|---\|---\|\n(?:\|.*\n)+/,
m => `<!-- box:start -->\n${m}<!-- box:end -->\n`);
text = text.replace(/```\ncheck-rules:[\s\S]*?```/,
m => `<!-- guards:start -->\n${m}\n<!-- guards:end -->`);
}
const withBox = replaceRegion(text, "box", box);
if (!withBox) { console.error("update-readme: box markers missing"); process.exit(1); }
const withGuards = replaceRegion(withBox, "guards",
"```\n" + guardLines.join("\n") + "\n```");
if (!withGuards) { console.error("update-readme: guard markers missing"); process.exit(1); }
await writeFile(readme, withGuards, "utf8");
console.log(`update-readme: OK — ${items} items, ${Object.keys(ROLES).length} postings, `
+ `${Object.keys(TRADES).length} trades, ${guardLines.length} guard lines`);