Version v2.0.0#9
Conversation
WalkthroughThe change replaces Zod-based list-data schemas with explicit TypeScript validation and structured validation results. Shared validators now collect issues, while Flames of War V4, Great War V4, and Team Yankee V2 expose validation and default-value APIs. Static metadata gains display fields and era-aware mappings, with option and display helpers moved into dedicated modules. List display-name helpers, barrel exports, tests, spelling configuration, and coverage settings are also updated. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/battlefront/_shared/schema/listData.validators.ts (1)
90-104: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse own-property checks for static-data keys.
The
inoperator accepts inherited names such astoStringandconstructor. For example, an optionalforceDiagram: "toString"can be treated as recognized and produce no issue. Replace every listed membership check with a shared own-property check.Also applies to: 133-135, 169-170, 214-216, 332-349, 440-457
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/battlefront/_shared/schema/listData.validators.ts` around lines 90 - 104, Replace every static-data membership test in listData.validators.ts, including the checks near the force diagram, faction, unit, and related validation blocks, with the shared own-property check. Ensure inherited keys such as toString and constructor are rejected while valid own keys retain the existing validation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/battlefront/_shared/schema/listData.ts`:
- Around line 25-64: Update validateListDataShape and each public
validate(rawFormData: unknown) entry point to perform shared runtime structural
validation before casting, normalization, metadata checks, or iterating
formations, units, and commandCards. Reject null and objects missing meta or
required array fields by returning { success: false, issues } instead of
dereferencing them, while preserving existing cross-field validation for
structurally valid data; add malformed-input tests.
In `@src/battlefront/flamesOfWarV4/schema/listData.ts`:
- Around line 64-96: Make validate safely handle malformed rawFormData before
accessing formData.meta or iterating formData.units. Replace the unsafe
cast-only flow with structural guards or the existing schema validation so null,
undefined, and missing nested properties produce ValidationIssue results rather
than throwing; preserve normal normalization, slot validation, and points-limit
validation for valid ListDataFormData.
In `@src/battlefront/flamesOfWarV4/static/factions.helpers.ts`:
- Around line 15-61: Normalize nullable era and alignment filters to undefined
at the start of getFactionOptions, and return all faction entries when neither
normalized filter is active, including for an empty object. Update
getForceDiagramOptions in
src/battlefront/flamesOfWarV4/static/forceDiagrams.helpers.ts (lines 9-35) to
use nullish checks for every optional filter, then add regression coverage for
empty and nullable filter objects in both helpers.
In `@src/battlefront/greatWarV4/schema/listData.ts`:
- Around line 56-87: Update validate to defensively read the unknown rawFormData
structure before accessing nested fields: use safe optional access for
formData.meta values and provide an empty-array fallback when iterating
formData.units. Preserve the existing validation and successful data
construction behavior for complete payloads while preventing malformed or
incomplete input from throwing runtime TypeErrors.
In `@src/battlefront/greatWarV4/static/factions.helpers.ts`:
- Around line 1-19: Update getFactionDisplayAdjective to use the shared
getDisplayAdjective utility, matching the pattern used by companion helpers such
as the alignment helpers. Import the utility from the common internal helpers
and pass factions and the requested key through it, removing the manual presence
check and direct lookup.
In `@src/battlefront/teamYankeeV2/schema/listData.ts`:
- Around line 64-78: Update validate to check and normalize rawFormData before
accessing formData.meta or iterating formData.units; handle undefined, objects
without required arrays, and other malformed roots by returning a structured
ValidateListDataResult containing validation issues instead of throwing. Only
call validateListDataShape and continue unit validation after the root shape is
confirmed valid.
- Around line 98-110: Update getDefaultValues to deep-copy the collection fields
formations, units, and commandCards when constructing each result, rather than
reusing references from defaultValues. Preserve the existing scalar and meta
defaults while ensuring every caller receives independent collections that
cannot mutate shared defaults.
In `@src/battlefront/teamYankeeV2/static/factions.helpers.ts`:
- Around line 39-44: Update the filter checks in the faction filtering logic to
treat both null and undefined as unset: only compare era when filters.era is
non-null, and only compare alignment when filters.alignment is non-null.
Preserve the existing comparisons and return behavior for provided values.
In `@src/battlefront/teamYankeeV2/static/forceDiagrams.helpers.ts`:
- Around line 16-30: Update the filtering conditions in getForceDiagramOptions
so nullable filter values are treated as unset, matching the filter contract.
Adjust the faction, alignment, series, and era checks to skip filtering when
their corresponding value is null or undefined, while preserving existing
filtering for defined non-null values.
In `@src/battlefront/teamYankeeV2/static/forceDiagrams.test.ts`:
- Around line 61-69: Extend the combined filters test around
getForceDiagramOptions to include the era filter, asserting every returned
diagram belongs to the requested era. Also cover an era with no matching
diagrams by asserting the result is empty, using the existing era and
force-diagram symbols.
In `@src/common/_internal/getDisplayAdjective.ts`:
- Around line 8-9: Update the lookup in getDisplayAdjective to access
items[search] directly instead of creating and scanning Object.entries(items).
Preserve returning the matched entry’s displayAdjective, or undefined when no
value exists.
---
Outside diff comments:
In `@src/battlefront/_shared/schema/listData.validators.ts`:
- Around line 90-104: Replace every static-data membership test in
listData.validators.ts, including the checks near the force diagram, faction,
unit, and related validation blocks, with the shared own-property check. Ensure
inherited keys such as toString and constructor are rejected while valid own
keys retain the existing validation behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 804b85aa-3c12-4581-be4d-988ce874b0c4
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (108)
.vscode/settings.jsonsrc/battlefront/_shared/_fixtures/getIssueMessages.test.tssrc/battlefront/_shared/_fixtures/getIssueMessages.tssrc/battlefront/_shared/_fixtures/validateOptionSet.tssrc/battlefront/_shared/_internal/createGetForceDiagramData.tssrc/battlefront/_shared/_internal/createGetListDisplayName.tssrc/battlefront/_shared/schema/commandCard.tssrc/battlefront/_shared/schema/formation.tssrc/battlefront/_shared/schema/listData.test.tssrc/battlefront/_shared/schema/listData.tssrc/battlefront/_shared/schema/listData.validators.tssrc/battlefront/_shared/schema/registrationDetails.test.tssrc/battlefront/_shared/schema/registrationDetails.tssrc/battlefront/_shared/schema/unit.tssrc/battlefront/_shared/types.tssrc/battlefront/flamesOfWarV4/helpers/getListDisplayName.test.tssrc/battlefront/flamesOfWarV4/helpers/getListDisplayName.tssrc/battlefront/flamesOfWarV4/helpers/getValidGameSystemConfig.tssrc/battlefront/flamesOfWarV4/helpers/getValidMatchResultDetails.tssrc/battlefront/flamesOfWarV4/helpers/isGameSystemConfigValid.tssrc/battlefront/flamesOfWarV4/helpers/isMatchResultDetailsValid.tssrc/battlefront/flamesOfWarV4/index.tssrc/battlefront/flamesOfWarV4/schema/listData.test.tssrc/battlefront/flamesOfWarV4/schema/listData.tssrc/battlefront/flamesOfWarV4/schema/registrationDetails.test.tssrc/battlefront/flamesOfWarV4/schema/registrationDetails.tssrc/battlefront/flamesOfWarV4/static/alignments.helpers.tssrc/battlefront/flamesOfWarV4/static/alignments.tssrc/battlefront/flamesOfWarV4/static/dynamicPointsVersions.helpers.tssrc/battlefront/flamesOfWarV4/static/dynamicPointsVersions.tssrc/battlefront/flamesOfWarV4/static/eras.helpers.tssrc/battlefront/flamesOfWarV4/static/eras.tssrc/battlefront/flamesOfWarV4/static/factions.helpers.tssrc/battlefront/flamesOfWarV4/static/factions.tssrc/battlefront/flamesOfWarV4/static/forceDiagrams.helpers.tssrc/battlefront/flamesOfWarV4/static/forceDiagrams.test.tssrc/battlefront/flamesOfWarV4/static/forceDiagrams.tssrc/battlefront/flamesOfWarV4/static/lessonsFromTheFrontVersions.helpers.tssrc/battlefront/flamesOfWarV4/static/lessonsFromTheFrontVersions.tssrc/battlefront/flamesOfWarV4/static/missionPackVersions.helpers.tssrc/battlefront/flamesOfWarV4/static/missionPackVersions.tssrc/battlefront/flamesOfWarV4/static/series.helpers.tssrc/battlefront/flamesOfWarV4/static/series.tssrc/battlefront/flamesOfWarV4/static/units.helpers.tssrc/battlefront/flamesOfWarV4/static/units.tssrc/battlefront/flamesOfWarV4/types.tssrc/battlefront/greatWarV4/helpers/getListDisplayName.test.tssrc/battlefront/greatWarV4/helpers/getListDisplayName.tssrc/battlefront/greatWarV4/index.tssrc/battlefront/greatWarV4/schema/listData.test.tssrc/battlefront/greatWarV4/schema/listData.tssrc/battlefront/greatWarV4/static/alignments.helpers.tssrc/battlefront/greatWarV4/static/alignments.tssrc/battlefront/greatWarV4/static/factions.helpers.tssrc/battlefront/greatWarV4/static/factions.tssrc/battlefront/greatWarV4/static/forceDiagrams.helpers.tssrc/battlefront/greatWarV4/static/forceDiagrams.test.tssrc/battlefront/greatWarV4/static/forceDiagrams.tssrc/battlefront/greatWarV4/static/missionNames.helpers.tssrc/battlefront/greatWarV4/static/missionNames.tssrc/battlefront/greatWarV4/static/missionPackUtils.tssrc/battlefront/greatWarV4/static/missionPackVersions.helpers.tssrc/battlefront/greatWarV4/static/missionPackVersions.tssrc/battlefront/greatWarV4/static/pointsVersions.helpers.tssrc/battlefront/greatWarV4/static/pointsVersions.tssrc/battlefront/greatWarV4/static/units.helpers.tssrc/battlefront/greatWarV4/static/units.tssrc/battlefront/greatWarV4/types.tssrc/battlefront/index.tssrc/battlefront/teamYankeeV2/helpers/getListDisplayName.test.tssrc/battlefront/teamYankeeV2/helpers/getListDisplayName.tssrc/battlefront/teamYankeeV2/helpers/getValidGameSystemConfig.tssrc/battlefront/teamYankeeV2/helpers/getValidMatchResultDetails.tssrc/battlefront/teamYankeeV2/helpers/isGameSystemConfigValid.tssrc/battlefront/teamYankeeV2/helpers/isMatchResultDetailsValid.tssrc/battlefront/teamYankeeV2/index.tssrc/battlefront/teamYankeeV2/schema/listData.test.tssrc/battlefront/teamYankeeV2/schema/listData.tssrc/battlefront/teamYankeeV2/schema/registrationDetails.test.tssrc/battlefront/teamYankeeV2/schema/registrationDetails.tssrc/battlefront/teamYankeeV2/static/alignments.helpers.tssrc/battlefront/teamYankeeV2/static/alignments.tssrc/battlefront/teamYankeeV2/static/dynamicPointsVersions.helpers.tssrc/battlefront/teamYankeeV2/static/dynamicPointsVersions.tssrc/battlefront/teamYankeeV2/static/eras.helpers.tssrc/battlefront/teamYankeeV2/static/eras.tssrc/battlefront/teamYankeeV2/static/factions.helpers.tssrc/battlefront/teamYankeeV2/static/factions.tssrc/battlefront/teamYankeeV2/static/fieldManual101Versions.helpers.tssrc/battlefront/teamYankeeV2/static/fieldManual101Versions.tssrc/battlefront/teamYankeeV2/static/forceDiagrams.helpers.tssrc/battlefront/teamYankeeV2/static/forceDiagrams.test.tssrc/battlefront/teamYankeeV2/static/forceDiagrams.tssrc/battlefront/teamYankeeV2/static/missionPackVersions.helpers.tssrc/battlefront/teamYankeeV2/static/missionPackVersions.tssrc/battlefront/teamYankeeV2/static/series.helpers.tssrc/battlefront/teamYankeeV2/static/series.tssrc/battlefront/teamYankeeV2/static/units.helpers.tssrc/battlefront/teamYankeeV2/static/units.tssrc/battlefront/teamYankeeV2/types.tssrc/common/_internal/createEnumSchema.test.tssrc/common/_internal/emptyToUndefined.tssrc/common/_internal/getDisplayAdjective.test.tssrc/common/_internal/getDisplayAdjective.tssrc/common/_internal/index.tssrc/common/schemas/listDataId.tssrc/common/types.tsvitest.config.ts
💤 Files with no reviewable changes (37)
- src/battlefront/_shared/schema/commandCard.ts
- src/common/_internal/emptyToUndefined.ts
- src/battlefront/_shared/_internal/createGetForceDiagramData.ts
- src/battlefront/teamYankeeV2/helpers/isGameSystemConfigValid.ts
- src/battlefront/flamesOfWarV4/schema/registrationDetails.test.ts
- src/battlefront/_shared/schema/formation.ts
- src/battlefront/flamesOfWarV4/schema/registrationDetails.ts
- src/battlefront/flamesOfWarV4/helpers/getValidGameSystemConfig.ts
- src/battlefront/flamesOfWarV4/helpers/isGameSystemConfigValid.ts
- src/battlefront/teamYankeeV2/helpers/isMatchResultDetailsValid.ts
- src/battlefront/teamYankeeV2/schema/registrationDetails.ts
- src/battlefront/teamYankeeV2/static/eras.ts
- src/battlefront/greatWarV4/static/missionPackVersions.ts
- src/battlefront/_shared/schema/registrationDetails.ts
- src/battlefront/flamesOfWarV4/helpers/getValidMatchResultDetails.ts
- src/battlefront/teamYankeeV2/schema/registrationDetails.test.ts
- src/battlefront/teamYankeeV2/helpers/getValidGameSystemConfig.ts
- src/battlefront/index.ts
- src/battlefront/flamesOfWarV4/static/lessonsFromTheFrontVersions.ts
- src/battlefront/_shared/schema/unit.ts
- src/battlefront/teamYankeeV2/helpers/getValidMatchResultDetails.ts
- src/battlefront/_shared/schema/registrationDetails.test.ts
- src/battlefront/flamesOfWarV4/helpers/isMatchResultDetailsValid.ts
- src/battlefront/flamesOfWarV4/static/dynamicPointsVersions.ts
- src/battlefront/teamYankeeV2/static/series.ts
- vitest.config.ts
- src/battlefront/teamYankeeV2/static/fieldManual101Versions.ts
- src/battlefront/flamesOfWarV4/static/series.ts
- src/battlefront/teamYankeeV2/static/missionPackVersions.ts
- src/battlefront/flamesOfWarV4/static/units.ts
- src/battlefront/flamesOfWarV4/static/missionPackVersions.ts
- src/battlefront/teamYankeeV2/static/units.ts
- src/battlefront/greatWarV4/static/units.ts
- src/battlefront/teamYankeeV2/static/dynamicPointsVersions.ts
- src/battlefront/flamesOfWarV4/static/eras.ts
- src/battlefront/greatWarV4/static/pointsVersions.ts
- src/battlefront/greatWarV4/static/missionNames.ts
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/battlefront/_shared/helpers/validateListData.ts`:
- Around line 64-87: Update validateListData so formations, units, and
commandCards each produce structural validation issues when their corresponding
values are not arrays, rather than silently iterating an empty list. Preserve
normal validation for array values and keep requireLegal limited to legality
checks; update the affected expectation in validateListData tests so incomplete
data no longer returns success.
In `@src/battlefront/_shared/helpers/validateListData.validators.ts`:
- Line 80: Replace the inherited-property check in the relevant validators,
including the condition near value metadata recognition, with an own-property
predicate on the corresponding context map. Apply this consistently at all
indicated checks so keys such as constructor and toString are not accepted as
valid faction, alignment, era, force-diagram, or unit metadata.
- Around line 322-326: Update the validation checks using getValue in
validateListData so slotId, command-card sourceId, and formation/unit sourceId
are accepted only when their values are strings (while preserving required-value
checks). Ensure source-key validation runs even when context.units is empty, so
truthy objects or numbers cannot produce a successful result.
In `@src/battlefront/_shared/types.ts`:
- Around line 28-35: Constrain the TSourceId generic in both ListDataFormation
and ListDataUnit to string so their sourceId fields match the string-keyed
contracts enforced by validateFormation and validateUnit. Preserve the existing
type shapes and identifiers while adding the shared string constraint.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b53a5e4e-63cb-410a-b97c-313511310392
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (21)
package.jsonsrc/battlefront/_shared/helpers/validateListData.test.tssrc/battlefront/_shared/helpers/validateListData.tssrc/battlefront/_shared/helpers/validateListData.validators.tssrc/battlefront/_shared/schema/listData.tssrc/battlefront/_shared/types.tssrc/battlefront/flamesOfWarV4/schema/listData.tssrc/battlefront/flamesOfWarV4/static/factions.helpers.tssrc/battlefront/flamesOfWarV4/static/factions.test.tssrc/battlefront/flamesOfWarV4/static/forceDiagrams.helpers.tssrc/battlefront/flamesOfWarV4/static/forceDiagrams.test.tssrc/battlefront/greatWarV4/schema/listData.tssrc/battlefront/greatWarV4/static/factions.helpers.tssrc/battlefront/teamYankeeV2/schema/listData.tssrc/battlefront/teamYankeeV2/static/factions.helpers.tssrc/battlefront/teamYankeeV2/static/forceDiagrams.helpers.tssrc/battlefront/teamYankeeV2/static/forceDiagrams.test.tssrc/common/_internal/getDisplayAdjective.tssrc/common/_internal/getValue.test.tssrc/common/_internal/getValue.tssrc/common/_internal/index.ts
💤 Files with no reviewable changes (1)
- src/battlefront/_shared/schema/listData.ts
Branch Overview:
v2vsmain—combat-command-game-systemsScope: 105 files changed, 2,273 insertions / 1,418 deletions. This is the published npm package (
@ianpaschal/combat-command-game-systems) consumed bycombat-command. Unlike the main app repo, this package has real external consumers, so its API changes are genuinely breaking.Conceptual shift: Mirrors the
combat-commandfrontend change — removes registration-level detail schemas entirely, reworkslistDatavalidation from a Zod-schema-factory model to a plain asyncvalidate()function, and splits static data files into data-only modules plus companion.helpers.tsfiles.1.
ListDataSchema and Validatorssrc/battlefront/_shared/schema/listData.ts: 100 → 60 lines.src/battlefront/_shared/schema/listData.validators.ts: 253 → 400+ lines.Breaking API change:
createListDataSchema()factory returning a Zod schema. Consumers calledlistData.schema.safeParse(data)orlistData.createSchema(options).safeParse(data). Types:GenericListData,CreateListDataSchemaContext,CreateListDataSchemaOptions.validateListDataShape(data: ListDataShape, context: ListDataContext, options?: ListDataOptions) => ValidationIssue[]. Consumers now callawait listData.validate(data, options)at the game-system level, returningValidateListDataResult<T> = { success: true; data: T } | { success: false; issues: ValidationIssue[] }.ListDataContext,ListDataOptions,ListDataShape.flamesOfWarV4/schema/listData.ts):listData.schemaandlistData.createSchema()removed;listData.validate(),listData.defaultValues,listData.getDefaultValues(config)added.ListData/ListDataFormDatatypes are now more concrete (e.g.era: Erainstead of optional,sourceId: Unitinstead of Zod-inferred).greatWarV4/schema/listData.tsinitially shipped withoutgetDefaultValues(), unlikeflamesOfWarV4/teamYankeeV2. Added for symmetry, plus matching test coverage (.getDefaultValuesdescribe block, and the "not a valid unit ID" checks onformations/unitsthatgreatWarV4— likeflamesOfWarV4— can enforce via its realUnitenum).2.
registrationDetailsRemovalDeleted:
src/battlefront/_shared/schema/registrationDetails.ts(47 lines)src/battlefront/flamesOfWarV4/schema/registrationDetails.ts+ testsrc/battlefront/teamYankeeV2/schema/registrationDetails.ts+ testgreatWarV4never had one)Deprecated helpers deleted (per flamesOfWarV4 and teamYankeeV2 — already
@deprecatedon main):getValidGameSystemConfig.ts,getValidMatchResultDetails.ts,isGameSystemConfigValid.ts,isMatchResultDetailsValid.tsRoot export removed:
src/battlefront/index.tsdropsexport * from './_shared/schema/registrationDetails'.No replacement — this functionality is fully retired, not relocated.
3. Static Data Files →
.helpers.tsPatternAll game-system static data files (alignments, eras, factions, forceDiagrams, units, dynamicPointsVersions, series, missionPackVersions, etc.) split into a data-only
.tsfile plus a companion.helpers.tsfile.Example —
flamesOfWarV4/static/factions.ts:Factionenum,factionsrecord, and helpers (getFactionOptions(),getFactionDisplayName()).factions.ts(20 lines, enum + record only) +factions.helpers.ts(85 lines, all helpers).getFactionOptions()signature changed: now takesGetFactionOptionsFilters(alignment?,era?).getFactionDisplayAdjective(key?),getFactionAlignment(key, era).Partial<Record<Era, Alignment>>instead of a single value.Example —
dynamicPointsVersions.ts: data (65 lines) split from helpers (dynamicPointsVersions.helpers.ts, 23 lines) —getDynamicPointsVersionOptions(),getDynamicPointsVersionDisplayName()moved out.Breaking import paths:
Each game-system
index.tsnow re-exports all.helpersmodules, so importing from the game-system root (.../flamesOfWarV4) still works — only direct submodule imports break.4. New
getListDisplayNameHelperAdded per game system, each with a test:
flamesOfWarV4/helpers/getListDisplayName.ts(+ test, 60 lines)greatWarV4/helpers/getListDisplayName.ts(+ test, 56 lines)teamYankeeV2/helpers/getListDisplayName.ts(+ test, 60 lines)export const getListDisplayName = (listData?: Partial): string
Falls back in order: force diagram → faction → alignment →
"Unknown", appending" Force". e.g.getListDisplayName({ meta: { forceDiagram: ForceDiagram.DDayBritish } })→'D-Day: British Force'. Exported from each game-systemindex.ts.5. Root
src/battlefront/index.tsSingle line removed:
export * from './_shared/schema/registrationDetails';. Nothing else changed at this entry point.6.
src/common/schemas/listDataId.tsandsrc/common/types.tslistDataId.ts— breaking change:Consumers importing
listDataIdas a Zod schema factory will break — it's now a type + type guard.types.ts— additions:7.
commandCard.ts,formation.ts,unit.tsDeletionsAll three Zod schema factories deleted:
commandCard.ts(9 lines) — wasexport const commandCard = z.object({ id: listDataId(), sourceId: z.string(), appliedTo: listDataId() })formation.ts(13 lines) — wasexport const createFormationSchema = <T>(sourceId: T) => z.object({...})unit.ts(13 lines) — wasexport const createUnitSchema = <T>(sourceId: T) => z.object({...})Replaced implicitly by the
ListDataShapestructural type inlistData.validators.ts— no schema-factory equivalent remains._shared/types.tschanges:AlignmentMetadatagainsdisplayAdjective: string,displayPlural: string.FactionMetadata<TAlignment>andForceDiagramMetadata<TFaction, TSeries>removed from shared types, moved to per-game-systemtypes.tswith different shapes:flamesOfWarV4/teamYankeeV2:FactionMetadata<TEra, TAlignment>, era-aware (alignment: Partial<Record<TEra, TAlignment>>).greatWarV4:FactionMetadata<TAlignment>, single value, no era dimension.8. Dependencies
package.json: no version or dependency changes.package-lock.json: addslodash@^4.18.1(runtime) and@types/lodash@^4.17.24(dev) — confirmed in use, viagetDefaultValues()in each game system'slistData.ts(flamesOfWarV4,teamYankeeV2,greatWarV4).src/common/_internal/emptyToUndefined.tsdeleted (5 lines) — a Zod-specific transformer no longer needed.Fixed: those three
listData.tsfiles originally importedlodashasimport { merge } from 'lodash'.lodashis CommonJS, and that named-import syntax only resolves under bundlers (Vite, webpack) that shim CJS/ESM interop — it fails under Node's native ESM loader or any consumer that skips transformingnode_modules(e.g.combat-command'svitestproject forconvex/**, which runsedge-runtimewithexternal: ['**/node_modules/**']). Since this package ships its build output directly to consumers without bundling dependencies, that failure surfaced downstream, not in this repo's own tests. Changed toimport lodash from 'lodash'+lodash.merge(...), which works under both bundled and native-ESM consumption. No behavioral change — same function reference either way.Breaking Changes for Consumers
listDatavalidation API replaced.schema.safeParse()/createSchema()are gone; consumers must switch toawait listData.validate(data, options)returning{ success, data | issues }instead of Zod'sSafeParseReturnType..../static/factionsno longer export helper functions — they're in.../static/factions.helpers(or via the game-system's root index, which still re-exports everything).registrationDetailsschemas and deprecated helpers fully removed (getValidGameSystemConfig,getValidMatchResultDetails,isGameSystemConfigValid,isMatchResultDetailsValid) — no replacement, by design.commandCard,createFormationSchema,createUnitSchemadeleted — any direct import breaks.listDataIdis no longer a Zod schema factory — it's nowtype ListDataId = stringplusisListDataId()type guard.FactionMetadata/ForceDiagramMetadatashape changed and relocated out of shared types into per-game-system types, withflamesOfWarV4/teamYankeeV2now keying faction alignment by era (greatWarV4unaffected on this dimension since it has no eras).This lines up with (and is the underlying dependency for) the breaking changes found in the
combat-commandapp branch — that repo'spackage.jsoncurrently points at a localfile:tarball of this package rather than a published version, so these two branches need to land together.Summary by CodeRabbit
New Features
Bug Fixes