fitzroy 1.3.1 → 1.4.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 CHANGED
@@ -315,6 +315,62 @@ var init_team_mapping = __esm({
315
315
  }
316
316
  });
317
317
 
318
+ // src/lib/venue-mapping.ts
319
+ function normaliseVenueName(raw) {
320
+ const trimmed = raw.trim();
321
+ return VENUE_ALIAS_MAP.get(trimmed.toLowerCase()) ?? trimmed;
322
+ }
323
+ var VENUE_ALIASES, VENUE_ALIAS_MAP;
324
+ var init_venue_mapping = __esm({
325
+ "src/lib/venue-mapping.ts"() {
326
+ "use strict";
327
+ VENUE_ALIASES = [
328
+ ["MCG", "M.C.G.", "Melbourne Cricket Ground"],
329
+ ["SCG", "S.C.G.", "Sydney Cricket Ground"],
330
+ ["Marvel Stadium", "Docklands", "Etihad Stadium", "Telstra Dome", "Colonial Stadium"],
331
+ ["Kardinia Park", "GMHBA Stadium", "Simonds Stadium", "Skilled Stadium"],
332
+ ["Gabba", "The Gabba", "Brisbane Cricket Ground"],
333
+ [
334
+ "Sydney Showground",
335
+ "ENGIE Stadium",
336
+ "GIANTS Stadium",
337
+ "Showground Stadium",
338
+ "Sydney Showground Stadium"
339
+ ],
340
+ ["Accor Stadium", "Stadium Australia", "ANZ Stadium", "Homebush"],
341
+ ["Carrara", "People First Stadium", "Heritage Bank Stadium", "Metricon Stadium"],
342
+ ["Perth Stadium", "Optus Stadium"],
343
+ ["Adelaide Oval"],
344
+ ["Manuka Oval", "Corroboree Group Oval Manuka"],
345
+ ["Blundstone Arena", "Bellerive Oval"],
346
+ ["UTAS Stadium", "York Park", "University of Tasmania Stadium", "Aurora Stadium"],
347
+ ["TIO Stadium", "Marrara Oval"],
348
+ ["Traeger Park", "TIO Traeger Park"],
349
+ ["Mars Stadium", "Eureka Stadium"],
350
+ ["Cazalys Stadium", "Cazaly's Stadium"],
351
+ ["Jiangwan Stadium"],
352
+ ["Riverway Stadium"],
353
+ ["Norwood Oval"],
354
+ ["Subiaco Oval", "Subiaco"],
355
+ ["Football Park", "AAMI Stadium"],
356
+ ["Princes Park", "Ikon Park"],
357
+ ["Blacktown International Sportspark"],
358
+ ["Barossa Park", "Barossa Oval", "Adelaide Hills"],
359
+ ["Ninja Stadium", "Summit Sports Park"]
360
+ ];
361
+ VENUE_ALIAS_MAP = (() => {
362
+ const map = /* @__PURE__ */ new Map();
363
+ for (const [canonical, ...aliases] of VENUE_ALIASES) {
364
+ map.set(canonical.toLowerCase(), canonical);
365
+ for (const alias of aliases) {
366
+ map.set(alias.toLowerCase(), canonical);
367
+ }
368
+ }
369
+ return map;
370
+ })();
371
+ }
372
+ });
373
+
318
374
  // src/lib/parse-utils.ts
