Skip to Content
Game ImportersEchoes of AstraAdrVariant Slug + Influence "X" Handling

Variant Slug + Influence “X” Handling

Date2026-06-03
StatusAccepted
Decision Makers@GaultierRomon

Context and Problem Statement

The Echoes of Astra Products sheet has two columns that don’t fit the generic SheetImporter cleanly:

  • variant — every row has a value (Normal, Serialized, Framebreak, or Signature). The base importer appends any non-"standard" variant to the printing slug, so Normal rows would all get a redundant -normal suffix.
  • influence — most cards have a numeric value (0–3), but some have the literal X (variable influence). The base importer coerces range attributes with Number(), turning X into NaN.

Decision Drivers

  • Slugs must stay stable and clean. Games without a variant column produce …-imp001 / …-imp001-foil; Echoes of Astra should match that for its base printings.
  • Special variants are genuinely distinct printings and must keep a differentiating slug.
  • NaN must never be persisted to the database.
  • We must not modify the shared SheetImporter for one game’s quirks.

Considered Options

  1. Override transformSheetProduct in EoaImporter — handle both quirks locally.
  2. Modify the base SheetImporter — rejected; leaks game-specific behaviour into shared code.
  3. Pre-process the sheet — rejected; the sheet is publisher-owned.

Decision Outcome

Chosen option: Override transformSheetProduct in EoaImporter.

Variant

const rawVariant = product.variant != null ? String(product.variant) : undefined const isNormalVariant = !rawVariant || rawVariant.toLowerCase() === "normal" // Neutralize "Normal" so the base slug builder skips the suffix. if (isNormalVariant) product.variant = undefined const card = super.transformSheetProduct(product, expansion) // Restore + persist the real variant so it stays filterable. product.variant = rawVariant if (rawVariant) card.printings[0].variant = rawVariant as EoaVariant
  • Normal → no slug suffix, but the printing still stores variant: "Normal" for filtering.
  • Serialized / Framebreak / Signature → kept on product.variant, so the base builder appends the suffix and auto-maps the attribute. They form distinct printings (e.g. …imp045-serialized-foil).

Influence

const cardRecord = card as unknown as Record<string, unknown> for (const stat of ["supplyCost", "influence", "attack", "health"]) { if (typeof cardRecord[stat] === "number" && Number.isNaN(cardRecord[stat] as number)) { delete cardRecord[stat] } }

Any stat that coerced to NaN (in practice only influence: "X") is stripped, so cards with variable influence simply have no numeric influence rather than a poisoned value. Range filters and the SEO builder skip the missing field cleanly.

Consequences

  • âś… Clean, stable slugs; special variants remain distinguishable.
  • âś… No NaN reaches the database; range filters behave.
  • ⚠️ Cards with X influence are not matched by any influence range filter (acceptable — X is not a fixed value).
Last updated on