feat: multi-team, multi-league config format #4

Merged
freemasen merged 3 commits from ada/nba-calendar-utility:feat/multi-team-config into main 2026-05-20 02:01:46 +00:00
Contributor

What

Changes config.json from a single-team format to a multi-team format where each league key maps to an array of team entries. This lets you track multiple teams across multiple leagues in a single run, each writing to its own calendar.

New config format

{
  "nba": [
    { "teamCode": "NYK", "calendarId": "primary" },
    { "teamCode": "BOS", "calendarId": "celtics@group.calendar.google.com", "year": 2025 }
  ],
  "wnba": [
    { "teamCode": "NYL", "calendarId": "liberty@group.calendar.google.com" }
  ]
}

Each team entry has:

  • teamCode (required) — 3-letter team tricode
  • calendarId (required) — calendar to write to (accepts "primary", email addresses, or full Google Calendar URLs)
  • year (optional) — season year, defaults to current season

Changes

  • src/config.jsreadConfig() returns { league: TeamEntry[] } instead of a flat object. Validates each entry, extracts calendar IDs from URLs, falls back to current season year.
  • index.mjs — Iterates over each league and each team entry in the config, processing them sequentially with a single auth session.
  • src/calendar.js — Updated log message to use dateTime instead of date (matches the timed events from PR #3).
  • config.json.example — Updated to new format with multiple teams.
  • README.md — Updated config docs to explain the new format.

Testing

Validated config parsing with:

  • Multi-league, multi-team configs
  • Calendar ID extraction from URLs
  • Missing teamCode validation
  • Non-array league value validation
  • Fallback year computation
## What Changes config.json from a single-team format to a multi-team format where each league key maps to an array of team entries. This lets you track multiple teams across multiple leagues in a single run, each writing to its own calendar. ## New config format ```json { "nba": [ { "teamCode": "NYK", "calendarId": "primary" }, { "teamCode": "BOS", "calendarId": "celtics@group.calendar.google.com", "year": 2025 } ], "wnba": [ { "teamCode": "NYL", "calendarId": "liberty@group.calendar.google.com" } ] } ``` Each team entry has: - `teamCode` (required) — 3-letter team tricode - `calendarId` (required) — calendar to write to (accepts "primary", email addresses, or full Google Calendar URLs) - `year` (optional) — season year, defaults to current season ## Changes - **`src/config.js`** — `readConfig()` returns `{ league: TeamEntry[] }` instead of a flat object. Validates each entry, extracts calendar IDs from URLs, falls back to current season year. - **`index.mjs`** — Iterates over each league and each team entry in the config, processing them sequentially with a single auth session. - **`src/calendar.js`** — Updated log message to use `dateTime` instead of `date` (matches the timed events from PR #3). - **`config.json.example`** — Updated to new format with multiple teams. - **`README.md`** — Updated config docs to explain the new format. ## Testing Validated config parsing with: - Multi-league, multi-team configs ✅ - Calendar ID extraction from URLs ✅ - Missing teamCode validation ✅ - Non-array league value validation ✅ - Fallback year computation ✅
The config.json now uses league keys with arrays of team entries,
supporting multiple teams across multiple leagues in a single run.

Old format:
  { "league": "nba", "teamCode": "NYK", "calendarId": "primary" }

New format:
  {
    "nba": [
      { "teamCode": "NYK", "calendarId": "primary" },
      { "teamCode": "BOS", "calendarId": "celtics@..." }
    ],
    "wnba": [
      { "teamCode": "NYL", "calendarId": "liberty@..." }
    ]
  }

Each team entry has its own calendarId and optional year, so different
teams can write to different calendars with different season years.

- Rewrote config.js readConfig() to parse and validate the new format
- Updated index.mjs to iterate over leagues and team entries
- Updated calendar.js saveEvents() log to use dateTime (not date)
- Updated config.json.example and README with new format docs
Replaces the plain-object config with three classes:

- TeamEntry: team code, calendar ID, season year
  - fromJson() validates teamCode (3 chars, uppercased),
    extracts calendarId from URLs, falls back year
  - toJson() serializes back to plain JSON

- LeagueConfig: league key + array of TeamEntry
  - fromJson() maps raw entry objects to TeamEntry instances
  - toJson() produces { league: entries[] }

- Config: top-level, holds LeagueConfig[]
  - fromJson() parses the full config object
  - fromFile() reads and parses a config.json file
  - toJson() serializes the full config

All properties are explicitly defined on the classes with
JSDoc type annotations. The readConfig() convenience function
is preserved for index.mjs.

Round-trip (fromJson → toJson → fromJson) verified in tests.
Tests for extractCalendarId, fallbackYear, TeamEntry, LeagueConfig,
and Config covering:
- Calendar ID extraction from URLs (embed, settings, view)
- Team code validation and uppercasing
- Year fallback behavior
- Error cases (missing fields, wrong types, empty config)
- toJson/fromJson round-trip

Run with: npm test
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
freemasen/nba-calendar-utility!4
No description provided.