fitzroy 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +376 -212
- package/dist/index.d.ts +267 -261
- package/dist/index.js +121 -91
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -59,35 +59,40 @@ var init_result = __esm({
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
// src/lib/date-utils.ts
|
|
62
|
-
function parseFootyWireDate(dateStr) {
|
|
62
|
+
function parseFootyWireDate(dateStr, defaultYear) {
|
|
63
63
|
const trimmed = dateStr.trim();
|
|
64
64
|
if (trimmed === "") {
|
|
65
65
|
return null;
|
|
66
66
|
}
|
|
67
67
|
const withoutDow = trimmed.replace(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\w*\s+/i, "");
|
|
68
68
|
const normalised = withoutDow.replace(/-/g, " ");
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
const monthIndex = MONTH_ABBREV_TO_INDEX.get(monthStr.toLowerCase());
|
|
78
|
-
if (monthIndex === void 0) {
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
const year = Number.parseInt(yearStr, 10);
|
|
82
|
-
const day = Number.parseInt(dayStr, 10);
|
|
83
|
-
const date = new Date(Date.UTC(year, monthIndex, day));
|
|
84
|
-
if (Number.isNaN(date.getTime())) {
|
|
85
|
-
return null;
|
|
69
|
+
const fullMatch = /^(\d{1,2})\s+([A-Za-z]+)\s+(\d{4})$/.exec(normalised);
|
|
70
|
+
if (fullMatch) {
|
|
71
|
+
const [, dayStr, monthStr, yearStr] = fullMatch;
|
|
72
|
+
if (dayStr && monthStr && yearStr) {
|
|
73
|
+
return buildUtcDate(Number.parseInt(yearStr, 10), monthStr, Number.parseInt(dayStr, 10));
|
|
74
|
+
}
|
|
86
75
|
}
|
|
87
|
-
|
|
88
|
-
|
|
76
|
+
const shortMatch = /^(\d{1,2})\s+([A-Za-z]+)(?:\s+(\d{1,2}):(\d{2})(am|pm))?$/i.exec(normalised);
|
|
77
|
+
if (shortMatch && defaultYear != null) {
|
|
78
|
+
const [, dayStr, monthStr, hourStr, minStr, ampm] = shortMatch;
|
|
79
|
+
if (!dayStr || !monthStr) return null;
|
|
80
|
+
const monthIndex = MONTH_ABBREV_TO_INDEX.get(monthStr.toLowerCase());
|
|
81
|
+
if (monthIndex === void 0) return null;
|
|
82
|
+
const day = Number.parseInt(dayStr, 10);
|
|
83
|
+
const hasTime = hourStr && minStr && ampm;
|
|
84
|
+
if (!hasTime) {
|
|
85
|
+
return buildUtcDate(defaultYear, monthStr, day);
|
|
86
|
+
}
|
|
87
|
+
let aestHours = Number.parseInt(hourStr, 10);
|
|
88
|
+
const minutes = Number.parseInt(minStr, 10);
|
|
89
|
+
if (ampm.toLowerCase() === "pm" && aestHours < 12) aestHours += 12;
|
|
90
|
+
if (ampm.toLowerCase() === "am" && aestHours === 12) aestHours = 0;
|
|
91
|
+
const date = new Date(Date.UTC(defaultYear, monthIndex, day, aestHours - 10, minutes));
|
|
92
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
93
|
+
return date;
|
|
89
94
|
}
|
|
90
|
-
return
|
|
95
|
+
return null;
|
|
91
96
|
}
|
|
92
97
|
function parseAflTablesDate(dateStr) {
|
|
93
98
|
const trimmed = dateStr.trim();
|
|
@@ -622,7 +627,7 @@ function parseMatchList(html, year) {
|
|
|
622
627
|
const scoreLink = scoreCell.find("a").attr("href") ?? "";
|
|
623
628
|
const midMatch = /mid=(\d+)/.exec(scoreLink);
|
|
624
629
|
const matchId = midMatch?.[1] ? `FW_${midMatch[1]}` : `FW_${year}_R${currentRound}_${homeTeam}`;
|
|
625
|
-
const date = parseFootyWireDate(dateText) ?? new Date(year, 0, 1);
|
|
630
|
+
const date = parseFootyWireDate(dateText, year) ?? new Date(Date.UTC(year, 0, 1));
|
|
626
631
|
const homeGoals = Math.floor(homePoints / 6);
|
|
627
632
|
const homeBehinds = homePoints - homeGoals * 6;
|
|
628
633
|
const awayGoals = Math.floor(awayPoints / 6);
|
|
@@ -692,7 +697,7 @@ function parseFixtureList(html, year) {
|
|
|
692
697
|
if (teamLinks.length < 2) return;
|
|
693
698
|
const homeTeam = normaliseTeamName($(teamLinks[0]).text().trim());
|
|
694
699
|
const awayTeam = normaliseTeamName($(teamLinks[1]).text().trim());
|
|
695
|
-
const date = parseFootyWireDate(dateText) ?? new Date(year, 0, 1);
|
|
700
|
+
const date = parseFootyWireDate(dateText, year) ?? new Date(Date.UTC(year, 0, 1));
|
|
696
701
|
gameNumber++;
|
|
697
702
|
const scoreCell = cells.length >= 5 ? $(cells[4]) : null;
|
|
698
703
|
const scoreText = scoreCell?.text().trim() ?? "";
|
|
@@ -780,6 +785,12 @@ function mergeTeamAndOppStats(teamStats, oppStats) {
|
|
|
780
785
|
function teamNameToFootyWireSlug(teamName) {
|
|
781
786
|
return FOOTYWIRE_SLUG_MAP.get(teamName);
|
|
782
787
|
}
|
|
788
|
+
function normaliseDob(raw) {
|
|
789
|
+
if (!raw) return null;
|
|
790
|
+
const parsed = parseFootyWireDate(raw);
|
|
791
|
+
if (parsed) return parsed.toISOString().slice(0, 10);
|
|
792
|
+
return raw;
|
|
793
|
+
}
|
|
783
794
|
function parseFootyWirePlayerList(html, teamName) {
|
|
784
795
|
const $ = cheerio2.load(html);
|
|
785
796
|
const players = [];
|
|
@@ -821,7 +832,7 @@ function parseFootyWirePlayerList(html, teamName) {
|
|
|
821
832
|
team: teamName,
|
|
822
833
|
jumperNumber,
|
|
823
834
|
position: position || null,
|
|
824
|
-
dateOfBirth: dobText
|
|
835
|
+
dateOfBirth: normaliseDob(dobText),
|
|
825
836
|
heightCm,
|
|
826
837
|
weightKg: null,
|
|
827
838
|
gamesPlayed,
|
|
@@ -1292,7 +1303,7 @@ var init_coaches_votes = __esm({
|
|
|
1292
1303
|
|
|
1293
1304
|
// src/lib/validation.ts
|
|
1294
1305
|
import { z } from "zod/v4";
|
|
1295
|
-
var AflApiTokenSchema, CompetitionSchema, CompetitionListSchema, CompseasonSchema, CompseasonListSchema, RoundSchema, RoundListSchema, ScoreSchema, PeriodScoreSchema, TeamScoreSchema, CfsMatchTeamSchema, CfsMatchSchema, CfsScoreSchema, CfsVenueSchema, MatchItemSchema, MatchItemListSchema, CfsPlayerInnerSchema, PlayerGameStatsSchema, PlayerStatsItemSchema, PlayerStatsListSchema, RosterPlayerSchema, TeamPlayersSchema, MatchRosterSchema, TeamItemSchema, TeamListSchema, SquadPlayerInnerSchema, SquadPlayerItemSchema, SquadSchema, SquadListSchema, WinLossRecordSchema, LadderEntryRawSchema, LadderResponseSchema;
|
|
1306
|
+
var AflApiTokenSchema, CompetitionSchema, CompetitionListSchema, CompseasonSchema, CompseasonListSchema, RoundSchema, RoundListSchema, ScoreSchema, PeriodScoreSchema, TeamScoreSchema, CfsMatchTeamSchema, CfsMatchSchema, CfsScoreSchema, CfsVenueSchema, MatchItemSchema, MatchItemListSchema, CfsPlayerInnerSchema, statNum, PlayerGameStatsSchema, PlayerStatsItemSchema, PlayerStatsListSchema, RosterPlayerSchema, TeamPlayersSchema, MatchRosterSchema, TeamItemSchema, TeamListSchema, SquadPlayerInnerSchema, SquadPlayerItemSchema, SquadSchema, SquadListSchema, WinLossRecordSchema, LadderEntryRawSchema, LadderResponseSchema;
|
|
1296
1307
|
var init_validation = __esm({
|
|
1297
1308
|
"src/lib/validation.ts"() {
|
|
1298
1309
|
"use strict";
|
|
@@ -1399,71 +1410,72 @@ var init_validation = __esm({
|
|
|
1399
1410
|
captain: z.boolean().optional(),
|
|
1400
1411
|
playerJumperNumber: z.number().optional()
|
|
1401
1412
|
}).passthrough();
|
|
1413
|
+
statNum = z.number().nullable().optional();
|
|
1402
1414
|
PlayerGameStatsSchema = z.object({
|
|
1403
|
-
goals:
|
|
1404
|
-
behinds:
|
|
1405
|
-
kicks:
|
|
1406
|
-
handballs:
|
|
1407
|
-
disposals:
|
|
1408
|
-
marks:
|
|
1409
|
-
bounces:
|
|
1410
|
-
tackles:
|
|
1411
|
-
contestedPossessions:
|
|
1412
|
-
uncontestedPossessions:
|
|
1413
|
-
totalPossessions:
|
|
1414
|
-
inside50s:
|
|
1415
|
-
marksInside50:
|
|
1416
|
-
contestedMarks:
|
|
1417
|
-
hitouts:
|
|
1418
|
-
onePercenters:
|
|
1419
|
-
disposalEfficiency:
|
|
1420
|
-
clangers:
|
|
1421
|
-
freesFor:
|
|
1422
|
-
freesAgainst:
|
|
1423
|
-
dreamTeamPoints:
|
|
1415
|
+
goals: statNum,
|
|
1416
|
+
behinds: statNum,
|
|
1417
|
+
kicks: statNum,
|
|
1418
|
+
handballs: statNum,
|
|
1419
|
+
disposals: statNum,
|
|
1420
|
+
marks: statNum,
|
|
1421
|
+
bounces: statNum,
|
|
1422
|
+
tackles: statNum,
|
|
1423
|
+
contestedPossessions: statNum,
|
|
1424
|
+
uncontestedPossessions: statNum,
|
|
1425
|
+
totalPossessions: statNum,
|
|
1426
|
+
inside50s: statNum,
|
|
1427
|
+
marksInside50: statNum,
|
|
1428
|
+
contestedMarks: statNum,
|
|
1429
|
+
hitouts: statNum,
|
|
1430
|
+
onePercenters: statNum,
|
|
1431
|
+
disposalEfficiency: statNum,
|
|
1432
|
+
clangers: statNum,
|
|
1433
|
+
freesFor: statNum,
|
|
1434
|
+
freesAgainst: statNum,
|
|
1435
|
+
dreamTeamPoints: statNum,
|
|
1424
1436
|
clearances: z.object({
|
|
1425
|
-
centreClearances:
|
|
1426
|
-
stoppageClearances:
|
|
1427
|
-
totalClearances:
|
|
1428
|
-
}).passthrough().optional(),
|
|
1429
|
-
rebound50s:
|
|
1430
|
-
goalAssists:
|
|
1431
|
-
goalAccuracy:
|
|
1432
|
-
turnovers:
|
|
1433
|
-
intercepts:
|
|
1434
|
-
tacklesInside50:
|
|
1435
|
-
shotsAtGoal:
|
|
1436
|
-
metresGained:
|
|
1437
|
-
scoreInvolvements:
|
|
1438
|
-
ratingPoints:
|
|
1437
|
+
centreClearances: statNum,
|
|
1438
|
+
stoppageClearances: statNum,
|
|
1439
|
+
totalClearances: statNum
|
|
1440
|
+
}).passthrough().nullable().optional(),
|
|
1441
|
+
rebound50s: statNum,
|
|
1442
|
+
goalAssists: statNum,
|
|
1443
|
+
goalAccuracy: statNum,
|
|
1444
|
+
turnovers: statNum,
|
|
1445
|
+
intercepts: statNum,
|
|
1446
|
+
tacklesInside50: statNum,
|
|
1447
|
+
shotsAtGoal: statNum,
|
|
1448
|
+
metresGained: statNum,
|
|
1449
|
+
scoreInvolvements: statNum,
|
|
1450
|
+
ratingPoints: statNum,
|
|
1439
1451
|
extendedStats: z.object({
|
|
1440
|
-
effectiveDisposals:
|
|
1441
|
-
effectiveKicks:
|
|
1442
|
-
kickEfficiency:
|
|
1443
|
-
kickToHandballRatio:
|
|
1444
|
-
pressureActs:
|
|
1445
|
-
defHalfPressureActs:
|
|
1446
|
-
spoils:
|
|
1447
|
-
hitoutsToAdvantage:
|
|
1448
|
-
hitoutWinPercentage:
|
|
1449
|
-
hitoutToAdvantageRate:
|
|
1450
|
-
groundBallGets:
|
|
1451
|
-
f50GroundBallGets:
|
|
1452
|
-
interceptMarks:
|
|
1453
|
-
marksOnLead:
|
|
1454
|
-
contestedPossessionRate:
|
|
1455
|
-
contestOffOneOnOnes:
|
|
1456
|
-
contestOffWins:
|
|
1457
|
-
contestOffWinsPercentage:
|
|
1458
|
-
contestDefOneOnOnes:
|
|
1459
|
-
contestDefLosses:
|
|
1460
|
-
contestDefLossPercentage:
|
|
1461
|
-
centreBounceAttendances:
|
|
1462
|
-
kickins:
|
|
1463
|
-
kickinsPlayon:
|
|
1464
|
-
ruckContests:
|
|
1465
|
-
scoreLaunches:
|
|
1466
|
-
}).passthrough().optional()
|
|
1452
|
+
effectiveDisposals: statNum,
|
|
1453
|
+
effectiveKicks: statNum,
|
|
1454
|
+
kickEfficiency: statNum,
|
|
1455
|
+
kickToHandballRatio: statNum,
|
|
1456
|
+
pressureActs: statNum,
|
|
1457
|
+
defHalfPressureActs: statNum,
|
|
1458
|
+
spoils: statNum,
|
|
1459
|
+
hitoutsToAdvantage: statNum,
|
|
1460
|
+
hitoutWinPercentage: statNum,
|
|
1461
|
+
hitoutToAdvantageRate: statNum,
|
|
1462
|
+
groundBallGets: statNum,
|
|
1463
|
+
f50GroundBallGets: statNum,
|
|
1464
|
+
interceptMarks: statNum,
|
|
1465
|
+
marksOnLead: statNum,
|
|
1466
|
+
contestedPossessionRate: statNum,
|
|
1467
|
+
contestOffOneOnOnes: statNum,
|
|
1468
|
+
contestOffWins: statNum,
|
|
1469
|
+
contestOffWinsPercentage: statNum,
|
|
1470
|
+
contestDefOneOnOnes: statNum,
|
|
1471
|
+
contestDefLosses: statNum,
|
|
1472
|
+
contestDefLossPercentage: statNum,
|
|
1473
|
+
centreBounceAttendances: statNum,
|
|
1474
|
+
kickins: statNum,
|
|
1475
|
+
kickinsPlayon: statNum,
|
|
1476
|
+
ruckContests: statNum,
|
|
1477
|
+
scoreLaunches: statNum
|
|
1478
|
+
}).passthrough().nullable().optional()
|
|
1467
1479
|
}).passthrough();
|
|
1468
1480
|
PlayerStatsItemSchema = z.object({
|
|
1469
1481
|
player: z.object({
|
|
@@ -1476,7 +1488,7 @@ var init_validation = __esm({
|
|
|
1476
1488
|
teamId: z.string(),
|
|
1477
1489
|
playerStats: z.object({
|
|
1478
1490
|
stats: PlayerGameStatsSchema,
|
|
1479
|
-
timeOnGroundPercentage: z.number().optional()
|
|
1491
|
+
timeOnGroundPercentage: z.number().nullable().optional()
|
|
1480
1492
|
}).passthrough()
|
|
1481
1493
|
}).passthrough();
|
|
1482
1494
|
PlayerStatsListSchema = z.object({
|
|
@@ -2486,6 +2498,7 @@ function parseAflTablesTeamStats(html, year) {
|
|
|
2486
2498
|
$(rows[0]).find("td, th").each((_ci, cell) => {
|
|
2487
2499
|
headers.push($(cell).text().trim());
|
|
2488
2500
|
});
|
|
2501
|
+
const gpColIdx = headers.findIndex((h, i) => i > 0 && GP_HEADERS.has(h.toLowerCase()));
|
|
2489
2502
|
for (let ri = 1; ri < rows.length; ri++) {
|
|
2490
2503
|
const cells = $(rows[ri]).find("td");
|
|
2491
2504
|
if (cells.length < 3) continue;
|
|
@@ -2498,7 +2511,12 @@ function parseAflTablesTeamStats(html, year) {
|
|
|
2498
2511
|
}
|
|
2499
2512
|
const entry = teamMap.get(teamName);
|
|
2500
2513
|
if (!entry) continue;
|
|
2514
|
+
if (gpColIdx >= 0 && suffix === "_for") {
|
|
2515
|
+
const gpVal = Number.parseFloat($(cells[gpColIdx]).text().trim().replace(/,/g, "")) || 0;
|
|
2516
|
+
entry.gamesPlayed = gpVal;
|
|
2517
|
+
}
|
|
2501
2518
|
for (let ci = 1; ci < cells.length; ci++) {
|
|
2519
|
+
if (ci === gpColIdx) continue;
|
|
2502
2520
|
const header = headers[ci];
|
|
2503
2521
|
if (!header) continue;
|
|
2504
2522
|
const value = Number.parseFloat($(cells[ci]).text().trim().replace(/,/g, "")) || 0;
|
|
@@ -2574,7 +2592,7 @@ function parseAflTablesPlayerList(html, teamName) {
|
|
|
2574
2592
|
});
|
|
2575
2593
|
return players;
|
|
2576
2594
|
}
|
|
2577
|
-
var AFL_TABLES_BASE, AflTablesClient, AFL_TABLES_SLUG_MAP;
|
|
2595
|
+
var AFL_TABLES_BASE, AflTablesClient, GP_HEADERS, AFL_TABLES_SLUG_MAP;
|
|
2578
2596
|
var init_afl_tables = __esm({
|
|
2579
2597
|
"src/sources/afl-tables.ts"() {
|
|
2580
2598
|
"use strict";
|
|
@@ -2756,6 +2774,7 @@ var init_afl_tables = __esm({
|
|
|
2756
2774
|
}
|
|
2757
2775
|
}
|
|
2758
2776
|
};
|
|
2777
|
+
GP_HEADERS = /* @__PURE__ */ new Set(["gm", "gp", "p", "mp", "games"]);
|
|
2759
2778
|
AFL_TABLES_SLUG_MAP = /* @__PURE__ */ new Map([
|
|
2760
2779
|
["Adelaide Crows", "adelaide"],
|
|
2761
2780
|
["Brisbane Lions", "brisbane"],
|
|
@@ -3310,15 +3329,26 @@ async function fetchPlayerStats(query) {
|
|
|
3310
3329
|
case "afl-api": {
|
|
3311
3330
|
const client = new AflApiClient();
|
|
3312
3331
|
if (query.matchId) {
|
|
3313
|
-
const
|
|
3314
|
-
|
|
3332
|
+
const [rosterResult, statsResult] = await Promise.all([
|
|
3333
|
+
client.fetchMatchRoster(query.matchId),
|
|
3334
|
+
client.fetchPlayerStats(query.matchId)
|
|
3335
|
+
]);
|
|
3336
|
+
if (!statsResult.success) return statsResult;
|
|
3337
|
+
const teamIdMap2 = /* @__PURE__ */ new Map();
|
|
3338
|
+
if (rosterResult.success) {
|
|
3339
|
+
const match = rosterResult.data.match;
|
|
3340
|
+
teamIdMap2.set(match.homeTeamId, match.homeTeam.name);
|
|
3341
|
+
teamIdMap2.set(match.awayTeamId, match.awayTeam.name);
|
|
3342
|
+
}
|
|
3315
3343
|
return ok(
|
|
3316
3344
|
transformPlayerStats(
|
|
3317
|
-
|
|
3345
|
+
statsResult.data,
|
|
3318
3346
|
query.matchId,
|
|
3319
3347
|
query.season,
|
|
3320
3348
|
query.round ?? 0,
|
|
3321
|
-
competition
|
|
3349
|
+
competition,
|
|
3350
|
+
"afl-api",
|
|
3351
|
+
teamIdMap2.size > 0 ? teamIdMap2 : void 0
|
|
3322
3352
|
)
|
|
3323
3353
|
);
|
|
3324
3354
|
}
|
|
@@ -3570,7 +3600,7 @@ var init_json = __esm({
|
|
|
3570
3600
|
// src/cli/formatters/table.ts
|
|
3571
3601
|
function toDisplayValue(value) {
|
|
3572
3602
|
if (value === null || value === void 0) return "-";
|
|
3573
|
-
if (value instanceof Date) return
|
|
3603
|
+
if (value instanceof Date) return AEST_COMPACT_FORMATTER.format(value);
|
|
3574
3604
|
if (typeof value === "object") return JSON.stringify(value);
|
|
3575
3605
|
return String(value);
|
|
3576
3606
|
}
|
|
@@ -3644,9 +3674,18 @@ function formatTable(data, options = {}) {
|
|
|
3644
3674
|
});
|
|
3645
3675
|
return [header, separator, ...rows].join("\n");
|
|
3646
3676
|
}
|
|
3677
|
+
var AEST_COMPACT_FORMATTER;
|
|
3647
3678
|
var init_table = __esm({
|
|
3648
3679
|
"src/cli/formatters/table.ts"() {
|
|
3649
3680
|
"use strict";
|
|
3681
|
+
AEST_COMPACT_FORMATTER = new Intl.DateTimeFormat("en-AU", {
|
|
3682
|
+
timeZone: "Australia/Melbourne",
|
|
3683
|
+
day: "numeric",
|
|
3684
|
+
month: "short",
|
|
3685
|
+
hour: "numeric",
|
|
3686
|
+
minute: "2-digit",
|
|
3687
|
+
hour12: true
|
|
3688
|
+
});
|
|
3650
3689
|
}
|
|
3651
3690
|
});
|
|
3652
3691
|
|
|
@@ -3686,7 +3725,7 @@ var init_formatters = __esm({
|
|
|
3686
3725
|
|
|
3687
3726
|
// src/cli/ui.ts
|
|
3688
3727
|
import { spinner } from "@clack/prompts";
|
|
3689
|
-
import
|
|
3728
|
+
import pc2 from "picocolors";
|
|
3690
3729
|
async function withSpinner(message, fn) {
|
|
3691
3730
|
if (!isTTY) {
|
|
3692
3731
|
return fn();
|
|
@@ -3704,7 +3743,7 @@ async function withSpinner(message, fn) {
|
|
|
3704
3743
|
}
|
|
3705
3744
|
function showSummary(message) {
|
|
3706
3745
|
if (!isTTY) return;
|
|
3707
|
-
console.error(
|
|
3746
|
+
console.error(pc2.dim(message));
|
|
3708
3747
|
}
|
|
3709
3748
|
var isTTY;
|
|
3710
3749
|
var init_ui = __esm({
|
|
@@ -3714,6 +3753,86 @@ var init_ui = __esm({
|
|
|
3714
3753
|
}
|
|
3715
3754
|
});
|
|
3716
3755
|
|
|
3756
|
+
// src/cli/validation.ts
|
|
3757
|
+
function validateSeason(raw) {
|
|
3758
|
+
const season = Number(raw);
|
|
3759
|
+
if (Number.isNaN(season) || !Number.isInteger(season)) {
|
|
3760
|
+
throw new Error(`Invalid season: "${raw}" \u2014 season must be a number (e.g. 2025)`);
|
|
3761
|
+
}
|
|
3762
|
+
if (season < 1897 || season > 2100) {
|
|
3763
|
+
throw new Error(`Invalid season: ${season} \u2014 must be between 1897 and 2100`);
|
|
3764
|
+
}
|
|
3765
|
+
return season;
|
|
3766
|
+
}
|
|
3767
|
+
function validateOptionalSeason(raw) {
|
|
3768
|
+
if (raw != null) return validateSeason(raw);
|
|
3769
|
+
return void 0;
|
|
3770
|
+
}
|
|
3771
|
+
function resolveDefaultSeason(competition = "AFLM") {
|
|
3772
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
3773
|
+
return competition === "AFLW" ? year - 1 : year;
|
|
3774
|
+
}
|
|
3775
|
+
function validateRound(raw) {
|
|
3776
|
+
const round = Number(raw);
|
|
3777
|
+
if (Number.isNaN(round) || !Number.isInteger(round) || round < 0) {
|
|
3778
|
+
throw new Error(`Invalid round: "${raw}" \u2014 round must be a non-negative integer`);
|
|
3779
|
+
}
|
|
3780
|
+
return round;
|
|
3781
|
+
}
|
|
3782
|
+
function validateFormat(raw) {
|
|
3783
|
+
if (raw == null) return void 0;
|
|
3784
|
+
const lower = raw.toLowerCase();
|
|
3785
|
+
if (VALID_FORMATS.includes(lower)) {
|
|
3786
|
+
return lower;
|
|
3787
|
+
}
|
|
3788
|
+
throw new Error(`Invalid format: "${raw}" \u2014 valid formats are: ${VALID_FORMATS.join(", ")}`);
|
|
3789
|
+
}
|
|
3790
|
+
function validateCompetition(raw) {
|
|
3791
|
+
const upper = raw.toUpperCase();
|
|
3792
|
+
if (upper === "AFLM" || upper === "AFLW") {
|
|
3793
|
+
return upper;
|
|
3794
|
+
}
|
|
3795
|
+
throw new Error(
|
|
3796
|
+
`Invalid competition: "${raw}" \u2014 valid values are: ${VALID_COMPETITIONS.join(", ")}`
|
|
3797
|
+
);
|
|
3798
|
+
}
|
|
3799
|
+
function validateOptionalCompetition(raw) {
|
|
3800
|
+
if (raw == null) return void 0;
|
|
3801
|
+
return validateCompetition(raw);
|
|
3802
|
+
}
|
|
3803
|
+
function validateSource(raw) {
|
|
3804
|
+
if (VALID_SOURCES.includes(raw)) {
|
|
3805
|
+
return raw;
|
|
3806
|
+
}
|
|
3807
|
+
throw new Error(`Invalid source: "${raw}" \u2014 valid sources are: ${VALID_SOURCES.join(", ")}`);
|
|
3808
|
+
}
|
|
3809
|
+
function resolveTeamIdentifier(raw, teams) {
|
|
3810
|
+
const trimmed = raw.trim();
|
|
3811
|
+
if (/^\d+$/.test(trimmed)) {
|
|
3812
|
+
return trimmed;
|
|
3813
|
+
}
|
|
3814
|
+
const canonical = normaliseTeamName(trimmed);
|
|
3815
|
+
const byCanonical = teams.find((t) => t.name === canonical);
|
|
3816
|
+
if (byCanonical) return byCanonical.teamId;
|
|
3817
|
+
const lower = trimmed.toLowerCase();
|
|
3818
|
+
const byName = teams.find((t) => t.name.toLowerCase() === lower);
|
|
3819
|
+
if (byName) return byName.teamId;
|
|
3820
|
+
const byAbbrev = teams.find((t) => t.abbreviation.toLowerCase() === lower);
|
|
3821
|
+
if (byAbbrev) return byAbbrev.teamId;
|
|
3822
|
+
const validNames = teams.map((t) => `${t.name} (${t.abbreviation})`).join(", ");
|
|
3823
|
+
throw new Error(`Unknown team: "${raw}" \u2014 valid teams are: ${validNames}`);
|
|
3824
|
+
}
|
|
3825
|
+
var VALID_SOURCES, VALID_COMPETITIONS, VALID_FORMATS;
|
|
3826
|
+
var init_validation2 = __esm({
|
|
3827
|
+
"src/cli/validation.ts"() {
|
|
3828
|
+
"use strict";
|
|
3829
|
+
init_team_mapping();
|
|
3830
|
+
VALID_SOURCES = ["afl-api", "footywire", "afl-tables", "squiggle"];
|
|
3831
|
+
VALID_COMPETITIONS = ["AFLM", "AFLW"];
|
|
3832
|
+
VALID_FORMATS = ["table", "json", "csv"];
|
|
3833
|
+
}
|
|
3834
|
+
});
|
|
3835
|
+
|
|
3717
3836
|
// src/cli/commands/matches.ts
|
|
3718
3837
|
var matches_exports = {};
|
|
3719
3838
|
__export(matches_exports, {
|
|
@@ -3727,6 +3846,7 @@ var init_matches = __esm({
|
|
|
3727
3846
|
init_index();
|
|
3728
3847
|
init_formatters();
|
|
3729
3848
|
init_ui();
|
|
3849
|
+
init_validation2();
|
|
3730
3850
|
DEFAULT_COLUMNS = [
|
|
3731
3851
|
{ key: "date", label: "Date", maxWidth: 16 },
|
|
3732
3852
|
{ key: "roundNumber", label: "Round", maxWidth: 6 },
|
|
@@ -3756,16 +3876,14 @@ var init_matches = __esm({
|
|
|
3756
3876
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
3757
3877
|
},
|
|
3758
3878
|
async run({ args }) {
|
|
3759
|
-
const season =
|
|
3760
|
-
const round = args.round ?
|
|
3879
|
+
const season = validateSeason(args.season);
|
|
3880
|
+
const round = args.round ? validateRound(args.round) : void 0;
|
|
3881
|
+
const source = validateSource(args.source);
|
|
3882
|
+
const competition = validateCompetition(args.competition);
|
|
3883
|
+
const format = validateFormat(args.format);
|
|
3761
3884
|
const result = await withSpinner(
|
|
3762
3885
|
"Fetching match results\u2026",
|
|
3763
|
-
() => fetchMatchResults({
|
|
3764
|
-
source: args.source,
|
|
3765
|
-
season,
|
|
3766
|
-
round,
|
|
3767
|
-
competition: args.competition
|
|
3768
|
-
})
|
|
3886
|
+
() => fetchMatchResults({ source, season, round, competition })
|
|
3769
3887
|
);
|
|
3770
3888
|
if (!result.success) {
|
|
3771
3889
|
throw result.error;
|
|
@@ -3775,7 +3893,7 @@ var init_matches = __esm({
|
|
|
3775
3893
|
const formatOptions = {
|
|
3776
3894
|
json: args.json,
|
|
3777
3895
|
csv: args.csv,
|
|
3778
|
-
format
|
|
3896
|
+
format,
|
|
3779
3897
|
full: args.full,
|
|
3780
3898
|
columns: DEFAULT_COLUMNS
|
|
3781
3899
|
};
|
|
@@ -3798,6 +3916,7 @@ var init_stats = __esm({
|
|
|
3798
3916
|
init_index();
|
|
3799
3917
|
init_formatters();
|
|
3800
3918
|
init_ui();
|
|
3919
|
+
init_validation2();
|
|
3801
3920
|
DEFAULT_COLUMNS2 = [
|
|
3802
3921
|
{ key: "displayName", label: "Player", maxWidth: 22 },
|
|
3803
3922
|
{ key: "team", label: "Team", maxWidth: 18 },
|
|
@@ -3828,18 +3947,15 @@ var init_stats = __esm({
|
|
|
3828
3947
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
3829
3948
|
},
|
|
3830
3949
|
async run({ args }) {
|
|
3831
|
-
const season =
|
|
3832
|
-
const round = args.round ?
|
|
3950
|
+
const season = validateSeason(args.season);
|
|
3951
|
+
const round = args.round ? validateRound(args.round) : void 0;
|
|
3833
3952
|
const matchId = args["match-id"];
|
|
3953
|
+
const source = validateSource(args.source);
|
|
3954
|
+
const competition = validateCompetition(args.competition);
|
|
3955
|
+
const format = validateFormat(args.format);
|
|
3834
3956
|
const result = await withSpinner(
|
|
3835
3957
|
"Fetching player stats\u2026",
|
|
3836
|
-
() => fetchPlayerStats({
|
|
3837
|
-
source: args.source,
|
|
3838
|
-
season,
|
|
3839
|
-
round,
|
|
3840
|
-
matchId,
|
|
3841
|
-
competition: args.competition
|
|
3842
|
-
})
|
|
3958
|
+
() => fetchPlayerStats({ source, season, round, matchId, competition })
|
|
3843
3959
|
);
|
|
3844
3960
|
if (!result.success) {
|
|
3845
3961
|
throw result.error;
|
|
@@ -3851,7 +3967,7 @@ var init_stats = __esm({
|
|
|
3851
3967
|
const formatOptions = {
|
|
3852
3968
|
json: args.json,
|
|
3853
3969
|
csv: args.csv,
|
|
3854
|
-
format
|
|
3970
|
+
format,
|
|
3855
3971
|
full: args.full,
|
|
3856
3972
|
columns: DEFAULT_COLUMNS2
|
|
3857
3973
|
};
|
|
@@ -3874,6 +3990,7 @@ var init_fixture2 = __esm({
|
|
|
3874
3990
|
init_index();
|
|
3875
3991
|
init_formatters();
|
|
3876
3992
|
init_ui();
|
|
3993
|
+
init_validation2();
|
|
3877
3994
|
DEFAULT_COLUMNS3 = [
|
|
3878
3995
|
{ key: "roundNumber", label: "Round", maxWidth: 6 },
|
|
3879
3996
|
{ key: "date", label: "Date", maxWidth: 16 },
|
|
@@ -3901,16 +4018,14 @@ var init_fixture2 = __esm({
|
|
|
3901
4018
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
3902
4019
|
},
|
|
3903
4020
|
async run({ args }) {
|
|
3904
|
-
const season =
|
|
3905
|
-
const round = args.round ?
|
|
4021
|
+
const season = validateSeason(args.season);
|
|
4022
|
+
const round = args.round ? validateRound(args.round) : void 0;
|
|
4023
|
+
const source = validateSource(args.source);
|
|
4024
|
+
const competition = validateCompetition(args.competition);
|
|
4025
|
+
const format = validateFormat(args.format);
|
|
3906
4026
|
const result = await withSpinner(
|
|
3907
4027
|
"Fetching fixture\u2026",
|
|
3908
|
-
() => fetchFixture({
|
|
3909
|
-
source: args.source,
|
|
3910
|
-
season,
|
|
3911
|
-
round,
|
|
3912
|
-
competition: args.competition
|
|
3913
|
-
})
|
|
4028
|
+
() => fetchFixture({ source, season, round, competition })
|
|
3914
4029
|
);
|
|
3915
4030
|
if (!result.success) {
|
|
3916
4031
|
throw result.error;
|
|
@@ -3920,7 +4035,7 @@ var init_fixture2 = __esm({
|
|
|
3920
4035
|
const formatOptions = {
|
|
3921
4036
|
json: args.json,
|
|
3922
4037
|
csv: args.csv,
|
|
3923
|
-
format
|
|
4038
|
+
format,
|
|
3924
4039
|
full: args.full,
|
|
3925
4040
|
columns: DEFAULT_COLUMNS3
|
|
3926
4041
|
};
|
|
@@ -3943,6 +4058,7 @@ var init_ladder3 = __esm({
|
|
|
3943
4058
|
init_index();
|
|
3944
4059
|
init_formatters();
|
|
3945
4060
|
init_ui();
|
|
4061
|
+
init_validation2();
|
|
3946
4062
|
DEFAULT_COLUMNS4 = [
|
|
3947
4063
|
{ key: "position", label: "Pos", maxWidth: 4 },
|
|
3948
4064
|
{ key: "team", label: "Team", maxWidth: 24 },
|
|
@@ -3972,16 +4088,14 @@ var init_ladder3 = __esm({
|
|
|
3972
4088
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
3973
4089
|
},
|
|
3974
4090
|
async run({ args }) {
|
|
3975
|
-
const season =
|
|
3976
|
-
const round = args.round ?
|
|
4091
|
+
const season = validateSeason(args.season);
|
|
4092
|
+
const round = args.round ? validateRound(args.round) : void 0;
|
|
4093
|
+
const source = validateSource(args.source);
|
|
4094
|
+
const competition = validateCompetition(args.competition);
|
|
4095
|
+
const format = validateFormat(args.format);
|
|
3977
4096
|
const result = await withSpinner(
|
|
3978
4097
|
"Fetching ladder\u2026",
|
|
3979
|
-
() => fetchLadder({
|
|
3980
|
-
source: args.source,
|
|
3981
|
-
season,
|
|
3982
|
-
round,
|
|
3983
|
-
competition: args.competition
|
|
3984
|
-
})
|
|
4098
|
+
() => fetchLadder({ source, season, round, competition })
|
|
3985
4099
|
);
|
|
3986
4100
|
if (!result.success) {
|
|
3987
4101
|
throw result.error;
|
|
@@ -3993,7 +4107,7 @@ var init_ladder3 = __esm({
|
|
|
3993
4107
|
const formatOptions = {
|
|
3994
4108
|
json: args.json,
|
|
3995
4109
|
csv: args.csv,
|
|
3996
|
-
format
|
|
4110
|
+
format,
|
|
3997
4111
|
full: args.full,
|
|
3998
4112
|
columns: DEFAULT_COLUMNS4
|
|
3999
4113
|
};
|
|
@@ -4009,6 +4123,28 @@ __export(lineup_exports, {
|
|
|
4009
4123
|
lineupCommand: () => lineupCommand
|
|
4010
4124
|
});
|
|
4011
4125
|
import { defineCommand as defineCommand5 } from "citty";
|
|
4126
|
+
function flattenLineups(lineups) {
|
|
4127
|
+
const rows = [];
|
|
4128
|
+
for (const lineup of lineups) {
|
|
4129
|
+
for (const { players, team } of [
|
|
4130
|
+
{ players: lineup.homePlayers, team: lineup.homeTeam },
|
|
4131
|
+
{ players: lineup.awayPlayers, team: lineup.awayTeam }
|
|
4132
|
+
]) {
|
|
4133
|
+
for (const p of players) {
|
|
4134
|
+
rows.push({
|
|
4135
|
+
matchId: lineup.matchId,
|
|
4136
|
+
team,
|
|
4137
|
+
displayName: p.displayName,
|
|
4138
|
+
jumperNumber: p.jumperNumber,
|
|
4139
|
+
position: p.position,
|
|
4140
|
+
isEmergency: p.isEmergency,
|
|
4141
|
+
isSubstitute: p.isSubstitute
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
return rows;
|
|
4147
|
+
}
|
|
4012
4148
|
var DEFAULT_COLUMNS5, lineupCommand;
|
|
4013
4149
|
var init_lineup3 = __esm({
|
|
4014
4150
|
"src/cli/commands/lineup.ts"() {
|
|
@@ -4016,10 +4152,13 @@ var init_lineup3 = __esm({
|
|
|
4016
4152
|
init_index();
|
|
4017
4153
|
init_formatters();
|
|
4018
4154
|
init_ui();
|
|
4155
|
+
init_validation2();
|
|
4019
4156
|
DEFAULT_COLUMNS5 = [
|
|
4020
|
-
{ key: "matchId", label: "Match", maxWidth:
|
|
4021
|
-
{ key: "
|
|
4022
|
-
{ key: "
|
|
4157
|
+
{ key: "matchId", label: "Match", maxWidth: 14 },
|
|
4158
|
+
{ key: "team", label: "Team", maxWidth: 20 },
|
|
4159
|
+
{ key: "displayName", label: "Player", maxWidth: 24 },
|
|
4160
|
+
{ key: "jumperNumber", label: "#", maxWidth: 4 },
|
|
4161
|
+
{ key: "position", label: "Pos", maxWidth: 12 }
|
|
4023
4162
|
];
|
|
4024
4163
|
lineupCommand = defineCommand5({
|
|
4025
4164
|
meta: {
|
|
@@ -4042,18 +4181,15 @@ var init_lineup3 = __esm({
|
|
|
4042
4181
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4043
4182
|
},
|
|
4044
4183
|
async run({ args }) {
|
|
4045
|
-
const season =
|
|
4046
|
-
const round =
|
|
4184
|
+
const season = validateSeason(args.season);
|
|
4185
|
+
const round = validateRound(args.round);
|
|
4047
4186
|
const matchId = args["match-id"];
|
|
4187
|
+
const source = validateSource(args.source);
|
|
4188
|
+
const competition = validateCompetition(args.competition);
|
|
4189
|
+
const format = validateFormat(args.format);
|
|
4048
4190
|
const result = await withSpinner(
|
|
4049
4191
|
"Fetching lineups\u2026",
|
|
4050
|
-
() => fetchLineup({
|
|
4051
|
-
source: args.source,
|
|
4052
|
-
season,
|
|
4053
|
-
round,
|
|
4054
|
-
matchId,
|
|
4055
|
-
competition: args.competition
|
|
4056
|
-
})
|
|
4192
|
+
() => fetchLineup({ source, season, round, matchId, competition })
|
|
4057
4193
|
);
|
|
4058
4194
|
if (!result.success) {
|
|
4059
4195
|
throw result.error;
|
|
@@ -4063,11 +4199,16 @@ var init_lineup3 = __esm({
|
|
|
4063
4199
|
const formatOptions = {
|
|
4064
4200
|
json: args.json,
|
|
4065
4201
|
csv: args.csv,
|
|
4066
|
-
format
|
|
4202
|
+
format,
|
|
4067
4203
|
full: args.full,
|
|
4068
4204
|
columns: DEFAULT_COLUMNS5
|
|
4069
4205
|
};
|
|
4070
|
-
|
|
4206
|
+
const resolvedFormat = resolveFormat(formatOptions);
|
|
4207
|
+
if (resolvedFormat === "json") {
|
|
4208
|
+
console.log(formatOutput(data, formatOptions));
|
|
4209
|
+
} else {
|
|
4210
|
+
console.log(formatOutput(flattenLineups(data), formatOptions));
|
|
4211
|
+
}
|
|
4071
4212
|
}
|
|
4072
4213
|
});
|
|
4073
4214
|
}
|
|
@@ -4086,6 +4227,7 @@ var init_squad = __esm({
|
|
|
4086
4227
|
init_index();
|
|
4087
4228
|
init_formatters();
|
|
4088
4229
|
init_ui();
|
|
4230
|
+
init_validation2();
|
|
4089
4231
|
DEFAULT_COLUMNS6 = [
|
|
4090
4232
|
{ key: "displayName", label: "Player", maxWidth: 24 },
|
|
4091
4233
|
{ key: "jumperNumber", label: "#", maxWidth: 4 },
|
|
@@ -4099,7 +4241,11 @@ var init_squad = __esm({
|
|
|
4099
4241
|
description: "Fetch team squad for a season"
|
|
4100
4242
|
},
|
|
4101
4243
|
args: {
|
|
4102
|
-
"team-id": {
|
|
4244
|
+
"team-id": {
|
|
4245
|
+
type: "string",
|
|
4246
|
+
description: "Team ID, abbreviation, or name (e.g. 5, CARL, Carlton)",
|
|
4247
|
+
required: true
|
|
4248
|
+
},
|
|
4103
4249
|
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
4104
4250
|
competition: {
|
|
4105
4251
|
type: "string",
|
|
@@ -4112,15 +4258,21 @@ var init_squad = __esm({
|
|
|
4112
4258
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4113
4259
|
},
|
|
4114
4260
|
async run({ args }) {
|
|
4115
|
-
const
|
|
4116
|
-
const
|
|
4261
|
+
const season = validateSeason(args.season);
|
|
4262
|
+
const competition = validateCompetition(args.competition);
|
|
4263
|
+
const format = validateFormat(args.format);
|
|
4264
|
+
let teamId = args["team-id"].trim();
|
|
4265
|
+
const isNumeric = /^\d+$/.test(teamId);
|
|
4266
|
+
if (!isNumeric) {
|
|
4267
|
+
const teamsResult = await withSpinner("Resolving team\u2026", () => fetchTeams({ competition }));
|
|
4268
|
+
if (!teamsResult.success) {
|
|
4269
|
+
throw teamsResult.error;
|
|
4270
|
+
}
|
|
4271
|
+
teamId = resolveTeamIdentifier(args["team-id"], teamsResult.data);
|
|
4272
|
+
}
|
|
4117
4273
|
const result = await withSpinner(
|
|
4118
4274
|
"Fetching squad\u2026",
|
|
4119
|
-
() => fetchSquad({
|
|
4120
|
-
teamId,
|
|
4121
|
-
season,
|
|
4122
|
-
competition: args.competition
|
|
4123
|
-
})
|
|
4275
|
+
() => fetchSquad({ teamId, season, competition })
|
|
4124
4276
|
);
|
|
4125
4277
|
if (!result.success) {
|
|
4126
4278
|
throw result.error;
|
|
@@ -4130,7 +4282,7 @@ var init_squad = __esm({
|
|
|
4130
4282
|
const formatOptions = {
|
|
4131
4283
|
json: args.json,
|
|
4132
4284
|
csv: args.csv,
|
|
4133
|
-
format
|
|
4285
|
+
format,
|
|
4134
4286
|
full: args.full,
|
|
4135
4287
|
columns: DEFAULT_COLUMNS6
|
|
4136
4288
|
};
|
|
@@ -4153,6 +4305,7 @@ var init_teams2 = __esm({
|
|
|
4153
4305
|
init_index();
|
|
4154
4306
|
init_formatters();
|
|
4155
4307
|
init_ui();
|
|
4308
|
+
init_validation2();
|
|
4156
4309
|
DEFAULT_COLUMNS7 = [
|
|
4157
4310
|
{ key: "teamId", label: "ID", maxWidth: 8 },
|
|
4158
4311
|
{ key: "name", label: "Team", maxWidth: 24 },
|
|
@@ -4173,22 +4326,26 @@ var init_teams2 = __esm({
|
|
|
4173
4326
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4174
4327
|
},
|
|
4175
4328
|
async run({ args }) {
|
|
4329
|
+
const competition = validateOptionalCompetition(args.competition);
|
|
4330
|
+
const format = validateFormat(args.format);
|
|
4176
4331
|
const result = await withSpinner(
|
|
4177
4332
|
"Fetching teams\u2026",
|
|
4178
|
-
() => fetchTeams({
|
|
4179
|
-
competition: args.competition,
|
|
4180
|
-
teamType: args["team-type"]
|
|
4181
|
-
})
|
|
4333
|
+
() => fetchTeams({ competition, teamType: args["team-type"] })
|
|
4182
4334
|
);
|
|
4183
4335
|
if (!result.success) {
|
|
4184
4336
|
throw result.error;
|
|
4185
4337
|
}
|
|
4186
4338
|
const data = result.data;
|
|
4339
|
+
if (data.length === 0 && args["team-type"]) {
|
|
4340
|
+
console.error(
|
|
4341
|
+
`No teams found for team type "${args["team-type"]}". Try running without --team-type to see available teams.`
|
|
4342
|
+
);
|
|
4343
|
+
}
|
|
4187
4344
|
showSummary(`Loaded ${data.length} teams`);
|
|
4188
4345
|
const formatOptions = {
|
|
4189
4346
|
json: args.json,
|
|
4190
4347
|
csv: args.csv,
|
|
4191
|
-
format
|
|
4348
|
+
format,
|
|
4192
4349
|
full: args.full,
|
|
4193
4350
|
columns: DEFAULT_COLUMNS7
|
|
4194
4351
|
};
|
|
@@ -4217,9 +4374,18 @@ var init_team_stats2 = __esm({
|
|
|
4217
4374
|
init_index();
|
|
4218
4375
|
init_formatters();
|
|
4219
4376
|
init_ui();
|
|
4377
|
+
init_validation2();
|
|
4220
4378
|
DEFAULT_COLUMNS8 = [
|
|
4221
4379
|
{ key: "team", label: "Team", maxWidth: 24 },
|
|
4222
|
-
{ key: "gamesPlayed", label: "GP", maxWidth: 5 }
|
|
4380
|
+
{ key: "gamesPlayed", label: "GP", maxWidth: 5 },
|
|
4381
|
+
{ key: "K", label: "K", maxWidth: 6 },
|
|
4382
|
+
{ key: "HB", label: "HB", maxWidth: 6 },
|
|
4383
|
+
{ key: "D", label: "D", maxWidth: 6 },
|
|
4384
|
+
{ key: "M", label: "M", maxWidth: 6 },
|
|
4385
|
+
{ key: "G", label: "G", maxWidth: 6 },
|
|
4386
|
+
{ key: "B", label: "B", maxWidth: 6 },
|
|
4387
|
+
{ key: "T", label: "T", maxWidth: 6 },
|
|
4388
|
+
{ key: "I50", label: "I50", maxWidth: 6 }
|
|
4223
4389
|
];
|
|
4224
4390
|
teamStatsCommand = defineCommand8({
|
|
4225
4391
|
meta: {
|
|
@@ -4240,15 +4406,13 @@ var init_team_stats2 = __esm({
|
|
|
4240
4406
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4241
4407
|
},
|
|
4242
4408
|
async run({ args }) {
|
|
4243
|
-
const season =
|
|
4409
|
+
const season = validateSeason(args.season);
|
|
4410
|
+
const source = validateSource(args.source);
|
|
4411
|
+
const format = validateFormat(args.format);
|
|
4244
4412
|
const summaryType = args.summary;
|
|
4245
4413
|
const result = await withSpinner(
|
|
4246
4414
|
"Fetching team stats\u2026",
|
|
4247
|
-
() => fetchTeamStats({
|
|
4248
|
-
source: args.source,
|
|
4249
|
-
season,
|
|
4250
|
-
summaryType
|
|
4251
|
-
})
|
|
4415
|
+
() => fetchTeamStats({ source, season, summaryType })
|
|
4252
4416
|
);
|
|
4253
4417
|
if (!result.success) {
|
|
4254
4418
|
throw result.error;
|
|
@@ -4259,7 +4423,7 @@ var init_team_stats2 = __esm({
|
|
|
4259
4423
|
const formatOptions = {
|
|
4260
4424
|
json: args.json,
|
|
4261
4425
|
csv: args.csv,
|
|
4262
|
-
format
|
|
4426
|
+
format,
|
|
4263
4427
|
full: args.full,
|
|
4264
4428
|
columns: DEFAULT_COLUMNS8
|
|
4265
4429
|
};
|
|
@@ -4282,6 +4446,7 @@ var init_player_details2 = __esm({
|
|
|
4282
4446
|
init_index();
|
|
4283
4447
|
init_formatters();
|
|
4284
4448
|
init_ui();
|
|
4449
|
+
init_validation2();
|
|
4285
4450
|
DEFAULT_COLUMNS9 = [
|
|
4286
4451
|
{ key: "displayName", label: "Player", maxWidth: 24 },
|
|
4287
4452
|
{ key: "jumperNumber", label: "#", maxWidth: 4 },
|
|
@@ -4315,16 +4480,13 @@ var init_player_details2 = __esm({
|
|
|
4315
4480
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4316
4481
|
},
|
|
4317
4482
|
async run({ args }) {
|
|
4318
|
-
const source = args.source;
|
|
4319
|
-
const
|
|
4483
|
+
const source = validateSource(args.source);
|
|
4484
|
+
const competition = validateCompetition(args.competition);
|
|
4485
|
+
const format = validateFormat(args.format);
|
|
4486
|
+
const season = validateOptionalSeason(args.season) ?? resolveDefaultSeason(competition);
|
|
4320
4487
|
const result = await withSpinner(
|
|
4321
4488
|
"Fetching player details\u2026",
|
|
4322
|
-
() => fetchPlayerDetails({
|
|
4323
|
-
source,
|
|
4324
|
-
team: args.team,
|
|
4325
|
-
season,
|
|
4326
|
-
competition: args.competition
|
|
4327
|
-
})
|
|
4489
|
+
() => fetchPlayerDetails({ source, team: args.team, season, competition })
|
|
4328
4490
|
);
|
|
4329
4491
|
if (!result.success) {
|
|
4330
4492
|
throw result.error;
|
|
@@ -4334,7 +4496,7 @@ var init_player_details2 = __esm({
|
|
|
4334
4496
|
const formatOptions = {
|
|
4335
4497
|
json: args.json,
|
|
4336
4498
|
csv: args.csv,
|
|
4337
|
-
format
|
|
4499
|
+
format,
|
|
4338
4500
|
full: args.full,
|
|
4339
4501
|
columns: DEFAULT_COLUMNS9
|
|
4340
4502
|
};
|
|
@@ -4357,6 +4519,7 @@ var init_coaches_votes2 = __esm({
|
|
|
4357
4519
|
init_index();
|
|
4358
4520
|
init_formatters();
|
|
4359
4521
|
init_ui();
|
|
4522
|
+
init_validation2();
|
|
4360
4523
|
DEFAULT_COLUMNS10 = [
|
|
4361
4524
|
{ key: "season", label: "Season", maxWidth: 8 },
|
|
4362
4525
|
{ key: "round", label: "Round", maxWidth: 6 },
|
|
@@ -4385,16 +4548,13 @@ var init_coaches_votes2 = __esm({
|
|
|
4385
4548
|
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4386
4549
|
},
|
|
4387
4550
|
async run({ args }) {
|
|
4388
|
-
const season =
|
|
4389
|
-
const round = args.round ?
|
|
4551
|
+
const season = validateSeason(args.season);
|
|
4552
|
+
const round = args.round ? validateRound(args.round) : void 0;
|
|
4553
|
+
const competition = validateCompetition(args.competition);
|
|
4554
|
+
const format = validateFormat(args.format);
|
|
4390
4555
|
const result = await withSpinner(
|
|
4391
4556
|
"Fetching coaches votes\u2026",
|
|
4392
|
-
() => fetchCoachesVotes({
|
|
4393
|
-
season,
|
|
4394
|
-
round,
|
|
4395
|
-
competition: args.competition,
|
|
4396
|
-
team: args.team
|
|
4397
|
-
})
|
|
4557
|
+
() => fetchCoachesVotes({ season, round, competition, team: args.team })
|
|
4398
4558
|
);
|
|
4399
4559
|
if (!result.success) {
|
|
4400
4560
|
throw result.error;
|
|
@@ -4406,7 +4566,7 @@ var init_coaches_votes2 = __esm({
|
|
|
4406
4566
|
const formatOptions = {
|
|
4407
4567
|
json: args.json,
|
|
4408
4568
|
csv: args.csv,
|
|
4409
|
-
format
|
|
4569
|
+
format,
|
|
4410
4570
|
full: args.full,
|
|
4411
4571
|
columns: DEFAULT_COLUMNS10
|
|
4412
4572
|
};
|
|
@@ -4417,13 +4577,39 @@ var init_coaches_votes2 = __esm({
|
|
|
4417
4577
|
});
|
|
4418
4578
|
|
|
4419
4579
|
// src/cli.ts
|
|
4420
|
-
init_errors();
|
|
4421
4580
|
import { defineCommand as defineCommand11, runMain } from "citty";
|
|
4422
|
-
|
|
4581
|
+
|
|
4582
|
+
// src/cli/error-boundary.ts
|
|
4583
|
+
init_errors();
|
|
4584
|
+
import pc from "picocolors";
|
|
4585
|
+
function formatError(error) {
|
|
4586
|
+
if (error instanceof ValidationError && error.issues) {
|
|
4587
|
+
const issueLines = error.issues.map((i) => ` ${pc.yellow(i.path)}: ${i.message}`);
|
|
4588
|
+
return `${pc.red("Validation error:")}
|
|
4589
|
+
${issueLines.join("\n")}`;
|
|
4590
|
+
}
|
|
4591
|
+
if (error instanceof AflApiError) {
|
|
4592
|
+
const status = error.statusCode ? ` (HTTP ${error.statusCode})` : "";
|
|
4593
|
+
return `${pc.red("AFL API error:")} ${error.message}${status}`;
|
|
4594
|
+
}
|
|
4595
|
+
if (error instanceof ScrapeError) {
|
|
4596
|
+
const source = error.source ? ` [${error.source}]` : "";
|
|
4597
|
+
return `${pc.red("Scrape error:")} ${error.message}${source}`;
|
|
4598
|
+
}
|
|
4599
|
+
if (error instanceof UnsupportedSourceError) {
|
|
4600
|
+
return `${pc.red("Unsupported source:")} ${error.message}`;
|
|
4601
|
+
}
|
|
4602
|
+
if (error instanceof Error) {
|
|
4603
|
+
return `${pc.red("Error:")} ${error.message}`;
|
|
4604
|
+
}
|
|
4605
|
+
return `${pc.red("Error:")} ${String(error)}`;
|
|
4606
|
+
}
|
|
4607
|
+
|
|
4608
|
+
// src/cli.ts
|
|
4423
4609
|
var main = defineCommand11({
|
|
4424
4610
|
meta: {
|
|
4425
4611
|
name: "fitzroy",
|
|
4426
|
-
version: "1.1.
|
|
4612
|
+
version: "1.1.1",
|
|
4427
4613
|
description: "CLI for fetching AFL data \u2014 match results, player stats, fixtures, ladders, and more"
|
|
4428
4614
|
},
|
|
4429
4615
|
subCommands: {
|
|
@@ -4439,28 +4625,6 @@ var main = defineCommand11({
|
|
|
4439
4625
|
"coaches-votes": () => Promise.resolve().then(() => (init_coaches_votes2(), coaches_votes_exports)).then((m) => m.coachesVotesCommand)
|
|
4440
4626
|
}
|
|
4441
4627
|
});
|
|
4442
|
-
function formatError(error) {
|
|
4443
|
-
if (error instanceof ValidationError && error.issues) {
|
|
4444
|
-
const issueLines = error.issues.map((i) => ` ${pc2.yellow(i.path)}: ${i.message}`);
|
|
4445
|
-
return `${pc2.red("Validation error:")}
|
|
4446
|
-
${issueLines.join("\n")}`;
|
|
4447
|
-
}
|
|
4448
|
-
if (error instanceof AflApiError) {
|
|
4449
|
-
const status = error.statusCode ? ` (HTTP ${error.statusCode})` : "";
|
|
4450
|
-
return `${pc2.red("AFL API error:")} ${error.message}${status}`;
|
|
4451
|
-
}
|
|
4452
|
-
if (error instanceof ScrapeError) {
|
|
4453
|
-
const source = error.source ? ` [${error.source}]` : "";
|
|
4454
|
-
return `${pc2.red("Scrape error:")} ${error.message}${source}`;
|
|
4455
|
-
}
|
|
4456
|
-
if (error instanceof UnsupportedSourceError) {
|
|
4457
|
-
return `${pc2.red("Unsupported source:")} ${error.message}`;
|
|
4458
|
-
}
|
|
4459
|
-
if (error instanceof Error) {
|
|
4460
|
-
return `${pc2.red("Error:")} ${error.message}`;
|
|
4461
|
-
}
|
|
4462
|
-
return `${pc2.red("Error:")} ${String(error)}`;
|
|
4463
|
-
}
|
|
4464
4628
|
runMain(main).catch((error) => {
|
|
4465
4629
|
console.error(formatError(error));
|
|
4466
4630
|
process.exit(1);
|