brackt/app/lib/parse-results-text.ts
Chris Parsons 1798020c74
feat: batch qualifying results entry (#290)
Fixes #289

* docs: add batch qualifying results entry design spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: add batch qualifying results entry implementation plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: ignore .worktrees directory

* feat: add qualifying results text parser with tests

* fix: handle no-space after dot separator, tighten T-prefix to uppercase only

* feat: add batch-add-results server intent with duplicate filtering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add create-participant intent for inline participant creation

* fix: trim sportsSeasonId validation in create-participant intent

* feat: fill 0-QP rows for unplaced participants on qualifying event finalize

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* perf: use bulk insert for 0-QP rows on qualifying event finalize

* feat: add BatchResultEntry component for paste-and-parse batch result import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: disable add participant button while create request is in flight

* feat: render BatchResultEntry on qualifying event pages

Add BatchResultEntry component import and render it on event pages when
the event is a qualifying event, not a final_standings/playoff_game type,
and not yet complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address final review issues (sportsSeasonId authority, participant validation, CRLF, unused prop)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 14:52:22 -07:00

51 lines
1.4 KiB
TypeScript

export interface ParsedLine {
placement: number;
rawName: string;
}
/**
* Parse a pasted results text into placement + name pairs.
*
* Supported formats per line:
* 1. Name (dot separator)
* 1, Name (comma separator)
* 1 Name (space separator)
* T3. Name (T-prefix tie, dot separator)
* T3, Name (T-prefix tie, comma separator)
* T3 Name (T-prefix tie, space separator)
*
* Repeated rank numbers across consecutive lines are both emitted
* with the same placement (treated as ties automatically).
* Blank lines are ignored.
*/
export function parseResultsText(text: string): ParsedLine[] {
const results: ParsedLine[] = [];
for (const rawLine of text.split(/\r?\n/)) {
const line = rawLine.trim();
if (!line) continue;
// Try to match: optional T, digits, optional separator (. or ,), then whitespace and the name
// Pattern 1: "1. Name", "1, Name", "T3. Name", "T3, Name"
const match = line.match(/^T?(\d+)[.,]\s*(.+)$/);
if (match) {
results.push({
placement: parseInt(match[1], 10),
rawName: match[2].trim(),
});
continue;
}
// Pattern 2: "1 Name", "T3 Name" (space-only separator)
const spaceMatch = line.match(/^T?(\d+)\s+(.+)$/);
if (spaceMatch) {
results.push({
placement: parseInt(spaceMatch[1], 10),
rawName: spaceMatch[2].trim(),
});
continue;
}
}
return results;
}