/** Pure helpers for ranking rows (no DB, no server-only) — shared by the cancer Rankings tab and tests. */ export interface ScopedRankingRow { metric_slug: string; scope_key: string; } /** Year encoded in a scope key ("…|year=2021|…"); 0 when absent or "latest". */ export function scopeYear(scopeKey: string): number { const m = /year=(\d{4})/.exec(scopeKey); return m ? Number(m[1]) : 0; } /** Scope key with the year component removed — identifies the (geo, sex, age, level) scope across years. */ export function scopeWithoutYear(scopeKey: string): string { return scopeKey .split('|') .filter((part) => !part.startsWith('year=')) .join('|'); } /** * Keep one row per (metric, scope-without-year): the latest year. Earlier yearly snapshots are * left to the ranking pages. Input order is preserved for the surviving rows; ties on year keep * the first row seen. */ export function latestYearPerScope(rows: T[]): { rows: T[]; hidden: number } { const latest = new Map(); rows.forEach((r, index) => { const key = `${r.metric_slug}|${scopeWithoutYear(r.scope_key)}`; const year = scopeYear(r.scope_key); const cur = latest.get(key); if (!cur || year > cur.year) latest.set(key, { row: r, year, index: cur?.index ?? index }); }); const kept = [...latest.values()].sort((a, b) => a.index - b.index).map((x) => x.row); return { rows: kept, hidden: rows.length - kept.length }; }