Add trains endpoint handler
All checks were successful
Publish Package / build-and-publish (push) Successful in 8s

This commit is contained in:
2026-04-27 22:28:55 +01:00
parent d10dabf604
commit 3c81b5225f
7 changed files with 128 additions and 6 deletions

View File

@@ -2,11 +2,13 @@ import { BaseClient } from "./base.js";
import { PisModule } from "../modules/pis.js";
import { LocationFilterModule } from "../modules/locationFilter.js";
import { StationDataModule } from "../modules/stationData.js";
import { TrainsModule } from "src/modules/trains.js";
export class OwlBoardClient extends BaseClient {
public readonly pis: PisModule;
public readonly locationFilter: LocationFilterModule;
public readonly stationData: StationDataModule;
public readonly stationData: StationDataModule;
public readonly trains: TrainsModule;
constructor(baseUrl: string, apiKey?: string) {
super(baseUrl, apiKey);
@@ -14,5 +16,6 @@ export class OwlBoardClient extends BaseClient {
this.pis = new PisModule(this);
this.locationFilter = new LocationFilterModule(this);
this.stationData = new StationDataModule(this);
this.trains = new TrainsModule(this);
}
}

20
src/lib/helpers.ts Normal file
View File

@@ -0,0 +1,20 @@
/**
* Normalises input to YYYY-MM-DD string
* - Strings are passed through as is
* - Date objects are converted to UK time
*/
export const ensureDateString = (input: Date | string): string => {
if (typeof input === 'string') return input.trim();
const d = new Intl.DateTimeFormat('en-GB', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
timeZone: 'Europe/London'
}).formatToParts(input);
const part = (type: string) => d.find(p => p.type === type)?.value;
return `${part('year')}-${part('month')}-${part('day')}`
}

View File

@@ -1,3 +1,13 @@
/**
* Checks if a character code is a digit
*/
const isDigit = (c: number) => c >= 48 && c <= 57;
/**
* Checks if a character code is an upper case letter
*/
const isUpper = (c: number) => c >= 65 && c <= 90;
/**
* Checks if a string is a valid CRS (Syntactically Only)
* using byte level checking for max performance
@@ -49,6 +59,60 @@ export const IsValidPis = (PIS: string): boolean => {
return true;
}
/**
* Checks if a string is the correct format for a Headcode
* USes byte level checking for max performance
* @param Headcode The headcode to be validated
*/
export const IsValidHeadcode = (Headcode: string): boolean => {
if (Headcode.length !== 4) return false;
const c0 = Headcode.charCodeAt(0);
const c1 = Headcode.charCodeAt(1);
const c2 = Headcode.charCodeAt(2);
const c3 = Headcode.charCodeAt(3);
return isDigit(c0) && isUpper(c1) && isDigit(c2) && isDigit(c3)
}
/**
* Checks if a string is the correct format for a TOC Code
*/
export const IsValidToc = (toc: string): boolean => {
if (toc.length !== 2) {
return false;
}
const c0 = toc.charCodeAt(0);
const c1 = toc.charCodeAt(1);
return isUpper(c0) && isUpper(c1);
}
/**
* Checks if a string is the correct format, and is a valid date
*/
export const IsValidDateStr = (s: string): boolean => {
if (s.length !== 10) return false;
if (s[4] !== '-' || s[7] !== '-') return false;
for (let i = 0; i < 10; i++) {
if (i === 4 || i === 7) continue;
const c = s.charCodeAt(i);
if (!isDigit(i)) return false;
}
const y = parseInt(s.substring(0, 4), 10);
const m = parseInt(s.substring(5, 7), 10) - 1; // JS months are 0-11
const d = parseInt(s.substring(8, 10), 10);
const date = new Date(y, m, d);
return (
date.getFullYear() === y &&
date.getMonth() === m &&
date.getDate() === d
);
}
/**
* Validates Geohash string against standard b32 alphabet
* (Syntactically Only validation)