All files / web/src/lib/abacus identity.ts

100% Statements 52/52
100% Branches 13/13
100% Functions 1/1
100% Lines 52/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 532x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 60x 58x 58x 58x 60x 60x 3x 3x 52x 52x  
/**
 * The abacus identity triple — the shared vocabulary between the
 * player_abacus_identity table, its API route, and the studio UI.
 *
 * Deliberately framework- and drizzle-free so client components can import
 * the constants without dragging the DB schema into the bundle.
 */
 
export const ABACUS_COLOR_SCHEMES = [
  'monochrome',
  'place-value',
  'heaven-earth',
  'alternating',
] as const
 
export const ABACUS_COLOR_PALETTES = [
  'default',
  'colorblind',
  'mnemonic',
  'grayscale',
  'nature',
] as const
 
export type AbacusColorScheme = (typeof ABACUS_COLOR_SCHEMES)[number]
export type AbacusColorPalette = (typeof ABACUS_COLOR_PALETTES)[number]
 
/** The player-bound "my abacus": style (scheme + palette) and form (columns) */
export interface AbacusIdentity {
  colorScheme: AbacusColorScheme
  colorPalette: AbacusColorPalette
  columns: number
}
 
/** What a player without a saved row shows: the stock abacus */
export const DEFAULT_ABACUS_IDENTITY: AbacusIdentity = {
  colorScheme: 'place-value',
  colorPalette: 'default',
  columns: 4,
}
 
/** Runtime guard for API input and loose string fields (returns null on any mismatch) */
export function parseAbacusIdentity(input: unknown): AbacusIdentity | null {
  if (typeof input !== 'object' || input === null) return null
  const { colorScheme, colorPalette, columns } = input as Record<string, unknown>
  const scheme = ABACUS_COLOR_SCHEMES.find((s) => s === colorScheme)
  const palette = ABACUS_COLOR_PALETTES.find((p) => p === colorPalette)
  if (!scheme || !palette) return null
  if (typeof columns !== 'number' || !Number.isInteger(columns) || columns < 1 || columns > 21) {
    return null
  }
  return { colorScheme: scheme, colorPalette: palette, columns }
}