@alpaca-software/40kdc-data 0.5.11 → 0.5.12
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.
- package/README.md +10 -0
- package/dist/codegen-data.js +1 -0
- package/dist/codegen-data.js.map +1 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +3 -1
- package/dist/commands/import.js.map +1 -1
- package/dist/convert-faction.d.ts.map +1 -1
- package/dist/convert-faction.js +22 -2
- package/dist/convert-faction.js.map +1 -1
- package/dist/data/bundle.generated.js +1 -1
- package/dist/data/bundle.generated.js.map +1 -1
- package/dist/data/dataset.d.ts +2 -1
- package/dist/data/dataset.d.ts.map +1 -1
- package/dist/data/dataset.js +2 -0
- package/dist/data/dataset.js.map +1 -1
- package/dist/data/entities.d.ts +22 -0
- package/dist/data/entities.d.ts.map +1 -1
- package/dist/data/entities.js +28 -0
- package/dist/data/entities.js.map +1 -1
- package/dist/data/index.d.ts +2 -0
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +2 -0
- package/dist/data/index.js.map +1 -1
- package/dist/data/types.d.ts +3 -1
- package/dist/data/types.d.ts.map +1 -1
- package/dist/data/types.js +1 -0
- package/dist/data/types.js.map +1 -1
- package/dist/export/newrecruit-json.d.ts.map +1 -1
- package/dist/export/newrecruit-json.js +4 -3
- package/dist/export/newrecruit-json.js.map +1 -1
- package/dist/export/newrecruit-simple.js +2 -2
- package/dist/export/newrecruit-simple.js.map +1 -1
- package/dist/export/newrecruit-wtc.d.ts.map +1 -1
- package/dist/export/newrecruit-wtc.js +3 -1
- package/dist/export/newrecruit-wtc.js.map +1 -1
- package/dist/export/rosterizer.d.ts.map +1 -1
- package/dist/export/rosterizer.js +6 -7
- package/dist/export/rosterizer.js.map +1 -1
- package/dist/extract-faction-pack.d.ts +56 -0
- package/dist/extract-faction-pack.d.ts.map +1 -0
- package/dist/extract-faction-pack.js +374 -0
- package/dist/extract-faction-pack.js.map +1 -0
- package/dist/gen-conformance.js +37 -4
- package/dist/gen-conformance.js.map +1 -1
- package/dist/generated.d.ts +42 -2
- package/dist/generated.d.ts.map +1 -1
- package/dist/generated.js.map +1 -1
- package/dist/import/gw.js +1 -1
- package/dist/import/gw.js.map +1 -1
- package/dist/import/listforge-text.js +1 -1
- package/dist/import/listforge-text.js.map +1 -1
- package/dist/import/listforge.d.ts.map +1 -1
- package/dist/import/listforge.js +18 -3
- package/dist/import/listforge.js.map +1 -1
- package/dist/import/newrecruit-json.d.ts.map +1 -1
- package/dist/import/newrecruit-json.js +21 -3
- package/dist/import/newrecruit-json.js.map +1 -1
- package/dist/import/newrecruit-simple.js +1 -1
- package/dist/import/newrecruit-simple.js.map +1 -1
- package/dist/import/newrecruit-wtc.js +1 -1
- package/dist/import/newrecruit-wtc.js.map +1 -1
- package/dist/import/resolve.d.ts.map +1 -1
- package/dist/import/resolve.js +46 -18
- package/dist/import/resolve.js.map +1 -1
- package/dist/import/roster-json.d.ts +5 -3
- package/dist/import/roster-json.d.ts.map +1 -1
- package/dist/import/roster-json.js +8 -4
- package/dist/import/roster-json.js.map +1 -1
- package/dist/import/rosterizer.js +3 -3
- package/dist/import/rosterizer.js.map +1 -1
- package/dist/import/types.d.ts +15 -4
- package/dist/import/types.d.ts.map +1 -1
- package/dist/import/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/rube-goldberg.js +1 -1
- package/dist/rube-goldberg.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +33 -1
- package/dist/runner.js.map +1 -1
- package/dist/scope.d.ts +31 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +34 -0
- package/dist/scope.js.map +1 -0
- package/dist/translate/effect.d.ts +17 -3
- package/dist/translate/effect.d.ts.map +1 -1
- package/dist/translate/effect.js +23 -4
- package/dist/translate/effect.js.map +1 -1
- package/dist/translate/index.d.ts +1 -1
- package/dist/translate/index.d.ts.map +1 -1
- package/dist/translate/index.js +1 -1
- package/dist/translate/index.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +1 -0
- package/dist/validate.js.map +1 -1
- package/package.json +2 -1
- package/schemas/core/hull-shape.schema.json +30 -0
- package/schemas/core/roster.schema.json +24 -8
- package/schemas/core/stratagem.schema.json +2 -2
- package/schemas/core/unit-composition.schema.json +7 -0
- package/schemas/enrichment/ability-dsl/ability.schema.json +14 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../src/translate/effect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Humanize an Ability-DSL `effect` tree into plain English — the\n * `ability.print()` of the dataset. Output is an *approximation* generated\n * purely from the structured data (no external rules text), ASCII-only, with\n * a fixed clause order: it is pinned byte-for-byte across the TS and Rust\n * ports by the `conformance/effect-translation` corpus, so any phrasing\n * change here is a semantic corpus change (bump `conformance/SPEC_VERSION`).\n *\n * Container nodes (`sequence`, `conditional`, `choice`, `dice-gated`,\n * `dice-pool-allocation`) render block-style with two-space indentation and\n * an ASCII `-> ` arrow; leaves render as single clauses. Unknown leaf types\n * and unrecognized modifier shapes degrade to a deterministic bracketed form\n * (`[the-type]`) rather than failing — coverage improves as authoring does.\n */\n\nimport { describeCondition, dekebab, type Condition } from \"./condition.js\";\n\n/**\n * Minimal structural view of an effect node. Matches the ability-dsl effect\n * schema: a single effect carries `type` + `target` + `modifier`; containers\n * carry their own shape (`steps`, `options`, `condition`/`effect`, dice\n * fields).\n */\nexport interface Effect {\n type?: string;\n target?: string;\n modifier?: Record<string, unknown>;\n condition?: Condition;\n effect?: Effect;\n steps?: Effect[];\n options?: (Effect & {\n name?: string;\n requirement?: Record<string, unknown>;\n })[];\n choice_label?: string;\n dice?: string;\n threshold?: number | string;\n comparison?: string;\n on_success?: Effect | null;\n on_fail?: Effect | null;\n pool?: { count: number; die: string };\n max_activations?: number;\n}\n\n/** Ability scope, as carried on enrichment ability entries. */\nexport interface AbilityScope {\n range?: string;\n duration?: string;\n range_inches?: number;\n}\n\n/** Minimal ability view for `describeAbility`. */\nexport interface AbilityLike {\n name?: string;\n effect?: Effect;\n scope?: AbilityScope;\n}\n\n/** JS-template stringification (numbers print without trailing `.0`). */\nfunction jstr(v: unknown): string {\n if (v == null) return \"?\";\n if (Array.isArray(v)) return v.map(jstr).join(\", \");\n return String(v);\n}\n\nfunction formatTarget(t?: string): string {\n return t ? dekebab(t) : \"target\";\n}\n\nfunction signed(operation: unknown, value: unknown): string {\n const op = operation === \"add\" || operation === \"improve\" ? \"+\" : \"-\";\n return `${op}${jstr(value)}`;\n}\n\nfunction formatComparison(comp: string, threshold: unknown): string {\n const th = jstr(threshold);\n switch (comp) {\n case \"gte\":\n return `${th}+`;\n case \"lte\":\n return `${th} or less`;\n case \"gt\":\n return `greater than ${th}`;\n case \"lt\":\n return `less than ${th}`;\n case \"eq\":\n return `exactly ${th}`;\n default:\n return `${th}+`;\n }\n}\n\n/** Single-clause translation for leaf effects (and inline container forms). */\nexport function describeEffectInline(e: Effect): string {\n const m = e.modifier ?? {};\n const target = formatTarget(e.target);\n\n switch (e.type) {\n case \"stat-modifier\": {\n const scope = m.attack_type ? ` (${jstr(m.attack_type)})` : \"\";\n if (m.stat == null) return `modify stats for ${target}`;\n if (m.operation === \"set\") return `set ${jstr(m.stat)} to ${jstr(m.value)}${scope} for ${target}`;\n return `${signed(m.operation, m.value)} ${jstr(m.stat)}${scope} for ${target}`;\n }\n case \"roll-modifier\": {\n const ctx = m.context ? ` (${jstr(m.context)})` : \"\";\n if (m.value == null) return `${dekebab(jstr(m.operation))} ${jstr(m.roll)} rolls${ctx} for ${target}`;\n return `${signed(m.operation, m.value)} to ${jstr(m.roll)} rolls${ctx} for ${target}`;\n }\n case \"re-roll\": {\n const subset = m.subset ? ` (${dekebab(jstr(m.subset))})` : \"\";\n const atk = m.attack_type ? ` (${jstr(m.attack_type)})` : \"\";\n return `re-roll ${jstr(m.roll)} rolls${subset}${atk} for ${target}`;\n }\n case \"mortal-wounds\": {\n const amount = m.count ?? m.amount ?? (m.amount_table ? \"variable\" : \"?\");\n const range = m.range ?? m.range_inches;\n const within = range != null ? ` (within ${jstr(range)}\")` : \"\";\n return `deal ${jstr(amount)} mortal wounds to ${target}${within}`;\n }\n case \"feel-no-pain\":\n return `${target} gains Feel No Pain ${jstr(m.threshold)}+`;\n case \"ward\":\n return `${target} gains Ward ${jstr(m.threshold ?? m.value)}+`;\n case \"invulnerable-save\":\n return `${target} gains a ${jstr(m.value)}+ invulnerable save`;\n case \"keyword-grant\": {\n const kw = Array.isArray(m.keywords) ? m.keywords.map(jstr).join(\", \") : jstr(m.keyword ?? \"keywords\");\n if (m.weapon_name != null) return `${target}'s ${jstr(m.weapon_name)} gains ${kw}`;\n if (m.weapon_type != null) return `${target}'s ${jstr(m.weapon_type)} weapons gain ${kw}`;\n return `${target}'s weapons gain ${kw}`;\n }\n case \"ability-grant\": {\n const grant = m.grant_type ?? m.ability_id;\n const cap = m.capacity != null ? ` (${jstr(m.capacity)})` : \"\";\n return `${target} gains ${grant != null ? dekebab(jstr(grant)) : \"an ability\"}${cap}`;\n }\n case \"movement-modifier\": {\n const kind = m.move_type ?? m.type;\n const dist = m.distance ?? m.value;\n const inches = dist != null ? ` ${jstr(dist)}\"` : \"\";\n return `${target} gains ${kind != null ? dekebab(jstr(kind)) : \"a movement effect\"}${inches}`;\n }\n case \"damage-reduction\":\n return `reduce incoming damage to ${target} by ${jstr(m.amount ?? m.value)}`;\n case \"resurrection\":\n return `return ${jstr(m.count ?? 1)} model(s) to ${target} with ${jstr(m.wounds_remaining ?? \"full\")} wounds`;\n case \"model-destruction\":\n return `destroy ${jstr(m.count)} non-leader model(s) from ${target}`;\n case \"cp-gain\":\n return `gain ${jstr(m.amount)} CP`;\n case \"cp-refund\":\n return `refund ${jstr(m.amount)} CP`;\n case \"resource-gain\":\n return `gain ${jstr(m.amount)} to ${jstr(m.pool_id)}`;\n case \"resource-spend\":\n return `spend ${jstr(m.amount)} from ${jstr(m.pool_id)}`;\n case \"leadership-modifier\": {\n if (m.test != null && m.operation == null) return `force a ${dekebab(jstr(m.test))} test on ${target}`;\n if (m.test != null) return `${dekebab(jstr(m.operation))} ${dekebab(jstr(m.test))} tests for ${target}`;\n if (m.operation != null) return `${signed(m.operation, m.value)} Leadership for ${target}`;\n return `modify Leadership for ${target}`;\n }\n case \"fight-first\":\n return `${target} fights first`;\n case \"fight-last\":\n return `${target} fights last`;\n case \"fight-on-death\":\n return `${target} fights on death`;\n case \"shoot-on-death\":\n return `${target} shoots on death`;\n case \"deep-strike\":\n return `${target} can deep strike`;\n case \"fallback-and-act\":\n return `${target} can fall back and act`;\n case \"attack-restriction\": {\n const what = m.restriction ?? m.restriction_type;\n const range = m.range != null ? ` (within ${jstr(m.range)}\")` : \"\";\n const max = m.max_models != null ? ` (max ${jstr(m.max_models)} models)` : \"\";\n return `${target}: ${what != null ? dekebab(jstr(what)) : \"attack restriction\"}${range}${max}`;\n }\n case \"objective-control-modifier\": {\n if (m.operation != null) return `${signed(m.operation, m.value)} OC for ${target}`;\n return `modify OC of ${target} by ${jstr(m.value)}`;\n }\n case \"bs-modifier\":\n return `${signed(m.operation, m.value)} BS for ${target}`;\n case \"charge-roll-modifier\":\n return `${signed(m.operation, m.value)} to charge rolls for ${target}`;\n case \"engagement-passthrough\":\n return `${target} can move through engagement range`;\n case \"terrain-area-tag\":\n return `tag the terrain area as ${dekebab(jstr(m.tag))}`;\n case \"objective-tag\":\n return `tag the objective as ${dekebab(jstr(m.tag))}`;\n case \"unit-tag\":\n return `tag ${target} as ${dekebab(jstr(m.tag))}`;\n\n // Container types — inline forms.\n case \"conditional\":\n return `if ${describeCondition(e.condition ?? {})}: ${describeEffectInline(e.effect ?? {})}`;\n case \"sequence\":\n return (e.steps ?? []).map(describeEffectInline).join(\"; \");\n case \"choice\": {\n const label = e.choice_label ? ` (${e.choice_label})` : \"\";\n return `choose one${label}: ${(e.options ?? []).map(describeEffectInline).join(\" / \")}`;\n }\n case \"dice-gated\": {\n const comp = formatComparison(e.comparison ?? \"gte\", e.threshold);\n const success = e.on_success ? describeEffectInline(e.on_success) : \"nothing\";\n const fail = e.on_fail ? `, otherwise ${describeEffectInline(e.on_fail)}` : \"\";\n return `roll ${jstr(e.dice)}: on ${comp}, ${success}${fail}`;\n }\n case \"dice-pool-allocation\": {\n const pool = e.pool ? `${jstr(e.pool.count)}${jstr(e.pool.die)}` : \"?\";\n const opts = (e.options ?? [])\n .map((o) => `${jstr(o.name)} (${jstr(o.requirement?.min_value)}+): ${describeEffectInline(o.effect ?? {})}`)\n .join(\" / \");\n return `roll ${pool}: ${opts}`;\n }\n\n default:\n return `[${e.type ?? \"unknown\"}]`;\n }\n}\n\n/**\n * Block translation of an effect tree. Containers expand over multiple lines\n * with two-space indentation; leaves delegate to `describeEffectInline`.\n */\nexport function describeEffect(e: Effect, depth: number = 0): string {\n const indent = \" \".repeat(depth);\n const arrow = depth > 0 ? \"-> \" : \"\";\n\n switch (e.type) {\n case \"conditional\":\n return `${indent}If ${describeCondition(e.condition ?? {})}:\\n` + describeEffect(e.effect ?? {}, depth + 1);\n case \"sequence\":\n return (e.steps ?? []).map((s) => describeEffect(s, depth)).join(\"\\n\");\n case \"choice\": {\n const label = e.choice_label ? ` (${e.choice_label})` : \"\";\n return (\n `${indent}${arrow}Choose one${label}:\\n` +\n (e.options ?? []).map((o, i) => `${indent} ${i + 1}. ${describeEffectInline(o)}`).join(\"\\n\")\n );\n }\n case \"dice-gated\": {\n const comp = formatComparison(e.comparison ?? \"gte\", e.threshold);\n const success = e.on_success ? describeEffectInline(e.on_success) : \"nothing\";\n const fail = e.on_fail ? `, otherwise ${describeEffectInline(e.on_fail)}` : \"\";\n return `${indent}${arrow}Roll ${jstr(e.dice)}: on ${comp}, ${success}${fail}`;\n }\n case \"dice-pool-allocation\": {\n const pool = e.pool ? `${jstr(e.pool.count)}${jstr(e.pool.die)}` : \"?\";\n const lines = [`${indent}${arrow}Roll ${pool} (max ${jstr(e.max_activations)} activations):`];\n for (const opt of e.options ?? []) {\n lines.push(\n `${indent} - ${jstr(opt.name)}: need ${jstr(opt.requirement?.type)} of ${jstr(opt.requirement?.min_value)}+ -> ${describeEffectInline(opt.effect ?? {})}`\n );\n }\n return lines.join(\"\\n\");\n }\n default:\n return `${indent}${arrow}${describeEffectInline(e)}`;\n }\n}\n\n/** `Scope: aura (6\"). Duration: phase.` — empty string when absent. */\nexport function describeScope(s?: AbilityScope): string {\n if (!s || (!s.range && !s.duration)) return \"\";\n const range = dekebab(s.range ?? \"\");\n const inches = s.range_inches != null ? ` (${jstr(s.range_inches)}\")` : \"\";\n const duration = dekebab(s.duration ?? \"\");\n return `Scope: ${range}${inches}. Duration: ${duration}.`;\n}\n\n/**\n * Full generated text for an ability: the effect tree plus a trailing scope\n * line. This is the `ability.print()` consumers render when the dataset\n * carries no rules prose.\n */\nexport function describeAbility(a: AbilityLike): string {\n const effect = a.effect ? describeEffect(a.effect) : \"\";\n const scope = describeScope(a.scope);\n return scope ? (effect ? `${effect}\\n${scope}` : scope) : effect;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../src/translate/effect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Humanize an Ability-DSL `effect` tree into plain English — the\n * `ability.print()` of the dataset. Output is an *approximation* generated\n * purely from the structured data (no external rules text), ASCII-only, with\n * a fixed clause order: it is pinned byte-for-byte across the TS and Rust\n * ports by the `conformance/effect-translation` corpus, so any phrasing\n * change here is a semantic corpus change (bump `conformance/SPEC_VERSION`).\n *\n * Container nodes (`sequence`, `conditional`, `choice`, `dice-gated`,\n * `dice-pool-allocation`) render block-style with two-space indentation and\n * an ASCII `-> ` arrow; leaves render as single clauses. Unknown leaf types\n * and unrecognized modifier shapes degrade to a deterministic bracketed form\n * (`[the-type]`) rather than failing — coverage improves as authoring does.\n */\n\nimport { describeCondition, dekebab, type Condition } from \"./condition.js\";\n\n/**\n * Minimal structural view of an effect node. Matches the ability-dsl effect\n * schema: a single effect carries `type` + `target` + `modifier`; containers\n * carry their own shape (`steps`, `options`, `condition`/`effect`, dice\n * fields).\n */\nexport interface Effect {\n type?: string;\n target?: string;\n modifier?: Record<string, unknown>;\n condition?: Condition;\n effect?: Effect;\n steps?: Effect[];\n options?: (Effect & {\n name?: string;\n requirement?: Record<string, unknown>;\n })[];\n choice_label?: string;\n dice?: string;\n threshold?: number | string;\n comparison?: string;\n on_success?: Effect | null;\n on_fail?: Effect | null;\n pool?: { count: number; die: string };\n max_activations?: number;\n}\n\n/** Ability scope, as carried on enrichment ability entries. */\nexport interface AbilityScope {\n range?: string;\n duration?: string;\n range_inches?: number;\n}\n\n/** Curated keyword filter naming which units an ability benefits. */\nexport interface AbilityAppliesTo {\n required_keywords?: string[];\n excluded_keywords?: string[];\n}\n\n/** Minimal ability view for `describeAbility`. */\nexport interface AbilityLike {\n name?: string;\n effect?: Effect;\n scope?: AbilityScope;\n applies_to?: AbilityAppliesTo | null;\n}\n\n/** JS-template stringification (numbers print without trailing `.0`). */\nfunction jstr(v: unknown): string {\n if (v == null) return \"?\";\n if (Array.isArray(v)) return v.map(jstr).join(\", \");\n return String(v);\n}\n\nfunction formatTarget(t?: string): string {\n return t ? dekebab(t) : \"target\";\n}\n\nfunction signed(operation: unknown, value: unknown): string {\n const op = operation === \"add\" || operation === \"improve\" ? \"+\" : \"-\";\n return `${op}${jstr(value)}`;\n}\n\nfunction formatComparison(comp: string, threshold: unknown): string {\n const th = jstr(threshold);\n switch (comp) {\n case \"gte\":\n return `${th}+`;\n case \"lte\":\n return `${th} or less`;\n case \"gt\":\n return `greater than ${th}`;\n case \"lt\":\n return `less than ${th}`;\n case \"eq\":\n return `exactly ${th}`;\n default:\n return `${th}+`;\n }\n}\n\n/** Single-clause translation for leaf effects (and inline container forms). */\nexport function describeEffectInline(e: Effect): string {\n const m = e.modifier ?? {};\n const target = formatTarget(e.target);\n\n switch (e.type) {\n case \"stat-modifier\": {\n const scope = m.attack_type ? ` (${jstr(m.attack_type)})` : \"\";\n if (m.stat == null) return `modify stats for ${target}`;\n if (m.operation === \"set\") return `set ${jstr(m.stat)} to ${jstr(m.value)}${scope} for ${target}`;\n return `${signed(m.operation, m.value)} ${jstr(m.stat)}${scope} for ${target}`;\n }\n case \"roll-modifier\": {\n const ctx = m.context ? ` (${jstr(m.context)})` : \"\";\n if (m.value == null) return `${dekebab(jstr(m.operation))} ${jstr(m.roll)} rolls${ctx} for ${target}`;\n return `${signed(m.operation, m.value)} to ${jstr(m.roll)} rolls${ctx} for ${target}`;\n }\n case \"re-roll\": {\n const subset = m.subset ? ` (${dekebab(jstr(m.subset))})` : \"\";\n const atk = m.attack_type ? ` (${jstr(m.attack_type)})` : \"\";\n return `re-roll ${jstr(m.roll)} rolls${subset}${atk} for ${target}`;\n }\n case \"mortal-wounds\": {\n const amount = m.count ?? m.amount ?? (m.amount_table ? \"variable\" : \"?\");\n const range = m.range ?? m.range_inches;\n const within = range != null ? ` (within ${jstr(range)}\")` : \"\";\n return `deal ${jstr(amount)} mortal wounds to ${target}${within}`;\n }\n case \"feel-no-pain\":\n return `${target} gains Feel No Pain ${jstr(m.threshold)}+`;\n case \"ward\":\n return `${target} gains Ward ${jstr(m.threshold ?? m.value)}+`;\n case \"invulnerable-save\":\n return `${target} gains a ${jstr(m.value)}+ invulnerable save`;\n case \"keyword-grant\": {\n const kw = Array.isArray(m.keywords) ? m.keywords.map(jstr).join(\", \") : jstr(m.keyword ?? \"keywords\");\n if (m.weapon_name != null) return `${target}'s ${jstr(m.weapon_name)} gains ${kw}`;\n if (m.weapon_type != null) return `${target}'s ${jstr(m.weapon_type)} weapons gain ${kw}`;\n return `${target}'s weapons gain ${kw}`;\n }\n case \"ability-grant\": {\n const grant = m.grant_type ?? m.ability_id;\n const cap = m.capacity != null ? ` (${jstr(m.capacity)})` : \"\";\n return `${target} gains ${grant != null ? dekebab(jstr(grant)) : \"an ability\"}${cap}`;\n }\n case \"movement-modifier\": {\n const kind = m.move_type ?? m.type;\n const dist = m.distance ?? m.value;\n const inches = dist != null ? ` ${jstr(dist)}\"` : \"\";\n return `${target} gains ${kind != null ? dekebab(jstr(kind)) : \"a movement effect\"}${inches}`;\n }\n case \"damage-reduction\":\n return `reduce incoming damage to ${target} by ${jstr(m.amount ?? m.value)}`;\n case \"resurrection\":\n return `return ${jstr(m.count ?? 1)} model(s) to ${target} with ${jstr(m.wounds_remaining ?? \"full\")} wounds`;\n case \"model-destruction\":\n return `destroy ${jstr(m.count)} non-leader model(s) from ${target}`;\n case \"cp-gain\":\n return `gain ${jstr(m.amount)} CP`;\n case \"cp-refund\":\n return `refund ${jstr(m.amount)} CP`;\n case \"resource-gain\":\n return `gain ${jstr(m.amount)} to ${jstr(m.pool_id)}`;\n case \"resource-spend\":\n return `spend ${jstr(m.amount)} from ${jstr(m.pool_id)}`;\n case \"leadership-modifier\": {\n if (m.test != null && m.operation == null) return `force a ${dekebab(jstr(m.test))} test on ${target}`;\n if (m.test != null) return `${dekebab(jstr(m.operation))} ${dekebab(jstr(m.test))} tests for ${target}`;\n if (m.operation != null) return `${signed(m.operation, m.value)} Leadership for ${target}`;\n return `modify Leadership for ${target}`;\n }\n case \"fight-first\":\n return `${target} fights first`;\n case \"fight-last\":\n return `${target} fights last`;\n case \"fight-on-death\":\n return `${target} fights on death`;\n case \"shoot-on-death\":\n return `${target} shoots on death`;\n case \"deep-strike\":\n return `${target} can deep strike`;\n case \"fallback-and-act\":\n return `${target} can fall back and act`;\n case \"attack-restriction\": {\n const what = m.restriction ?? m.restriction_type;\n const range = m.range != null ? ` (within ${jstr(m.range)}\")` : \"\";\n const max = m.max_models != null ? ` (max ${jstr(m.max_models)} models)` : \"\";\n return `${target}: ${what != null ? dekebab(jstr(what)) : \"attack restriction\"}${range}${max}`;\n }\n case \"objective-control-modifier\": {\n if (m.operation != null) return `${signed(m.operation, m.value)} OC for ${target}`;\n return `modify OC of ${target} by ${jstr(m.value)}`;\n }\n case \"bs-modifier\":\n return `${signed(m.operation, m.value)} BS for ${target}`;\n case \"charge-roll-modifier\":\n return `${signed(m.operation, m.value)} to charge rolls for ${target}`;\n case \"engagement-passthrough\":\n return `${target} can move through engagement range`;\n case \"terrain-area-tag\":\n return `tag the terrain area as ${dekebab(jstr(m.tag))}`;\n case \"objective-tag\":\n return `tag the objective as ${dekebab(jstr(m.tag))}`;\n case \"unit-tag\":\n return `tag ${target} as ${dekebab(jstr(m.tag))}`;\n\n // Container types — inline forms.\n case \"conditional\":\n return `if ${describeCondition(e.condition ?? {})}: ${describeEffectInline(e.effect ?? {})}`;\n case \"sequence\":\n return (e.steps ?? []).map(describeEffectInline).join(\"; \");\n case \"choice\": {\n const label = e.choice_label ? ` (${e.choice_label})` : \"\";\n return `choose one${label}: ${(e.options ?? []).map(describeEffectInline).join(\" / \")}`;\n }\n case \"dice-gated\": {\n const comp = formatComparison(e.comparison ?? \"gte\", e.threshold);\n const success = e.on_success ? describeEffectInline(e.on_success) : \"nothing\";\n const fail = e.on_fail ? `, otherwise ${describeEffectInline(e.on_fail)}` : \"\";\n return `roll ${jstr(e.dice)}: on ${comp}, ${success}${fail}`;\n }\n case \"dice-pool-allocation\": {\n const pool = e.pool ? `${jstr(e.pool.count)}${jstr(e.pool.die)}` : \"?\";\n const opts = (e.options ?? [])\n .map((o) => `${jstr(o.name)} (${jstr(o.requirement?.min_value)}+): ${describeEffectInline(o.effect ?? {})}`)\n .join(\" / \");\n return `roll ${pool}: ${opts}`;\n }\n\n default:\n return `[${e.type ?? \"unknown\"}]`;\n }\n}\n\n/**\n * Block translation of an effect tree. Containers expand over multiple lines\n * with two-space indentation; leaves delegate to `describeEffectInline`.\n */\nexport function describeEffect(e: Effect, depth: number = 0): string {\n const indent = \" \".repeat(depth);\n const arrow = depth > 0 ? \"-> \" : \"\";\n\n switch (e.type) {\n case \"conditional\":\n return `${indent}If ${describeCondition(e.condition ?? {})}:\\n` + describeEffect(e.effect ?? {}, depth + 1);\n case \"sequence\":\n return (e.steps ?? []).map((s) => describeEffect(s, depth)).join(\"\\n\");\n case \"choice\": {\n const label = e.choice_label ? ` (${e.choice_label})` : \"\";\n return (\n `${indent}${arrow}Choose one${label}:\\n` +\n (e.options ?? []).map((o, i) => `${indent} ${i + 1}. ${describeEffectInline(o)}`).join(\"\\n\")\n );\n }\n case \"dice-gated\": {\n const comp = formatComparison(e.comparison ?? \"gte\", e.threshold);\n const success = e.on_success ? describeEffectInline(e.on_success) : \"nothing\";\n const fail = e.on_fail ? `, otherwise ${describeEffectInline(e.on_fail)}` : \"\";\n return `${indent}${arrow}Roll ${jstr(e.dice)}: on ${comp}, ${success}${fail}`;\n }\n case \"dice-pool-allocation\": {\n const pool = e.pool ? `${jstr(e.pool.count)}${jstr(e.pool.die)}` : \"?\";\n const lines = [`${indent}${arrow}Roll ${pool} (max ${jstr(e.max_activations)} activations):`];\n for (const opt of e.options ?? []) {\n lines.push(\n `${indent} - ${jstr(opt.name)}: need ${jstr(opt.requirement?.type)} of ${jstr(opt.requirement?.min_value)}+ -> ${describeEffectInline(opt.effect ?? {})}`\n );\n }\n return lines.join(\"\\n\");\n }\n default:\n return `${indent}${arrow}${describeEffectInline(e)}`;\n }\n}\n\n/** `Scope: aura (6\"). Duration: phase.` — empty string when absent. */\nexport function describeScope(s?: AbilityScope): string {\n if (!s || (!s.range && !s.duration)) return \"\";\n const range = dekebab(s.range ?? \"\");\n const inches = s.range_inches != null ? ` (${jstr(s.range_inches)}\")` : \"\";\n const duration = dekebab(s.duration ?? \"\");\n return `Scope: ${range}${inches}. Duration: ${duration}.`;\n}\n\n/**\n * `Applies to: units with Possessed.` — the roster-highlighting audience named\n * by a curated `applies_to` filter. Empty string when the filter is absent or\n * carries no keywords (nothing to say). `required_keywords` reads as an AND set;\n * `excluded_keywords` render as a trailing `(excluding …)`.\n */\nexport function describeAppliesTo(a?: AbilityAppliesTo | null): string {\n if (!a) return \"\";\n const required = a.required_keywords ?? [];\n const excluded = a.excluded_keywords ?? [];\n if (required.length === 0 && excluded.length === 0) return \"\";\n const base = required.length ? `units with ${required.join(\", \")}` : \"all units\";\n const exc = excluded.length ? ` (excluding ${excluded.join(\", \")})` : \"\";\n return `Applies to: ${base}${exc}.`;\n}\n\n/**\n * Full generated text for an ability: the effect tree, a trailing scope line,\n * and a trailing `Applies to:` line when the ability carries a curated\n * `applies_to` filter. This is the `ability.print()` consumers render when the\n * dataset carries no rules prose.\n */\nexport function describeAbility(a: AbilityLike): string {\n const effect = a.effect ? describeEffect(a.effect) : \"\";\n const scope = describeScope(a.scope);\n const applies = describeAppliesTo(a.applies_to);\n return [effect, scope, applies].filter(Boolean).join(\"\\n\");\n}\n"]}
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { describeCondition, dekebab, type Condition } from "./condition.js";
|
|
10
10
|
export { describeTrigger, describeAward, describeScoringCard, type ScoringTrigger, type ScoringAward, type ScoringMode, } from "./scoring.js";
|
|
11
|
-
export { describeEffect, describeEffectInline, describeAbility, describeScope, type Effect, type AbilityScope, type AbilityLike, } from "./effect.js";
|
|
11
|
+
export { describeEffect, describeEffectInline, describeAbility, describeAppliesTo, describeScope, type Effect, type AbilityScope, type AbilityAppliesTo, type AbilityLike, } from "./effect.js";
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/translate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/translate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC"}
|
package/dist/translate/index.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { describeCondition, dekebab } from "./condition.js";
|
|
10
10
|
export { describeTrigger, describeAward, describeScoringCard, } from "./scoring.js";
|
|
11
|
-
export { describeEffect, describeEffectInline, describeAbility, describeScope, } from "./effect.js";
|
|
11
|
+
export { describeEffect, describeEffectInline, describeAbility, describeAppliesTo, describeScope, } from "./effect.js";
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/translate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAkB,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,aAAa,EACb,mBAAmB,GAIpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,aAAa,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/translate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAkB,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,aAAa,EACb,mBAAmB,GAIpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,aAAa,GAKd,MAAM,aAAa,CAAC","sourcesContent":["/**\n * Plain-English translation of structured game data — the `secondary-card`\n * scoring `awards` (mission \"how to play\" readouts), the shared Ability-DSL\n * condition humanizer, and the Ability-DSL effect describer (\"ability.print()\").\n * Output is ASCII-only and pinned across language ports by the\n * `conformance/scoring-translation` and `conformance/effect-translation`\n * corpora.\n */\nexport { describeCondition, dekebab, type Condition } from \"./condition.js\";\nexport {\n describeTrigger,\n describeAward,\n describeScoringCard,\n type ScoringTrigger,\n type ScoringAward,\n type ScoringMode,\n} from \"./scoring.js\";\nexport {\n describeEffect,\n describeEffectInline,\n describeAbility,\n describeAppliesTo,\n describeScope,\n type Effect,\n type AbilityScope,\n type AbilityAppliesTo,\n type AbilityLike,\n} from \"./effect.js\";\n"]}
|
package/dist/validate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAS3B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAS3B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAkDD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,CAAC,CAkF3B"}
|
package/dist/validate.js
CHANGED
|
@@ -28,6 +28,7 @@ const SCHEMA_MAP = {
|
|
|
28
28
|
"secondary-cards": "https://40kdc.dev/schemas/core/secondary-card.schema.json",
|
|
29
29
|
"terrain-templates": "https://40kdc.dev/schemas/core/terrain-template.schema.json",
|
|
30
30
|
"terrain-layouts": "https://40kdc.dev/schemas/core/terrain-layout.schema.json",
|
|
31
|
+
"hull-shapes": "https://40kdc.dev/schemas/core/hull-shape.schema.json",
|
|
31
32
|
"phase-mappings": "https://40kdc.dev/schemas/enrichment/phase-mapping.schema.json",
|
|
32
33
|
"timing-flags": "https://40kdc.dev/schemas/enrichment/timing-flag.schema.json",
|
|
33
34
|
"interaction-flags": "https://40kdc.dev/schemas/enrichment/interaction-flag.schema.json",
|
package/dist/validate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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","sourcesContent":["import type Ajv from \"ajv\";\nimport { readFileSync } from \"node:fs\";\nimport { glob } from \"glob\";\nimport { resolve, basename } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst DATA_ROOT = resolve(__dirname, \"../../data\");\n\nexport interface ValidationError {\n file: string;\n index: number;\n errors: Array<{ path: string; message: string }>;\n}\n\nexport interface ValidationResult {\n totalFiles: number;\n totalItems: number;\n passed: number;\n failed: number;\n errors: ValidationError[];\n}\n\n/**\n * Map from data file base-name prefix to schema $id.\n */\nconst SCHEMA_MAP: Record<string, string> = {\n factions: \"https://40kdc.dev/schemas/core/faction.schema.json\",\n units: \"https://40kdc.dev/schemas/core/unit.schema.json\",\n \"target-profiles\": \"https://40kdc.dev/schemas/core/target-profile.schema.json\",\n weapons: \"https://40kdc.dev/schemas/core/weapon.schema.json\",\n \"weapon-keywords\": \"https://40kdc.dev/schemas/core/weapon-keyword.schema.json\",\n \"game-versions\": \"https://40kdc.dev/schemas/core/game-version.schema.json\",\n detachments: \"https://40kdc.dev/schemas/core/detachment.schema.json\",\n enhancements: \"https://40kdc.dev/schemas/core/enhancement.schema.json\",\n stratagems: \"https://40kdc.dev/schemas/core/stratagem.schema.json\",\n \"wargear-options\": \"https://40kdc.dev/schemas/core/wargear-option.schema.json\",\n wargear: \"https://40kdc.dev/schemas/core/wargear.schema.json\",\n \"leader-attachments\": \"https://40kdc.dev/schemas/core/leader-attachment.schema.json\",\n \"unit-compositions\": \"https://40kdc.dev/schemas/core/unit-composition.schema.json\",\n \"force-dispositions\": \"https://40kdc.dev/schemas/core/force-disposition.schema.json\",\n \"deployment-patterns\": \"https://40kdc.dev/schemas/core/deployment-pattern.schema.json\",\n \"mission-matchups\": \"https://40kdc.dev/schemas/core/mission-matchup.schema.json\",\n missions: \"https://40kdc.dev/schemas/core/mission.schema.json\",\n \"secondary-cards\": \"https://40kdc.dev/schemas/core/secondary-card.schema.json\",\n \"terrain-templates\": \"https://40kdc.dev/schemas/core/terrain-template.schema.json\",\n \"terrain-layouts\": \"https://40kdc.dev/schemas/core/terrain-layout.schema.json\",\n \"phase-mappings\": \"https://40kdc.dev/schemas/enrichment/phase-mapping.schema.json\",\n \"timing-flags\": \"https://40kdc.dev/schemas/enrichment/timing-flag.schema.json\",\n \"interaction-flags\": \"https://40kdc.dev/schemas/enrichment/interaction-flag.schema.json\",\n abilities: \"https://40kdc.dev/schemas/enrichment/ability-dsl/ability.schema.json\",\n \"resource-pools\": \"https://40kdc.dev/schemas/enrichment/resource-pool.schema.json\",\n};\n\n/**\n * Determine which schema $id to use for a given data file path.\n * Convention: the file's base name starts with a SCHEMA_MAP prefix (real data is\n * `<prefix>.json`; test fixtures are `<prefix>-good.json` / `<prefix>-bad.json`).\n * Prefixes are tried longest-first so `wargear-options.json` resolves to the\n * wargear-option schema rather than the shorter `wargear` key (distinct entities).\n */\nconst SCHEMA_PREFIXES = Object.keys(SCHEMA_MAP).sort((a, b) => b.length - a.length);\nfunction resolveSchemaId(filePath: string): string | null {\n const base = basename(filePath);\n for (const prefix of SCHEMA_PREFIXES) {\n if (base.startsWith(prefix)) return SCHEMA_MAP[prefix];\n }\n return null;\n}\n\n/**\n * Validate all data files matching the given glob pattern.\n * Each data file is expected to be a JSON array; each element is validated individually.\n */\nexport async function validateFiles(\n ajv: Ajv,\n pattern: string,\n cwd?: string,\n): Promise<ValidationResult> {\n const root = cwd ?? DATA_ROOT;\n const files = await glob(pattern, { cwd: root, absolute: true });\n\n const result: ValidationResult = {\n totalFiles: files.length,\n totalItems: 0,\n passed: 0,\n failed: 0,\n errors: [],\n };\n\n for (const file of files) {\n // Underscore-prefixed files are scratch/reports (e.g. the converter's\n // `_wargear-options.unparsed.json`), not dataset entities — skip them.\n if (basename(file).startsWith(\"_\")) continue;\n const schemaId = resolveSchemaId(file);\n if (!schemaId) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: `No schema mapping found for file: ${basename(file)}` }],\n });\n result.failed++;\n continue;\n }\n\n const validate = ajv.getSchema(schemaId);\n if (!validate) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: `Schema not found: ${schemaId}` }],\n });\n result.failed++;\n continue;\n }\n\n let data: unknown;\n try {\n const raw = readFileSync(file, \"utf-8\");\n data = JSON.parse(raw);\n } catch (err) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: `Failed to parse JSON: ${(err as Error).message}` }],\n });\n result.failed++;\n continue;\n }\n\n if (!Array.isArray(data)) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: \"Data file must be a JSON array\" }],\n });\n result.failed++;\n continue;\n }\n\n for (let i = 0; i < data.length; i++) {\n result.totalItems++;\n const valid = validate(data[i]);\n if (valid) {\n result.passed++;\n } else {\n result.failed++;\n result.errors.push({\n file,\n index: i,\n errors: (validate.errors ?? []).map((e) => ({\n path: e.instancePath || \"/\",\n message: e.message ?? \"Unknown validation error\",\n })),\n });\n }\n }\n }\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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","sourcesContent":["import type Ajv from \"ajv\";\nimport { readFileSync } from \"node:fs\";\nimport { glob } from \"glob\";\nimport { resolve, basename } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\nconst DATA_ROOT = resolve(__dirname, \"../../data\");\n\nexport interface ValidationError {\n file: string;\n index: number;\n errors: Array<{ path: string; message: string }>;\n}\n\nexport interface ValidationResult {\n totalFiles: number;\n totalItems: number;\n passed: number;\n failed: number;\n errors: ValidationError[];\n}\n\n/**\n * Map from data file base-name prefix to schema $id.\n */\nconst SCHEMA_MAP: Record<string, string> = {\n factions: \"https://40kdc.dev/schemas/core/faction.schema.json\",\n units: \"https://40kdc.dev/schemas/core/unit.schema.json\",\n \"target-profiles\": \"https://40kdc.dev/schemas/core/target-profile.schema.json\",\n weapons: \"https://40kdc.dev/schemas/core/weapon.schema.json\",\n \"weapon-keywords\": \"https://40kdc.dev/schemas/core/weapon-keyword.schema.json\",\n \"game-versions\": \"https://40kdc.dev/schemas/core/game-version.schema.json\",\n detachments: \"https://40kdc.dev/schemas/core/detachment.schema.json\",\n enhancements: \"https://40kdc.dev/schemas/core/enhancement.schema.json\",\n stratagems: \"https://40kdc.dev/schemas/core/stratagem.schema.json\",\n \"wargear-options\": \"https://40kdc.dev/schemas/core/wargear-option.schema.json\",\n wargear: \"https://40kdc.dev/schemas/core/wargear.schema.json\",\n \"leader-attachments\": \"https://40kdc.dev/schemas/core/leader-attachment.schema.json\",\n \"unit-compositions\": \"https://40kdc.dev/schemas/core/unit-composition.schema.json\",\n \"force-dispositions\": \"https://40kdc.dev/schemas/core/force-disposition.schema.json\",\n \"deployment-patterns\": \"https://40kdc.dev/schemas/core/deployment-pattern.schema.json\",\n \"mission-matchups\": \"https://40kdc.dev/schemas/core/mission-matchup.schema.json\",\n missions: \"https://40kdc.dev/schemas/core/mission.schema.json\",\n \"secondary-cards\": \"https://40kdc.dev/schemas/core/secondary-card.schema.json\",\n \"terrain-templates\": \"https://40kdc.dev/schemas/core/terrain-template.schema.json\",\n \"terrain-layouts\": \"https://40kdc.dev/schemas/core/terrain-layout.schema.json\",\n \"hull-shapes\": \"https://40kdc.dev/schemas/core/hull-shape.schema.json\",\n \"phase-mappings\": \"https://40kdc.dev/schemas/enrichment/phase-mapping.schema.json\",\n \"timing-flags\": \"https://40kdc.dev/schemas/enrichment/timing-flag.schema.json\",\n \"interaction-flags\": \"https://40kdc.dev/schemas/enrichment/interaction-flag.schema.json\",\n abilities: \"https://40kdc.dev/schemas/enrichment/ability-dsl/ability.schema.json\",\n \"resource-pools\": \"https://40kdc.dev/schemas/enrichment/resource-pool.schema.json\",\n};\n\n/**\n * Determine which schema $id to use for a given data file path.\n * Convention: the file's base name starts with a SCHEMA_MAP prefix (real data is\n * `<prefix>.json`; test fixtures are `<prefix>-good.json` / `<prefix>-bad.json`).\n * Prefixes are tried longest-first so `wargear-options.json` resolves to the\n * wargear-option schema rather than the shorter `wargear` key (distinct entities).\n */\nconst SCHEMA_PREFIXES = Object.keys(SCHEMA_MAP).sort((a, b) => b.length - a.length);\nfunction resolveSchemaId(filePath: string): string | null {\n const base = basename(filePath);\n for (const prefix of SCHEMA_PREFIXES) {\n if (base.startsWith(prefix)) return SCHEMA_MAP[prefix];\n }\n return null;\n}\n\n/**\n * Validate all data files matching the given glob pattern.\n * Each data file is expected to be a JSON array; each element is validated individually.\n */\nexport async function validateFiles(\n ajv: Ajv,\n pattern: string,\n cwd?: string,\n): Promise<ValidationResult> {\n const root = cwd ?? DATA_ROOT;\n const files = await glob(pattern, { cwd: root, absolute: true });\n\n const result: ValidationResult = {\n totalFiles: files.length,\n totalItems: 0,\n passed: 0,\n failed: 0,\n errors: [],\n };\n\n for (const file of files) {\n // Underscore-prefixed files are scratch/reports (e.g. the converter's\n // `_wargear-options.unparsed.json`), not dataset entities — skip them.\n if (basename(file).startsWith(\"_\")) continue;\n const schemaId = resolveSchemaId(file);\n if (!schemaId) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: `No schema mapping found for file: ${basename(file)}` }],\n });\n result.failed++;\n continue;\n }\n\n const validate = ajv.getSchema(schemaId);\n if (!validate) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: `Schema not found: ${schemaId}` }],\n });\n result.failed++;\n continue;\n }\n\n let data: unknown;\n try {\n const raw = readFileSync(file, \"utf-8\");\n data = JSON.parse(raw);\n } catch (err) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: `Failed to parse JSON: ${(err as Error).message}` }],\n });\n result.failed++;\n continue;\n }\n\n if (!Array.isArray(data)) {\n result.errors.push({\n file,\n index: -1,\n errors: [{ path: \"\", message: \"Data file must be a JSON array\" }],\n });\n result.failed++;\n continue;\n }\n\n for (let i = 0; i < data.length; i++) {\n result.totalItems++;\n const valid = validate(data[i]);\n if (valid) {\n result.passed++;\n } else {\n result.failed++;\n result.errors.push({\n file,\n index: i,\n errors: (validate.errors ?? []).map((e) => ({\n path: e.instancePath || \"/\",\n message: e.message ?? \"Unknown validation error\",\n })),\n });\n }\n }\n }\n\n return result;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alpaca-software/40kdc-data",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The 40kdc Warhammer 40K dataset behind a linked, typed API — find units, follow them to their weapons, abilities, phases, and factions. Also validates data against the canonical JSON Schemas.",
|
|
6
6
|
"keywords": [
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"translate": "tsx src/cli.ts translate",
|
|
65
65
|
"audit:coverage": "tsx src/cli.ts audit-coverage --write",
|
|
66
66
|
"scrub:defensive-flag": "tsx src/scrub-defensive-flag.ts",
|
|
67
|
+
"extract:faction-pack": "tsx src/extract-faction-pack.ts",
|
|
67
68
|
"author:input": "tsx src/author-input.ts",
|
|
68
69
|
"author:seed": "tsx src/author-seed.ts",
|
|
69
70
|
"author:propose": "tsx src/author-batch.ts propose",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/core/hull-shape.schema.json",
|
|
4
|
+
"title": "Hull Shape",
|
|
5
|
+
"description": "A model's 2D collision footprint as an explicit polygon, used in place of a circular/oval base for vehicles and other hull-based models. Points are authored in local inches (y-down); a consumer re-centers the polygon on its area centroid before placement, so the local origin does not affect where the model lands — only its shape matters (mirrors the terrain-template footprint convention). A hull shape is faction-agnostic and reusable: one outline (e.g. a Rhino chassis) is authored once and referenced by `hull_shape_id` from every model that shares that hull, across factions. This entity stores geometry only — never an image, image URL, or any source-asset metadata.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
9
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
10
|
+
"points": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"description": "Polygon vertices in local inches (y-down), in order around the outline. A hull is always a polygon (never a rectangle/right-triangle), so the points are given directly rather than via the shared `footprint` oneOf.",
|
|
13
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/vec2" },
|
|
14
|
+
"minItems": 3
|
|
15
|
+
},
|
|
16
|
+
"bounds_width_in": {
|
|
17
|
+
"type": "number",
|
|
18
|
+
"exclusiveMinimum": 0,
|
|
19
|
+
"description": "Cached axis-aligned bounding-box width in inches (max x − min x). Derived from `points`; recorded so consumers can size/scale without recomputing."
|
|
20
|
+
},
|
|
21
|
+
"bounds_height_in": {
|
|
22
|
+
"type": "number",
|
|
23
|
+
"exclusiveMinimum": 0,
|
|
24
|
+
"description": "Cached axis-aligned bounding-box height in inches (max y − min y). Derived from `points`."
|
|
25
|
+
},
|
|
26
|
+
"game_version": { "$ref": "../defs/game-version-ref.schema.json" }
|
|
27
|
+
},
|
|
28
|
+
"required": ["id", "name", "points", "bounds_width_in", "bounds_height_in", "game_version"],
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
}
|
|
@@ -39,12 +39,10 @@
|
|
|
39
39
|
],
|
|
40
40
|
"description": "Resolved primary faction; null when the source faction could not be matched."
|
|
41
41
|
},
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
],
|
|
47
|
-
"description": "Resolved detachment; null when absent or unmatched."
|
|
42
|
+
"detachments": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"description": "Resolved detachments. 11e lists may field several detachments under a detachment-point cap; pre-11e lists carry zero or one. Order is load-bearing (source/parse order). Empty when the source declared no detachment.",
|
|
45
|
+
"items": { "$ref": "#/$defs/roster-detachment" }
|
|
48
46
|
},
|
|
49
47
|
"battle_size": {
|
|
50
48
|
"oneOf": [
|
|
@@ -61,6 +59,10 @@
|
|
|
61
59
|
"oneOf": [{ "type": "integer", "minimum": 0 }, { "type": "null" }],
|
|
62
60
|
"description": "Points ceiling parsed from the battle size (e.g. 2000), if known."
|
|
63
61
|
},
|
|
62
|
+
"detachment_cap": {
|
|
63
|
+
"oneOf": [{ "type": "integer", "minimum": 0 }, { "type": "null" }],
|
|
64
|
+
"description": "11e detachment-point budget derived from the battle size (strike-force 3, incursion 2); null when the battle size is unknown. The sum of each detachment's `dp_cost` is meant to fit within this cap."
|
|
65
|
+
},
|
|
64
66
|
"total_reported": {
|
|
65
67
|
"oneOf": [{ "type": "integer", "minimum": 0 }, { "type": "null" }],
|
|
66
68
|
"description": "Total points as reported by the source roster's cost block."
|
|
@@ -71,7 +73,7 @@
|
|
|
71
73
|
"description": "Sum of this roster's per-unit point values."
|
|
72
74
|
}
|
|
73
75
|
},
|
|
74
|
-
"required": ["declared_limit", "total_reported", "total_computed"],
|
|
76
|
+
"required": ["declared_limit", "detachment_cap", "total_reported", "total_computed"],
|
|
75
77
|
"additionalProperties": false
|
|
76
78
|
},
|
|
77
79
|
"units": {
|
|
@@ -81,7 +83,7 @@
|
|
|
81
83
|
"game_version": { "$ref": "../defs/game-version-ref.schema.json" },
|
|
82
84
|
"diagnostics": { "$ref": "#/$defs/roster-diagnostics" }
|
|
83
85
|
},
|
|
84
|
-
"required": ["name", "source", "faction_id", "
|
|
86
|
+
"required": ["name", "source", "faction_id", "detachments", "battle_size", "points", "units", "game_version", "diagnostics"],
|
|
85
87
|
"additionalProperties": false,
|
|
86
88
|
"$defs": {
|
|
87
89
|
"roster-resolved-ref": {
|
|
@@ -122,6 +124,19 @@
|
|
|
122
124
|
"required": ["id", "raw_name", "resolved", "candidates"],
|
|
123
125
|
"additionalProperties": false
|
|
124
126
|
},
|
|
127
|
+
"roster-detachment": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"description": "One detachment selected on the roster, paired with its resolved detachment-point cost.",
|
|
130
|
+
"properties": {
|
|
131
|
+
"ref": { "$ref": "#/$defs/roster-resolved-ref" },
|
|
132
|
+
"dp_cost": {
|
|
133
|
+
"oneOf": [{ "type": "integer", "minimum": 0 }, { "type": "null" }],
|
|
134
|
+
"description": "Detachment-point cost (1–3) looked up from the resolved detachment entity's `detachment_points`. Null when the detachment is unresolved or the entity records no cost."
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"required": ["ref", "dp_cost"],
|
|
138
|
+
"additionalProperties": false
|
|
139
|
+
},
|
|
125
140
|
"roster-unit": {
|
|
126
141
|
"type": "object",
|
|
127
142
|
"properties": {
|
|
@@ -193,6 +208,7 @@
|
|
|
193
208
|
"weapon-unresolved",
|
|
194
209
|
"enhancement-unresolved",
|
|
195
210
|
"detachment-unresolved",
|
|
211
|
+
"detachment-points-exceeded",
|
|
196
212
|
"battle-size-unmapped",
|
|
197
213
|
"points-mismatch",
|
|
198
214
|
"leader-attachment-inferred",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"type": {
|
|
16
16
|
"type": "string",
|
|
17
17
|
"enum": ["battle-tactic", "strategic-ploy", "epic-deed", "wargear"],
|
|
18
|
-
"description": "GW-printed stratagem category from the card"
|
|
18
|
+
"description": "GW-printed stratagem category from the card. Optional: 11e faction packs omit it for newly introduced detachments, and the category has no in-game effect; absent when the source does not state one."
|
|
19
19
|
},
|
|
20
20
|
"detachment_id": {
|
|
21
21
|
"oneOf": [
|
|
@@ -53,6 +53,6 @@
|
|
|
53
53
|
},
|
|
54
54
|
"game_version": { "$ref": "../defs/game-version-ref.schema.json" }
|
|
55
55
|
},
|
|
56
|
-
"required": ["id", "name", "category", "
|
|
56
|
+
"required": ["id", "name", "category", "cp_cost", "phases", "player_turn", "timing", "game_version"],
|
|
57
57
|
"additionalProperties": false
|
|
58
58
|
}
|
|
@@ -28,6 +28,13 @@
|
|
|
28
28
|
"base_size_mm": {
|
|
29
29
|
"description": "This model's base. Absent when no base could be resolved for the model.",
|
|
30
30
|
"$ref": "../defs/common.schema.json#/$defs/base-size"
|
|
31
|
+
},
|
|
32
|
+
"hull_shape_id": {
|
|
33
|
+
"description": "Optional reference to a hull-shape entity giving this model's 2D collision polygon, used instead of the circular/oval base footprint. By convention a model carrying this should set `base_size_mm.shape` to \"hull\".",
|
|
34
|
+
"oneOf": [
|
|
35
|
+
{ "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
36
|
+
{ "type": "null" }
|
|
37
|
+
]
|
|
31
38
|
}
|
|
32
39
|
},
|
|
33
40
|
"required": ["name", "min", "max"],
|
|
@@ -39,6 +39,20 @@
|
|
|
39
39
|
},
|
|
40
40
|
"effect": { "$ref": "effect.schema.json" },
|
|
41
41
|
"scope": { "$ref": "scope.schema.json" },
|
|
42
|
+
"applies_to": {
|
|
43
|
+
"description": "Static, human-curated keyword filter naming which datasheet units this ability benefits, for roster-side highlighting. A unit matches when it carries every keyword in `required_keywords` (across its `keywords` + `faction_keywords`) and none in `excluded_keywords`. This is a denormalized projection distinct from the runtime `effect` condition tree (which mixes static class, runtime-granted markers, and timing gates and must not be scraped for scope). Absent/null means no resolvable unit scope — consumers render no highlight rather than guess.",
|
|
44
|
+
"oneOf": [
|
|
45
|
+
{
|
|
46
|
+
"type": "object",
|
|
47
|
+
"properties": {
|
|
48
|
+
"required_keywords": { "$ref": "../../defs/common.schema.json#/$defs/keyword-list" },
|
|
49
|
+
"excluded_keywords": { "$ref": "../../defs/common.schema.json#/$defs/keyword-list" }
|
|
50
|
+
},
|
|
51
|
+
"additionalProperties": false
|
|
52
|
+
},
|
|
53
|
+
{ "type": "null" }
|
|
54
|
+
]
|
|
55
|
+
},
|
|
42
56
|
"interactions": {
|
|
43
57
|
"type": "array",
|
|
44
58
|
"items": {
|