← back to CelebritySignatures

scripts/tm-normalize.mjs

35 lines

// Shared name/mark normalizer for the trademark-clearance subsystem.
// Used by build-tm-index.mjs (index side) and build-tm-clearance.mjs + the
// server (query side) so both sides normalize identically — the match only
// works if "Andy Warhol" and a mark "ANDY WARHOL" collapse to the same key.

const SUFFIXES = new Set(['jr', 'sr', 'ii', 'iii', 'iv', 'phd', 'md', 'esq']);

// Fold accents, lowercase, drop punctuation, drop honorific/generational
// suffixes, collapse whitespace. Returns '' for empty/garbage input.
export function normName(raw) {
  if (!raw) return '';
  let s = String(raw)
    .normalize('NFKD').replace(/[̀-ͯ]/g, '') // strip diacritics
    .toLowerCase()
    .replace(/&/g, ' and ')
    .replace(/[^a-z0-9\s]/g, ' ')     // punctuation -> space
    .replace(/\s+/g, ' ')
    .trim();
  const toks = s.split(' ').filter(t => t && !SUFFIXES.has(t));
  return toks.join(' ');
}

// Token set for subset/overlap matching (a mark that is a person's full name,
// or vice-versa, is a flag even if not an exact string match).
export function tokens(raw) {
  return new Set(normName(raw).split(' ').filter(Boolean));
}

// Is set `a` a subset of set `b`? (all of a's tokens appear in b)
export function isSubset(a, b) {
  if (!a.size) return false;
  for (const t of a) if (!b.has(t)) return false;
  return true;
}