PURPOSE

Pure sort utility for the Ships screen’s Upgrades tab. Orders an array of mod stacks by either acquisition recency (newest) or rarity tier (rarity), with a deterministic tie-break on the last uid in each stack.

OWNS

  • SortMode type — string literal union of 'newest' | 'rarity'.
  • StackForSort interface — minimal shape the sorter needs: templateId, rarity, uids (in acquisition order), hasUnseen flag.
  • RARITY_RANK table — module-private mapping from ModRarity to numeric rank (lower wins), legendary through common.
  • lastUid helper — module-private accessor that returns the last entry in a stack’s uids array, falling back to empty string for empty stacks.
  • sortUpgradeStacks — exported pure function that produces a new sorted array without mutating the input.

READS FROM

  • ModRarity from @starship-survivors/data/mods — used to type StackForSort.rarity and key the RARITY_RANK table.
  • Caller-supplied StackForSort[] — copies it via slice() before sorting.
  • Caller-supplied SortMode — selects which comparator branch runs.

PUSHES TO

Nothing. Pure function. Returns a new array; performs no I/O, no store writes, no side effects.

DOES NOT

  • Does not mutate the input array (uses slice() first).
  • Does not build the stacks — assumes callers have already grouped uids into StackForSort shapes and computed hasUnseen.
  • Does not read or update any unseen-uid set; consumes the precomputed hasUnseen boolean only.
  • Does not parse uids as timestamps — treats the last uid as an opaque string and uses localeCompare as the stable tie-break.
  • Does not render anything, does not subscribe to stores, does not handle empty stacks specially beyond the lastUid empty-string fallback.
  • Does not expose RARITY_RANK or lastUid — both are module-private.

Signals

  • SortMode'newest' or 'rarity'.
  • StackForSort.hasUnseen — true when any uid in the stack is unseen; in newest mode this lifts the stack above seen stacks.
  • RARITY_RANK ordering — legendary (0) < epic (1) < rare (2) < uncommon (3) < common (4).
  • Tie-break — lastUid(b).localeCompare(lastUid(a)) descending; newest acquisition (last appended uid) wins ties.

Entry points

  • sortUpgradeStacks(stacks, mode) — called by the Upgrades tab when rendering the stack grid.

Pattern notes

  • Pure-function module, no class, no state.
  • Acquisition recency is encoded by uid append-order in the source stacks, not by a separate timestamp — the sorter relies on the convention that callers push new uids to the end of uids.
  • The newest branch is a two-level sort: unseen-first, then last-uid descending. The rarity branch is also two-level: rarity rank ascending, then last-uid descending.
  • localeCompare on raw uid strings is used as a stable, total-order tie-break; the function does not assume uids are time-sortable, only that they compare consistently.
  • slice() then sort() keeps the function pure and safe to call inside selectors or memoized renders.