SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
1.8 KB · 41 lines typescript
Raw Blame History
1/**2 * String normalization used by reconciliation (CLAUDE.md §69). Deterministic, no LLM.3 */45const GREEK: Record<string, string> = { α: 'alpha', β: 'beta', γ: 'gamma', δ: 'delta', κ: 'kappa', λ: 'lambda', μ: 'mu' };67export function stripDiacritics(s: string): string {8  return s.normalize('NFKD').replace(/[̀-ͯ]/g, '');9}1011/** Lowercase, ASCII, punctuation → space, collapse whitespace. Keeps digits (G12C, HER2). */12export function normalizeLabel(input: string): string {13  let s = stripDiacritics(input).toLowerCase();14  s = s.replace(/[αβγδκλμ]/g, (c) => GREEK[c] ?? c);15  s = s.replace(/['’`"]/g, '');16  s = s.replace(/[^a-z0-9]+/g, ' ');17  s = s.replace(/\b(nos|unspecified|not otherwise specified)\b/g, ' ');18  s = s.replace(/\bcarcinomas\b/g, 'carcinoma').replace(/\bcancers\b/g, 'cancer').replace(/\btumou?rs\b/g, 'tumor').replace(/\btumour\b/g, 'tumor').replace(/\bneoplasms\b/g, 'neoplasm').replace(/\bsarcomas\b/g, 'sarcoma').replace(/\blymphomas\b/g, 'lymphoma').replace(/\bleukaemia\b/g, 'leukemia').replace(/\bleukemias\b/g, 'leukemia');19  return s.replace(/\s+/g, ' ').trim();20}2122/** "Carcinoma, Non-Small-Cell Lung" (MeSH inverted form) → "Non-Small-Cell Lung Carcinoma". */23export function uninvertMeshTerm(term: string): string {24  const parts = term.split(',').map((p) => p.trim());25  if (parts.length < 2) return term;26  return [...parts.slice(1), parts[0]].join(' ');27}2829/** URL slug for entity routes. */30export function slugify(input: string): string {31  return stripDiacritics(input)32    .toLowerCase()33    .replace(/[^a-z0-9]+/g, '-')34    .replace(/^-+|-+$/g, '')35    .slice(0, 120);36}3738export function sha256Hex(data: string | Uint8Array): Promise<string> {39  return import('node:crypto').then(({ createHash }) => createHash('sha256').update(data).digest('hex'));40}41