319
375
  function safeInt(text) {
320
376
  const cleaned = text.replace(/[^0-9-]/g, "").trim();
@@ -357,7 +413,7 @@ function parseStatsTable(html, expectedCols, rowParser) {
357
413
  const headerText = teamHeader.text().trim();
358
414
  const match = /^(\w[\w\s]+?)\s+Match Statistics/i.exec(headerText);
359
415
  if (match?.[1]) {
360
- teamName = match[1].trim();
416
+ teamName = normaliseTeamName(match[1].trim());
361
417
  }
362
418
  }
363
419
  const parsed = [];
@@ -530,6 +586,7 @@ var init_footywire_player_stats = __esm({
530
586
  "src/transforms/footywire-player-stats.ts"() {
531
587
  "use strict";
532
588
  init_parse_utils();
589
+ init_team_mapping();
533
590
  BASIC_COLS = [
534
591
  "Player",
535
592
  "K",
@@ -628,7 +685,7 @@ function transformMatchItems(items, season, competition, source = "afl-api") {
628
685
  roundNumber: item.round?.roundNumber ?? 0,
629
686
  roundType: inferRoundType(item.round?.name ?? ""),
630
687
  date: new Date(item.match.utcStartTime),
631
- venue: item.venue?.name ?? "",
688
+ venue: item.venue?.name ? normaliseVenueName(item.venue.name) : "",
632
689
  homeTeam: normaliseTeamName(item.match.homeTeam.name),
633
690
  awayTeam: normaliseTeamName(item.match.awayTeam.name),
634
691
  homeGoals: homeScore?.matchScore.goals ?? 0,
@@ -664,6 +721,7 @@ var init_match_results = __esm({
664
721
  "src/transforms/match-results.ts"() {
665
722
  "use strict";
666
723
  init_team_mapping();
724
+ init_venue_mapping();
667
725
  FINALS_PATTERN = /final|elimination|qualifying|preliminary|semi|grand/i;
668
726
  }
669
727
  });
@@ -723,7 +781,7 @@ function parseMatchList(html, year) {
723
781
  roundNumber: currentRound,
724
782
  roundType: currentRoundType,
725
783
  date,
726
- venue,
784
+ venue: normaliseVenueName(venue),
727
785
  homeTeam,
728
786
  awayTeam,
729
787
  homeGoals,
@@ -799,7 +857,7 @@ function parseFixtureList(html, year) {
799
857
  roundNumber: currentRound,
800
858
  roundType: currentRoundType,
801
859
  date,
802
- venue,
860
+ venue: normaliseVenueName(venue),
803
861
  homeTeam,
804
862
  awayTeam,
805
863
  status: hasScore ? "Complete" : "Upcoming",
@@ -945,6 +1003,7 @@ var init_footywire = __esm({
945
1003
  init_errors();
946
1004
  init_result();
947
1005
  init_team_mapping();
1006
+ init_venue_mapping();
948
1007
  init_footywire_player_stats();
949
1008
  init_match_results();
950
1009
  FOOTYWIRE_BASE = "https://www.footywire.com/afl/footy";
@@ -2235,7 +2294,7 @@ function transformSquiggleGamesToResults(games, season) {
2235
2294
  roundNumber: g.round,
2236
2295
  roundType: inferRoundType(g.roundname),
2237
2296
  date: new Date(g.unixtime * 1e3),
2238
- venue: g.venue,
2297
+ venue: normaliseVenueName(g.venue),
2239
2298
  homeTeam: normaliseTeamName(g.hteam),
2240
2299
  awayTeam: normaliseTeamName(g.ateam),
2241
2300
  homeGoals: g.hgoals ?? 0,
@@ -2272,7 +2331,7 @@ function transformSquiggleGamesToFixture(games, season) {
2272
2331
  roundNumber: g.round,
2273
2332
  roundType: inferRoundType(g.roundname),
2274
2333
  date: new Date(g.unixtime * 1e3),
2275
- venue: g.venue,
2334
+ venue: normaliseVenueName(g.venue),
2276
2335
  homeTeam: normaliseTeamName(g.hteam),
2277
2336
  awayTeam: normaliseTeamName(g.ateam),
2278
2337
  status: toMatchStatus2(g.complete),
@@ -2298,6 +2357,7 @@ var init_squiggle2 = __esm({
2298
2357
  "src/transforms/squiggle.ts"() {
2299
2358
  "use strict";
2300
2359
  init_team_mapping();
2360
+ init_venue_mapping();
2301
2361
  init_match_results();
2302
2362
  }
2303
2363
  });
@@ -2310,7 +2370,7 @@ function toFixture(item, season, fallbackRoundNumber, competition) {
2310
2370
  roundNumber: item.round?.roundNumber ?? fallbackRoundNumber,
2311
2371
  roundType: inferRoundType(item.round?.name ?? ""),
2312
2372
  date: new Date(item.match.utcStartTime),
2313
- venue: item.venue?.name ?? "",
2373
+ venue: normaliseVenueName(item.venue?.name ?? ""),
2314
2374
  homeTeam: normaliseTeamName(item.match.homeTeam.name),
2315
2375
  awayTeam: normaliseTeamName(item.match.awayTeam.name),
2316
2376
  status: toMatchStatus(item.match.status),
@@ -2379,6 +2439,7 @@ var init_fixture = __esm({
2379
2439
  init_errors();
2380
2440
  init_result();
2381
2441
  init_team_mapping();
2442
+ init_venue_mapping();
2382
2443
  init_afl_api();
2383
2444
  init_footywire();
2384
2445
  init_squiggle();
@@ -2555,7 +2616,7 @@ function parseSeasonPage(html, year) {
2555
2616
  const awayPoints = Number.parseInt($(awayCells[2]).text().trim(), 10) || 0;
2556
2617
  const infoText = $(homeCells[3]).text().trim();
2557
2618
  const date = parseDateFromInfo(infoText, year);
2558
- const venue = parseVenueFromInfo($(homeCells[3]).html() ?? "");
2619
+ const venue = normaliseVenueName(parseVenueFromInfo($(homeCells[3]).html() ?? ""));
2559
2620
  const attendance = parseAttendanceFromInfo(infoText);
2560
2621
  const homeFinal = homeQuarters[3];
2561
2622
  const awayFinal = awayQuarters[3];
@@ -2743,6 +2804,7 @@ var init_afl_tables = __esm({
2743
2804
  init_errors();
2744
2805
  init_result();
2745
2806
  init_team_mapping();
2807
+ init_venue_mapping();
2746
2808
  init_afl_tables_player_stats();
2747
2809
  init_match_results();
2748
2810
  AFL_TABLES_BASE = "https://afltables.com/afl/seas";
@@ -3855,9 +3917,17 @@ function escapeField(value) {
3855
3917
  }
3856
3918
  return value;
3857
3919
  }
3920
+ function dateToAestIso(date) {
3921
+ const parts = AEST_ISO_FORMATTER.formatToParts(date);
3922
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
3923
+ const offset = get("timeZoneName");
3924
+ const sign = offset.includes("-") ? "-" : "+";
3925
+ const offsetHours = offset.replace(/[^0-9]/g, "").padStart(2, "0");
3926
+ return `${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}${sign}${offsetHours}:00`;
3927
+ }
3858
3928
  function toStringValue(value) {
3859
3929
  if (value === null || value === void 0) return "";
3860
- if (value instanceof Date) return value.toISOString();
3930
+ if (value instanceof Date) return dateToAestIso(value);
3861
3931
  if (typeof value === "object") return JSON.stringify(value);
3862
3932
  return String(value);
3863
3933
  }
@@ -3873,19 +3943,57 @@ function formatCsv(data) {
3873
3943
  }
3874
3944
  return lines.join("\n");
3875
3945
  }
3946
+ var AEST_ISO_FORMATTER;
3876
3947
  var init_csv = __esm({
3877
3948
  "src/cli/formatters/csv.ts"() {
3878
3949
  "use strict";
3950
+ AEST_ISO_FORMATTER = new Intl.DateTimeFormat("en-AU", {
3951
+ timeZone: "Australia/Melbourne",
3952
+ year: "numeric",
3953
+ month: "2-digit",
3954
+ day: "2-digit",
3955
+ hour: "2-digit",
3956
+ minute: "2-digit",
3957
+ second: "2-digit",
3958
+ hour12: false,
3959
+ timeZoneName: "shortOffset"
3960
+ });
3879
3961
  }
3880
3962
  });
3881
3963
 
3882
3964
  // src/cli/formatters/json.ts
3965
+ function dateToAestIso2(date) {
3966
+ const parts = AEST_ISO_FORMATTER2.formatToParts(date);
3967
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
3968
+ const offset = get("timeZoneName");
3969
+ const sign = offset.includes("-") ? "-" : "+";
3970
+ const offsetHours = offset.replace(/[^0-9]/g, "").padStart(2, "0");
3971
+ return `${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}${sign}${offsetHours}:00`;
3972
+ }
3973
+ function jsonReplacer(_key, value) {
3974
+ if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
3975
+ return dateToAestIso2(new Date(value));
3976
+ }
3977
+ return value;
3978
+ }
3883
3979
  function formatJson(data) {
3884
- return JSON.stringify(data, null, 2);
3980
+ return JSON.stringify(data, jsonReplacer, 2);
3885
3981
  }
3982
+ var AEST_ISO_FORMATTER2;
3886
3983
  var init_json = __esm({
3887
3984
  "src/cli/formatters/json.ts"() {
3888
3985
  "use strict";
3986
+ AEST_ISO_FORMATTER2 = new Intl.DateTimeFormat("en-AU", {
3987
+ timeZone: "Australia/Melbourne",
3988
+ year: "numeric",
3989
+ month: "2-digit",
3990
+ day: "2-digit",
3991
+ hour: "2-digit",
3992
+ minute: "2-digit",
3993
+ second: "2-digit",
3994
+ hour12: false,
3995
+ timeZoneName: "shortOffset"
3996
+ });
3889
3997
  }
3890
3998
  });
3891
3999
 
@@ -5171,8 +5279,8 @@ resolveAliases();
5171
5279
  var main = defineCommand11({
5172
5280
  meta: {
5173
5281
  name: "fitzroy",
5174
- version: "1.3.1",
5175
- description: "CLI for fetching AFL data \u2014 match results, player stats, fixtures, ladders, and more"
5282
+ version: "1.4.1",
5283
+ description: "TypeScript port of the fitzRoy R package \u2014 fetch AFL data from the command line"
5176
5284
  },
5177
5285
  subCommands: {
5178
5286
  matches: () => Promise.resolve().then(() => (init_matches(), matches_exports)).then((m) => m.matchesCommand),
package/dist/index.d.ts CHANGED
@@ -1759,6 +1759,31 @@ declare const LadderResponseSchema: z2.ZodObject<{
1759
1759
  type LadderEntryRaw = z2.infer<typeof LadderEntryRawSchema>;
1760
1760
  /** Inferred type for the ladder API response. */
1761
1761
  type LadderResponse = z2.infer<typeof LadderResponseSchema>;
1762
+ /**
1763
+ * Venue name normalisation across AFL data sources.
1764
+ *
1765
+ * Maps sponsor names, historical names, and abbreviations to stable canonical
1766
+ * venue names. Lookups are case-insensitive.
1767
+ *
1768
+ * @example
1769
+ * ```ts
1770
+ * normaliseVenueName("GMHBA Stadium"); // "Kardinia Park"
1771
+ * normaliseVenueName("Etihad Stadium"); // "Marvel Stadium"
1772
+ * normaliseVenueName("ENGIE Stadium"); // "Sydney Showground"
1773
+ * normaliseVenueName("People First Stadium"); // "Carrara"
1774
+ * ```
1775
+ */
1776
+ /**
1777
+ * Normalise a venue name to its canonical form.
1778
+ *
1779
+ * Performs a case-insensitive lookup against all known venue names,
1780
+ * sponsor names, and historical names. Returns the input unchanged
1781
+ * if no mapping is found.
1782
+ *
1783
+ * @param raw - The raw venue name string from any data source.
1784
+ * @returns The canonical venue name, or the trimmed input if unknown.
1785
+ */
1786
+ declare function normaliseVenueName(raw: string): string;
1762
1787
  import { z as z3 } from "zod/v4";
1763
1788
  /** Options for constructing an {@link AflApiClient}. */
1764
1789
  interface AflApiClientOptions {
@@ -2179,4 +2204,4 @@ declare function transformSquiggleGamesToFixture(games: readonly SquiggleGame[],
2179
2204
  * Transform Squiggle standings into LadderEntry objects.
2180
2205
  */
2181
2206
  declare function transformSquiggleStandings(standings: readonly SquiggleStanding[]): LadderEntry[];
2182
- export { transformSquiggleStandings, transformSquiggleGamesToResults, transformSquiggleGamesToFixture, transformPlayerStats, transformMatchRoster, transformMatchItems, transformLadderEntries, toAestString, parseFootyWireDate, parseAflTablesDate, parseAflApiDate, ok, normaliseTeamName, inferRoundType, fetchTeams2 as fetchTeams, fetchTeamStats2 as fetchTeamStats, fetchSquad2 as fetchSquad, fetchPlayerStats2 as fetchPlayerStats, fetchPlayerDetails, fetchMatchResults, fetchLineup, fetchLadder2 as fetchLadder, fetchFryziggStats, fetchFixture, fetchCoachesVotes, fetchAwards, err, computeLadder, ValidationError, UnsupportedSourceError, TeamStatsSummaryType, TeamStatsQuery, TeamStatsEntry, TeamScoreSchema, TeamScore, TeamQuery, TeamPlayersSchema, TeamPlayers, TeamListSchema, TeamList, TeamItemSchema, TeamItem, Team, SquiggleStandingsResponseSchema, SquiggleStandingsResponse, SquiggleStandingSchema, SquiggleStanding, SquiggleGamesResponseSchema, SquiggleGamesResponse, SquiggleGameSchema, SquiggleGame, SquiggleClientOptions, SquiggleClient, SquadSchema, SquadQuery, SquadPlayerItemSchema, SquadPlayerItem, SquadPlayerInnerSchema, SquadPlayer, SquadListSchema, SquadList, Squad, SeasonRoundQuery, ScrapeError, ScoreSchema, Score, RoundType, RoundSchema, RoundListSchema, RoundList, Round, RosterPlayerSchema, RosterPlayer, RisingStarNomination, Result, QuarterScore, PlayerStatsQuery, PlayerStatsListSchema, PlayerStatsList, PlayerStatsItemSchema, PlayerStatsItem, PlayerStats, PlayerGameStatsSchema, PlayerGameStats, PlayerDetailsQuery, PlayerDetails, PeriodScoreSchema, PeriodScore, Ok, MatchStatus, MatchRosterSchema, MatchRoster, MatchResult, MatchQuery, MatchItemSchema, MatchItemListSchema, MatchItemList, MatchItem, LineupQuery, LineupPlayer, Lineup, LadderResponseSchema, LadderResponse, LadderQuery, LadderEntryRawSchema, LadderEntryRaw, LadderEntry, Ladder, FootyWireClientOptions, FootyWireClient, Fixture, Err, DataSource, CompseasonSchema, CompseasonListSchema, CompseasonList, Compseason, CompetitionSchema, CompetitionListSchema, CompetitionList, CompetitionCode, Competition, CoachesVoteQuery, CoachesVote, CfsVenueSchema, CfsVenue, CfsScoreSchema, CfsScore, CfsMatchTeamSchema, CfsMatchTeam, CfsMatchSchema, CfsMatch, BrownlowVote, AwardType, AwardQuery, Award, AllAustralianSelection, AflTablesClientOptions, AflTablesClient, AflCoachesClientOptions, AflCoachesClient, AflApiTokenSchema, AflApiToken, AflApiError, AflApiClientOptions, AflApiClient };
2207
+ export { transformSquiggleStandings, transformSquiggleGamesToResults, transformSquiggleGamesToFixture, transformPlayerStats, transformMatchRoster, transformMatchItems, transformLadderEntries, toAestString, parseFootyWireDate, parseAflTablesDate, parseAflApiDate, ok, normaliseVenueName, normaliseTeamName, inferRoundType, fetchTeams2 as fetchTeams, fetchTeamStats2 as fetchTeamStats, fetchSquad2 as fetchSquad, fetchPlayerStats2 as fetchPlayerStats, fetchPlayerDetails, fetchMatchResults, fetchLineup, fetchLadder2 as fetchLadder, fetchFryziggStats, fetchFixture, fetchCoachesVotes, fetchAwards, err, computeLadder, ValidationError, UnsupportedSourceError, TeamStatsSummaryType, TeamStatsQuery, TeamStatsEntry, TeamScoreSchema, TeamScore, TeamQuery, TeamPlayersSchema, TeamPlayers, TeamListSchema, TeamList, TeamItemSchema, TeamItem, Team, SquiggleStandingsResponseSchema, SquiggleStandingsResponse, SquiggleStandingSchema, SquiggleStanding, SquiggleGamesResponseSchema, SquiggleGamesResponse, SquiggleGameSchema, SquiggleGame, SquiggleClientOptions, SquiggleClient, SquadSchema, SquadQuery, SquadPlayerItemSchema, SquadPlayerItem, SquadPlayerInnerSchema, SquadPlayer, SquadListSchema, SquadList, Squad, SeasonRoundQuery, ScrapeError, ScoreSchema, Score, RoundType, RoundSchema, RoundListSchema, RoundList, Round, RosterPlayerSchema, RosterPlayer, RisingStarNomination, Result, QuarterScore, PlayerStatsQuery, PlayerStatsListSchema, PlayerStatsList, PlayerStatsItemSchema, PlayerStatsItem, PlayerStats, PlayerGameStatsSchema, PlayerGameStats, PlayerDetailsQuery, PlayerDetails, PeriodScoreSchema, PeriodScore, Ok, MatchStatus, MatchRosterSchema, MatchRoster, MatchResult, MatchQuery, MatchItemSchema, MatchItemListSchema, MatchItemList, MatchItem, LineupQuery, LineupPlayer, Lineup, LadderResponseSchema, LadderResponse, LadderQuery, LadderEntryRawSchema, LadderEntryRaw, LadderEntry, Ladder, FootyWireClientOptions, FootyWireClient, Fixture, Err, DataSource, CompseasonSchema, CompseasonListSchema, CompseasonList, Compseason, CompetitionSchema, CompetitionListSchema, CompetitionList, CompetitionCode, Competition, CoachesVoteQuery, CoachesVote, CfsVenueSchema, CfsVenue, CfsScoreSchema, CfsScore, CfsMatchTeamSchema, CfsMatchTeam, CfsMatchSchema, CfsMatch, BrownlowVote, AwardType, AwardQuery, Award, AllAustralianSelection, AflTablesClientOptions, AflTablesClient, AflCoachesClientOptions, AflCoachesClient, AflApiTokenSchema, AflApiToken, AflApiError, AflApiClientOptions, AflApiClient };
package/dist/index.js CHANGED
@@ -264,6 +264,56 @@ var AFL_API_TEAM_IDS = /* @__PURE__ */ new Map([
264
264
  ["CD_T140", "Western Bulldogs"]
265
265
  ]);
266
266
 
267
+ // src/lib/venue-mapping.ts
268
+ var VENUE_ALIASES = [
269
+ ["MCG", "M.C.G.", "Melbourne Cricket Ground"],
270
+ ["SCG", "S.C.G.", "Sydney Cricket Ground"],
271
+ ["Marvel Stadium", "Docklands", "Etihad Stadium", "Telstra Dome", "Colonial Stadium"],
272
+ ["Kardinia Park", "GMHBA Stadium", "Simonds Stadium", "Skilled Stadium"],
273
+ ["Gabba", "The Gabba", "Brisbane Cricket Ground"],
274
+ [
275
+ "Sydney Showground",
276
+ "ENGIE Stadium",
277
+ "GIANTS Stadium",
278
+ "Showground Stadium",
279
+ "Sydney Showground Stadium"
280
+ ],
281
+ ["Accor Stadium", "Stadium Australia", "ANZ Stadium", "Homebush"],
282
+ ["Carrara", "People First Stadium", "Heritage Bank Stadium", "Metricon Stadium"],
283
+ ["Perth Stadium", "Optus Stadium"],
284
+ ["Adelaide Oval"],
285
+ ["Manuka Oval", "Corroboree Group Oval Manuka"],
286
+ ["Blundstone Arena", "Bellerive Oval"],
287
+ ["UTAS Stadium", "York Park", "University of Tasmania Stadium", "Aurora Stadium"],
288
+ ["TIO Stadium", "Marrara Oval"],
289
+ ["Traeger Park", "TIO Traeger Park"],
290
+ ["Mars Stadium", "Eureka Stadium"],
291
+ ["Cazalys Stadium", "Cazaly's Stadium"],
292
+ ["Jiangwan Stadium"],
293
+ ["Riverway Stadium"],
294
+ ["Norwood Oval"],
295
+ ["Subiaco Oval", "Subiaco"],
296
+ ["Football Park", "AAMI Stadium"],
297
+ ["Princes Park", "Ikon Park"],
298
+ ["Blacktown International Sportspark"],
299
+ ["Barossa Park", "Barossa Oval", "Adelaide Hills"],
300
+ ["Ninja Stadium", "Summit Sports Park"]
301
+ ];
302
+ var VENUE_ALIAS_MAP = (() => {
303
+ const map = /* @__PURE__ */ new Map();
304
+ for (const [canonical, ...aliases] of VENUE_ALIASES) {
305
+ map.set(canonical.toLowerCase(), canonical);
306
+ for (const alias of aliases) {
307
+ map.set(alias.toLowerCase(), canonical);
308
+ }
309
+ }
310
+ return map;
311
+ })();
312
+ function normaliseVenueName(raw) {
313
+ const trimmed = raw.trim();
314
+ return VENUE_ALIAS_MAP.get(trimmed.toLowerCase()) ?? trimmed;
315
+ }
316
+
267
317
  // src/transforms/footywire-player-stats.ts
268
318
  import * as cheerio from "cheerio";
269
319
 
@@ -343,7 +393,7 @@ function parseStatsTable(html, expectedCols, rowParser) {
343
393
  const headerText = teamHeader.text().trim();
344
394
  const match = /^(\w[\w\s]+?)\s+Match Statistics/i.exec(headerText);
345
395
  if (match?.[1]) {
346
- teamName = match[1].trim();
396
+ teamName = normaliseTeamName(match[1].trim());
347
397
  }
348
398
  }
349
399
  const parsed = [];
@@ -568,7 +618,7 @@ function transformMatchItems(items, season, competition, source = "afl-api") {
568
618
  roundNumber: item.round?.roundNumber ?? 0,
569
619
  roundType: inferRoundType(item.round?.name ?? ""),
570
620
  date: new Date(item.match.utcStartTime),
571
- venue: item.venue?.name ?? "",
621
+ venue: item.venue?.name ? normaliseVenueName(item.venue.name) : "",
572
622
  homeTeam: normaliseTeamName(item.match.homeTeam.name),
573
623
  awayTeam: normaliseTeamName(item.match.awayTeam.name),
574
624
  homeGoals: homeScore?.matchScore.goals ?? 0,
@@ -870,7 +920,7 @@ function parseMatchList(html, year) {
870
920
  roundNumber: currentRound,
871
921
  roundType: currentRoundType,
872
922
  date,
873
- venue,
923
+ venue: normaliseVenueName(venue),
874
924
  homeTeam,
875
925
  awayTeam,
876
926
  homeGoals,
@@ -946,7 +996,7 @@ function parseFixtureList(html, year) {
946
996
  roundNumber: currentRound,
947
997
  roundType: currentRoundType,
948
998
  date,
949
- venue,
999
+ venue: normaliseVenueName(venue),
950
1000
  homeTeam,
951
1001
  awayTeam,
952
1002
  status: hasScore ? "Complete" : "Upcoming",
@@ -1125,7 +1175,7 @@ function parseBrownlowVotes(html, season) {
1125
1175
  const tds = $(row).find("td");
1126
1176
  if (tds.length < 9) return;
1127
1177
  const player = $(tds[0]).text().trim();
1128
- const team = $(tds[1]).text().trim();
1178
+ const team = normaliseTeamName($(tds[1]).text().trim());
1129
1179
  if (!player || player.toLowerCase() === "player") return;
1130
1180
  const votes3 = safeInt($(tds[2]).text()) ?? 0;
1131
1181
  const votes2 = safeInt($(tds[3]).text()) ?? 0;
@@ -1162,7 +1212,7 @@ function parseAllAustralian(html, season) {
1162
1212
  const playerLink = $(cell).find("a");
1163
1213
  const playerName = playerLink.text().trim();
1164
1214
  const teamSpan = $(cell).find("span.playerflag");
1165
- const team = teamSpan.text().trim();
1215
+ const team = normaliseTeamName(teamSpan.text().trim());
1166
1216
  if (playerName && team) {
1167
1217
  results.push({
1168
1218
  type: "all-australian",
@@ -1200,8 +1250,8 @@ function parseRisingStarNominations(html, season) {
1200
1250
  const round = safeInt(roundText);
1201
1251
  if (round == null) return;
1202
1252
  const player = $(tds[1]).text().trim();
1203
- const team = $(tds[2]).text().trim();
1204
- const opponent = $(tds[3]).text().trim();
1253
+ const team = normaliseTeamName($(tds[2]).text().trim());
1254
+ const opponent = normaliseTeamName($(tds[3]).text().trim());
1205
1255
  if (!player || player.toLowerCase() === "name") return;
1206
1256
  results.push({
1207
1257
  type: "rising-star",
@@ -2264,7 +2314,7 @@ function transformSquiggleGamesToResults(games, season) {
2264
2314
  roundNumber: g.round,
2265
2315
  roundType: inferRoundType(g.roundname),
2266
2316
  date: new Date(g.unixtime * 1e3),
2267
- venue: g.venue,
2317
+ venue: normaliseVenueName(g.venue),
2268
2318
  homeTeam: normaliseTeamName(g.hteam),
2269
2319
  awayTeam: normaliseTeamName(g.ateam),
2270
2320
  homeGoals: g.hgoals ?? 0,
@@ -2301,7 +2351,7 @@ function transformSquiggleGamesToFixture(games, season) {
2301
2351
  roundNumber: g.round,
2302
2352
  roundType: inferRoundType(g.roundname),
2303
2353
  date: new Date(g.unixtime * 1e3),
2304
- venue: g.venue,
2354
+ venue: normaliseVenueName(g.venue),
2305
2355
  homeTeam: normaliseTeamName(g.hteam),
2306
2356
  awayTeam: normaliseTeamName(g.ateam),
2307
2357
  status: toMatchStatus2(g.complete),
@@ -2332,7 +2382,7 @@ function toFixture(item, season, fallbackRoundNumber, competition) {
2332
2382
  roundNumber: item.round?.roundNumber ?? fallbackRoundNumber,
2333
2383
  roundType: inferRoundType(item.round?.name ?? ""),
2334
2384
  date: new Date(item.match.utcStartTime),
2335
- venue: item.venue?.name ?? "",
2385
+ venue: normaliseVenueName(item.venue?.name ?? ""),
2336
2386
  homeTeam: normaliseTeamName(item.match.homeTeam.name),
2337
2387
  awayTeam: normaliseTeamName(item.match.awayTeam.name),
2338
2388
  status: toMatchStatus(item.match.status),
@@ -2730,7 +2780,7 @@ function parseSeasonPage(html, year) {
2730
2780
  const awayPoints = Number.parseInt($(awayCells[2]).text().trim(), 10) || 0;
2731
2781
  const infoText = $(homeCells[3]).text().trim();
2732
2782
  const date = parseDateFromInfo(infoText, year);
2733
- const venue = parseVenueFromInfo($(homeCells[3]).html() ?? "");
2783
+ const venue = normaliseVenueName(parseVenueFromInfo($(homeCells[3]).html() ?? ""));
2734
2784
  const attendance = parseAttendanceFromInfo(infoText);
2735
2785
  const homeFinal = homeQuarters[3];
2736
2786
  const awayFinal = awayQuarters[3];
@@ -3700,6 +3750,7 @@ export {
3700
3750
  fetchTeams,
3701
3751
  inferRoundType,
3702
3752
  normaliseTeamName,
3753
+ normaliseVenueName,
3703
3754
  ok,
3704
3755
  parseAflApiDate,
3705
3756
  parseAflTablesDate,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fitzroy",
3
- "version": "1.3.1",
4
- "description": "TypeScript library and CLI for AFL data match results, player stats, fixtures, ladders, and more",
3
+ "version": "1.4.1",
4
+ "description": "TypeScript port of the fitzRoy R package — programmatic access to AFL data including match results, player stats, fixtures, ladders, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",