spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1/** Pure helpers for ranking rows (no DB, no server-only) — shared by the cancer Rankings tab and tests. */23export interface ScopedRankingRow {4 metric_slug: string;5 scope_key: string;6}78/** Year encoded in a scope key ("…|year=2021|…"); 0 when absent or "latest". */9export function scopeYear(scopeKey: string): number {10 const m = /year=(\d{4})/.exec(scopeKey);11 return m ? Number(m[1]) : 0;12}1314/** Scope key with the year component removed — identifies the (geo, sex, age, level) scope across years. */15export function scopeWithoutYear(scopeKey: string): string {16 return scopeKey17 .split('|')18 .filter((part) => !part.startsWith('year='))19 .join('|');20}2122/**23 * Keep one row per (metric, scope-without-year): the latest year. Earlier yearly snapshots are24 * left to the ranking pages. Input order is preserved for the surviving rows; ties on year keep25 * the first row seen.26 */27export function latestYearPerScope<T extends ScopedRankingRow>(rows: T[]): { rows: T[]; hidden: number } {28 const latest = new Map<string, { row: T; year: number; index: number }>();29 rows.forEach((r, index) => {30 const key = `${r.metric_slug}|${scopeWithoutYear(r.scope_key)}`;31 const year = scopeYear(r.scope_key);32 const cur = latest.get(key);33 if (!cur || year > cur.year) latest.set(key, { row: r, year, index: cur?.index ?? index });34 });35 const kept = [...latest.values()].sort((a, b) => a.index - b.index).map((x) => x.row);36 return { rows: kept, hidden: rows.length - kept.length };37}38