fitzroy 1.1.1 → 1.3.0
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 +802 -259
- package/dist/index.d.ts +258 -249
- package/dist/index.js +235 -87
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,12 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/errors.ts
|
|
13
|
+
function aflwUnsupportedError(source) {
|
|
14
|
+
return new UnsupportedSourceError(
|
|
15
|
+
`AFLW data is not available from ${source}. Use --source afl-api for AFLW data.`,
|
|
16
|
+
source
|
|
17
|
+
);
|
|
18
|
+
}
|
|
13
19
|
var AflApiError, ScrapeError, UnsupportedSourceError, ValidationError;
|
|
14
20
|
var init_errors = __esm({
|
|
15
21
|
"src/lib/errors.ts"() {
|
|
@@ -45,6 +51,47 @@ var init_errors = __esm({
|
|
|
45
51
|
}
|
|
46
52
|
});
|
|
47
53
|
|
|
54
|
+
// src/cli/error-boundary.ts
|
|
55
|
+
import pc from "picocolors";
|
|
56
|
+
function formatError(error) {
|
|
57
|
+
if (error instanceof ValidationError && error.issues) {
|
|
58
|
+
const issueLines = error.issues.map((i) => ` ${pc.yellow(i.path)}: ${i.message}`);
|
|
59
|
+
return `${pc.red("Validation error:")}
|
|
60
|
+
${issueLines.join("\n")}`;
|
|
61
|
+
}
|
|
62
|
+
if (error instanceof AflApiError) {
|
|
63
|
+
const status = error.statusCode ? ` (HTTP ${error.statusCode})` : "";
|
|
64
|
+
return `${pc.red("AFL API error:")} ${error.message}${status}`;
|
|
65
|
+
}
|
|
66
|
+
if (error instanceof ScrapeError) {
|
|
67
|
+
const source = error.source ? ` [${error.source}]` : "";
|
|
68
|
+
return `${pc.red("Scrape error:")} ${error.message}${source}`;
|
|
69
|
+
}
|
|
70
|
+
if (error instanceof UnsupportedSourceError) {
|
|
71
|
+
return `${pc.red("Unsupported source:")} ${error.message}`;
|
|
72
|
+
}
|
|
73
|
+
if (error instanceof Error) {
|
|
74
|
+
return `${pc.red("Error:")} ${error.message}`;
|
|
75
|
+
}
|
|
76
|
+
return `${pc.red("Error:")} ${String(error)}`;
|
|
77
|
+
}
|
|
78
|
+
function withErrorBoundary(fn) {
|
|
79
|
+
return async (ctx) => {
|
|
80
|
+
try {
|
|
81
|
+
await fn(ctx);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(formatError(error));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
var init_error_boundary = __esm({
|
|
89
|
+
"src/cli/error-boundary.ts"() {
|
|
90
|
+
"use strict";
|
|
91
|
+
init_errors();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
48
95
|
// src/lib/result.ts
|
|
49
96
|
function ok(data) {
|
|
50
97
|
return { success: true, data };
|
|
@@ -117,6 +164,10 @@ function parseAflTablesDate(dateStr) {
|
|
|
117
164
|
}
|
|
118
165
|
return null;
|
|
119
166
|
}
|
|
167
|
+
function resolveDefaultSeason(competition = "AFLM") {
|
|
168
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
169
|
+
return competition === "AFLW" ? year - 1 : year;
|
|
170
|
+
}
|
|
120
171
|
function buildUtcDate(year, monthStr, day) {
|
|
121
172
|
const monthIndex = MONTH_ABBREV_TO_INDEX.get(monthStr.toLowerCase());
|
|
122
173
|
if (monthIndex === void 0) {
|
|
@@ -168,7 +219,7 @@ function normaliseTeamName(raw) {
|
|
|
168
219
|
const trimmed = raw.trim();
|
|
169
220
|
return ALIAS_MAP.get(trimmed.toLowerCase()) ?? trimmed;
|
|
170
221
|
}
|
|
171
|
-
var TEAM_ALIASES, AFL_SENIOR_TEAMS, ALIAS_MAP;
|
|
222
|
+
var TEAM_ALIASES, AFL_SENIOR_TEAMS, ALIAS_MAP, AFL_API_TEAM_IDS;
|
|
172
223
|
var init_team_mapping = __esm({
|
|
173
224
|
"src/lib/team-mapping.ts"() {
|
|
174
225
|
"use strict";
|
|
@@ -241,6 +292,26 @@ var init_team_mapping = __esm({
|
|
|
241
292
|
}
|
|
242
293
|
return map;
|
|
243
294
|
})();
|
|
295
|
+
AFL_API_TEAM_IDS = /* @__PURE__ */ new Map([
|
|
296
|
+
["CD_T10", "Adelaide Crows"],
|
|
297
|
+
["CD_T20", "Brisbane Lions"],
|
|
298
|
+
["CD_T30", "Carlton"],
|
|
299
|
+
["CD_T40", "Collingwood"],
|
|
300
|
+
["CD_T50", "Essendon"],
|
|
301
|
+
["CD_T60", "Fremantle"],
|
|
302
|
+
["CD_T70", "Geelong Cats"],
|
|
303
|
+
["CD_T1000", "Gold Coast Suns"],
|
|
304
|
+
["CD_T1010", "GWS Giants"],
|
|
305
|
+
["CD_T80", "Hawthorn"],
|
|
306
|
+
["CD_T90", "Melbourne"],
|
|
307
|
+
["CD_T100", "North Melbourne"],
|
|
308
|
+
["CD_T110", "Port Adelaide"],
|
|
309
|
+
["CD_T120", "Richmond"],
|
|
310
|
+
["CD_T130", "St Kilda"],
|
|
311
|
+
["CD_T160", "Sydney Swans"],
|
|
312
|
+
["CD_T150", "West Coast Eagles"],
|
|
313
|
+
["CD_T140", "Western Bulldogs"]
|
|
314
|
+
]);
|
|
244
315
|
}
|
|
245
316
|
});
|
|
246
317
|
|
|
@@ -506,6 +577,14 @@ var init_footywire_player_stats = __esm({
|
|
|
506
577
|
function inferRoundType(roundName) {
|
|
507
578
|
return FINALS_PATTERN.test(roundName) ? "Finals" : "HomeAndAway";
|
|
508
579
|
}
|
|
580
|
+
function finalsRoundNumber(headerText, lastHARound) {
|
|
581
|
+
const lower = headerText.toLowerCase();
|
|
582
|
+
if (lower.includes("qualifying") || lower.includes("elimination")) return lastHARound + 1;
|
|
583
|
+
if (lower.includes("semi")) return lastHARound + 2;
|
|
584
|
+
if (lower.includes("preliminary")) return lastHARound + 3;
|
|
585
|
+
if (lower.includes("grand")) return lastHARound + 4;
|
|
586
|
+
return lastHARound + 1;
|
|
587
|
+
}
|
|
509
588
|
function toMatchStatus(raw) {
|
|
510
589
|
switch (raw) {
|
|
511
590
|
case "CONCLUDED":
|
|
@@ -595,6 +674,7 @@ function parseMatchList(html, year) {
|
|
|
595
674
|
const $ = cheerio2.load(html);
|
|
596
675
|
const results = [];
|
|
597
676
|
let currentRound = 0;
|
|
677
|
+
let lastHARound = 0;
|
|
598
678
|
let currentRoundType = "HomeAndAway";
|
|
599
679
|
$("tr").each((_i, row) => {
|
|
600
680
|
const roundHeader = $(row).find("td[colspan='7']");
|
|
@@ -604,6 +684,11 @@ function parseMatchList(html, year) {
|
|
|
604
684
|
const roundMatch = /Round\s+(\d+)/i.exec(text);
|
|
605
685
|
if (roundMatch?.[1]) {
|
|
606
686
|
currentRound = Number.parseInt(roundMatch[1], 10);
|
|
687
|
+
if (currentRoundType === "HomeAndAway") {
|
|
688
|
+
lastHARound = currentRound;
|
|
689
|
+
}
|
|
690
|
+
} else if (currentRoundType === "Finals") {
|
|
691
|
+
currentRound = finalsRoundNumber(text, lastHARound);
|
|
607
692
|
}
|
|
608
693
|
return;
|
|
609
694
|
}
|
|
@@ -674,6 +759,7 @@ function parseFixtureList(html, year) {
|
|
|
674
759
|
const $ = cheerio2.load(html);
|
|
675
760
|
const fixtures = [];
|
|
676
761
|
let currentRound = 0;
|
|
762
|
+
let lastHARound = 0;
|
|
677
763
|
let currentRoundType = "HomeAndAway";
|
|
678
764
|
let gameNumber = 0;
|
|
679
765
|
$("tr").each((_i, row) => {
|
|
@@ -684,6 +770,11 @@ function parseFixtureList(html, year) {
|
|
|
684
770
|
const roundMatch = /Round\s+(\d+)/i.exec(text);
|
|
685
771
|
if (roundMatch?.[1]) {
|
|
686
772
|
currentRound = Number.parseInt(roundMatch[1], 10);
|
|
773
|
+
if (currentRoundType === "HomeAndAway") {
|
|
774
|
+
lastHARound = currentRound;
|
|
775
|
+
}
|
|
776
|
+
} else if (currentRoundType === "Finals") {
|
|
777
|
+
currentRound = finalsRoundNumber(text, lastHARound);
|
|
687
778
|
}
|
|
688
779
|
return;
|
|
689
780
|
}
|
|
@@ -1301,6 +1392,27 @@ var init_coaches_votes = __esm({
|
|
|
1301
1392
|
}
|
|
1302
1393
|
});
|
|
1303
1394
|
|
|
1395
|
+
// src/lib/concurrency.ts
|
|
1396
|
+
async function batchedMap(items, fn, options) {
|
|
1397
|
+
const batchSize = options?.batchSize ?? 5;
|
|
1398
|
+
const delayMs = options?.delayMs ?? 0;
|
|
1399
|
+
const results = [];
|
|
1400
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
1401
|
+
const batch = items.slice(i, i + batchSize);
|
|
1402
|
+
const batchResults = await Promise.all(batch.map(fn));
|
|
1403
|
+
results.push(...batchResults);
|
|
1404
|
+
if (delayMs > 0 && i + batchSize < items.length) {
|
|
1405
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return results;
|
|
1409
|
+
}
|
|
1410
|
+
var init_concurrency = __esm({
|
|
1411
|
+
"src/lib/concurrency.ts"() {
|
|
1412
|
+
"use strict";
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1304
1416
|
// src/lib/validation.ts
|
|
1305
1417
|
import { z } from "zod/v4";
|
|
1306
1418
|
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;
|
|
@@ -1410,7 +1522,14 @@ var init_validation = __esm({
|
|
|
1410
1522
|
captain: z.boolean().optional(),
|
|
1411
1523
|
playerJumperNumber: z.number().optional()
|
|
1412
1524
|
}).passthrough();
|
|
1413
|
-
statNum = z.
|
|
1525
|
+
statNum = z.union([
|
|
1526
|
+
z.number(),
|
|
1527
|
+
z.string().transform((s) => {
|
|
1528
|
+
if (s === "" || s === "-") return null;
|
|
1529
|
+
const n = Number(s);
|
|
1530
|
+
return Number.isNaN(n) ? null : n;
|
|
1531
|
+
})
|
|
1532
|
+
]).nullable().optional();
|
|
1414
1533
|
PlayerGameStatsSchema = z.object({
|
|
1415
1534
|
goals: statNum,
|
|
1416
1535
|
behinds: statNum,
|
|
@@ -1488,8 +1607,8 @@ var init_validation = __esm({
|
|
|
1488
1607
|
teamId: z.string(),
|
|
1489
1608
|
playerStats: z.object({
|
|
1490
1609
|
stats: PlayerGameStatsSchema,
|
|
1491
|
-
timeOnGroundPercentage:
|
|
1492
|
-
}).passthrough()
|
|
1610
|
+
timeOnGroundPercentage: statNum
|
|
1611
|
+
}).passthrough().nullable().optional()
|
|
1493
1612
|
}).passthrough();
|
|
1494
1613
|
PlayerStatsListSchema = z.object({
|
|
1495
1614
|
homeTeamPlayerStats: z.array(PlayerStatsItemSchema),
|
|
@@ -1589,6 +1708,7 @@ var TOKEN_URL, API_BASE, CFS_BASE, AflApiClient;
|
|
|
1589
1708
|
var init_afl_api = __esm({
|
|
1590
1709
|
"src/sources/afl-api.ts"() {
|
|
1591
1710
|
"use strict";
|
|
1711
|
+
init_concurrency();
|
|
1592
1712
|
init_errors();
|
|
1593
1713
|
init_result();
|
|
1594
1714
|
init_validation();
|
|
@@ -1599,6 +1719,7 @@ var init_afl_api = __esm({
|
|
|
1599
1719
|
fetchFn;
|
|
1600
1720
|
tokenUrl;
|
|
1601
1721
|
cachedToken = null;
|
|
1722
|
+
pendingAuth = null;
|
|
1602
1723
|
constructor(options) {
|
|
1603
1724
|
this.fetchFn = options?.fetchFn ?? globalThis.fetch;
|
|
1604
1725
|
this.tokenUrl = options?.tokenUrl ?? TOKEN_URL;
|
|
@@ -1606,9 +1727,21 @@ var init_afl_api = __esm({
|
|
|
1606
1727
|
/**
|
|
1607
1728
|
* Authenticate with the WMCTok token endpoint and cache the token.
|
|
1608
1729
|
*
|
|
1730
|
+
* Concurrent callers share the same in-flight request to avoid
|
|
1731
|
+
* redundant token fetches (thundering herd prevention).
|
|
1732
|
+
*
|
|
1609
1733
|
* @returns The access token on success, or an error Result.
|
|
1610
1734
|
*/
|
|
1611
1735
|
async authenticate() {
|
|
1736
|
+
if (this.pendingAuth) {
|
|
1737
|
+
return this.pendingAuth;
|
|
1738
|
+
}
|
|
1739
|
+
this.pendingAuth = this.doAuthenticate().finally(() => {
|
|
1740
|
+
this.pendingAuth = null;
|
|
1741
|
+
});
|
|
1742
|
+
return this.pendingAuth;
|
|
1743
|
+
}
|
|
1744
|
+
async doAuthenticate() {
|
|
1612
1745
|
try {
|
|
1613
1746
|
const response = await this.fetchFn(this.tokenUrl, {
|
|
1614
1747
|
method: "POST",
|
|
@@ -1863,7 +1996,7 @@ var init_afl_api = __esm({
|
|
|
1863
1996
|
return roundsResult;
|
|
1864
1997
|
}
|
|
1865
1998
|
const providerIds = roundsResult.data.flatMap((r) => r.providerId ? [r.providerId] : []);
|
|
1866
|
-
const results = await
|
|
1999
|
+
const results = await batchedMap(providerIds, (id) => this.fetchRoundMatchItems(id));
|
|
1867
2000
|
const allItems = [];
|
|
1868
2001
|
for (const result of results) {
|
|
1869
2002
|
if (!result.success) {
|
|
@@ -2186,12 +2319,14 @@ function toFixture(item, season, fallbackRoundNumber, competition) {
|
|
|
2186
2319
|
async function fetchFixture(query) {
|
|
2187
2320
|
const competition = query.competition ?? "AFLM";
|
|
2188
2321
|
if (query.source === "squiggle") {
|
|
2322
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("squiggle"));
|
|
2189
2323
|
const client2 = new SquiggleClient();
|
|
2190
2324
|
const result = await client2.fetchGames(query.season, query.round ?? void 0);
|
|
2191
2325
|
if (!result.success) return result;
|
|
2192
2326
|
return ok(transformSquiggleGamesToFixture(result.data.games, query.season));
|
|
2193
2327
|
}
|
|
2194
2328
|
if (query.source === "footywire") {
|
|
2329
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
2195
2330
|
const fwClient = new FootyWireClient();
|
|
2196
2331
|
const result = await fwClient.fetchSeasonFixture(query.season);
|
|
2197
2332
|
if (!result.success) return result;
|
|
@@ -2221,8 +2356,9 @@ async function fetchFixture(query) {
|
|
|
2221
2356
|
const roundProviderIds = roundsResult.data.flatMap(
|
|
2222
2357
|
(r) => r.providerId ? [{ providerId: r.providerId, roundNumber: r.roundNumber }] : []
|
|
2223
2358
|
);
|
|
2224
|
-
const roundResults = await
|
|
2225
|
-
roundProviderIds
|
|
2359
|
+
const roundResults = await batchedMap(
|
|
2360
|
+
roundProviderIds,
|
|
2361
|
+
(r) => client.fetchRoundMatchItems(r.providerId)
|
|
2226
2362
|
);
|
|
2227
2363
|
const fixtures = [];
|
|
2228
2364
|
for (let i = 0; i < roundResults.length; i++) {
|
|
@@ -2238,6 +2374,7 @@ async function fetchFixture(query) {
|
|
|
2238
2374
|
var init_fixture = __esm({
|
|
2239
2375
|
"src/api/fixture.ts"() {
|
|
2240
2376
|
"use strict";
|
|
2377
|
+
init_concurrency();
|
|
2241
2378
|
init_errors();
|
|
2242
2379
|
init_result();
|
|
2243
2380
|
init_team_mapping();
|
|
@@ -2380,6 +2517,7 @@ function parseSeasonPage(html, year) {
|
|
|
2380
2517
|
const results = [];
|
|
2381
2518
|
let currentRound = 0;
|
|
2382
2519
|
let currentRoundType = "HomeAndAway";
|
|
2520
|
+
let lastHARound = 0;
|
|
2383
2521
|
let matchCounter = 0;
|
|
2384
2522
|
$("table").each((_i, table) => {
|
|
2385
2523
|
const $table = $(table);
|
|
@@ -2389,10 +2527,14 @@ function parseSeasonPage(html, year) {
|
|
|
2389
2527
|
if (roundMatch?.[1] && border !== "1") {
|
|
2390
2528
|
currentRound = Number.parseInt(roundMatch[1], 10);
|
|
2391
2529
|
currentRoundType = inferRoundType(text);
|
|
2530
|
+
if (currentRoundType === "HomeAndAway") {
|
|
2531
|
+
lastHARound = currentRound;
|
|
2532
|
+
}
|
|
2392
2533
|
return;
|
|
2393
2534
|
}
|
|
2394
2535
|
if (border !== "1" && inferRoundType(text) === "Finals") {
|
|
2395
2536
|
currentRoundType = "Finals";
|
|
2537
|
+
currentRound = finalsRoundNumber(text, lastHARound);
|
|
2396
2538
|
return;
|
|
2397
2539
|
}
|
|
2398
2540
|
if (border !== "1") return;
|
|
@@ -2902,6 +3044,7 @@ var init_ladder = __esm({
|
|
|
2902
3044
|
async function fetchLadder(query) {
|
|
2903
3045
|
const competition = query.competition ?? "AFLM";
|
|
2904
3046
|
if (query.source === "squiggle") {
|
|
3047
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("squiggle"));
|
|
2905
3048
|
const client2 = new SquiggleClient();
|
|
2906
3049
|
const result = await client2.fetchStandings(query.season, query.round ?? void 0);
|
|
2907
3050
|
if (!result.success) return result;
|
|
@@ -2913,6 +3056,7 @@ async function fetchLadder(query) {
|
|
|
2913
3056
|
});
|
|
2914
3057
|
}
|
|
2915
3058
|
if (query.source === "afl-tables") {
|
|
3059
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
2916
3060
|
const atClient = new AflTablesClient();
|
|
2917
3061
|
const resultsResult = await atClient.fetchSeasonResults(query.season);
|
|
2918
3062
|
if (!resultsResult.success) return resultsResult;
|
|
@@ -3034,8 +3178,9 @@ async function fetchLineup(query) {
|
|
|
3034
3178
|
if (matchItems.data.length === 0) {
|
|
3035
3179
|
return err(new AflApiError(`No matches found for round ${query.round}`));
|
|
3036
3180
|
}
|
|
3037
|
-
const rosterResults = await
|
|
3038
|
-
matchItems.data
|
|
3181
|
+
const rosterResults = await batchedMap(
|
|
3182
|
+
matchItems.data,
|
|
3183
|
+
(item) => client.fetchMatchRoster(item.match.matchId)
|
|
3039
3184
|
);
|
|
3040
3185
|
const lineups = [];
|
|
3041
3186
|
for (const rosterResult of rosterResults) {
|
|
@@ -3047,6 +3192,7 @@ async function fetchLineup(query) {
|
|
|
3047
3192
|
var init_lineup2 = __esm({
|
|
3048
3193
|
"src/api/lineup.ts"() {
|
|
3049
3194
|
"use strict";
|
|
3195
|
+
init_concurrency();
|
|
3050
3196
|
init_errors();
|
|
3051
3197
|
init_result();
|
|
3052
3198
|
init_afl_api();
|
|
@@ -3075,6 +3221,7 @@ async function fetchMatchResults(query) {
|
|
|
3075
3221
|
return ok(transformMatchItems(itemsResult.data, query.season, competition));
|
|
3076
3222
|
}
|
|
3077
3223
|
case "footywire": {
|
|
3224
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
3078
3225
|
const client = new FootyWireClient();
|
|
3079
3226
|
const result = await client.fetchSeasonResults(query.season);
|
|
3080
3227
|
if (!result.success) return result;
|
|
@@ -3084,6 +3231,7 @@ async function fetchMatchResults(query) {
|
|
|
3084
3231
|
return result;
|
|
3085
3232
|
}
|
|
3086
3233
|
case "afl-tables": {
|
|
3234
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
3087
3235
|
const client = new AflTablesClient();
|
|
3088
3236
|
const result = await client.fetchSeasonResults(query.season);
|
|
3089
3237
|
if (!result.success) return result;
|
|
@@ -3093,6 +3241,7 @@ async function fetchMatchResults(query) {
|
|
|
3093
3241
|
return result;
|
|
3094
3242
|
}
|
|
3095
3243
|
case "squiggle": {
|
|
3244
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("squiggle"));
|
|
3096
3245
|
const client = new SquiggleClient();
|
|
3097
3246
|
const result = await client.fetchGames(query.season, query.round ?? void 0, 100);
|
|
3098
3247
|
if (!result.success) return result;
|
|
@@ -3131,7 +3280,7 @@ async function resolveTeamId(client, teamName, competition) {
|
|
|
3131
3280
|
async function fetchFromAflApi(query) {
|
|
3132
3281
|
const client = new AflApiClient();
|
|
3133
3282
|
const competition = query.competition ?? "AFLM";
|
|
3134
|
-
const season = query.season ?? (
|
|
3283
|
+
const season = query.season ?? resolveDefaultSeason(competition);
|
|
3135
3284
|
const [teamIdResult, seasonResult] = await Promise.all([
|
|
3136
3285
|
resolveTeamId(client, query.team, competition),
|
|
3137
3286
|
client.resolveCompSeason(competition, season)
|
|
@@ -3154,8 +3303,8 @@ async function fetchFromAflApi(query) {
|
|
|
3154
3303
|
jumperNumber: p.jumperNumber ?? null,
|
|
3155
3304
|
position: p.position ?? null,
|
|
3156
3305
|
dateOfBirth: p.player.dateOfBirth ?? null,
|
|
3157
|
-
heightCm: p.player.heightInCm
|
|
3158
|
-
weightKg: p.player.weightInKg
|
|
3306
|
+
heightCm: p.player.heightInCm || null,
|
|
3307
|
+
weightKg: p.player.weightInKg || null,
|
|
3159
3308
|
gamesPlayed: null,
|
|
3160
3309
|
goals: null,
|
|
3161
3310
|
draftYear: p.player.draftYear ? Number.parseInt(p.player.draftYear, 10) || null : null,
|
|
@@ -3169,8 +3318,9 @@ async function fetchFromAflApi(query) {
|
|
|
3169
3318
|
return ok(players);
|
|
3170
3319
|
}
|
|
3171
3320
|
async function fetchFromFootyWire(query) {
|
|
3172
|
-
const client = new FootyWireClient();
|
|
3173
3321
|
const competition = query.competition ?? "AFLM";
|
|
3322
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
3323
|
+
const client = new FootyWireClient();
|
|
3174
3324
|
const teamName = normaliseTeamName(query.team);
|
|
3175
3325
|
const result = await client.fetchPlayerList(teamName);
|
|
3176
3326
|
if (!result.success) return result;
|
|
@@ -3182,8 +3332,9 @@ async function fetchFromFootyWire(query) {
|
|
|
3182
3332
|
return ok(players);
|
|
3183
3333
|
}
|
|
3184
3334
|
async function fetchFromAflTables(query) {
|
|
3185
|
-
const client = new AflTablesClient();
|
|
3186
3335
|
const competition = query.competition ?? "AFLM";
|
|
3336
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
3337
|
+
const client = new AflTablesClient();
|
|
3187
3338
|
const teamName = normaliseTeamName(query.team);
|
|
3188
3339
|
const result = await client.fetchPlayerList(teamName);
|
|
3189
3340
|
if (!result.success) return result;
|
|
@@ -3214,6 +3365,7 @@ async function fetchPlayerDetails(query) {
|
|
|
3214
3365
|
var init_player_details = __esm({
|
|
3215
3366
|
"src/api/player-details.ts"() {
|
|
3216
3367
|
"use strict";
|
|
3368
|
+
init_date_utils();
|
|
3217
3369
|
init_errors();
|
|
3218
3370
|
init_result();
|
|
3219
3371
|
init_team_mapping();
|
|
@@ -3229,80 +3381,82 @@ function toNullable(value) {
|
|
|
3229
3381
|
}
|
|
3230
3382
|
function transformOne(item, matchId, season, roundNumber, competition, source, teamIdMap) {
|
|
3231
3383
|
const inner = item.player.player.player;
|
|
3232
|
-
const stats = item.playerStats
|
|
3233
|
-
const clearances = stats
|
|
3384
|
+
const stats = item.playerStats?.stats;
|
|
3385
|
+
const clearances = stats?.clearances;
|
|
3234
3386
|
return {
|
|
3235
3387
|
matchId,
|
|
3236
3388
|
season,
|
|
3237
3389
|
roundNumber,
|
|
3238
|
-
team: normaliseTeamName(
|
|
3390
|
+
team: normaliseTeamName(
|
|
3391
|
+
teamIdMap?.get(item.teamId) ?? AFL_API_TEAM_IDS.get(item.teamId) ?? item.teamId
|
|
3392
|
+
),
|
|
3239
3393
|
competition,
|
|
3240
3394
|
playerId: inner.playerId,
|
|
3241
3395
|
givenName: inner.playerName.givenName,
|
|
3242
3396
|
surname: inner.playerName.surname,
|
|
3243
3397
|
displayName: `${inner.playerName.givenName} ${inner.playerName.surname}`,
|
|
3244
3398
|
jumperNumber: item.player.jumperNumber ?? null,
|
|
3245
|
-
kicks: toNullable(stats
|
|
3246
|
-
handballs: toNullable(stats
|
|
3247
|
-
disposals: toNullable(stats
|
|
3248
|
-
marks: toNullable(stats
|
|
3249
|
-
goals: toNullable(stats
|
|
3250
|
-
behinds: toNullable(stats
|
|
3251
|
-
tackles: toNullable(stats
|
|
3252
|
-
hitouts: toNullable(stats
|
|
3253
|
-
freesFor: toNullable(stats
|
|
3254
|
-
freesAgainst: toNullable(stats
|
|
3255
|
-
contestedPossessions: toNullable(stats
|
|
3256
|
-
uncontestedPossessions: toNullable(stats
|
|
3257
|
-
contestedMarks: toNullable(stats
|
|
3258
|
-
intercepts: toNullable(stats
|
|
3399
|
+
kicks: toNullable(stats?.kicks),
|
|
3400
|
+
handballs: toNullable(stats?.handballs),
|
|
3401
|
+
disposals: toNullable(stats?.disposals),
|
|
3402
|
+
marks: toNullable(stats?.marks),
|
|
3403
|
+
goals: toNullable(stats?.goals),
|
|
3404
|
+
behinds: toNullable(stats?.behinds),
|
|
3405
|
+
tackles: toNullable(stats?.tackles),
|
|
3406
|
+
hitouts: toNullable(stats?.hitouts),
|
|
3407
|
+
freesFor: toNullable(stats?.freesFor),
|
|
3408
|
+
freesAgainst: toNullable(stats?.freesAgainst),
|
|
3409
|
+
contestedPossessions: toNullable(stats?.contestedPossessions),
|
|
3410
|
+
uncontestedPossessions: toNullable(stats?.uncontestedPossessions),
|
|
3411
|
+
contestedMarks: toNullable(stats?.contestedMarks),
|
|
3412
|
+
intercepts: toNullable(stats?.intercepts),
|
|
3259
3413
|
centreClearances: toNullable(clearances?.centreClearances),
|
|
3260
3414
|
stoppageClearances: toNullable(clearances?.stoppageClearances),
|
|
3261
3415
|
totalClearances: toNullable(clearances?.totalClearances),
|
|
3262
|
-
inside50s: toNullable(stats
|
|
3263
|
-
rebound50s: toNullable(stats
|
|
3264
|
-
clangers: toNullable(stats
|
|
3265
|
-
turnovers: toNullable(stats
|
|
3266
|
-
onePercenters: toNullable(stats
|
|
3267
|
-
bounces: toNullable(stats
|
|
3268
|
-
goalAssists: toNullable(stats
|
|
3269
|
-
disposalEfficiency: toNullable(stats
|
|
3270
|
-
metresGained: toNullable(stats
|
|
3271
|
-
goalAccuracy: toNullable(stats
|
|
3272
|
-
marksInside50: toNullable(stats
|
|
3273
|
-
tacklesInside50: toNullable(stats
|
|
3274
|
-
shotsAtGoal: toNullable(stats
|
|
3275
|
-
scoreInvolvements: toNullable(stats
|
|
3276
|
-
totalPossessions: toNullable(stats
|
|
3277
|
-
timeOnGroundPercentage: toNullable(item.playerStats
|
|
3278
|
-
ratingPoints: toNullable(stats
|
|
3279
|
-
dreamTeamPoints: toNullable(stats
|
|
3280
|
-
effectiveDisposals: toNullable(stats
|
|
3281
|
-
effectiveKicks: toNullable(stats
|
|
3282
|
-
kickEfficiency: toNullable(stats
|
|
3283
|
-
kickToHandballRatio: toNullable(stats
|
|
3284
|
-
pressureActs: toNullable(stats
|
|
3285
|
-
defHalfPressureActs: toNullable(stats
|
|
3286
|
-
spoils: toNullable(stats
|
|
3287
|
-
hitoutsToAdvantage: toNullable(stats
|
|
3288
|
-
hitoutWinPercentage: toNullable(stats
|
|
3289
|
-
hitoutToAdvantageRate: toNullable(stats
|
|
3290
|
-
groundBallGets: toNullable(stats
|
|
3291
|
-
f50GroundBallGets: toNullable(stats
|
|
3292
|
-
interceptMarks: toNullable(stats
|
|
3293
|
-
marksOnLead: toNullable(stats
|
|
3294
|
-
contestedPossessionRate: toNullable(stats
|
|
3295
|
-
contestOffOneOnOnes: toNullable(stats
|
|
3296
|
-
contestOffWins: toNullable(stats
|
|
3297
|
-
contestOffWinsPercentage: toNullable(stats
|
|
3298
|
-
contestDefOneOnOnes: toNullable(stats
|
|
3299
|
-
contestDefLosses: toNullable(stats
|
|
3300
|
-
contestDefLossPercentage: toNullable(stats
|
|
3301
|
-
centreBounceAttendances: toNullable(stats
|
|
3302
|
-
kickins: toNullable(stats
|
|
3303
|
-
kickinsPlayon: toNullable(stats
|
|
3304
|
-
ruckContests: toNullable(stats
|
|
3305
|
-
scoreLaunches: toNullable(stats
|
|
3416
|
+
inside50s: toNullable(stats?.inside50s),
|
|
3417
|
+
rebound50s: toNullable(stats?.rebound50s),
|
|
3418
|
+
clangers: toNullable(stats?.clangers),
|
|
3419
|
+
turnovers: toNullable(stats?.turnovers),
|
|
3420
|
+
onePercenters: toNullable(stats?.onePercenters),
|
|
3421
|
+
bounces: toNullable(stats?.bounces),
|
|
3422
|
+
goalAssists: toNullable(stats?.goalAssists),
|
|
3423
|
+
disposalEfficiency: toNullable(stats?.disposalEfficiency),
|
|
3424
|
+
metresGained: toNullable(stats?.metresGained),
|
|
3425
|
+
goalAccuracy: toNullable(stats?.goalAccuracy),
|
|
3426
|
+
marksInside50: toNullable(stats?.marksInside50),
|
|
3427
|
+
tacklesInside50: toNullable(stats?.tacklesInside50),
|
|
3428
|
+
shotsAtGoal: toNullable(stats?.shotsAtGoal),
|
|
3429
|
+
scoreInvolvements: toNullable(stats?.scoreInvolvements),
|
|
3430
|
+
totalPossessions: toNullable(stats?.totalPossessions),
|
|
3431
|
+
timeOnGroundPercentage: toNullable(item.playerStats?.timeOnGroundPercentage),
|
|
3432
|
+
ratingPoints: toNullable(stats?.ratingPoints),
|
|
3433
|
+
dreamTeamPoints: toNullable(stats?.dreamTeamPoints),
|
|
3434
|
+
effectiveDisposals: toNullable(stats?.extendedStats?.effectiveDisposals),
|
|
3435
|
+
effectiveKicks: toNullable(stats?.extendedStats?.effectiveKicks),
|
|
3436
|
+
kickEfficiency: toNullable(stats?.extendedStats?.kickEfficiency),
|
|
3437
|
+
kickToHandballRatio: toNullable(stats?.extendedStats?.kickToHandballRatio),
|
|
3438
|
+
pressureActs: toNullable(stats?.extendedStats?.pressureActs),
|
|
3439
|
+
defHalfPressureActs: toNullable(stats?.extendedStats?.defHalfPressureActs),
|
|
3440
|
+
spoils: toNullable(stats?.extendedStats?.spoils),
|
|
3441
|
+
hitoutsToAdvantage: toNullable(stats?.extendedStats?.hitoutsToAdvantage),
|
|
3442
|
+
hitoutWinPercentage: toNullable(stats?.extendedStats?.hitoutWinPercentage),
|
|
3443
|
+
hitoutToAdvantageRate: toNullable(stats?.extendedStats?.hitoutToAdvantageRate),
|
|
3444
|
+
groundBallGets: toNullable(stats?.extendedStats?.groundBallGets),
|
|
3445
|
+
f50GroundBallGets: toNullable(stats?.extendedStats?.f50GroundBallGets),
|
|
3446
|
+
interceptMarks: toNullable(stats?.extendedStats?.interceptMarks),
|
|
3447
|
+
marksOnLead: toNullable(stats?.extendedStats?.marksOnLead),
|
|
3448
|
+
contestedPossessionRate: toNullable(stats?.extendedStats?.contestedPossessionRate),
|
|
3449
|
+
contestOffOneOnOnes: toNullable(stats?.extendedStats?.contestOffOneOnOnes),
|
|
3450
|
+
contestOffWins: toNullable(stats?.extendedStats?.contestOffWins),
|
|
3451
|
+
contestOffWinsPercentage: toNullable(stats?.extendedStats?.contestOffWinsPercentage),
|
|
3452
|
+
contestDefOneOnOnes: toNullable(stats?.extendedStats?.contestDefOneOnOnes),
|
|
3453
|
+
contestDefLosses: toNullable(stats?.extendedStats?.contestDefLosses),
|
|
3454
|
+
contestDefLossPercentage: toNullable(stats?.extendedStats?.contestDefLossPercentage),
|
|
3455
|
+
centreBounceAttendances: toNullable(stats?.extendedStats?.centreBounceAttendances),
|
|
3456
|
+
kickins: toNullable(stats?.extendedStats?.kickins),
|
|
3457
|
+
kickinsPlayon: toNullable(stats?.extendedStats?.kickinsPlayon),
|
|
3458
|
+
ruckContests: toNullable(stats?.extendedStats?.ruckContests),
|
|
3459
|
+
scoreLaunches: toNullable(stats?.extendedStats?.scoreLaunches),
|
|
3306
3460
|
source
|
|
3307
3461
|
};
|
|
3308
3462
|
}
|
|
@@ -3365,8 +3519,9 @@ async function fetchPlayerStats(query) {
|
|
|
3365
3519
|
teamIdMap.set(item.match.homeTeamId, item.match.homeTeam.name);
|
|
3366
3520
|
teamIdMap.set(item.match.awayTeamId, item.match.awayTeam.name);
|
|
3367
3521
|
}
|
|
3368
|
-
const statsResults = await
|
|
3369
|
-
matchItemsResult.data
|
|
3522
|
+
const statsResults = await batchedMap(
|
|
3523
|
+
matchItemsResult.data,
|
|
3524
|
+
(item) => client.fetchPlayerStats(item.match.matchId)
|
|
3370
3525
|
);
|
|
3371
3526
|
const allStats = [];
|
|
3372
3527
|
for (let i = 0; i < statsResults.length; i++) {
|
|
@@ -3390,6 +3545,7 @@ async function fetchPlayerStats(query) {
|
|
|
3390
3545
|
return ok(allStats);
|
|
3391
3546
|
}
|
|
3392
3547
|
case "footywire": {
|
|
3548
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
3393
3549
|
const fwClient = new FootyWireClient();
|
|
3394
3550
|
const idsResult = await fwClient.fetchSeasonMatchIds(query.season);
|
|
3395
3551
|
if (!idsResult.success) return idsResult;
|
|
@@ -3419,6 +3575,7 @@ async function fetchPlayerStats(query) {
|
|
|
3419
3575
|
return ok(allStats);
|
|
3420
3576
|
}
|
|
3421
3577
|
case "afl-tables": {
|
|
3578
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
3422
3579
|
const atClient = new AflTablesClient();
|
|
3423
3580
|
const atResult = await atClient.fetchSeasonPlayerStats(query.season);
|
|
3424
3581
|
if (!atResult.success) return atResult;
|
|
@@ -3434,6 +3591,7 @@ async function fetchPlayerStats(query) {
|
|
|
3434
3591
|
var init_player_stats2 = __esm({
|
|
3435
3592
|
"src/api/player-stats.ts"() {
|
|
3436
3593
|
"use strict";
|
|
3594
|
+
init_concurrency();
|
|
3437
3595
|
init_errors();
|
|
3438
3596
|
init_result();
|
|
3439
3597
|
init_afl_api();
|
|
@@ -3453,7 +3611,37 @@ async function fetchTeamStats(query) {
|
|
|
3453
3611
|
}
|
|
3454
3612
|
case "afl-tables": {
|
|
3455
3613
|
const client = new AflTablesClient();
|
|
3456
|
-
|
|
3614
|
+
const statsResult = await client.fetchTeamStats(query.season);
|
|
3615
|
+
if (!statsResult.success) return statsResult;
|
|
3616
|
+
const needsGp = statsResult.data.some((e) => e.gamesPlayed === 0);
|
|
3617
|
+
const gpMap = /* @__PURE__ */ new Map();
|
|
3618
|
+
if (needsGp) {
|
|
3619
|
+
const resultsResult = await client.fetchSeasonResults(query.season);
|
|
3620
|
+
if (resultsResult.success) {
|
|
3621
|
+
for (const m of resultsResult.data) {
|
|
3622
|
+
gpMap.set(m.homeTeam, (gpMap.get(m.homeTeam) ?? 0) + 1);
|
|
3623
|
+
gpMap.set(m.awayTeam, (gpMap.get(m.awayTeam) ?? 0) + 1);
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
const enriched = statsResult.data.map((entry) => ({
|
|
3628
|
+
...entry,
|
|
3629
|
+
gamesPlayed: gpMap.get(entry.team) ?? entry.gamesPlayed
|
|
3630
|
+
}));
|
|
3631
|
+
if (summaryType === "averages") {
|
|
3632
|
+
return ok(
|
|
3633
|
+
enriched.map((entry) => ({
|
|
3634
|
+
...entry,
|
|
3635
|
+
stats: Object.fromEntries(
|
|
3636
|
+
Object.entries(entry.stats).map(([k, v]) => [
|
|
3637
|
+
k,
|
|
3638
|
+
entry.gamesPlayed > 0 ? +(v / entry.gamesPlayed).toFixed(1) : 0
|
|
3639
|
+
])
|
|
3640
|
+
)
|
|
3641
|
+
}))
|
|
3642
|
+
);
|
|
3643
|
+
}
|
|
3644
|
+
return ok(enriched);
|
|
3457
3645
|
}
|
|
3458
3646
|
case "afl-api":
|
|
3459
3647
|
case "squiggle":
|
|
@@ -3481,19 +3669,30 @@ var init_team_stats = __esm({
|
|
|
3481
3669
|
function teamTypeForComp(comp) {
|
|
3482
3670
|
return comp === "AFLW" ? "WOMEN" : "MEN";
|
|
3483
3671
|
}
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
const teamType = query?.teamType ?? teamTypeForComp(query?.competition ?? "AFLM");
|
|
3487
|
-
const result = await client.fetchTeams(teamType);
|
|
3488
|
-
if (!result.success) return result;
|
|
3489
|
-
const competition = query?.competition ?? "AFLM";
|
|
3490
|
-
const teams = result.data.map((t) => ({
|
|
3672
|
+
function toTeams(data, competition) {
|
|
3673
|
+
return data.map((t) => ({
|
|
3491
3674
|
teamId: String(t.id),
|
|
3492
3675
|
name: normaliseTeamName(t.name),
|
|
3493
3676
|
abbreviation: t.abbreviation ?? "",
|
|
3494
3677
|
competition
|
|
3495
3678
|
})).filter((t) => AFL_SENIOR_TEAMS.has(t.name));
|
|
3496
|
-
|
|
3679
|
+
}
|
|
3680
|
+
async function fetchTeams(query) {
|
|
3681
|
+
const client = new AflApiClient();
|
|
3682
|
+
if (!query?.competition && !query?.teamType) {
|
|
3683
|
+
const [menResult, womenResult] = await Promise.all([
|
|
3684
|
+
client.fetchTeams("MEN"),
|
|
3685
|
+
client.fetchTeams("WOMEN")
|
|
3686
|
+
]);
|
|
3687
|
+
if (!menResult.success) return menResult;
|
|
3688
|
+
if (!womenResult.success) return womenResult;
|
|
3689
|
+
return ok([...toTeams(menResult.data, "AFLM"), ...toTeams(womenResult.data, "AFLW")]);
|
|
3690
|
+
}
|
|
3691
|
+
const competition = query?.competition ?? "AFLM";
|
|
3692
|
+
const teamType = query?.teamType ?? teamTypeForComp(competition);
|
|
3693
|
+
const result = await client.fetchTeams(teamType);
|
|
3694
|
+
if (!result.success) return result;
|
|
3695
|
+
return ok(toTeams(result.data, competition));
|
|
3497
3696
|
}
|
|
3498
3697
|
async function fetchSquad(query) {
|
|
3499
3698
|
const client = new AflApiClient();
|
|
@@ -3514,8 +3713,8 @@ async function fetchSquad(query) {
|
|
|
3514
3713
|
jumperNumber: p.jumperNumber ?? null,
|
|
3515
3714
|
position: p.position ?? null,
|
|
3516
3715
|
dateOfBirth: p.player.dateOfBirth ? new Date(p.player.dateOfBirth) : null,
|
|
3517
|
-
heightCm: p.player.heightInCm
|
|
3518
|
-
weightKg: p.player.weightInKg
|
|
3716
|
+
heightCm: p.player.heightInCm || null,
|
|
3717
|
+
weightKg: p.player.weightInKg || null,
|
|
3519
3718
|
draftYear: p.player.draftYear ? Number.parseInt(p.player.draftYear, 10) || null : null,
|
|
3520
3719
|
draftPosition: p.player.draftPosition ? Number.parseInt(p.player.draftPosition, 10) || null : null,
|
|
3521
3720
|
draftType: p.player.draftType ?? null,
|
|
@@ -3556,6 +3755,94 @@ var init_index = __esm({
|
|
|
3556
3755
|
}
|
|
3557
3756
|
});
|
|
3558
3757
|
|
|
3758
|
+
// src/cli/flags.ts
|
|
3759
|
+
var SEASON_FLAG, OPTIONAL_SEASON_FLAG, ROUND_FLAG, REQUIRED_ROUND_FLAG, SOURCE_FLAG, COMPETITION_FLAG, OPTIONAL_COMPETITION_FLAG, OUTPUT_FLAGS, REQUIRED_TEAM_FLAG, TEAM_FLAG, PLAYER_FLAG;
|
|
3760
|
+
var init_flags = __esm({
|
|
3761
|
+
"src/cli/flags.ts"() {
|
|
3762
|
+
"use strict";
|
|
3763
|
+
SEASON_FLAG = {
|
|
3764
|
+
season: {
|
|
3765
|
+
type: "string",
|
|
3766
|
+
description: "Season year (e.g. 2025)",
|
|
3767
|
+
required: true,
|
|
3768
|
+
alias: "s"
|
|
3769
|
+
}
|
|
3770
|
+
};
|
|
3771
|
+
OPTIONAL_SEASON_FLAG = {
|
|
3772
|
+
season: {
|
|
3773
|
+
type: "string",
|
|
3774
|
+
description: "Season year (e.g. 2025)",
|
|
3775
|
+
alias: "s"
|
|
3776
|
+
}
|
|
3777
|
+
};
|
|
3778
|
+
ROUND_FLAG = {
|
|
3779
|
+
round: {
|
|
3780
|
+
type: "string",
|
|
3781
|
+
description: "Round number",
|
|
3782
|
+
alias: "r"
|
|
3783
|
+
}
|
|
3784
|
+
};
|
|
3785
|
+
REQUIRED_ROUND_FLAG = {
|
|
3786
|
+
round: {
|
|
3787
|
+
type: "string",
|
|
3788
|
+
description: "Round number",
|
|
3789
|
+
required: true,
|
|
3790
|
+
alias: "r"
|
|
3791
|
+
}
|
|
3792
|
+
};
|
|
3793
|
+
SOURCE_FLAG = {
|
|
3794
|
+
source: {
|
|
3795
|
+
type: "string",
|
|
3796
|
+
description: "Data source",
|
|
3797
|
+
default: "afl-api"
|
|
3798
|
+
}
|
|
3799
|
+
};
|
|
3800
|
+
COMPETITION_FLAG = {
|
|
3801
|
+
competition: {
|
|
3802
|
+
type: "string",
|
|
3803
|
+
description: "Competition code (AFLM or AFLW)",
|
|
3804
|
+
default: "AFLM",
|
|
3805
|
+
alias: "c"
|
|
3806
|
+
}
|
|
3807
|
+
};
|
|
3808
|
+
OPTIONAL_COMPETITION_FLAG = {
|
|
3809
|
+
competition: {
|
|
3810
|
+
type: "string",
|
|
3811
|
+
description: "Competition code (AFLM or AFLW)",
|
|
3812
|
+
alias: "c"
|
|
3813
|
+
}
|
|
3814
|
+
};
|
|
3815
|
+
OUTPUT_FLAGS = {
|
|
3816
|
+
json: { type: "boolean", description: "Output as JSON", alias: "j" },
|
|
3817
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
3818
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
3819
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
3820
|
+
};
|
|
3821
|
+
REQUIRED_TEAM_FLAG = {
|
|
3822
|
+
team: {
|
|
3823
|
+
type: "string",
|
|
3824
|
+
description: "Team name, abbreviation, or ID (e.g. Carlton, CARL, 5)",
|
|
3825
|
+
required: true,
|
|
3826
|
+
alias: "t"
|
|
3827
|
+
}
|
|
3828
|
+
};
|
|
3829
|
+
TEAM_FLAG = {
|
|
3830
|
+
team: {
|
|
3831
|
+
type: "string",
|
|
3832
|
+
description: "Filter by team name",
|
|
3833
|
+
alias: "t"
|
|
3834
|
+
}
|
|
3835
|
+
};
|
|
3836
|
+
PLAYER_FLAG = {
|
|
3837
|
+
player: {
|
|
3838
|
+
type: "string",
|
|
3839
|
+
description: "Filter by player name",
|
|
3840
|
+
alias: "p"
|
|
3841
|
+
}
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
});
|
|
3845
|
+
|
|
3559
3846
|
// src/cli/formatters/csv.ts
|
|
3560
3847
|
function escapeField(value) {
|
|
3561
3848
|
if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
|
|
@@ -3768,10 +4055,6 @@ function validateOptionalSeason(raw) {
|
|
|
3768
4055
|
if (raw != null) return validateSeason(raw);
|
|
3769
4056
|
return void 0;
|
|
3770
4057
|
}
|
|
3771
|
-
function resolveDefaultSeason(competition = "AFLM") {
|
|
3772
|
-
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
3773
|
-
return competition === "AFLW" ? year - 1 : year;
|
|
3774
|
-
}
|
|
3775
4058
|
function validateRound(raw) {
|
|
3776
4059
|
const round = Number(raw);
|
|
3777
4060
|
if (Number.isNaN(round) || !Number.isInteger(round) || round < 0) {
|
|
@@ -3822,11 +4105,35 @@ function resolveTeamIdentifier(raw, teams) {
|
|
|
3822
4105
|
const validNames = teams.map((t) => `${t.name} (${t.abbreviation})`).join(", ");
|
|
3823
4106
|
throw new Error(`Unknown team: "${raw}" \u2014 valid teams are: ${validNames}`);
|
|
3824
4107
|
}
|
|
4108
|
+
function resolveMatchByTeam(teamSearch, matchItems) {
|
|
4109
|
+
const normalised = normaliseTeamName(teamSearch);
|
|
4110
|
+
const lower = teamSearch.toLowerCase();
|
|
4111
|
+
const matches = matchItems.filter((item) => {
|
|
4112
|
+
const home = item.match.homeTeam.name;
|
|
4113
|
+
const away = item.match.awayTeam.name;
|
|
4114
|
+
return normaliseTeamName(home) === normalised || normaliseTeamName(away) === normalised || home.toLowerCase().includes(lower) || away.toLowerCase().includes(lower);
|
|
4115
|
+
});
|
|
4116
|
+
const singleMatch = matches[0];
|
|
4117
|
+
if (matches.length === 1 && singleMatch) {
|
|
4118
|
+
return singleMatch.match.matchId;
|
|
4119
|
+
}
|
|
4120
|
+
if (matches.length === 0) {
|
|
4121
|
+
const available = matchItems.map((item) => `${item.match.homeTeam.name} vs ${item.match.awayTeam.name}`).join(", ");
|
|
4122
|
+
throw new Error(
|
|
4123
|
+
`No match found for "${teamSearch}" in this round. Available matches: ${available}`
|
|
4124
|
+
);
|
|
4125
|
+
}
|
|
4126
|
+
const ambiguous = matches.map((item) => `${item.match.homeTeam.name} vs ${item.match.awayTeam.name}`).join(", ");
|
|
4127
|
+
throw new Error(
|
|
4128
|
+
`Multiple matches found for "${teamSearch}": ${ambiguous}. Please be more specific.`
|
|
4129
|
+
);
|
|
4130
|
+
}
|
|
3825
4131
|
var VALID_SOURCES, VALID_COMPETITIONS, VALID_FORMATS;
|
|
3826
4132
|
var init_validation2 = __esm({
|
|
3827
4133
|
"src/cli/validation.ts"() {
|
|
3828
4134
|
"use strict";
|
|
3829
4135
|
init_team_mapping();
|
|
4136
|
+
init_date_utils();
|
|
3830
4137
|
VALID_SOURCES = ["afl-api", "footywire", "afl-tables", "squiggle"];
|
|
3831
4138
|
VALID_COMPETITIONS = ["AFLM", "AFLW"];
|
|
3832
4139
|
VALID_FORMATS = ["table", "json", "csv"];
|
|
@@ -3844,6 +4151,8 @@ var init_matches = __esm({
|
|
|
3844
4151
|
"src/cli/commands/matches.ts"() {
|
|
3845
4152
|
"use strict";
|
|
3846
4153
|
init_index();
|
|
4154
|
+
init_error_boundary();
|
|
4155
|
+
init_flags();
|
|
3847
4156
|
init_formatters();
|
|
3848
4157
|
init_ui();
|
|
3849
4158
|
init_validation2();
|
|
@@ -3862,20 +4171,13 @@ var init_matches = __esm({
|
|
|
3862
4171
|
description: "Fetch match results for a season"
|
|
3863
4172
|
},
|
|
3864
4173
|
args: {
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
description: "Competition code (AFLM or AFLW)",
|
|
3871
|
-
default: "AFLM"
|
|
3872
|
-
},
|
|
3873
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
3874
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
3875
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
3876
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4174
|
+
...SEASON_FLAG,
|
|
4175
|
+
...ROUND_FLAG,
|
|
4176
|
+
...SOURCE_FLAG,
|
|
4177
|
+
...COMPETITION_FLAG,
|
|
4178
|
+
...OUTPUT_FLAGS
|
|
3877
4179
|
},
|
|
3878
|
-
async
|
|
4180
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
3879
4181
|
const season = validateSeason(args.season);
|
|
3880
4182
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
3881
4183
|
const source = validateSource(args.source);
|
|
@@ -3898,8 +4200,205 @@ var init_matches = __esm({
|
|
|
3898
4200
|
columns: DEFAULT_COLUMNS
|
|
3899
4201
|
};
|
|
3900
4202
|
console.log(formatOutput(data, formatOptions));
|
|
3901
|
-
}
|
|
4203
|
+
})
|
|
4204
|
+
});
|
|
4205
|
+
}
|
|
4206
|
+
});
|
|
4207
|
+
|
|
4208
|
+
// src/lib/fuzzy.ts
|
|
4209
|
+
function levenshteinDistance(a, b) {
|
|
4210
|
+
const la = a.length;
|
|
4211
|
+
const lb = b.length;
|
|
4212
|
+
if (la === 0) return lb;
|
|
4213
|
+
if (lb === 0) return la;
|
|
4214
|
+
if (la < lb) return levenshteinDistance(b, a);
|
|
4215
|
+
const row = Array.from({ length: lb + 1 }, (_, i) => i);
|
|
4216
|
+
for (let i = 1; i <= la; i++) {
|
|
4217
|
+
let prev = i;
|
|
4218
|
+
for (let j = 1; j <= lb; j++) {
|
|
4219
|
+
const current = row[j - 1];
|
|
4220
|
+
const rowJ = row[j];
|
|
4221
|
+
if (current === void 0 || rowJ === void 0) continue;
|
|
4222
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
4223
|
+
const val = Math.min(rowJ + 1, prev + 1, current + cost);
|
|
4224
|
+
row[j - 1] = prev;
|
|
4225
|
+
prev = val;
|
|
4226
|
+
}
|
|
4227
|
+
row[lb] = prev;
|
|
4228
|
+
}
|
|
4229
|
+
return row[lb] ?? 0;
|
|
4230
|
+
}
|
|
4231
|
+
function fuzzySearch(query, candidates, keySelector, options) {
|
|
4232
|
+
const maxResults = options?.maxResults ?? 10;
|
|
4233
|
+
const threshold = options?.threshold ?? 0.4;
|
|
4234
|
+
const lowerQuery = query.toLowerCase();
|
|
4235
|
+
const results = [];
|
|
4236
|
+
for (const item of candidates) {
|
|
4237
|
+
const key = keySelector(item).toLowerCase();
|
|
4238
|
+
if (key === lowerQuery) {
|
|
4239
|
+
results.push({ item, score: 0 });
|
|
4240
|
+
continue;
|
|
4241
|
+
}
|
|
4242
|
+
if (key.startsWith(lowerQuery)) {
|
|
4243
|
+
results.push({ item, score: 0.1 });
|
|
4244
|
+
continue;
|
|
4245
|
+
}
|
|
4246
|
+
if (key.includes(lowerQuery)) {
|
|
4247
|
+
results.push({ item, score: 0.3 });
|
|
4248
|
+
continue;
|
|
4249
|
+
}
|
|
4250
|
+
const maxLen = Math.max(lowerQuery.length, key.length);
|
|
4251
|
+
if (maxLen === 0) continue;
|
|
4252
|
+
const distance = levenshteinDistance(lowerQuery, key);
|
|
4253
|
+
const normalised = distance / maxLen;
|
|
4254
|
+
if (normalised <= threshold) {
|
|
4255
|
+
const score = 0.4 + normalised / threshold * 0.6;
|
|
4256
|
+
results.push({ item, score });
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
results.sort((a, b) => {
|
|
4260
|
+
if (a.score !== b.score) return a.score - b.score;
|
|
4261
|
+
return keySelector(a.item).localeCompare(keySelector(b.item));
|
|
4262
|
+
});
|
|
4263
|
+
return results.slice(0, maxResults);
|
|
4264
|
+
}
|
|
4265
|
+
var init_fuzzy = __esm({
|
|
4266
|
+
"src/lib/fuzzy.ts"() {
|
|
4267
|
+
"use strict";
|
|
4268
|
+
}
|
|
4269
|
+
});
|
|
4270
|
+
|
|
4271
|
+
// src/cli/resolvers.ts
|
|
4272
|
+
import { isCancel, select } from "@clack/prompts";
|
|
4273
|
+
async function resolveTeamOrPrompt(query, teams) {
|
|
4274
|
+
try {
|
|
4275
|
+
return resolveTeamIdentifier(query, teams);
|
|
4276
|
+
} catch {
|
|
4277
|
+
}
|
|
4278
|
+
const matches = fuzzySearch(query.trim(), teams, (t) => t.name, {
|
|
4279
|
+
maxResults: 5,
|
|
4280
|
+
threshold: 0.4
|
|
4281
|
+
});
|
|
4282
|
+
const abbrevMatches = fuzzySearch(query.trim(), teams, (t) => t.abbreviation, {
|
|
4283
|
+
maxResults: 5,
|
|
4284
|
+
threshold: 0.4
|
|
4285
|
+
});
|
|
4286
|
+
const seen = new Set(matches.map((m) => m.item.teamId));
|
|
4287
|
+
for (const m of abbrevMatches) {
|
|
4288
|
+
if (!seen.has(m.item.teamId)) {
|
|
4289
|
+
matches.push(m);
|
|
4290
|
+
seen.add(m.item.teamId);
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
matches.sort((a, b) => a.score - b.score);
|
|
4294
|
+
return disambiguate(
|
|
4295
|
+
query.trim(),
|
|
4296
|
+
matches.map((m) => ({ value: m.item.teamId, label: m.item.name, score: m.score })),
|
|
4297
|
+
teams.map((t) => `${t.name} (${t.abbreviation})`),
|
|
4298
|
+
"team"
|
|
4299
|
+
);
|
|
4300
|
+
}
|
|
4301
|
+
async function resolveTeamNameOrPrompt(query, teamNames) {
|
|
4302
|
+
const trimmed = query.trim();
|
|
4303
|
+
const canonical = normaliseTeamName(trimmed);
|
|
4304
|
+
const candidates = teamNames ?? [...AFL_SENIOR_TEAMS];
|
|
4305
|
+
if (candidates.includes(canonical)) {
|
|
4306
|
+
return canonical;
|
|
4307
|
+
}
|
|
4308
|
+
const items = candidates.map((name) => ({ name }));
|
|
4309
|
+
const matches = fuzzySearch(trimmed, items, (t) => t.name, {
|
|
4310
|
+
maxResults: 5,
|
|
4311
|
+
threshold: 0.4
|
|
4312
|
+
});
|
|
4313
|
+
return disambiguate(
|
|
4314
|
+
trimmed,
|
|
4315
|
+
matches.map((m) => ({ value: m.item.name, label: m.item.name, score: m.score })),
|
|
4316
|
+
candidates,
|
|
4317
|
+
"team"
|
|
4318
|
+
);
|
|
4319
|
+
}
|
|
4320
|
+
async function resolveMatchOrPrompt(query, matchItems) {
|
|
4321
|
+
try {
|
|
4322
|
+
return resolveMatchByTeam(query, matchItems);
|
|
4323
|
+
} catch {
|
|
4324
|
+
}
|
|
4325
|
+
const labelledItems = matchItems.map((item) => ({
|
|
4326
|
+
item,
|
|
4327
|
+
label: `${item.match.homeTeam.name} vs ${item.match.awayTeam.name}`
|
|
4328
|
+
}));
|
|
4329
|
+
const matches = fuzzySearch(query, labelledItems, (l) => l.label, {
|
|
4330
|
+
maxResults: 5,
|
|
4331
|
+
threshold: 0.5
|
|
4332
|
+
});
|
|
4333
|
+
const homeMatches = fuzzySearch(query, matchItems, (i) => i.match.homeTeam.name, {
|
|
4334
|
+
maxResults: 5,
|
|
4335
|
+
threshold: 0.4
|
|
4336
|
+
});
|
|
4337
|
+
const awayMatches = fuzzySearch(query, matchItems, (i) => i.match.awayTeam.name, {
|
|
4338
|
+
maxResults: 5,
|
|
4339
|
+
threshold: 0.4
|
|
4340
|
+
});
|
|
4341
|
+
const seen = new Set(matches.map((m) => m.item.item.match.matchId));
|
|
4342
|
+
for (const m of homeMatches) {
|
|
4343
|
+
if (!seen.has(m.item.match.matchId)) {
|
|
4344
|
+
const label = `${m.item.match.homeTeam.name} vs ${m.item.match.awayTeam.name}`;
|
|
4345
|
+
matches.push({ item: { item: m.item, label }, score: m.score });
|
|
4346
|
+
seen.add(m.item.match.matchId);
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
for (const m of awayMatches) {
|
|
4350
|
+
if (!seen.has(m.item.match.matchId)) {
|
|
4351
|
+
const label = `${m.item.match.homeTeam.name} vs ${m.item.match.awayTeam.name}`;
|
|
4352
|
+
matches.push({ item: { item: m.item, label }, score: m.score });
|
|
4353
|
+
seen.add(m.item.match.matchId);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
matches.sort((a, b) => a.score - b.score);
|
|
4357
|
+
const available = matchItems.map(
|
|
4358
|
+
(item) => `${item.match.homeTeam.name} vs ${item.match.awayTeam.name}`
|
|
4359
|
+
);
|
|
4360
|
+
return disambiguate(
|
|
4361
|
+
query,
|
|
4362
|
+
matches.map((m) => ({
|
|
4363
|
+
value: m.item.item.match.matchId,
|
|
4364
|
+
label: m.item.label,
|
|
4365
|
+
score: m.score
|
|
4366
|
+
})),
|
|
4367
|
+
available,
|
|
4368
|
+
"match"
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
async function disambiguate(query, options, allLabels, entityName) {
|
|
4372
|
+
const best = options[0];
|
|
4373
|
+
if (!best) {
|
|
4374
|
+
throw new Error(
|
|
4375
|
+
`No ${entityName} found for "${query}". Valid options: ${allLabels.join(", ")}`
|
|
4376
|
+
);
|
|
4377
|
+
}
|
|
4378
|
+
if (best.score < 0.2 || options.length === 1) {
|
|
4379
|
+
return best.value;
|
|
4380
|
+
}
|
|
4381
|
+
if (isTTY2) {
|
|
4382
|
+
const choice = await select({
|
|
4383
|
+
message: `Multiple ${entityName}s matched "${query}". Which did you mean?`,
|
|
4384
|
+
options: options.map((o) => ({ value: o.value, label: o.label }))
|
|
3902
4385
|
});
|
|
4386
|
+
if (isCancel(choice)) {
|
|
4387
|
+
process.exit(0);
|
|
4388
|
+
}
|
|
4389
|
+
return choice;
|
|
4390
|
+
}
|
|
4391
|
+
console.error(`Matched "${query}" \u2192 ${best.label}`);
|
|
4392
|
+
return best.value;
|
|
4393
|
+
}
|
|
4394
|
+
var isTTY2;
|
|
4395
|
+
var init_resolvers = __esm({
|
|
4396
|
+
"src/cli/resolvers.ts"() {
|
|
4397
|
+
"use strict";
|
|
4398
|
+
init_fuzzy();
|
|
4399
|
+
init_team_mapping();
|
|
4400
|
+
init_validation2();
|
|
4401
|
+
isTTY2 = process.stdout.isTTY === true;
|
|
3903
4402
|
}
|
|
3904
4403
|
});
|
|
3905
4404
|
|
|
@@ -3914,7 +4413,12 @@ var init_stats = __esm({
|
|
|
3914
4413
|
"src/cli/commands/stats.ts"() {
|
|
3915
4414
|
"use strict";
|
|
3916
4415
|
init_index();
|
|
4416
|
+
init_fuzzy();
|
|
4417
|
+
init_afl_api();
|
|
4418
|
+
init_error_boundary();
|
|
4419
|
+
init_flags();
|
|
3917
4420
|
init_formatters();
|
|
4421
|
+
init_resolvers();
|
|
3918
4422
|
init_ui();
|
|
3919
4423
|
init_validation2();
|
|
3920
4424
|
DEFAULT_COLUMNS2 = [
|
|
@@ -3932,27 +4436,32 @@ var init_stats = __esm({
|
|
|
3932
4436
|
description: "Fetch player statistics for a season"
|
|
3933
4437
|
},
|
|
3934
4438
|
args: {
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
},
|
|
3944
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
3945
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
3946
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
3947
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4439
|
+
...SEASON_FLAG,
|
|
4440
|
+
...ROUND_FLAG,
|
|
4441
|
+
match: { type: "string", description: "Filter by team name to find a specific match" },
|
|
4442
|
+
"match-id": { type: "string", description: "Specific match provider ID (advanced)" },
|
|
4443
|
+
...SOURCE_FLAG,
|
|
4444
|
+
...COMPETITION_FLAG,
|
|
4445
|
+
...PLAYER_FLAG,
|
|
4446
|
+
...OUTPUT_FLAGS
|
|
3948
4447
|
},
|
|
3949
|
-
async
|
|
4448
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
3950
4449
|
const season = validateSeason(args.season);
|
|
3951
4450
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
3952
|
-
const matchId = args["match-id"];
|
|
3953
4451
|
const source = validateSource(args.source);
|
|
3954
4452
|
const competition = validateCompetition(args.competition);
|
|
3955
4453
|
const format = validateFormat(args.format);
|
|
4454
|
+
let matchId = args["match-id"];
|
|
4455
|
+
if (!matchId && args.match && round != null) {
|
|
4456
|
+
const client = new AflApiClient();
|
|
4457
|
+
const seasonResult = await client.resolveCompSeason(competition, season);
|
|
4458
|
+
if (!seasonResult.success) throw seasonResult.error;
|
|
4459
|
+
const itemsResult = await client.fetchRoundMatchItemsByNumber(seasonResult.data, round);
|
|
4460
|
+
if (!itemsResult.success) throw itemsResult.error;
|
|
4461
|
+
matchId = await resolveMatchOrPrompt(args.match, itemsResult.data);
|
|
4462
|
+
} else if (args.match && round == null) {
|
|
4463
|
+
throw new Error("--match requires --round (-r) to identify which round to search.");
|
|
4464
|
+
}
|
|
3956
4465
|
const result = await withSpinner(
|
|
3957
4466
|
"Fetching player stats\u2026",
|
|
3958
4467
|
() => fetchPlayerStats({ source, season, round, matchId, competition })
|
|
@@ -3960,7 +4469,14 @@ var init_stats = __esm({
|
|
|
3960
4469
|
if (!result.success) {
|
|
3961
4470
|
throw result.error;
|
|
3962
4471
|
}
|
|
3963
|
-
|
|
4472
|
+
let data = result.data;
|
|
4473
|
+
if (args.player) {
|
|
4474
|
+
const playerMatches = fuzzySearch(args.player, data, (p) => p.displayName, {
|
|
4475
|
+
maxResults: 50,
|
|
4476
|
+
threshold: 0.4
|
|
4477
|
+
});
|
|
4478
|
+
data = playerMatches.map((m) => m.item);
|
|
4479
|
+
}
|
|
3964
4480
|
showSummary(
|
|
3965
4481
|
`Loaded ${data.length} player stat lines for ${season}${round ? ` round ${round}` : ""}`
|
|
3966
4482
|
);
|
|
@@ -3972,7 +4488,7 @@ var init_stats = __esm({
|
|
|
3972
4488
|
columns: DEFAULT_COLUMNS2
|
|
3973
4489
|
};
|
|
3974
4490
|
console.log(formatOutput(data, formatOptions));
|
|
3975
|
-
}
|
|
4491
|
+
})
|
|
3976
4492
|
});
|
|
3977
4493
|
}
|
|
3978
4494
|
});
|
|
@@ -3988,6 +4504,8 @@ var init_fixture2 = __esm({
|
|
|
3988
4504
|
"src/cli/commands/fixture.ts"() {
|
|
3989
4505
|
"use strict";
|
|
3990
4506
|
init_index();
|
|
4507
|
+
init_error_boundary();
|
|
4508
|
+
init_flags();
|
|
3991
4509
|
init_formatters();
|
|
3992
4510
|
init_ui();
|
|
3993
4511
|
init_validation2();
|
|
@@ -4004,20 +4522,13 @@ var init_fixture2 = __esm({
|
|
|
4004
4522
|
description: "Fetch fixture/schedule for a season"
|
|
4005
4523
|
},
|
|
4006
4524
|
args: {
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
description: "Competition code (AFLM or AFLW)",
|
|
4013
|
-
default: "AFLM"
|
|
4014
|
-
},
|
|
4015
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
4016
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4017
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4018
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4525
|
+
...SEASON_FLAG,
|
|
4526
|
+
...ROUND_FLAG,
|
|
4527
|
+
...SOURCE_FLAG,
|
|
4528
|
+
...COMPETITION_FLAG,
|
|
4529
|
+
...OUTPUT_FLAGS
|
|
4019
4530
|
},
|
|
4020
|
-
async
|
|
4531
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4021
4532
|
const season = validateSeason(args.season);
|
|
4022
4533
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4023
4534
|
const source = validateSource(args.source);
|
|
@@ -4040,7 +4551,7 @@ var init_fixture2 = __esm({
|
|
|
4040
4551
|
columns: DEFAULT_COLUMNS3
|
|
4041
4552
|
};
|
|
4042
4553
|
console.log(formatOutput(data, formatOptions));
|
|
4043
|
-
}
|
|
4554
|
+
})
|
|
4044
4555
|
});
|
|
4045
4556
|
}
|
|
4046
4557
|
});
|
|
@@ -4056,6 +4567,8 @@ var init_ladder3 = __esm({
|
|
|
4056
4567
|
"src/cli/commands/ladder.ts"() {
|
|
4057
4568
|
"use strict";
|
|
4058
4569
|
init_index();
|
|
4570
|
+
init_error_boundary();
|
|
4571
|
+
init_flags();
|
|
4059
4572
|
init_formatters();
|
|
4060
4573
|
init_ui();
|
|
4061
4574
|
init_validation2();
|
|
@@ -4074,20 +4587,13 @@ var init_ladder3 = __esm({
|
|
|
4074
4587
|
description: "Fetch ladder standings for a season"
|
|
4075
4588
|
},
|
|
4076
4589
|
args: {
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
description: "Competition code (AFLM or AFLW)",
|
|
4083
|
-
default: "AFLM"
|
|
4084
|
-
},
|
|
4085
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
4086
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4087
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4088
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4590
|
+
...SEASON_FLAG,
|
|
4591
|
+
...ROUND_FLAG,
|
|
4592
|
+
...SOURCE_FLAG,
|
|
4593
|
+
...COMPETITION_FLAG,
|
|
4594
|
+
...OUTPUT_FLAGS
|
|
4089
4595
|
},
|
|
4090
|
-
async
|
|
4596
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4091
4597
|
const season = validateSeason(args.season);
|
|
4092
4598
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4093
4599
|
const source = validateSource(args.source);
|
|
@@ -4112,7 +4618,7 @@ var init_ladder3 = __esm({
|
|
|
4112
4618
|
columns: DEFAULT_COLUMNS4
|
|
4113
4619
|
};
|
|
4114
4620
|
console.log(formatOutput(data.entries, formatOptions));
|
|
4115
|
-
}
|
|
4621
|
+
})
|
|
4116
4622
|
});
|
|
4117
4623
|
}
|
|
4118
4624
|
});
|
|
@@ -4150,7 +4656,11 @@ var init_lineup3 = __esm({
|
|
|
4150
4656
|
"src/cli/commands/lineup.ts"() {
|
|
4151
4657
|
"use strict";
|
|
4152
4658
|
init_index();
|
|
4659
|
+
init_afl_api();
|
|
4660
|
+
init_error_boundary();
|
|
4661
|
+
init_flags();
|
|
4153
4662
|
init_formatters();
|
|
4663
|
+
init_resolvers();
|
|
4154
4664
|
init_ui();
|
|
4155
4665
|
init_validation2();
|
|
4156
4666
|
DEFAULT_COLUMNS5 = [
|
|
@@ -4166,27 +4676,29 @@ var init_lineup3 = __esm({
|
|
|
4166
4676
|
description: "Fetch match lineups for a round"
|
|
4167
4677
|
},
|
|
4168
4678
|
args: {
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
default: "AFLM"
|
|
4177
|
-
},
|
|
4178
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
4179
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4180
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4181
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4679
|
+
...SEASON_FLAG,
|
|
4680
|
+
...REQUIRED_ROUND_FLAG,
|
|
4681
|
+
match: { type: "string", description: "Filter by team name to find a specific match" },
|
|
4682
|
+
"match-id": { type: "string", description: "Specific match provider ID (advanced)" },
|
|
4683
|
+
...SOURCE_FLAG,
|
|
4684
|
+
...COMPETITION_FLAG,
|
|
4685
|
+
...OUTPUT_FLAGS
|
|
4182
4686
|
},
|
|
4183
|
-
async
|
|
4687
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4184
4688
|
const season = validateSeason(args.season);
|
|
4185
4689
|
const round = validateRound(args.round);
|
|
4186
|
-
const matchId = args["match-id"];
|
|
4187
4690
|
const source = validateSource(args.source);
|
|
4188
4691
|
const competition = validateCompetition(args.competition);
|
|
4189
4692
|
const format = validateFormat(args.format);
|
|
4693
|
+
let matchId = args["match-id"];
|
|
4694
|
+
if (!matchId && args.match) {
|
|
4695
|
+
const client = new AflApiClient();
|
|
4696
|
+
const seasonResult = await client.resolveCompSeason(competition, season);
|
|
4697
|
+
if (!seasonResult.success) throw seasonResult.error;
|
|
4698
|
+
const itemsResult = await client.fetchRoundMatchItemsByNumber(seasonResult.data, round);
|
|
4699
|
+
if (!itemsResult.success) throw itemsResult.error;
|
|
4700
|
+
matchId = await resolveMatchOrPrompt(args.match, itemsResult.data);
|
|
4701
|
+
}
|
|
4190
4702
|
const result = await withSpinner(
|
|
4191
4703
|
"Fetching lineups\u2026",
|
|
4192
4704
|
() => fetchLineup({ source, season, round, matchId, competition })
|
|
@@ -4209,7 +4721,7 @@ var init_lineup3 = __esm({
|
|
|
4209
4721
|
} else {
|
|
4210
4722
|
console.log(formatOutput(flattenLineups(data), formatOptions));
|
|
4211
4723
|
}
|
|
4212
|
-
}
|
|
4724
|
+
})
|
|
4213
4725
|
});
|
|
4214
4726
|
}
|
|
4215
4727
|
});
|
|
@@ -4225,7 +4737,10 @@ var init_squad = __esm({
|
|
|
4225
4737
|
"src/cli/commands/squad.ts"() {
|
|
4226
4738
|
"use strict";
|
|
4227
4739
|
init_index();
|
|
4740
|
+
init_error_boundary();
|
|
4741
|
+
init_flags();
|
|
4228
4742
|
init_formatters();
|
|
4743
|
+
init_resolvers();
|
|
4229
4744
|
init_ui();
|
|
4230
4745
|
init_validation2();
|
|
4231
4746
|
DEFAULT_COLUMNS6 = [
|
|
@@ -4241,34 +4756,22 @@ var init_squad = __esm({
|
|
|
4241
4756
|
description: "Fetch team squad for a season"
|
|
4242
4757
|
},
|
|
4243
4758
|
args: {
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
},
|
|
4249
|
-
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
4250
|
-
competition: {
|
|
4251
|
-
type: "string",
|
|
4252
|
-
description: "Competition code (AFLM or AFLW)",
|
|
4253
|
-
default: "AFLM"
|
|
4254
|
-
},
|
|
4255
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
4256
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4257
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4258
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4759
|
+
...REQUIRED_TEAM_FLAG,
|
|
4760
|
+
...SEASON_FLAG,
|
|
4761
|
+
...COMPETITION_FLAG,
|
|
4762
|
+
...OUTPUT_FLAGS
|
|
4259
4763
|
},
|
|
4260
|
-
async
|
|
4764
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4261
4765
|
const season = validateSeason(args.season);
|
|
4262
4766
|
const competition = validateCompetition(args.competition);
|
|
4263
4767
|
const format = validateFormat(args.format);
|
|
4264
|
-
let teamId = args
|
|
4265
|
-
|
|
4266
|
-
if (!isNumeric) {
|
|
4768
|
+
let teamId = args.team.trim();
|
|
4769
|
+
if (!/^\d+$/.test(teamId)) {
|
|
4267
4770
|
const teamsResult = await withSpinner("Resolving team\u2026", () => fetchTeams({ competition }));
|
|
4268
4771
|
if (!teamsResult.success) {
|
|
4269
4772
|
throw teamsResult.error;
|
|
4270
4773
|
}
|
|
4271
|
-
teamId =
|
|
4774
|
+
teamId = await resolveTeamOrPrompt(args.team, teamsResult.data);
|
|
4272
4775
|
}
|
|
4273
4776
|
const result = await withSpinner(
|
|
4274
4777
|
"Fetching squad\u2026",
|
|
@@ -4287,7 +4790,7 @@ var init_squad = __esm({
|
|
|
4287
4790
|
columns: DEFAULT_COLUMNS6
|
|
4288
4791
|
};
|
|
4289
4792
|
console.log(formatOutput(data.players, formatOptions));
|
|
4290
|
-
}
|
|
4793
|
+
})
|
|
4291
4794
|
});
|
|
4292
4795
|
}
|
|
4293
4796
|
});
|
|
@@ -4303,6 +4806,8 @@ var init_teams2 = __esm({
|
|
|
4303
4806
|
"src/cli/commands/teams.ts"() {
|
|
4304
4807
|
"use strict";
|
|
4305
4808
|
init_index();
|
|
4809
|
+
init_error_boundary();
|
|
4810
|
+
init_flags();
|
|
4306
4811
|
init_formatters();
|
|
4307
4812
|
init_ui();
|
|
4308
4813
|
init_validation2();
|
|
@@ -4318,14 +4823,11 @@ var init_teams2 = __esm({
|
|
|
4318
4823
|
description: "Fetch team list"
|
|
4319
4824
|
},
|
|
4320
4825
|
args: {
|
|
4321
|
-
|
|
4826
|
+
...OPTIONAL_COMPETITION_FLAG,
|
|
4322
4827
|
"team-type": { type: "string", description: "Team type filter" },
|
|
4323
|
-
|
|
4324
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4325
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4326
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4828
|
+
...OUTPUT_FLAGS
|
|
4327
4829
|
},
|
|
4328
|
-
async
|
|
4830
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4329
4831
|
const competition = validateOptionalCompetition(args.competition);
|
|
4330
4832
|
const format = validateFormat(args.format);
|
|
4331
4833
|
const result = await withSpinner(
|
|
@@ -4350,7 +4852,7 @@ var init_teams2 = __esm({
|
|
|
4350
4852
|
columns: DEFAULT_COLUMNS7
|
|
4351
4853
|
};
|
|
4352
4854
|
console.log(formatOutput(data, formatOptions));
|
|
4353
|
-
}
|
|
4855
|
+
})
|
|
4354
4856
|
});
|
|
4355
4857
|
}
|
|
4356
4858
|
});
|
|
@@ -4364,14 +4866,20 @@ import { defineCommand as defineCommand8 } from "citty";
|
|
|
4364
4866
|
function flattenEntries(data) {
|
|
4365
4867
|
return data.map((entry) => {
|
|
4366
4868
|
const { stats, ...rest } = entry;
|
|
4367
|
-
|
|
4869
|
+
const normalised = {};
|
|
4870
|
+
for (const [key, value] of Object.entries(stats)) {
|
|
4871
|
+
normalised[AFL_TABLES_KEY_MAP[key] ?? key] = value;
|
|
4872
|
+
}
|
|
4873
|
+
return { ...rest, ...normalised };
|
|
4368
4874
|
});
|
|
4369
4875
|
}
|
|
4370
|
-
var DEFAULT_COLUMNS8, teamStatsCommand;
|
|
4876
|
+
var DEFAULT_COLUMNS8, AFL_TABLES_KEY_MAP, teamStatsCommand;
|
|
4371
4877
|
var init_team_stats2 = __esm({
|
|
4372
4878
|
"src/cli/commands/team-stats.ts"() {
|
|
4373
4879
|
"use strict";
|
|
4374
4880
|
init_index();
|
|
4881
|
+
init_error_boundary();
|
|
4882
|
+
init_flags();
|
|
4375
4883
|
init_formatters();
|
|
4376
4884
|
init_ui();
|
|
4377
4885
|
init_validation2();
|
|
@@ -4387,25 +4895,69 @@ var init_team_stats2 = __esm({
|
|
|
4387
4895
|
{ key: "T", label: "T", maxWidth: 6 },
|
|
4388
4896
|
{ key: "I50", label: "I50", maxWidth: 6 }
|
|
4389
4897
|
];
|
|
4898
|
+
AFL_TABLES_KEY_MAP = {
|
|
4899
|
+
KI_for: "K",
|
|
4900
|
+
MK_for: "M",
|
|
4901
|
+
HB_for: "HB",
|
|
4902
|
+
DI_for: "D",
|
|
4903
|
+
GL_for: "G",
|
|
4904
|
+
BH_for: "B",
|
|
4905
|
+
HO_for: "HO",
|
|
4906
|
+
TK_for: "T",
|
|
4907
|
+
RB_for: "RB",
|
|
4908
|
+
IF_for: "IF",
|
|
4909
|
+
CL_for: "CL",
|
|
4910
|
+
CG_for: "CG",
|
|
4911
|
+
FF_for: "FF",
|
|
4912
|
+
BR_for: "BR",
|
|
4913
|
+
CP_for: "CP",
|
|
4914
|
+
UP_for: "UP",
|
|
4915
|
+
CM_for: "CM",
|
|
4916
|
+
MI_for: "MI",
|
|
4917
|
+
"1%_for": "1%",
|
|
4918
|
+
BO_for: "BO",
|
|
4919
|
+
GA_for: "GA",
|
|
4920
|
+
I50_for: "I50",
|
|
4921
|
+
// "against" variants
|
|
4922
|
+
KI_against: "K_against",
|
|
4923
|
+
MK_against: "M_against",
|
|
4924
|
+
HB_against: "HB_against",
|
|
4925
|
+
DI_against: "D_against",
|
|
4926
|
+
GL_against: "G_against",
|
|
4927
|
+
BH_against: "B_against",
|
|
4928
|
+
HO_against: "HO_against",
|
|
4929
|
+
TK_against: "T_against",
|
|
4930
|
+
RB_against: "RB_against",
|
|
4931
|
+
IF_against: "IF_against",
|
|
4932
|
+
CL_against: "CL_against",
|
|
4933
|
+
CG_against: "CG_against",
|
|
4934
|
+
FF_against: "FF_against",
|
|
4935
|
+
BR_against: "BR_against",
|
|
4936
|
+
CP_against: "CP_against",
|
|
4937
|
+
UP_against: "UP_against",
|
|
4938
|
+
CM_against: "CM_against",
|
|
4939
|
+
MI_against: "MI_against",
|
|
4940
|
+
"1%_against": "1%_against",
|
|
4941
|
+
BO_against: "BO_against",
|
|
4942
|
+
GA_against: "GA_against",
|
|
4943
|
+
I50_against: "I50_against"
|
|
4944
|
+
};
|
|
4390
4945
|
teamStatsCommand = defineCommand8({
|
|
4391
4946
|
meta: {
|
|
4392
4947
|
name: "team-stats",
|
|
4393
4948
|
description: "Fetch team aggregate statistics for a season"
|
|
4394
4949
|
},
|
|
4395
4950
|
args: {
|
|
4396
|
-
|
|
4951
|
+
...SEASON_FLAG,
|
|
4397
4952
|
source: {
|
|
4398
4953
|
type: "string",
|
|
4399
4954
|
description: "Data source (footywire, afl-tables)",
|
|
4400
4955
|
default: "footywire"
|
|
4401
4956
|
},
|
|
4402
4957
|
summary: { type: "string", description: "Summary type: totals or averages", default: "totals" },
|
|
4403
|
-
|
|
4404
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4405
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4406
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
4958
|
+
...OUTPUT_FLAGS
|
|
4407
4959
|
},
|
|
4408
|
-
async
|
|
4960
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4409
4961
|
const season = validateSeason(args.season);
|
|
4410
4962
|
const source = validateSource(args.source);
|
|
4411
4963
|
const format = validateFormat(args.format);
|
|
@@ -4428,7 +4980,7 @@ var init_team_stats2 = __esm({
|
|
|
4428
4980
|
columns: DEFAULT_COLUMNS8
|
|
4429
4981
|
};
|
|
4430
4982
|
console.log(formatOutput(flat, formatOptions));
|
|
4431
|
-
}
|
|
4983
|
+
})
|
|
4432
4984
|
});
|
|
4433
4985
|
}
|
|
4434
4986
|
});
|
|
@@ -4444,7 +4996,10 @@ var init_player_details2 = __esm({
|
|
|
4444
4996
|
"src/cli/commands/player-details.ts"() {
|
|
4445
4997
|
"use strict";
|
|
4446
4998
|
init_index();
|
|
4999
|
+
init_error_boundary();
|
|
5000
|
+
init_flags();
|
|
4447
5001
|
init_formatters();
|
|
5002
|
+
init_resolvers();
|
|
4448
5003
|
init_ui();
|
|
4449
5004
|
init_validation2();
|
|
4450
5005
|
DEFAULT_COLUMNS9 = [
|
|
@@ -4462,37 +5017,31 @@ var init_player_details2 = __esm({
|
|
|
4462
5017
|
description: "Fetch player biographical details for a team"
|
|
4463
5018
|
},
|
|
4464
5019
|
args: {
|
|
4465
|
-
|
|
5020
|
+
...REQUIRED_TEAM_FLAG,
|
|
4466
5021
|
source: {
|
|
4467
5022
|
type: "string",
|
|
4468
5023
|
description: "Data source: afl-api, footywire, afl-tables",
|
|
4469
5024
|
default: "afl-api"
|
|
4470
5025
|
},
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
description: "Competition code (AFLM or AFLW)",
|
|
4475
|
-
default: "AFLM"
|
|
4476
|
-
},
|
|
4477
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
4478
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4479
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4480
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
5026
|
+
...OPTIONAL_SEASON_FLAG,
|
|
5027
|
+
...COMPETITION_FLAG,
|
|
5028
|
+
...OUTPUT_FLAGS
|
|
4481
5029
|
},
|
|
4482
|
-
async
|
|
5030
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4483
5031
|
const source = validateSource(args.source);
|
|
4484
5032
|
const competition = validateCompetition(args.competition);
|
|
4485
5033
|
const format = validateFormat(args.format);
|
|
4486
5034
|
const season = validateOptionalSeason(args.season) ?? resolveDefaultSeason(competition);
|
|
5035
|
+
const team = await resolveTeamNameOrPrompt(args.team);
|
|
4487
5036
|
const result = await withSpinner(
|
|
4488
5037
|
"Fetching player details\u2026",
|
|
4489
|
-
() => fetchPlayerDetails({ source, team
|
|
5038
|
+
() => fetchPlayerDetails({ source, team, season, competition })
|
|
4490
5039
|
);
|
|
4491
5040
|
if (!result.success) {
|
|
4492
5041
|
throw result.error;
|
|
4493
5042
|
}
|
|
4494
5043
|
const data = result.data;
|
|
4495
|
-
showSummary(`Loaded ${data.length} players for ${
|
|
5044
|
+
showSummary(`Loaded ${data.length} players for ${team} (${source})`);
|
|
4496
5045
|
const formatOptions = {
|
|
4497
5046
|
json: args.json,
|
|
4498
5047
|
csv: args.csv,
|
|
@@ -4501,7 +5050,7 @@ var init_player_details2 = __esm({
|
|
|
4501
5050
|
columns: DEFAULT_COLUMNS9
|
|
4502
5051
|
};
|
|
4503
5052
|
console.log(formatOutput(data, formatOptions));
|
|
4504
|
-
}
|
|
5053
|
+
})
|
|
4505
5054
|
});
|
|
4506
5055
|
}
|
|
4507
5056
|
});
|
|
@@ -4517,7 +5066,10 @@ var init_coaches_votes2 = __esm({
|
|
|
4517
5066
|
"src/cli/commands/coaches-votes.ts"() {
|
|
4518
5067
|
"use strict";
|
|
4519
5068
|
init_index();
|
|
5069
|
+
init_error_boundary();
|
|
5070
|
+
init_flags();
|
|
4520
5071
|
init_formatters();
|
|
5072
|
+
init_resolvers();
|
|
4521
5073
|
init_ui();
|
|
4522
5074
|
init_validation2();
|
|
4523
5075
|
DEFAULT_COLUMNS10 = [
|
|
@@ -4534,33 +5086,27 @@ var init_coaches_votes2 = __esm({
|
|
|
4534
5086
|
description: "Fetch AFLCA coaches votes for a season"
|
|
4535
5087
|
},
|
|
4536
5088
|
args: {
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
default: "AFLM"
|
|
4543
|
-
},
|
|
4544
|
-
team: { type: "string", description: "Filter by team name" },
|
|
4545
|
-
json: { type: "boolean", description: "Output as JSON" },
|
|
4546
|
-
csv: { type: "boolean", description: "Output as CSV" },
|
|
4547
|
-
format: { type: "string", description: "Output format: table, json, csv" },
|
|
4548
|
-
full: { type: "boolean", description: "Show all columns in table output" }
|
|
5089
|
+
...SEASON_FLAG,
|
|
5090
|
+
...ROUND_FLAG,
|
|
5091
|
+
...COMPETITION_FLAG,
|
|
5092
|
+
...TEAM_FLAG,
|
|
5093
|
+
...OUTPUT_FLAGS
|
|
4549
5094
|
},
|
|
4550
|
-
async
|
|
5095
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4551
5096
|
const season = validateSeason(args.season);
|
|
4552
5097
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4553
5098
|
const competition = validateCompetition(args.competition);
|
|
4554
5099
|
const format = validateFormat(args.format);
|
|
5100
|
+
const team = args.team ? await resolveTeamNameOrPrompt(args.team) : void 0;
|
|
4555
5101
|
const result = await withSpinner(
|
|
4556
5102
|
"Fetching coaches votes\u2026",
|
|
4557
|
-
() => fetchCoachesVotes({ season, round, competition, team
|
|
5103
|
+
() => fetchCoachesVotes({ season, round, competition, team })
|
|
4558
5104
|
);
|
|
4559
5105
|
if (!result.success) {
|
|
4560
5106
|
throw result.error;
|
|
4561
5107
|
}
|
|
4562
5108
|
const data = result.data;
|
|
4563
|
-
const teamSuffix =
|
|
5109
|
+
const teamSuffix = team ? ` for ${team}` : "";
|
|
4564
5110
|
const roundSuffix = round ? ` round ${round}` : "";
|
|
4565
5111
|
showSummary(`Loaded ${data.length} vote records for ${season}${roundSuffix}${teamSuffix}`);
|
|
4566
5112
|
const formatOptions = {
|
|
@@ -4571,7 +5117,7 @@ var init_coaches_votes2 = __esm({
|
|
|
4571
5117
|
columns: DEFAULT_COLUMNS10
|
|
4572
5118
|
};
|
|
4573
5119
|
console.log(formatOutput(data, formatOptions));
|
|
4574
|
-
}
|
|
5120
|
+
})
|
|
4575
5121
|
});
|
|
4576
5122
|
}
|
|
4577
5123
|
});
|
|
@@ -4579,37 +5125,34 @@ var init_coaches_votes2 = __esm({
|
|
|
4579
5125
|
// src/cli.ts
|
|
4580
5126
|
import { defineCommand as defineCommand11, runMain } from "citty";
|
|
4581
5127
|
|
|
4582
|
-
// src/cli/
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
return `${pc.red("Unsupported source:")} ${error.message}`;
|
|
4601
|
-
}
|
|
4602
|
-
if (error instanceof Error) {
|
|
4603
|
-
return `${pc.red("Error:")} ${error.message}`;
|
|
5128
|
+
// src/cli/alias-resolution.ts
|
|
5129
|
+
var SHORT_TO_LONG = {
|
|
5130
|
+
"-s": "--season",
|
|
5131
|
+
"-r": "--round",
|
|
5132
|
+
"-c": "--competition",
|
|
5133
|
+
"-j": "--json",
|
|
5134
|
+
"-t": "--team",
|
|
5135
|
+
"-p": "--player"
|
|
5136
|
+
};
|
|
5137
|
+
function resolveAliases() {
|
|
5138
|
+
for (let i = 0; i < process.argv.length; i++) {
|
|
5139
|
+
const arg = process.argv[i];
|
|
5140
|
+
if (arg != null) {
|
|
5141
|
+
const long = SHORT_TO_LONG[arg];
|
|
5142
|
+
if (long) {
|
|
5143
|
+
process.argv[i] = long;
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
4604
5146
|
}
|
|
4605
|
-
return `${pc.red("Error:")} ${String(error)}`;
|
|
4606
5147
|
}
|
|
4607
5148
|
|
|
4608
5149
|
// src/cli.ts
|
|
5150
|
+
init_error_boundary();
|
|
5151
|
+
resolveAliases();
|
|
4609
5152
|
var main = defineCommand11({
|
|
4610
5153
|
meta: {
|
|
4611
5154
|
name: "fitzroy",
|
|
4612
|
-
version: "1.
|
|
5155
|
+
version: "1.3.0",
|
|
4613
5156
|
description: "CLI for fetching AFL data \u2014 match results, player stats, fixtures, ladders, and more"
|
|
4614
5157
|
},
|
|
4615
5158
|
subCommands: {
|