Skip to content

feat: couple trf types to @echecs/tournament #24

@mormubis

Description

@mormubis

couple trf directly to @echecs/tournament types. parse() returns TournamentData, stringify() takes TournamentData. the adapter in endorsement (trfToSwiss()) becomes unnecessary.

supersedes #23.

depends on echecsjs/tournament#20.


what changes

parse() output

  • returns TournamentData | null (from @echecs/tournament)
  • Player.id is string (was number as pairingNumber)
  • Player.startingRank set to the numeric pairing number
  • Player.points and Player.rank read from file as-is (source of truth)
  • results stored as CompletedRound[] with Game[] — not per-player RoundResult[]
  • ResultCode mapped internally to Game.result ('white' / 'black' / 'draw' / 'none') + Game.forfeit + Game.rated
  • byes stored as Bye objects (separate from games) with kind: 'full' | 'half' | 'zero' | 'pairing'
  • TRF metadata mapped to TournamentMetadata (chiefArbiter, city, comments, roundDates, etc.)
  • AbnormalPoints (tag 299) mapped to PointAdjustment[]

game construction from TRF lines

TRF stores results per-player (each 001 line has that player's round results). parse builds Game objects by taking the white player's entry as canonical. black player's entry is cross-checked — if it disagrees, a warning is emitted via onWarning.

mapping from TRF result codes to Game:

TRF code result forfeit rated
1 'white' (or 'black') - true
0 'black' (or 'white') - true
= 'draw' - true
W 'white' (or 'black') - false
D 'draw' - false
L 'black' (or 'white') - false
+ winner side loser side -
- winner side loser side -
F - - bye: 'full'
H - - bye: 'half'
Z - - bye: 'zero'
U - - bye: 'pairing'

result direction depends on which player's line we're reading (white or black).

stringify() input

  • takes TournamentData + StringifyOptions
  • StringifyOptions.version controls TRF16 vs TRF26 output (default: TRF26)
  • reconstructs per-player result columns from CompletedRound[].games
  • for each player in each round: finds the game involving that player, determines their color, maps Game.result + Game.forfeit + Game.rated back to a TRF result code
  • reads Player.points and Player.rank directly (no recomputation)
  • uses Player.startingRank for pairing number when present, otherwise assigns sequential numbers
  • maps PointAdjustment[] back to AbnormalPoints (tag 299)
  • writes TournamentMetadata fields to header tags
  • derives NRS line fields (name, birthDate, sex) from the Player object

removed exports

  • ResultCode — internal to parse/stringify
  • RoundResult — replaced by Game (from tournament)
  • Sex, Title — on Player (from tournament)
  • Tournament type — replaced by TournamentData (from tournament)
  • Version — stays but not on the data model, only in StringifyOptions

new dependency

@echecs/tournament becomes a dependency (for types only — no runtime code imported).


encoding types that stay in trf

these are TRF format details, not domain concepts:

  • Version ('TRF16' | 'TRF26')
  • TeamRoundResult / TeamRoundResult801 / TeamRoundResult802 — two encoding variants for team round results. parse maps both into the clean TeamRoundResult domain shape (if added to tournament). stringify picks the encoding based on version/context.
  • AbnormalPoints raw type codes — parse maps to PointAdjustment, stringify maps back
  • OutOfOrderLineup — TRF-specific team lineup exception record
  • ForfeitedMatch with '+-' | '-+' | '--' codes — derivable from games with forfeits
  • TeamPairingAllocatedBye — TRF-specific team bye allocation format
  • ParseError, ParseWarning, ParseOptions, StringifyOptions

test migration

~387 tests. every assertion that checks player.results, player.points, player.rank, or ResultCode values needs updating. the main categories:

  • player shape assertionspairingNumberid (string), results → gone (check rounds instead), points/rank still present
  • result assertionsResultCode strings → Game.result / Game.forfeit / Game.rated
  • round-trip tests (parse → stringify → parse) — most critical. validate lossless conversion through the new data model.
  • fixture tests — 6 real-world TRF files. all assertions need rewriting for new shapes.

implementation order

  1. feat: widen types for trf/swiss integration tournament#20 ships first — new types available
  2. add @echecs/tournament as dependency
  3. rewrite src/types.ts — import from tournament, keep encoding types
  4. rewrite src/parse.ts — build TournamentData with CompletedRound[], map result codes
  5. rewrite src/stringify.ts — consume TournamentData, reconstruct per-player lines
  6. rewrite tests
  7. update src/index.ts exports

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions