Fork FancyScribe as BrevyScribe with the datasheet transforms built in
CI / check (push) Has been cancelled
CI / check (push) Has been cancelled
Print generic datasheets - every option a unit could take, the way the official cards read - instead of a record of one particular list. The three Python scripts that used to rewrite the .ros file before upload are now transforms in src/transforms/, running in the browser between DOMParser and the roster parser. Most of each script was machinery for preserving the file byte for byte on the way back to disk; in the browser the document is never serialised, so only the domain logic came across. Because they run on the parsed document rather than the uploaded file, flipping a transform off rebuilds from the original XML with no re-upload. Saved rosters therefore hold the raw roster XML rather than the parsed object, under new localStorage keys. The scripts' output over four 11th-edition rosters is checked in as test fixtures, so the port is measured against an independent implementation that was verified by printing the cards; scripts/update-fixtures.mjs refuses to overwrite those without --force. Two parser call sites now use :scope> rather than repeating the scope element's own name, which means the same thing in a browser and also works under jsdom, where the old form matched nothing. Also: served at the root rather than a GitHub Pages subpath, PostHog analytics removed, and deploy/ carries an nginx site for scribe.luxick.de plus an rsync deploy script. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env node
|
||||
//
|
||||
// Write the expected-output fixtures for a roster added to
|
||||
// src/transforms/__fixtures__/.
|
||||
//
|
||||
// node scripts/update-fixtures.mjs # only writes what is missing
|
||||
// node scripts/update-fixtures.mjs --force # re-baselines everything
|
||||
//
|
||||
// Drop a new `<name>.ros` in that directory and run this to generate the four
|
||||
// `<name>.{merge,strip,convert,all}.ros` files the test suite compares against.
|
||||
// Read the diff before committing: this records whatever the transforms do
|
||||
// today, so it cannot tell a fix from a regression.
|
||||
//
|
||||
// Existing fixtures are left alone unless --force is given, and that guard is
|
||||
// the point rather than a convenience. The fixtures that came with this repo
|
||||
// were produced by a separate Python implementation and verified by printing
|
||||
// the cards; the test suite is worth something because it checks the transforms
|
||||
// against that independent output. Re-baselining a fixture from the JS replaces
|
||||
// it with the very thing under test, and the comparison becomes a tautology
|
||||
// that passes no matter what the code does.
|
||||
|
||||
import { readFileSync, readdirSync, existsSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { JSDOM } from "jsdom";
|
||||
|
||||
import {
|
||||
convertChoiceAbilities,
|
||||
defaultConfig,
|
||||
mergeDuplicateUnits,
|
||||
removeLeaderAbilities,
|
||||
} from "../src/transforms/index.js";
|
||||
|
||||
const FIXTURES = join(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
"..",
|
||||
"src",
|
||||
"transforms",
|
||||
"__fixtures__",
|
||||
);
|
||||
|
||||
const STEPS = {
|
||||
merge: (doc) => mergeDuplicateUnits(doc, defaultConfig),
|
||||
strip: (doc) => removeLeaderAbilities(doc, defaultConfig),
|
||||
convert: (doc) => convertChoiceAbilities(doc, defaultConfig),
|
||||
};
|
||||
|
||||
// Chained, in the order the app runs them; see src/transforms/index.js.
|
||||
const PIPELINE = ["merge", "strip", "convert"];
|
||||
|
||||
const force = process.argv.includes("--force");
|
||||
const { window } = new JSDOM();
|
||||
|
||||
const inputs = readdirSync(FIXTURES)
|
||||
.filter((name) => name.endsWith(".ros") && name.split(".").length === 2)
|
||||
.map((name) => name.replace(/\.ros$/, ""));
|
||||
|
||||
let written = 0;
|
||||
let kept = 0;
|
||||
|
||||
for (const input of inputs) {
|
||||
const xml = readFileSync(join(FIXTURES, `${input}.ros`), "utf8");
|
||||
|
||||
const outputs = { ...STEPS, all: null };
|
||||
for (const label of Object.keys(outputs)) {
|
||||
const path = join(FIXTURES, `${input}.${label}.ros`);
|
||||
if (existsSync(path) && !force) {
|
||||
kept++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const doc = new window.DOMParser().parseFromString(xml, "text/xml");
|
||||
if (label === "all") {
|
||||
for (const step of PIPELINE) STEPS[step](doc);
|
||||
} else {
|
||||
STEPS[label](doc);
|
||||
}
|
||||
|
||||
writeFileSync(path, new window.XMLSerializer().serializeToString(doc), "utf8");
|
||||
console.log(`wrote ${input}.${label}.ros`);
|
||||
written++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n${written} written, ${kept} left alone.`);
|
||||
if (kept > 0 && !force) {
|
||||
console.log("Pass --force to re-baseline the rest, but read the header first.");
|
||||
}
|
||||
Reference in New Issue
Block a user