@alpaca-software/40kdc-data 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88,7 +88,8 @@ function genNormalize() {
88
88
  }
89
89
  /** Locate the canonical input for a fixture dir: prefer `input.json` (legacy
90
90
  * ListForge), then `input.newrecruit-json.json` (NewRecruit), then the
91
- * text-only `input.gw.txt` (GW app export import-only, like ListForge). */
91
+ * text-only `input.gw.txt` / `input.listforge-text.txt` (app text exports
92
+ * import-only, like ListForge). */
92
93
  function seedRoster(caseDir, ds) {
93
94
  const decoded = decodeCanonicalSeed(caseDir);
94
95
  return importRoster(decoded, { dataset: ds });
@@ -109,6 +110,10 @@ function decodeCanonicalSeed(caseDir) {
109
110
  if (existsSync(gwSeed)) {
110
111
  return readFileSync(gwSeed, "utf8");
111
112
  }
113
+ const lfTextSeed = join(caseDir, "input.listforge-text.txt");
114
+ if (existsSync(lfTextSeed)) {
115
+ return readFileSync(lfTextSeed, "utf8");
116
+ }
112
117
  throw new Error(`no canonical input found in ${caseDir}`);
113
118
  }
114
119
  /** Run a decoded payload through the adapter pipeline up to (but not past)
@@ -1 +1 @@
1
- {"version":3,"file":"gen-conformance.js","sourceRoot":"","sources":["../src/gen-conformance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generate the cross-implementation conformance corpus under repo-root\n * `conformance/`. The TypeScript package is the reference implementation, so\n * the goldens it emits are what the Rust crate must reproduce byte-for-byte\n * (structurally). Run via `npm run gen:conformance`; CI regenerates and asserts\n * `git diff --exit-code conformance/` is clean.\n *\n * Outputs:\n * - `conformance/normalize.json` — `[{ input, expected }]` for normalizeName.\n * - `conformance/roster/<case>/expected.roster.json` — the resolved Roster.\n * - `conformance/roster/<case>/expected.<fmt>.{txt,json}` — every export\n * target's golden output. The TS exporter is the oracle; the Rust mirror\n * asserts byte-equal output for the same Roster.\n * - `conformance/roster/<case>/input.newrecruit-{wtc-compact,wtc-full,simple}.txt`\n * — text inputs derived from the seed by the exporter, so a re-import\n * regression in either implementation surfaces immediately.\n *\n * Seeding: each `<case>/` carries one canonical input — either the legacy\n * `input.json` (ListForge) or `input.newrecruit-json.json` (NewRecruit). Other\n * inputs are derived.\n */\nimport { readdirSync, readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { Dataset } from \"./data/dataset.js\";\nimport { normalizeName } from \"./data/normalize.js\";\nimport { describeScoringCard, describeAbility, type Effect } from \"./translate/index.js\";\nimport { awardsOf } from \"./scoring/index.js\";\nimport { createRunnerState, dispatch } from \"./runner.js\";\nimport { exportRoster, type ExportFormat } from \"./export/index.js\";\nimport { importRoster, REGISTERED_ADAPTERS } from \"./import/import-roster.js\";\nimport { selectAdapter } from \"./import/adapter.js\";\nimport type { ParsedRoster, Roster } from \"./import/types.js\";\nimport { encodeBase } from \"./runner.js\";\nimport { attributeStages } from \"./cruncher/attribution.js\";\nimport type { EngineInput } from \"./cruncher/index.js\";\nimport {\n resolveLayout,\n type TerrainTemplate as ResolverTemplate,\n type TerrainLayout as ResolverLayout,\n} from \"./terrain/resolve.js\";\nimport { keystoneMeasurements, BOARD_INCHES } from \"./terrain/keystones.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst REPO_ROOT = join(__dirname, \"../..\");\nconst CONFORMANCE = join(REPO_ROOT, \"conformance\");\n\nconst NORMALIZE_INPUTS = [\n // NFD diacritic strip\n \"Khârn the Betrayer\",\n \"Brôkhyr\",\n \"Ûthar\",\n \"Magnús\",\n // apostrophe / quote variants\n \"T'au\",\n \"Be’lakor\",\n \"Kor’sarro Khan\",\n \"Aetaos'rau'keres\",\n \"‘quoted’\",\n // whitespace / hyphen collapse + trim\n \"Brôkhyr Iron-master\",\n \" the betrayer \",\n \"space--marines\",\n // casefold\n \"KHÂRN THE BETRAYER\",\n // already-normalized (idempotence)\n \"kharn the betrayer\",\n // distinctness anchors (must NOT collapse together)\n \"Khorne\",\n \"Khârn\",\n // Unicode whitespace beyond ASCII — every Unicode whitespace must collapse\n // identically across implementations or `find(\"Khorne Lord\")` and\n // `find(\"Khorne Lord\")` will silently disagree across ports.\n \"Khorne Lord\",\n \"Khorne Lord\",\n // Turkish dotted-I: NFD decomposes to `I` + combining dot above; the dot is\n // stripped, then locale-independent lowercase yields `i`. The case pins that\n // no implementation introduces locale-aware casefolding (which would map\n // `I` → `ı` under Turkish locale and break ASCII-text search).\n \"İmperial Fists\",\n // Zero-width joiner: passes through every step today. Pinned so behavior\n // does not silently change — if a future commit strips Cf-category chars,\n // this golden updates in the same PR.\n \"Khorne‍Lord\",\n];\n\nfunction writeJson(path: string, value: unknown): void {\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction writeText(path: string, value: string): void {\n writeFileSync(path, value);\n}\n\nfunction genNormalize(): void {\n const table = NORMALIZE_INPUTS.map((input) => ({ input, expected: normalizeName(input) }));\n writeJson(join(CONFORMANCE, \"normalize.json\"), table);\n console.log(`normalize.json: ${table.length} cases`);\n}\n\n/** Locate the canonical input for a fixture dir: prefer `input.json` (legacy\n * ListForge), then `input.newrecruit-json.json` (NewRecruit), then the\n * text-only `input.gw.txt` (GW app export — import-only, like ListForge). */\nfunction seedRoster(caseDir: string, ds: Dataset): Roster {\n const decoded = decodeCanonicalSeed(caseDir);\n return importRoster(decoded, { dataset: ds });\n}\n\n/** Return the decoded payload for the canonical seed — the same value the\n * import pipeline would dispatch on. JSON seeds come back parsed; text seeds\n * come back as the raw string. */\nfunction decodeCanonicalSeed(caseDir: string): unknown {\n const jsonSeed = join(caseDir, \"input.json\");\n if (existsSync(jsonSeed)) {\n return JSON.parse(readFileSync(jsonSeed, \"utf8\"));\n }\n const nrSeed = join(caseDir, \"input.newrecruit-json.json\");\n if (existsSync(nrSeed)) {\n return JSON.parse(readFileSync(nrSeed, \"utf8\"));\n }\n const gwSeed = join(caseDir, \"input.gw.txt\");\n if (existsSync(gwSeed)) {\n return readFileSync(gwSeed, \"utf8\");\n }\n throw new Error(`no canonical input found in ${caseDir}`);\n}\n\n/** Run a decoded payload through the adapter pipeline up to (but not past)\n * resolution. The result is the format-agnostic ParsedRoster — the same\n * intermediate the resolver consumes. Pinning this layer surfaces parser\n * regressions even when resolution masks them. */\nfunction parsedFromCanonicalSeed(caseDir: string): ParsedRoster {\n const decoded = decodeCanonicalSeed(caseDir);\n const adapter = selectAdapter(decoded, [...REGISTERED_ADAPTERS]);\n return adapter.parse(decoded);\n}\n\nconst TEXT_FORMATS: { format: ExportFormat; inputName: string; goldenName: string }[] = [\n {\n format: \"newrecruit-wtc-compact\",\n inputName: \"input.newrecruit-wtc-compact.txt\",\n goldenName: \"expected.newrecruit-wtc-compact.txt\",\n },\n {\n format: \"newrecruit-wtc-full\",\n inputName: \"input.newrecruit-wtc-full.txt\",\n goldenName: \"expected.newrecruit-wtc-full.txt\",\n },\n {\n format: \"newrecruit-simple\",\n inputName: \"input.newrecruit-simple.txt\",\n goldenName: \"expected.newrecruit-simple.txt\",\n },\n];\n\nfunction genRosters(): void {\n const ds = Dataset.embedded();\n const rosterDir = join(CONFORMANCE, \"roster\");\n for (const entry of readdirSync(rosterDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const caseDir = join(rosterDir, entry.name);\n\n const seed = seedRoster(caseDir, ds);\n writeJson(join(caseDir, \"expected.roster.json\"), seed);\n\n // Parsed-stage golden — the intermediate ParsedRoster produced by the\n // adapter for the canonical seed, before resolution. Catches parser bugs\n // that resolution would otherwise mask (e.g. wrong unit count from a\n // duplicate cost line that resolves to the same unit twice).\n writeJson(join(caseDir, \"expected.parsed.json\"), parsedFromCanonicalSeed(caseDir));\n\n // JSON export golden — NewRecruit-shaped skeleton.\n const jsonOut = exportRoster(seed, \"newrecruit-json\");\n writeJson(join(caseDir, \"expected.newrecruit-json.json\"), JSON.parse(jsonOut));\n\n // Canonical Roster JSON export — should equal the resolved roster.\n writeJson(join(caseDir, \"expected.roster-json.json\"), JSON.parse(exportRoster(seed, \"roster-json\")));\n\n // Text exports: always write the export golden so every fixture exercises\n // the cross-implementation byte-equality check. Only write the\n // `input.*.txt` round-trip seed when the fixture was authored for the\n // NewRecruit pipeline — legacy ListForge fixtures carry decoration\n // (multi-force warnings, leader-attachment inference) that the simple/wtc\n // exporters can't fully preserve, so the round-trip would fail\n // structurally rather than uncover a parser bug.\n const isNewRecruitSeed = existsSync(join(caseDir, \"input.newrecruit-json.json\"));\n for (const { format, inputName, goldenName } of TEXT_FORMATS) {\n const out = exportRoster(seed, format);\n writeText(join(caseDir, goldenName), out);\n if (isNewRecruitSeed) {\n writeText(join(caseDir, inputName), out);\n }\n }\n\n // Rosterizer JSON export + a derived round-trip input. The exporter is\n // deterministic and round-trips through the adapter, so emitting it as\n // both `expected.rosterizer.json` and `input.rosterizer.json` pins the\n // cross-implementation goldens and the importer regression at the same\n // time. Same NewRecruit-seed gate as the text formats — multi-force\n // ListForge fixtures lose their provisional leader-attachment under\n // round-trip, so they only get the export golden, not the derived input.\n const rosterizerOut = exportRoster(seed, \"rosterizer\");\n writeJson(join(caseDir, \"expected.rosterizer.json\"), JSON.parse(rosterizerOut));\n if (isNewRecruitSeed) {\n writeJson(join(caseDir, \"input.rosterizer.json\"), JSON.parse(rosterizerOut));\n }\n\n console.log(\n `roster/${entry.name}: ${seed.units.length} units, ${seed.diagnostics.warnings.length} warnings`,\n );\n }\n}\n\n/**\n * Linked-API query cases. Each descriptor names a query method on Dataset, the\n * args to call it with, and how the result should be compared.\n *\n * `comparison: \"ordered\"` pins the result order — used for queries that iterate\n * a data-driven array (`unit.ability_ids`, `unit.weapon_ids`) where order is\n * encoded in the data and both implementations iterate it the same way.\n *\n * `comparison: \"set\"` pins only the set of ids — used for queries that walk an\n * index (faction → abilities, ability → phases) where iteration order depends\n * on dataset bundler internals and is incidental. Ids are sorted before\n * comparison.\n *\n * `comparison: \"scalar\"` pins a single id-or-null result (find_* and\n * faction_of(unit)).\n */\ntype LinkedApiQuery =\n | { name: string; query: \"find_unit\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"find_weapon\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"find_faction\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"find_ability\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"abilities_of\"; args: { unitId: string }; comparison: \"ordered\" }\n | { name: string; query: \"weapons_of\"; args: { unitId: string }; comparison: \"ordered\" }\n | { name: string; query: \"phases_of\"; args: { abilityId: string }; comparison: \"set\" }\n | { name: string; query: \"faction_of\"; args: { unitId: string }; comparison: \"scalar\" }\n | { name: string; query: \"abilities_of_faction\"; args: { factionId: string }; comparison: \"set\" }\n | { name: string; query: \"weapons_of_faction\"; args: { factionId: string }; comparison: \"set\" }\n | { name: string; query: \"base_size_of\"; args: { unitId: string }; comparison: \"scalar\" }\n | { name: string; query: \"model_bases_of\"; args: { unitId: string }; comparison: \"ordered\" };\n\nconst LINKED_API_QUERIES: LinkedApiQuery[] = [\n // find_unit: diacritic-insensitive lookup, miss returns null.\n { name: \"find_unit by diacritic name\", query: \"find_unit\", args: { query: \"Kharn\" }, comparison: \"scalar\" },\n { name: \"find_unit miss returns null\", query: \"find_unit\", args: { query: \"not-a-real-unit-xyz\" }, comparison: \"scalar\" },\n // find_weapon: hyphen + space tolerance.\n { name: \"find_weapon by name\", query: \"find_weapon\", args: { query: \"bolt rifle\" }, comparison: \"scalar\" },\n // find_faction: punctuation/diacritic tolerance.\n { name: \"find_faction by display name\", query: \"find_faction\", args: { query: \"World Eaters\" }, comparison: \"scalar\" },\n // find_ability: ability name lookup.\n { name: \"find_ability by name\", query: \"find_ability\", args: { query: \"Berzerker Frenzy\" }, comparison: \"scalar\" },\n // abilities_of(unit): ordered, iterates unit.ability_ids array.\n { name: \"abilities_of intercessor-squad\", query: \"abilities_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"ordered\" },\n { name: \"abilities_of kharn-the-betrayer\", query: \"abilities_of\", args: { unitId: \"kharn-the-betrayer\" }, comparison: \"ordered\" },\n // weapons_of(unit): ordered, iterates unit.weapon_ids array.\n { name: \"weapons_of intercessor-squad\", query: \"weapons_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"ordered\" },\n { name: \"weapons_of kharn-the-betrayer\", query: \"weapons_of\", args: { unitId: \"kharn-the-betrayer\" }, comparison: \"ordered\" },\n // phases_of(ability): compared as set (phase index iteration order is incidental).\n { name: \"phases_of berzerker-frenzy\", query: \"phases_of\", args: { abilityId: \"berzerker-frenzy\" }, comparison: \"set\" },\n // faction_of(unit): scalar id or null.\n { name: \"faction_of intercessor-squad\", query: \"faction_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"scalar\" },\n // abilities_of_faction: compared as set (collection-index order is incidental).\n { name: \"abilities_of_faction world-eaters\", query: \"abilities_of_faction\", args: { factionId: \"world-eaters\" }, comparison: \"set\" },\n // weapons_of_faction: compared as set.\n { name: \"weapons_of_faction world-eaters\", query: \"weapons_of_faction\", args: { factionId: \"world-eaters\" }, comparison: \"set\" },\n // base_size_of(unit): scalar encoded base — round, oval, and a draft flying-base.\n { name: \"base_size_of intercessor-squad\", query: \"base_size_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"scalar\" },\n { name: \"base_size_of vertus-praetors\", query: \"base_size_of\", args: { unitId: \"vertus-praetors\" }, comparison: \"scalar\" },\n { name: \"base_size_of windriders (draft flying base)\", query: \"base_size_of\", args: { unitId: \"windriders\" }, comparison: \"scalar\" },\n // model_bases_of(unit): ordered per-model bases; jakhals mixes 28.5mm bodies with a 40mm Dishonoured.\n { name: \"model_bases_of jakhals (mixed)\", query: \"model_bases_of\", args: { unitId: \"jakhals\" }, comparison: \"ordered\" },\n];\n\nfunction genLinkedApi(): void {\n const ds = Dataset.embedded();\n const cases = LINKED_API_QUERIES.map((q) => {\n const expected = runLinkedQuery(ds, q);\n return { ...q, expected };\n });\n writeJson(join(CONFORMANCE, \"linked-api\", \"cases.json\"), cases);\n console.log(`linked-api/cases.json: ${cases.length} cases`);\n}\n\nfunction runLinkedQuery(ds: Dataset, q: LinkedApiQuery): string | null | string[] {\n switch (q.query) {\n case \"find_unit\":\n return ds.units.find(q.args.query)?.id ?? null;\n case \"find_weapon\":\n return ds.weapons.find(q.args.query)?.id ?? null;\n case \"find_faction\":\n return ds.factions.find(q.args.query)?.id ?? null;\n case \"find_ability\":\n return ds.abilities.find(q.args.query)?.id ?? null;\n case \"abilities_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`abilities_of: unknown unit ${q.args.unitId}`);\n return u.abilities.map((a) => a.id);\n }\n case \"weapons_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`weapons_of: unknown unit ${q.args.unitId}`);\n return u.weapons.map((w) => w.id);\n }\n case \"phases_of\": {\n const a = ds.abilities.get(q.args.abilityId);\n if (!a) throw new Error(`phases_of: unknown ability ${q.args.abilityId}`);\n return [...a.phases].sort();\n }\n case \"faction_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`faction_of: unknown unit ${q.args.unitId}`);\n return u.faction?.id ?? null;\n }\n case \"abilities_of_faction\":\n return ds.abilities.byFaction(q.args.factionId).map((a) => a.id).sort();\n case \"weapons_of_faction\": {\n // Mirrors Rust `weapons_of_faction`: aggregate weapons across the\n // faction's units and dedupe by id. The collection-level\n // `weapons.byFaction()` is a different operation (it looks up weapons\n // whose own `faction_id` is set, which is empty for most factions).\n const f = ds.factions.get(q.args.factionId);\n if (!f) throw new Error(`weapons_of_faction: unknown faction ${q.args.factionId}`);\n return f.weapons.map((w) => w.id).sort();\n }\n case \"base_size_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`base_size_of: unknown unit ${q.args.unitId}`);\n return encodeBase(u.raw.base_size_mm);\n }\n case \"model_bases_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`model_bases_of: unknown unit ${q.args.unitId}`);\n const comp = ds.unitCompositions.find((c) => c.unit_id === q.args.unitId);\n return (comp?.models ?? []).map((m) => `${m.name}=${encodeBase(m.base_size_mm) ?? \"none\"}`);\n }\n }\n}\n\n/**\n * Attribution corpus: reuses the existing cruncher inputs from the cases that\n * carry at least one groupable buff (ability or manual). The expected shape\n * is the AttributedStage array produced by attributeStages; both\n * implementations of the leave-one-out decomposition must reproduce it\n * within the per-stage float tolerance.\n */\nconst ATTRIBUTION_CASE_FILES = [\n \"05-anti-infantry-vs-cultist.json\",\n \"07-twin-linked-heavy-stationary-vs-knight.json\",\n];\n\ninterface CruncherCaseInput {\n name: string;\n attacker: { weaponId: string; profileIndex: number };\n modelsFiring: number;\n target: { unitId: string; profileIndex: number; modelCount?: number };\n context: EngineInput[\"context\"];\n buffs: EngineInput[\"buffs\"];\n}\n\nfunction loadAttributionInput(ds: Dataset, filename: string): {\n name: string;\n input: EngineInput;\n} {\n const path = join(CONFORMANCE, \"cruncher\", filename);\n const c = JSON.parse(readFileSync(path, \"utf8\")) as CruncherCaseInput;\n const weapon = ds.weapons.get(c.attacker.weaponId);\n const unit = ds.units.get(c.target.unitId);\n if (!weapon) throw new Error(`attribution: unknown weapon ${c.attacker.weaponId}`);\n if (!unit) throw new Error(`attribution: unknown unit ${c.target.unitId}`);\n return {\n name: c.name,\n input: {\n attacker: { weapon: weapon.raw, profileIndex: c.attacker.profileIndex },\n target: {\n unit: unit.raw,\n profileIndex: c.target.profileIndex,\n ...(c.target.modelCount !== undefined ? { modelCount: c.target.modelCount } : {}),\n },\n modelsFiring: c.modelsFiring,\n buffs: c.buffs,\n context: c.context,\n },\n };\n}\n\nfunction genAttribution(): void {\n const ds = Dataset.embedded();\n const cases = ATTRIBUTION_CASE_FILES.map((filename, idx) => {\n const { name, input } = loadAttributionInput(ds, filename);\n const stages = attributeStages(input, ds);\n return {\n // Persist the input by file reference so the corpus stays a single\n // source of truth — the cruncher case file already pins the EngineInput.\n name,\n cruncher_case: filename,\n expected: stages.map((s) => ({\n name: s.name,\n expected: s.expected,\n baseline: s.baseline,\n lifts: s.lifts.map((l) => ({ source: l.source, delta: l.delta })),\n residual: s.residual,\n intrinsics: s.intrinsics,\n })),\n // Stable ordering of cases in the corpus file.\n _order: idx,\n };\n });\n // Sort by _order and strip the helper before writing.\n cases.sort((a, b) => a._order - b._order);\n const serialised = cases.map(({ _order: _o, ...rest }) => rest);\n writeJson(join(CONFORMANCE, \"attribution\", \"cases.json\"), serialised);\n console.log(`attribution/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Scoring-card translation corpus: humanize each primary mission card's\n * `awards` into plain English. The TS translator is the oracle; the Rust port\n * must reproduce every string byte-for-byte (the differ compares structurally,\n * no tolerance). Only `card_type: \"primary\"` cards are pinned — the 14-card\n * secondary deck isn't revealed yet. Cases are sorted by id for stability, and\n * the `awards` array order within each card is load-bearing.\n */\nfunction genScoringTranslation(): void {\n const ds = Dataset.embedded();\n mkdirSync(join(CONFORMANCE, \"scoring-translation\"), { recursive: true });\n // Pin the translation of every mission card's awards — primary and secondary\n // alike (the secondary deck has the same `awards` shape and deserves the same\n // cross-impl pinning).\n const cases = ds.missionCards.all\n .filter((c) => c.card_type === \"primary\" || c.card_type === \"secondary\")\n .slice()\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))\n .map((card) => ({ cardId: card.id, expected: { awards: describeScoringCard(card) } }));\n writeJson(join(CONFORMANCE, \"scoring-translation\", \"cases.json\"), cases);\n console.log(`scoring-translation/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Scoring-engine corpus: pin the pure VP arithmetic of the scoring engine\n * (`tools/src/scoring/` — the oracle) so the Rust `wh40kdc::scoring` port\n * reproduces it. Three ops, each case `{ name, op, args, expected }`:\n *\n * - `score_event` — per card and approach, assert every award matching the\n * approach (by its full-`awards`-array index). Pins `scoreAward`, `scoreTurn`\n * (exclusive-group \"highest only\", `vp_per × count` clamped to `per_max`,\n * cumulative sums), `scoreCap` (tactical 5 vs fixed `vp_max`/uncapped), and\n * `scoreSecondaryEvent`; primary cards also carry a `roundCap` to pin\n * `scorePrimaryEvent`. `cap: null` means uncapped (Infinity has no JSON form).\n * - `score_state` — replay scenarios over a `PlayerGame`, pinning the per-round\n * cap (15), per-game primary cap (45), grand-total cap (100), score+discard,\n * and undo.\n * - `wtc_result` — the 20-point band mapping across its boundaries.\n *\n * Goldens are produced by driving the TS runner's own `dispatch`, so the corpus\n * and the runner agree by construction; the cross-impl contract is the Rust\n * runner reproducing them. Integers are compared exactly (no tolerance).\n */\nfunction genScoring(): void {\n const ds = Dataset.embedded();\n mkdirSync(join(CONFORMANCE, \"scoring\"), { recursive: true });\n\n // One initialized runner state, reused across cases (the ops don't mutate it).\n const specVersion = Number.parseInt(\n readFileSync(join(CONFORMANCE, \"SPEC_VERSION\"), \"utf8\").trim(),\n 10,\n );\n const state = createRunnerState();\n const init = dispatch(state, {\n op: \"init\",\n args: { spec_version: specVersion, locale: \"C\", tz: \"UTC\", seed: 0 },\n });\n if (!init.ok) throw new Error(`gen scoring: init failed: ${JSON.stringify(init)}`);\n const run = (op: string, args: unknown): unknown => {\n const r = dispatch(state, { op, args });\n if (!r.ok) throw new Error(`gen scoring: ${op} failed: ${JSON.stringify(r)} for ${JSON.stringify(args)}`);\n return r.value;\n };\n\n type Case = { name: string; op: string; args: unknown; expected: unknown };\n const cases: Case[] = [];\n\n // score_event: every mission card, both approaches. Assert the approach's\n // awards by their full-array index; count vp_per awards to their per_max\n // (else 2) so the cap logic actually bites.\n const cards = ds.missionCards.all\n .slice()\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n for (const card of cards) {\n for (const approach of [\"fixed\", \"tactical\"] as const) {\n const asserted = awardsOf(card)\n .map((aw, index) => ({ aw, index }))\n .filter(({ aw }) => aw.mode == null || aw.mode === approach)\n .map(({ aw, index }) =>\n aw.vp_per != null ? { index, count: aw.per_max ?? 2 } : { index },\n );\n const args: Record<string, unknown> = { cardId: card.id, approach, asserted };\n if (card.card_type === \"primary\") args.roundCap = 15;\n cases.push({\n name: `score_event/${card.id}/${approach}`,\n op: \"score_event\",\n args,\n expected: run(\"score_event\", args),\n });\n }\n }\n\n // score_state: hand-authored replay scenarios. Card ids are real deck/mission\n // cards; expected state is whatever the engine produces.\n const stateScenarios: { name: string; args: unknown }[] = [\n {\n name: \"primary-round-and-game-caps\",\n args: {\n approach: \"tactical\",\n ops: [\n { kind: \"set-primary\", round: 1, vp: 30, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 2, vp: 30, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 3, vp: 30, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 4, vp: 30, roundCap: 15, gameCap: 45 },\n ],\n },\n },\n {\n // The full primary path: a card's raw round total, clamped to the round\n // cap on store, then cleared back to 0 by a set-primary 0.\n name: \"score-primary-then-clear\",\n args: {\n approach: \"tactical\",\n ops: [\n {\n kind: \"score-primary\",\n cardId: \"battlefield-dominance\",\n round: 2,\n asserted: awardsOf(ds.missionCards.get(\"battlefield-dominance\")!).map((aw, index) =>\n aw.vp_per != null ? { index, count: aw.per_max ?? 3 } : { index },\n ),\n roundCap: 15,\n gameCap: 45,\n },\n { kind: \"set-primary\", round: 3, vp: 99, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 2, vp: 0, roundCap: 15, gameCap: 45 },\n ],\n },\n },\n {\n name: \"secondary-score-and-undo\",\n args: {\n approach: \"tactical\",\n ops: [\n { kind: \"draw\", cardId: \"no-prisoners\" },\n { kind: \"score-secondary\", cardId: \"no-prisoners\", round: 2, asserted: [{ index: 0, count: 3 }] },\n { kind: \"remove-score\", index: 0 },\n ],\n },\n },\n {\n // Uncapped set-primary (no caps) overshoots so the 100 grand-total cap bites.\n name: \"grand-total-cap-at-100\",\n args: {\n approach: \"tactical\",\n ops: [\n { kind: \"set-primary\", round: 1, vp: 30 },\n { kind: \"set-primary\", round: 2, vp: 30 },\n { kind: \"set-primary\", round: 3, vp: 30 },\n { kind: \"set-primary\", round: 4, vp: 30 },\n { kind: \"set-primary\", round: 5, vp: 30 },\n { kind: \"draw\", cardId: \"no-prisoners\" },\n { kind: \"score-secondary\", cardId: \"no-prisoners\", round: 5, asserted: [{ index: 0, count: 99 }] },\n ],\n },\n },\n ];\n for (const s of stateScenarios) {\n cases.push({ name: `score_state/${s.name}`, op: \"score_state\", args: s.args, expected: run(\"score_state\", s.args) });\n }\n\n // wtc_result: band boundaries and symmetry.\n const wtcPairs: [number, number][] = [\n [50, 50],\n [48, 45],\n [45, 50],\n [56, 50],\n [50, 61],\n [100, 50],\n [100, 49],\n [0, 100],\n [60, 40],\n [55, 50],\n ];\n for (const [a, b] of wtcPairs) {\n const args = { a, b };\n cases.push({ name: `wtc_result/${a}-${b}`, op: \"wtc_result\", args, expected: run(\"wtc_result\", args) });\n }\n\n writeJson(join(CONFORMANCE, \"scoring\", \"cases.json\"), cases);\n console.log(`scoring/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Terrain-resolver corpus: resolve template-anchored layouts to absolute\n * board-space vertices (y-down inches). The TS resolver is the oracle; the Rust\n * port must reproduce every vertex within 5e-4 (per-area invariant in\n * CONFORMANCE.md). Cases are self-contained — each carries its own `templates`\n * and `layout` — so the corpus does not depend on the bundled catalog and the\n * runner op can pass both in `args`. Coverage: per-template centroid anchoring\n * (identity), cardinal + oblique rotations, both mirror axes on an asymmetric\n * shape, embedded-feature composition, explicit parenting, and the inline\n * footprint escape hatch.\n */\nfunction genTerrainResolver(): void {\n mkdirSync(join(CONFORMANCE, \"terrain-resolver\"), { recursive: true });\n\n const areaLarge: ResolverTemplate = {\n id: \"area-large\",\n name: \"Large Area\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 11.5, height: 7 },\n };\n const areaMedium: ResolverTemplate = {\n id: \"area-medium\",\n name: \"Medium Area\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 6, height: 4 },\n };\n const areaTrapezoid: ResolverTemplate = {\n id: \"area-trapezoid\",\n name: \"Trapezoid Area\",\n kind: \"area\",\n footprint: {\n type: \"polygon\",\n points: [\n { x: 0, y: 0 },\n { x: 8, y: 0 },\n { x: 2, y: 11.5 },\n { x: 0, y: 11.5 },\n ],\n },\n };\n const wedge: ResolverTemplate = {\n id: \"wedge\",\n name: \"Right Wedge\",\n kind: \"area\",\n footprint: { type: \"right-triangle\", width: 8, height: 11.5 },\n };\n const wallLong: ResolverTemplate = {\n id: \"wall-long\",\n name: \"Long Wall\",\n kind: \"feature\",\n footprint: { type: \"rectangle\", width: 7, height: 0.25 },\n };\n const ruinComposed: ResolverTemplate = {\n id: \"ruin-composed\",\n name: \"Composed Ruin\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 11.5, height: 7 },\n features: [\n { id: \"back-wall\", template: \"wall-long\", position: { x: 0, y: -3 } },\n { id: \"side-wall\", template: \"wall-long\", position: { x: -5, y: 0 }, rotation_degrees: 90, mirror: \"horizontal\" },\n ],\n };\n\n const baseCatalog = [areaLarge, areaMedium, areaTrapezoid, wedge, wallLong];\n\n const layoutCases: { name: string; templates: ResolverTemplate[]; layout: ResolverLayout }[] = [\n {\n name: \"identity-large\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-large\", position: { x: 30, y: 22 } }] },\n },\n {\n name: \"identity-wedge\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"wedge\", position: { x: 12, y: 30 } }] },\n },\n {\n name: \"identity-trapezoid\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 40, y: 18 } }] },\n },\n {\n name: \"rotate-medium-90\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-medium\", position: { x: 30, y: 22 }, rotation_degrees: 90 }] },\n },\n {\n name: \"rotate-medium-180\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-medium\", position: { x: 30, y: 22 }, rotation_degrees: 180 }] },\n },\n {\n name: \"rotate-medium-270\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-medium\", position: { x: 30, y: 22 }, rotation_degrees: 270 }] },\n },\n {\n name: \"rotate-large-oblique-55\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-large\", position: { x: 30, y: 22 }, rotation_degrees: 55 }] },\n },\n {\n name: \"rotate-trapezoid-oblique-235\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 35.75, y: 27 }, rotation_degrees: 235 }] },\n },\n {\n name: \"mirror-trapezoid-horizontal\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 40, y: 18 }, mirror: \"horizontal\" }] },\n },\n {\n name: \"mirror-trapezoid-vertical-rot90\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 40, y: 18 }, rotation_degrees: 90, mirror: \"vertical\" }] },\n },\n {\n name: \"composition-ruin-rot90-mirror-h\",\n templates: [ruinComposed, wallLong],\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"a1\", template: \"ruin-composed\", position: { x: 30, y: 22 }, rotation_degrees: 90, mirror: \"horizontal\" }] },\n },\n {\n name: \"explicit-parent-feature\",\n templates: [areaLarge, wallLong],\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n { id: \"a1\", template: \"area-large\", position: { x: 30, y: 22 }, rotation_degrees: 90, mirror: \"horizontal\" },\n { id: \"back-wall\", template: \"wall-long\", parent_area_id: \"a1\", position: { x: 0, y: -3 } },\n ],\n },\n },\n {\n name: \"inline-footprint-polygon\",\n templates: [],\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n footprint: { type: \"polygon\", points: [{ x: 0, y: 0 }, { x: 4, y: 0 }, { x: 2, y: 5 }] },\n position: { x: 50, y: 40 },\n rotation_degrees: 30,\n },\n ],\n },\n },\n ];\n\n const cases = layoutCases.map((c) => ({\n name: c.name,\n templates: c.templates,\n layout: c.layout,\n expected: { pieces: resolveLayout(c.layout, c.templates) },\n }));\n writeJson(join(CONFORMANCE, \"terrain-resolver\", \"cases.json\"), cases);\n console.log(`terrain-resolver/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Terrain-keystones corpus: derive the printed distance of each authored\n * keystone (board edge → piece feature) from resolved geometry. The TS helper\n * is the oracle; the Rust port must reproduce every distance within 5e-4.\n * Cases are self-contained like the resolver corpus. Coverage: all four\n * edges, vertex and bounding-face refs, an oblique rotation, a mirrored\n * asymmetric shape, a parented feature (composition through the parent\n * frame), an inline footprint, and a custom board size.\n */\nfunction genTerrainKeystones(): void {\n mkdirSync(join(CONFORMANCE, \"terrain-keystones\"), { recursive: true });\n\n const areaLarge: ResolverTemplate = {\n id: \"area-large\",\n name: \"Large Area\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 11.5, height: 7 },\n };\n const areaTrapezoid: ResolverTemplate = {\n id: \"area-trapezoid\",\n name: \"Trapezoid Area\",\n kind: \"area\",\n footprint: {\n type: \"polygon\",\n points: [\n { x: 0, y: 0 },\n { x: 8, y: 0 },\n { x: 2, y: 11.5 },\n { x: 0, y: 11.5 },\n ],\n },\n };\n const wallLong: ResolverTemplate = {\n id: \"wall-long\",\n name: \"Long Wall\",\n kind: \"feature\",\n footprint: { type: \"rectangle\", width: 7, height: 0.25 },\n };\n const catalog = [areaLarge, areaTrapezoid, wallLong];\n\n const keystoneCases: {\n name: string;\n templates: ResolverTemplate[];\n layout: ResolverLayout;\n board?: { width: number; height: number };\n }[] = [\n {\n name: \"identity-four-edges-vertices\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-large\",\n position: { x: 30, y: 22 },\n keystones: [\n { edge: \"left\", ref: { kind: \"vertex\", index: 0 } },\n { edge: \"top\", ref: { kind: \"vertex\", index: 1 } },\n { edge: \"right\", ref: { kind: \"vertex\", index: 2 } },\n { edge: \"bottom\", ref: { kind: \"vertex\", index: 3 } },\n ],\n },\n ],\n },\n },\n {\n name: \"identity-bounding-faces\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-large\",\n position: { x: 20, y: 30 },\n keystones: [\n { edge: \"left\", ref: { kind: \"face\", side: \"min-x\" } },\n { edge: \"right\", ref: { kind: \"face\", side: \"max-x\" } },\n { edge: \"top\", ref: { kind: \"face\", side: \"min-y\" } },\n { edge: \"bottom\", ref: { kind: \"face\", side: \"max-y\" } },\n ],\n },\n ],\n },\n },\n {\n name: \"oblique-rotation-vertex\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-trapezoid\",\n position: { x: 35.75, y: 27 },\n rotation_degrees: 235,\n keystones: [\n { edge: \"left\", ref: { kind: \"vertex\", index: 2 } },\n { edge: \"bottom\", ref: { kind: \"face\", side: \"max-y\" } },\n ],\n },\n ],\n },\n },\n {\n name: \"mirrored-trapezoid-vertex\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-trapezoid\",\n position: { x: 40, y: 18 },\n mirror: \"horizontal\",\n keystones: [\n { edge: \"right\", ref: { kind: \"vertex\", index: 1 } },\n { edge: \"top\", ref: { kind: \"vertex\", index: 0 } },\n ],\n },\n ],\n },\n },\n {\n name: \"parented-feature-keystone\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"a1\",\n template: \"area-large\",\n position: { x: 30, y: 22 },\n rotation_degrees: 90,\n mirror: \"horizontal\",\n keystones: [{ edge: \"left\", ref: { kind: \"vertex\", index: 0 } }],\n },\n {\n id: \"back-wall\",\n template: \"wall-long\",\n parent_area_id: \"a1\",\n position: { x: 0, y: -3 },\n keystones: [\n { edge: \"top\", ref: { kind: \"vertex\", index: 1 } },\n { edge: \"right\", ref: { kind: \"face\", side: \"max-x\" } },\n ],\n },\n ],\n },\n },\n {\n name: \"inline-footprint-keystone\",\n templates: [],\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n footprint: { type: \"polygon\", points: [{ x: 0, y: 0 }, { x: 4, y: 0 }, { x: 2, y: 5 }] },\n position: { x: 50, y: 40 },\n rotation_degrees: 30,\n keystones: [\n { edge: \"right\", ref: { kind: \"vertex\", index: 0 } },\n { edge: \"bottom\", ref: { kind: \"vertex\", index: 2 } },\n ],\n },\n ],\n },\n },\n {\n name: \"custom-board-extents\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-large\",\n position: { x: 15, y: 15 },\n keystones: [\n { edge: \"right\", ref: { kind: \"face\", side: \"max-x\" } },\n { edge: \"bottom\", ref: { kind: \"face\", side: \"max-y\" } },\n ],\n },\n ],\n },\n board: { width: 30, height: 22.4 },\n },\n ];\n\n const cases = keystoneCases.map((c) => ({\n name: c.name,\n templates: c.templates,\n layout: c.layout,\n ...(c.board ? { board: c.board } : {}),\n expected: {\n measurements: keystoneMeasurements(c.layout, c.templates, c.board ?? BOARD_INCHES),\n },\n }));\n writeJson(join(CONFORMANCE, \"terrain-keystones\", \"cases.json\"), cases);\n console.log(`terrain-keystones/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Effect-translation corpus: pin the Ability-DSL effect describer\n * (`describeEffect`/`describeAbility` — the \"ability.print()\") across the TS\n * and Rust ports. Cases embed the raw `effect` (+ `scope`) so parity does not\n * depend on collection dup-id resolution; selection greedily covers every\n * effect node type at least once (up to 5 exemplars per type) over the\n * id-sorted ability list, so the corpus stays small but exhaustive by shape.\n */\nfunction genEffectTranslation(): void {\n const ds = Dataset.embedded();\n mkdirSync(join(CONFORMANCE, \"effect-translation\"), { recursive: true });\n\n const collectTypes = (e: unknown, out: Set<string>): void => {\n if (Array.isArray(e)) {\n for (const v of e) collectTypes(v, out);\n return;\n }\n if (typeof e !== \"object\" || e === null) return;\n const rec = e as Record<string, unknown>;\n if (typeof rec.type === \"string\") out.add(rec.type);\n for (const key of [\"effect\", \"on_success\", \"on_fail\", \"steps\", \"options\", \"condition\"]) {\n if (key in rec) collectTypes(rec[key], out);\n }\n };\n\n const abilities = ds.abilities.all\n .slice()\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n\n const seen = new Map<string, number>();\n const CAP = 5;\n const cases: unknown[] = [];\n for (const a of abilities) {\n const types = new Set<string>();\n collectTypes(a.raw.effect, types);\n let fresh = false;\n for (const t of types) {\n if ((seen.get(t) ?? 0) < CAP) fresh = true;\n }\n if (!fresh) continue;\n for (const t of types) seen.set(t, (seen.get(t) ?? 0) + 1);\n cases.push({\n caseId: `${a.id}#${cases.length}`,\n effect: a.raw.effect,\n scope: a.raw.scope ?? null,\n expected: { text: describeAbility({ effect: a.raw.effect as Effect, scope: a.raw.scope }) },\n });\n }\n writeJson(join(CONFORMANCE, \"effect-translation\", \"cases.json\"), cases);\n console.log(`effect-translation/cases.json: ${cases.length} cases (${seen.size} node types)`);\n}\n\ngenNormalize();\ngenRosters();\ngenLinkedApi();\ngenAttribution();\ngenScoringTranslation();\ngenEffectTranslation();\ngenScoring();\ngenTerrainResolver();\ngenTerrainKeystones();\n"]}
1
+ {"version":3,"file":"gen-conformance.js","sourceRoot":"","sources":["../src/gen-conformance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generate the cross-implementation conformance corpus under repo-root\n * `conformance/`. The TypeScript package is the reference implementation, so\n * the goldens it emits are what the Rust crate must reproduce byte-for-byte\n * (structurally). Run via `npm run gen:conformance`; CI regenerates and asserts\n * `git diff --exit-code conformance/` is clean.\n *\n * Outputs:\n * - `conformance/normalize.json` — `[{ input, expected }]` for normalizeName.\n * - `conformance/roster/<case>/expected.roster.json` — the resolved Roster.\n * - `conformance/roster/<case>/expected.<fmt>.{txt,json}` — every export\n * target's golden output. The TS exporter is the oracle; the Rust mirror\n * asserts byte-equal output for the same Roster.\n * - `conformance/roster/<case>/input.newrecruit-{wtc-compact,wtc-full,simple}.txt`\n * — text inputs derived from the seed by the exporter, so a re-import\n * regression in either implementation surfaces immediately.\n *\n * Seeding: each `<case>/` carries one canonical input — either the legacy\n * `input.json` (ListForge) or `input.newrecruit-json.json` (NewRecruit). Other\n * inputs are derived.\n */\nimport { readdirSync, readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { Dataset } from \"./data/dataset.js\";\nimport { normalizeName } from \"./data/normalize.js\";\nimport { describeScoringCard, describeAbility, type Effect } from \"./translate/index.js\";\nimport { awardsOf } from \"./scoring/index.js\";\nimport { createRunnerState, dispatch } from \"./runner.js\";\nimport { exportRoster, type ExportFormat } from \"./export/index.js\";\nimport { importRoster, REGISTERED_ADAPTERS } from \"./import/import-roster.js\";\nimport { selectAdapter } from \"./import/adapter.js\";\nimport type { ParsedRoster, Roster } from \"./import/types.js\";\nimport { encodeBase } from \"./runner.js\";\nimport { attributeStages } from \"./cruncher/attribution.js\";\nimport type { EngineInput } from \"./cruncher/index.js\";\nimport {\n resolveLayout,\n type TerrainTemplate as ResolverTemplate,\n type TerrainLayout as ResolverLayout,\n} from \"./terrain/resolve.js\";\nimport { keystoneMeasurements, BOARD_INCHES } from \"./terrain/keystones.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst REPO_ROOT = join(__dirname, \"../..\");\nconst CONFORMANCE = join(REPO_ROOT, \"conformance\");\n\nconst NORMALIZE_INPUTS = [\n // NFD diacritic strip\n \"Khârn the Betrayer\",\n \"Brôkhyr\",\n \"Ûthar\",\n \"Magnús\",\n // apostrophe / quote variants\n \"T'au\",\n \"Be’lakor\",\n \"Kor’sarro Khan\",\n \"Aetaos'rau'keres\",\n \"‘quoted’\",\n // whitespace / hyphen collapse + trim\n \"Brôkhyr Iron-master\",\n \" the betrayer \",\n \"space--marines\",\n // casefold\n \"KHÂRN THE BETRAYER\",\n // already-normalized (idempotence)\n \"kharn the betrayer\",\n // distinctness anchors (must NOT collapse together)\n \"Khorne\",\n \"Khârn\",\n // Unicode whitespace beyond ASCII — every Unicode whitespace must collapse\n // identically across implementations or `find(\"Khorne Lord\")` and\n // `find(\"Khorne Lord\")` will silently disagree across ports.\n \"Khorne Lord\",\n \"Khorne Lord\",\n // Turkish dotted-I: NFD decomposes to `I` + combining dot above; the dot is\n // stripped, then locale-independent lowercase yields `i`. The case pins that\n // no implementation introduces locale-aware casefolding (which would map\n // `I` → `ı` under Turkish locale and break ASCII-text search).\n \"İmperial Fists\",\n // Zero-width joiner: passes through every step today. Pinned so behavior\n // does not silently change — if a future commit strips Cf-category chars,\n // this golden updates in the same PR.\n \"Khorne‍Lord\",\n];\n\nfunction writeJson(path: string, value: unknown): void {\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction writeText(path: string, value: string): void {\n writeFileSync(path, value);\n}\n\nfunction genNormalize(): void {\n const table = NORMALIZE_INPUTS.map((input) => ({ input, expected: normalizeName(input) }));\n writeJson(join(CONFORMANCE, \"normalize.json\"), table);\n console.log(`normalize.json: ${table.length} cases`);\n}\n\n/** Locate the canonical input for a fixture dir: prefer `input.json` (legacy\n * ListForge), then `input.newrecruit-json.json` (NewRecruit), then the\n * text-only `input.gw.txt` / `input.listforge-text.txt` (app text exports —\n * import-only, like ListForge). */\nfunction seedRoster(caseDir: string, ds: Dataset): Roster {\n const decoded = decodeCanonicalSeed(caseDir);\n return importRoster(decoded, { dataset: ds });\n}\n\n/** Return the decoded payload for the canonical seed — the same value the\n * import pipeline would dispatch on. JSON seeds come back parsed; text seeds\n * come back as the raw string. */\nfunction decodeCanonicalSeed(caseDir: string): unknown {\n const jsonSeed = join(caseDir, \"input.json\");\n if (existsSync(jsonSeed)) {\n return JSON.parse(readFileSync(jsonSeed, \"utf8\"));\n }\n const nrSeed = join(caseDir, \"input.newrecruit-json.json\");\n if (existsSync(nrSeed)) {\n return JSON.parse(readFileSync(nrSeed, \"utf8\"));\n }\n const gwSeed = join(caseDir, \"input.gw.txt\");\n if (existsSync(gwSeed)) {\n return readFileSync(gwSeed, \"utf8\");\n }\n const lfTextSeed = join(caseDir, \"input.listforge-text.txt\");\n if (existsSync(lfTextSeed)) {\n return readFileSync(lfTextSeed, \"utf8\");\n }\n throw new Error(`no canonical input found in ${caseDir}`);\n}\n\n/** Run a decoded payload through the adapter pipeline up to (but not past)\n * resolution. The result is the format-agnostic ParsedRoster — the same\n * intermediate the resolver consumes. Pinning this layer surfaces parser\n * regressions even when resolution masks them. */\nfunction parsedFromCanonicalSeed(caseDir: string): ParsedRoster {\n const decoded = decodeCanonicalSeed(caseDir);\n const adapter = selectAdapter(decoded, [...REGISTERED_ADAPTERS]);\n return adapter.parse(decoded);\n}\n\nconst TEXT_FORMATS: { format: ExportFormat; inputName: string; goldenName: string }[] = [\n {\n format: \"newrecruit-wtc-compact\",\n inputName: \"input.newrecruit-wtc-compact.txt\",\n goldenName: \"expected.newrecruit-wtc-compact.txt\",\n },\n {\n format: \"newrecruit-wtc-full\",\n inputName: \"input.newrecruit-wtc-full.txt\",\n goldenName: \"expected.newrecruit-wtc-full.txt\",\n },\n {\n format: \"newrecruit-simple\",\n inputName: \"input.newrecruit-simple.txt\",\n goldenName: \"expected.newrecruit-simple.txt\",\n },\n];\n\nfunction genRosters(): void {\n const ds = Dataset.embedded();\n const rosterDir = join(CONFORMANCE, \"roster\");\n for (const entry of readdirSync(rosterDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const caseDir = join(rosterDir, entry.name);\n\n const seed = seedRoster(caseDir, ds);\n writeJson(join(caseDir, \"expected.roster.json\"), seed);\n\n // Parsed-stage golden — the intermediate ParsedRoster produced by the\n // adapter for the canonical seed, before resolution. Catches parser bugs\n // that resolution would otherwise mask (e.g. wrong unit count from a\n // duplicate cost line that resolves to the same unit twice).\n writeJson(join(caseDir, \"expected.parsed.json\"), parsedFromCanonicalSeed(caseDir));\n\n // JSON export golden — NewRecruit-shaped skeleton.\n const jsonOut = exportRoster(seed, \"newrecruit-json\");\n writeJson(join(caseDir, \"expected.newrecruit-json.json\"), JSON.parse(jsonOut));\n\n // Canonical Roster JSON export — should equal the resolved roster.\n writeJson(join(caseDir, \"expected.roster-json.json\"), JSON.parse(exportRoster(seed, \"roster-json\")));\n\n // Text exports: always write the export golden so every fixture exercises\n // the cross-implementation byte-equality check. Only write the\n // `input.*.txt` round-trip seed when the fixture was authored for the\n // NewRecruit pipeline — legacy ListForge fixtures carry decoration\n // (multi-force warnings, leader-attachment inference) that the simple/wtc\n // exporters can't fully preserve, so the round-trip would fail\n // structurally rather than uncover a parser bug.\n const isNewRecruitSeed = existsSync(join(caseDir, \"input.newrecruit-json.json\"));\n for (const { format, inputName, goldenName } of TEXT_FORMATS) {\n const out = exportRoster(seed, format);\n writeText(join(caseDir, goldenName), out);\n if (isNewRecruitSeed) {\n writeText(join(caseDir, inputName), out);\n }\n }\n\n // Rosterizer JSON export + a derived round-trip input. The exporter is\n // deterministic and round-trips through the adapter, so emitting it as\n // both `expected.rosterizer.json` and `input.rosterizer.json` pins the\n // cross-implementation goldens and the importer regression at the same\n // time. Same NewRecruit-seed gate as the text formats — multi-force\n // ListForge fixtures lose their provisional leader-attachment under\n // round-trip, so they only get the export golden, not the derived input.\n const rosterizerOut = exportRoster(seed, \"rosterizer\");\n writeJson(join(caseDir, \"expected.rosterizer.json\"), JSON.parse(rosterizerOut));\n if (isNewRecruitSeed) {\n writeJson(join(caseDir, \"input.rosterizer.json\"), JSON.parse(rosterizerOut));\n }\n\n console.log(\n `roster/${entry.name}: ${seed.units.length} units, ${seed.diagnostics.warnings.length} warnings`,\n );\n }\n}\n\n/**\n * Linked-API query cases. Each descriptor names a query method on Dataset, the\n * args to call it with, and how the result should be compared.\n *\n * `comparison: \"ordered\"` pins the result order — used for queries that iterate\n * a data-driven array (`unit.ability_ids`, `unit.weapon_ids`) where order is\n * encoded in the data and both implementations iterate it the same way.\n *\n * `comparison: \"set\"` pins only the set of ids — used for queries that walk an\n * index (faction → abilities, ability → phases) where iteration order depends\n * on dataset bundler internals and is incidental. Ids are sorted before\n * comparison.\n *\n * `comparison: \"scalar\"` pins a single id-or-null result (find_* and\n * faction_of(unit)).\n */\ntype LinkedApiQuery =\n | { name: string; query: \"find_unit\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"find_weapon\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"find_faction\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"find_ability\"; args: { query: string }; comparison: \"scalar\" }\n | { name: string; query: \"abilities_of\"; args: { unitId: string }; comparison: \"ordered\" }\n | { name: string; query: \"weapons_of\"; args: { unitId: string }; comparison: \"ordered\" }\n | { name: string; query: \"phases_of\"; args: { abilityId: string }; comparison: \"set\" }\n | { name: string; query: \"faction_of\"; args: { unitId: string }; comparison: \"scalar\" }\n | { name: string; query: \"abilities_of_faction\"; args: { factionId: string }; comparison: \"set\" }\n | { name: string; query: \"weapons_of_faction\"; args: { factionId: string }; comparison: \"set\" }\n | { name: string; query: \"base_size_of\"; args: { unitId: string }; comparison: \"scalar\" }\n | { name: string; query: \"model_bases_of\"; args: { unitId: string }; comparison: \"ordered\" };\n\nconst LINKED_API_QUERIES: LinkedApiQuery[] = [\n // find_unit: diacritic-insensitive lookup, miss returns null.\n { name: \"find_unit by diacritic name\", query: \"find_unit\", args: { query: \"Kharn\" }, comparison: \"scalar\" },\n { name: \"find_unit miss returns null\", query: \"find_unit\", args: { query: \"not-a-real-unit-xyz\" }, comparison: \"scalar\" },\n // find_weapon: hyphen + space tolerance.\n { name: \"find_weapon by name\", query: \"find_weapon\", args: { query: \"bolt rifle\" }, comparison: \"scalar\" },\n // find_faction: punctuation/diacritic tolerance.\n { name: \"find_faction by display name\", query: \"find_faction\", args: { query: \"World Eaters\" }, comparison: \"scalar\" },\n // find_ability: ability name lookup.\n { name: \"find_ability by name\", query: \"find_ability\", args: { query: \"Berzerker Frenzy\" }, comparison: \"scalar\" },\n // abilities_of(unit): ordered, iterates unit.ability_ids array.\n { name: \"abilities_of intercessor-squad\", query: \"abilities_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"ordered\" },\n { name: \"abilities_of kharn-the-betrayer\", query: \"abilities_of\", args: { unitId: \"kharn-the-betrayer\" }, comparison: \"ordered\" },\n // weapons_of(unit): ordered, iterates unit.weapon_ids array.\n { name: \"weapons_of intercessor-squad\", query: \"weapons_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"ordered\" },\n { name: \"weapons_of kharn-the-betrayer\", query: \"weapons_of\", args: { unitId: \"kharn-the-betrayer\" }, comparison: \"ordered\" },\n // phases_of(ability): compared as set (phase index iteration order is incidental).\n { name: \"phases_of berzerker-frenzy\", query: \"phases_of\", args: { abilityId: \"berzerker-frenzy\" }, comparison: \"set\" },\n // faction_of(unit): scalar id or null.\n { name: \"faction_of intercessor-squad\", query: \"faction_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"scalar\" },\n // abilities_of_faction: compared as set (collection-index order is incidental).\n { name: \"abilities_of_faction world-eaters\", query: \"abilities_of_faction\", args: { factionId: \"world-eaters\" }, comparison: \"set\" },\n // weapons_of_faction: compared as set.\n { name: \"weapons_of_faction world-eaters\", query: \"weapons_of_faction\", args: { factionId: \"world-eaters\" }, comparison: \"set\" },\n // base_size_of(unit): scalar encoded base — round, oval, and a draft flying-base.\n { name: \"base_size_of intercessor-squad\", query: \"base_size_of\", args: { unitId: \"intercessor-squad\" }, comparison: \"scalar\" },\n { name: \"base_size_of vertus-praetors\", query: \"base_size_of\", args: { unitId: \"vertus-praetors\" }, comparison: \"scalar\" },\n { name: \"base_size_of windriders (draft flying base)\", query: \"base_size_of\", args: { unitId: \"windriders\" }, comparison: \"scalar\" },\n // model_bases_of(unit): ordered per-model bases; jakhals mixes 28.5mm bodies with a 40mm Dishonoured.\n { name: \"model_bases_of jakhals (mixed)\", query: \"model_bases_of\", args: { unitId: \"jakhals\" }, comparison: \"ordered\" },\n];\n\nfunction genLinkedApi(): void {\n const ds = Dataset.embedded();\n const cases = LINKED_API_QUERIES.map((q) => {\n const expected = runLinkedQuery(ds, q);\n return { ...q, expected };\n });\n writeJson(join(CONFORMANCE, \"linked-api\", \"cases.json\"), cases);\n console.log(`linked-api/cases.json: ${cases.length} cases`);\n}\n\nfunction runLinkedQuery(ds: Dataset, q: LinkedApiQuery): string | null | string[] {\n switch (q.query) {\n case \"find_unit\":\n return ds.units.find(q.args.query)?.id ?? null;\n case \"find_weapon\":\n return ds.weapons.find(q.args.query)?.id ?? null;\n case \"find_faction\":\n return ds.factions.find(q.args.query)?.id ?? null;\n case \"find_ability\":\n return ds.abilities.find(q.args.query)?.id ?? null;\n case \"abilities_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`abilities_of: unknown unit ${q.args.unitId}`);\n return u.abilities.map((a) => a.id);\n }\n case \"weapons_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`weapons_of: unknown unit ${q.args.unitId}`);\n return u.weapons.map((w) => w.id);\n }\n case \"phases_of\": {\n const a = ds.abilities.get(q.args.abilityId);\n if (!a) throw new Error(`phases_of: unknown ability ${q.args.abilityId}`);\n return [...a.phases].sort();\n }\n case \"faction_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`faction_of: unknown unit ${q.args.unitId}`);\n return u.faction?.id ?? null;\n }\n case \"abilities_of_faction\":\n return ds.abilities.byFaction(q.args.factionId).map((a) => a.id).sort();\n case \"weapons_of_faction\": {\n // Mirrors Rust `weapons_of_faction`: aggregate weapons across the\n // faction's units and dedupe by id. The collection-level\n // `weapons.byFaction()` is a different operation (it looks up weapons\n // whose own `faction_id` is set, which is empty for most factions).\n const f = ds.factions.get(q.args.factionId);\n if (!f) throw new Error(`weapons_of_faction: unknown faction ${q.args.factionId}`);\n return f.weapons.map((w) => w.id).sort();\n }\n case \"base_size_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`base_size_of: unknown unit ${q.args.unitId}`);\n return encodeBase(u.raw.base_size_mm);\n }\n case \"model_bases_of\": {\n const u = ds.units.get(q.args.unitId);\n if (!u) throw new Error(`model_bases_of: unknown unit ${q.args.unitId}`);\n const comp = ds.unitCompositions.find((c) => c.unit_id === q.args.unitId);\n return (comp?.models ?? []).map((m) => `${m.name}=${encodeBase(m.base_size_mm) ?? \"none\"}`);\n }\n }\n}\n\n/**\n * Attribution corpus: reuses the existing cruncher inputs from the cases that\n * carry at least one groupable buff (ability or manual). The expected shape\n * is the AttributedStage array produced by attributeStages; both\n * implementations of the leave-one-out decomposition must reproduce it\n * within the per-stage float tolerance.\n */\nconst ATTRIBUTION_CASE_FILES = [\n \"05-anti-infantry-vs-cultist.json\",\n \"07-twin-linked-heavy-stationary-vs-knight.json\",\n];\n\ninterface CruncherCaseInput {\n name: string;\n attacker: { weaponId: string; profileIndex: number };\n modelsFiring: number;\n target: { unitId: string; profileIndex: number; modelCount?: number };\n context: EngineInput[\"context\"];\n buffs: EngineInput[\"buffs\"];\n}\n\nfunction loadAttributionInput(ds: Dataset, filename: string): {\n name: string;\n input: EngineInput;\n} {\n const path = join(CONFORMANCE, \"cruncher\", filename);\n const c = JSON.parse(readFileSync(path, \"utf8\")) as CruncherCaseInput;\n const weapon = ds.weapons.get(c.attacker.weaponId);\n const unit = ds.units.get(c.target.unitId);\n if (!weapon) throw new Error(`attribution: unknown weapon ${c.attacker.weaponId}`);\n if (!unit) throw new Error(`attribution: unknown unit ${c.target.unitId}`);\n return {\n name: c.name,\n input: {\n attacker: { weapon: weapon.raw, profileIndex: c.attacker.profileIndex },\n target: {\n unit: unit.raw,\n profileIndex: c.target.profileIndex,\n ...(c.target.modelCount !== undefined ? { modelCount: c.target.modelCount } : {}),\n },\n modelsFiring: c.modelsFiring,\n buffs: c.buffs,\n context: c.context,\n },\n };\n}\n\nfunction genAttribution(): void {\n const ds = Dataset.embedded();\n const cases = ATTRIBUTION_CASE_FILES.map((filename, idx) => {\n const { name, input } = loadAttributionInput(ds, filename);\n const stages = attributeStages(input, ds);\n return {\n // Persist the input by file reference so the corpus stays a single\n // source of truth — the cruncher case file already pins the EngineInput.\n name,\n cruncher_case: filename,\n expected: stages.map((s) => ({\n name: s.name,\n expected: s.expected,\n baseline: s.baseline,\n lifts: s.lifts.map((l) => ({ source: l.source, delta: l.delta })),\n residual: s.residual,\n intrinsics: s.intrinsics,\n })),\n // Stable ordering of cases in the corpus file.\n _order: idx,\n };\n });\n // Sort by _order and strip the helper before writing.\n cases.sort((a, b) => a._order - b._order);\n const serialised = cases.map(({ _order: _o, ...rest }) => rest);\n writeJson(join(CONFORMANCE, \"attribution\", \"cases.json\"), serialised);\n console.log(`attribution/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Scoring-card translation corpus: humanize each primary mission card's\n * `awards` into plain English. The TS translator is the oracle; the Rust port\n * must reproduce every string byte-for-byte (the differ compares structurally,\n * no tolerance). Only `card_type: \"primary\"` cards are pinned — the 14-card\n * secondary deck isn't revealed yet. Cases are sorted by id for stability, and\n * the `awards` array order within each card is load-bearing.\n */\nfunction genScoringTranslation(): void {\n const ds = Dataset.embedded();\n mkdirSync(join(CONFORMANCE, \"scoring-translation\"), { recursive: true });\n // Pin the translation of every mission card's awards — primary and secondary\n // alike (the secondary deck has the same `awards` shape and deserves the same\n // cross-impl pinning).\n const cases = ds.missionCards.all\n .filter((c) => c.card_type === \"primary\" || c.card_type === \"secondary\")\n .slice()\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))\n .map((card) => ({ cardId: card.id, expected: { awards: describeScoringCard(card) } }));\n writeJson(join(CONFORMANCE, \"scoring-translation\", \"cases.json\"), cases);\n console.log(`scoring-translation/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Scoring-engine corpus: pin the pure VP arithmetic of the scoring engine\n * (`tools/src/scoring/` — the oracle) so the Rust `wh40kdc::scoring` port\n * reproduces it. Three ops, each case `{ name, op, args, expected }`:\n *\n * - `score_event` — per card and approach, assert every award matching the\n * approach (by its full-`awards`-array index). Pins `scoreAward`, `scoreTurn`\n * (exclusive-group \"highest only\", `vp_per × count` clamped to `per_max`,\n * cumulative sums), `scoreCap` (tactical 5 vs fixed `vp_max`/uncapped), and\n * `scoreSecondaryEvent`; primary cards also carry a `roundCap` to pin\n * `scorePrimaryEvent`. `cap: null` means uncapped (Infinity has no JSON form).\n * - `score_state` — replay scenarios over a `PlayerGame`, pinning the per-round\n * cap (15), per-game primary cap (45), grand-total cap (100), score+discard,\n * and undo.\n * - `wtc_result` — the 20-point band mapping across its boundaries.\n *\n * Goldens are produced by driving the TS runner's own `dispatch`, so the corpus\n * and the runner agree by construction; the cross-impl contract is the Rust\n * runner reproducing them. Integers are compared exactly (no tolerance).\n */\nfunction genScoring(): void {\n const ds = Dataset.embedded();\n mkdirSync(join(CONFORMANCE, \"scoring\"), { recursive: true });\n\n // One initialized runner state, reused across cases (the ops don't mutate it).\n const specVersion = Number.parseInt(\n readFileSync(join(CONFORMANCE, \"SPEC_VERSION\"), \"utf8\").trim(),\n 10,\n );\n const state = createRunnerState();\n const init = dispatch(state, {\n op: \"init\",\n args: { spec_version: specVersion, locale: \"C\", tz: \"UTC\", seed: 0 },\n });\n if (!init.ok) throw new Error(`gen scoring: init failed: ${JSON.stringify(init)}`);\n const run = (op: string, args: unknown): unknown => {\n const r = dispatch(state, { op, args });\n if (!r.ok) throw new Error(`gen scoring: ${op} failed: ${JSON.stringify(r)} for ${JSON.stringify(args)}`);\n return r.value;\n };\n\n type Case = { name: string; op: string; args: unknown; expected: unknown };\n const cases: Case[] = [];\n\n // score_event: every mission card, both approaches. Assert the approach's\n // awards by their full-array index; count vp_per awards to their per_max\n // (else 2) so the cap logic actually bites.\n const cards = ds.missionCards.all\n .slice()\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n for (const card of cards) {\n for (const approach of [\"fixed\", \"tactical\"] as const) {\n const asserted = awardsOf(card)\n .map((aw, index) => ({ aw, index }))\n .filter(({ aw }) => aw.mode == null || aw.mode === approach)\n .map(({ aw, index }) =>\n aw.vp_per != null ? { index, count: aw.per_max ?? 2 } : { index },\n );\n const args: Record<string, unknown> = { cardId: card.id, approach, asserted };\n if (card.card_type === \"primary\") args.roundCap = 15;\n cases.push({\n name: `score_event/${card.id}/${approach}`,\n op: \"score_event\",\n args,\n expected: run(\"score_event\", args),\n });\n }\n }\n\n // score_state: hand-authored replay scenarios. Card ids are real deck/mission\n // cards; expected state is whatever the engine produces.\n const stateScenarios: { name: string; args: unknown }[] = [\n {\n name: \"primary-round-and-game-caps\",\n args: {\n approach: \"tactical\",\n ops: [\n { kind: \"set-primary\", round: 1, vp: 30, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 2, vp: 30, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 3, vp: 30, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 4, vp: 30, roundCap: 15, gameCap: 45 },\n ],\n },\n },\n {\n // The full primary path: a card's raw round total, clamped to the round\n // cap on store, then cleared back to 0 by a set-primary 0.\n name: \"score-primary-then-clear\",\n args: {\n approach: \"tactical\",\n ops: [\n {\n kind: \"score-primary\",\n cardId: \"battlefield-dominance\",\n round: 2,\n asserted: awardsOf(ds.missionCards.get(\"battlefield-dominance\")!).map((aw, index) =>\n aw.vp_per != null ? { index, count: aw.per_max ?? 3 } : { index },\n ),\n roundCap: 15,\n gameCap: 45,\n },\n { kind: \"set-primary\", round: 3, vp: 99, roundCap: 15, gameCap: 45 },\n { kind: \"set-primary\", round: 2, vp: 0, roundCap: 15, gameCap: 45 },\n ],\n },\n },\n {\n name: \"secondary-score-and-undo\",\n args: {\n approach: \"tactical\",\n ops: [\n { kind: \"draw\", cardId: \"no-prisoners\" },\n { kind: \"score-secondary\", cardId: \"no-prisoners\", round: 2, asserted: [{ index: 0, count: 3 }] },\n { kind: \"remove-score\", index: 0 },\n ],\n },\n },\n {\n // Uncapped set-primary (no caps) overshoots so the 100 grand-total cap bites.\n name: \"grand-total-cap-at-100\",\n args: {\n approach: \"tactical\",\n ops: [\n { kind: \"set-primary\", round: 1, vp: 30 },\n { kind: \"set-primary\", round: 2, vp: 30 },\n { kind: \"set-primary\", round: 3, vp: 30 },\n { kind: \"set-primary\", round: 4, vp: 30 },\n { kind: \"set-primary\", round: 5, vp: 30 },\n { kind: \"draw\", cardId: \"no-prisoners\" },\n { kind: \"score-secondary\", cardId: \"no-prisoners\", round: 5, asserted: [{ index: 0, count: 99 }] },\n ],\n },\n },\n ];\n for (const s of stateScenarios) {\n cases.push({ name: `score_state/${s.name}`, op: \"score_state\", args: s.args, expected: run(\"score_state\", s.args) });\n }\n\n // wtc_result: band boundaries and symmetry.\n const wtcPairs: [number, number][] = [\n [50, 50],\n [48, 45],\n [45, 50],\n [56, 50],\n [50, 61],\n [100, 50],\n [100, 49],\n [0, 100],\n [60, 40],\n [55, 50],\n ];\n for (const [a, b] of wtcPairs) {\n const args = { a, b };\n cases.push({ name: `wtc_result/${a}-${b}`, op: \"wtc_result\", args, expected: run(\"wtc_result\", args) });\n }\n\n writeJson(join(CONFORMANCE, \"scoring\", \"cases.json\"), cases);\n console.log(`scoring/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Terrain-resolver corpus: resolve template-anchored layouts to absolute\n * board-space vertices (y-down inches). The TS resolver is the oracle; the Rust\n * port must reproduce every vertex within 5e-4 (per-area invariant in\n * CONFORMANCE.md). Cases are self-contained — each carries its own `templates`\n * and `layout` — so the corpus does not depend on the bundled catalog and the\n * runner op can pass both in `args`. Coverage: per-template centroid anchoring\n * (identity), cardinal + oblique rotations, both mirror axes on an asymmetric\n * shape, embedded-feature composition, explicit parenting, and the inline\n * footprint escape hatch.\n */\nfunction genTerrainResolver(): void {\n mkdirSync(join(CONFORMANCE, \"terrain-resolver\"), { recursive: true });\n\n const areaLarge: ResolverTemplate = {\n id: \"area-large\",\n name: \"Large Area\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 11.5, height: 7 },\n };\n const areaMedium: ResolverTemplate = {\n id: \"area-medium\",\n name: \"Medium Area\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 6, height: 4 },\n };\n const areaTrapezoid: ResolverTemplate = {\n id: \"area-trapezoid\",\n name: \"Trapezoid Area\",\n kind: \"area\",\n footprint: {\n type: \"polygon\",\n points: [\n { x: 0, y: 0 },\n { x: 8, y: 0 },\n { x: 2, y: 11.5 },\n { x: 0, y: 11.5 },\n ],\n },\n };\n const wedge: ResolverTemplate = {\n id: \"wedge\",\n name: \"Right Wedge\",\n kind: \"area\",\n footprint: { type: \"right-triangle\", width: 8, height: 11.5 },\n };\n const wallLong: ResolverTemplate = {\n id: \"wall-long\",\n name: \"Long Wall\",\n kind: \"feature\",\n footprint: { type: \"rectangle\", width: 7, height: 0.25 },\n };\n const ruinComposed: ResolverTemplate = {\n id: \"ruin-composed\",\n name: \"Composed Ruin\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 11.5, height: 7 },\n features: [\n { id: \"back-wall\", template: \"wall-long\", position: { x: 0, y: -3 } },\n { id: \"side-wall\", template: \"wall-long\", position: { x: -5, y: 0 }, rotation_degrees: 90, mirror: \"horizontal\" },\n ],\n };\n\n const baseCatalog = [areaLarge, areaMedium, areaTrapezoid, wedge, wallLong];\n\n const layoutCases: { name: string; templates: ResolverTemplate[]; layout: ResolverLayout }[] = [\n {\n name: \"identity-large\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-large\", position: { x: 30, y: 22 } }] },\n },\n {\n name: \"identity-wedge\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"wedge\", position: { x: 12, y: 30 } }] },\n },\n {\n name: \"identity-trapezoid\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 40, y: 18 } }] },\n },\n {\n name: \"rotate-medium-90\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-medium\", position: { x: 30, y: 22 }, rotation_degrees: 90 }] },\n },\n {\n name: \"rotate-medium-180\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-medium\", position: { x: 30, y: 22 }, rotation_degrees: 180 }] },\n },\n {\n name: \"rotate-medium-270\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-medium\", position: { x: 30, y: 22 }, rotation_degrees: 270 }] },\n },\n {\n name: \"rotate-large-oblique-55\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-large\", position: { x: 30, y: 22 }, rotation_degrees: 55 }] },\n },\n {\n name: \"rotate-trapezoid-oblique-235\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 35.75, y: 27 }, rotation_degrees: 235 }] },\n },\n {\n name: \"mirror-trapezoid-horizontal\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 40, y: 18 }, mirror: \"horizontal\" }] },\n },\n {\n name: \"mirror-trapezoid-vertical-rot90\",\n templates: baseCatalog,\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"p\", template: \"area-trapezoid\", position: { x: 40, y: 18 }, rotation_degrees: 90, mirror: \"vertical\" }] },\n },\n {\n name: \"composition-ruin-rot90-mirror-h\",\n templates: [ruinComposed, wallLong],\n layout: { id: \"c\", name: \"c\", pieces: [{ id: \"a1\", template: \"ruin-composed\", position: { x: 30, y: 22 }, rotation_degrees: 90, mirror: \"horizontal\" }] },\n },\n {\n name: \"explicit-parent-feature\",\n templates: [areaLarge, wallLong],\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n { id: \"a1\", template: \"area-large\", position: { x: 30, y: 22 }, rotation_degrees: 90, mirror: \"horizontal\" },\n { id: \"back-wall\", template: \"wall-long\", parent_area_id: \"a1\", position: { x: 0, y: -3 } },\n ],\n },\n },\n {\n name: \"inline-footprint-polygon\",\n templates: [],\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n footprint: { type: \"polygon\", points: [{ x: 0, y: 0 }, { x: 4, y: 0 }, { x: 2, y: 5 }] },\n position: { x: 50, y: 40 },\n rotation_degrees: 30,\n },\n ],\n },\n },\n ];\n\n const cases = layoutCases.map((c) => ({\n name: c.name,\n templates: c.templates,\n layout: c.layout,\n expected: { pieces: resolveLayout(c.layout, c.templates) },\n }));\n writeJson(join(CONFORMANCE, \"terrain-resolver\", \"cases.json\"), cases);\n console.log(`terrain-resolver/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Terrain-keystones corpus: derive the printed distance of each authored\n * keystone (board edge → piece feature) from resolved geometry. The TS helper\n * is the oracle; the Rust port must reproduce every distance within 5e-4.\n * Cases are self-contained like the resolver corpus. Coverage: all four\n * edges, vertex and bounding-face refs, an oblique rotation, a mirrored\n * asymmetric shape, a parented feature (composition through the parent\n * frame), an inline footprint, and a custom board size.\n */\nfunction genTerrainKeystones(): void {\n mkdirSync(join(CONFORMANCE, \"terrain-keystones\"), { recursive: true });\n\n const areaLarge: ResolverTemplate = {\n id: \"area-large\",\n name: \"Large Area\",\n kind: \"area\",\n footprint: { type: \"rectangle\", width: 11.5, height: 7 },\n };\n const areaTrapezoid: ResolverTemplate = {\n id: \"area-trapezoid\",\n name: \"Trapezoid Area\",\n kind: \"area\",\n footprint: {\n type: \"polygon\",\n points: [\n { x: 0, y: 0 },\n { x: 8, y: 0 },\n { x: 2, y: 11.5 },\n { x: 0, y: 11.5 },\n ],\n },\n };\n const wallLong: ResolverTemplate = {\n id: \"wall-long\",\n name: \"Long Wall\",\n kind: \"feature\",\n footprint: { type: \"rectangle\", width: 7, height: 0.25 },\n };\n const catalog = [areaLarge, areaTrapezoid, wallLong];\n\n const keystoneCases: {\n name: string;\n templates: ResolverTemplate[];\n layout: ResolverLayout;\n board?: { width: number; height: number };\n }[] = [\n {\n name: \"identity-four-edges-vertices\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-large\",\n position: { x: 30, y: 22 },\n keystones: [\n { edge: \"left\", ref: { kind: \"vertex\", index: 0 } },\n { edge: \"top\", ref: { kind: \"vertex\", index: 1 } },\n { edge: \"right\", ref: { kind: \"vertex\", index: 2 } },\n { edge: \"bottom\", ref: { kind: \"vertex\", index: 3 } },\n ],\n },\n ],\n },\n },\n {\n name: \"identity-bounding-faces\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-large\",\n position: { x: 20, y: 30 },\n keystones: [\n { edge: \"left\", ref: { kind: \"face\", side: \"min-x\" } },\n { edge: \"right\", ref: { kind: \"face\", side: \"max-x\" } },\n { edge: \"top\", ref: { kind: \"face\", side: \"min-y\" } },\n { edge: \"bottom\", ref: { kind: \"face\", side: \"max-y\" } },\n ],\n },\n ],\n },\n },\n {\n name: \"oblique-rotation-vertex\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-trapezoid\",\n position: { x: 35.75, y: 27 },\n rotation_degrees: 235,\n keystones: [\n { edge: \"left\", ref: { kind: \"vertex\", index: 2 } },\n { edge: \"bottom\", ref: { kind: \"face\", side: \"max-y\" } },\n ],\n },\n ],\n },\n },\n {\n name: \"mirrored-trapezoid-vertex\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-trapezoid\",\n position: { x: 40, y: 18 },\n mirror: \"horizontal\",\n keystones: [\n { edge: \"right\", ref: { kind: \"vertex\", index: 1 } },\n { edge: \"top\", ref: { kind: \"vertex\", index: 0 } },\n ],\n },\n ],\n },\n },\n {\n name: \"parented-feature-keystone\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"a1\",\n template: \"area-large\",\n position: { x: 30, y: 22 },\n rotation_degrees: 90,\n mirror: \"horizontal\",\n keystones: [{ edge: \"left\", ref: { kind: \"vertex\", index: 0 } }],\n },\n {\n id: \"back-wall\",\n template: \"wall-long\",\n parent_area_id: \"a1\",\n position: { x: 0, y: -3 },\n keystones: [\n { edge: \"top\", ref: { kind: \"vertex\", index: 1 } },\n { edge: \"right\", ref: { kind: \"face\", side: \"max-x\" } },\n ],\n },\n ],\n },\n },\n {\n name: \"inline-footprint-keystone\",\n templates: [],\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n footprint: { type: \"polygon\", points: [{ x: 0, y: 0 }, { x: 4, y: 0 }, { x: 2, y: 5 }] },\n position: { x: 50, y: 40 },\n rotation_degrees: 30,\n keystones: [\n { edge: \"right\", ref: { kind: \"vertex\", index: 0 } },\n { edge: \"bottom\", ref: { kind: \"vertex\", index: 2 } },\n ],\n },\n ],\n },\n },\n {\n name: \"custom-board-extents\",\n templates: catalog,\n layout: {\n id: \"c\",\n name: \"c\",\n pieces: [\n {\n id: \"p\",\n template: \"area-large\",\n position: { x: 15, y: 15 },\n keystones: [\n { edge: \"right\", ref: { kind: \"face\", side: \"max-x\" } },\n { edge: \"bottom\", ref: { kind: \"face\", side: \"max-y\" } },\n ],\n },\n ],\n },\n board: { width: 30, height: 22.4 },\n },\n ];\n\n const cases = keystoneCases.map((c) => ({\n name: c.name,\n templates: c.templates,\n layout: c.layout,\n ...(c.board ? { board: c.board } : {}),\n expected: {\n measurements: keystoneMeasurements(c.layout, c.templates, c.board ?? BOARD_INCHES),\n },\n }));\n writeJson(join(CONFORMANCE, \"terrain-keystones\", \"cases.json\"), cases);\n console.log(`terrain-keystones/cases.json: ${cases.length} cases`);\n}\n\n/**\n * Effect-translation corpus: pin the Ability-DSL effect describer\n * (`describeEffect`/`describeAbility` — the \"ability.print()\") across the TS\n * and Rust ports. Cases embed the raw `effect` (+ `scope`) so parity does not\n * depend on collection dup-id resolution; selection greedily covers every\n * effect node type at least once (up to 5 exemplars per type) over the\n * id-sorted ability list, so the corpus stays small but exhaustive by shape.\n */\nfunction genEffectTranslation(): void {\n const ds = Dataset.embedded();\n mkdirSync(join(CONFORMANCE, \"effect-translation\"), { recursive: true });\n\n const collectTypes = (e: unknown, out: Set<string>): void => {\n if (Array.isArray(e)) {\n for (const v of e) collectTypes(v, out);\n return;\n }\n if (typeof e !== \"object\" || e === null) return;\n const rec = e as Record<string, unknown>;\n if (typeof rec.type === \"string\") out.add(rec.type);\n for (const key of [\"effect\", \"on_success\", \"on_fail\", \"steps\", \"options\", \"condition\"]) {\n if (key in rec) collectTypes(rec[key], out);\n }\n };\n\n const abilities = ds.abilities.all\n .slice()\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n\n const seen = new Map<string, number>();\n const CAP = 5;\n const cases: unknown[] = [];\n for (const a of abilities) {\n const types = new Set<string>();\n collectTypes(a.raw.effect, types);\n let fresh = false;\n for (const t of types) {\n if ((seen.get(t) ?? 0) < CAP) fresh = true;\n }\n if (!fresh) continue;\n for (const t of types) seen.set(t, (seen.get(t) ?? 0) + 1);\n cases.push({\n caseId: `${a.id}#${cases.length}`,\n effect: a.raw.effect,\n scope: a.raw.scope ?? null,\n expected: { text: describeAbility({ effect: a.raw.effect as Effect, scope: a.raw.scope }) },\n });\n }\n writeJson(join(CONFORMANCE, \"effect-translation\", \"cases.json\"), cases);\n console.log(`effect-translation/cases.json: ${cases.length} cases (${seen.size} node types)`);\n}\n\ngenNormalize();\ngenRosters();\ngenLinkedApi();\ngenAttribution();\ngenScoringTranslation();\ngenEffectTranslation();\ngenScoring();\ngenTerrainResolver();\ngenTerrainKeystones();\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../src/import/decode.ts"],"names":[],"mappings":"AA6CA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA+BtD"}
1
+ {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../src/import/decode.ts"],"names":[],"mappings":"AA6DA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA+BtD"}
@@ -12,11 +12,27 @@
12
12
  * - a bare base64 segment,
13
13
  * - an already-decoded JSON string (passed straight to `JSON.parse`).
14
14
  *
15
- * Only `node:zlib` is used no third-party dependency.
15
+ * Decompression uses `fflate` (a tiny, dependency-free inflate) rather than
16
+ * `node:zlib` so the importer works in browsers as well as Node — this module
17
+ * is reachable from the package's root barrel and must stay universal.
16
18
  *
17
19
  * @packageDocumentation
18
20
  */
19
- import { gunzipSync } from "node:zlib";
21
+ import { gunzipSync } from "fflate";
22
+ /**
23
+ * Universal base64 → bytes. Node decodes via Buffer; browsers via atob.
24
+ * (`Uint8Array.fromBase64` is still too new to rely on.)
25
+ */
26
+ function base64ToBytes(b64) {
27
+ if (typeof Buffer !== "undefined") {
28
+ return new Uint8Array(Buffer.from(b64, "base64"));
29
+ }
30
+ const binary = atob(b64);
31
+ const bytes = new Uint8Array(binary.length);
32
+ for (let i = 0; i < binary.length; i += 1)
33
+ bytes[i] = binary.charCodeAt(i);
34
+ return bytes;
35
+ }
20
36
  /** The base64 prefix every ListForge gzip payload begins with. */
21
37
  const GZIP_BASE64_PREFIX = "H4sIA";
22
38
  /** The path marker ListForge uses ahead of the payload. */
@@ -60,8 +76,8 @@ export function decodeListForge(input) {
60
76
  }
61
77
  let json;
62
78
  try {
63
- const bytes = Buffer.from(segment, "base64");
64
- json = gunzipSync(bytes).toString("utf8");
79
+ const bytes = base64ToBytes(segment);
80
+ json = new TextDecoder().decode(gunzipSync(bytes));
65
81
  }
66
82
  catch (cause) {
67
83
  throw new Error("decodeListForge: failed to gunzip base64 payload", {
@@ -1 +1 @@
1
- {"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/import/decode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,kEAAkE;AAClE,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAEnC,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAEvC;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpD,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,mCAAmC;IACnC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,wEAAwE;YACtE,4CAA4C,kBAAkB,KAAK,CACtE,CAAC;IACJ,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kDAAkD,EAAE;YAClE,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["/**\n * Decode a ListForge share payload into a JSON object.\n *\n * ListForge packs a roster as `base64( gzip( utf8(json) ) )` and embeds it in a\n * URL hash fragment: `https://app/#/listforge/<BASE64>`. The fragment is used\n * deliberately so browsers never send it to a server, preserving the payload\n * verbatim. A valid gzipped payload always base64-encodes to a string starting\n * with `H4sIAAAAAAAAA`.\n *\n * {@link decodeListForge} accepts any of three forms and returns the parsed JSON:\n * - a full URL (the segment after the last `/` is taken),\n * - a bare base64 segment,\n * - an already-decoded JSON string (passed straight to `JSON.parse`).\n *\n * Only `node:zlib` is usedno third-party dependency.\n *\n * @packageDocumentation\n */\nimport { gunzipSync } from \"node:zlib\";\n\n/** The base64 prefix every ListForge gzip payload begins with. */\nconst GZIP_BASE64_PREFIX = \"H4sIA\";\n\n/** The path marker ListForge uses ahead of the payload. */\nconst LISTFORGE_MARKER = \"/listforge/\";\n\n/**\n * Extract the payload segment from an input that may be a URL.\n *\n * The base64 alphabet includes `/`, so a bare base64 segment cannot be split on\n * `/`. We only treat the input as a URL when it carries the `/listforge/` marker\n * or an `http(s)://` scheme; otherwise it is returned unchanged.\n */\nfunction extractSegment(input: string): string {\n const markerIndex = input.indexOf(LISTFORGE_MARKER);\n if (markerIndex !== -1) {\n return input.slice(markerIndex + LISTFORGE_MARKER.length);\n }\n if (/^https?:\\/\\//i.test(input)) {\n const lastSlash = input.lastIndexOf(\"/\");\n return lastSlash === -1 ? input : input.slice(lastSlash + 1);\n }\n return input;\n}\n\n/**\n * Decode a ListForge payload (URL, bare base64, or raw JSON) into a JSON value.\n *\n * @throws if the input is neither valid JSON nor a decodable gzip payload.\n */\nexport function decodeListForge(input: string): unknown {\n const trimmed = input.trim();\n if (trimmed === \"\") {\n throw new Error(\"decodeListForge: empty input\");\n }\n\n // Raw JSON object passed directly.\n if (trimmed.startsWith(\"{\")) {\n return JSON.parse(trimmed);\n }\n\n const segment = extractSegment(trimmed);\n\n if (!segment.startsWith(GZIP_BASE64_PREFIX)) {\n throw new Error(\n \"decodeListForge: input is not a ListForge payload (expected raw JSON, \" +\n `or a gzip+base64 segment beginning with \"${GZIP_BASE64_PREFIX}…\")`,\n );\n }\n\n let json: string;\n try {\n const bytes = Buffer.from(segment, \"base64\");\n json = gunzipSync(bytes).toString(\"utf8\");\n } catch (cause) {\n throw new Error(\"decodeListForge: failed to gunzip base64 payload\", {\n cause,\n });\n }\n\n return JSON.parse(json);\n}\n"]}
1
+ {"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/import/decode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;GAGG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kEAAkE;AAClE,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAEnC,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAEvC;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpD,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,mCAAmC;IACnC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,wEAAwE;YACtE,4CAA4C,kBAAkB,KAAK,CACtE,CAAC;IACJ,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kDAAkD,EAAE;YAClE,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC","sourcesContent":["/**\n * Decode a ListForge share payload into a JSON object.\n *\n * ListForge packs a roster as `base64( gzip( utf8(json) ) )` and embeds it in a\n * URL hash fragment: `https://app/#/listforge/<BASE64>`. The fragment is used\n * deliberately so browsers never send it to a server, preserving the payload\n * verbatim. A valid gzipped payload always base64-encodes to a string starting\n * with `H4sIAAAAAAAAA`.\n *\n * {@link decodeListForge} accepts any of three forms and returns the parsed JSON:\n * - a full URL (the segment after the last `/` is taken),\n * - a bare base64 segment,\n * - an already-decoded JSON string (passed straight to `JSON.parse`).\n *\n * Decompression uses `fflate` (a tiny, dependency-free inflate) rather than\n * `node:zlib` so the importer works in browsers as well as Node this module\n * is reachable from the package's root barrel and must stay universal.\n *\n * @packageDocumentation\n */\nimport { gunzipSync } from \"fflate\";\n\n/**\n * Universal base64 → bytes. Node decodes via Buffer; browsers via atob.\n * (`Uint8Array.fromBase64` is still too new to rely on.)\n */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof Buffer !== \"undefined\") {\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n }\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\n/** The base64 prefix every ListForge gzip payload begins with. */\nconst GZIP_BASE64_PREFIX = \"H4sIA\";\n\n/** The path marker ListForge uses ahead of the payload. */\nconst LISTFORGE_MARKER = \"/listforge/\";\n\n/**\n * Extract the payload segment from an input that may be a URL.\n *\n * The base64 alphabet includes `/`, so a bare base64 segment cannot be split on\n * `/`. We only treat the input as a URL when it carries the `/listforge/` marker\n * or an `http(s)://` scheme; otherwise it is returned unchanged.\n */\nfunction extractSegment(input: string): string {\n const markerIndex = input.indexOf(LISTFORGE_MARKER);\n if (markerIndex !== -1) {\n return input.slice(markerIndex + LISTFORGE_MARKER.length);\n }\n if (/^https?:\\/\\//i.test(input)) {\n const lastSlash = input.lastIndexOf(\"/\");\n return lastSlash === -1 ? input : input.slice(lastSlash + 1);\n }\n return input;\n}\n\n/**\n * Decode a ListForge payload (URL, bare base64, or raw JSON) into a JSON value.\n *\n * @throws if the input is neither valid JSON nor a decodable gzip payload.\n */\nexport function decodeListForge(input: string): unknown {\n const trimmed = input.trim();\n if (trimmed === \"\") {\n throw new Error(\"decodeListForge: empty input\");\n }\n\n // Raw JSON object passed directly.\n if (trimmed.startsWith(\"{\")) {\n return JSON.parse(trimmed);\n }\n\n const segment = extractSegment(trimmed);\n\n if (!segment.startsWith(GZIP_BASE64_PREFIX)) {\n throw new Error(\n \"decodeListForge: input is not a ListForge payload (expected raw JSON, \" +\n `or a gzip+base64 segment beginning with \"${GZIP_BASE64_PREFIX}…\")`,\n );\n }\n\n let json: string;\n try {\n const bytes = base64ToBytes(segment);\n json = new TextDecoder().decode(gunzipSync(bytes));\n } catch (cause) {\n throw new Error(\"decodeListForge: failed to gunzip base64 payload\", {\n cause,\n });\n }\n\n return JSON.parse(json);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"import-roster.d.ts","sourceRoot":"","sources":["../../src/import/import-roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAalD,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA2BvD,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAG/E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAUhF;AAyBD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAM/E;AAMD,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAC3B,aAAa,GACb,eAAe,GACf,oBAAoB,GACpB,cAAc,CAAC;AAEnB,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,YAAY,CAAC;IACjB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;IACjB;6DACyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAClD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAWN;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,aAAkB,GACvB,YAAY,CA+Dd;AAED;uCACuC;AACvC,eAAO,MAAM,mBAAmB,EAAE,SAAS,aAAa,EAAa,CAAC"}
1
+ {"version":3,"file":"import-roster.d.ts","sourceRoot":"","sources":["../../src/import/import-roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAclD,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA8BvD,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAG/E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAUhF;AAyBD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAM/E;AAMD,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAC3B,aAAa,GACb,eAAe,GACf,oBAAoB,GACpB,cAAc,CAAC;AAEnB,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,YAAY,CAAC;IACjB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;IACjB;6DACyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAClD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAWN;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,aAAkB,GACvB,YAAY,CA+Dd;AAED;uCACuC;AACvC,eAAO,MAAM,mBAAmB,EAAE,SAAS,aAAa,EAAa,CAAC"}
@@ -15,6 +15,7 @@ import { selectAdapter } from "./adapter.js";
15
15
  import { decodeListForge } from "./decode.js";
16
16
  import { gwAdapter } from "./gw.js";
17
17
  import { listForgeAdapter } from "./listforge.js";
18
+ import { listForgeTextAdapter } from "./listforge-text.js";
18
19
  import { newRecruitJsonAdapter } from "./newrecruit-json.js";
19
20
  import { newRecruitSimpleAdapter } from "./newrecruit-simple.js";
20
21
  import { newRecruitWtcCompactAdapter, newRecruitWtcFullAdapter, } from "./newrecruit-wtc.js";
@@ -26,12 +27,14 @@ import { rosterizerAdapter } from "./rosterizer.js";
26
27
  * NewRecruit-JSON runs ahead of ListForge because both recognise a
27
28
  * `roster.forces` BattleScribe payload, and the NewRecruit signature is more
28
29
  * specific (`xmlns: rosterSchema` or `generatedBy: newrecruit.eu`). The text
29
- * adapters (`gw` / `wtc-compact` / `wtc-full` / `simple`) only match strings and
30
- * disambiguate among themselves via structural cues, so their order amongst
31
- * each other doesn't matter; wtc-full goes before wtc-compact because its
32
- * matcher is the more specific of the two. GW shares the WTC summary header but
33
- * carries `•` bullets and no `N with` lines, so it stays disjoint from both wtc
34
- * matchers. Rosterizer rides at the top of the JSON dispatch — its `rulebook` +
30
+ * adapters (`gw` / `wtc-compact` / `wtc-full` / `simple` / `listforge-text`)
31
+ * only match strings and disambiguate among themselves via structural cues, so
32
+ * their order amongst each other doesn't matter; wtc-full goes before
33
+ * wtc-compact because its matcher is the more specific of the two. GW shares
34
+ * the WTC summary header but carries `•` bullets and no `N with` lines, so it
35
+ * stays disjoint from both wtc matchers; listforge-text requires the
36
+ * `name - faction - detachment (N Points)` first line none of the others
37
+ * accept. Rosterizer rides at the top of the JSON dispatch — its `rulebook` +
35
38
  * `snapshot` signature is structurally distinct from the BattleScribe
36
39
  * `roster.forces` shape.
37
40
  */
@@ -42,6 +45,7 @@ const ADAPTERS = [
42
45
  newRecruitWtcFullAdapter,
43
46
  newRecruitWtcCompactAdapter,
44
47
  newRecruitSimpleAdapter,
48
+ listForgeTextAdapter,
45
49
  listForgeAdapter,
46
50
  ];
47
51
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"import-roster.js","sourceRoot":"","sources":["../../src/import/import-roster.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Orchestrates an army-list import: decode → parse → resolve.\n *\n * The adapter seam ({@link FormatAdapter}) lets every supported source format\n * plug in here without touching {@link decode} or {@link resolve}. Adapters are\n * registered in priority order, and every adapter's `matches()` predicate is\n * tight enough that **at most one** matches any given decoded payload —\n * {@link tryImportRoster} relies on that disjointness to short-circuit on the\n * first match.\n *\n * @packageDocumentation\n */\nimport { Dataset } from \"../data/dataset.js\";\nimport type { FormatAdapter } from \"./adapter.js\";\nimport { selectAdapter } from \"./adapter.js\";\nimport { decodeListForge } from \"./decode.js\";\nimport { gwAdapter } from \"./gw.js\";\nimport { listForgeAdapter } from \"./listforge.js\";\nimport { newRecruitJsonAdapter } from \"./newrecruit-json.js\";\nimport { newRecruitSimpleAdapter } from \"./newrecruit-simple.js\";\nimport {\n newRecruitWtcCompactAdapter,\n newRecruitWtcFullAdapter,\n} from \"./newrecruit-wtc.js\";\nimport { resolve } from \"./resolve.js\";\nimport { rosterizerAdapter } from \"./rosterizer.js\";\nimport type { Roster, RosterFormat } from \"./types.js\";\n\n/**\n * Adapters available to {@link importRoster}, in match-priority order.\n *\n * NewRecruit-JSON runs ahead of ListForge because both recognise a\n * `roster.forces` BattleScribe payload, and the NewRecruit signature is more\n * specific (`xmlns: rosterSchema` or `generatedBy: newrecruit.eu`). The text\n * adapters (`gw` / `wtc-compact` / `wtc-full` / `simple`) only match strings and\n * disambiguate among themselves via structural cues, so their order amongst\n * each other doesn't matter; wtc-full goes before wtc-compact because its\n * matcher is the more specific of the two. GW shares the WTC summary header but\n * carries `•` bullets and no `N with` lines, so it stays disjoint from both wtc\n * matchers. Rosterizer rides at the top of the JSON dispatch — its `rulebook` +\n * `snapshot` signature is structurally distinct from the BattleScribe\n * `roster.forces` shape.\n */\nconst ADAPTERS: readonly FormatAdapter[] = [\n rosterizerAdapter,\n newRecruitJsonAdapter,\n gwAdapter,\n newRecruitWtcFullAdapter,\n newRecruitWtcCompactAdapter,\n newRecruitSimpleAdapter,\n listForgeAdapter,\n];\n\nexport interface ImportOptions {\n /** Dataset to resolve against. Defaults to the package's embedded dataset. */\n dataset?: Dataset;\n}\n\n/**\n * Import a ListForge share payload into a resolved 40kdc {@link Roster}.\n *\n * `input` may be a full ListForge URL, a bare base64 segment, or an\n * already-decoded JSON string — all are handled transparently. For NewRecruit\n * sources, use {@link importNewRecruit} (no base64/gzip decode).\n */\nexport function importListForge(input: string, opts: ImportOptions = {}): Roster {\n const decoded = decodeListForge(input);\n return importRoster(decoded, opts);\n}\n\n/**\n * Import a NewRecruit export (any of the four formats — JSON, wtc-compact,\n * wtc-full, simple) into a resolved 40kdc {@link Roster}.\n *\n * The JSON form is parsed when `input` is valid JSON; the text forms are\n * dispatched on string content. No base64/gzip decoding is attempted —\n * NewRecruit exports are not encoded.\n */\nexport function importNewRecruit(input: string, opts: ImportOptions = {}): Roster {\n const trimmed = input.trimStart();\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n return importRoster(JSON.parse(input), opts);\n } catch {\n // Fall through to treating the input as raw text.\n }\n }\n return importRoster(input, opts);\n}\n\n/**\n * Import an already-decoded payload. Selects the matching format adapter and\n * resolves the result against the dataset. Accepts either a parsed JSON object\n * (NewRecruit JSON / ListForge) or a string (the three NewRecruit text formats).\n */\n/**\n * Detect an already-resolved canonical {@link Roster} (the JSON shape produced\n * by `rosterJsonSerializer`). Lets a downstream consumer round-trip canonical\n * Roster JSON through `importRoster` without going through an adapter.\n */\nfunction isCanonicalRoster(decoded: unknown): decoded is Roster {\n if (typeof decoded !== \"object\" || decoded === null) return false;\n const r = decoded as Record<string, unknown>;\n const source = r.source as Record<string, unknown> | undefined;\n return (\n typeof source === \"object\" &&\n source !== null &&\n typeof source.format === \"string\" &&\n Array.isArray(r.units) &&\n \"diagnostics\" in r\n );\n}\n\nexport function importRoster(decoded: unknown, opts: ImportOptions = {}): Roster {\n if (isCanonicalRoster(decoded)) return decoded;\n const ds = opts.dataset ?? Dataset.embedded();\n const adapter = selectAdapter(decoded, [...ADAPTERS]);\n const parsed = adapter.parse(decoded);\n return resolve(parsed, ds, adapter.id);\n}\n\n// ---------------------------------------------------------------------------\n// tryImportRoster — single string-in, structured-result-out entry point.\n// ---------------------------------------------------------------------------\n\n/** Why a {@link tryImportRoster} call did not produce a roster. */\nexport type ImportFailureReason =\n | \"empty-input\"\n | \"decode-failed\"\n | \"no-adapter-matched\"\n | \"parse-failed\";\n\n/** Per-adapter outcome from a {@link tryImportRoster} dispatch. */\nexport interface AdapterTrial {\n id: RosterFormat;\n /** True iff this adapter's `matches()` predicate accepted the decoded input. */\n matched: boolean;\n /** Present when {@link matched} is true and `parse()` then threw — the matcher\n * violated its contract. Absent for clean rejections. */\n reason?: string;\n}\n\n/** Discriminated result returned by {@link tryImportRoster}. */\nexport type ImportResult =\n | { ok: true; roster: Roster; format: RosterFormat }\n | {\n ok: false;\n reason: ImportFailureReason;\n message: string;\n trials: AdapterTrial[];\n };\n\n/** Cheap predicate: does the input look like ListForge's URL-or-base64 wrapper? */\nfunction looksLikeListForgeEncoded(input: string): boolean {\n if (input.includes(\"/listforge/\")) return true;\n if (/^https?:\\/\\//i.test(input)) return true;\n // Every gzip-then-base64 payload starts with this prefix.\n if (input.startsWith(\"H4sIA\")) return true;\n return false;\n}\n\n/**\n * Auto-detect and import any supported roster format from a single string.\n *\n * Pipeline:\n * 1. Empty input → `empty-input`.\n * 2. Looks like a ListForge URL / base64 payload → decode (base64 + gunzip + JSON.parse).\n * 3. Looks like raw JSON (starts with `{`/`[`) → JSON.parse.\n * 4. Otherwise treat as text.\n * 5. Greedy first-match adapter dispatch. The first adapter whose `matches()`\n * accepts the decoded value wins; subsequent adapters are not tried.\n * 6. If the matched adapter's `parse()` throws, that's a matcher contract\n * violation — surfaced as `parse-failed`, not silently retried.\n *\n * Caller never sees an exception; the discriminated {@link ImportResult} carries\n * either the resolved {@link Roster} (with the detected {@link RosterFormat})\n * or a typed failure plus per-adapter trial info for diagnostics.\n *\n * Prefer this over {@link importListForge} / {@link importNewRecruit} when the\n * caller doesn't know which format the user pasted.\n */\nexport function tryImportRoster(\n input: string,\n opts: ImportOptions = {},\n): ImportResult {\n const trimmed = input.trim();\n if (trimmed === \"\") {\n return { ok: false, reason: \"empty-input\", message: \"input is empty\", trials: [] };\n }\n\n let decoded: unknown;\n if (looksLikeListForgeEncoded(trimmed)) {\n try {\n decoded = decodeListForge(trimmed);\n } catch (err) {\n const message = (err as Error).message;\n return {\n ok: false,\n reason: \"decode-failed\",\n message: `failed to decode ListForge payload: ${message}`,\n trials: [{ id: \"listforge\", matched: false, reason: message }],\n };\n }\n } else if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n decoded = JSON.parse(trimmed);\n } catch (err) {\n return {\n ok: false,\n reason: \"decode-failed\",\n message: `input looks like JSON but failed to parse: ${(err as Error).message}`,\n trials: [],\n };\n }\n } else {\n decoded = input;\n }\n\n const ds = opts.dataset ?? Dataset.embedded();\n const trials: AdapterTrial[] = [];\n for (const adapter of ADAPTERS) {\n if (!adapter.matches(decoded)) {\n trials.push({ id: adapter.id, matched: false });\n continue;\n }\n try {\n const parsed = adapter.parse(decoded);\n const roster = resolve(parsed, ds, adapter.id);\n return { ok: true, roster, format: adapter.id };\n } catch (err) {\n const message = (err as Error).message;\n trials.push({ id: adapter.id, matched: true, reason: message });\n return {\n ok: false,\n reason: \"parse-failed\",\n message: `${adapter.id}: ${message}`,\n trials,\n };\n }\n }\n\n return {\n ok: false,\n reason: \"no-adapter-matched\",\n message: `tried ${ADAPTERS.length} formats, none recognised the input`,\n trials,\n };\n}\n\n/** The adapter list, exposed for tests that need to walk every matcher (e.g.\n * the disjointness invariant test). */\nexport const REGISTERED_ADAPTERS: readonly FormatAdapter[] = ADAPTERS;\n"]}
1
+ {"version":3,"file":"import-roster.js","sourceRoot":"","sources":["../../src/import/import-roster.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Orchestrates an army-list import: decode → parse → resolve.\n *\n * The adapter seam ({@link FormatAdapter}) lets every supported source format\n * plug in here without touching {@link decode} or {@link resolve}. Adapters are\n * registered in priority order, and every adapter's `matches()` predicate is\n * tight enough that **at most one** matches any given decoded payload —\n * {@link tryImportRoster} relies on that disjointness to short-circuit on the\n * first match.\n *\n * @packageDocumentation\n */\nimport { Dataset } from \"../data/dataset.js\";\nimport type { FormatAdapter } from \"./adapter.js\";\nimport { selectAdapter } from \"./adapter.js\";\nimport { decodeListForge } from \"./decode.js\";\nimport { gwAdapter } from \"./gw.js\";\nimport { listForgeAdapter } from \"./listforge.js\";\nimport { listForgeTextAdapter } from \"./listforge-text.js\";\nimport { newRecruitJsonAdapter } from \"./newrecruit-json.js\";\nimport { newRecruitSimpleAdapter } from \"./newrecruit-simple.js\";\nimport {\n newRecruitWtcCompactAdapter,\n newRecruitWtcFullAdapter,\n} from \"./newrecruit-wtc.js\";\nimport { resolve } from \"./resolve.js\";\nimport { rosterizerAdapter } from \"./rosterizer.js\";\nimport type { Roster, RosterFormat } from \"./types.js\";\n\n/**\n * Adapters available to {@link importRoster}, in match-priority order.\n *\n * NewRecruit-JSON runs ahead of ListForge because both recognise a\n * `roster.forces` BattleScribe payload, and the NewRecruit signature is more\n * specific (`xmlns: rosterSchema` or `generatedBy: newrecruit.eu`). The text\n * adapters (`gw` / `wtc-compact` / `wtc-full` / `simple` / `listforge-text`)\n * only match strings and disambiguate among themselves via structural cues, so\n * their order amongst each other doesn't matter; wtc-full goes before\n * wtc-compact because its matcher is the more specific of the two. GW shares\n * the WTC summary header but carries `•` bullets and no `N with` lines, so it\n * stays disjoint from both wtc matchers; listforge-text requires the\n * `name - faction - detachment (N Points)` first line none of the others\n * accept. Rosterizer rides at the top of the JSON dispatch — its `rulebook` +\n * `snapshot` signature is structurally distinct from the BattleScribe\n * `roster.forces` shape.\n */\nconst ADAPTERS: readonly FormatAdapter[] = [\n rosterizerAdapter,\n newRecruitJsonAdapter,\n gwAdapter,\n newRecruitWtcFullAdapter,\n newRecruitWtcCompactAdapter,\n newRecruitSimpleAdapter,\n listForgeTextAdapter,\n listForgeAdapter,\n];\n\nexport interface ImportOptions {\n /** Dataset to resolve against. Defaults to the package's embedded dataset. */\n dataset?: Dataset;\n}\n\n/**\n * Import a ListForge share payload into a resolved 40kdc {@link Roster}.\n *\n * `input` may be a full ListForge URL, a bare base64 segment, or an\n * already-decoded JSON string — all are handled transparently. For NewRecruit\n * sources, use {@link importNewRecruit} (no base64/gzip decode).\n */\nexport function importListForge(input: string, opts: ImportOptions = {}): Roster {\n const decoded = decodeListForge(input);\n return importRoster(decoded, opts);\n}\n\n/**\n * Import a NewRecruit export (any of the four formats — JSON, wtc-compact,\n * wtc-full, simple) into a resolved 40kdc {@link Roster}.\n *\n * The JSON form is parsed when `input` is valid JSON; the text forms are\n * dispatched on string content. No base64/gzip decoding is attempted —\n * NewRecruit exports are not encoded.\n */\nexport function importNewRecruit(input: string, opts: ImportOptions = {}): Roster {\n const trimmed = input.trimStart();\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n return importRoster(JSON.parse(input), opts);\n } catch {\n // Fall through to treating the input as raw text.\n }\n }\n return importRoster(input, opts);\n}\n\n/**\n * Import an already-decoded payload. Selects the matching format adapter and\n * resolves the result against the dataset. Accepts either a parsed JSON object\n * (NewRecruit JSON / ListForge) or a string (the three NewRecruit text formats).\n */\n/**\n * Detect an already-resolved canonical {@link Roster} (the JSON shape produced\n * by `rosterJsonSerializer`). Lets a downstream consumer round-trip canonical\n * Roster JSON through `importRoster` without going through an adapter.\n */\nfunction isCanonicalRoster(decoded: unknown): decoded is Roster {\n if (typeof decoded !== \"object\" || decoded === null) return false;\n const r = decoded as Record<string, unknown>;\n const source = r.source as Record<string, unknown> | undefined;\n return (\n typeof source === \"object\" &&\n source !== null &&\n typeof source.format === \"string\" &&\n Array.isArray(r.units) &&\n \"diagnostics\" in r\n );\n}\n\nexport function importRoster(decoded: unknown, opts: ImportOptions = {}): Roster {\n if (isCanonicalRoster(decoded)) return decoded;\n const ds = opts.dataset ?? Dataset.embedded();\n const adapter = selectAdapter(decoded, [...ADAPTERS]);\n const parsed = adapter.parse(decoded);\n return resolve(parsed, ds, adapter.id);\n}\n\n// ---------------------------------------------------------------------------\n// tryImportRoster — single string-in, structured-result-out entry point.\n// ---------------------------------------------------------------------------\n\n/** Why a {@link tryImportRoster} call did not produce a roster. */\nexport type ImportFailureReason =\n | \"empty-input\"\n | \"decode-failed\"\n | \"no-adapter-matched\"\n | \"parse-failed\";\n\n/** Per-adapter outcome from a {@link tryImportRoster} dispatch. */\nexport interface AdapterTrial {\n id: RosterFormat;\n /** True iff this adapter's `matches()` predicate accepted the decoded input. */\n matched: boolean;\n /** Present when {@link matched} is true and `parse()` then threw — the matcher\n * violated its contract. Absent for clean rejections. */\n reason?: string;\n}\n\n/** Discriminated result returned by {@link tryImportRoster}. */\nexport type ImportResult =\n | { ok: true; roster: Roster; format: RosterFormat }\n | {\n ok: false;\n reason: ImportFailureReason;\n message: string;\n trials: AdapterTrial[];\n };\n\n/** Cheap predicate: does the input look like ListForge's URL-or-base64 wrapper? */\nfunction looksLikeListForgeEncoded(input: string): boolean {\n if (input.includes(\"/listforge/\")) return true;\n if (/^https?:\\/\\//i.test(input)) return true;\n // Every gzip-then-base64 payload starts with this prefix.\n if (input.startsWith(\"H4sIA\")) return true;\n return false;\n}\n\n/**\n * Auto-detect and import any supported roster format from a single string.\n *\n * Pipeline:\n * 1. Empty input → `empty-input`.\n * 2. Looks like a ListForge URL / base64 payload → decode (base64 + gunzip + JSON.parse).\n * 3. Looks like raw JSON (starts with `{`/`[`) → JSON.parse.\n * 4. Otherwise treat as text.\n * 5. Greedy first-match adapter dispatch. The first adapter whose `matches()`\n * accepts the decoded value wins; subsequent adapters are not tried.\n * 6. If the matched adapter's `parse()` throws, that's a matcher contract\n * violation — surfaced as `parse-failed`, not silently retried.\n *\n * Caller never sees an exception; the discriminated {@link ImportResult} carries\n * either the resolved {@link Roster} (with the detected {@link RosterFormat})\n * or a typed failure plus per-adapter trial info for diagnostics.\n *\n * Prefer this over {@link importListForge} / {@link importNewRecruit} when the\n * caller doesn't know which format the user pasted.\n */\nexport function tryImportRoster(\n input: string,\n opts: ImportOptions = {},\n): ImportResult {\n const trimmed = input.trim();\n if (trimmed === \"\") {\n return { ok: false, reason: \"empty-input\", message: \"input is empty\", trials: [] };\n }\n\n let decoded: unknown;\n if (looksLikeListForgeEncoded(trimmed)) {\n try {\n decoded = decodeListForge(trimmed);\n } catch (err) {\n const message = (err as Error).message;\n return {\n ok: false,\n reason: \"decode-failed\",\n message: `failed to decode ListForge payload: ${message}`,\n trials: [{ id: \"listforge\", matched: false, reason: message }],\n };\n }\n } else if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n decoded = JSON.parse(trimmed);\n } catch (err) {\n return {\n ok: false,\n reason: \"decode-failed\",\n message: `input looks like JSON but failed to parse: ${(err as Error).message}`,\n trials: [],\n };\n }\n } else {\n decoded = input;\n }\n\n const ds = opts.dataset ?? Dataset.embedded();\n const trials: AdapterTrial[] = [];\n for (const adapter of ADAPTERS) {\n if (!adapter.matches(decoded)) {\n trials.push({ id: adapter.id, matched: false });\n continue;\n }\n try {\n const parsed = adapter.parse(decoded);\n const roster = resolve(parsed, ds, adapter.id);\n return { ok: true, roster, format: adapter.id };\n } catch (err) {\n const message = (err as Error).message;\n trials.push({ id: adapter.id, matched: true, reason: message });\n return {\n ok: false,\n reason: \"parse-failed\",\n message: `${adapter.id}: ${message}`,\n trials,\n };\n }\n }\n\n return {\n ok: false,\n reason: \"no-adapter-matched\",\n message: `tried ${ADAPTERS.length} formats, none recognised the input`,\n trials,\n };\n}\n\n/** The adapter list, exposed for tests that need to walk every matcher (e.g.\n * the disjointness invariant test). */\nexport const REGISTERED_ADAPTERS: readonly FormatAdapter[] = ADAPTERS;\n"]}