Functional Weave
Code in TypeScript

dates.bank-holidays@1.0.1

impl/typescript.ts

1,609 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { BANK_HOLIDAYS } from "./dates_bank_holidays_data.ts";  ← this capability’s own data, compiled from data/bank-holidays.json into the same file by fune build
import { type BankHoliday, type UkRegion } from "./dates_bank_holidays_types.ts";

/**
 * The bank holidays for a UK region and year, in date order, as gov.uk
 * publishes them. A year the data does not cover is an error rather than an
 * empty list, because an empty list reads as "no holidays" and a deadline
 * calculation would then count Christmas Day as a working day.
 */
export function bankHolidays(region: UkRegion, year: number): readonly BankHoliday[] {
  if (!Number.isInteger(year)) {
    throw new TypeError(`year must be an integer, received ${year}`);
  }
  let first: number | null = null;
  let last: number | null = null;
  const found: BankHoliday[] = [];
  const prefix = `${String(year).padStart(4, "0")}-`;
  for (const row of BANK_HOLIDAYS) {
    if (row.region !== region) continue;
    const rowYear = Number(row.date.slice(0, 4));
    if (first === null || rowYear < first) first = rowYear;
    if (last === null || rowYear > last) last = rowYear;
    if (row.date.startsWith(prefix)) found.push({ date: row.date, title: row.title, substitute: row.substitute });
  }
  if (first === null || last === null) {
    throw new RangeError(`unknown region "${region}": expected england-and-wales, scotland or northern-ireland`);
  }
  if (year < first || year > last) {
    throw new RangeError(`no bank holiday data for ${region} in ${year}: the published calendar covers ${first} to ${last}`);
  }
  // ISO dates sort correctly as strings.
  return found.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));
}