spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1/** URL state helpers for server-side filtered pages (§295). */2export type SP = Record<string, string | string[] | undefined>;34export function str(sp: SP, key: string, fallback = ''): string {5 const v = sp[key];6 const s = Array.isArray(v) ? v[0] : v;7 return (s ?? fallback).toString().trim();8}910export function int(sp: SP, key: string, fallback: number, min = -Infinity, max = Infinity): number {11 const n = Number.parseInt(str(sp, key, ''), 10);12 if (!Number.isFinite(n)) return fallback;13 return Math.min(max, Math.max(min, n));14}1516export function oneOf<T extends string>(sp: SP, key: string, allowed: readonly T[], fallback: T): T {17 const v = str(sp, key, '');18 return (allowed as readonly string[]).includes(v) ? (v as T) : fallback;19}2021export function bool(sp: SP, key: string): boolean | null {22 const v = str(sp, key, '');23 if (v === '1' || v === 'true' || v === 'yes') return true;24 if (v === '0' || v === 'false' || v === 'no') return false;25 return null;26}2728/** Build a query string from the current params with overrides (drops empty values). */29export function withParams(current: Record<string, string | number | null | undefined>, overrides: Record<string, string | number | null | undefined>): string {30 const merged = { ...current, ...overrides };31 const qs = new URLSearchParams();32 for (const [k, v] of Object.entries(merged)) {33 if (v == null || v === '' || v === 'all' && k !== 'level') continue;34 qs.set(k, String(v));35 }36 const s = qs.toString();37 return s ? `?${s}` : '';38}39