fitzroy 1.0.0 → 1.0.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 +663 -21
- package/dist/index.js +1658 -61
- package/package.json +3 -2
- package/dist/shared/chunk-99nkfy8s.js +0 -65
- package/dist/shared/chunk-9zcjfgwe.js +0 -66
- package/dist/shared/chunk-b380x0p6.js +0 -54
- package/dist/shared/chunk-c7vawngt.js +0 -63
- package/dist/shared/chunk-d6fkap72.js +0 -67
- package/dist/shared/chunk-eyrvakjt.js +0 -1
- package/dist/shared/chunk-kr78ch1j.js +0 -67
- package/dist/shared/chunk-ngvkaczn.js +0 -70
- package/dist/shared/chunk-xv8z2kms.js +0 -4
- package/dist/shared/chunk-z78xs4nr.js +0 -185
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,653 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __returnValue = (v) => v;
|
|
5
|
+
function __exportSetter(name, newValue) {
|
|
6
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
7
|
+
}
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {
|
|
11
|
+
get: all[name],
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
set: __exportSetter.bind(all, name)
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
5
18
|
|
|
6
|
-
// src/
|
|
7
|
-
|
|
19
|
+
// src/index.ts
|
|
20
|
+
var init_src = () => {};
|
|
21
|
+
|
|
22
|
+
// src/cli/formatters/csv.ts
|
|
23
|
+
function escapeField(value) {
|
|
24
|
+
if (value.includes(",") || value.includes('"') || value.includes(`
|
|
25
|
+
`) || value.includes("\r")) {
|
|
26
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
function toStringValue(value) {
|
|
31
|
+
if (value === null || value === undefined)
|
|
32
|
+
return "";
|
|
33
|
+
if (value instanceof Date)
|
|
34
|
+
return value.toISOString();
|
|
35
|
+
if (typeof value === "object")
|
|
36
|
+
return JSON.stringify(value);
|
|
37
|
+
return String(value);
|
|
38
|
+
}
|
|
39
|
+
function formatCsv(data) {
|
|
40
|
+
if (data.length === 0)
|
|
41
|
+
return "";
|
|
42
|
+
const firstRow = data[0];
|
|
43
|
+
if (!firstRow)
|
|
44
|
+
return "";
|
|
45
|
+
const headers = Object.keys(firstRow);
|
|
46
|
+
const lines = [headers.map(escapeField).join(",")];
|
|
47
|
+
for (const row of data) {
|
|
48
|
+
const values = headers.map((h) => escapeField(toStringValue(row[h])));
|
|
49
|
+
lines.push(values.join(","));
|
|
50
|
+
}
|
|
51
|
+
return lines.join(`
|
|
52
|
+
`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/cli/formatters/json.ts
|
|
56
|
+
function formatJson(data) {
|
|
57
|
+
return JSON.stringify(data, null, 2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/cli/formatters/table.ts
|
|
61
|
+
function toDisplayValue(value) {
|
|
62
|
+
if (value === null || value === undefined)
|
|
63
|
+
return "-";
|
|
64
|
+
if (value instanceof Date)
|
|
65
|
+
return value.toISOString().slice(0, 16).replace("T", " ");
|
|
66
|
+
if (typeof value === "object")
|
|
67
|
+
return JSON.stringify(value);
|
|
68
|
+
return String(value);
|
|
69
|
+
}
|
|
70
|
+
function truncate(str, maxLen) {
|
|
71
|
+
if (str.length <= maxLen)
|
|
72
|
+
return str;
|
|
73
|
+
return `${str.slice(0, maxLen - 1)}…`;
|
|
74
|
+
}
|
|
75
|
+
function formatTable(data, options = {}) {
|
|
76
|
+
if (data.length === 0)
|
|
77
|
+
return "No data.";
|
|
78
|
+
const firstRow = data[0];
|
|
79
|
+
if (!firstRow)
|
|
80
|
+
return "No data.";
|
|
81
|
+
const termWidth = options.terminalWidth ?? process.stdout.columns ?? 120;
|
|
82
|
+
const allKeys = Object.keys(firstRow);
|
|
83
|
+
let columns;
|
|
84
|
+
if (options.full || !options.columns || options.columns.length === 0) {
|
|
85
|
+
columns = allKeys.map((key) => ({ key }));
|
|
86
|
+
} else {
|
|
87
|
+
columns = [...options.columns];
|
|
88
|
+
}
|
|
89
|
+
const colWidths = columns.map((col) => (col.label ?? col.key).length);
|
|
90
|
+
for (const row of data) {
|
|
91
|
+
for (let i = 0;i < columns.length; i++) {
|
|
92
|
+
const col = columns[i];
|
|
93
|
+
if (!col)
|
|
94
|
+
continue;
|
|
95
|
+
const len = toDisplayValue(row[col.key]).length;
|
|
96
|
+
const current = colWidths[i];
|
|
97
|
+
if (current !== undefined && len > current) {
|
|
98
|
+
colWidths[i] = len;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (let i = 0;i < columns.length; i++) {
|
|
103
|
+
const col = columns[i];
|
|
104
|
+
const width = colWidths[i];
|
|
105
|
+
if (!col || width === undefined)
|
|
106
|
+
continue;
|
|
107
|
+
colWidths[i] = Math.min(col.maxWidth ?? 30, width);
|
|
108
|
+
}
|
|
109
|
+
const gap = 2;
|
|
110
|
+
const visibleCols = [];
|
|
111
|
+
let usedWidth = 0;
|
|
112
|
+
for (let i = 0;i < columns.length; i++) {
|
|
113
|
+
const colWidth = colWidths[i];
|
|
114
|
+
if (colWidth === undefined)
|
|
115
|
+
continue;
|
|
116
|
+
const needed = usedWidth > 0 ? colWidth + gap : colWidth;
|
|
117
|
+
if (usedWidth + needed > termWidth && visibleCols.length > 0)
|
|
118
|
+
break;
|
|
119
|
+
visibleCols.push(i);
|
|
120
|
+
usedWidth += needed;
|
|
121
|
+
}
|
|
122
|
+
const headerParts = visibleCols.map((i) => {
|
|
123
|
+
const col = columns[i];
|
|
124
|
+
const width = colWidths[i];
|
|
125
|
+
if (!col || width === undefined)
|
|
126
|
+
return "";
|
|
127
|
+
const label = (col.label ?? col.key).toUpperCase();
|
|
128
|
+
return truncate(label, width).padEnd(width);
|
|
129
|
+
});
|
|
130
|
+
const header = headerParts.join(" ");
|
|
131
|
+
const separator = visibleCols.map((i) => {
|
|
132
|
+
const width = colWidths[i];
|
|
133
|
+
if (width === undefined)
|
|
134
|
+
return "";
|
|
135
|
+
return "─".repeat(width);
|
|
136
|
+
}).join(" ");
|
|
137
|
+
const rows = data.map((row) => {
|
|
138
|
+
const parts = visibleCols.map((i) => {
|
|
139
|
+
const col = columns[i];
|
|
140
|
+
const width = colWidths[i];
|
|
141
|
+
if (!col || width === undefined)
|
|
142
|
+
return "";
|
|
143
|
+
const val = toDisplayValue(row[col.key]);
|
|
144
|
+
return truncate(val, width).padEnd(width);
|
|
145
|
+
});
|
|
146
|
+
return parts.join(" ");
|
|
147
|
+
});
|
|
148
|
+
return [header, separator, ...rows].join(`
|
|
149
|
+
`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/cli/formatters/index.ts
|
|
153
|
+
function resolveFormat(options) {
|
|
154
|
+
if (options.json)
|
|
155
|
+
return "json";
|
|
156
|
+
if (options.csv)
|
|
157
|
+
return "csv";
|
|
158
|
+
if (options.format === "json" || options.format === "csv" || options.format === "table") {
|
|
159
|
+
return options.format;
|
|
160
|
+
}
|
|
161
|
+
if (!process.stdout.isTTY)
|
|
162
|
+
return "json";
|
|
163
|
+
return "table";
|
|
164
|
+
}
|
|
165
|
+
function formatOutput(data, options) {
|
|
166
|
+
const rows = data;
|
|
167
|
+
const format = resolveFormat(options);
|
|
168
|
+
switch (format) {
|
|
169
|
+
case "json":
|
|
170
|
+
return formatJson(rows);
|
|
171
|
+
case "csv":
|
|
172
|
+
return formatCsv(rows);
|
|
173
|
+
case "table":
|
|
174
|
+
return formatTable(rows, {
|
|
175
|
+
columns: options.columns,
|
|
176
|
+
full: options.full ?? false
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
var init_formatters = () => {};
|
|
181
|
+
|
|
182
|
+
// src/cli/ui.ts
|
|
183
|
+
import { spinner } from "@clack/prompts";
|
|
8
184
|
import pc from "picocolors";
|
|
185
|
+
async function withSpinner(message, fn) {
|
|
186
|
+
if (!isTTY) {
|
|
187
|
+
return fn();
|
|
188
|
+
}
|
|
189
|
+
const s = spinner();
|
|
190
|
+
s.start(message);
|
|
191
|
+
try {
|
|
192
|
+
const result = await fn();
|
|
193
|
+
s.stop(message);
|
|
194
|
+
return result;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
s.error("Failed");
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function showSummary(message) {
|
|
201
|
+
if (!isTTY)
|
|
202
|
+
return;
|
|
203
|
+
console.error(pc.dim(message));
|
|
204
|
+
}
|
|
205
|
+
var isTTY;
|
|
206
|
+
var init_ui = __esm(() => {
|
|
207
|
+
isTTY = process.stdout.isTTY === true;
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// src/cli/commands/matches.ts
|
|
211
|
+
var exports_matches = {};
|
|
212
|
+
__export(exports_matches, {
|
|
213
|
+
matchesCommand: () => matchesCommand
|
|
214
|
+
});
|
|
215
|
+
import { defineCommand } from "citty";
|
|
216
|
+
var DEFAULT_COLUMNS, matchesCommand;
|
|
217
|
+
var init_matches = __esm(() => {
|
|
218
|
+
init_src();
|
|
219
|
+
init_formatters();
|
|
220
|
+
init_ui();
|
|
221
|
+
DEFAULT_COLUMNS = [
|
|
222
|
+
{ key: "date", label: "Date", maxWidth: 16 },
|
|
223
|
+
{ key: "roundNumber", label: "Round", maxWidth: 6 },
|
|
224
|
+
{ key: "homeTeam", label: "Home", maxWidth: 20 },
|
|
225
|
+
{ key: "awayTeam", label: "Away", maxWidth: 20 },
|
|
226
|
+
{ key: "homePoints", label: "H.Pts", maxWidth: 6 },
|
|
227
|
+
{ key: "awayPoints", label: "A.Pts", maxWidth: 6 },
|
|
228
|
+
{ key: "venue", label: "Venue", maxWidth: 24 }
|
|
229
|
+
];
|
|
230
|
+
matchesCommand = defineCommand({
|
|
231
|
+
meta: {
|
|
232
|
+
name: "matches",
|
|
233
|
+
description: "Fetch match results for a season"
|
|
234
|
+
},
|
|
235
|
+
args: {
|
|
236
|
+
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
237
|
+
round: { type: "string", description: "Round number" },
|
|
238
|
+
source: { type: "string", description: "Data source", default: "afl-api" },
|
|
239
|
+
competition: {
|
|
240
|
+
type: "string",
|
|
241
|
+
description: "Competition code (AFLM or AFLW)",
|
|
242
|
+
default: "AFLM"
|
|
243
|
+
},
|
|
244
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
245
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
246
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
247
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
248
|
+
},
|
|
249
|
+
async run({ args }) {
|
|
250
|
+
const season = Number(args.season);
|
|
251
|
+
const round = args.round ? Number(args.round) : undefined;
|
|
252
|
+
const result = await withSpinner("Fetching match results…", () => fetchMatchResults({
|
|
253
|
+
source: args.source,
|
|
254
|
+
season,
|
|
255
|
+
round,
|
|
256
|
+
competition: args.competition
|
|
257
|
+
}));
|
|
258
|
+
if (!result.success) {
|
|
259
|
+
throw result.error;
|
|
260
|
+
}
|
|
261
|
+
const data = result.data;
|
|
262
|
+
showSummary(`Loaded ${data.length} matches for ${season}${round ? ` round ${round}` : ""}`);
|
|
263
|
+
const formatOptions = {
|
|
264
|
+
json: args.json,
|
|
265
|
+
csv: args.csv,
|
|
266
|
+
format: args.format,
|
|
267
|
+
full: args.full,
|
|
268
|
+
columns: DEFAULT_COLUMNS
|
|
269
|
+
};
|
|
270
|
+
console.log(formatOutput(data, formatOptions));
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// src/cli/commands/stats.ts
|
|
276
|
+
var exports_stats = {};
|
|
277
|
+
__export(exports_stats, {
|
|
278
|
+
statsCommand: () => statsCommand
|
|
279
|
+
});
|
|
280
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
281
|
+
var DEFAULT_COLUMNS2, statsCommand;
|
|
282
|
+
var init_stats = __esm(() => {
|
|
283
|
+
init_src();
|
|
284
|
+
init_formatters();
|
|
285
|
+
init_ui();
|
|
286
|
+
DEFAULT_COLUMNS2 = [
|
|
287
|
+
{ key: "displayName", label: "Player", maxWidth: 22 },
|
|
288
|
+
{ key: "team", label: "Team", maxWidth: 18 },
|
|
289
|
+
{ key: "disposals", label: "Disp", maxWidth: 6 },
|
|
290
|
+
{ key: "kicks", label: "Kicks", maxWidth: 6 },
|
|
291
|
+
{ key: "handballs", label: "HB", maxWidth: 6 },
|
|
292
|
+
{ key: "marks", label: "Marks", maxWidth: 6 },
|
|
293
|
+
{ key: "goals", label: "Goals", maxWidth: 6 }
|
|
294
|
+
];
|
|
295
|
+
statsCommand = defineCommand2({
|
|
296
|
+
meta: {
|
|
297
|
+
name: "stats",
|
|
298
|
+
description: "Fetch player statistics for a season"
|
|
299
|
+
},
|
|
300
|
+
args: {
|
|
301
|
+
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
302
|
+
round: { type: "string", description: "Round number" },
|
|
303
|
+
"match-id": { type: "string", description: "Specific match ID" },
|
|
304
|
+
source: { type: "string", description: "Data source", default: "afl-api" },
|
|
305
|
+
competition: {
|
|
306
|
+
type: "string",
|
|
307
|
+
description: "Competition code (AFLM or AFLW)",
|
|
308
|
+
default: "AFLM"
|
|
309
|
+
},
|
|
310
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
311
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
312
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
313
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
314
|
+
},
|
|
315
|
+
async run({ args }) {
|
|
316
|
+
const season = Number(args.season);
|
|
317
|
+
const round = args.round ? Number(args.round) : undefined;
|
|
318
|
+
const matchId = args["match-id"];
|
|
319
|
+
const result = await withSpinner("Fetching player stats…", () => fetchPlayerStats({
|
|
320
|
+
source: args.source,
|
|
321
|
+
season,
|
|
322
|
+
round,
|
|
323
|
+
matchId,
|
|
324
|
+
competition: args.competition
|
|
325
|
+
}));
|
|
326
|
+
if (!result.success) {
|
|
327
|
+
throw result.error;
|
|
328
|
+
}
|
|
329
|
+
const data = result.data;
|
|
330
|
+
showSummary(`Loaded ${data.length} player stat lines for ${season}${round ? ` round ${round}` : ""}`);
|
|
331
|
+
const formatOptions = {
|
|
332
|
+
json: args.json,
|
|
333
|
+
csv: args.csv,
|
|
334
|
+
format: args.format,
|
|
335
|
+
full: args.full,
|
|
336
|
+
columns: DEFAULT_COLUMNS2
|
|
337
|
+
};
|
|
338
|
+
console.log(formatOutput(data, formatOptions));
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// src/cli/commands/fixture.ts
|
|
344
|
+
var exports_fixture = {};
|
|
345
|
+
__export(exports_fixture, {
|
|
346
|
+
fixtureCommand: () => fixtureCommand
|
|
347
|
+
});
|
|
348
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
349
|
+
var DEFAULT_COLUMNS3, fixtureCommand;
|
|
350
|
+
var init_fixture = __esm(() => {
|
|
351
|
+
init_src();
|
|
352
|
+
init_formatters();
|
|
353
|
+
init_ui();
|
|
354
|
+
DEFAULT_COLUMNS3 = [
|
|
355
|
+
{ key: "roundNumber", label: "Round", maxWidth: 6 },
|
|
356
|
+
{ key: "date", label: "Date", maxWidth: 16 },
|
|
357
|
+
{ key: "homeTeam", label: "Home", maxWidth: 20 },
|
|
358
|
+
{ key: "awayTeam", label: "Away", maxWidth: 20 },
|
|
359
|
+
{ key: "venue", label: "Venue", maxWidth: 24 }
|
|
360
|
+
];
|
|
361
|
+
fixtureCommand = defineCommand3({
|
|
362
|
+
meta: {
|
|
363
|
+
name: "fixture",
|
|
364
|
+
description: "Fetch fixture/schedule for a season"
|
|
365
|
+
},
|
|
366
|
+
args: {
|
|
367
|
+
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
368
|
+
round: { type: "string", description: "Round number" },
|
|
369
|
+
source: { type: "string", description: "Data source", default: "afl-api" },
|
|
370
|
+
competition: {
|
|
371
|
+
type: "string",
|
|
372
|
+
description: "Competition code (AFLM or AFLW)",
|
|
373
|
+
default: "AFLM"
|
|
374
|
+
},
|
|
375
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
376
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
377
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
378
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
379
|
+
},
|
|
380
|
+
async run({ args }) {
|
|
381
|
+
const season = Number(args.season);
|
|
382
|
+
const round = args.round ? Number(args.round) : undefined;
|
|
383
|
+
const result = await withSpinner("Fetching fixture…", () => fetchFixture({
|
|
384
|
+
source: args.source,
|
|
385
|
+
season,
|
|
386
|
+
round,
|
|
387
|
+
competition: args.competition
|
|
388
|
+
}));
|
|
389
|
+
if (!result.success) {
|
|
390
|
+
throw result.error;
|
|
391
|
+
}
|
|
392
|
+
const data = result.data;
|
|
393
|
+
showSummary(`Loaded ${data.length} fixtures for ${season}${round ? ` round ${round}` : ""}`);
|
|
394
|
+
const formatOptions = {
|
|
395
|
+
json: args.json,
|
|
396
|
+
csv: args.csv,
|
|
397
|
+
format: args.format,
|
|
398
|
+
full: args.full,
|
|
399
|
+
columns: DEFAULT_COLUMNS3
|
|
400
|
+
};
|
|
401
|
+
console.log(formatOutput(data, formatOptions));
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// src/cli/commands/ladder.ts
|
|
407
|
+
var exports_ladder = {};
|
|
408
|
+
__export(exports_ladder, {
|
|
409
|
+
ladderCommand: () => ladderCommand
|
|
410
|
+
});
|
|
411
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
412
|
+
var DEFAULT_COLUMNS4, ladderCommand;
|
|
413
|
+
var init_ladder = __esm(() => {
|
|
414
|
+
init_src();
|
|
415
|
+
init_formatters();
|
|
416
|
+
init_ui();
|
|
417
|
+
DEFAULT_COLUMNS4 = [
|
|
418
|
+
{ key: "position", label: "Pos", maxWidth: 4 },
|
|
419
|
+
{ key: "team", label: "Team", maxWidth: 24 },
|
|
420
|
+
{ key: "wins", label: "W", maxWidth: 4 },
|
|
421
|
+
{ key: "losses", label: "L", maxWidth: 4 },
|
|
422
|
+
{ key: "draws", label: "D", maxWidth: 4 },
|
|
423
|
+
{ key: "percentage", label: "Pct", maxWidth: 8 },
|
|
424
|
+
{ key: "premiershipsPoints", label: "Pts", maxWidth: 5 }
|
|
425
|
+
];
|
|
426
|
+
ladderCommand = defineCommand4({
|
|
427
|
+
meta: {
|
|
428
|
+
name: "ladder",
|
|
429
|
+
description: "Fetch ladder standings for a season"
|
|
430
|
+
},
|
|
431
|
+
args: {
|
|
432
|
+
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
433
|
+
round: { type: "string", description: "Round number" },
|
|
434
|
+
source: { type: "string", description: "Data source", default: "afl-api" },
|
|
435
|
+
competition: {
|
|
436
|
+
type: "string",
|
|
437
|
+
description: "Competition code (AFLM or AFLW)",
|
|
438
|
+
default: "AFLM"
|
|
439
|
+
},
|
|
440
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
441
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
442
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
443
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
444
|
+
},
|
|
445
|
+
async run({ args }) {
|
|
446
|
+
const season = Number(args.season);
|
|
447
|
+
const round = args.round ? Number(args.round) : undefined;
|
|
448
|
+
const result = await withSpinner("Fetching ladder…", () => fetchLadder({
|
|
449
|
+
source: args.source,
|
|
450
|
+
season,
|
|
451
|
+
round,
|
|
452
|
+
competition: args.competition
|
|
453
|
+
}));
|
|
454
|
+
if (!result.success) {
|
|
455
|
+
throw result.error;
|
|
456
|
+
}
|
|
457
|
+
const data = result.data;
|
|
458
|
+
showSummary(`Loaded ladder for ${season}${round ? ` round ${round}` : ""} (${data.entries.length} teams)`);
|
|
459
|
+
const formatOptions = {
|
|
460
|
+
json: args.json,
|
|
461
|
+
csv: args.csv,
|
|
462
|
+
format: args.format,
|
|
463
|
+
full: args.full,
|
|
464
|
+
columns: DEFAULT_COLUMNS4
|
|
465
|
+
};
|
|
466
|
+
console.log(formatOutput(data.entries, formatOptions));
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// src/cli/commands/lineup.ts
|
|
472
|
+
var exports_lineup = {};
|
|
473
|
+
__export(exports_lineup, {
|
|
474
|
+
lineupCommand: () => lineupCommand
|
|
475
|
+
});
|
|
476
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
477
|
+
var DEFAULT_COLUMNS5, lineupCommand;
|
|
478
|
+
var init_lineup = __esm(() => {
|
|
479
|
+
init_src();
|
|
480
|
+
init_formatters();
|
|
481
|
+
init_ui();
|
|
482
|
+
DEFAULT_COLUMNS5 = [
|
|
483
|
+
{ key: "matchId", label: "Match", maxWidth: 12 },
|
|
484
|
+
{ key: "homeTeam", label: "Home", maxWidth: 20 },
|
|
485
|
+
{ key: "awayTeam", label: "Away", maxWidth: 20 }
|
|
486
|
+
];
|
|
487
|
+
lineupCommand = defineCommand5({
|
|
488
|
+
meta: {
|
|
489
|
+
name: "lineup",
|
|
490
|
+
description: "Fetch match lineups for a round"
|
|
491
|
+
},
|
|
492
|
+
args: {
|
|
493
|
+
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
494
|
+
round: { type: "string", description: "Round number", required: true },
|
|
495
|
+
"match-id": { type: "string", description: "Specific match ID" },
|
|
496
|
+
source: { type: "string", description: "Data source", default: "afl-api" },
|
|
497
|
+
competition: {
|
|
498
|
+
type: "string",
|
|
499
|
+
description: "Competition code (AFLM or AFLW)",
|
|
500
|
+
default: "AFLM"
|
|
501
|
+
},
|
|
502
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
503
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
504
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
505
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
506
|
+
},
|
|
507
|
+
async run({ args }) {
|
|
508
|
+
const season = Number(args.season);
|
|
509
|
+
const round = Number(args.round);
|
|
510
|
+
const matchId = args["match-id"];
|
|
511
|
+
const result = await withSpinner("Fetching lineups…", () => fetchLineup({
|
|
512
|
+
source: args.source,
|
|
513
|
+
season,
|
|
514
|
+
round,
|
|
515
|
+
matchId,
|
|
516
|
+
competition: args.competition
|
|
517
|
+
}));
|
|
518
|
+
if (!result.success) {
|
|
519
|
+
throw result.error;
|
|
520
|
+
}
|
|
521
|
+
const data = result.data;
|
|
522
|
+
showSummary(`Loaded ${data.length} lineups for ${season} round ${round}`);
|
|
523
|
+
const formatOptions = {
|
|
524
|
+
json: args.json,
|
|
525
|
+
csv: args.csv,
|
|
526
|
+
format: args.format,
|
|
527
|
+
full: args.full,
|
|
528
|
+
columns: DEFAULT_COLUMNS5
|
|
529
|
+
};
|
|
530
|
+
console.log(formatOutput(data, formatOptions));
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// src/cli/commands/squad.ts
|
|
536
|
+
var exports_squad = {};
|
|
537
|
+
__export(exports_squad, {
|
|
538
|
+
squadCommand: () => squadCommand
|
|
539
|
+
});
|
|
540
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
541
|
+
var DEFAULT_COLUMNS6, squadCommand;
|
|
542
|
+
var init_squad = __esm(() => {
|
|
543
|
+
init_src();
|
|
544
|
+
init_formatters();
|
|
545
|
+
init_ui();
|
|
546
|
+
DEFAULT_COLUMNS6 = [
|
|
547
|
+
{ key: "displayName", label: "Player", maxWidth: 24 },
|
|
548
|
+
{ key: "jumperNumber", label: "#", maxWidth: 4 },
|
|
549
|
+
{ key: "position", label: "Pos", maxWidth: 12 },
|
|
550
|
+
{ key: "heightCm", label: "Ht", maxWidth: 5 },
|
|
551
|
+
{ key: "weightKg", label: "Wt", maxWidth: 5 }
|
|
552
|
+
];
|
|
553
|
+
squadCommand = defineCommand6({
|
|
554
|
+
meta: {
|
|
555
|
+
name: "squad",
|
|
556
|
+
description: "Fetch team squad for a season"
|
|
557
|
+
},
|
|
558
|
+
args: {
|
|
559
|
+
"team-id": { type: "string", description: "Team ID", required: true },
|
|
560
|
+
season: { type: "string", description: "Season year (e.g. 2025)", required: true },
|
|
561
|
+
competition: {
|
|
562
|
+
type: "string",
|
|
563
|
+
description: "Competition code (AFLM or AFLW)",
|
|
564
|
+
default: "AFLM"
|
|
565
|
+
},
|
|
566
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
567
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
568
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
569
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
570
|
+
},
|
|
571
|
+
async run({ args }) {
|
|
572
|
+
const teamId = args["team-id"];
|
|
573
|
+
const season = Number(args.season);
|
|
574
|
+
const result = await withSpinner("Fetching squad…", () => fetchSquad({
|
|
575
|
+
teamId,
|
|
576
|
+
season,
|
|
577
|
+
competition: args.competition
|
|
578
|
+
}));
|
|
579
|
+
if (!result.success) {
|
|
580
|
+
throw result.error;
|
|
581
|
+
}
|
|
582
|
+
const data = result.data;
|
|
583
|
+
showSummary(`Loaded ${data.players.length} players for ${data.teamName} ${season}`);
|
|
584
|
+
const formatOptions = {
|
|
585
|
+
json: args.json,
|
|
586
|
+
csv: args.csv,
|
|
587
|
+
format: args.format,
|
|
588
|
+
full: args.full,
|
|
589
|
+
columns: DEFAULT_COLUMNS6
|
|
590
|
+
};
|
|
591
|
+
console.log(formatOutput(data.players, formatOptions));
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
// src/cli/commands/teams.ts
|
|
597
|
+
var exports_teams = {};
|
|
598
|
+
__export(exports_teams, {
|
|
599
|
+
teamsCommand: () => teamsCommand
|
|
600
|
+
});
|
|
601
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
602
|
+
var DEFAULT_COLUMNS7, teamsCommand;
|
|
603
|
+
var init_teams = __esm(() => {
|
|
604
|
+
init_src();
|
|
605
|
+
init_formatters();
|
|
606
|
+
init_ui();
|
|
607
|
+
DEFAULT_COLUMNS7 = [
|
|
608
|
+
{ key: "teamId", label: "ID", maxWidth: 8 },
|
|
609
|
+
{ key: "name", label: "Team", maxWidth: 24 },
|
|
610
|
+
{ key: "abbreviation", label: "Abbr", maxWidth: 6 },
|
|
611
|
+
{ key: "competition", label: "Comp", maxWidth: 6 }
|
|
612
|
+
];
|
|
613
|
+
teamsCommand = defineCommand7({
|
|
614
|
+
meta: {
|
|
615
|
+
name: "teams",
|
|
616
|
+
description: "Fetch team list"
|
|
617
|
+
},
|
|
618
|
+
args: {
|
|
619
|
+
competition: { type: "string", description: "Competition code (AFLM or AFLW)" },
|
|
620
|
+
"team-type": { type: "string", description: "Team type filter" },
|
|
621
|
+
json: { type: "boolean", description: "Output as JSON" },
|
|
622
|
+
csv: { type: "boolean", description: "Output as CSV" },
|
|
623
|
+
format: { type: "string", description: "Output format: table, json, csv" },
|
|
624
|
+
full: { type: "boolean", description: "Show all columns in table output" }
|
|
625
|
+
},
|
|
626
|
+
async run({ args }) {
|
|
627
|
+
const result = await withSpinner("Fetching teams…", () => fetchTeams({
|
|
628
|
+
competition: args.competition,
|
|
629
|
+
teamType: args["team-type"]
|
|
630
|
+
}));
|
|
631
|
+
if (!result.success) {
|
|
632
|
+
throw result.error;
|
|
633
|
+
}
|
|
634
|
+
const data = result.data;
|
|
635
|
+
showSummary(`Loaded ${data.length} teams`);
|
|
636
|
+
const formatOptions = {
|
|
637
|
+
json: args.json,
|
|
638
|
+
csv: args.csv,
|
|
639
|
+
format: args.format,
|
|
640
|
+
full: args.full,
|
|
641
|
+
columns: DEFAULT_COLUMNS7
|
|
642
|
+
};
|
|
643
|
+
console.log(formatOutput(data, formatOptions));
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
// src/cli.ts
|
|
649
|
+
import { defineCommand as defineCommand8, runMain } from "citty";
|
|
650
|
+
import pc2 from "picocolors";
|
|
9
651
|
|
|
10
652
|
// src/lib/errors.ts
|
|
11
653
|
class AflApiError extends Error {
|
|
@@ -45,44 +687,44 @@ class ValidationError extends Error {
|
|
|
45
687
|
}
|
|
46
688
|
|
|
47
689
|
// src/cli.ts
|
|
48
|
-
var main =
|
|
690
|
+
var main = defineCommand8({
|
|
49
691
|
meta: {
|
|
50
692
|
name: "fitzroy",
|
|
51
|
-
version: "1.0.
|
|
693
|
+
version: "1.0.1",
|
|
52
694
|
description: "CLI for fetching AFL data — match results, player stats, fixtures, ladders, and more"
|
|
53
695
|
},
|
|
54
696
|
subCommands: {
|
|
55
|
-
matches: () =>
|
|
56
|
-
stats: () =>
|
|
57
|
-
fixture: () =>
|
|
58
|
-
ladder: () =>
|
|
59
|
-
lineup: () =>
|
|
60
|
-
squad: () =>
|
|
61
|
-
teams: () =>
|
|
697
|
+
matches: () => Promise.resolve().then(() => (init_matches(), exports_matches)).then((m) => m.matchesCommand),
|
|
698
|
+
stats: () => Promise.resolve().then(() => (init_stats(), exports_stats)).then((m) => m.statsCommand),
|
|
699
|
+
fixture: () => Promise.resolve().then(() => (init_fixture(), exports_fixture)).then((m) => m.fixtureCommand),
|
|
700
|
+
ladder: () => Promise.resolve().then(() => (init_ladder(), exports_ladder)).then((m) => m.ladderCommand),
|
|
701
|
+
lineup: () => Promise.resolve().then(() => (init_lineup(), exports_lineup)).then((m) => m.lineupCommand),
|
|
702
|
+
squad: () => Promise.resolve().then(() => (init_squad(), exports_squad)).then((m) => m.squadCommand),
|
|
703
|
+
teams: () => Promise.resolve().then(() => (init_teams(), exports_teams)).then((m) => m.teamsCommand)
|
|
62
704
|
}
|
|
63
705
|
});
|
|
64
706
|
function formatError(error) {
|
|
65
707
|
if (error instanceof ValidationError && error.issues) {
|
|
66
|
-
const issueLines = error.issues.map((i) => ` ${
|
|
67
|
-
return `${
|
|
708
|
+
const issueLines = error.issues.map((i) => ` ${pc2.yellow(i.path)}: ${i.message}`);
|
|
709
|
+
return `${pc2.red("Validation error:")}
|
|
68
710
|
${issueLines.join(`
|
|
69
711
|
`)}`;
|
|
70
712
|
}
|
|
71
713
|
if (error instanceof AflApiError) {
|
|
72
714
|
const status = error.statusCode ? ` (HTTP ${error.statusCode})` : "";
|
|
73
|
-
return `${
|
|
715
|
+
return `${pc2.red("AFL API error:")} ${error.message}${status}`;
|
|
74
716
|
}
|
|
75
717
|
if (error instanceof ScrapeError) {
|
|
76
718
|
const source = error.source ? ` [${error.source}]` : "";
|
|
77
|
-
return `${
|
|
719
|
+
return `${pc2.red("Scrape error:")} ${error.message}${source}`;
|
|
78
720
|
}
|
|
79
721
|
if (error instanceof UnsupportedSourceError) {
|
|
80
|
-
return `${
|
|
722
|
+
return `${pc2.red("Unsupported source:")} ${error.message}`;
|
|
81
723
|
}
|
|
82
724
|
if (error instanceof Error) {
|
|
83
|
-
return `${
|
|
725
|
+
return `${pc2.red("Error:")} ${error.message}`;
|
|
84
726
|
}
|
|
85
|
-
return `${
|
|
727
|
+
return `${pc2.red("Error:")} ${String(error)}`;
|
|
86
728
|
}
|
|
87
729
|
runMain(main).catch((error) => {
|
|
88
730
|
console.error(formatError(error));
|