26 lines
1.1 KiB
TypeScript
26 lines
1.1 KiB
TypeScript
|
|
/**
|
||
|
|
* Pure helpers for the bracket-scoring route action, extracted so the
|
||
|
|
* knockout-detection logic can be unit-tested without the full action harness.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* From a set of matches being scored this action, return the season_participant
|
||
|
|
* ids knocked out for the FIRST time. A loser counts only when its match was NOT
|
||
|
|
* already complete — a re-score/correction of a finished match must not
|
||
|
|
* re-announce the exit (mirrors populateBracketFromDraw's first-completion rule in
|
||
|
|
* the live-sync path). Entries with an unknown loser (`null`) are skipped.
|
||
|
|
*
|
||
|
|
* The ids are season_participant ids of the primary window (playoff_matches are
|
||
|
|
* keyed by season_participant); the fan-out translates them to each mirror
|
||
|
|
* window's own season_participant id before announcing the "Knocked Out" section.
|
||
|
|
*/
|
||
|
|
export function newlyDecidedLosers(
|
||
|
|
entries: Array<{ wasComplete: boolean; loserId: string | null }>
|
||
|
|
): string[] {
|
||
|
|
return entries
|
||
|
|
.filter((e): e is { wasComplete: boolean; loserId: string } =>
|
||
|
|
!e.wasComplete && e.loserId !== null
|
||
|
|
)
|
||
|
|
.map((e) => e.loserId);
|
||
|
|
}
|