fitzroy 1.0.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.
@@ -0,0 +1,185 @@
1
+ // src/cli/formatters/csv.ts
2
+ function escapeField(value) {
3
+ if (value.includes(",") || value.includes('"') || value.includes(`
4
+ `) || value.includes("\r")) {
5
+ return `"${value.replace(/"/g, '""')}"`;
6
+ }
7
+ return value;
8
+ }
9
+ function toStringValue(value) {
10
+ if (value === null || value === undefined)
11
+ return "";
12
+ if (value instanceof Date)
13
+ return value.toISOString();
14
+ if (typeof value === "object")
15
+ return JSON.stringify(value);
16
+ return String(value);
17
+ }
18
+ function formatCsv(data) {
19
+ if (data.length === 0)
20
+ return "";
21
+ const firstRow = data[0];
22
+ if (!firstRow)
23
+ return "";
24
+ const headers = Object.keys(firstRow);
25
+ const lines = [headers.map(escapeField).join(",")];
26
+ for (const row of data) {
27
+ const values = headers.map((h) => escapeField(toStringValue(row[h])));
28
+ lines.push(values.join(","));
29
+ }
30
+ return lines.join(`
31
+ `);
32
+ }
33
+
34
+ // src/cli/formatters/json.ts
35
+ function formatJson(data) {
36
+ return JSON.stringify(data, null, 2);
37
+ }
38
+
39
+ // src/cli/formatters/table.ts
40
+ function toDisplayValue(value) {
41
+ if (value === null || value === undefined)
42
+ return "-";
43
+ if (value instanceof Date)
44
+ return value.toISOString().slice(0, 16).replace("T", " ");
45
+ if (typeof value === "object")
46
+ return JSON.stringify(value);
47
+ return String(value);
48
+ }
49
+ function truncate(str, maxLen) {
50
+ if (str.length <= maxLen)
51
+ return str;
52
+ return `${str.slice(0, maxLen - 1)}…`;
53
+ }
54
+ function formatTable(data, options = {}) {
55
+ if (data.length === 0)
56
+ return "No data.";
57
+ const firstRow = data[0];
58
+ if (!firstRow)
59
+ return "No data.";
60
+ const termWidth = options.terminalWidth ?? process.stdout.columns ?? 120;
61
+ const allKeys = Object.keys(firstRow);
62
+ let columns;
63
+ if (options.full || !options.columns || options.columns.length === 0) {
64
+ columns = allKeys.map((key) => ({ key }));
65
+ } else {
66
+ columns = [...options.columns];
67
+ }
68
+ const colWidths = columns.map((col) => (col.label ?? col.key).length);
69
+ for (const row of data) {
70
+ for (let i = 0;i < columns.length; i++) {
71
+ const col = columns[i];
72
+ if (!col)
73
+ continue;
74
+ const len = toDisplayValue(row[col.key]).length;
75
+ const current = colWidths[i];
76
+ if (current !== undefined && len > current) {
77
+ colWidths[i] = len;
78
+ }
79
+ }
80
+ }
81
+ for (let i = 0;i < columns.length; i++) {
82
+ const col = columns[i];
83
+ const width = colWidths[i];
84
+ if (!col || width === undefined)
85
+ continue;
86
+ colWidths[i] = Math.min(col.maxWidth ?? 30, width);
87
+ }
88
+ const gap = 2;
89
+ const visibleCols = [];
90
+ let usedWidth = 0;
91
+ for (let i = 0;i < columns.length; i++) {
92
+ const colWidth = colWidths[i];
93
+ if (colWidth === undefined)
94
+ continue;
95
+ const needed = usedWidth > 0 ? colWidth + gap : colWidth;
96
+ if (usedWidth + needed > termWidth && visibleCols.length > 0)
97
+ break;
98
+ visibleCols.push(i);
99
+ usedWidth += needed;
100
+ }
101
+ const headerParts = visibleCols.map((i) => {
102
+ const col = columns[i];
103
+ const width = colWidths[i];
104
+ if (!col || width === undefined)
105
+ return "";
106
+ const label = (col.label ?? col.key).toUpperCase();
107
+ return truncate(label, width).padEnd(width);
108
+ });
109
+ const header = headerParts.join(" ");
110
+ const separator = visibleCols.map((i) => {
111
+ const width = colWidths[i];
112
+ if (width === undefined)
113
+ return "";
114
+ return "─".repeat(width);
115
+ }).join(" ");
116
+ const rows = data.map((row) => {
117
+ const parts = visibleCols.map((i) => {
118
+ const col = columns[i];
119
+ const width = colWidths[i];
120
+ if (!col || width === undefined)
121
+ return "";
122
+ const val = toDisplayValue(row[col.key]);
123
+ return truncate(val, width).padEnd(width);
124
+ });
125
+ return parts.join(" ");
126
+ });
127
+ return [header, separator, ...rows].join(`
128
+ `);
129
+ }
130
+
131
+ // src/cli/formatters/index.ts
132
+ function resolveFormat(options) {
133
+ if (options.json)
134
+ return "json";
135
+ if (options.csv)
136
+ return "csv";
137
+ if (options.format === "json" || options.format === "csv" || options.format === "table") {
138
+ return options.format;
139
+ }
140
+ if (!process.stdout.isTTY)
141
+ return "json";
142
+ return "table";
143
+ }
144
+ function formatOutput(data, options) {
145
+ const rows = data;
146
+ const format = resolveFormat(options);
147
+ switch (format) {
148
+ case "json":
149
+ return formatJson(rows);
150
+ case "csv":
151
+ return formatCsv(rows);
152
+ case "table":
153
+ return formatTable(rows, {
154
+ columns: options.columns,
155
+ full: options.full ?? false
156
+ });
157
+ }
158
+ }
159
+
160
+ // src/cli/ui.ts
161
+ import { spinner } from "@clack/prompts";
162
+ import pc from "picocolors";
163
+ var isTTY = process.stdout.isTTY === true;
164
+ async function withSpinner(message, fn) {
165
+ if (!isTTY) {
166
+ return fn();
167
+ }
168
+ const s = spinner();
169
+ s.start(message);
170
+ try {
171
+ const result = await fn();
172
+ s.stop(message);
173
+ return result;
174
+ } catch (error) {
175
+ s.error("Failed");
176
+ throw error;
177
+ }
178
+ }
179
+ function showSummary(message) {
180
+ if (!isTTY)
181
+ return;
182
+ console.error(pc.dim(message));
183
+ }
184
+
185
+ export { formatOutput, withSpinner, showSummary };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "fitzroy",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript library and CLI for AFL data — match results, player stats, fixtures, ladders, and more",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "bin": {
15
+ "fitzroy": "./dist/cli.js"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "sideEffects": false,
21
+ "engines": {
22
+ "node": ">=20"
23
+ },
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/jackemcpherson/fitzRoy-ts.git"
28
+ },
29
+ "keywords": [
30
+ "afl",
31
+ "australian-football",
32
+ "sports-data",
33
+ "fitzroy",
34
+ "aflw"
35
+ ],
36
+ "scripts": {
37
+ "build": "bunup",
38
+ "test": "vitest",
39
+ "check": "biome check .",
40
+ "format": "biome format --write .",
41
+ "typecheck": "tsc --noEmit",
42
+ "prepublishOnly": "bun run build"
43
+ },
44
+ "dependencies": {
45
+ "@clack/prompts": "^1.1.0",
46
+ "cheerio": "^1.0.0",
47
+ "citty": "^0.2.1",
48
+ "picocolors": "^1.1.1",
49
+ "zod": "^4.3.6"
50
+ },
51
+ "devDependencies": {
52
+ "@biomejs/biome": "^2.4.9",
53
+ "@types/node": "^25.5.0",
54
+ "bunup": "^0.16.31",
55
+ "typescript": "^6.0.2",
56
+ "vitest": "^4.1.1"
57
+ }
58
+ }