fitzroy 1.2.0 → 1.3.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 +378 -146
- package/dist/index.d.ts +253 -249
- package/dist/index.js +203 -84
- 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
|
}
|
|
@@ -1431,7 +1522,15 @@ var init_validation = __esm({
|
|
|
1431
1522
|
captain: z.boolean().optional(),
|
|
1432
1523
|
playerJumperNumber: z.number().optional()
|
|
1433
1524
|
}).passthrough();
|
|
1434
|
-
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
|
+
z.boolean().transform((b) => b ? 1 : 0)
|
|
1533
|
+
]).nullable().optional();
|
|
1435
1534
|
PlayerGameStatsSchema = z.object({
|
|
1436
1535
|
goals: statNum,
|
|
1437
1536
|
behinds: statNum,
|
|
@@ -1509,8 +1608,8 @@ var init_validation = __esm({
|
|
|
1509
1608
|
teamId: z.string(),
|
|
1510
1609
|
playerStats: z.object({
|
|
1511
1610
|
stats: PlayerGameStatsSchema,
|
|
1512
|
-
timeOnGroundPercentage:
|
|
1513
|
-
}).passthrough()
|
|
1611
|
+
timeOnGroundPercentage: statNum
|
|
1612
|
+
}).passthrough().nullable().optional()
|
|
1514
1613
|
}).passthrough();
|
|
1515
1614
|
PlayerStatsListSchema = z.object({
|
|
1516
1615
|
homeTeamPlayerStats: z.array(PlayerStatsItemSchema),
|
|
@@ -2221,12 +2320,14 @@ function toFixture(item, season, fallbackRoundNumber, competition) {
|
|
|
2221
2320
|
async function fetchFixture(query) {
|
|
2222
2321
|
const competition = query.competition ?? "AFLM";
|
|
2223
2322
|
if (query.source === "squiggle") {
|
|
2323
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("squiggle"));
|
|
2224
2324
|
const client2 = new SquiggleClient();
|
|
2225
2325
|
const result = await client2.fetchGames(query.season, query.round ?? void 0);
|
|
2226
2326
|
if (!result.success) return result;
|
|
2227
2327
|
return ok(transformSquiggleGamesToFixture(result.data.games, query.season));
|
|
2228
2328
|
}
|
|
2229
2329
|
if (query.source === "footywire") {
|
|
2330
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
2230
2331
|
const fwClient = new FootyWireClient();
|
|
2231
2332
|
const result = await fwClient.fetchSeasonFixture(query.season);
|
|
2232
2333
|
if (!result.success) return result;
|
|
@@ -2417,6 +2518,7 @@ function parseSeasonPage(html, year) {
|
|
|
2417
2518
|
const results = [];
|
|
2418
2519
|
let currentRound = 0;
|
|
2419
2520
|
let currentRoundType = "HomeAndAway";
|
|
2521
|
+
let lastHARound = 0;
|
|
2420
2522
|
let matchCounter = 0;
|
|
2421
2523
|
$("table").each((_i, table) => {
|
|
2422
2524
|
const $table = $(table);
|
|
@@ -2426,10 +2528,14 @@ function parseSeasonPage(html, year) {
|
|
|
2426
2528
|
if (roundMatch?.[1] && border !== "1") {
|
|
2427
2529
|
currentRound = Number.parseInt(roundMatch[1], 10);
|
|
2428
2530
|
currentRoundType = inferRoundType(text);
|
|
2531
|
+
if (currentRoundType === "HomeAndAway") {
|
|
2532
|
+
lastHARound = currentRound;
|
|
2533
|
+
}
|
|
2429
2534
|
return;
|
|
2430
2535
|
}
|
|
2431
2536
|
if (border !== "1" && inferRoundType(text) === "Finals") {
|
|
2432
2537
|
currentRoundType = "Finals";
|
|
2538
|
+
currentRound = finalsRoundNumber(text, lastHARound);
|
|
2433
2539
|
return;
|
|
2434
2540
|
}
|
|
2435
2541
|
if (border !== "1") return;
|
|
@@ -2939,6 +3045,7 @@ var init_ladder = __esm({
|
|
|
2939
3045
|
async function fetchLadder(query) {
|
|
2940
3046
|
const competition = query.competition ?? "AFLM";
|
|
2941
3047
|
if (query.source === "squiggle") {
|
|
3048
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("squiggle"));
|
|
2942
3049
|
const client2 = new SquiggleClient();
|
|
2943
3050
|
const result = await client2.fetchStandings(query.season, query.round ?? void 0);
|
|
2944
3051
|
if (!result.success) return result;
|
|
@@ -2950,6 +3057,7 @@ async function fetchLadder(query) {
|
|
|
2950
3057
|
});
|
|
2951
3058
|
}
|
|
2952
3059
|
if (query.source === "afl-tables") {
|
|
3060
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
2953
3061
|
const atClient = new AflTablesClient();
|
|
2954
3062
|
const resultsResult = await atClient.fetchSeasonResults(query.season);
|
|
2955
3063
|
if (!resultsResult.success) return resultsResult;
|
|
@@ -3114,6 +3222,7 @@ async function fetchMatchResults(query) {
|
|
|
3114
3222
|
return ok(transformMatchItems(itemsResult.data, query.season, competition));
|
|
3115
3223
|
}
|
|
3116
3224
|
case "footywire": {
|
|
3225
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
3117
3226
|
const client = new FootyWireClient();
|
|
3118
3227
|
const result = await client.fetchSeasonResults(query.season);
|
|
3119
3228
|
if (!result.success) return result;
|
|
@@ -3123,6 +3232,7 @@ async function fetchMatchResults(query) {
|
|
|
3123
3232
|
return result;
|
|
3124
3233
|
}
|
|
3125
3234
|
case "afl-tables": {
|
|
3235
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
3126
3236
|
const client = new AflTablesClient();
|
|
3127
3237
|
const result = await client.fetchSeasonResults(query.season);
|
|
3128
3238
|
if (!result.success) return result;
|
|
@@ -3132,6 +3242,7 @@ async function fetchMatchResults(query) {
|
|
|
3132
3242
|
return result;
|
|
3133
3243
|
}
|
|
3134
3244
|
case "squiggle": {
|
|
3245
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("squiggle"));
|
|
3135
3246
|
const client = new SquiggleClient();
|
|
3136
3247
|
const result = await client.fetchGames(query.season, query.round ?? void 0, 100);
|
|
3137
3248
|
if (!result.success) return result;
|
|
@@ -3170,7 +3281,7 @@ async function resolveTeamId(client, teamName, competition) {
|
|
|
3170
3281
|
async function fetchFromAflApi(query) {
|
|
3171
3282
|
const client = new AflApiClient();
|
|
3172
3283
|
const competition = query.competition ?? "AFLM";
|
|
3173
|
-
const season = query.season ?? (
|
|
3284
|
+
const season = query.season ?? resolveDefaultSeason(competition);
|
|
3174
3285
|
const [teamIdResult, seasonResult] = await Promise.all([
|
|
3175
3286
|
resolveTeamId(client, query.team, competition),
|
|
3176
3287
|
client.resolveCompSeason(competition, season)
|
|
@@ -3193,8 +3304,8 @@ async function fetchFromAflApi(query) {
|
|
|
3193
3304
|
jumperNumber: p.jumperNumber ?? null,
|
|
3194
3305
|
position: p.position ?? null,
|
|
3195
3306
|
dateOfBirth: p.player.dateOfBirth ?? null,
|
|
3196
|
-
heightCm: p.player.heightInCm
|
|
3197
|
-
weightKg: p.player.weightInKg
|
|
3307
|
+
heightCm: p.player.heightInCm || null,
|
|
3308
|
+
weightKg: p.player.weightInKg || null,
|
|
3198
3309
|
gamesPlayed: null,
|
|
3199
3310
|
goals: null,
|
|
3200
3311
|
draftYear: p.player.draftYear ? Number.parseInt(p.player.draftYear, 10) || null : null,
|
|
@@ -3208,8 +3319,9 @@ async function fetchFromAflApi(query) {
|
|
|
3208
3319
|
return ok(players);
|
|
3209
3320
|
}
|
|
3210
3321
|
async function fetchFromFootyWire(query) {
|
|
3211
|
-
const client = new FootyWireClient();
|
|
3212
3322
|
const competition = query.competition ?? "AFLM";
|
|
3323
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
3324
|
+
const client = new FootyWireClient();
|
|
3213
3325
|
const teamName = normaliseTeamName(query.team);
|
|
3214
3326
|
const result = await client.fetchPlayerList(teamName);
|
|
3215
3327
|
if (!result.success) return result;
|
|
@@ -3221,8 +3333,9 @@ async function fetchFromFootyWire(query) {
|
|
|
3221
3333
|
return ok(players);
|
|
3222
3334
|
}
|
|
3223
3335
|
async function fetchFromAflTables(query) {
|
|
3224
|
-
const client = new AflTablesClient();
|
|
3225
3336
|
const competition = query.competition ?? "AFLM";
|
|
3337
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
3338
|
+
const client = new AflTablesClient();
|
|
3226
3339
|
const teamName = normaliseTeamName(query.team);
|
|
3227
3340
|
const result = await client.fetchPlayerList(teamName);
|
|
3228
3341
|
if (!result.success) return result;
|
|
@@ -3253,6 +3366,7 @@ async function fetchPlayerDetails(query) {
|
|
|
3253
3366
|
var init_player_details = __esm({
|
|
3254
3367
|
"src/api/player-details.ts"() {
|
|
3255
3368
|
"use strict";
|
|
3369
|
+
init_date_utils();
|
|
3256
3370
|
init_errors();
|
|
3257
3371
|
init_result();
|
|
3258
3372
|
init_team_mapping();
|
|
@@ -3268,80 +3382,82 @@ function toNullable(value) {
|
|
|
3268
3382
|
}
|
|
3269
3383
|
function transformOne(item, matchId, season, roundNumber, competition, source, teamIdMap) {
|
|
3270
3384
|
const inner = item.player.player.player;
|
|
3271
|
-
const stats = item.playerStats
|
|
3272
|
-
const clearances = stats
|
|
3385
|
+
const stats = item.playerStats?.stats;
|
|
3386
|
+
const clearances = stats?.clearances;
|
|
3273
3387
|
return {
|
|
3274
3388
|
matchId,
|
|
3275
3389
|
season,
|
|
3276
3390
|
roundNumber,
|
|
3277
|
-
team: normaliseTeamName(
|
|
3391
|
+
team: normaliseTeamName(
|
|
3392
|
+
teamIdMap?.get(item.teamId) ?? AFL_API_TEAM_IDS.get(item.teamId) ?? item.teamId
|
|
3393
|
+
),
|
|
3278
3394
|
competition,
|
|
3279
3395
|
playerId: inner.playerId,
|
|
3280
3396
|
givenName: inner.playerName.givenName,
|
|
3281
3397
|
surname: inner.playerName.surname,
|
|
3282
3398
|
displayName: `${inner.playerName.givenName} ${inner.playerName.surname}`,
|
|
3283
3399
|
jumperNumber: item.player.jumperNumber ?? null,
|
|
3284
|
-
kicks: toNullable(stats
|
|
3285
|
-
handballs: toNullable(stats
|
|
3286
|
-
disposals: toNullable(stats
|
|
3287
|
-
marks: toNullable(stats
|
|
3288
|
-
goals: toNullable(stats
|
|
3289
|
-
behinds: toNullable(stats
|
|
3290
|
-
tackles: toNullable(stats
|
|
3291
|
-
hitouts: toNullable(stats
|
|
3292
|
-
freesFor: toNullable(stats
|
|
3293
|
-
freesAgainst: toNullable(stats
|
|
3294
|
-
contestedPossessions: toNullable(stats
|
|
3295
|
-
uncontestedPossessions: toNullable(stats
|
|
3296
|
-
contestedMarks: toNullable(stats
|
|
3297
|
-
intercepts: toNullable(stats
|
|
3400
|
+
kicks: toNullable(stats?.kicks),
|
|
3401
|
+
handballs: toNullable(stats?.handballs),
|
|
3402
|
+
disposals: toNullable(stats?.disposals),
|
|
3403
|
+
marks: toNullable(stats?.marks),
|
|
3404
|
+
goals: toNullable(stats?.goals),
|
|
3405
|
+
behinds: toNullable(stats?.behinds),
|
|
3406
|
+
tackles: toNullable(stats?.tackles),
|
|
3407
|
+
hitouts: toNullable(stats?.hitouts),
|
|
3408
|
+
freesFor: toNullable(stats?.freesFor),
|
|
3409
|
+
freesAgainst: toNullable(stats?.freesAgainst),
|
|
3410
|
+
contestedPossessions: toNullable(stats?.contestedPossessions),
|
|
3411
|
+
uncontestedPossessions: toNullable(stats?.uncontestedPossessions),
|
|
3412
|
+
contestedMarks: toNullable(stats?.contestedMarks),
|
|
3413
|
+
intercepts: toNullable(stats?.intercepts),
|
|
3298
3414
|
centreClearances: toNullable(clearances?.centreClearances),
|
|
3299
3415
|
stoppageClearances: toNullable(clearances?.stoppageClearances),
|
|
3300
3416
|
totalClearances: toNullable(clearances?.totalClearances),
|
|
3301
|
-
inside50s: toNullable(stats
|
|
3302
|
-
rebound50s: toNullable(stats
|
|
3303
|
-
clangers: toNullable(stats
|
|
3304
|
-
turnovers: toNullable(stats
|
|
3305
|
-
onePercenters: toNullable(stats
|
|
3306
|
-
bounces: toNullable(stats
|
|
3307
|
-
goalAssists: toNullable(stats
|
|
3308
|
-
disposalEfficiency: toNullable(stats
|
|
3309
|
-
metresGained: toNullable(stats
|
|
3310
|
-
goalAccuracy: toNullable(stats
|
|
3311
|
-
marksInside50: toNullable(stats
|
|
3312
|
-
tacklesInside50: toNullable(stats
|
|
3313
|
-
shotsAtGoal: toNullable(stats
|
|
3314
|
-
scoreInvolvements: toNullable(stats
|
|
3315
|
-
totalPossessions: toNullable(stats
|
|
3316
|
-
timeOnGroundPercentage: toNullable(item.playerStats
|
|
3317
|
-
ratingPoints: toNullable(stats
|
|
3318
|
-
dreamTeamPoints: toNullable(stats
|
|
3319
|
-
effectiveDisposals: toNullable(stats
|
|
3320
|
-
effectiveKicks: toNullable(stats
|
|
3321
|
-
kickEfficiency: toNullable(stats
|
|
3322
|
-
kickToHandballRatio: toNullable(stats
|
|
3323
|
-
pressureActs: toNullable(stats
|
|
3324
|
-
defHalfPressureActs: toNullable(stats
|
|
3325
|
-
spoils: toNullable(stats
|
|
3326
|
-
hitoutsToAdvantage: toNullable(stats
|
|
3327
|
-
hitoutWinPercentage: toNullable(stats
|
|
3328
|
-
hitoutToAdvantageRate: toNullable(stats
|
|
3329
|
-
groundBallGets: toNullable(stats
|
|
3330
|
-
f50GroundBallGets: toNullable(stats
|
|
3331
|
-
interceptMarks: toNullable(stats
|
|
3332
|
-
marksOnLead: toNullable(stats
|
|
3333
|
-
contestedPossessionRate: toNullable(stats
|
|
3334
|
-
contestOffOneOnOnes: toNullable(stats
|
|
3335
|
-
contestOffWins: toNullable(stats
|
|
3336
|
-
contestOffWinsPercentage: toNullable(stats
|
|
3337
|
-
contestDefOneOnOnes: toNullable(stats
|
|
3338
|
-
contestDefLosses: toNullable(stats
|
|
3339
|
-
contestDefLossPercentage: toNullable(stats
|
|
3340
|
-
centreBounceAttendances: toNullable(stats
|
|
3341
|
-
kickins: toNullable(stats
|
|
3342
|
-
kickinsPlayon: toNullable(stats
|
|
3343
|
-
ruckContests: toNullable(stats
|
|
3344
|
-
scoreLaunches: toNullable(stats
|
|
3417
|
+
inside50s: toNullable(stats?.inside50s),
|
|
3418
|
+
rebound50s: toNullable(stats?.rebound50s),
|
|
3419
|
+
clangers: toNullable(stats?.clangers),
|
|
3420
|
+
turnovers: toNullable(stats?.turnovers),
|
|
3421
|
+
onePercenters: toNullable(stats?.onePercenters),
|
|
3422
|
+
bounces: toNullable(stats?.bounces),
|
|
3423
|
+
goalAssists: toNullable(stats?.goalAssists),
|
|
3424
|
+
disposalEfficiency: toNullable(stats?.disposalEfficiency),
|
|
3425
|
+
metresGained: toNullable(stats?.metresGained),
|
|
3426
|
+
goalAccuracy: toNullable(stats?.goalAccuracy),
|
|
3427
|
+
marksInside50: toNullable(stats?.marksInside50),
|
|
3428
|
+
tacklesInside50: toNullable(stats?.tacklesInside50),
|
|
3429
|
+
shotsAtGoal: toNullable(stats?.shotsAtGoal),
|
|
3430
|
+
scoreInvolvements: toNullable(stats?.scoreInvolvements),
|
|
3431
|
+
totalPossessions: toNullable(stats?.totalPossessions),
|
|
3432
|
+
timeOnGroundPercentage: toNullable(item.playerStats?.timeOnGroundPercentage),
|
|
3433
|
+
ratingPoints: toNullable(stats?.ratingPoints),
|
|
3434
|
+
dreamTeamPoints: toNullable(stats?.dreamTeamPoints),
|
|
3435
|
+
effectiveDisposals: toNullable(stats?.extendedStats?.effectiveDisposals),
|
|
3436
|
+
effectiveKicks: toNullable(stats?.extendedStats?.effectiveKicks),
|
|
3437
|
+
kickEfficiency: toNullable(stats?.extendedStats?.kickEfficiency),
|
|
3438
|
+
kickToHandballRatio: toNullable(stats?.extendedStats?.kickToHandballRatio),
|
|
3439
|
+
pressureActs: toNullable(stats?.extendedStats?.pressureActs),
|
|
3440
|
+
defHalfPressureActs: toNullable(stats?.extendedStats?.defHalfPressureActs),
|
|
3441
|
+
spoils: toNullable(stats?.extendedStats?.spoils),
|
|
3442
|
+
hitoutsToAdvantage: toNullable(stats?.extendedStats?.hitoutsToAdvantage),
|
|
3443
|
+
hitoutWinPercentage: toNullable(stats?.extendedStats?.hitoutWinPercentage),
|
|
3444
|
+
hitoutToAdvantageRate: toNullable(stats?.extendedStats?.hitoutToAdvantageRate),
|
|
3445
|
+
groundBallGets: toNullable(stats?.extendedStats?.groundBallGets),
|
|
3446
|
+
f50GroundBallGets: toNullable(stats?.extendedStats?.f50GroundBallGets),
|
|
3447
|
+
interceptMarks: toNullable(stats?.extendedStats?.interceptMarks),
|
|
3448
|
+
marksOnLead: toNullable(stats?.extendedStats?.marksOnLead),
|
|
3449
|
+
contestedPossessionRate: toNullable(stats?.extendedStats?.contestedPossessionRate),
|
|
3450
|
+
contestOffOneOnOnes: toNullable(stats?.extendedStats?.contestOffOneOnOnes),
|
|
3451
|
+
contestOffWins: toNullable(stats?.extendedStats?.contestOffWins),
|
|
3452
|
+
contestOffWinsPercentage: toNullable(stats?.extendedStats?.contestOffWinsPercentage),
|
|
3453
|
+
contestDefOneOnOnes: toNullable(stats?.extendedStats?.contestDefOneOnOnes),
|
|
3454
|
+
contestDefLosses: toNullable(stats?.extendedStats?.contestDefLosses),
|
|
3455
|
+
contestDefLossPercentage: toNullable(stats?.extendedStats?.contestDefLossPercentage),
|
|
3456
|
+
centreBounceAttendances: toNullable(stats?.extendedStats?.centreBounceAttendances),
|
|
3457
|
+
kickins: toNullable(stats?.extendedStats?.kickins),
|
|
3458
|
+
kickinsPlayon: toNullable(stats?.extendedStats?.kickinsPlayon),
|
|
3459
|
+
ruckContests: toNullable(stats?.extendedStats?.ruckContests),
|
|
3460
|
+
scoreLaunches: toNullable(stats?.extendedStats?.scoreLaunches),
|
|
3345
3461
|
source
|
|
3346
3462
|
};
|
|
3347
3463
|
}
|
|
@@ -3373,11 +3489,11 @@ async function fetchPlayerStats(query) {
|
|
|
3373
3489
|
client.fetchPlayerStats(query.matchId)
|
|
3374
3490
|
]);
|
|
3375
3491
|
if (!statsResult.success) return statsResult;
|
|
3376
|
-
const teamIdMap2 =
|
|
3492
|
+
const teamIdMap2 = new Map(AFL_API_TEAM_IDS);
|
|
3377
3493
|
if (rosterResult.success) {
|
|
3378
3494
|
const match = rosterResult.data.match;
|
|
3379
|
-
teamIdMap2.set(match.homeTeamId, match.homeTeam.name);
|
|
3380
|
-
teamIdMap2.set(match.awayTeamId, match.awayTeam.name);
|
|
3495
|
+
teamIdMap2.set(match.homeTeamId, normaliseTeamName(match.homeTeam.name));
|
|
3496
|
+
teamIdMap2.set(match.awayTeamId, normaliseTeamName(match.awayTeam.name));
|
|
3381
3497
|
}
|
|
3382
3498
|
return ok(
|
|
3383
3499
|
transformPlayerStats(
|
|
@@ -3387,7 +3503,7 @@ async function fetchPlayerStats(query) {
|
|
|
3387
3503
|
query.round ?? 0,
|
|
3388
3504
|
competition,
|
|
3389
3505
|
"afl-api",
|
|
3390
|
-
teamIdMap2
|
|
3506
|
+
teamIdMap2
|
|
3391
3507
|
)
|
|
3392
3508
|
);
|
|
3393
3509
|
}
|
|
@@ -3430,6 +3546,7 @@ async function fetchPlayerStats(query) {
|
|
|
3430
3546
|
return ok(allStats);
|
|
3431
3547
|
}
|
|
3432
3548
|
case "footywire": {
|
|
3549
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("footywire"));
|
|
3433
3550
|
const fwClient = new FootyWireClient();
|
|
3434
3551
|
const idsResult = await fwClient.fetchSeasonMatchIds(query.season);
|
|
3435
3552
|
if (!idsResult.success) return idsResult;
|
|
@@ -3459,6 +3576,7 @@ async function fetchPlayerStats(query) {
|
|
|
3459
3576
|
return ok(allStats);
|
|
3460
3577
|
}
|
|
3461
3578
|
case "afl-tables": {
|
|
3579
|
+
if (competition === "AFLW") return err(aflwUnsupportedError("afl-tables"));
|
|
3462
3580
|
const atClient = new AflTablesClient();
|
|
3463
3581
|
const atResult = await atClient.fetchSeasonPlayerStats(query.season);
|
|
3464
3582
|
if (!atResult.success) return atResult;
|
|
@@ -3477,6 +3595,7 @@ var init_player_stats2 = __esm({
|
|
|
3477
3595
|
init_concurrency();
|
|
3478
3596
|
init_errors();
|
|
3479
3597
|
init_result();
|
|
3598
|
+
init_team_mapping();
|
|
3480
3599
|
init_afl_api();
|
|
3481
3600
|
init_afl_tables();
|
|
3482
3601
|
init_footywire();
|
|
@@ -3494,7 +3613,39 @@ async function fetchTeamStats(query) {
|
|
|
3494
3613
|
}
|
|
3495
3614
|
case "afl-tables": {
|
|
3496
3615
|
const client = new AflTablesClient();
|
|
3497
|
-
|
|
3616
|
+
const statsResult = await client.fetchTeamStats(query.season);
|
|
3617
|
+
if (!statsResult.success) return statsResult;
|
|
3618
|
+
const needsGp = statsResult.data.some((e) => e.gamesPlayed === 0);
|
|
3619
|
+
const gpMap = /* @__PURE__ */ new Map();
|
|
3620
|
+
if (needsGp) {
|
|
3621
|
+
const resultsResult = await client.fetchSeasonResults(query.season);
|
|
3622
|
+
if (resultsResult.success) {
|
|
3623
|
+
for (const m of resultsResult.data) {
|
|
3624
|
+
const home = normaliseTeamName(m.homeTeam);
|
|
3625
|
+
const away = normaliseTeamName(m.awayTeam);
|
|
3626
|
+
gpMap.set(home, (gpMap.get(home) ?? 0) + 1);
|
|
3627
|
+
gpMap.set(away, (gpMap.get(away) ?? 0) + 1);
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
const enriched = statsResult.data.map((entry) => ({
|
|
3632
|
+
...entry,
|
|
3633
|
+
gamesPlayed: gpMap.get(normaliseTeamName(entry.team)) ?? entry.gamesPlayed
|
|
3634
|
+
}));
|
|
3635
|
+
if (summaryType === "averages") {
|
|
3636
|
+
return ok(
|
|
3637
|
+
enriched.map((entry) => ({
|
|
3638
|
+
...entry,
|
|
3639
|
+
stats: Object.fromEntries(
|
|
3640
|
+
Object.entries(entry.stats).map(([k, v]) => [
|
|
3641
|
+
k,
|
|
3642
|
+
entry.gamesPlayed > 0 ? +(v / entry.gamesPlayed).toFixed(1) : 0
|
|
3643
|
+
])
|
|
3644
|
+
)
|
|
3645
|
+
}))
|
|
3646
|
+
);
|
|
3647
|
+
}
|
|
3648
|
+
return ok(enriched);
|
|
3498
3649
|
}
|
|
3499
3650
|
case "afl-api":
|
|
3500
3651
|
case "squiggle":
|
|
@@ -3513,6 +3664,7 @@ var init_team_stats = __esm({
|
|
|
3513
3664
|
"use strict";
|
|
3514
3665
|
init_errors();
|
|
3515
3666
|
init_result();
|
|
3667
|
+
init_team_mapping();
|
|
3516
3668
|
init_afl_tables();
|
|
3517
3669
|
init_footywire();
|
|
3518
3670
|
}
|
|
@@ -3522,19 +3674,30 @@ var init_team_stats = __esm({
|
|
|
3522
3674
|
function teamTypeForComp(comp) {
|
|
3523
3675
|
return comp === "AFLW" ? "WOMEN" : "MEN";
|
|
3524
3676
|
}
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
const teamType = query?.teamType ?? teamTypeForComp(query?.competition ?? "AFLM");
|
|
3528
|
-
const result = await client.fetchTeams(teamType);
|
|
3529
|
-
if (!result.success) return result;
|
|
3530
|
-
const competition = query?.competition ?? "AFLM";
|
|
3531
|
-
const teams = result.data.map((t) => ({
|
|
3677
|
+
function toTeams(data, competition) {
|
|
3678
|
+
return data.map((t) => ({
|
|
3532
3679
|
teamId: String(t.id),
|
|
3533
3680
|
name: normaliseTeamName(t.name),
|
|
3534
3681
|
abbreviation: t.abbreviation ?? "",
|
|
3535
3682
|
competition
|
|
3536
3683
|
})).filter((t) => AFL_SENIOR_TEAMS.has(t.name));
|
|
3537
|
-
|
|
3684
|
+
}
|
|
3685
|
+
async function fetchTeams(query) {
|
|
3686
|
+
const client = new AflApiClient();
|
|
3687
|
+
if (!query?.competition && !query?.teamType) {
|
|
3688
|
+
const [menResult, womenResult] = await Promise.all([
|
|
3689
|
+
client.fetchTeams("MEN"),
|
|
3690
|
+
client.fetchTeams("WOMEN")
|
|
3691
|
+
]);
|
|
3692
|
+
if (!menResult.success) return menResult;
|
|
3693
|
+
if (!womenResult.success) return womenResult;
|
|
3694
|
+
return ok([...toTeams(menResult.data, "AFLM"), ...toTeams(womenResult.data, "AFLW")]);
|
|
3695
|
+
}
|
|
3696
|
+
const competition = query?.competition ?? "AFLM";
|
|
3697
|
+
const teamType = query?.teamType ?? teamTypeForComp(competition);
|
|
3698
|
+
const result = await client.fetchTeams(teamType);
|
|
3699
|
+
if (!result.success) return result;
|
|
3700
|
+
return ok(toTeams(result.data, competition));
|
|
3538
3701
|
}
|
|
3539
3702
|
async function fetchSquad(query) {
|
|
3540
3703
|
const client = new AflApiClient();
|
|
@@ -3555,8 +3718,8 @@ async function fetchSquad(query) {
|
|
|
3555
3718
|
jumperNumber: p.jumperNumber ?? null,
|
|
3556
3719
|
position: p.position ?? null,
|
|
3557
3720
|
dateOfBirth: p.player.dateOfBirth ? new Date(p.player.dateOfBirth) : null,
|
|
3558
|
-
heightCm: p.player.heightInCm
|
|
3559
|
-
weightKg: p.player.weightInKg
|
|
3721
|
+
heightCm: p.player.heightInCm || null,
|
|
3722
|
+
weightKg: p.player.weightInKg || null,
|
|
3560
3723
|
draftYear: p.player.draftYear ? Number.parseInt(p.player.draftYear, 10) || null : null,
|
|
3561
3724
|
draftPosition: p.player.draftPosition ? Number.parseInt(p.player.draftPosition, 10) || null : null,
|
|
3562
3725
|
draftType: p.player.draftType ?? null,
|
|
@@ -3897,10 +4060,6 @@ function validateOptionalSeason(raw) {
|
|
|
3897
4060
|
if (raw != null) return validateSeason(raw);
|
|
3898
4061
|
return void 0;
|
|
3899
4062
|
}
|
|
3900
|
-
function resolveDefaultSeason(competition = "AFLM") {
|
|
3901
|
-
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
3902
|
-
return competition === "AFLW" ? year - 1 : year;
|
|
3903
|
-
}
|
|
3904
4063
|
function validateRound(raw) {
|
|
3905
4064
|
const round = Number(raw);
|
|
3906
4065
|
if (Number.isNaN(round) || !Number.isInteger(round) || round < 0) {
|
|
@@ -3935,6 +4094,15 @@ function validateSource(raw) {
|
|
|
3935
4094
|
}
|
|
3936
4095
|
throw new Error(`Invalid source: "${raw}" \u2014 valid sources are: ${VALID_SOURCES.join(", ")}`);
|
|
3937
4096
|
}
|
|
4097
|
+
function validateSummary(raw) {
|
|
4098
|
+
const lower = raw.toLowerCase();
|
|
4099
|
+
if (VALID_SUMMARIES.includes(lower)) {
|
|
4100
|
+
return lower;
|
|
4101
|
+
}
|
|
4102
|
+
throw new Error(
|
|
4103
|
+
`Invalid summary type: "${raw}" \u2014 valid values are: ${VALID_SUMMARIES.join(", ")}`
|
|
4104
|
+
);
|
|
4105
|
+
}
|
|
3938
4106
|
function resolveTeamIdentifier(raw, teams) {
|
|
3939
4107
|
const trimmed = raw.trim();
|
|
3940
4108
|
if (/^\d+$/.test(trimmed)) {
|
|
@@ -3964,24 +4132,30 @@ function resolveMatchByTeam(teamSearch, matchItems) {
|
|
|
3964
4132
|
return singleMatch.match.matchId;
|
|
3965
4133
|
}
|
|
3966
4134
|
if (matches.length === 0) {
|
|
3967
|
-
const available = matchItems.map(
|
|
4135
|
+
const available = matchItems.map(
|
|
4136
|
+
(item) => `${normaliseTeamName(item.match.homeTeam.name)} vs ${normaliseTeamName(item.match.awayTeam.name)}`
|
|
4137
|
+
).join(", ");
|
|
3968
4138
|
throw new Error(
|
|
3969
4139
|
`No match found for "${teamSearch}" in this round. Available matches: ${available}`
|
|
3970
4140
|
);
|
|
3971
4141
|
}
|
|
3972
|
-
const ambiguous = matches.map(
|
|
4142
|
+
const ambiguous = matches.map(
|
|
4143
|
+
(item) => `${normaliseTeamName(item.match.homeTeam.name)} vs ${normaliseTeamName(item.match.awayTeam.name)}`
|
|
4144
|
+
).join(", ");
|
|
3973
4145
|
throw new Error(
|
|
3974
4146
|
`Multiple matches found for "${teamSearch}": ${ambiguous}. Please be more specific.`
|
|
3975
4147
|
);
|
|
3976
4148
|
}
|
|
3977
|
-
var VALID_SOURCES, VALID_COMPETITIONS, VALID_FORMATS;
|
|
4149
|
+
var VALID_SOURCES, VALID_COMPETITIONS, VALID_FORMATS, VALID_SUMMARIES;
|
|
3978
4150
|
var init_validation2 = __esm({
|
|
3979
4151
|
"src/cli/validation.ts"() {
|
|
3980
4152
|
"use strict";
|
|
3981
4153
|
init_team_mapping();
|
|
4154
|
+
init_date_utils();
|
|
3982
4155
|
VALID_SOURCES = ["afl-api", "footywire", "afl-tables", "squiggle"];
|
|
3983
4156
|
VALID_COMPETITIONS = ["AFLM", "AFLW"];
|
|
3984
4157
|
VALID_FORMATS = ["table", "json", "csv"];
|
|
4158
|
+
VALID_SUMMARIES = ["totals", "averages"];
|
|
3985
4159
|
}
|
|
3986
4160
|
});
|
|
3987
4161
|
|
|
@@ -3996,6 +4170,7 @@ var init_matches = __esm({
|
|
|
3996
4170
|
"src/cli/commands/matches.ts"() {
|
|
3997
4171
|
"use strict";
|
|
3998
4172
|
init_index();
|
|
4173
|
+
init_error_boundary();
|
|
3999
4174
|
init_flags();
|
|
4000
4175
|
init_formatters();
|
|
4001
4176
|
init_ui();
|
|
@@ -4021,7 +4196,7 @@ var init_matches = __esm({
|
|
|
4021
4196
|
...COMPETITION_FLAG,
|
|
4022
4197
|
...OUTPUT_FLAGS
|
|
4023
4198
|
},
|
|
4024
|
-
async
|
|
4199
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4025
4200
|
const season = validateSeason(args.season);
|
|
4026
4201
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4027
4202
|
const source = validateSource(args.source);
|
|
@@ -4044,7 +4219,7 @@ var init_matches = __esm({
|
|
|
4044
4219
|
columns: DEFAULT_COLUMNS
|
|
4045
4220
|
};
|
|
4046
4221
|
console.log(formatOutput(data, formatOptions));
|
|
4047
|
-
}
|
|
4222
|
+
})
|
|
4048
4223
|
});
|
|
4049
4224
|
}
|
|
4050
4225
|
});
|
|
@@ -4168,7 +4343,7 @@ async function resolveMatchOrPrompt(query, matchItems) {
|
|
|
4168
4343
|
}
|
|
4169
4344
|
const labelledItems = matchItems.map((item) => ({
|
|
4170
4345
|
item,
|
|
4171
|
-
label: `${item.match.homeTeam.name} vs ${item.match.awayTeam.name}`
|
|
4346
|
+
label: `${normaliseTeamName(item.match.homeTeam.name)} vs ${normaliseTeamName(item.match.awayTeam.name)}`
|
|
4172
4347
|
}));
|
|
4173
4348
|
const matches = fuzzySearch(query, labelledItems, (l) => l.label, {
|
|
4174
4349
|
maxResults: 5,
|
|
@@ -4185,21 +4360,21 @@ async function resolveMatchOrPrompt(query, matchItems) {
|
|
|
4185
4360
|
const seen = new Set(matches.map((m) => m.item.item.match.matchId));
|
|
4186
4361
|
for (const m of homeMatches) {
|
|
4187
4362
|
if (!seen.has(m.item.match.matchId)) {
|
|
4188
|
-
const label = `${m.item.match.homeTeam.name} vs ${m.item.match.awayTeam.name}`;
|
|
4363
|
+
const label = `${normaliseTeamName(m.item.match.homeTeam.name)} vs ${normaliseTeamName(m.item.match.awayTeam.name)}`;
|
|
4189
4364
|
matches.push({ item: { item: m.item, label }, score: m.score });
|
|
4190
4365
|
seen.add(m.item.match.matchId);
|
|
4191
4366
|
}
|
|
4192
4367
|
}
|
|
4193
4368
|
for (const m of awayMatches) {
|
|
4194
4369
|
if (!seen.has(m.item.match.matchId)) {
|
|
4195
|
-
const label = `${m.item.match.homeTeam.name} vs ${m.item.match.awayTeam.name}`;
|
|
4370
|
+
const label = `${normaliseTeamName(m.item.match.homeTeam.name)} vs ${normaliseTeamName(m.item.match.awayTeam.name)}`;
|
|
4196
4371
|
matches.push({ item: { item: m.item, label }, score: m.score });
|
|
4197
4372
|
seen.add(m.item.match.matchId);
|
|
4198
4373
|
}
|
|
4199
4374
|
}
|
|
4200
4375
|
matches.sort((a, b) => a.score - b.score);
|
|
4201
4376
|
const available = matchItems.map(
|
|
4202
|
-
(item) => `${item.match.homeTeam.name} vs ${item.match.awayTeam.name}`
|
|
4377
|
+
(item) => `${normaliseTeamName(item.match.homeTeam.name)} vs ${normaliseTeamName(item.match.awayTeam.name)}`
|
|
4203
4378
|
);
|
|
4204
4379
|
return disambiguate(
|
|
4205
4380
|
query,
|
|
@@ -4259,6 +4434,7 @@ var init_stats = __esm({
|
|
|
4259
4434
|
init_index();
|
|
4260
4435
|
init_fuzzy();
|
|
4261
4436
|
init_afl_api();
|
|
4437
|
+
init_error_boundary();
|
|
4262
4438
|
init_flags();
|
|
4263
4439
|
init_formatters();
|
|
4264
4440
|
init_resolvers();
|
|
@@ -4288,7 +4464,7 @@ var init_stats = __esm({
|
|
|
4288
4464
|
...PLAYER_FLAG,
|
|
4289
4465
|
...OUTPUT_FLAGS
|
|
4290
4466
|
},
|
|
4291
|
-
async
|
|
4467
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4292
4468
|
const season = validateSeason(args.season);
|
|
4293
4469
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4294
4470
|
const source = validateSource(args.source);
|
|
@@ -4331,7 +4507,7 @@ var init_stats = __esm({
|
|
|
4331
4507
|
columns: DEFAULT_COLUMNS2
|
|
4332
4508
|
};
|
|
4333
4509
|
console.log(formatOutput(data, formatOptions));
|
|
4334
|
-
}
|
|
4510
|
+
})
|
|
4335
4511
|
});
|
|
4336
4512
|
}
|
|
4337
4513
|
});
|
|
@@ -4347,6 +4523,7 @@ var init_fixture2 = __esm({
|
|
|
4347
4523
|
"src/cli/commands/fixture.ts"() {
|
|
4348
4524
|
"use strict";
|
|
4349
4525
|
init_index();
|
|
4526
|
+
init_error_boundary();
|
|
4350
4527
|
init_flags();
|
|
4351
4528
|
init_formatters();
|
|
4352
4529
|
init_ui();
|
|
@@ -4370,7 +4547,7 @@ var init_fixture2 = __esm({
|
|
|
4370
4547
|
...COMPETITION_FLAG,
|
|
4371
4548
|
...OUTPUT_FLAGS
|
|
4372
4549
|
},
|
|
4373
|
-
async
|
|
4550
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4374
4551
|
const season = validateSeason(args.season);
|
|
4375
4552
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4376
4553
|
const source = validateSource(args.source);
|
|
@@ -4393,7 +4570,7 @@ var init_fixture2 = __esm({
|
|
|
4393
4570
|
columns: DEFAULT_COLUMNS3
|
|
4394
4571
|
};
|
|
4395
4572
|
console.log(formatOutput(data, formatOptions));
|
|
4396
|
-
}
|
|
4573
|
+
})
|
|
4397
4574
|
});
|
|
4398
4575
|
}
|
|
4399
4576
|
});
|
|
@@ -4409,6 +4586,7 @@ var init_ladder3 = __esm({
|
|
|
4409
4586
|
"src/cli/commands/ladder.ts"() {
|
|
4410
4587
|
"use strict";
|
|
4411
4588
|
init_index();
|
|
4589
|
+
init_error_boundary();
|
|
4412
4590
|
init_flags();
|
|
4413
4591
|
init_formatters();
|
|
4414
4592
|
init_ui();
|
|
@@ -4434,7 +4612,7 @@ var init_ladder3 = __esm({
|
|
|
4434
4612
|
...COMPETITION_FLAG,
|
|
4435
4613
|
...OUTPUT_FLAGS
|
|
4436
4614
|
},
|
|
4437
|
-
async
|
|
4615
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4438
4616
|
const season = validateSeason(args.season);
|
|
4439
4617
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4440
4618
|
const source = validateSource(args.source);
|
|
@@ -4459,7 +4637,7 @@ var init_ladder3 = __esm({
|
|
|
4459
4637
|
columns: DEFAULT_COLUMNS4
|
|
4460
4638
|
};
|
|
4461
4639
|
console.log(formatOutput(data.entries, formatOptions));
|
|
4462
|
-
}
|
|
4640
|
+
})
|
|
4463
4641
|
});
|
|
4464
4642
|
}
|
|
4465
4643
|
});
|
|
@@ -4498,6 +4676,7 @@ var init_lineup3 = __esm({
|
|
|
4498
4676
|
"use strict";
|
|
4499
4677
|
init_index();
|
|
4500
4678
|
init_afl_api();
|
|
4679
|
+
init_error_boundary();
|
|
4501
4680
|
init_flags();
|
|
4502
4681
|
init_formatters();
|
|
4503
4682
|
init_resolvers();
|
|
@@ -4524,7 +4703,7 @@ var init_lineup3 = __esm({
|
|
|
4524
4703
|
...COMPETITION_FLAG,
|
|
4525
4704
|
...OUTPUT_FLAGS
|
|
4526
4705
|
},
|
|
4527
|
-
async
|
|
4706
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4528
4707
|
const season = validateSeason(args.season);
|
|
4529
4708
|
const round = validateRound(args.round);
|
|
4530
4709
|
const source = validateSource(args.source);
|
|
@@ -4561,7 +4740,7 @@ var init_lineup3 = __esm({
|
|
|
4561
4740
|
} else {
|
|
4562
4741
|
console.log(formatOutput(flattenLineups(data), formatOptions));
|
|
4563
4742
|
}
|
|
4564
|
-
}
|
|
4743
|
+
})
|
|
4565
4744
|
});
|
|
4566
4745
|
}
|
|
4567
4746
|
});
|
|
@@ -4577,6 +4756,7 @@ var init_squad = __esm({
|
|
|
4577
4756
|
"src/cli/commands/squad.ts"() {
|
|
4578
4757
|
"use strict";
|
|
4579
4758
|
init_index();
|
|
4759
|
+
init_error_boundary();
|
|
4580
4760
|
init_flags();
|
|
4581
4761
|
init_formatters();
|
|
4582
4762
|
init_resolvers();
|
|
@@ -4600,7 +4780,7 @@ var init_squad = __esm({
|
|
|
4600
4780
|
...COMPETITION_FLAG,
|
|
4601
4781
|
...OUTPUT_FLAGS
|
|
4602
4782
|
},
|
|
4603
|
-
async
|
|
4783
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4604
4784
|
const season = validateSeason(args.season);
|
|
4605
4785
|
const competition = validateCompetition(args.competition);
|
|
4606
4786
|
const format = validateFormat(args.format);
|
|
@@ -4629,7 +4809,7 @@ var init_squad = __esm({
|
|
|
4629
4809
|
columns: DEFAULT_COLUMNS6
|
|
4630
4810
|
};
|
|
4631
4811
|
console.log(formatOutput(data.players, formatOptions));
|
|
4632
|
-
}
|
|
4812
|
+
})
|
|
4633
4813
|
});
|
|
4634
4814
|
}
|
|
4635
4815
|
});
|
|
@@ -4645,6 +4825,7 @@ var init_teams2 = __esm({
|
|
|
4645
4825
|
"src/cli/commands/teams.ts"() {
|
|
4646
4826
|
"use strict";
|
|
4647
4827
|
init_index();
|
|
4828
|
+
init_error_boundary();
|
|
4648
4829
|
init_flags();
|
|
4649
4830
|
init_formatters();
|
|
4650
4831
|
init_ui();
|
|
@@ -4662,10 +4843,10 @@ var init_teams2 = __esm({
|
|
|
4662
4843
|
},
|
|
4663
4844
|
args: {
|
|
4664
4845
|
...OPTIONAL_COMPETITION_FLAG,
|
|
4665
|
-
"team-type": { type: "string", description: "Team type filter" },
|
|
4846
|
+
"team-type": { type: "string", description: "Team type filter (e.g. CLUB, REPRESENTATIVE)" },
|
|
4666
4847
|
...OUTPUT_FLAGS
|
|
4667
4848
|
},
|
|
4668
|
-
async
|
|
4849
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4669
4850
|
const competition = validateOptionalCompetition(args.competition);
|
|
4670
4851
|
const format = validateFormat(args.format);
|
|
4671
4852
|
const result = await withSpinner(
|
|
@@ -4677,8 +4858,8 @@ var init_teams2 = __esm({
|
|
|
4677
4858
|
}
|
|
4678
4859
|
const data = result.data;
|
|
4679
4860
|
if (data.length === 0 && args["team-type"]) {
|
|
4680
|
-
|
|
4681
|
-
`No teams found for team type "${args["team-type"]}". Try running without --team-type to see
|
|
4861
|
+
throw new Error(
|
|
4862
|
+
`No teams found for team type "${args["team-type"]}". Known team types include: CLUB, REPRESENTATIVE. Try running without --team-type to see all teams.`
|
|
4682
4863
|
);
|
|
4683
4864
|
}
|
|
4684
4865
|
showSummary(`Loaded ${data.length} teams`);
|
|
@@ -4690,7 +4871,7 @@ var init_teams2 = __esm({
|
|
|
4690
4871
|
columns: DEFAULT_COLUMNS7
|
|
4691
4872
|
};
|
|
4692
4873
|
console.log(formatOutput(data, formatOptions));
|
|
4693
|
-
}
|
|
4874
|
+
})
|
|
4694
4875
|
});
|
|
4695
4876
|
}
|
|
4696
4877
|
});
|
|
@@ -4704,14 +4885,19 @@ import { defineCommand as defineCommand8 } from "citty";
|
|
|
4704
4885
|
function flattenEntries(data) {
|
|
4705
4886
|
return data.map((entry) => {
|
|
4706
4887
|
const { stats, ...rest } = entry;
|
|
4707
|
-
|
|
4888
|
+
const normalised = {};
|
|
4889
|
+
for (const [key, value] of Object.entries(stats)) {
|
|
4890
|
+
normalised[AFL_TABLES_KEY_MAP[key] ?? key] = value;
|
|
4891
|
+
}
|
|
4892
|
+
return { ...rest, ...normalised };
|
|
4708
4893
|
});
|
|
4709
4894
|
}
|
|
4710
|
-
var DEFAULT_COLUMNS8, teamStatsCommand;
|
|
4895
|
+
var DEFAULT_COLUMNS8, AFL_TABLES_KEY_MAP, teamStatsCommand;
|
|
4711
4896
|
var init_team_stats2 = __esm({
|
|
4712
4897
|
"src/cli/commands/team-stats.ts"() {
|
|
4713
4898
|
"use strict";
|
|
4714
4899
|
init_index();
|
|
4900
|
+
init_error_boundary();
|
|
4715
4901
|
init_flags();
|
|
4716
4902
|
init_formatters();
|
|
4717
4903
|
init_ui();
|
|
@@ -4728,6 +4914,53 @@ var init_team_stats2 = __esm({
|
|
|
4728
4914
|
{ key: "T", label: "T", maxWidth: 6 },
|
|
4729
4915
|
{ key: "I50", label: "I50", maxWidth: 6 }
|
|
4730
4916
|
];
|
|
4917
|
+
AFL_TABLES_KEY_MAP = {
|
|
4918
|
+
KI_for: "K",
|
|
4919
|
+
MK_for: "M",
|
|
4920
|
+
HB_for: "HB",
|
|
4921
|
+
DI_for: "D",
|
|
4922
|
+
GL_for: "G",
|
|
4923
|
+
BH_for: "B",
|
|
4924
|
+
HO_for: "HO",
|
|
4925
|
+
TK_for: "T",
|
|
4926
|
+
RB_for: "RB",
|
|
4927
|
+
IF_for: "IF",
|
|
4928
|
+
CL_for: "CL",
|
|
4929
|
+
CG_for: "CG",
|
|
4930
|
+
FF_for: "FF",
|
|
4931
|
+
BR_for: "BR",
|
|
4932
|
+
CP_for: "CP",
|
|
4933
|
+
UP_for: "UP",
|
|
4934
|
+
CM_for: "CM",
|
|
4935
|
+
MI_for: "MI",
|
|
4936
|
+
"1%_for": "1%",
|
|
4937
|
+
BO_for: "BO",
|
|
4938
|
+
GA_for: "GA",
|
|
4939
|
+
I50_for: "I50",
|
|
4940
|
+
// "against" variants
|
|
4941
|
+
KI_against: "K_against",
|
|
4942
|
+
MK_against: "M_against",
|
|
4943
|
+
HB_against: "HB_against",
|
|
4944
|
+
DI_against: "D_against",
|
|
4945
|
+
GL_against: "G_against",
|
|
4946
|
+
BH_against: "B_against",
|
|
4947
|
+
HO_against: "HO_against",
|
|
4948
|
+
TK_against: "T_against",
|
|
4949
|
+
RB_against: "RB_against",
|
|
4950
|
+
IF_against: "IF_against",
|
|
4951
|
+
CL_against: "CL_against",
|
|
4952
|
+
CG_against: "CG_against",
|
|
4953
|
+
FF_against: "FF_against",
|
|
4954
|
+
BR_against: "BR_against",
|
|
4955
|
+
CP_against: "CP_against",
|
|
4956
|
+
UP_against: "UP_against",
|
|
4957
|
+
CM_against: "CM_against",
|
|
4958
|
+
MI_against: "MI_against",
|
|
4959
|
+
"1%_against": "1%_against",
|
|
4960
|
+
BO_against: "BO_against",
|
|
4961
|
+
GA_against: "GA_against",
|
|
4962
|
+
I50_against: "I50_against"
|
|
4963
|
+
};
|
|
4731
4964
|
teamStatsCommand = defineCommand8({
|
|
4732
4965
|
meta: {
|
|
4733
4966
|
name: "team-stats",
|
|
@@ -4743,11 +4976,11 @@ var init_team_stats2 = __esm({
|
|
|
4743
4976
|
summary: { type: "string", description: "Summary type: totals or averages", default: "totals" },
|
|
4744
4977
|
...OUTPUT_FLAGS
|
|
4745
4978
|
},
|
|
4746
|
-
async
|
|
4979
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4747
4980
|
const season = validateSeason(args.season);
|
|
4748
4981
|
const source = validateSource(args.source);
|
|
4749
4982
|
const format = validateFormat(args.format);
|
|
4750
|
-
const summaryType = args.summary;
|
|
4983
|
+
const summaryType = validateSummary(args.summary);
|
|
4751
4984
|
const result = await withSpinner(
|
|
4752
4985
|
"Fetching team stats\u2026",
|
|
4753
4986
|
() => fetchTeamStats({ source, season, summaryType })
|
|
@@ -4766,7 +4999,7 @@ var init_team_stats2 = __esm({
|
|
|
4766
4999
|
columns: DEFAULT_COLUMNS8
|
|
4767
5000
|
};
|
|
4768
5001
|
console.log(formatOutput(flat, formatOptions));
|
|
4769
|
-
}
|
|
5002
|
+
})
|
|
4770
5003
|
});
|
|
4771
5004
|
}
|
|
4772
5005
|
});
|
|
@@ -4782,6 +5015,7 @@ var init_player_details2 = __esm({
|
|
|
4782
5015
|
"src/cli/commands/player-details.ts"() {
|
|
4783
5016
|
"use strict";
|
|
4784
5017
|
init_index();
|
|
5018
|
+
init_error_boundary();
|
|
4785
5019
|
init_flags();
|
|
4786
5020
|
init_formatters();
|
|
4787
5021
|
init_resolvers();
|
|
@@ -4812,7 +5046,7 @@ var init_player_details2 = __esm({
|
|
|
4812
5046
|
...COMPETITION_FLAG,
|
|
4813
5047
|
...OUTPUT_FLAGS
|
|
4814
5048
|
},
|
|
4815
|
-
async
|
|
5049
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4816
5050
|
const source = validateSource(args.source);
|
|
4817
5051
|
const competition = validateCompetition(args.competition);
|
|
4818
5052
|
const format = validateFormat(args.format);
|
|
@@ -4835,7 +5069,7 @@ var init_player_details2 = __esm({
|
|
|
4835
5069
|
columns: DEFAULT_COLUMNS9
|
|
4836
5070
|
};
|
|
4837
5071
|
console.log(formatOutput(data, formatOptions));
|
|
4838
|
-
}
|
|
5072
|
+
})
|
|
4839
5073
|
});
|
|
4840
5074
|
}
|
|
4841
5075
|
});
|
|
@@ -4851,6 +5085,7 @@ var init_coaches_votes2 = __esm({
|
|
|
4851
5085
|
"src/cli/commands/coaches-votes.ts"() {
|
|
4852
5086
|
"use strict";
|
|
4853
5087
|
init_index();
|
|
5088
|
+
init_error_boundary();
|
|
4854
5089
|
init_flags();
|
|
4855
5090
|
init_formatters();
|
|
4856
5091
|
init_resolvers();
|
|
@@ -4876,7 +5111,7 @@ var init_coaches_votes2 = __esm({
|
|
|
4876
5111
|
...TEAM_FLAG,
|
|
4877
5112
|
...OUTPUT_FLAGS
|
|
4878
5113
|
},
|
|
4879
|
-
async
|
|
5114
|
+
run: withErrorBoundary(async ({ args }) => {
|
|
4880
5115
|
const season = validateSeason(args.season);
|
|
4881
5116
|
const round = args.round ? validateRound(args.round) : void 0;
|
|
4882
5117
|
const competition = validateCompetition(args.competition);
|
|
@@ -4901,7 +5136,7 @@ var init_coaches_votes2 = __esm({
|
|
|
4901
5136
|
columns: DEFAULT_COLUMNS10
|
|
4902
5137
|
};
|
|
4903
5138
|
console.log(formatOutput(data, formatOptions));
|
|
4904
|
-
}
|
|
5139
|
+
})
|
|
4905
5140
|
});
|
|
4906
5141
|
}
|
|
4907
5142
|
});
|
|
@@ -4909,37 +5144,34 @@ var init_coaches_votes2 = __esm({
|
|
|
4909
5144
|
// src/cli.ts
|
|
4910
5145
|
import { defineCommand as defineCommand11, runMain } from "citty";
|
|
4911
5146
|
|
|
4912
|
-
// src/cli/
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
return `${pc.red("Unsupported source:")} ${error.message}`;
|
|
4931
|
-
}
|
|
4932
|
-
if (error instanceof Error) {
|
|
4933
|
-
return `${pc.red("Error:")} ${error.message}`;
|
|
5147
|
+
// src/cli/alias-resolution.ts
|
|
5148
|
+
var SHORT_TO_LONG = {
|
|
5149
|
+
"-s": "--season",
|
|
5150
|
+
"-r": "--round",
|
|
5151
|
+
"-c": "--competition",
|
|
5152
|
+
"-j": "--json",
|
|
5153
|
+
"-t": "--team",
|
|
5154
|
+
"-p": "--player"
|
|
5155
|
+
};
|
|
5156
|
+
function resolveAliases() {
|
|
5157
|
+
for (let i = 0; i < process.argv.length; i++) {
|
|
5158
|
+
const arg = process.argv[i];
|
|
5159
|
+
if (arg != null) {
|
|
5160
|
+
const long = SHORT_TO_LONG[arg];
|
|
5161
|
+
if (long) {
|
|
5162
|
+
process.argv[i] = long;
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
4934
5165
|
}
|
|
4935
|
-
return `${pc.red("Error:")} ${String(error)}`;
|
|
4936
5166
|
}
|
|
4937
5167
|
|
|
4938
5168
|
// src/cli.ts
|
|
5169
|
+
init_error_boundary();
|
|
5170
|
+
resolveAliases();
|
|
4939
5171
|
var main = defineCommand11({
|
|
4940
5172
|
meta: {
|
|
4941
5173
|
name: "fitzroy",
|
|
4942
|
-
version: "1.
|
|
5174
|
+
version: "1.3.1",
|
|
4943
5175
|
description: "CLI for fetching AFL data \u2014 match results, player stats, fixtures, ladders, and more"
|
|
4944
5176
|
},
|
|
4945
5177
|
subCommands: {
|