All files / scripts/fetch-calendar cli.ts

68.75% Statements 22/32
76.19% Branches 16/21
66.66% Functions 2/3
70% Lines 21/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77                                      5x 5x                       9x 9x 9x 17x 17x 17x 17x 17x 16x 16x   1x     9x 9x 9x 9x 4x   5x 1x   4x                                          
/**
 * @module scripts/fetch-calendar/cli
 * @description CLI argument parsing and main() entry for the fetch-calendar
 * script.
 *
 * Accepts `--to` (preferred) and `--tom` (Swedish alias used in the repo
 * docs) as the end-date flag. Invokes the orchestrator and writes either
 * a persistent JSON file (`--persist`) or pipes the result to stdout.
 *
 * @author Hack23 AB
 * @license Apache-2.0
 */
 
import { fetchCalendarWithFallback } from './orchestrator.js';
import { formatManifestMarkdown, persistCalendarJson } from './manifest.js';
 
/** Thrown by `parseCalendarArgs` for invalid CLI arguments (exit code 2). */
export class CliArgsError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'CliArgsError';
  }
}
 
/**
 * Parse CLI argv into `{ from, to, persist }`.
 */
export function parseCalendarArgs(argv: readonly string[]): {
  from: string;
  to: string;
  persist: boolean;
} {
  const flags = new Map<string, string>();
  const booleans = new Set<string>();
  for (let i = 0; i < argv.length; i++) {
    const token = argv[i];
    Iif (!token || !token.startsWith('--')) continue;
    const key = token.slice(2);
    const next = argv[i + 1];
    if (next !== undefined && !next.startsWith('--')) {
      flags.set(key, next);
      i++;
    } else {
      booleans.add(key);
    }
  }
  const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
  const from = flags.get('from') ?? '';
  const to = flags.get('to') ?? flags.get('tom') ?? '';
  if (!ISO_DATE_RE.test(from)) {
    throw new CliArgsError(`--from must be an ISO 8601 date (YYYY-MM-DD), got: "${from}"`);
  }
  if (!ISO_DATE_RE.test(to)) {
    throw new CliArgsError(`--to must be an ISO 8601 date (YYYY-MM-DD), got: "${to}"`);
  }
  return { from, to, persist: booleans.has('persist') };
}
 
export async function main(): Promise<void> {
  const args = parseCalendarArgs(process.argv.slice(2));
  console.error(`📅 [fetch-calendar] Fetching ${args.from} → ${args.to}`);
 
  const result = await fetchCalendarWithFallback(args.from, args.to);
 
  console.error(formatManifestMarkdown(result.manifest));
 
  if (args.persist) {
    persistCalendarJson(args.from, result);
  } else {
    process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
  }
 
  if (result.manifest.path === 'none') {
    process.exit(1);
  }
}