@finbheara/names 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,7 @@ import {
19
19
  commaReading2,
20
20
  levelOf2,
21
21
  defaultPersonNameFactory2
22
- } from "./index-khxa4qjy.js";
22
+ } from "./index-yf904dam.js";
23
23
  import {
24
24
  isTeamPrint2
25
25
  } from "./index-0phgwy52.js";
@@ -1423,4 +1423,4 @@ function deriveNameFormat2(prints, options = {}) {
1423
1423
  export { repairMojibake2, sameGivenFamily2, comparePosition2, nameRelation2, nameCompare2, probablySame2, createNameSet2, createNameMap2, createNameClusters2, MAX_READINGS2, surnameParts2, printAttestsOrder2, nameReadings2, meetReading2, refinesReading2, sameReading2, chooseReadingPair2, composeReadings2, composeNames2, meetReadings2, nameMeet2, showReading2, blockKeysOfReadings2, nameBlockKeys2, namesFeasible2, INFEASIBLE_CLASSES2, editDistance2, nearSpelling2, compoundGiven2, middleForm2, infeasibleClass2, isListJoiner2, personList2, surnameBlock2, initialsBlock2, metaphoneBlocks2, NAME_LEVEL_COLUMNS2, NAME_COLUMNS2, nameColumns2, NAME_FORMATS2, nameFormatOrder2, ORDER_READINGS2, readNameCell2, DEFAULT_NAME_FORMAT_THRESHOLD2, deriveNameFormat2 };
1424
1424
 
1425
1425
  //# debugId=A39684B9543A024164756E2164756E21
1426
- //# sourceMappingURL=index-7sppf1vh.js.map
1426
+ //# sourceMappingURL=index-vqbvesky.js.map
@@ -170,7 +170,7 @@ function scrubNameDetail2(printed, options = {}) {
170
170
  rules.push("accept-team");
171
171
  return { value: s, refused: false, rules };
172
172
  }
173
- if (s.split(" ").filter((t) => t !== "").length < 2) {
173
+ if (s.split(/[ ,]/).filter((t) => t !== "").length < 2) {
174
174
  rules.push("refuse-single-token");
175
175
  return { value: NAME_REFUSED2, refused: true, rules };
176
176
  }
@@ -200,7 +200,68 @@ var PLATFORM_PLACEHOLDERS2 = [
200
200
  authority: "42 name rows (`#N/A`, a spreadsheet's missing-value mark; it parsed as the person `A<<N`); 43 school rows (`#N/A`, `N/A`)"
201
201
  },
202
202
  { print: "none", authority: "0 name rows; 21 school rows (`None`, `none`)" },
203
- { print: "not applicable", authority: "0 name rows; 1 school row (`Not applicable`)" }
203
+ { print: "not applicable", authority: "0 name rows; 1 school row (`Not applicable`)" },
204
+ {
205
+ print: "no school",
206
+ authority: "0 name rows; 76 school rows (`No School`): the dancer is entered with no school"
207
+ },
208
+ {
209
+ print: "independent",
210
+ authority: "0 name rows; 5 school rows (`Independent`, `independent`, `Independent?`): no school, by the dancer's own description"
211
+ },
212
+ {
213
+ print: "independent dancer",
214
+ authority: "0 name rows; 8 school rows (`Independent Dancer`, `Independent dancer`, `Independent Dancer?`)"
215
+ },
216
+ { print: "no school judge", authority: "0 rows: a form option for an adjudicator's entry" },
217
+ {
218
+ print: "no school associations",
219
+ authority: "0 name rows; 13 school rows (`No School Associations`)"
220
+ },
221
+ { print: "no dance school", authority: "0 rows: a form option" },
222
+ { print: "no lessons yet", authority: "0 name rows; 5 school rows (`No lessons yet`)" },
223
+ {
224
+ print: "none inactive dancer",
225
+ authority: "0 name rows; 1 school row (`None - Inactive Dancer`)"
226
+ },
227
+ { print: "not certified", authority: "0 name rows; 1 school row (`Not Certified`)" },
228
+ { print: "other", authority: "0 name rows; 2 school rows (`Other`)" },
229
+ { print: "school other", authority: "0 rows: a form option" },
230
+ { print: "non", authority: "0 rows: a form option, the truncation of `Non-dancer`" },
231
+ { print: "non dancer", authority: "0 name rows; 4 school rows (`Non-dancer`)" },
232
+ { print: "non dancing", authority: "0 name rows; 88 school rows (`Non-dancing`)" },
233
+ {
234
+ print: "non dance competitions",
235
+ authority: "0 name rows; 3 school rows (`Non-Dance Competitions`)"
236
+ },
237
+ {
238
+ print: "unknown irish dancing school",
239
+ authority: "0 name rows; 1 school row (`Unknown Irish Dancing School`)"
240
+ },
241
+ { print: "unknown music school", authority: "0 rows: a form option" },
242
+ { print: "school deleted", authority: "0 rows: a form option (`---SCHOOL DELETED`)" },
243
+ {
244
+ print: "not listed",
245
+ match: "prefix",
246
+ authority: "0 name rows; 2 school rows (`--Not Listed--`), and the form's `--Not Listed` run-ons"
247
+ },
248
+ { print: "choose one", authority: "0 name rows; 41 school rows (`-- Choose One --`)" },
249
+ { print: "select school", authority: "0 rows: a form option (`--Select School--`)" },
250
+ {
251
+ print: "no school selected",
252
+ match: "prefix",
253
+ authority: "0 name rows; 16 school rows (`NO SCHOOL SELECTED - Please change your profile`)"
254
+ },
255
+ {
256
+ print: "school not selected",
257
+ match: "prefix",
258
+ authority: "0 name rows; 45 school rows (`SCHOOL NOT SELECTED - update your … profile`)"
259
+ },
260
+ { print: "x closed select new school", authority: "0 rows: a form option" },
261
+ { print: "x school closed please select another school", authority: "0 rows: a form option" },
262
+ { print: "default school", authority: "0 rows: a form option" },
263
+ { print: "my school of irish dance", authority: "0 rows: a form's example text" },
264
+ { print: "n e e d", authority: "0 name rows; 1 school row (`(n e e d ) ____`), keyboard filler" }
204
265
  ];
205
266
  var NAME_PLACEHOLDERS2 = [
206
267
  {
@@ -220,17 +281,24 @@ var NAME_PLACEHOLDERS2 = [
220
281
  authority: "`X`, 2 rows: a bare keyboard filler in the name field"
221
282
  }
222
283
  ];
223
- var SHARED = new Set(PLATFORM_PLACEHOLDERS2.map((p) => p.print));
284
+ var SHARED = new Map(PLATFORM_PLACEHOLDERS2.filter((p) => p.match === undefined).map((p) => [p.print, p]));
285
+ var SHARED_PREFIX = PLATFORM_PLACEHOLDERS2.filter((p) => p.match === "prefix");
224
286
  var NAME_ONLY = new Set(NAME_PLACEHOLDERS2.map((p) => p.print));
225
287
  var HAS_LETTER = /\p{L}/u;
288
+ function sharedRow(folded) {
289
+ return SHARED.get(folded) ?? SHARED_PREFIX.find((p) => folded === p.print || folded.startsWith(`${p.print} `));
290
+ }
291
+ function placeholderOf2(print) {
292
+ return sharedRow(foldNameKey2(print));
293
+ }
226
294
  function isPlaceholderPrint2(print) {
227
- return SHARED.has(foldNameKey2(print));
295
+ return placeholderOf2(print) !== undefined;
228
296
  }
229
297
  function isNoNamePrint2(print) {
230
298
  if (!HAS_LETTER.test(print))
231
299
  return true;
232
300
  const folded = foldNameKey2(print);
233
- return NAME_ONLY.has(folded) || SHARED.has(folded);
301
+ return NAME_ONLY.has(folded) || sharedRow(folded) !== undefined;
234
302
  }
235
303
 
236
304
  // src/normalize/compound-surnames.ts
@@ -1055,7 +1123,7 @@ function personNameFromIcao2(icao, print) {
1055
1123
  return defaultPersonNameFactory2().fromIcao(icao, print);
1056
1124
  }
1057
1125
 
1058
- export { NAME_REFUSED2, stripEveryAside2, stripTrailingCredentials2, scrubNameDetail2, scrubName2, foldNameKey2, nameFold2, PLATFORM_PLACEHOLDERS2, NAME_PLACEHOLDERS2, isPlaceholderPrint2, isNoNamePrint2, COMPOUND_SURNAMES2, isCompoundSurname2, spaceAfterComma2, isNameSuffix, tokenize, inferNameOrder2, commaReading2, lexiconNameOrder, resolveNameOrder2, splitPersonName2, classifyCell2, capitalise2, nameCase2, SURNAME_SEPARATOR2, GIVEN_SEPARATOR2, titleCaseNamePart2, spellingLookup2, parsePersonName2, formatPersonDisplay2, personDisplayName2, NAME_TRADITIONS2, traditionFromIndex2, isIcaoName2, levelOf2, givenKeyAbbreviates2, givenAbbreviates2, PersonName2, DEFAULT_PERSON_NAME_CAPACITY2, traditionLookupOf2, createPersonNameFactory2, createCachingPersonNameFactory2, defaultPersonNameFactory2, personName2, personNameFromIcao2 };
1126
+ export { NAME_REFUSED2, stripEveryAside2, stripTrailingCredentials2, scrubNameDetail2, scrubName2, foldNameKey2, nameFold2, PLATFORM_PLACEHOLDERS2, NAME_PLACEHOLDERS2, placeholderOf2, isPlaceholderPrint2, isNoNamePrint2, COMPOUND_SURNAMES2, isCompoundSurname2, spaceAfterComma2, isNameSuffix, tokenize, inferNameOrder2, commaReading2, lexiconNameOrder, resolveNameOrder2, splitPersonName2, classifyCell2, capitalise2, nameCase2, SURNAME_SEPARATOR2, GIVEN_SEPARATOR2, titleCaseNamePart2, spellingLookup2, parsePersonName2, formatPersonDisplay2, personDisplayName2, NAME_TRADITIONS2, traditionFromIndex2, isIcaoName2, levelOf2, givenKeyAbbreviates2, givenAbbreviates2, PersonName2, DEFAULT_PERSON_NAME_CAPACITY2, traditionLookupOf2, createPersonNameFactory2, createCachingPersonNameFactory2, defaultPersonNameFactory2, personName2, personNameFromIcao2 };
1059
1127
 
1060
- //# debugId=49F5F13DC88ECCC664756E2164756E21
1061
- //# sourceMappingURL=index-khxa4qjy.js.map
1128
+ //# debugId=17771FA89E876DFF64756E2164756E21
1129
+ //# sourceMappingURL=index-yf904dam.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/normalize/name-scrub.ts", "../src/normalize/name-fold.ts", "../src/normalize/name-placeholder.ts", "../src/normalize/compound-surnames.ts", "../src/normalize/name-split.ts", "../src/normalize/cell-verdict.ts", "../src/normalize/name-case.ts", "../src/normalize/person-display.ts", "../src/normalize/person-name.ts", "../src/normalize/factory.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * name-scrub.ts — the three-phase treatment a printed person-name cell gets\n * before anything splits it.\n *\n * The rules, in the words that set them —\n *\n * > if there are dangling pairs (a single `\"` or `)` or `(` ) then those get\n * > replaced after the pairs are fixed\n *\n * > the credentials should probably be stripped. fix the initials (two periods\n * > are different than one). it must run on adjudicators. They are people.\n *\n * ## THE PHASE ORDER IS PART OF THE RULE\n *\n * REPAIR, then STRIP, then REFUSE. The reason is mechanical: `Samantha 0 Connor`\n * carries a digit, so a refusal that ran first would throw away a print the\n * repair can fix. Every rule below names its phase and the phases run in that\n * order, once, top to bottom.\n *\n * ## It moves AWAY from the print\n *\n * Everything here is a reading applied on the way into a derived store; it never\n * rewrites the transcription. The transcription keeps what the page printed, and\n * a consumer should keep the printed value beside the scrubbed one. Nothing here\n * is an erratum: an erratum repairs a transcription toward the page, and the\n * phase-1 repairs below are downstream readings of a print that is not being\n * re-rendered.\n *\n * ## The refusal is a value, not an exception\n *\n * A cell that cannot be a person's name scrubs to `NAME_REFUSED`, spelled\n * `!!!INVALID`. It is deliberately not a name-shaped string: it can never be\n * mistaken for a rendered `Last<<First`, it sorts and greps out of the way, and\n * a consumer that forgets to check it produces visible nonsense rather than a\n * plausible dancer. A consumer should count it, so the population is reported\n * rather than silently absorbed.\n *\n * ## What is NOT here\n *\n * - **Casing, ASCII folding, splitting.** `./name-case.ts`,\n * `../lexicon/ascii-approx.ts` and `./name-split.ts` own those and run after\n * this.\n * - **The comma.** It is the `Last, First` order separator and is read against\n * the producing document's `meta.nameFormat` by `./name-split.ts`. The one\n * comma this file touches is the credential delimiter of `Maxwell, ADCRG`,\n * which is not an order separator and would otherwise make `ADCRG` a given\n * name.\n * - **A printed status qualifier fused into the cell** (`- WMH`) — a separate\n * fact for the caller, held aside here only so the spaced-hyphen rule does\n * not close it up into a surname.\n * - **A lost byte printing as `?`** (`Jystarvard, M?jaillell`) — an erratum toward the\n * page, corrected in the transcription rather than guessed at here. The bare\n * `???` names nobody and is refused here.\n * - **A trailing `Á'` that is really in the source bytes.** Where the source file\n * itself carries `0xC1 0x27` and it is decoded faithfully, with no OCR in the\n * path, the question is whether the source is accurate, not a mis-decode this\n * layer may read through.\n */\n\nimport { canonicalTeamName } from \"./team-name.ts\";\n\n/**\n * The refusal value: a cell that cannot be a person's name.\n *\n * ONE SPELLING, EVERYWHERE. Phase 3 says the cell \"is `!!!INVALID`\", and no\n * other spelling of the refusal exists anywhere in the tree.\n */\nexport const NAME_REFUSED = \"!!!INVALID\";\n\n/** Which rule fired. Stable strings — a census and a report quote them. */\nexport type ScrubRule =\n\t// ── phase 1, repair ──────────────────────────────────────────────────────\n\t/** `0` leading a name token read back as `O`: `JESSICA 0'SULLIVAN`. */\n\t| \"ocr-zero-for-o\"\n\t/** `;` between letters read back as `i`: `KESTR;A-ROSE` → `KESTRIA-ROSE`. */\n\t| \"ocr-semicolon-for-i\"\n\t/** A standalone U+00B4 ACUTE dropped: `Fa´inne` → `Fainne`. */\n\t| \"ocr-stray-acute\"\n\t// ── phase 2, strip ───────────────────────────────────────────────────────\n\t/** A parenthesised alias removed: `Lena (Xiaoyu) Zumock` → `Lena Zumock`. */\n\t| \"strip-parens\"\n\t/** A quoted nickname removed: `Pundeallina \"Katie\" Foxe` → `Pundeallina Foxe`. */\n\t| \"strip-quotes\"\n\t/** A `(`, `)` or `\"` left over once the pairs are gone, replaced by a space. */\n\t| \"strip-dangling\"\n\t/** A trailing teaching credential removed: `Maxwell, ADCRG` → `Maxwell`. */\n\t| \"strip-credential\"\n\t/** A `.` that is not part of an initials token, replaced by a space. */\n\t| \"strip-period\"\n\t/** An initials token held together and spelled compactly: `K. T.` → `K.T.`. */\n\t| \"join-initials\"\n\t/** A literal `\\'` read back as the apostrophe it escapes: `O\\'Brien` → `O'Brien`. */\n\t| \"unescape-apostrophe\"\n\t/** `/` or `\\` replaced by a space: `MAKAYLA\\ FONNAILLOW`. */\n\t| \"strip-slash\"\n\t/** A hyphen with whitespace beside it closed up: `GRACE- OSYRNIA` → `GRACE-OSYRNIA`. */\n\t| \"close-spaced-hyphen\"\n\t/** Trailing non-letters removed: `Annika Walter,` → `Annika Walter`. */\n\t| \"strip-trailing-punct\"\n\t// ── phase 3, refuse ──────────────────────────────────────────────────────\n\t/** A digit survived phase 1: `KELSEY PEARRAILLINA - BN2018`. */\n\t| \"refuse-digit\"\n\t/** A location trailer: `London Hryniuk Lyrunnett : Western Region, Canada`. */\n\t| \"refuse-location-trailer\"\n\t/**\n\t * A parenthesised or quoted aside the `ParentheticalHandler` refused. A handler\n\t * may name its own `refuse-…` rule instead (e.g. `refuse-location-alias`).\n\t */\n\t| \"refuse-parenthetical\"\n\t| `refuse-${string}`\n\t/** One token cannot be both a surname and a given name: `Saunders`, `???`. */\n\t| \"refuse-single-token\"\n\t/**\n\t * A team designation in its canonical format, exempted from the refusals\n\t * below it: `Team`, `Team A`. The EIGHTEENTH rule, added after the others: a\n\t * team designation has a canonical format (`./team-name.ts`), which takes\n\t * `Team` out of `refuse-single-token`'s population. It repairs nothing and\n\t * strips nothing; it is recorded so the census can count the exemption rather\n\t * than report a silent gap in the refusals.\n\t */\n\t| \"accept-team\";\n\n/**\n * What an aside set apart by `( … )` or `\" … \"` in a name cell means.\n *\n * Asked once per pair, inside-out, with the trimmed text between the delimiters.\n * `\"strip\"` removes the pair (the aside is a nickname or alias:\n * `Lena (Xiaoyu) Zumock` → `Lena Zumock`). `\"refuse\"` refuses the whole cell as no\n * person's name, under `refuse-parenthetical`; `{ refuse: \"refuse-<rule>\" }`\n * refuses it under a rule the caller names.\n *\n * ASKED ONLY INSIDE THE DELIMITERS, never of a bare token: `Victoria` and\n * `London` are good given names in the open.\n */\nexport type ParentheticalHandler = (\n\taside: string,\n\tcontext: { readonly print: string; readonly delimiter: \"()\" | '\"\"' },\n) => \"strip\" | \"refuse\" | { readonly refuse: `refuse-${string}` };\n\n/** The default: every aside is an alias, and is stripped. */\nexport const stripEveryAside: ParentheticalHandler = () => \"strip\";\n\n/** Options for `scrubNameDetail`. */\nexport interface ScrubOptions {\n\t/** default: `stripEveryAside` */\n\treadonly parenthetical?: ParentheticalHandler;\n}\n\nexport interface ScrubResult {\n\t/** The scrubbed print, or `NAME_REFUSED`. */\n\tvalue: string;\n\t/** True when `value` is `NAME_REFUSED`. */\n\trefused: boolean;\n\t/** Every rule that fired, in the order the phases ran them. */\n\trules: ScrubRule[];\n}\n\n/**\n * Teaching credentials, stripped; generational suffixes, kept.\n *\n * The split is that of an earlier Java implementation, which ran over this corpus\n * for years: it lists `TCRG`, `ADCRG`, `BG`, `PHD` beside `Jr`, `II`, `III`,\n * `IV`, and only the first group is stripped (\"the credentials should probably\n * be stripped\"). `SDCRG` is added because the corpus prints it (17 panel seats)\n * and\n * it is the same kind of thing — a CLRG teaching qualification, not part of\n * anybody's name. A generational suffix IS part of the name and stays, which is\n * why `./name-split.ts`'s `NAME_SUFFIXES` still carries both groups: it has to\n * recognize what it must not make a surname.\n */\nconst CREDENTIALS: ReadonlySet<string> = new Set([\"tcrg\", \"adcrg\", \"sdcrg\", \"bg\", \"phd\"]);\n\n/**\n * The `strip-credential` rule, on its own, so the one implementation serves\n * every caller.\n *\n * TRAILING POSITION ONLY. The regex is end-anchored, which is the whole\n * content of the rule: `Bg` *inside* a name is untouched, and a bare `ADCRG`\n * with nothing before it is not a credential to strip — it is all there is.\n * The separator may be a comma or a space, because a source prints both\n * (`Claire Maxted, ADCRG` and `Alice Gellane-O'Luthindby ADCRG`), and an optional\n * full stop is allowed after the token. It loops, so `Dr. Irene Brustirley, PhD,\n * ADCRG` loses both.\n *\n * IT TAKES A PRINTED NAME *OR* A FOLDED KEY. Both are handled by the same\n * anchor: a fold key is lower-case with single spaces, so `carol quarnell\n * adcrg` matches on the space exactly as the printed form matches on the\n * comma. An adjudicator fold is the typical second caller, and a second copy of\n * these five lines is precisely what lets the two drift — a positionless\n * `split(\" \").filter(...)` copy once lost `phd` from its vocabulary, and its\n * positionlessness was then cited as the reason the fold could not use it.\n *\n * Not exported through the phase pipeline's `ScrubRule` accounting: a caller\n * that wants the rule NAMED as it fires calls `scrubNameDetail`.\n */\nexport function stripTrailingCredentials(s: string): string {\n\tlet next = s;\n\tfor (;;) {\n\t\tconst m = /[,\\s]+([\\p{L}]+)\\.?$/u.exec(next);\n\t\tif (m === null || !CREDENTIALS.has((m[1] as string).toLocaleLowerCase())) break;\n\t\tnext = next.slice(0, m.index);\n\t}\n\treturn next;\n}\n\n/**\n * A trailing token that is a printed STATUS QUALIFIER rather than half of a\n * double-barrelled name.\n *\n * IT IS HELD ASIDE, NOT STRIPPED. The marker carries the world-qualifier fact,\n * which is the caller's to read; all this set does is stop `close-spaced-hyphen`\n * from welding `ELLA McVeanaivard - WMH` into the surname `McVeanaivard-WMH`. The codes\n * are the printed status-qualifier vocabulary, listed here because this package\n * is a leaf with no dependencies.\n *\n * The qualification-CODE shape (`BN2018`, `AI2015`, `AS2015`, `BN24`, `2017`)\n * needs no list: it carries a digit, so phase 3 refuses the cell anyway.\n */\nconst STATUS_QUALIFIERS: ReadonlySet<string> = new Set([\n\t\"WQ\",\n\t\"WMH\",\n\t\"NQ\",\n\t\"REC\",\n\t\"OS\",\n\t\"R\",\n\t\"FTC\",\n\t\"HM\",\n]);\n\n/** Collapse runs of whitespace and trim. Every rule leaves its own spaces behind. */\nfunction tidy(s: string): string {\n\treturn s.replace(/\\s+/gu, \" \").trim();\n}\n\n/**\n * An INITIALS token: two or more single letters, each a separate initial, at\n * least one of them carrying a period.\n *\n * THE RULE IS THAT TWO PERIODS ARE DIFFERENT FROM ONE. `T.J. Quellane`\n * prints one given name that is spelled with two initials; `Kathryn C.\n * Komythith` prints a given name and a separate middle initial. Splitting the\n * first on its periods invents a second given name that nobody has, so the run\n * is held together as one token while `strip-period` runs, then spelled back\n * compactly — `K. T.` and `T.J` both reach `K.T.` and `T.J.`, which is what\n * makes one dancer's several prints converge instead of fragmenting.\n *\n * A MULTI-LETTER ABBREVIATION IS NOT AN INITIAL, which is the whole boundary:\n * `St. John`, `St.Furaimue` and `SARAH C.NUTTINGDALE` all fail the single-letter unit\n * and take `strip-period` like any other cell.\n *\n * AN APOSTROPHE ENDS THE RUN, and leaving it out is a live defect this caught:\n * `Patrick J. O'Hare` read `J. O` as a two-initial run, since `O` is followed by\n * `'` rather than by a letter, and the seat rendered `Patrick J.O.'Hare`. An\n * apostrophe-join particle is the head of the surname it governs, never an\n * initial.\n */\nconst INITIALS_RUN =\n\t/(?<![\\p{L}\\p{N}.])(?:\\p{L}\\.\\s*){2,}(?![\\p{L}\\p{N}'\\u2019\\u0060])|(?<![\\p{L}\\p{N}.])\\p{L}\\.\\s*\\p{L}(?![\\p{L}\\p{N}'\\u2019\\u0060])/gu;\n\n/** `K. T.` → `K.T.`; `T.J` → `T.J.`. Each letter keeps exactly one period. */\nfunction joinInitials(run: string): string {\n\treturn (run.match(/\\p{L}/gu) ?? []).map((c) => `${c}.`).join(\"\");\n}\n\n/** U+E000 — a private-use marker, so a protected initials token cannot collide. */\nconst HOLD = \"\";\n\n/**\n * Strip one balanced-delimiter aside, or refuse the cell where the\n * `ParentheticalHandler` says the aside makes it no person's name.\n *\n * Shared by `strip-parens` and `strip-quotes` because the two are the same\n * shape — quotes behave as parens — while staying two rules: the caller\n * supplies its own pattern and its own rule name, so each has its own\n * population, its own tests and its own place in the order.\n */\nfunction stripAlias(\n\ts: string,\n\tpattern: RegExp,\n\trule: ScrubRule,\n\trules: ScrubRule[],\n\thandler: ParentheticalHandler,\n\tprint: string,\n): string | null {\n\tconst delimiter = rule === \"strip-quotes\" ? '\"\"' : \"()\";\n\tlet out = s;\n\tlet fired = false;\n\tfor (;;) {\n\t\tconst m = pattern.exec(out);\n\t\tpattern.lastIndex = 0;\n\t\tif (m === null) break;\n\t\tconst inner = (m[1] ?? \"\").trim();\n\t\tif (inner !== \"\") {\n\t\t\tconst verdict = handler(inner, { print, delimiter });\n\t\t\tif (verdict !== \"strip\") {\n\t\t\t\trules.push(verdict === \"refuse\" ? \"refuse-parenthetical\" : verdict.refuse);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tout = `${out.slice(0, m.index)} ${out.slice(m.index + m[0].length)}`;\n\t\tfired = true;\n\t}\n\tif (fired) rules.push(rule);\n\treturn out;\n}\n\n/**\n * Scrub one printed person-name cell. Total: it returns a value for every input,\n * and that value is `NAME_REFUSED` exactly where the cell names no person.\n *\n * An empty print is returned empty and unrefused — \"no name was printed\" is a\n * different fact from \"this is not a name\", and a caller should flag each\n * separately.\n */\nexport function scrubNameDetail(printed: string, options: ScrubOptions = {}): ScrubResult {\n\tconst handler = options.parenthetical ?? stripEveryAside;\n\tconst rules: ScrubRule[] = [];\n\tlet s = tidy(printed);\n\tif (s === \"\") return { value: \"\", refused: false, rules };\n\n\t// ── PHASE 1 — repair, toward what the page meant ─────────────────────────\n\n\t// `0` READ BACK AS `O`, AND IT RUNS FIRST so the four zero-for-O prints never\n\t// reach the digit refusal. It fires only where the `0` LEADS a token and a\n\t// letter or an apostrophe follows, which is the shape of an Irish `O'`\n\t// surname and of nothing else in the corpus: the `0` inside `BN2018` is\n\t// preceded by a digit and the `2017` of a bare-year qualifier does not start\n\t// with one. `../particles/particle-vocabulary.ts` already keys `\"0\"` as an O particle\n\t// with an apostrophe join, so the splitter agrees with this reading.\n\t{\n\t\tconst next = s.replace(/(?<=^|\\s)0(?=['’`]\\p{L}|\\s\\p{L}|\\p{L})/gu, \"O\");\n\t\tif (next !== s) rules.push(\"ocr-zero-for-o\");\n\t\ts = next;\n\t}\n\n\t// `;` READ BACK AS `i`, between letters only: *\"Bad OCR for KESTRIA (lower\n\t// case I)\"*. The replacement takes the case of the letter before it,\n\t// so an all-caps print stays all-caps and the casing rule downstream still\n\t// sees one consistent run.\n\t{\n\t\tconst next = s.replace(/(?<=\\p{L});(?=\\p{L})/gu, (_m, ...a) => {\n\t\t\tconst at = a[a.length - 2] as number;\n\t\t\tconst prev = s[at - 1] as string;\n\t\t\treturn prev === prev.toLocaleUpperCase() && prev !== prev.toLocaleLowerCase() ? \"I\" : \"i\";\n\t\t});\n\t\tif (next !== s) rules.push(\"ocr-semicolon-for-i\");\n\t\ts = next;\n\t}\n\n\t// A STANDALONE U+00B4 IS NOT A LETTER AND NOT AN APOSTROPHE. It is a spacing\n\t// acute the renderer emitted where the page carried an accent, and it is\n\t// dropped rather than re-combined: `Fa´inne` → `Fainne`. Combining it would\n\t// guess which letter it belonged to, which is a question for the page.\n\tif (s.includes(\"´\")) {\n\t\ts = tidy(s.replace(/´/gu, \"\"));\n\t\trules.push(\"ocr-stray-acute\");\n\t}\n\n\t// ── PHASE 2 — strip the junk, keep the name ──────────────────────────────\n\n\t// PARENS FIRST, THEN QUOTES, THEN WHATEVER IS LEFT OVER. The order is the\n\t// rule: the pairs are fixed, and only then is a surviving single delimiter replaced.\n\t{\n\t\tconst next = stripAlias(s, /\\(([^()]*)\\)/u, \"strip-parens\", rules, handler, printed);\n\t\tif (next === null) return { value: NAME_REFUSED, refused: true, rules };\n\t\ts = tidy(next);\n\t}\n\t{\n\t\tconst next = stripAlias(s, /\"([^\"]*)\"/u, \"strip-quotes\", rules, handler, printed);\n\t\tif (next === null) return { value: NAME_REFUSED, refused: true, rules };\n\t\ts = tidy(next);\n\t}\n\tif (/[()\"]/u.test(s)) {\n\t\ts = tidy(s.replace(/[()\"]/gu, \" \"));\n\t\trules.push(\"strip-dangling\");\n\t}\n\n\t// A CREDENTIAL COMES OFF BEFORE ANYTHING READS THE COMMA. The comma of\n\t// `Claire Maxted, ADCRG` is a credential delimiter, not the `Last, First`\n\t// order separator, and handing it to the splitter unguarded parses the\n\t// surname as `Claire Maxted` and the given name as `ADCRG`.\n\t{\n\t\tconst next = stripTrailingCredentials(s);\n\t\tif (next !== s) rules.push(\"strip-credential\");\n\t\ts = tidy(next);\n\t}\n\n\t// AN INITIALS RUN IS HELD OUT OF `strip-period`, then spelled back compactly.\n\tconst held: string[] = [];\n\t{\n\t\tconst next = s.replace(INITIALS_RUN, (run) => {\n\t\t\theld.push(joinInitials(run));\n\t\t\treturn `${HOLD}${held.length - 1}${HOLD}`;\n\t\t});\n\t\tif (held.length > 0) rules.push(\"join-initials\");\n\t\ts = next;\n\t}\n\tif (s.includes(\".\")) {\n\t\ts = s.replace(/\\./gu, \" \");\n\t\trules.push(\"strip-period\");\n\t}\n\t// A LITERAL `\\'` IS AN ESCAPED APOSTROPHE, AND IT RUNS BEFORE `strip-slash`,\n\t// or `O\\'Brien` becomes `O ' Brien` and the surname breaks in two. The earlier\n\t// Java implementation unescaped it; `../lexicon/irish.ts` folds glyph SHAPE\n\t// only, so without this rule the backslash would survive. Zero cells carry\n\t// the shape in the measured corpus — its one backslash is\n\t// `MAKAYLA\\ FONNAILLOW`, a slash before a space — and the rule is still owed,\n\t// because the escape is a property of the producing tool and the next source\n\t// may print it.\n\tif (s.includes(\"\\\\'\")) {\n\t\ts = s.replace(/\\\\'/gu, \"'\");\n\t\trules.push(\"unescape-apostrophe\");\n\t}\n\tif (/[/\\\\]/u.test(s)) {\n\t\ts = s.replace(/[/\\\\]/gu, \" \");\n\t\trules.push(\"strip-slash\");\n\t}\n\ts = tidy(s);\n\n\t// A HYPHEN WITH WHITESPACE BESIDE IT CLOSES UP. `GRACE- OSYRNIA JERLEY` and\n\t// `Maistow - Marie Gallowmere` print one double-barrelled name each, and the space is\n\t// the sheet's, not the name's.\n\t//\n\t// A STATUS QUALIFIER IS HELD ASIDE FIRST, or this rule welds `ELLA McVeanaivard\n\t// - WMH` into the surname `McVeanaivard-WMH`. It is put back untouched: the\n\t// marker carries the world-qualifier fact and that is the caller's to read.\n\t{\n\t\tconst q = /\\s+-\\s*([\\p{Lu}]+)$/u.exec(s);\n\t\tconst trailer = q !== null && STATUS_QUALIFIERS.has(q[1] as string) ? q[0] : \"\";\n\t\tconst head = trailer === \"\" ? s : s.slice(0, s.length - trailer.length);\n\t\tconst closed = head.replace(/\\s+-\\s*|\\s*-\\s+/gu, \"-\");\n\t\tif (closed !== head) rules.push(\"close-spaced-hyphen\");\n\t\ts = closed + trailer;\n\t}\n\n\t// TRAILING NON-LETTERS COME OFF, as the earlier Java implementation's\n\t// `removeTrailingPunct` did. Unicode-aware, unlike a plain `[A-Za-z]` test,\n\t// which would eat the `é` off a name that ends in one. A held initials token\n\t// is restored afterwards, so a name ending in `T.J.` keeps its period.\n\t{\n\t\tconst next = s.replace(/[^\\p{L}\\p{N}]+$/u, \"\");\n\t\tif (next !== s) rules.push(\"strip-trailing-punct\");\n\t\ts = next;\n\t}\n\n\ts = tidy(\n\t\ts.replace(new RegExp(`${HOLD}(\\\\d+)${HOLD}`, \"gu\"), (_m, i) => held[Number(i)] as string),\n\t);\n\n\t// ── PHASE 3 — refuse ─────────────────────────────────────────────────────\n\n\t// A DIGIT, AFTER THE ZERO-FOR-O REPAIR. Nobody's name carries one, and the\n\t// corpus population is a registration or qualification code fused into the\n\t// cell — `- BN2018`, `- AI2015`, `- AS2015`, `- BN24`, the bare year `- 2017`.\n\tif (/\\p{Nd}/u.test(s)) {\n\t\trules.push(\"refuse-digit\");\n\t\treturn { value: NAME_REFUSED, refused: true, rules };\n\t}\n\n\t// A LOCATION TRAILER: *\"need location trailer detection to trigger\n\t// !!!INVALID\"*. The `:` is the signal and it is the only one: the cells are\n\t// a name, a school and a region fused into one field, and there is\n\t// no name in there to recover without deciding where the school begins.\n\t//\n\t// A TRAILING `, <place>` IS NOT THIS RULE AND MUST NOT BE. `Jovindane,\n\t// Katarina Victoria` is a surname-first print whose given name happens to be\n\t// a place name — which is why asides are judged only inside a paired\n\t// delimiter, by the `ParentheticalHandler`.\n\tif (s.includes(\":\")) {\n\t\trules.push(\"refuse-location-trailer\");\n\t\treturn { value: NAME_REFUSED, refused: true, rules };\n\t}\n\n\t// A TEAM DESIGNATION IS NOT A PERSON AND IS NOT A DEFECT. The designation\n\t// has one canonical spelling, `Team`, adorned with at most one upper-case\n\t// letter. The bare form is one whitespace token, so without this exemption\n\t// `refuse-single-token` below would refuse it and a legitimate team cell\n\t// with no letter would be reported as an invalid name.\n\t//\n\t// IT SITS BELOW `refuse-digit` DELIBERATELY. A digit is not a legal\n\t// designator, so `Team 1` must keep refusing and this\n\t// exemption must not be able to reach it. Ordering is the whole guarantee:\n\t// the rule above has already returned by the time this is asked.\n\t//\n\t// THE VALUE IS NOT CANONICALIZED HERE. Casing is `./name-case.ts`'s and runs\n\t// after this file (§ *What is NOT here*), so `TEAM A` leaves this function\n\t// spelled as the sheet spelled it and reaches the canonical `Team A` at the\n\t// renderer, exactly as it did before.\n\tif (canonicalTeamName(s) !== null) {\n\t\trules.push(\"accept-team\");\n\t\treturn { value: s, refused: false, rules };\n\t}\n\n\t// ONE TOKEN CANNOT BE BOTH A SURNAME AND A GIVEN NAME. The earlier Java\n\t// implementation refused it outright, and here the same print scrubs to\n\t// `!!!INVALID` — `KESTRELDUNMERE`, `CHLOE`, `Saunders`, `???`. The bare `???`\n\t// names nobody and lands here too, having no letters at all. A bare `Team`\n\t// would too, but the team exemption above has already accepted it.\n\tif (s.split(\" \").filter((t) => t !== \"\").length < 2) {\n\t\trules.push(\"refuse-single-token\");\n\t\treturn { value: NAME_REFUSED, refused: true, rules };\n\t}\n\n\treturn { value: s, refused: false, rules };\n}\n\n/** `scrubNameDetail`'s value alone, for the callers that do not count rules. */\nexport function scrubName(printed: string): string {\n\treturn scrubNameDetail(printed).value;\n}\n",
5
+ "/**\n * name-scrub.ts — the three-phase treatment a printed person-name cell gets\n * before anything splits it.\n *\n * The rules, in the words that set them —\n *\n * > if there are dangling pairs (a single `\"` or `)` or `(` ) then those get\n * > replaced after the pairs are fixed\n *\n * > the credentials should probably be stripped. fix the initials (two periods\n * > are different than one). it must run on adjudicators. They are people.\n *\n * ## THE PHASE ORDER IS PART OF THE RULE\n *\n * REPAIR, then STRIP, then REFUSE. The reason is mechanical: `Samantha 0 Connor`\n * carries a digit, so a refusal that ran first would throw away a print the\n * repair can fix. Every rule below names its phase and the phases run in that\n * order, once, top to bottom.\n *\n * ## It moves AWAY from the print\n *\n * Everything here is a reading applied on the way into a derived store; it never\n * rewrites the transcription. The transcription keeps what the page printed, and\n * a consumer should keep the printed value beside the scrubbed one. Nothing here\n * is an erratum: an erratum repairs a transcription toward the page, and the\n * phase-1 repairs below are downstream readings of a print that is not being\n * re-rendered.\n *\n * ## The refusal is a value, not an exception\n *\n * A cell that cannot be a person's name scrubs to `NAME_REFUSED`, spelled\n * `!!!INVALID`. It is deliberately not a name-shaped string: it can never be\n * mistaken for a rendered `Last<<First`, it sorts and greps out of the way, and\n * a consumer that forgets to check it produces visible nonsense rather than a\n * plausible dancer. A consumer should count it, so the population is reported\n * rather than silently absorbed.\n *\n * ## What is NOT here\n *\n * - **Casing, ASCII folding, splitting.** `./name-case.ts`,\n * `../lexicon/ascii-approx.ts` and `./name-split.ts` own those and run after\n * this.\n * - **The comma.** It is the `Last, First` order separator and is read against\n * the producing document's `meta.nameFormat` by `./name-split.ts`. The one\n * comma this file touches is the credential delimiter of `Maxwell, ADCRG`,\n * which is not an order separator and would otherwise make `ADCRG` a given\n * name.\n * - **A printed status qualifier fused into the cell** (`- WMH`) — a separate\n * fact for the caller, held aside here only so the spaced-hyphen rule does\n * not close it up into a surname.\n * - **A lost byte printing as `?`** (`Jystarvard, M?jaillell`) — an erratum toward the\n * page, corrected in the transcription rather than guessed at here. The bare\n * `???` names nobody and is refused here.\n * - **A trailing `Á'` that is really in the source bytes.** Where the source file\n * itself carries `0xC1 0x27` and it is decoded faithfully, with no OCR in the\n * path, the question is whether the source is accurate, not a mis-decode this\n * layer may read through.\n */\n\nimport { canonicalTeamName } from \"./team-name.ts\";\n\n/**\n * The refusal value: a cell that cannot be a person's name.\n *\n * ONE SPELLING, EVERYWHERE. Phase 3 says the cell \"is `!!!INVALID`\", and no\n * other spelling of the refusal exists anywhere in the tree.\n */\nexport const NAME_REFUSED = \"!!!INVALID\";\n\n/** Which rule fired. Stable strings — a census and a report quote them. */\nexport type ScrubRule =\n\t// ── phase 1, repair ──────────────────────────────────────────────────────\n\t/** `0` leading a name token read back as `O`: `JESSICA 0'SULLIVAN`. */\n\t| \"ocr-zero-for-o\"\n\t/** `;` between letters read back as `i`: `KESTR;A-ROSE` → `KESTRIA-ROSE`. */\n\t| \"ocr-semicolon-for-i\"\n\t/** A standalone U+00B4 ACUTE dropped: `Fa´inne` → `Fainne`. */\n\t| \"ocr-stray-acute\"\n\t// ── phase 2, strip ───────────────────────────────────────────────────────\n\t/** A parenthesised alias removed: `Lena (Xiaoyu) Zumock` → `Lena Zumock`. */\n\t| \"strip-parens\"\n\t/** A quoted nickname removed: `Pundeallina \"Katie\" Foxe` → `Pundeallina Foxe`. */\n\t| \"strip-quotes\"\n\t/** A `(`, `)` or `\"` left over once the pairs are gone, replaced by a space. */\n\t| \"strip-dangling\"\n\t/** A trailing teaching credential removed: `Maxwell, ADCRG` → `Maxwell`. */\n\t| \"strip-credential\"\n\t/** A `.` that is not part of an initials token, replaced by a space. */\n\t| \"strip-period\"\n\t/** An initials token held together and spelled compactly: `K. T.` → `K.T.`. */\n\t| \"join-initials\"\n\t/** A literal `\\'` read back as the apostrophe it escapes: `O\\'Brien` → `O'Brien`. */\n\t| \"unescape-apostrophe\"\n\t/** `/` or `\\` replaced by a space: `MAKAYLA\\ FONNAILLOW`. */\n\t| \"strip-slash\"\n\t/** A hyphen with whitespace beside it closed up: `GRACE- OSYRNIA` → `GRACE-OSYRNIA`. */\n\t| \"close-spaced-hyphen\"\n\t/** Trailing non-letters removed: `Annika Walter,` → `Annika Walter`. */\n\t| \"strip-trailing-punct\"\n\t// ── phase 3, refuse ──────────────────────────────────────────────────────\n\t/** A digit survived phase 1: `KELSEY PEARRAILLINA - BN2018`. */\n\t| \"refuse-digit\"\n\t/** A location trailer: `London Hryniuk Lyrunnett : Western Region, Canada`. */\n\t| \"refuse-location-trailer\"\n\t/**\n\t * A parenthesised or quoted aside the `ParentheticalHandler` refused. A handler\n\t * may name its own `refuse-…` rule instead (e.g. `refuse-location-alias`).\n\t */\n\t| \"refuse-parenthetical\"\n\t| `refuse-${string}`\n\t/** One token cannot be both a surname and a given name: `Saunders`, `???`. */\n\t| \"refuse-single-token\"\n\t/**\n\t * A team designation in its canonical format, exempted from the refusals\n\t * below it: `Team`, `Team A`. The EIGHTEENTH rule, added after the others: a\n\t * team designation has a canonical format (`./team-name.ts`), which takes\n\t * `Team` out of `refuse-single-token`'s population. It repairs nothing and\n\t * strips nothing; it is recorded so the census can count the exemption rather\n\t * than report a silent gap in the refusals.\n\t */\n\t| \"accept-team\";\n\n/**\n * What an aside set apart by `( … )` or `\" … \"` in a name cell means.\n *\n * Asked once per pair, inside-out, with the trimmed text between the delimiters.\n * `\"strip\"` removes the pair (the aside is a nickname or alias:\n * `Lena (Xiaoyu) Zumock` → `Lena Zumock`). `\"refuse\"` refuses the whole cell as no\n * person's name, under `refuse-parenthetical`; `{ refuse: \"refuse-<rule>\" }`\n * refuses it under a rule the caller names.\n *\n * ASKED ONLY INSIDE THE DELIMITERS, never of a bare token: `Victoria` and\n * `London` are good given names in the open.\n */\nexport type ParentheticalHandler = (\n\taside: string,\n\tcontext: { readonly print: string; readonly delimiter: \"()\" | '\"\"' },\n) => \"strip\" | \"refuse\" | { readonly refuse: `refuse-${string}` };\n\n/** The default: every aside is an alias, and is stripped. */\nexport const stripEveryAside: ParentheticalHandler = () => \"strip\";\n\n/** Options for `scrubNameDetail`. */\nexport interface ScrubOptions {\n\t/** default: `stripEveryAside` */\n\treadonly parenthetical?: ParentheticalHandler;\n}\n\nexport interface ScrubResult {\n\t/** The scrubbed print, or `NAME_REFUSED`. */\n\tvalue: string;\n\t/** True when `value` is `NAME_REFUSED`. */\n\trefused: boolean;\n\t/** Every rule that fired, in the order the phases ran them. */\n\trules: ScrubRule[];\n}\n\n/**\n * Teaching credentials, stripped; generational suffixes, kept.\n *\n * The split is that of an earlier Java implementation, which ran over this corpus\n * for years: it lists `TCRG`, `ADCRG`, `BG`, `PHD` beside `Jr`, `II`, `III`,\n * `IV`, and only the first group is stripped (\"the credentials should probably\n * be stripped\"). `SDCRG` is added because the corpus prints it (17 panel seats)\n * and\n * it is the same kind of thing — a CLRG teaching qualification, not part of\n * anybody's name. A generational suffix IS part of the name and stays, which is\n * why `./name-split.ts`'s `NAME_SUFFIXES` still carries both groups: it has to\n * recognize what it must not make a surname.\n */\nconst CREDENTIALS: ReadonlySet<string> = new Set([\"tcrg\", \"adcrg\", \"sdcrg\", \"bg\", \"phd\"]);\n\n/**\n * The `strip-credential` rule, on its own, so the one implementation serves\n * every caller.\n *\n * TRAILING POSITION ONLY. The regex is end-anchored, which is the whole\n * content of the rule: `Bg` *inside* a name is untouched, and a bare `ADCRG`\n * with nothing before it is not a credential to strip — it is all there is.\n * The separator may be a comma or a space, because a source prints both\n * (`Claire Maxted, ADCRG` and `Alice Gellane-O'Luthindby ADCRG`), and an optional\n * full stop is allowed after the token. It loops, so `Dr. Irene Brustirley, PhD,\n * ADCRG` loses both.\n *\n * IT TAKES A PRINTED NAME *OR* A FOLDED KEY. Both are handled by the same\n * anchor: a fold key is lower-case with single spaces, so `carol quarnell\n * adcrg` matches on the space exactly as the printed form matches on the\n * comma. An adjudicator fold is the typical second caller, and a second copy of\n * these five lines is precisely what lets the two drift — a positionless\n * `split(\" \").filter(...)` copy once lost `phd` from its vocabulary, and its\n * positionlessness was then cited as the reason the fold could not use it.\n *\n * Not exported through the phase pipeline's `ScrubRule` accounting: a caller\n * that wants the rule NAMED as it fires calls `scrubNameDetail`.\n */\nexport function stripTrailingCredentials(s: string): string {\n\tlet next = s;\n\tfor (;;) {\n\t\tconst m = /[,\\s]+([\\p{L}]+)\\.?$/u.exec(next);\n\t\tif (m === null || !CREDENTIALS.has((m[1] as string).toLocaleLowerCase())) break;\n\t\tnext = next.slice(0, m.index);\n\t}\n\treturn next;\n}\n\n/**\n * A trailing token that is a printed STATUS QUALIFIER rather than half of a\n * double-barrelled name.\n *\n * IT IS HELD ASIDE, NOT STRIPPED. The marker carries the world-qualifier fact,\n * which is the caller's to read; all this set does is stop `close-spaced-hyphen`\n * from welding `ELLA McVeanaivard - WMH` into the surname `McVeanaivard-WMH`. The codes\n * are the printed status-qualifier vocabulary, listed here because this package\n * is a leaf with no dependencies.\n *\n * The qualification-CODE shape (`BN2018`, `AI2015`, `AS2015`, `BN24`, `2017`)\n * needs no list: it carries a digit, so phase 3 refuses the cell anyway.\n */\nconst STATUS_QUALIFIERS: ReadonlySet<string> = new Set([\n\t\"WQ\",\n\t\"WMH\",\n\t\"NQ\",\n\t\"REC\",\n\t\"OS\",\n\t\"R\",\n\t\"FTC\",\n\t\"HM\",\n]);\n\n/** Collapse runs of whitespace and trim. Every rule leaves its own spaces behind. */\nfunction tidy(s: string): string {\n\treturn s.replace(/\\s+/gu, \" \").trim();\n}\n\n/**\n * An INITIALS token: two or more single letters, each a separate initial, at\n * least one of them carrying a period.\n *\n * THE RULE IS THAT TWO PERIODS ARE DIFFERENT FROM ONE. `T.J. Quellane`\n * prints one given name that is spelled with two initials; `Kathryn C.\n * Komythith` prints a given name and a separate middle initial. Splitting the\n * first on its periods invents a second given name that nobody has, so the run\n * is held together as one token while `strip-period` runs, then spelled back\n * compactly — `K. T.` and `T.J` both reach `K.T.` and `T.J.`, which is what\n * makes one dancer's several prints converge instead of fragmenting.\n *\n * A MULTI-LETTER ABBREVIATION IS NOT AN INITIAL, which is the whole boundary:\n * `St. John`, `St.Furaimue` and `SARAH C.NUTTINGDALE` all fail the single-letter unit\n * and take `strip-period` like any other cell.\n *\n * AN APOSTROPHE ENDS THE RUN, and leaving it out is a live defect this caught:\n * `Patrick J. O'Hare` read `J. O` as a two-initial run, since `O` is followed by\n * `'` rather than by a letter, and the seat rendered `Patrick J.O.'Hare`. An\n * apostrophe-join particle is the head of the surname it governs, never an\n * initial.\n */\nconst INITIALS_RUN =\n\t/(?<![\\p{L}\\p{N}.])(?:\\p{L}\\.\\s*){2,}(?![\\p{L}\\p{N}'\\u2019\\u0060])|(?<![\\p{L}\\p{N}.])\\p{L}\\.\\s*\\p{L}(?![\\p{L}\\p{N}'\\u2019\\u0060])/gu;\n\n/** `K. T.` → `K.T.`; `T.J` → `T.J.`. Each letter keeps exactly one period. */\nfunction joinInitials(run: string): string {\n\treturn (run.match(/\\p{L}/gu) ?? []).map((c) => `${c}.`).join(\"\");\n}\n\n/** U+E000 — a private-use marker, so a protected initials token cannot collide. */\nconst HOLD = \"\";\n\n/**\n * Strip one balanced-delimiter aside, or refuse the cell where the\n * `ParentheticalHandler` says the aside makes it no person's name.\n *\n * Shared by `strip-parens` and `strip-quotes` because the two are the same\n * shape — quotes behave as parens — while staying two rules: the caller\n * supplies its own pattern and its own rule name, so each has its own\n * population, its own tests and its own place in the order.\n */\nfunction stripAlias(\n\ts: string,\n\tpattern: RegExp,\n\trule: ScrubRule,\n\trules: ScrubRule[],\n\thandler: ParentheticalHandler,\n\tprint: string,\n): string | null {\n\tconst delimiter = rule === \"strip-quotes\" ? '\"\"' : \"()\";\n\tlet out = s;\n\tlet fired = false;\n\tfor (;;) {\n\t\tconst m = pattern.exec(out);\n\t\tpattern.lastIndex = 0;\n\t\tif (m === null) break;\n\t\tconst inner = (m[1] ?? \"\").trim();\n\t\tif (inner !== \"\") {\n\t\t\tconst verdict = handler(inner, { print, delimiter });\n\t\t\tif (verdict !== \"strip\") {\n\t\t\t\trules.push(verdict === \"refuse\" ? \"refuse-parenthetical\" : verdict.refuse);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tout = `${out.slice(0, m.index)} ${out.slice(m.index + m[0].length)}`;\n\t\tfired = true;\n\t}\n\tif (fired) rules.push(rule);\n\treturn out;\n}\n\n/**\n * Scrub one printed person-name cell. Total: it returns a value for every input,\n * and that value is `NAME_REFUSED` exactly where the cell names no person.\n *\n * An empty print is returned empty and unrefused — \"no name was printed\" is a\n * different fact from \"this is not a name\", and a caller should flag each\n * separately.\n */\nexport function scrubNameDetail(printed: string, options: ScrubOptions = {}): ScrubResult {\n\tconst handler = options.parenthetical ?? stripEveryAside;\n\tconst rules: ScrubRule[] = [];\n\tlet s = tidy(printed);\n\tif (s === \"\") return { value: \"\", refused: false, rules };\n\n\t// ── PHASE 1 — repair, toward what the page meant ─────────────────────────\n\n\t// `0` READ BACK AS `O`, AND IT RUNS FIRST so the four zero-for-O prints never\n\t// reach the digit refusal. It fires only where the `0` LEADS a token and a\n\t// letter or an apostrophe follows, which is the shape of an Irish `O'`\n\t// surname and of nothing else in the corpus: the `0` inside `BN2018` is\n\t// preceded by a digit and the `2017` of a bare-year qualifier does not start\n\t// with one. `../particles/particle-vocabulary.ts` already keys `\"0\"` as an O particle\n\t// with an apostrophe join, so the splitter agrees with this reading.\n\t{\n\t\tconst next = s.replace(/(?<=^|\\s)0(?=['’`]\\p{L}|\\s\\p{L}|\\p{L})/gu, \"O\");\n\t\tif (next !== s) rules.push(\"ocr-zero-for-o\");\n\t\ts = next;\n\t}\n\n\t// `;` READ BACK AS `i`, between letters only: *\"Bad OCR for KESTRIA (lower\n\t// case I)\"*. The replacement takes the case of the letter before it,\n\t// so an all-caps print stays all-caps and the casing rule downstream still\n\t// sees one consistent run.\n\t{\n\t\tconst next = s.replace(/(?<=\\p{L});(?=\\p{L})/gu, (_m, ...a) => {\n\t\t\tconst at = a[a.length - 2] as number;\n\t\t\tconst prev = s[at - 1] as string;\n\t\t\treturn prev === prev.toLocaleUpperCase() && prev !== prev.toLocaleLowerCase() ? \"I\" : \"i\";\n\t\t});\n\t\tif (next !== s) rules.push(\"ocr-semicolon-for-i\");\n\t\ts = next;\n\t}\n\n\t// A STANDALONE U+00B4 IS NOT A LETTER AND NOT AN APOSTROPHE. It is a spacing\n\t// acute the renderer emitted where the page carried an accent, and it is\n\t// dropped rather than re-combined: `Fa´inne` → `Fainne`. Combining it would\n\t// guess which letter it belonged to, which is a question for the page.\n\tif (s.includes(\"´\")) {\n\t\ts = tidy(s.replace(/´/gu, \"\"));\n\t\trules.push(\"ocr-stray-acute\");\n\t}\n\n\t// ── PHASE 2 — strip the junk, keep the name ──────────────────────────────\n\n\t// PARENS FIRST, THEN QUOTES, THEN WHATEVER IS LEFT OVER. The order is the\n\t// rule: the pairs are fixed, and only then is a surviving single delimiter replaced.\n\t{\n\t\tconst next = stripAlias(s, /\\(([^()]*)\\)/u, \"strip-parens\", rules, handler, printed);\n\t\tif (next === null) return { value: NAME_REFUSED, refused: true, rules };\n\t\ts = tidy(next);\n\t}\n\t{\n\t\tconst next = stripAlias(s, /\"([^\"]*)\"/u, \"strip-quotes\", rules, handler, printed);\n\t\tif (next === null) return { value: NAME_REFUSED, refused: true, rules };\n\t\ts = tidy(next);\n\t}\n\tif (/[()\"]/u.test(s)) {\n\t\ts = tidy(s.replace(/[()\"]/gu, \" \"));\n\t\trules.push(\"strip-dangling\");\n\t}\n\n\t// A CREDENTIAL COMES OFF BEFORE ANYTHING READS THE COMMA. The comma of\n\t// `Claire Maxted, ADCRG` is a credential delimiter, not the `Last, First`\n\t// order separator, and handing it to the splitter unguarded parses the\n\t// surname as `Claire Maxted` and the given name as `ADCRG`.\n\t{\n\t\tconst next = stripTrailingCredentials(s);\n\t\tif (next !== s) rules.push(\"strip-credential\");\n\t\ts = tidy(next);\n\t}\n\n\t// AN INITIALS RUN IS HELD OUT OF `strip-period`, then spelled back compactly.\n\tconst held: string[] = [];\n\t{\n\t\tconst next = s.replace(INITIALS_RUN, (run) => {\n\t\t\theld.push(joinInitials(run));\n\t\t\treturn `${HOLD}${held.length - 1}${HOLD}`;\n\t\t});\n\t\tif (held.length > 0) rules.push(\"join-initials\");\n\t\ts = next;\n\t}\n\tif (s.includes(\".\")) {\n\t\ts = s.replace(/\\./gu, \" \");\n\t\trules.push(\"strip-period\");\n\t}\n\t// A LITERAL `\\'` IS AN ESCAPED APOSTROPHE, AND IT RUNS BEFORE `strip-slash`,\n\t// or `O\\'Brien` becomes `O ' Brien` and the surname breaks in two. The earlier\n\t// Java implementation unescaped it; `../lexicon/irish.ts` folds glyph SHAPE\n\t// only, so without this rule the backslash would survive. Zero cells carry\n\t// the shape in the measured corpus — its one backslash is\n\t// `MAKAYLA\\ FONNAILLOW`, a slash before a space — and the rule is still owed,\n\t// because the escape is a property of the producing tool and the next source\n\t// may print it.\n\tif (s.includes(\"\\\\'\")) {\n\t\ts = s.replace(/\\\\'/gu, \"'\");\n\t\trules.push(\"unescape-apostrophe\");\n\t}\n\tif (/[/\\\\]/u.test(s)) {\n\t\ts = s.replace(/[/\\\\]/gu, \" \");\n\t\trules.push(\"strip-slash\");\n\t}\n\ts = tidy(s);\n\n\t// A HYPHEN WITH WHITESPACE BESIDE IT CLOSES UP. `GRACE- OSYRNIA JERLEY` and\n\t// `Maistow - Marie Gallowmere` print one double-barrelled name each, and the space is\n\t// the sheet's, not the name's.\n\t//\n\t// A STATUS QUALIFIER IS HELD ASIDE FIRST, or this rule welds `ELLA McVeanaivard\n\t// - WMH` into the surname `McVeanaivard-WMH`. It is put back untouched: the\n\t// marker carries the world-qualifier fact and that is the caller's to read.\n\t{\n\t\tconst q = /\\s+-\\s*([\\p{Lu}]+)$/u.exec(s);\n\t\tconst trailer = q !== null && STATUS_QUALIFIERS.has(q[1] as string) ? q[0] : \"\";\n\t\tconst head = trailer === \"\" ? s : s.slice(0, s.length - trailer.length);\n\t\tconst closed = head.replace(/\\s+-\\s*|\\s*-\\s+/gu, \"-\");\n\t\tif (closed !== head) rules.push(\"close-spaced-hyphen\");\n\t\ts = closed + trailer;\n\t}\n\n\t// TRAILING NON-LETTERS COME OFF, as the earlier Java implementation's\n\t// `removeTrailingPunct` did. Unicode-aware, unlike a plain `[A-Za-z]` test,\n\t// which would eat the `é` off a name that ends in one. A held initials token\n\t// is restored afterwards, so a name ending in `T.J.` keeps its period.\n\t{\n\t\tconst next = s.replace(/[^\\p{L}\\p{N}]+$/u, \"\");\n\t\tif (next !== s) rules.push(\"strip-trailing-punct\");\n\t\ts = next;\n\t}\n\n\ts = tidy(\n\t\ts.replace(new RegExp(`${HOLD}(\\\\d+)${HOLD}`, \"gu\"), (_m, i) => held[Number(i)] as string),\n\t);\n\n\t// ── PHASE 3 — refuse ─────────────────────────────────────────────────────\n\n\t// A DIGIT, AFTER THE ZERO-FOR-O REPAIR. Nobody's name carries one, and the\n\t// corpus population is a registration or qualification code fused into the\n\t// cell — `- BN2018`, `- AI2015`, `- AS2015`, `- BN24`, the bare year `- 2017`.\n\tif (/\\p{Nd}/u.test(s)) {\n\t\trules.push(\"refuse-digit\");\n\t\treturn { value: NAME_REFUSED, refused: true, rules };\n\t}\n\n\t// A LOCATION TRAILER: *\"need location trailer detection to trigger\n\t// !!!INVALID\"*. The `:` is the signal and it is the only one: the cells are\n\t// a name, a school and a region fused into one field, and there is\n\t// no name in there to recover without deciding where the school begins.\n\t//\n\t// A TRAILING `, <place>` IS NOT THIS RULE AND MUST NOT BE. `Jovindane,\n\t// Katarina Victoria` is a surname-first print whose given name happens to be\n\t// a place name — which is why asides are judged only inside a paired\n\t// delimiter, by the `ParentheticalHandler`.\n\tif (s.includes(\":\")) {\n\t\trules.push(\"refuse-location-trailer\");\n\t\treturn { value: NAME_REFUSED, refused: true, rules };\n\t}\n\n\t// A TEAM DESIGNATION IS NOT A PERSON AND IS NOT A DEFECT. The designation\n\t// has one canonical spelling, `Team`, adorned with at most one upper-case\n\t// letter. The bare form is one whitespace token, so without this exemption\n\t// `refuse-single-token` below would refuse it and a legitimate team cell\n\t// with no letter would be reported as an invalid name.\n\t//\n\t// IT SITS BELOW `refuse-digit` DELIBERATELY. A digit is not a legal\n\t// designator, so `Team 1` must keep refusing and this\n\t// exemption must not be able to reach it. Ordering is the whole guarantee:\n\t// the rule above has already returned by the time this is asked.\n\t//\n\t// THE VALUE IS NOT CANONICALIZED HERE. Casing is `./name-case.ts`'s and runs\n\t// after this file (§ *What is NOT here*), so `TEAM A` leaves this function\n\t// spelled as the sheet spelled it and reaches the canonical `Team A` at the\n\t// renderer, exactly as it did before.\n\tif (canonicalTeamName(s) !== null) {\n\t\trules.push(\"accept-team\");\n\t\treturn { value: s, refused: false, rules };\n\t}\n\n\t// ONE TOKEN CANNOT BE BOTH A SURNAME AND A GIVEN NAME. The earlier Java\n\t// implementation refused it outright, and here the same print scrubs to\n\t// `!!!INVALID` — `KESTRELDUNMERE`, `CHLOE`, `Saunders`, `???`. The bare `???`\n\t// names nobody and lands here too, having no letters at all. A bare `Team`\n\t// would too, but the team exemption above has already accepted it. A comma\n\t// separates tokens as a space does, so `Surname,Given` is two tokens, as\n\t// `Surname, Given` is.\n\tif (s.split(/[ ,]/).filter((t) => t !== \"\").length < 2) {\n\t\trules.push(\"refuse-single-token\");\n\t\treturn { value: NAME_REFUSED, refused: true, rules };\n\t}\n\n\treturn { value: s, refused: false, rules };\n}\n\n/** `scrubNameDetail`'s value alone, for the callers that do not count rules. */\nexport function scrubName(printed: string): string {\n\treturn scrubNameDetail(printed).value;\n}\n",
6
6
  "/**\n * `foldNameKey` — the blocking key over a PRINTED PERSONAL NAME.\n *\n * One implementation for two kinds of consumer, and that is the whole reason it\n * lives here rather than beside either of them:\n *\n * - a record linker folds every printed adjudicator and dancer string to\n * block candidate pairs;\n * - a panel check folds a printed PANEL SEAT to whole tokens, so a seat-state\n * word (\"withdrawn\", \"vacant\") is matched on a token and never on a\n * substring.\n *\n * The two must not be able to disagree. A seat the transcription-time check\n * calls a person and the linker calls a marker — or the reverse — is a silent\n * split between two layers over one printed string, so the fold lives in this\n * zero-dependency leaf rather than being copied: a second copy can silently\n * disagree with the first.\n *\n * IT IS A BLOCKING KEY, NEVER AN IDENTITY KEY — this package's standing rule.\n * Two prints folding alike are a candidate pair, nothing more.\n *\n * WHAT IT FOLDS, in order: NFD decomposition, combining marks dropped\n * (U+0300–U+036F), lowercase, every character outside `a-z` and space replaced\n * by a space, runs of whitespace collapsed, ends trimmed. So `\"Ní Jirkirkane\"` and\n * `\"Ni Jirkirkane\"` fold alike, `\"O'Hare\"` folds to `o hare`, and `\"N/A\"` folds to\n * the two tokens `n a`.\n */\nexport function foldNameKey(s: string): string {\n\treturn s\n\t\t.normalize(\"NFD\")\n\t\t.replace(/[̀-ͯ]/g, \"\")\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z ]/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n}\n\n/**\n * `nameFold` — the COMPARISON fold over one name token or one joined run.\n *\n * Distinct from `foldNameKey` above and deliberately not merged with it: that\n * one is a blocking key over a whole printed name and KEEPS the whitespace that\n * separates its tokens, because a seat marker is matched on whole tokens. This\n * one exists to ask whether two spellings of the SAME span are the same span, so\n * it drops every separator there is.\n *\n * APPLIED TO A JOINED RUN RATHER THAN TOKEN BY TOKEN wherever a surname is\n * compared, because `name-split.ts`'s tokenizer glues `O Brien` into one token\n * while the printed cell holds two. Concatenating before folding makes the two\n * spellings equal without either side knowing about the glue.\n *\n * IT LIVES IN THIS LEAF BECAUSE THREE THINGS AT THREE LAYERS MUST AGREE on it:\n * the primed bar's anchor index (`./name-order-bar.ts`), the generated compound\n * surname table (`./compound-surnames.ts`) and the splitter that looks a span up\n * in that table (`./name-split.ts`). A second copy of these five lines is a\n * table whose keys silently stop matching the lookups.\n */\nexport function nameFold(s: string): string {\n\treturn s\n\t\t.normalize(\"NFD\")\n\t\t.replace(/\\p{M}+/gu, \"\")\n\t\t.replace(/[^\\p{L}\\p{N}]+/gu, \"\")\n\t\t.toLocaleLowerCase();\n}\n",
7
- "/**\n * name-placeholder.ts — THE ONE ANSWER to \"did the page print a name here at all\".\n *\n * A person cell prints NO NAME when it is one of three things, and this file is where all\n * three are decided:\n *\n * 1. it holds no letter at all: empty, whitespace, `???`, `0`, `, .`, `22 - ()`\n * (`^[^\\p{L}]*$`, any Unicode letter, so a name written in a non-Latin script is a\n * name);\n * 2. it is a platform sentinel a row's name cell and school cell share (`N/A`, `TBA`,\n * `Unknown`, `None`): `PLATFORM_PLACEHOLDERS`, asked through `isPlaceholderPrint`, ONE\n * list for both cells so they cannot drift apart;\n * 3. it is one of `NAME_PLACEHOLDERS`: the sentinels only a NAME cell prints, each with\n * where it was measured.\n *\n * `PersonName.printsNoName()` is the accessor a caller holding a parse asks; `isNoNamePrint`\n * is the same answer for a caller holding only the print, and it parses nothing.\n *\n * A TEST ENTRY IS NOT HERE. `Test Dancer` prints a name-shaped string; whether a platform's\n * test entries are rows at all is a different question from whether a name was printed, and it\n * is the consumer's.\n */\n\nimport { foldNameKey } from \"./name-fold.ts\";\n\n/** One sentinel a cell prints where no name was given, with its measurement. */\nexport interface NamePlaceholder {\n\t/** the print folded by `foldNameKey`: lower case, accents and punctuation gone, single spaces */\n\treadonly print: string;\n\t/** where it was seen, so a reviewer can audit the row */\n\treadonly authority: string;\n}\n\n/**\n * THE SHARED SENTINELS: what an entry platform writes where nothing was entered, in a name cell\n * or a school cell alike. A school reader asks `isPlaceholderPrint` of its cell, so `N/A` is\n * refused on both sides of a row by this one list. A sentinel worded about a school\n * (`No School`, `-- Choose One --`) is a school-cell fact and stays with the school reader.\n *\n * Measured 2026-10-01 over every stream of the results corpus (3,776,915 rows): rows per\n * cell, matched on the fold.\n */\nexport const PLATFORM_PLACEHOLDERS: readonly NamePlaceholder[] = [\n\t{\n\t\tprint: \"unknown\",\n\t\tauthority:\n\t\t\t\"4 name rows (`Unknown`, `unknown`); 237 school rows (`Unknown`, `unknown`, `*Unknown*`)\",\n\t},\n\t{ print: \"tba\", authority: \"4 name rows (`TBA`); 4 school rows\" },\n\t{\n\t\tprint: \"n a\",\n\t\tauthority:\n\t\t\t\"42 name rows (`#N/A`, a spreadsheet's missing-value mark; it parsed as the person `A<<N`); 43 school rows (`#N/A`, `N/A`)\",\n\t},\n\t{ print: \"none\", authority: \"0 name rows; 21 school rows (`None`, `none`)\" },\n\t{ print: \"not applicable\", authority: \"0 name rows; 1 school row (`Not applicable`)\" },\n];\n\n/**\n * THE NAME-ONLY SENTINELS: the placeholder-shaped prints that hold a letter, that only a name\n * cell prints, and that `PLATFORM_PLACEHOLDERS` does not already hold. Measured 2026-10-01 over\n * every stream of the results corpus (3,776,915 rows).\n */\nexport const NAME_PLACEHOLDERS: readonly NamePlaceholder[] = [\n\t{\n\t\tprint: \"name withheld\",\n\t\tauthority: \"`Name Withheld`, 136 rows: the platform printed that the name was withheld\",\n\t},\n\t{\n\t\tprint: \"none none\",\n\t\tauthority: \"`none none`, 5 rows: the sentinel `none` typed into both name fields\",\n\t},\n\t{\n\t\tprint: \"not known\",\n\t\tauthority: \"`Not known`, 2 rows. It parsed as the person `Known<<Not`\",\n\t},\n\t{\n\t\tprint: \"x\",\n\t\tauthority: \"`X`, 2 rows: a bare keyboard filler in the name field\",\n\t},\n];\n\nconst SHARED = new Set(PLATFORM_PLACEHOLDERS.map((p) => p.print));\nconst NAME_ONLY = new Set(NAME_PLACEHOLDERS.map((p) => p.print));\n\nconst HAS_LETTER = /\\p{L}/u;\n\n/**\n * Is this print one of the PLATFORM PLACEHOLDERS a name cell and a school cell share\n * (`N/A`, `TBA`, `Unknown`, `None`)? The question a school reader asks of its cell.\n */\nexport function isPlaceholderPrint(print: string): boolean {\n\treturn SHARED.has(foldNameKey(print));\n}\n\n/**\n * Did this person cell print NO NAME: no letter, a shared placeholder, or a name-only one?\n * Total over any string; the print is read, never rewritten, and nothing is parsed.\n */\nexport function isNoNamePrint(print: string): boolean {\n\tif (!HAS_LETTER.test(print)) return true;\n\tconst folded = foldNameKey(print);\n\treturn NAME_ONLY.has(folded) || SHARED.has(folded);\n}\n",
7
+ "/**\n * name-placeholder.ts — THE ONE ANSWER to \"did the page print a name here at all\".\n *\n * A person cell prints NO NAME when it is one of three things, and this file is where all\n * three are decided:\n *\n * 1. it holds no letter at all: empty, whitespace, `???`, `0`, `, .`, `22 - ()`\n * (`^[^\\p{L}]*$`, any Unicode letter, so a name written in a non-Latin script is a\n * name);\n * 2. it is a platform sentinel a row's name cell and school cell share (`N/A`, `TBA`,\n * `Unknown`, `None`, `No School`, `Independent`): `PLATFORM_PLACEHOLDERS`, asked through\n * `isPlaceholderPrint`, ONE list for both cells so they cannot drift apart;\n * 3. it is one of `NAME_PLACEHOLDERS`: the sentinels only a NAME cell prints, each with\n * where it was measured.\n *\n * `PersonName.printsNoName()` is the accessor a caller holding a parse asks; `isNoNamePrint`\n * is the same answer for a caller holding only the print, and it parses nothing.\n *\n * A TEST ENTRY IS NOT HERE. `Test Dancer` prints a name-shaped string; whether a platform's\n * test entries are rows at all is a different question from whether a name was printed, and it\n * is the consumer's.\n */\n\nimport { foldNameKey } from \"./name-fold.ts\";\n\n/** One sentinel a cell prints where no name was given, with its measurement. */\nexport interface NamePlaceholder {\n\t/** the print folded by `foldNameKey`: lower case, accents and punctuation gone, single spaces */\n\treadonly print: string;\n\t/** where it was seen, so a reviewer can audit the row */\n\treadonly authority: string;\n\t/**\n\t * `prefix`: the folded print STARTS with this row's words, for an entry form's instruction\n\t * that runs on (`NO SCHOOL SELECTED - Please change your profile`). Whole words only.\n\t * Absent: the folded print is exactly this row.\n\t */\n\treadonly match?: \"prefix\";\n}\n\n/**\n * THE SHARED SENTINELS: what an entry platform writes where nothing was entered or chosen, in a\n * name cell or a school cell alike. A school reader asks `isPlaceholderPrint` of its cell, so\n * `N/A`, `No School` and `Independent` are refused on both sides of a row by this one list. A\n * sentinel worded about a school is still no name when a name cell prints it, so it is here\n * too and not in a second list. Ordinary prints that merely CONTAIN one of these words are\n * not placeholders: a row matches the whole folded print, or its leading words for `prefix`.\n *\n * The first five were measured 2026-10-01 over every stream of the results corpus (3,776,915\n * rows), the rest 2026-10-05 over the same corpus (3,586,702 rows): rows per cell, matched on\n * the fold. A row with 0 rows is an entry form's option seen only as a form label.\n */\nexport const PLATFORM_PLACEHOLDERS: readonly NamePlaceholder[] = [\n\t{\n\t\tprint: \"unknown\",\n\t\tauthority:\n\t\t\t\"4 name rows (`Unknown`, `unknown`); 237 school rows (`Unknown`, `unknown`, `*Unknown*`)\",\n\t},\n\t{ print: \"tba\", authority: \"4 name rows (`TBA`); 4 school rows\" },\n\t{\n\t\tprint: \"n a\",\n\t\tauthority:\n\t\t\t\"42 name rows (`#N/A`, a spreadsheet's missing-value mark; it parsed as the person `A<<N`); 43 school rows (`#N/A`, `N/A`)\",\n\t},\n\t{ print: \"none\", authority: \"0 name rows; 21 school rows (`None`, `none`)\" },\n\t{ print: \"not applicable\", authority: \"0 name rows; 1 school row (`Not applicable`)\" },\n\t{\n\t\tprint: \"no school\",\n\t\tauthority: \"0 name rows; 76 school rows (`No School`): the dancer is entered with no school\",\n\t},\n\t{\n\t\tprint: \"independent\",\n\t\tauthority:\n\t\t\t\"0 name rows; 5 school rows (`Independent`, `independent`, `Independent?`): no school, by the dancer's own description\",\n\t},\n\t{\n\t\tprint: \"independent dancer\",\n\t\tauthority:\n\t\t\t\"0 name rows; 8 school rows (`Independent Dancer`, `Independent dancer`, `Independent Dancer?`)\",\n\t},\n\t{ print: \"no school judge\", authority: \"0 rows: a form option for an adjudicator's entry\" },\n\t{\n\t\tprint: \"no school associations\",\n\t\tauthority: \"0 name rows; 13 school rows (`No School Associations`)\",\n\t},\n\t{ print: \"no dance school\", authority: \"0 rows: a form option\" },\n\t{ print: \"no lessons yet\", authority: \"0 name rows; 5 school rows (`No lessons yet`)\" },\n\t{\n\t\tprint: \"none inactive dancer\",\n\t\tauthority: \"0 name rows; 1 school row (`None - Inactive Dancer`)\",\n\t},\n\t{ print: \"not certified\", authority: \"0 name rows; 1 school row (`Not Certified`)\" },\n\t{ print: \"other\", authority: \"0 name rows; 2 school rows (`Other`)\" },\n\t{ print: \"school other\", authority: \"0 rows: a form option\" },\n\t{ print: \"non\", authority: \"0 rows: a form option, the truncation of `Non-dancer`\" },\n\t{ print: \"non dancer\", authority: \"0 name rows; 4 school rows (`Non-dancer`)\" },\n\t{ print: \"non dancing\", authority: \"0 name rows; 88 school rows (`Non-dancing`)\" },\n\t{\n\t\tprint: \"non dance competitions\",\n\t\tauthority: \"0 name rows; 3 school rows (`Non-Dance Competitions`)\",\n\t},\n\t{\n\t\tprint: \"unknown irish dancing school\",\n\t\tauthority: \"0 name rows; 1 school row (`Unknown Irish Dancing School`)\",\n\t},\n\t{ print: \"unknown music school\", authority: \"0 rows: a form option\" },\n\t{ print: \"school deleted\", authority: \"0 rows: a form option (`---SCHOOL DELETED`)\" },\n\t{\n\t\tprint: \"not listed\",\n\t\tmatch: \"prefix\",\n\t\tauthority:\n\t\t\t\"0 name rows; 2 school rows (`--Not Listed--`), and the form's `--Not Listed` run-ons\",\n\t},\n\t{ print: \"choose one\", authority: \"0 name rows; 41 school rows (`-- Choose One --`)\" },\n\t{ print: \"select school\", authority: \"0 rows: a form option (`--Select School--`)\" },\n\t{\n\t\tprint: \"no school selected\",\n\t\tmatch: \"prefix\",\n\t\tauthority: \"0 name rows; 16 school rows (`NO SCHOOL SELECTED - Please change your profile`)\",\n\t},\n\t{\n\t\tprint: \"school not selected\",\n\t\tmatch: \"prefix\",\n\t\tauthority: \"0 name rows; 45 school rows (`SCHOOL NOT SELECTED - update your … profile`)\",\n\t},\n\t{ print: \"x closed select new school\", authority: \"0 rows: a form option\" },\n\t{ print: \"x school closed please select another school\", authority: \"0 rows: a form option\" },\n\t{ print: \"default school\", authority: \"0 rows: a form option\" },\n\t{ print: \"my school of irish dance\", authority: \"0 rows: a form's example text\" },\n\t{ print: \"n e e d\", authority: \"0 name rows; 1 school row (`(n e e d ) ____`), keyboard filler\" },\n];\n\n/**\n * THE NAME-ONLY SENTINELS: the placeholder-shaped prints that hold a letter, that only a name\n * cell prints, and that `PLATFORM_PLACEHOLDERS` does not already hold. Measured 2026-10-01 over\n * every stream of the results corpus (3,776,915 rows).\n */\nexport const NAME_PLACEHOLDERS: readonly NamePlaceholder[] = [\n\t{\n\t\tprint: \"name withheld\",\n\t\tauthority: \"`Name Withheld`, 136 rows: the platform printed that the name was withheld\",\n\t},\n\t{\n\t\tprint: \"none none\",\n\t\tauthority: \"`none none`, 5 rows: the sentinel `none` typed into both name fields\",\n\t},\n\t{\n\t\tprint: \"not known\",\n\t\tauthority: \"`Not known`, 2 rows. It parsed as the person `Known<<Not`\",\n\t},\n\t{\n\t\tprint: \"x\",\n\t\tauthority: \"`X`, 2 rows: a bare keyboard filler in the name field\",\n\t},\n];\n\nconst SHARED = new Map(\n\tPLATFORM_PLACEHOLDERS.filter((p) => p.match === undefined).map((p) => [p.print, p]),\n);\nconst SHARED_PREFIX = PLATFORM_PLACEHOLDERS.filter((p) => p.match === \"prefix\");\nconst NAME_ONLY = new Set(NAME_PLACEHOLDERS.map((p) => p.print));\n\nconst HAS_LETTER = /\\p{L}/u;\n\n/** The shared row a folded print matches: exactly, or by its leading words for a `prefix` row. */\nfunction sharedRow(folded: string): NamePlaceholder | undefined {\n\treturn (\n\t\tSHARED.get(folded) ??\n\t\tSHARED_PREFIX.find((p) => folded === p.print || folded.startsWith(`${p.print} `))\n\t);\n}\n\n/**\n * The PLATFORM_PLACEHOLDERS row this print is, or `undefined`. For a reader that records\n * which sentinel refused a cell; `isPlaceholderPrint` is the yes/no.\n */\nexport function placeholderOf(print: string): NamePlaceholder | undefined {\n\treturn sharedRow(foldNameKey(print));\n}\n\n/**\n * Is this print one of the PLATFORM PLACEHOLDERS a name cell and a school cell share\n * (`N/A`, `TBA`, `Unknown`, `None`, `No School`, `Independent`)? The question a school reader\n * asks of its cell.\n */\nexport function isPlaceholderPrint(print: string): boolean {\n\treturn placeholderOf(print) !== undefined;\n}\n\n/**\n * Did this person cell print NO NAME: no letter, a shared placeholder, or a name-only one?\n * Total over any string; the print is read, never rewritten, and nothing is parsed.\n */\nexport function isNoNamePrint(print: string): boolean {\n\tif (!HAS_LETTER.test(print)) return true;\n\tconst folded = foldNameKey(print);\n\treturn NAME_ONLY.has(folded) || sharedRow(folded) !== undefined;\n}\n",
8
8
  "/**\n * compound-surnames.ts — surname spans the corpus names outright, for the\n * splitter to read where the print itself carries no boundary.\n *\n * GENERATED by a walk over a large results corpus. DO NOT HAND-EDIT — change\n * the walk and re-run it.\n *\n * Each entry is one surname span some `Last, First` print in the corpus puts\n * ahead of its own inversion comma, folded (`./name-fold.ts`) and joined. None\n * carries a standalone particle: a span the particle vocabulary can already walk\n * back over is the vocabulary's business and is deliberately not here, so the two\n * never contend for the same boundary. The comment on each row is how one anchor\n * print spelt it.\n *\n * WHAT THIS IS NOT. It is not a per-name lookup deciding WHICH PERSON a print is\n * — the class `name-split.ts`'s header excludes. It decides where the surname\n * ENDS, which is the split's own question, and it generalizes past the bearer the\n * anchor named: `Trulton McKenna, Nuala` also settles `Petra Trulton Mairvivith`'s\n * sibling spans for every other bearer of the same surname.\n */\n\nimport { nameFold } from \"./name-fold.ts\";\n\n/** The spans, folded and joined. */\nexport const COMPOUND_SURNAMES: ReadonlySet<string> = new Set([\n\t\"bremersumma\", // Bremer Summa\n\t\"graymilewski\", // Gray Milewski\n\t\"lawlerlopez\", // Lawler Lopez\n\t\"mcinerneyzona\", // McInerney Zona\n\t\"morandenno\", // Moran Denno\n\t\"murphyzink\", // Murphy Zink\n\t\"murraymacritchie\", // Murray Macritchie\n\t\"powersozyurt\", // Powers Ozyurt\n\t\"sharkeyochoa\", // Sharkey Ochoa\n\t\"vanderkooi\", // Vander Kooi\n\t\"vanderwoude\", // Vander Woude\n\t\"woodsdoherty\", // Woods Doherty\n\t\"woodsmckenna\", // Woods McKenna\n]);\n\n/**\n * Do these tokens, read as one span, form a surname the corpus names outright?\n *\n * Folds the JOINED run rather than each token, so a print that spaces what\n * another glues matches either way.\n */\nexport function isCompoundSurname(tokens: readonly string[]): boolean {\n\treturn COMPOUND_SURNAMES.has(tokens.map(nameFold).join(\"\"));\n}\n",
9
9
  "/**\n * name-split.ts — THE splitter. One printed personal name in, one decision out:\n * which tokens are the surname, which are given names, which are suffixes.\n *\n * The rule this module answers to has two halves: when the producing document\n * declares the name order, split by the declaration; when it does not, guess, and\n * guess correctly more often than not.\n *\n * ## What this returns, and why it is indices rather than strings\n *\n * Three implementations answered this question before this file existed, and\n * they returned three different KINDS of string — an accent-stripped upper-case\n * ICAO key (an earlier keying parser), an accent-preserving Title Case display\n * string (`./person-display.ts`), and a census probe's verdict. Those renderings\n * genuinely differ and are each correct for their consumer: the keying string\n * folds `Ó` to `O` because it is a key, and the display string must not because\n * it is what a reader sees.\n *\n * So the shared thing is not a string. It is the DECISION, and this returns it\n * as token indices into the print, verbatim — no casing, no accent folding, no\n * fixup tables, no gluing. Each renderer builds its own string from the same\n * decision, which is what makes \"one splitter, two renderings\" a real statement\n * rather than a hope. A caller that wants the tokens back gets them from\n * `tokens`, which re-tiles the print.\n *\n * ## The declaration decides; the guess only fills in\n *\n * `order` is the producing document's own `meta.nameFormat` declaration. Where\n * one is supplied it decides the reading and nothing here guesses. Where it is\n * absent or `\"unknown\"` — both meaning \"no order to act on\" — `inferNameOrder`\n * runs, and the rule's second half is what it is measured against: *when not\n * told, it should guess correctly more often than not*.\n *\n * That bar is MEASURED, not asserted. Every transcript carrying a `nameFormat`\n * declaration is ground truth, so the score is taken by withholding the\n * declaration and comparing (`./name-order-bar.ts` holds the predicates). The\n * floor it gates on is a decided figure, never a threshold widened toward\n * whatever this achieves.\n *\n * ## What is deliberately NOT here\n *\n * **Team detection.** `Team A`, `Foireann B` and their kin name no person, and\n * which prints those are is the caller's dispatch — `./team-name.ts`, which\n * reads the canonical team format and is what `personDisplayName` and\n * `PersonName.isTeam()` ask, and a sheet parser's wider team-word test, which is\n * a WIDER question: what a sheet printed, `Foireann` included. This function is\n * told it has a personal name.\n *\n * **Every per-name lookup table.** `LAST_NAME_FIXES`, `LAST_FIRST_FIXES`,\n * `MIDDLE_NAME_FIXES`, `ILLEGAL_NAME_WHITELIST`: those decide WHICH PERSON a\n * print is, which is entity resolution and not splitting, and\n * `person-display.ts` has always excluded them for that reason. They belong to\n * whatever keying parser owns them, applied to its own output after the split.\n *\n * **`NOT_REAL_LAST_NAMES`.** The earlier keying parser carried a 17-word\n * given-name lexicon (`anne`, `kate`, `rose`, `grace`, …) and walked the surname\n * backwards off any final token in it. It is dropped rather than shared, and the\n * corpus says what that costs: over every `name` on a result line of a large\n * results corpus, the walk-back moves FIVE prints, and four of them —\n * `HARWENNICK WEVETT GRACE`, `Mollison Dyrrell Grace`, `Thealina Stullomue Claire`,\n * `Lainnyrrenn Larvina Clare` — are surname-first prints, where the walk-back is a\n * wrong guess at exactly the question the declaration now answers. The fifth\n * (`Odile Quar lane`) is a garbled cell.\n */\n\nimport { isStandaloneNameParticle, particleJoin } from \"../particles/particle-vocabulary.ts\";\nimport { isCompoundSurname } from \"./compound-surnames.ts\";\n\n/**\n * Which token of a printed personal name is the surname.\n *\n * The three members are the fact, not the print convention that signals it: a\n * comma is one spelling of `surname-first` and an unreliable one, which is why\n * the declaration exists at all.\n *\n * `\"unknown\"` is a REAL member rather than implicit absence. Absence means\n * *nobody looked*; `\"unknown\"` means *it was looked at and could not be\n * settled*. Both reach this splitter as \"no order to act on\", and that is\n * deliberate: the distinction is recorded for a reader, and there is nothing\n * different for a split to DO with it.\n */\nexport type NameOrder = \"given-first\" | \"surname-first\" | \"unknown\";\n\n/** The order actually acted on. `\"unknown\"` is not one — it is resolved first. */\nexport type ResolvedNameOrder = \"given-first\" | \"surname-first\";\n\n/**\n * A COMMA PACKED AGAINST THE NEXT LETTER IS A MISSING SPACE, restored.\n *\n * `Surname,Given` is not a second format. It is `Surname, Given` typeset without the\n * space, and every consumer that cuts at the comma reads it correctly by accident while\n * every consumer that reads TOKENS sees one whitespace-free token and refuses the cell\n * (`classifyCell`'s single-token rule). The CLRG teachers' directory prints 8 of its\n * 3,012 distinct names that way.\n *\n * IT IS NEVER-INFORMATION AND NOTHING ELSE, which is the only kind of repair NN1 allows:\n * no letter moves, no letter is dropped, and a comma already followed by a space is\n * untouched. It is offered rather than folded into `renderNn1` so that it applies where a\n * producer is KNOWN to print `Surname, Given` and nowhere else. A comma inside a\n * free-text cell is not this.\n */\nexport function spaceAfterComma(printed: string): string {\n\treturn printed.replace(/,(?=\\S)/gu, \", \");\n}\n\n/**\n * One printed personal name, partitioned.\n *\n * THE INDEX ARRAYS READ IN ORDER, NOT IN PRINT ORDER. For all but one shape the\n * two coincide. The exception is a print like `Histow, Livia De`, where the\n * particle trailing the given half belongs to the surname ahead of it: the\n * surname reads `De` then `Histow`, so `surname` is `[2, 0]`. A renderer joins in\n * the order given and is right; a renderer that sorted would emit `HistowDe`.\n *\n * Every index is a valid index into `tokens`, each token appears in exactly one\n * of the three arrays, and together they re-tile `tokens`.\n */\nexport interface NameSplit {\n\t/**\n\t * The print's tokens, in PRINT order. Whitespace is collapsed, a comma is\n\t * consumed as a token separator, and an apostrophe-join particle is glued to\n\t * the token it governs (`tokenize` below). Nothing else is changed, so a\n\t * token still carries its own casing, diacritics and apostrophes.\n\t */\n\ttokens: readonly string[];\n\t/** the tokens forming the surname, in the order they read. Never empty. */\n\tsurname: readonly number[];\n\t/** the given-name tokens, in print order. Empty for a surname-only print. */\n\tgiven: readonly number[];\n\t/** trailing generational or qualification suffixes, in print order. */\n\tsuffixes: readonly number[];\n\t/** the order this split was made under */\n\torder: ResolvedNameOrder;\n\t/** true when `order` came from the caller, false when `inferNameOrder` guessed it */\n\tdeclared: boolean;\n}\n\n/**\n * Suffixes that follow a personal name.\n *\n * ONE SET, read at three points that must agree: whether a comma is a suffix\n * delimiter rather than an order separator (`inferNameOrder`), which trailing\n * tokens come off before the surname is chosen, and — through\n * `isNameSuffix` — which of them a renderer spells canonically. Two sets is how\n * `Kevin B Lundham, Jr` reordered to `Jr Kevin B. Lundham` and put `Jr` in\n * the given-name slot.\n *\n * The union of what the two earlier splitters carried: the keying parser's\n * `LAST_NAME_SUFFIXES` (nine) plus `v` from `person-display.ts`'s\n * `NAME_SUFFIXES` (ten). A declaration-DERIVATION tool's suffix list is NOT\n * folded in: it only has to recognize a suffix well enough to discount one comma\n * out of hundreds, so it is deliberately a superset. Reading a print and\n * deriving a declaration are different jobs.\n */\nexport const NAME_SUFFIXES: ReadonlySet<string> = new Set([\n\t\"tcrg\",\n\t\"adcrg\",\n\t\"bg\",\n\t\"phd\",\n\t\"jr\",\n\t\"sr\",\n\t\"ii\",\n\t\"iii\",\n\t\"iv\",\n\t\"v\",\n]);\n\n/** A token is a suffix whether or not it prints its full stop: `Jr` and `Jr.`. */\nexport function isNameSuffix(token: string): boolean {\n\treturn NAME_SUFFIXES.has(token.replace(/\\./gu, \"\").toLocaleLowerCase());\n}\n\n/**\n * Split on whitespace, then GLUE an apostrophe-join particle to the token it\n * governs.\n *\n * `Kristin O Brien`, `Condby O' Jealtonham` and `Samantha 0 Connor` print the `O` as\n * its own token, and it is not one in any reading — it is the head of the\n * surname it precedes. Both renderers already did this, separately and before\n * the split: `fixOPrefix` in `src/lexicon/irish.ts` (\"the apostrophe is removed\n * entirely, producing a single token\") and the lone-`O` splice in\n * `person-display.ts`. Doing it here is what makes them one rule, and it is why\n * `Declan O Fyrrina Ryan` still reads surname `Ryan` with `O'Fyrrina` intact in\n * the middle slot rather than leaving a bare `O` token behind.\n *\n * IT FIRES FOR `o` AND `0` ONLY, because those are the only apostrophe-join\n * particles the corpus prints standalone. `mac`, `mc`, `de` and the rest are\n * glued or spaced, and they are NOT joined here: `Mac Reanaillia` must stay two\n * tokens or it is one token and unparseable.\n *\n * It never fires on the last token, which governs nothing.\n *\n * NOR, WHEN `leadIsGiven`, ON THE FIRST TOKEN. In a given-first print of three or\n * more name tokens the first token is the first given name, and a first name is\n * never a particle (the precondition the surname walk and `givenNameGroups` state),\n * so a lone `O` there is an INITIAL: a results page that cuts the given name to its\n * initial prints `O Brady-Lynch Doyle` for `Oliver Brady-Lynch Doyle`, and gluing\n * read a given name `O'Brady-Lynch` no print means. `splitPersonName` decides when\n * the lead is given; `Kristin O Brien` and `Declan O Fyrrina Ryan` are untouched, because\n * their particle is not the first token.\n */\nexport function tokenize(s: string, leadIsGiven = false): string[] {\n\tconst raw = s.split(/\\s+/u).filter((t) => t !== \"\");\n\tconst out: string[] = [];\n\tfor (let i = 0; i < raw.length; i++) {\n\t\tconst tok = raw[i] as string;\n\t\tconst next = raw[i + 1];\n\t\tif (i === 0 && leadIsGiven) {\n\t\t\tout.push(tok);\n\t\t\tcontinue;\n\t\t}\n\t\tif (next !== undefined && isStandaloneNameParticle(tok) && particleJoin(tok) === \"apostrophe\") {\n\t\t\tout.push(`${tok.replace(/['\\u2019`]+$/u, \"\")}'${next}`);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tout.push(tok);\n\t}\n\treturn out;\n}\n\n/**\n * Guess the printed order from the print alone — used ONLY where the producing\n * document declares none.\n *\n * The comma is the whole signal, and three classes of comma are not order\n * separators. Each is a class the corpus holds:\n *\n * - a `:` anywhere means a glued name+school+region print, where the comma\n * separates a region from a country (`… : Eastern Region, Canada`);\n * - nothing after the comma is stray punctuation (`Annika Walter,`);\n * - only suffixes after it is a suffix delimiter (`Thomas Ryskurett, Jr.`).\n *\n * AND THE INVERTED READING IS REFUSED WHERE IT WOULD MAKE A PARTICLE THE\n * SURNAME. Reading `Una O,thyltith` as inverted puts `O` in the surname slot,\n * which this project's own vocabulary says is not a surname — the print is far\n * likelier to be a comma typed for the apostrophe in `O'Thyltith`. Handing it back\n * to the given-first path is what parses it. A DECLARED `surname-first` lifts\n * this refusal: with a declaration there is no guess left to defend, and a\n * genuinely defective declared print is repaired as an erratum toward the page\n * at layer 1.\n *\n * MEASURED, NOT ASSERTED: this is scored against every transcript that carries a\n * `nameFormat` declaration, with the declaration withheld.\n */\nexport function inferNameOrder(printed: string, roles?: NameRoleLookup): ResolvedNameOrder {\n\tconst comma = commaReading(printed);\n\tif (comma === \"none\")\n\t\treturn (roles === undefined ? undefined : lexiconNameOrder(printed, roles)) ?? \"given-first\";\n\treturn comma === \"separator\" ? \"surname-first\" : \"given-first\";\n}\n\n/**\n * How a print's comma reads: `separator` is an order separator (`Quorrish, Zelvine`), `none`\n * is no comma at all, and every other member is a comma `inferNameOrder` discounts, by\n * the class it was discounted as — `glue` (a `:` anywhere), `trailing` (nothing after\n * it), `suffix` (only suffixes after it) and `particle` (a particle before it).\n *\n * `inferNameOrder` is this, read one print at a time; `deriveNameFormat` counts it over\n * a collection. One rule answers both.\n */\nexport type CommaReading = \"none\" | \"separator\" | \"glue\" | \"trailing\" | \"suffix\" | \"particle\";\n\nexport function commaReading(printed: string): CommaReading {\n\tif (printed.includes(\":\")) return \"glue\";\n\tconst at = printed.indexOf(\",\");\n\tif (at <= 0) return \"none\";\n\tconst after = tokenize(printed.slice(at + 1));\n\tif (after.length === 0) return \"trailing\";\n\tif (after.every(isNameSuffix)) return \"suffix\";\n\tconst before = tokenize(printed.slice(0, at));\n\tconst tail = before[before.length - 1];\n\tif (tail !== undefined && isStandaloneNameParticle(tail)) return \"particle\";\n\treturn \"separator\";\n}\n\n/**\n * What the name lexicon says ONE token of a print can be: a surname, a given name,\n * both, or (`undefined`) nothing it knows. `names.txt` flags `L`/`A` answer\n * `surname` and `F`/`M`/`N` answer `given`, so `Ryan:AM` is both.\n *\n * INJECTED, NOT READ. This module reads no file (a cache keyed on this code cannot\n * see a data file move), so the caller that holds `names.txt` hands its lookup in,\n * the way `DisplayLexicon` is handed in.\n */\nexport interface NameRole {\n\tsurname: boolean;\n\tgiven: boolean;\n}\nexport type NameRoleLookup = (token: string) => NameRole | undefined;\n\n/**\n * THE LEXICON TIPS AN ORDER NOBODY DECLARED, or says nothing.\n *\n * Asked only of a comma-less print whose producing document declared no order\n * (`nameFormat` `unknown`): `Krasinska Joanna` and `Sandra Stillervith` are the same\n * shape and nothing in the print tells them apart, so the question goes to the\n * lexicon, which is a HINT: *\"mostly useful for cleaning up smushes, detecting\n * unknown name order, and capitalizing properly\"*. A hint\n * never overrides a declaration, and it never decides when it disagrees with\n * itself.\n *\n * ONLY THE TWO ENDS OF A COMMA-LESS PRINT CAN HOLD THE SURNAME, so only they are\n * asked, and ONLY A GIVEN NAME VOTES: a token the lexicon knows as a given name\n * and never as a surname (`F`/`M`/`N`, no `L`/`A`).\n *\n * surname-first ← the LAST token is a given name\n * given-first ← the FIRST token is a given name\n *\n * One vote decides; two (`Gairvock Oriana-Mirela`, `Gairvock:M`) or none answer\n * `undefined` and the caller falls back. `Krasinska Joanna` with `Joanna:F` is surname-first, `Sandra\n * Stillervith` with `Sandra:F` given-first.\n *\n * WHY A SURNAME FLAG DOES NOT VOTE, MEASURED on a large results corpus, over the\n * 280,837 comma-less prints on a transcript that DECLARES its order, with the\n * declaration withheld. When a rule tips a print surname-first, how often was the\n * declaration surname-first? Voting on both ends with `L`/`A` as surname: 1,492 of\n * 5,736 (26%); `A` read as both (which is what `names.txt` says `A` is): 1,498 of\n * 4,044 (37%); only when both ends vote and agree: 235 of 535 (44%); a given name\n * alone voting, as here: 1,196 of 1,786 (67%), and a given-first tip is right\n * 234,862 times of 236,554 (99.3%). Most of the 590 surname-first misses are\n * surnames that are also given names (`Ruby-Mae Thomas`, `Ryan Pierce`) or rows\n * whose own declaration is wrong (`Contavarre Katelyn`, `DUNMEROVA SARA` on `First Last`\n * pages). `L` is unreliable in the one direction that matters: `Bailey`, `Quellmore`,\n * `Finn`, `Cearvane`, `Trearrock` and `Rinenn` are all `L` only, and on that corpus's\n * `unknown` transcripts each leads a given-first print (`Quellmore Benvarlo`, `Cearvane Rernley`) that a\n * vote on `L` reversed.\n */\nexport function lexiconNameOrder(\n\tprinted: string,\n\troles: NameRoleLookup,\n): ResolvedNameOrder | undefined {\n\tconst s = cleanPrint(printed);\n\tif (s.includes(\",\") || s.includes(\":\")) return undefined;\n\tconst tokens = tokenize(s).filter((t) => !isNameSuffix(t));\n\tif (tokens.length < 2) return undefined;\n\t// A HYPHENATED GIVEN NAME the lexicon lists whole answers whole; one it does not\n\t// (`Oriana-Tessa`) is a given name when every part is (`Oriana:F`, `Tessa:F`).\n\tconst one = (t: string): boolean => {\n\t\tconst r = roles(t);\n\t\treturn r?.given === true && !r.surname;\n\t};\n\tconst givenOnly = (t: string): boolean => {\n\t\tif (roles(t) !== undefined) return one(t);\n\t\tconst parts = t.split(\"-\").filter((p) => p !== \"\");\n\t\treturn parts.length > 1 && parts.every(one);\n\t};\n\tconst first = givenOnly(tokens[0] as string);\n\tconst last = givenOnly(tokens[tokens.length - 1] as string);\n\tif (first === last) return undefined;\n\treturn last ? \"surname-first\" : \"given-first\";\n}\n\n/**\n * THE ORDER AN UNDECLARED, COMMA-LESS PRINT IS TIPPED TO, and by what, or\n * `undefined` where nothing tips it and `inferNameOrder`'s guess stands.\n *\n * The lexicon first (`lexiconNameOrder`), then `pinned`, the order a person wrote\n * down for the print's event. A print carrying a comma or a colon is never tipped:\n * its punctuation is its own evidence and `inferNameOrder` reads it. The caller\n * asks this ONLY where the producing document declared `unknown`; a declared\n * order is never put to it.\n */\nexport function tippedNameOrder(\n\tprinted: string,\n\troles: NameRoleLookup | undefined,\n\tpinned: ResolvedNameOrder | undefined,\n): { order: ResolvedNameOrder; via: \"lexicon\" | \"override\" } | undefined {\n\tconst s = cleanPrint(printed);\n\tif (s === \"\" || s.includes(\",\") || s.includes(\":\")) return undefined;\n\tconst lex = roles === undefined ? undefined : lexiconNameOrder(s, roles);\n\tif (lex !== undefined) return { order: lex, via: \"lexicon\" };\n\tif (pinned !== undefined) return { order: pinned, via: \"override\" };\n\treturn undefined;\n}\n\n/**\n * The print as the splitter reads it: whitespace collapsed, a trailing comma\n * dropped. Shared so that a caller resolving the order ahead of a split resolves\n * it against the same bytes `splitPersonName` will infer from.\n */\nfunction cleanPrint(printed: string): string {\n\treturn printed.replace(/\\s+/gu, \" \").trim().replace(/,+$/u, \"\").trim();\n}\n\n/**\n * The order a split will actually be made under: the declaration where the\n * producing document made one, the guess where it did not.\n *\n * EXPORTED BECAUSE A STORE HAS TO KEY ON IT. A store that interns one dict row per\n * printed name and bakes its folds there needs two rows for a print that reads two\n * ways, and the key has to name which reading each holds.\n * Keying on the DECLARATION instead would split every source that declares\n * nothing from every source that declares the order it was already guessed to\n * have, for identical folds. `splitPersonName` calls this, so the resolved order\n * a caller stores is the one the split used and not a second opinion.\n */\nexport function resolveNameOrder(printed: string, order: NameOrder = \"unknown\"): ResolvedNameOrder {\n\treturn order !== \"unknown\" ? (order as ResolvedNameOrder) : inferNameOrder(cleanPrint(printed));\n}\n\n/** Strip trailing suffix tokens off one half, leaving the rest of the half. */\nfunction peelSuffixes(\n\thalf: number[],\n\ttokens: readonly string[],\n): { rest: number[]; suffixes: number[] } {\n\tconst rest = [...half];\n\tconst suffixes: number[] = [];\n\twhile (rest.length > 0 && isNameSuffix(tokens[rest[rest.length - 1] as number] as string)) {\n\t\tsuffixes.unshift(rest.pop() as number);\n\t}\n\treturn { rest, suffixes };\n}\n\n/**\n * Partition one printed personal name.\n *\n * `null` where the print cannot fill both a surname and a given name — a single\n * token (`Madonna`, or a glued `KESTRELDUNMERE`), or an empty cell.\n * Layer 3 may normalize; it may not guess, so an unsplittable print is refused\n * rather than answered with a surname-less person.\n */\nexport function splitPersonName(printed: string, order: NameOrder = \"unknown\"): NameSplit | null {\n\t// A TRAILING COMMA IS PUNCTUATION, NOT A SEPARATOR. Nothing follows it, so it\n\t// cannot be marking an inversion, and left in place it rides into the surname\n\t// and yields a plausible-looking `Walter,<<Annika` that is not a split.\n\tconst s = cleanPrint(printed);\n\tif (s === \"\") return null;\n\n\tconst declared = order !== \"unknown\";\n\tconst effective: ResolvedNameOrder = resolveNameOrder(printed, order);\n\n\t// THE SEPARATOR IS THE COMMA, not the two-character string `\", \"`. Keying on\n\t// comma-plus-space made every other spelling miss, silently and in two\n\t// directions: `Raimby,Jennifer` reported as a single word, and `Raimby ,Jennifer`\n\t// carried the separator INTO the surname. A split on the character cannot do\n\t// either. Only the FIRST comma is a boundary; a further one inside a half is\n\t// just another separator (`Mailtina, John, TCRG`).\n\tconst at = s.indexOf(\",\");\n\tconst headText = at > 0 ? s.slice(0, at) : s;\n\tconst tailText = at > 0 ? s.slice(at + 1) : \"\";\n\t// THE LEAD OF A COMMA-LESS GIVEN-FIRST PRINT IS A GIVEN NAME, never a particle to\n\t// glue, once the print holds three or more name tokens. Two tokens (`O Brien`) keep\n\t// the glue: with nothing else in the print, `O` reads as the particle it is in\n\t// `Kristin O Brien` and the print is refused for having no given name, as before. A\n\t// COMMA keeps it too: `O Shea, Rosalie` on a page declared given-first is the\n\t// declaration being wrong, and its head is the surname `O'Shea`.\n\tconst nameTokens = s.split(/\\s+/u).filter((t) => t !== \"\" && !isNameSuffix(t));\n\tconst leadIsGiven = at < 0 && effective === \"given-first\" && nameTokens.length >= 3;\n\tconst headTokens = tokenize(headText.replace(/,/gu, \" \"), leadIsGiven);\n\tconst tokens = [...headTokens, ...tokenize(tailText.replace(/,/gu, \" \"))];\n\tif (tokens.length < 2) return null;\n\tconst headLen = headTokens.length;\n\tconst head = tokens.map((_, i) => i).slice(0, headLen);\n\tconst tail = tokens.map((_, i) => i).slice(headLen);\n\n\t// Suffixes come off EACH HALF's tail independently, before any ordering\n\t// decision. That is what makes `Jyskock II, John` (suffix in the surname\n\t// half) and `Mailtina, John, TCRG` (suffix in the given half) one rule rather\n\t// than two, and it is what turns `Kevin Lundham,Jr` — whose whole post-comma\n\t// half is a suffix — back into an uninverted print with a suffix on it.\n\tconst h = peelSuffixes(head, tokens);\n\tconst t = peelSuffixes(tail, tokens);\n\tconst suffixes = [...h.suffixes, ...t.suffixes].sort((a, b) => a - b);\n\n\tlet surname: number[];\n\tlet given: number[];\n\n\tif (effective === \"surname-first\" && t.rest.length > 0) {\n\t\t// THE COMMA IS THE BOUNDARY. Everything before it is the surname and\n\t\t// everything after it the given names; no heuristic is consulted, because\n\t\t// the declaration (or the inference) has already said which side is which.\n\t\tsurname = h.rest;\n\t\tgiven = t.rest;\n\t\t// …EXCEPT A PARTICLE TRAILING THE GIVEN HALF, which belongs to the surname\n\t\t// ahead of it: `Histow, Livia De` is `De Histow`, and the surname therefore\n\t\t// READS `De` then `Histow` rather than in print order.\n\t\twhile (\n\t\t\tgiven.length > 1 &&\n\t\t\tisStandaloneNameParticle(tokens[given[given.length - 1] as number] as string)\n\t\t) {\n\t\t\tsurname = [given.pop() as number, ...surname];\n\t\t}\n\t} else if (effective === \"surname-first\") {\n\t\t// AND THE COMMA IS NOT WHAT MAKES IT INVERTED — THE DECLARATION IS.\n\t\t// A `Last First` source prints `RYMORKETT CORVANE`, `GREAMARD ALICE`, `NEASTURKUE GRYLTENN`:\n\t\t// surname first, no comma anywhere. The surname is the LEADING token,\n\t\t// extended while that token is a particle, so `van der Quell Pealling` reads\n\t\t// surname `van der Quell` and not surname `van`. It never swallows the last\n\t\t// token, because a print with no given name left is not this shape.\n\t\tconst all = [...h.rest, ...t.rest];\n\t\tlet end = 0;\n\t\twhile (end < all.length - 1 && isStandaloneNameParticle(tokens[all[end] as number] as string))\n\t\t\tend++;\n\t\tsurname = all.slice(0, end + 1);\n\t\tgiven = all.slice(end + 1);\n\t} else {\n\t\t// GIVEN-FIRST. The surname is the final token plus the CONTIGUOUS particle\n\t\t// run immediately before it. Contiguity is the whole of it: a run that may\n\t\t// skip an intervening token welds a surname across a given name, which is\n\t\t// how `Dyrnton De Gellmore Teathostell` read `DETEATHOSTELL<<DYRNTON<GELLMORE`. And the walk\n\t\t// never reaches index 0, because a first name is never a particle — that\n\t\t// precondition is what lets `Mac Reanaillia` and `Mc Neskick` parse at all,\n\t\t// and what keeps `Mac Torren Quellby` from welding\n\t\t// `MACQUELLBY` across an intervening given name.\n\t\tconst all = [...h.rest, ...t.rest];\n\t\tlet start = all.length - 1;\n\t\twhile (start > 1 && isStandaloneNameParticle(tokens[all[start - 1] as number] as string))\n\t\t\tstart--;\n\t\t// …AND WHERE NO PARTICLE MARKS THE BOUNDARY, THE CORPUS DOES. `Wrexley Quist`,\n\t\t// `Dunmere Drundenn` and `Ovynick Tarrow` are two ordinary surname tokens with\n\t\t// nothing between them to walk over, so this print carries no evidence about\n\t\t// where its own surname starts — but `Wrexley Quist, Nuala` elsewhere in the\n\t\t// corpus names the span outright, and `./compound-surnames.ts` is that\n\t\t// evidence, generated. Consulted ONLY where the particle walk found\n\t\t// nothing, longest span first, and never as far as index 0: a print with no\n\t\t// given name left is not this shape.\n\t\tif (start === all.length - 1) {\n\t\t\tfor (let from = 1; from < start; from++) {\n\t\t\t\tif (isCompoundSurname(all.slice(from).map((i) => tokens[i] as string))) {\n\t\t\t\t\tstart = from;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tsurname = all.slice(start);\n\t\tgiven = all.slice(0, start);\n\t}\n\n\tif (surname.length === 0) return null;\n\treturn { tokens, surname, given, suffixes, order: effective, declared };\n}\n\n/**\n * The given tokens, grouped so that a particle run reads with the token it\n * governs: `Daniel Mc Virkby Cevley` yields `[[Daniel], [Mc, Virkby]]`.\n *\n * A PARTICLE GOVERNS THE TOKEN AFTER IT, WHEREVER IT SITS. The surname walk in\n * `splitPersonName` extends backwards from the final token and therefore only\n * ever picks up a run CONTIGUOUS WITH THE END of the print — that contiguity is\n * deliberate and is what stops `Dyrnton De Gellmore Teathostell` welding\n * `DETEATHOSTELL<<DYRNTON<GELLMORE`. The consequence was that a run sitting in a\n * given-name position was never picked up at all and landed as separate middle\n * names, so `Daniel Mc Virkby Cevley` keyed `CEVLEY<<DANIEL<MC<VIRKBY` and could\n * not equal the same dancer's clean print `CEVLEY<<DANIEL<MCVIRKBY`.\n * Grouping here fixes that without moving the surname boundary: the partition\n * `splitPersonName` returns is unchanged, and only how a renderer reads the\n * given half changes.\n *\n * A TRAILING RUN THAT GOVERNS NOTHING IS ITS OWN GROUP rather than dropped. It\n * arises only where the print has no token after it — `Mc Reanaillia` splits\n * surname `Reanaillia`, given `Mc` — and a renderer must still emit it, because a\n * token the print carried never vanishes from the rendering.\n *\n * AND THE FIRST GIVEN TOKEN IS NEVER A PARTICLE, the same precondition the\n * surname walk-back states and for the same evidence: a results platform carries first and\n * last name in separate fields and prints `fname: \"Mac\"`. Without it\n * `Mac Torren Quellby` groups `MacTorren` and loses the given name the corpus\n * says is there.\n *\n * Each group is one given name. Groups read in print order, every index appears\n * exactly once, and together they re-tile `split.given`.\n */\nexport function givenNameGroups(split: NameSplit): number[][] {\n\tconst groups: number[][] = [];\n\tlet run: number[] = [];\n\tfor (let k = 0; k < split.given.length; k++) {\n\t\tconst i = split.given[k] as number;\n\t\trun.push(i);\n\t\tif (k === 0 || !isStandaloneNameParticle(split.tokens[i] as string)) {\n\t\t\tgroups.push(run);\n\t\t\trun = [];\n\t\t}\n\t}\n\tif (run.length > 0) groups.push(run);\n\treturn groups;\n}\n",
10
10
  "/**\n * cell-verdict.ts — `classifyCell`, the guard in front of the name parser.\n *\n * `docs/NAME-NORMALIZATION.md` § *The API* specifies it: *\"the guard — refuses, never\n * repairs\"*. What it returns is a VERDICT, never a rewritten cell, and that is\n * the whole of that sentence as a function contract — a caller is told what the\n * cell is and is handed nothing it could mistake for the print.\n *\n * ## It does not own the repairs, and does not duplicate them\n *\n * `./name-scrub.ts` owns the scrub rules, including the team exemption, and its\n * phase order REPAIR → STRIP → REFUSE is part of those rules: refusing first\n * throws away `Samantha 0 Connor`, whose digit the repair phase is what removes.\n * A guard that re-derived the refusal without the repairs in front of it would\n * refuse prints that scrub accepts, so this calls\n * `scrubNameDetail` and reads its verdict rather than writing a second one.\n *\n * ## The one thing it adds\n *\n * Scrub's `refuse-single-token` counts whitespace tokens. `./name-split.ts`\n * TOKENIZES, gluing an apostrophe-join particle to the token it governs, so\n * `Mary O` is two whitespace tokens and one split token and `splitPersonName`\n * returns `null` on it. That gap is the `\"unsplittable\"` refusal below, and it\n * is why the guard runs the split rather than stopping at the scrub.\n *\n * ## And the placeholders\n *\n * `N/A` is two whitespace tokens and two split tokens, so neither of the above\n * refuses it, and it parsed as the person `N<<A`. The `\"placeholder\"` refusal\n * asks `isNoNamePrint` (`./name-placeholder.ts`), which holds the platform\n * sentinels a row's name and school cells share as one list and adds the few\n * only a name cell prints (`Not known`). It runs AFTER the scrub, so a\n * placeholder the scrub already refuses (`TBA`, `refuse-single-token`) keeps the\n * scrub's rule name, and `PersonName.printsNoName()` is the question that does\n * not depend on which rule fired.\n *\n * ## Order is not asked for, and cannot change the answer\n *\n * `splitPersonName` returns `null` only where the print cannot fill both a\n * surname and a given name, which is a token-count fact and the same under\n * either reading. So the guard takes no `NameOrder`, and a caller that has one\n * gets the same verdict as a caller that does not.\n */\n\nimport { isNoNamePrint } from \"./name-placeholder.ts\";\nimport { NAME_REFUSED, type ScrubOptions, type ScrubRule, scrubNameDetail } from \"./name-scrub.ts\";\nimport { splitPersonName } from \"./name-split.ts\";\n\n/**\n * Why a cell was refused.\n *\n * Every member but two is a `ScrubRule` of the refuse phase, re-exposed rather\n * than re-spelled so a census counting refusals counts one vocabulary. See\n * `\"unsplittable\"` and `\"placeholder\"` on the module header for the two this\n * file adds.\n */\nexport type NameRefusalRule =\n\t| Extract<ScrubRule, `refuse-${string}`>\n\t/** A sentinel written where no name was given (`N/A`, `Not known`): `isNoNamePrint`. */\n\t| \"placeholder\"\n\t/** Scrub accepted it; `splitPersonName` could not fill both halves. */\n\t| \"unsplittable\";\n\n/** A refusal, as `PersonName.refusal` carries it. */\nexport interface Refusal {\n\t/** which test refused the cell */\n\treadonly rule: NameRefusalRule;\n\t/** the cell as handed in, verbatim — nothing here rewrites a print */\n\treadonly printed: string;\n\t/** the fixed spelling of a refused cell, `!!!INVALID`. */\n\treadonly value: typeof NAME_REFUSED;\n}\n\n/**\n * What one printed cell is.\n *\n * THE THREE KINDS ARE NOT TWO. \"No name was printed\" and \"this is not a name\"\n * are different facts about a sheet, and a caller flags each separately, so an\n * empty cell is `\"empty\"` and never a refusal.\n *\n * `scrubbed` IS EVIDENCE, NOT A PRODUCT. It is carried so a caller can see what\n * the rules made of the cell and so the parser does not scrub it twice; a guard\n * that returned it as its answer would be repairing, which that line forbids.\n */\nexport type CellVerdict =\n\t| {\n\t\t\treadonly kind: \"name\";\n\t\t\t/** the cell after `scrubNameDetail`, which is what the parser reads */\n\t\t\treadonly scrubbed: string;\n\t\t\treadonly rules: readonly ScrubRule[];\n\t }\n\t| { readonly kind: \"empty\"; readonly rules: readonly ScrubRule[] }\n\t| {\n\t\t\treadonly kind: \"refused\";\n\t\t\treadonly refusal: Refusal;\n\t\t\treadonly rules: readonly ScrubRule[];\n\t };\n\n/** The refuse-phase rule that fired, or the unsplittable fallback. */\nfunction refusalRule(rules: readonly ScrubRule[]): NameRefusalRule {\n\tfor (let i = rules.length - 1; i >= 0; i--) {\n\t\tconst r = rules[i] as ScrubRule;\n\t\tif (r.startsWith(\"refuse-\")) return r as NameRefusalRule;\n\t}\n\treturn \"unsplittable\";\n}\n\n/**\n * Classify one printed person-name cell. Total: every input gets a verdict.\n *\n * `printed` is returned on the refusal verbatim, so the caller still holds what\n * the page said. A transcript keeps the print verbatim upstream of this, and\n * nothing here may be the only copy of a print.\n */\nexport function classifyCell(printed: string, options: ScrubOptions = {}): CellVerdict {\n\tconst scrub = scrubNameDetail(printed, options);\n\tconst rules: readonly ScrubRule[] = scrub.rules;\n\tif (scrub.refused) {\n\t\treturn {\n\t\t\tkind: \"refused\",\n\t\t\trefusal: { rule: refusalRule(rules), printed, value: NAME_REFUSED },\n\t\t\trules,\n\t\t};\n\t}\n\tif (scrub.value === \"\") return { kind: \"empty\", rules };\n\tif (isNoNamePrint(printed)) {\n\t\treturn {\n\t\t\tkind: \"refused\",\n\t\t\trefusal: { rule: \"placeholder\", printed, value: NAME_REFUSED },\n\t\t\trules,\n\t\t};\n\t}\n\tif (splitPersonName(scrub.value) === null) {\n\t\treturn {\n\t\t\tkind: \"refused\",\n\t\t\trefusal: { rule: \"unsplittable\", printed, value: NAME_REFUSED },\n\t\t\trules,\n\t\t};\n\t}\n\treturn { kind: \"name\", scrubbed: scrub.value, rules };\n}\n",
@@ -13,7 +13,7 @@
13
13
  "/**\n * person-name.ts — the parsed personal name, and its five level projections.\n *\n * `docs/NAME-NORMALIZATION.md` § *The shape of the normalizer* (440-560) is the\n * specification. Read it; this file implements it and does not restate it.\n *\n * ## One parse, five projections — not five normalizers\n *\n * The ask is a canonical NAME normalizer, not a canonical STRING normalizer. A\n * string normalizer must pick one lossy answer, and every caller that wanted a\n * different one writes its own — which is how six particle vocabularies and\n * three splitters happened. This parses once, keeps the structure, and lets each\n * caller name the loss it can afford with a `dop` argument.\n *\n * NN0 is the print. NN1 repairs only never-information. NN2 is the canonical\n * display string. NN3 drops punctuation and case off NN2. NN4 drops field order\n * off NN3. The level table in § *The levels, by use case* is authority for which of those each level\n * keeps.\n *\n * ## NN2 IS NOT RE-IMPLEMENTED HERE\n *\n * It is `./person-display.ts`, called. That module is the display convention's renderer\n * and it already reads the one splitter, the one particle vocabulary and the\n * lexicon; a second renderer built off `NamePart` would be the third\n * implementation of \"which token is the surname\" that this whole initiative\n * exists to delete. NN3 and NN4 are then pure string transforms of NN2, which is\n * exactly what that table says they are.\n *\n * ## What `NamePart` is for, since NN2 does not read it\n *\n * The per-PART lexicon lookup. `lexiconKey(\"Torvell-MacDonald\")` is\n * `torvellmacdonald`, which no entry answers; `macdonald` is one. A compound's\n * `parts` make that lookup per-part by construction, so no fused-prefix stem list is\n * needed to find the lexicon entry inside a compound.\n *\n * ## Recursion, not inheritance\n *\n * `McRalue-Quorvez`, `de la Varno-O'Thyltith` and `McFoskemow-Varnowski` are measured\n * corpus names that a class hierarchy cannot express — no object is both\n * `IrishName` and `HispanicName`. A part that may contain parts holds them\n * without strain and each child keeps its own `tradition`.\n *\n * ## The parts carry the PRINT\n *\n * `particles`, `base` and `suffixes` hold the print's own tokens — accent, case\n * and apostrophe intact. `{ particles: [\"Ní\"], base: \"Mhaolvarna\" }` is what\n * makes `NíMhaolvarna`, `Ní Mhaolvarna` and `nimhaolvarna` three renderings of one\n * parse instead of a smush committed at parse time.\n *\n * ## A FUSED prefix is not a particle run\n *\n * `particles` holds what the PRINT separated. The `Mc` of `McRalue` is inside\n * the token, so it is part of `base` and `./name-case.ts`'s D3 rules answer for\n * it; the `Mc` of `Mc Virkby` is a run. That is the vocabulary's own test read at\n * the other boundary — a particle is confirmed from the tokens that follow it,\n * never from resemblance.\n */\n\nimport { normalizeApostrophes } from \"../lexicon/apostrophes.ts\";\nimport { toAscii } from \"../lexicon/ascii-approx.ts\";\nimport { isStandaloneNameParticle, nameParticle } from \"../particles/particle-vocabulary.ts\";\nimport { type CellVerdict, type Refusal, classifyCell } from \"./cell-verdict.ts\";\nimport { isNoNamePrint } from \"./name-placeholder.ts\";\nimport { NAME_REFUSED, type ParentheticalHandler } from \"./name-scrub.ts\";\nimport {\n\ttype NameOrder,\n\ttype NameSplit,\n\tgivenNameGroups,\n\tisNameSuffix,\n\tsplitPersonName,\n} from \"./name-split.ts\";\nimport {\n\ttype DisplayLexicon,\n\tGIVEN_SEPARATOR,\n\tSURNAME_SEPARATOR,\n\tformatPersonDisplay,\n\tlexiconKey,\n\tparsePersonName,\n} from \"./person-display.ts\";\nimport { isTeamPrint } from \"./team-name.ts\";\n\n// ─── traditions ───────────────────────────────────────────────────────────────\n\n/**\n * What tradition a name part belongs to. One letter, per `docs/NAME-NORMALIZATION.md:449`.\n *\n * IT IS CARRIED AND NEVER BRANCHED ON, which is the same discipline\n * `../particles/particle-vocabulary.ts` states for `ParticleTradition`: the flag is\n * evidence for a consumer, and the only behaviour the document reserves for it is\n * denial at NN5 — *\"two parts with different non-null traditions never match\"* —\n * which is the experimental band and not implemented here.\n */\nexport type NameTradition = \"a\" | \"b\" | \"g\" | \"i\" | \"n\" | \"s\";\n\n/**\n * The six traditions, each under BOTH of its codes.\n *\n * TWO ALPHABETS FOR ONE CONCEPT, AND THAT IS WHY THIS TABLE EXISTS. `names.txt`\n * issues a tradition as a DIGIT (`Kowalski:L6`) and its header rules those\n * indices permanent, running `1-9` then `a-z`; `docs/NAME-NORMALIZATION.md`\n * spells the same six as LETTERS. Deriving either from the other by position is\n * how they silently diverge the first time a seventh tradition is issued, so\n * both codes sit on one row and a spec pins that each column is injective.\n *\n * WELSH AND ROMANCE ARE DELIBERATELY UNISSUED — `names.txt` says so in its own\n * header — so no particle of the `romance` group reaches a tradition here.\n */\nexport const NAME_TRADITIONS: readonly {\n\treadonly letter: NameTradition;\n\treadonly index: string;\n\treadonly label: string;\n}[] = [\n\t{ letter: \"a\", index: \"1\", label: \"Armenian\" },\n\t{ letter: \"g\", index: \"2\", label: \"Germanic\" },\n\t{ letter: \"b\", index: \"3\", label: \"Iberian\" },\n\t{ letter: \"i\", index: \"4\", label: \"Irish/Gaelic\" },\n\t{ letter: \"n\", index: \"5\", label: \"Nordic\" },\n\t{ letter: \"s\", index: \"6\", label: \"Slavic\" },\n];\n\n/** `names.txt`'s tradition index → this module's letter. `undefined` if unissued. */\nexport function traditionFromIndex(index: string): NameTradition | undefined {\n\treturn NAME_TRADITIONS.find((t) => t.index === index)?.letter;\n}\n\n/**\n * A tradition lookup over `names.txt`, as this module consults it: one O(1)\n * question keyed by `lexiconKey()`, answered with a letter or `undefined`.\n *\n * IT IS INJECTED FOR THE SAME REASON `DisplayLexicon` IS. This package is a\n * zero-dependency leaf that reads no file, and a consumer may cache folds that run\n * through it under a key that covers the code and no data file — so a table compiled\n * in here is one such a cache key cannot see moving. The caller that already holds\n * `names.txt` hands its lookup in.\n */\nexport type NameTraditionLookup = (key: string) => NameTradition | undefined;\n\n// ─── the type ─────────────────────────────────────────────────────────────────\n\n/**\n * One name part: a root, the particle run that governs it, and — for a\n * compound joined by a hyphen or a space — the decomposition of that root.\n */\nexport interface NamePart {\n\t/**\n\t * The particle run as the PRINT gave it, in reading order, never smushed.\n\t * Empty where the print separated none.\n\t */\n\treadonly particles: readonly string[];\n\t/**\n\t * The root the particles govern, as printed. May carry a space (`Stoskmore Trirock`)\n\t * or a hyphen (`Walter-Oreskarard`), and either makes it a compound — see `parts`.\n\t */\n\treadonly base: string;\n\t/**\n\t * `base` decomposed. NON-EMPTY ONLY FOR A COMPOUND, and a compound here is a root\n\t * of two or more pieces joined by a HYPHEN OR A SPACE: `O'Mearorro-Failtonton` and\n\t * `Comerton Rennuvham` both decompose, one leaf per piece. The rule\n\t * for names is that a hyphen and a space between two surname parts are the same\n\t * thing (`name-compose.ts`, `surnameParts`), and a directory that prints\n\t * `Comerton Rennuvham, Ciara` names the same `Rennuvham` a register printing `Ciara\n\t * Rennuvham` does. The JOINER IS NOT RECORDED HERE because nothing renders from the\n\t * parts: `base` keeps the print's own space or hyphen, and `person-display.ts`\n\t * renders `base` (`Stoskmore Trirock`, never `StoskmoreTrirock`).\n\t */\n\treadonly parts: readonly NamePart[];\n\t/** what tradition the part asserts, or `null` where nothing settles it */\n\treadonly tradition: NameTradition | null;\n}\n\n/** The levels over which equality is an equivalence relation. */\nexport type TransitiveLevel = \"nn0\" | \"nn1\" | \"nn2\" | \"nn3\" | \"nn4\";\n\n/**\n * Every level, including the experimental similarity band.\n *\n * THE BOUNDARY BETWEEN NN4 AND NN5 IS TRANSITIVITY, and it is in the types\n * rather than in a docblock. NN0-NN4 are total functions, so equal\n * keys form an equivalence relation and a hash-backed set or map is well\n * defined. NN5 is a DISTANCE, so `probablySame(a,b) ∧ probablySame(b,c) ⇏\n * probablySame(a,c)` and any structure over it is a clustering whose contents\n * depend on insertion order and on a declared linkage.\n */\nexport type Level = TransitiveLevel | \"nn5\";\n\n/**\n * A printed personal name, parsed.\n *\n * `toString()` RETURNS NN2 DELIBERATELY, and the reason is asymmetric cost: NN2\n * is the strictest view, so an accidental `${a} === ${b}` UNDER-merges. A false\n * reject is recoverable. A false accept silently merges two dancers.\n *\n * NEVER COMPARE TWO LEVEL STRINGS WITH `===`. This is the floating-point\n * discipline and it is what stops a caller writing a second normalizer: a caller\n * that cannot compare declares its precision instead, and the `dop` argument at\n * the call site *is* the justification, inline and readable.\n */\nexport interface PersonName {\n\treadonly [Symbol.toStringTag]: \"PersonName\";\n\t/** NN2. See the note above before comparing it with anything. */\n\ttoString(): string;\n\n\t/** NN0 — exactly what the page said. */\n\treadonly nn0: string;\n\t/** NN1 — the print with only never-information repaired. */\n\treadonly nn1: string;\n\t/** NN2 — the canonical display string, `Last<<First<Middle`, ASCII. */\n\treadonly nn2: string;\n\t/**\n\t * NN3 — the fold two prints are COMPARED at. NOT a drawer a row goes in: no row is\n\t * ever filed under a key, and a key is never used for matching by `===`. A row is filed for the\n\t * address of the result that printed it. Two names are compared with\n\t * `probablySame(a, b, dop)`; a caller needing a hash structure takes\n\t * `createNameSet(dop)` / `createNameMap(dop)`, which hold the precision themselves.\n\t */\n\treadonly nn3: string;\n\t/** NN4 — NN3 with field order dropped. A matching view, never a key. */\n\treadonly nn4: string;\n\n\t/**\n\t * How long the DISPLAY name is — `toString()`, which is NN2.\n\t *\n\t * IT IS A GETTER FOR THE DISPLAY NAME LENGTH: `p.nn3.length` asks for the exact\n\t * level's length, and `p.length` is the display name's. A caller wanting the\n\t * length of some OTHER level still asks that level for it, which is the point\n\t * of the split — this one is the length of the name as the project renders it,\n\t * and nothing has to know which level that is.\n\t *\n\t * IT IS NOT A COMPARISON. Two names of equal display length are not thereby\n\t * the same name; `nameCompare`/`probablySame` are the only things that answer\n\t * that, at a declared level.\n\t */\n\treadonly length: number;\n\n\t/**\n\t * The SURNAME field of NN3 — upper case, punctuation and accents gone.\n\t *\n\t * THE KEY-GRADE SURNAME, and it exists so that a caller asking *\"do these two\n\t * prints share a surname\"* never re-derives one. It is the half of `nn3`\n\t * before the field separator, so it folds exactly as `nn3` folds and two\n\t * callers cannot disagree about it: `O'Rervton`, `ORervton` and `Ó Rervton` reach\n\t * `ORERVTON`, and the spaced compound `Graro - Brarkia` reaches `GRAROBRARKIA`\n\t * because a compound surname is ONE field (C4).\n\t *\n\t * `surname` above is the PARSE — particles, base, sub-parts, tradition, with\n\t * the print's own case and accents intact. This is its projection at NN3. Ask\n\t * `surname` what the name IS; ask this whether two prints AGREE on it. It is not\n\t * a filing key and a row is never filed under it (see `nn3`).\n\t *\n\t * `\"\"` for a refusal, which is the same answer as \"no surname was captured\"\n\t * on purpose: neither holds a surname, and a refusal must not fold to a\n\t * name-shaped token (see `nn3`).\n\t */\n\tsurnameKey(): string;\n\n\t/**\n\t * The GIVEN-NAME fields of NN3, in print order, AS A LIST.\n\t *\n\t * `givenName()` below is this joined, and it is DEFINED as this joined, so the\n\t * two cannot disagree about where a field boundary is. A caller that wants the\n\t * fields asks for the fields; splitting the joined string on the separator is\n\t * a hand split, and a hand split is a second answer to where a field boundary is.\n\t *\n\t * THE FIELD ORDER IS THE PRINT'S. Element `0` is the first given name and the\n\t * rest are what NN5 calls the MIDDLE fields; `./name-middle.ts` is the one\n\t * consumer that reads it that way, and it is a RELATION over two of these\n\t * lists rather than a sixth level.\n\t *\n\t * A TOKEN-VALUED PARTITIONER IS COMPARED AS TOKENS. The same rule holds for school\n\t * names, and the reason is the same here, except that C4 makes it stronger — no\n\t * NN3 field contains a space, so the join back is injective and the rule is\n\t * about which question is being asked, not about ambiguity.\n\t *\n\t * `[]` where the parse holds no given name at all, and for a refusal.\n\t */\n\tgivenFields(): readonly string[];\n\n\t/**\n\t * The GIVEN-NAME fields of NN3, in print order, `<`-joined.\n\t *\n\t * IT EXISTS so that no caller slices a stored key at `<<` and splits the remainder\n\t * on `<` itself. `surnameKey()` and this one partition\n\t * `nn3`, so a caller needs neither separator.\n\t *\n\t * IT IS NN3'S FIELD STRUCTURE AND NOT THE PARSE'S. A suffix NN2 wrote into the\n\t * trailing given slot is here too — `Jyskock<<John<II` gives `JOHN<II` —\n\t * because that is where the KEY carries it, and a caller comparing given-name\n\t * fields is comparing what the key holds. `suffixes` is where the parse's own\n\t * list of them is, and it is the thing to read when the question is about\n\t * generation rather than about the key.\n\t *\n\t * `\"\"` where the parse holds no given name at all, and for a refusal.\n\t */\n\tgivenName(): string;\n\n\treadonly surname: NamePart;\n\treadonly given: readonly NamePart[];\n\t/**\n\t * Generational and qualification suffixes, AS PRINTED and in print order.\n\t * The canonical spelling is a rendering decision and lives at NN2.\n\t */\n\treadonly suffixes: readonly string[];\n\n\t/**\n\t * Non-null exactly when the cell holds something that is not a person's name.\n\t * An EMPTY cell holds nothing and carries no refusal (`isEmpty()`), so\n\t * `refusal === null` is not \"a person\": ask `isPerson()`.\n\t */\n\treadonly refusal: Refusal | null;\n\t/** What `classifyCell` made of the cell. */\n\treadonly verdict: CellVerdict;\n\n\t/**\n\t * Does this cell name a TEAM rather than a person?\n\t *\n\t * THE PREDICATE, and the reason it exists is the shape it replaces:\n\t * `PersonName.toString().contains('Team')` or anything like it.\n\t * A substring test says yes to `Teamwork Murphy`; this reads the team\n\t * format — the word, and at most one letter after one space.\n\t *\n\t * IT IS ASKED OF NN1, NOT OF `toString()`. NN2 of a team is `!!!INVALID`,\n\t * because a team fills neither the surname nor the given slot and the parse\n\t * refuses it; NN1 is the print with only never-information repaired, which is\n\t * where the designation still is. A `true` here therefore EXPLAINS a refusal\n\t * rather than contradicting one — the cell was rejected as a person's name\n\t * because it is a team, which is a different fact from a defective cell.\n\t */\n\tisTeam(): boolean;\n\n\t/**\n\t * Does this cell name a person?\n\t *\n\t * THE THREE KINDS ARE NOT TWO, and this predicate is where a caller stops\n\t * having to know that. `./cell-verdict.ts` keeps *\"no name was captured\"*\n\t * and *\"this is not a name\"* apart because a consumer reports each\n\t * separately; a caller asking whether it holds a person wants `false` for\n\t * both, and would otherwise re-derive the disjunction — a second answer to\n\t * the question `classifyCell` already settled.\n\t *\n\t * IT REPLACES `icao === null`. A key string that is absent is the OUTPUT of\n\t * a refusal, so testing it makes every consumer depend on the spelling of a\n\t * fold rather than on the verdict behind it: `icao === null` becomes\n\t * `!nameA?.isPerson()`.\n\t *\n\t * It says nothing about WHICH person, and nothing about teams — which\n\t * prints name no person is `isTeam()`'s question and is not answered here.\n\t */\n\tisPerson(): boolean;\n\n\t/**\n\t * Was NO name captured: the cell is empty, or whitespace only?\n\t *\n\t * The third kind, asked directly. An empty cell is neither a person nor a\n\t * refusal, so a caller that means \"the sheet printed nothing here\" asks this\n\t * and never `refusal === null && !isPerson()`.\n\t */\n\tisEmpty(): boolean;\n\n\t/**\n\t * Did the page print NO NAME here: an empty cell, a cell with no letter in\n\t * it (`???`, `0`), or a placeholder (`Unknown`, `TBA`, `Not known`)?\n\t *\n\t * `isEmpty()` is the first kind alone; this is the whole of \"no name was\n\t * printed\", and it does not depend on which refusal rule fired (`TBA` is the\n\t * scrub's `refuse-single-token`, `Not known` the guard's `placeholder`).\n\t * `./name-placeholder.ts` is the one place the answer is decided, and\n\t * `isNoNamePrint` there is the same answer for a caller that holds only the\n\t * print.\n\t */\n\tprintsNoName(): boolean;\n}\n\n// ─── build context ────────────────────────────────────────────────────────────\n\n/**\n * What one factory builds names under. Nothing in this module is state: every\n * function that consults the lexicon, the tradition lookup or the parenthetical\n * handler takes the context it was handed, so two factories never see each\n * other's options. `./factory.ts` makes the public factories over it.\n */\nexport interface BuildContext {\n\t/** consulted by NN2 before its rules (doc D5); `undefined` means rules only */\n\treadonly lexicon: DisplayLexicon | undefined;\n\t/** a root's tradition where its particles do not settle it */\n\treadonly traditions: NameTraditionLookup | undefined;\n\t/** what an aside in `( … )` or `\" … \"` means; `undefined` strips every aside */\n\treadonly parenthetical: ParentheticalHandler | undefined;\n}\n\n// ─── the levels ───────────────────────────────────────────────────────────────\n\n/**\n * NN1 — the print with only NEVER-INFORMATION repaired.\n *\n * Compatibility composition folds a ligature (`Delfina` → `Delfina`), the apostrophe\n * vocabulary folds a curly quote, format characters go and control characters\n * become the whitespace they were standing in for. CASE AND ACCENTS SURVIVE:\n * the level table keeps both at this level, and input case is a signal that NN0 and NN1\n * may read.\n */\nfunction renderNn1(print: string): string {\n\treturn normalizeApostrophes(print.normalize(\"NFKC\"))\n\t\t.replace(/\\p{Cf}+/gu, \"\")\n\t\t.replace(/\\p{Cc}+/gu, \" \")\n\t\t.replace(/\\s+/gu, \" \")\n\t\t.trim();\n}\n\n/**\n * NN3 — NN2 with punctuation and case dropped (the level table, D2, C4).\n *\n * A PURE TRANSFORM OF NN2, which is what makes NN3 \"ignores strictly more than\n * NN2 does\" a property rather than a hope. The separators survive because they\n * are the field structure, not punctuation: `O'Rervton<<Moira` reaches\n * `ORERVTON<<MOIRA`, and the space of `Stoskmore Trirock<<Steathainnell` goes with\n * everything else, which is C4 — no field contains a space.\n */\nfunction renderNn3(nn2: string): string {\n\treturn nn2.replace(/[^\\p{L}\\p{N}<]+/gu, \"\").toLocaleUpperCase();\n}\n\n/**\n * NN2 cut into its fields — the surname, then each given name, in print order.\n *\n * ONE CUT, READ BY BOTH HALVES. `surnameKey()` takes `[0]` and `givenName()`\n * takes the rest, so the two cannot disagree about where the boundary is, and\n * neither re-implements `renderNn3` — each folds the slice it took with the same\n * function `nn3` itself uses. The suffixes are already outside the given-name\n * fields, because NN2 wrote them there.\n */\nfunction fieldsOfNn2(nn2: string): string[] {\n\tconst at = nn2.indexOf(SURNAME_SEPARATOR);\n\tif (at < 0) return [nn2];\n\treturn [\n\t\tnn2.slice(0, at),\n\t\t...nn2\n\t\t\t.slice(at + SURNAME_SEPARATOR.length)\n\t\t\t.split(GIVEN_SEPARATOR)\n\t\t\t.filter((f) => f !== \"\"),\n\t];\n}\n\n/**\n * NN4 — NN3 with field order dropped (the level table).\n *\n * THE ORDER IT TOLERATES IS THE NAME ORDER. A sheet that printed `Mailtina John`\n * where another printed `John Mailtina` produces two different NN3 keys and one\n * NN4, which is what the level is for: asking whether two prints are the same\n * name when the split may have read them opposite ways.\n */\nfunction renderNn4(nn3: string): string {\n\treturn nn3\n\t\t.split(GIVEN_SEPARATOR)\n\t\t.filter((f) => f !== \"\")\n\t\t.sort()\n\t\t.join(GIVEN_SEPARATOR);\n}\n\n// ─── the parse ────────────────────────────────────────────────────────────────\n\n/** The tradition a particle run asserts, where the vocabulary settles one. */\nfunction traditionOfParticles(particles: readonly string[]): NameTradition | null {\n\tfor (const p of particles) {\n\t\tconst entry = nameParticle(p);\n\t\tif (entry === undefined) continue;\n\t\t// THREE OF THE SIX VOCABULARY GROUPS MAP, AND THE PROJECT ALREADY SAID SO.\n\t\t// `src/cli/propose-traditions.ts` is the proposer\n\t\t// that issues these indices from a print's morphology: its Irish/Gaelic\n\t\t// marker is `^(Mc|Fitz)` — *\"covers the Norman `Fitz`\"* — and its Germanic\n\t\t// marker is the `Van|Von|Der|Den|Ter|Ten|Zu` particle. `romance` reaches\n\t\t// nothing, because `names.txt` rules Romance deliberately unissued and the\n\t\t// proposer types only the MULTI-TOKEN `de la`/`de los`/`del` as Iberian,\n\t\t// which is a fact about the whole print and not about a bare `de`.\n\t\t// `elided` and `ocr` describe how a print spells a join, not what it\n\t\t// asserts. A token carrying several traditions is answered by the first\n\t\t// that maps, so `o` (gaelic AND elided) is Irish and `d` is nothing.\n\t\tif (entry.traditions.includes(\"gaelic\") || entry.traditions.includes(\"norman\")) return \"i\";\n\t\tif (entry.traditions.includes(\"germanic\")) return \"g\";\n\t}\n\treturn null;\n}\n\n/** The tradition of one root, from the particles first and the lexicon second. */\nfunction traditionOf(\n\tparticles: readonly string[],\n\tbase: string,\n\tctx: BuildContext,\n): NameTradition | null {\n\tconst fromParticles = traditionOfParticles(particles);\n\tif (fromParticles !== null) return fromParticles;\n\tif (ctx.traditions === undefined) return null;\n\tconst key = lexiconKey(base);\n\treturn key === \"\" ? null : (ctx.traditions(key) ?? null);\n}\n\n/** A leaf part: no particles of its own, no decomposition. Used for a compound's children. */\nfunction leafPart(base: string, ctx: BuildContext): NamePart {\n\treturn { particles: [], base, parts: [], tradition: traditionOf([], base, ctx) };\n}\n\n/**\n * A ROOT'S COMPOUND PIECES, or one piece where it is not a compound.\n *\n * A HYPHEN AND A SPACE ARE ONE JOINER between two surname parts: `Walter-Oreskarard`\n * and `Comerton Rennuvham` both cut.\n *\n * A HYPHEN ALWAYS CUTS (`docs/NAME-NORMALIZATION.md` § *Consumer contract*). The print\n * hyphenated the piece off, so a hyphenated particle is a piece of its own: `El-Varoun` reads\n * `El` and `Varoun`, `De-Ste-Varne` reads `De`, `Ste` and `Varne`, `Goskick-La-Vorne` reads\n * `Goskick`, `La` and `Vorne`.\n *\n * A SPACE AFTER A PARTICLE DOES NOT CUT: a space is how a particle is printed as well as how\n * two surnames are joined, so the particle stays on the piece after it with the space the\n * print gave, and `Ní Jirkirkane Uí Sevith`'s root reads `Jirkirkane` and `Uí Sevith` and never a\n * part `Uí`. A particle with nothing after it in its hyphen piece is a piece of its own, the\n * same test `partFromTokens` applies to the leading run.\n *\n * Either way the particle still GOVERNS the piece after it, and what compares parts glues it\n * on (`./name-compose.ts`, `surnameParts`), as NN3 does.\n */\nfunction compoundSegments(base: string): string[] {\n\tconst out: string[] = [];\n\tfor (const piece of base.split(/-+/u)) {\n\t\tconst raw = piece.split(/\\s+/u).filter((s) => s !== \"\");\n\t\tlet held: string[] = [];\n\t\tfor (let i = 0; i < raw.length; i++) {\n\t\t\tconst t = raw[i] as string;\n\t\t\tif (i + 1 < raw.length && isStandaloneNameParticle(t)) {\n\t\t\t\theld.push(t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tout.push([...held, t].join(\" \"));\n\t\t\theld = [];\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * One part from a run of printed tokens.\n *\n * The particle run is the LEADING tokens that are standalone particles and\n * govern something after them; the rest, joined by the space the print gave, is\n * the root. A trailing token governs nothing and is therefore never a particle,\n * whatever it resembles — the same test `./person-display.ts` applies when it\n * renders the run.\n */\nfunction partFromTokens(tokens: readonly string[], ctx: BuildContext): NamePart {\n\tlet i = 0;\n\twhile (i + 1 < tokens.length && isStandaloneNameParticle(tokens[i] as string)) i++;\n\tconst particles = tokens.slice(0, i);\n\tconst base = tokens.slice(i).join(\" \");\n\tconst segments = compoundSegments(base);\n\treturn {\n\t\tparticles,\n\t\tbase,\n\t\tparts: segments.length > 1 ? segments.map((seg) => leafPart(seg, ctx)) : [],\n\t\ttradition: traditionOf(particles, base, ctx),\n\t};\n}\n\n/** One part from a run of token indices into a split. */\nfunction partFromRun(split: NameSplit, run: readonly number[], ctx: BuildContext): NamePart {\n\treturn partFromTokens(\n\t\trun.map((i) => split.tokens[i] as string),\n\t\tctx,\n\t);\n}\n\n// ─── construction ─────────────────────────────────────────────────────────────\n\ninterface Built {\n\tnn0: string;\n\tnn1: string;\n\tnn2: string;\n\tsurname: NamePart;\n\tgiven: readonly NamePart[];\n\tsuffixes: readonly string[];\n\trefusal: Refusal | null;\n\tverdict: CellVerdict;\n}\n\n/**\n * A `PersonName` over a built parse, with NN3 and NN4 computed on first read.\n *\n * A CLASS, SO THE METHODS LIVE ON THE PROTOTYPE. This was an object literal, and an\n * object literal's methods and getters are function objects made anew per instance:\n * nine of them, each with a closure over the builder, on every one of the ~166k names\n * the memo holds over a corpus pass. Measured on those names, the\n * literal cost 3.9 KB an instance and 612 MB of RSS for the memo; the class holds the\n * strings, the parts and two lazy slots and nothing else per instance.\n */\nclass MaterializedName implements PersonName {\n\treadonly nn0: string;\n\treadonly nn1: string;\n\treadonly nn2: string;\n\treadonly surname: NamePart;\n\treadonly given: readonly NamePart[];\n\treadonly suffixes: readonly string[];\n\treadonly refusal: Refusal | null;\n\treadonly verdict: CellVerdict;\n\t#nn3: string | undefined;\n\t#nn4: string | undefined;\n\n\tconstructor(b: Built) {\n\t\tthis.nn0 = b.nn0;\n\t\tthis.nn1 = b.nn1;\n\t\tthis.nn2 = b.nn2;\n\t\tthis.surname = b.surname;\n\t\tthis.given = b.given;\n\t\tthis.suffixes = b.suffixes;\n\t\tthis.refusal = b.refusal;\n\t\tthis.verdict = b.verdict;\n\t}\n\n\tget [Symbol.toStringTag](): \"PersonName\" {\n\t\treturn \"PersonName\";\n\t}\n\ttoString(): string {\n\t\treturn this.nn2;\n\t}\n\tget nn3(): string {\n\t\t// REFUSAL IS NOT A NAME AND IS NOT FOLDED LIKE ONE. `!!!INVALID` through\n\t\t// `renderNn3` would lose its punctuation and read as a name-shaped token,\n\t\t// which is the one thing the `!!!` spelling of it exists to prevent.\n\t\tthis.#nn3 ??= this.refusal !== null ? NAME_REFUSED : renderNn3(this.nn2);\n\t\treturn this.#nn3;\n\t}\n\tget nn4(): string {\n\t\tthis.#nn4 ??= this.refusal !== null ? NAME_REFUSED : renderNn4(renderNn3(this.nn2));\n\t\treturn this.#nn4;\n\t}\n\tget length(): number {\n\t\treturn this.nn2.length;\n\t}\n\tsurnameKey(): string {\n\t\treturn this.refusal !== null ? \"\" : renderNn3(fieldsOfNn2(this.nn2)[0] ?? \"\");\n\t}\n\tgivenFields(): readonly string[] {\n\t\treturn this.refusal !== null ? [] : fieldsOfNn2(this.nn2).slice(1).map(renderNn3);\n\t}\n\tgivenName(): string {\n\t\t// DEFINED AS THE FIELDS JOINED, not rendered a second way. `renderNn3`\n\t\t// keeps the separator, so folding each field and joining is the same string\n\t\t// as joining and folding — and writing it this way makes that an identity\n\t\t// rather than a coincidence two bodies have to keep agreeing on.\n\t\treturn this.givenFields().join(GIVEN_SEPARATOR);\n\t}\n\tisTeam(): boolean {\n\t\treturn isTeamPrint(this.nn1);\n\t}\n\tisPerson(): boolean {\n\t\treturn this.refusal === null && this.verdict.kind !== \"empty\";\n\t}\n\tisEmpty(): boolean {\n\t\treturn this.verdict.kind === \"empty\";\n\t}\n\tprintsNoName(): boolean {\n\t\treturn this.isEmpty() || isNoNamePrint(this.nn0);\n\t}\n}\n\nfunction materialize(b: Built): PersonName {\n\treturn new MaterializedName(b);\n}\n\nconst EMPTY_PART: NamePart = { particles: [], base: \"\", parts: [], tradition: null };\n\nfunction refusedName(\n\tprint: string,\n\tnn1: string,\n\tverdict: CellVerdict,\n\trefusal: Refusal,\n): PersonName {\n\treturn materialize({\n\t\tnn0: print,\n\t\tnn1,\n\t\t// NN0 AND NN1 STILL CARRY THE PRINT. A refusal says the cell is not a name;\n\t\t// it does not say the page printed nothing, and the level table gives NN0 as\n\t\t// \"exactly what the page said\" with no carve-out.\n\t\tnn2: NAME_REFUSED,\n\t\tsurname: EMPTY_PART,\n\t\tgiven: [],\n\t\tsuffixes: [],\n\t\trefusal,\n\t\tverdict,\n\t});\n}\n\n/**\n * The ICAO shape, as a fast path for a string already believed well-formed.\n *\n * `Surname<<Given<Middle`, which is the shape of the key a row is filed under\n * and what a human-facing surface renders. THROWS on anything else: the point of\n * the fast path is to skip the guard, so a caller that is wrong about its input\n * must find out rather than receive a plausible parse.\n *\n * A SUFFIX IN THE TRAILING GIVEN SLOT IS READ BACK AS A SUFFIX, because that is\n * where NN2 put it (`Jyskock<<John<II`), so `factory.fromIcao(pn.nn2)`\n * reproduces `pn`'s own partition rather than inventing a given name `II`.\n *\n * `print` IS THE VERBATIM STRING THE KEY WAS MADE FROM, where the caller holds\n * it — a stored row holds both. Without it the key stands in for its own input\n * and NN0 reports a fold as though it were the page, which is the one thing NN0\n * may never do: the level table gives NN0 as *\"exactly what the page said\"*.\n * Pass it wherever a row carries it. It changes NOTHING else: the partition, and\n * every level from NN2 down, come off the key, because the key is what the row\n * was filed under and a second opinion at read time is a silent split between\n * the query side and the stored side.\n */\n/**\n * Will `fromIcao` read this string, or throw on it?\n *\n * IT ASKS THE SAME QUESTION THE THROW ASKS, off the same normalized form, so a\n * caller that tests before calling cannot be told yes and then thrown at. That is\n * the whole reason it is here rather than spelled as an `indexOf` at each caller:\n * a stored key with a leading space is ICAO-shaped to a raw `indexOf` and is not\n * to `renderNn1`, and the corpus holds such keys.\n */\nexport function isIcaoName(icao: string): boolean {\n\treturn renderNn1(icao).indexOf(SURNAME_SEPARATOR) > 0;\n}\n\n/** An ICAO key read back into a name. The factories' `fromIcao`. */\nexport function buildFromIcao(ctx: BuildContext, icao: string, print?: string): PersonName {\n\tconst s = renderNn1(icao);\n\tconst at = s.indexOf(SURNAME_SEPARATOR);\n\tif (at <= 0) {\n\t\tthrow new TypeError(\n\t\t\t`fromIcao: not an ICAO name, expected Surname${SURNAME_SEPARATOR}Given: ${JSON.stringify(icao)}`,\n\t\t);\n\t}\n\tconst surnameText = s.slice(0, at);\n\tconst fields = s\n\t\t.slice(at + SURNAME_SEPARATOR.length)\n\t\t.split(GIVEN_SEPARATOR)\n\t\t.filter((f) => f !== \"\");\n\tconst suffixes: string[] = [];\n\twhile (fields.length > 0 && isNameSuffix(fields[fields.length - 1] as string)) {\n\t\tsuffixes.unshift(fields.pop() as string);\n\t}\n\tconst nn2 = toAscii(s);\n\treturn materialize({\n\t\tnn0: print ?? icao,\n\t\tnn1: print === undefined ? s : renderNn1(print),\n\t\tnn2,\n\t\tsurname: partFromTokens(\n\t\t\tsurnameText.split(\" \").filter((t) => t !== \"\"),\n\t\t\tctx,\n\t\t),\n\t\tgiven: fields.map((f) =>\n\t\t\tpartFromTokens(\n\t\t\t\tf.split(\" \").filter((t) => t !== \"\"),\n\t\t\t\tctx,\n\t\t\t),\n\t\t),\n\t\tsuffixes,\n\t\trefusal: null,\n\t\tverdict: { kind: \"name\", scrubbed: s, rules: [] },\n\t});\n}\n\n/**\n * An NN4 string read back: fields whose ORDER carries nothing, because NN4 is\n * the level that dropped it.\n *\n * IT EXISTS FOR C2 AND FOR NOTHING ELSE. Idempotence is scoped to a level\n * re-applied to its OWN output, so `personName(x.nn4).nn4 === x.nn4` has to\n * hold; reading NN2 or NN3 off such a parse is defined but meaningless, since\n * the surname slot holds whichever field sorted first.\n */\nfunction parseUnordered(s: string, ctx: BuildContext): PersonName {\n\tconst fields = s.split(GIVEN_SEPARATOR).filter((f) => f !== \"\");\n\treturn materialize({\n\t\tnn0: s,\n\t\tnn1: s,\n\t\tnn2: (fields[0] as string) + SURNAME_SEPARATOR + fields.slice(1).join(GIVEN_SEPARATOR),\n\t\tsurname: partFromTokens([fields[0] as string], ctx),\n\t\tgiven: fields.slice(1).map((f) => partFromTokens([f], ctx)),\n\t\tsuffixes: [],\n\t\trefusal: null,\n\t\tverdict: { kind: \"name\", scrubbed: s, rules: [] },\n\t});\n}\n\n/** The parse of one printed cell. Total. The factories' `parse`. */\nexport function buildPersonName(ctx: BuildContext, print: string, order: NameOrder): PersonName {\n\tconst nn1 = renderNn1(print);\n\t// THE FAST PATH IS TAKEN ONLY WHERE IT CANNOT THROW, which is what makes this\n\t// function total. `buildFromIcao` rejects a separator at index 0 — the\n\t// point of a fast path is to skip the guard — so `<<Sean`, a key whose\n\t// surname half is empty, would reach a caller as an exception rather than as\n\t// a refusal. It is handed to the guard below instead, which is total.\n\tif (nn1.indexOf(SURNAME_SEPARATOR) > 0) return buildFromIcao(ctx, print);\n\t// An NN4 string: separators but no surname separator. See `parseUnordered`.\n\t//\n\t// A STRING OF BARE SEPARATORS IS NOT ONE. `parseUnordered` reads field 0 as\n\t// the surname slot, so a print whose separators fence off no field at all\n\t// would put `undefined` there and render a name-shaped NN2 out of nothing.\n\t// It is handed to the guard below, which refuses it.\n\tif (\n\t\tnn1.includes(GIVEN_SEPARATOR) &&\n\t\t!/[^\\p{L}\\p{N}<]/u.test(nn1) &&\n\t\tnn1.split(GIVEN_SEPARATOR).some((f) => f !== \"\")\n\t)\n\t\treturn parseUnordered(nn1, ctx);\n\n\tconst verdict = classifyCell(print, { parenthetical: ctx.parenthetical });\n\tif (verdict.kind === \"refused\") return refusedName(print, nn1, verdict, verdict.refusal);\n\tif (verdict.kind === \"empty\") {\n\t\treturn materialize({\n\t\t\tnn0: print,\n\t\t\tnn1,\n\t\t\tnn2: \"\",\n\t\t\tsurname: EMPTY_PART,\n\t\t\tgiven: [],\n\t\t\tsuffixes: [],\n\t\t\t// \"NO NAME WAS CAPTURED\" IS NOT \"THIS IS NOT A NAME\". A consumer reports\n\t\t\t// each separately and `classifyCell` keeps them apart, so an empty\n\t\t\t// cell carries no refusal.\n\t\t\trefusal: null,\n\t\t\tverdict,\n\t\t});\n\t}\n\n\tconst split = splitPersonName(verdict.scrubbed, order);\n\tconst parts = parsePersonName(verdict.scrubbed, order, ctx.lexicon);\n\tif (split === null || parts === null) {\n\t\t// A TEAM PRINT LANDS HERE, via `parsePersonName`'s own null, and it is the\n\t\t// one refusal that is not a defect. `isTeam()` above is what tells the two\n\t\t// apart; there is still no second answer to \"which prints name no person\"\n\t\t// written here, because `parsePersonName` asks the same predicate.\n\t\tconst refusal: Refusal = { rule: \"unsplittable\", printed: print, value: NAME_REFUSED };\n\t\treturn refusedName(print, nn1, verdict, refusal);\n\t}\n\n\treturn materialize({\n\t\tnn0: print,\n\t\tnn1,\n\t\tnn2: formatPersonDisplay(parts),\n\t\tsurname: partFromRun(split, split.surname, ctx),\n\t\tgiven: givenNameGroups(split).map((g) => partFromRun(split, g, ctx)),\n\t\tsuffixes: split.suffixes.map((i) => split.tokens[i] as string),\n\t\trefusal: null,\n\t\tverdict,\n\t});\n}\n\n/**\n * One level off a parsed name, by name.\n *\n * TRANSITIVE LEVELS ONLY, and the type is where that is said: NN5 is a distance\n * and has no string to read.\n */\nexport function levelOf(name: PersonName, dop: TransitiveLevel): string {\n\treturn name[dop];\n}\n\n/**\n * IS ONE GIVEN KEY THE OTHER MADE POORER? Both are `givenName()` keys, and `poorer` abbreviates\n * `fuller` in two shapes. Equal keys abbreviate each other.\n *\n * - THE WHOLE GIVEN NAME AS ONE INITIAL: a platform's public pages print `M Mailtina` where\n * its signed-in pages print `Mary Vellane Mailtina`, so the key `M` abbreviates `MARY<VELLANE`\n * - FIELD BY FIELD, the same number of fields and each field of `poorer` the matching field of\n * `fuller` or its one-letter INITIAL. The parse puts the first part of a compound surname it\n * does not know into the given fields: `N Kaiskystham Vearvo` and `Natalia Kaiskystham Vearvo` are\n * the keys `N<KAISKYSTHAM` and `NATALIA<KAISKYSTHAM` over one surname key `VEARVO`\n *\n * Nothing else is: `C Mailtina Beannell` (`C<MAILTINA`) is not `Cian Beannell` (`CIAN`), and crossed initials\n * (`NATALIA<M` against `N<KAISKYSTHAM`) are neither reading made poorer. The fields are cut here,\n * where the separator is defined, so no caller slices a key by hand.\n */\nexport function givenKeyAbbreviates(poorer: string, fuller: string): boolean {\n\treturn givenFieldsAbbreviate(poorer.split(GIVEN_SEPARATOR), fuller.split(GIVEN_SEPARATOR));\n}\n\n/** `givenKeyAbbreviates` over fields already cut: the one rule, read by both entry points. */\nfunction givenFieldsAbbreviate(p: readonly string[], f: readonly string[]): boolean {\n\tif (p.length === f.length && p.every((x, i) => x === f[i])) return true;\n\tconst whole = p.length === 1 ? (p[0] as string) : \"\";\n\tif (whole.length === 1 && (f[0] ?? \"\").startsWith(whole)) return true;\n\tif (p.length !== f.length) return false;\n\treturn p.every((x, i) => {\n\t\tconst y = f[i] as string;\n\t\treturn x === y || (x.length === 1 && y.startsWith(x));\n\t});\n}\n\n/**\n * Where a name's NN3 given fields stop being given names and start being suffixes. NN2 writes\n * a suffix into the trailing given slot (`Smithson<<W<IV`), and `suffixes` says how many of the\n * trailing fields it is. The same cut as `./name-middle.ts`'s, read off the parse's own decision\n * and never off the vocabulary (`Victoria V Mailtina` prints a middle INITIAL `V`).\n */\nfunction givenSuffixCut(p: PersonName): number {\n\treturn Math.max(1, p.givenFields().length - p.suffixes.length);\n}\n\n/**\n * IS ONE NAME'S GIVEN NAME THE OTHER'S MADE POORER, WITH THE SUFFIXES SET ASIDE? The rule is\n * `givenKeyAbbreviates`'s, applied to the given fields before the suffix cut, and the suffix\n * fields must then be equal at NN3. `givenName()` keeps the suffix in the trailing given slot,\n * because that is where the key carries it, so `W Smithson IV` (`W<IV`) against `William J.\n * Smithson IV` (`WILLIAM<J<IV`) had two fields against three and neither shape fired; set aside,\n * `W` is the whole given name as one initial of `WILLIAM<J`. A suffix one name prints and the\n * other does not is not set aside: `John Mailtina` is not `John Mailtina Jr` made poorer, he may be\n * the father.\n */\nexport function givenAbbreviates(poorer: PersonName, fuller: PersonName): boolean {\n\tconst p = poorer.givenFields();\n\tconst f = fuller.givenFields();\n\tconst pc = givenSuffixCut(poorer);\n\tconst fc = givenSuffixCut(fuller);\n\tconst ps = p.slice(pc);\n\tconst fs = f.slice(fc);\n\tif (ps.length !== fs.length || !ps.every((x, i) => x === fs[i])) return false;\n\treturn givenFieldsAbbreviate(p.slice(0, pc), f.slice(0, fc));\n}\n",
14
14
  "/**\n * The PersonName factories. A `PersonName` is only ever made by one of these.\n *\n * - `createPersonNameFactory(options)`: parses every call.\n * - `createCachingPersonNameFactory(options)`: memoizes `parse` on `(print, order)`.\n * - `defaultPersonNameFactory()`: one caching factory over the committed `names.txt`,\n * made on first use; `personName` and `personNameFromIcao` are its shorthands.\n *\n * A factory's options are fixed when it is made. Nothing here is mutable module\n * state, so a factory built for a test, a fixture lexicon or a different aside\n * policy can never change what another factory answers or poison its memo.\n */\n\nimport type { DisplayLexicon } from \"../lexicon/display.ts\";\nimport { Lexicon } from \"../lexicon/index.ts\";\nimport { lexiconKey } from \"../lexicon/keys.ts\";\nimport { NAME_REFUSED, type ParentheticalHandler } from \"./name-scrub.ts\";\nimport type { NameOrder } from \"./name-split.ts\";\nimport {\n\ttype BuildContext,\n\tNAME_TRADITIONS,\n\ttype NameTradition,\n\ttype NameTraditionLookup,\n\ttype PersonName as PersonNameShape,\n\tbuildFromIcao,\n\tbuildPersonName,\n\tgivenAbbreviates,\n\tgivenKeyAbbreviates,\n\tisIcaoName,\n\tlevelOf,\n\ttraditionFromIndex,\n} from \"./person-name.ts\";\n\n/**\n * One printed person's name, parsed. Made only by a `PersonNameFactory`.\n *\n * Read the levels (`nn0`–`nn4`, see `docs/NAME-NORMALIZATION.md`), the parts\n * (`surname`, `given`, `suffixes`), and ask it what it is (`isPerson()`,\n * `isTeam()`). Persist a level string (`nn2`, or `nn3` as a key), never the\n * object; read `nn2` back with `factory.fromIcao`.\n */\nexport type PersonName = PersonNameShape;\n\n/** The functions that go with a `PersonName` but are not asked of one. */\nexport const PersonName = {\n\t/** Will `fromIcao` read this string, or throw on it? */\n\tisIcao: isIcaoName,\n\t/** One transitive level off a parsed name, by name. */\n\tlevelOf,\n\t/** Is the given key `poorer` an abbreviation of `fuller`? */\n\tgivenKeyAbbreviates,\n\t/** Is `poorer`'s given name `fuller`'s made poorer, the suffixes set aside? */\n\tgivenAbbreviates,\n\t/** The value every level from NN2 down holds for a refused cell. */\n\tREFUSED: NAME_REFUSED,\n\t/** The six traditions, each under its letter and its names.txt index. */\n\tTRADITIONS: NAME_TRADITIONS,\n\t/** A names.txt tradition index → its letter. */\n\ttraditionFromIndex,\n} as const;\n\nexport interface PersonNameFactoryOptions {\n\t/**\n\t * The spellings NN2 consults before its rules. Default: the committed\n\t * `names.txt`. A `Lexicon` also supplies the default `traditions`. `null`:\n\t * rules only.\n\t */\n\treadonly lexicon?: Lexicon | DisplayLexicon | null;\n\t/**\n\t * A root's tradition where its particles do not settle it. Default: read from\n\t * the lexicon's digit flags when `lexicon` is a `Lexicon` (or defaulted),\n\t * otherwise none. `null`: none.\n\t */\n\treadonly traditions?: NameTraditionLookup | null;\n\t/** What an aside in `( … )` or `\" … \"` means. Default: strip every aside. */\n\treadonly parenthetical?: ParentheticalHandler;\n}\n\nexport interface CachingPersonNameFactoryOptions extends PersonNameFactoryOptions {\n\t/**\n\t * How many `(print, order)` parses to hold. Default\n\t * `DEFAULT_PERSON_NAME_CAPACITY`. `0` holds none, which is how a test shows\n\t * the memo changes no answer. Past capacity the oldest entry is evicted.\n\t */\n\treadonly capacity?: number;\n}\n\nexport interface PersonNameFactory {\n\t/** The parse of one printed cell. Total: a cell that is no name is refused, not thrown. */\n\tparse(print: string, order?: NameOrder): PersonName;\n\t/**\n\t * A stored ICAO key (`Surname<<Given<Middle`, an `nn2`) read back. Throws\n\t * where `PersonName.isIcao` says no. `print`, where known, becomes `nn0`.\n\t */\n\tfromIcao(icao: string, print?: string): PersonName;\n\t/** The options it was made with, as given. */\n\treadonly options: Readonly<PersonNameFactoryOptions>;\n}\n\nexport interface PersonNameCacheStats {\n\treadonly hits: number;\n\treadonly misses: number;\n\treadonly evictions: number;\n\treadonly size: number;\n\treadonly capacity: number;\n}\n\nexport interface CachingPersonNameFactory extends PersonNameFactory {\n\tstats(): PersonNameCacheStats;\n\t/** Empty the memo and zero the counters. */\n\tclear(): void;\n}\n\n/**\n * The default capacity. Above the distinct `(print, order)` pairs of a large\n * results corpus (~194k over 5.2M rows), so a full pass evicts nothing. A power\n * of two only because `Map` growth is happier that way.\n *\n * Memory, measured on 166,210 real names: ~1 KB retained per entry.\n */\nexport const DEFAULT_PERSON_NAME_CAPACITY = 262_144;\n\n/** Joins the order to the print with a character no print carries. */\nconst MEMO_SEPARATOR = \"\\u0000\";\n\n/**\n * The tradition lookup a lexicon's digit flags spell, keyed by `lexiconKey`.\n * A key whose entries carry two different traditions answers nothing.\n */\nexport function traditionLookupOf(lexicon: Lexicon): NameTraditionLookup {\n\tconst table = new Map<string, NameTradition | null>();\n\tfor (const { name, flags } of lexicon.entries) {\n\t\tlet t: NameTradition | undefined;\n\t\tfor (const ch of flags) {\n\t\t\tt = traditionFromIndex(ch);\n\t\t\tif (t !== undefined) break;\n\t\t}\n\t\tif (t === undefined) continue;\n\t\tconst key = lexiconKey(name);\n\t\tif (key === \"\") continue;\n\t\tconst was = table.get(key);\n\t\ttable.set(key, was === undefined || was === t ? t : null);\n\t}\n\treturn (key) => table.get(key) ?? undefined;\n}\n\nfunction contextOf(options: PersonNameFactoryOptions): BuildContext {\n\tconst lex = options.lexicon === undefined ? Lexicon.default() : (options.lexicon ?? undefined);\n\tconst lexicon = lex instanceof Lexicon ? lex.displayLexicon() : lex;\n\tconst traditions =\n\t\toptions.traditions === undefined\n\t\t\t? lex instanceof Lexicon\n\t\t\t\t? traditionLookupOf(lex)\n\t\t\t\t: undefined\n\t\t\t: (options.traditions ?? undefined);\n\treturn { lexicon, traditions, parenthetical: options.parenthetical };\n}\n\n/** A factory that parses every call. */\nexport function createPersonNameFactory(options: PersonNameFactoryOptions = {}): PersonNameFactory {\n\tconst ctx = contextOf(options);\n\treturn {\n\t\tparse: (print, order = \"unknown\") => buildPersonName(ctx, print, order),\n\t\tfromIcao: (icao, print) => buildFromIcao(ctx, icao, print),\n\t\toptions,\n\t};\n}\n\n/**\n * A factory that memoizes `parse` on `(print, order)`, which with its fixed\n * options is everything a parse reads. The same pair answers the same object.\n */\nexport function createCachingPersonNameFactory(\n\toptions: CachingPersonNameFactoryOptions = {},\n): CachingPersonNameFactory {\n\tconst ctx = contextOf(options);\n\tconst capacity = options.capacity ?? DEFAULT_PERSON_NAME_CAPACITY;\n\tconst cache = new Map<string, PersonName>();\n\tlet hits = 0;\n\tlet misses = 0;\n\tlet evictions = 0;\n\treturn {\n\t\tparse(print, order = \"unknown\") {\n\t\t\tconst key = `${order}${MEMO_SEPARATOR}${print}`;\n\t\t\tconst hit = cache.get(key);\n\t\t\tif (hit !== undefined) {\n\t\t\t\thits++;\n\t\t\t\treturn hit;\n\t\t\t}\n\t\t\tmisses++;\n\t\t\tconst built = buildPersonName(ctx, print, order);\n\t\t\tif (capacity > 0) {\n\t\t\t\t// INSERTION ORDER IS THE EVICTION ORDER: `Map`'s own iteration order,\n\t\t\t\t// so the policy needs no second structure.\n\t\t\t\tif (cache.size >= capacity) {\n\t\t\t\t\tconst oldest = cache.keys().next();\n\t\t\t\t\tif (!oldest.done) {\n\t\t\t\t\t\tcache.delete(oldest.value);\n\t\t\t\t\t\tevictions++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcache.set(key, built);\n\t\t\t}\n\t\t\treturn built;\n\t\t},\n\t\tfromIcao: (icao, print) => buildFromIcao(ctx, icao, print),\n\t\toptions,\n\t\tstats: () => ({ hits, misses, evictions, size: cache.size, capacity }),\n\t\tclear() {\n\t\t\tcache.clear();\n\t\t\thits = 0;\n\t\t\tmisses = 0;\n\t\t\tevictions = 0;\n\t\t},\n\t};\n}\n\nlet theDefault: CachingPersonNameFactory | undefined;\n\n/**\n * The shared caching factory over the committed `names.txt`, with default\n * options. Made on first call; the lexicon is parsed then, not at import.\n */\nexport function defaultPersonNameFactory(): CachingPersonNameFactory {\n\ttheDefault ??= createCachingPersonNameFactory();\n\treturn theDefault;\n}\n\n/** `defaultPersonNameFactory().parse(print, order)`. */\nexport function personName(print: string, order: NameOrder = \"unknown\"): PersonName {\n\treturn defaultPersonNameFactory().parse(print, order);\n}\n\n/** `defaultPersonNameFactory().fromIcao(icao, print)`. */\nexport function personNameFromIcao(icao: string, print?: string): PersonName {\n\treturn defaultPersonNameFactory().fromIcao(icao, print);\n}\n"
15
15
  ],
16
- "mappings": "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",
17
- "debugId": "49F5F13DC88ECCC664756E2164756E21",
16
+ "mappings": "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",
17
+ "debugId": "17771FA89E876DFF64756E2164756E21",
18
18
  "names": []
19
19
  }
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  lexiconNameOrder,
7
7
  defaultPersonNameFactory2
8
- } from "./index-khxa4qjy.js";
8
+ } from "./index-yf904dam.js";
9
9
  import {
10
10
  isNameParticle2
11
11
  } from "./index-23rzmwe2.js";
@@ -134,4 +134,4 @@ function createNameCensus2(options = {}) {
134
134
  export { createNameCensus2 };
135
135
 
136
136
  //# debugId=42B6EBFD51EC241764756E2164756E21
137
- //# sourceMappingURL=index-yq8hsd1f.js.map
137
+ //# sourceMappingURL=index-ztpxgcs1.js.map
@@ -2,8 +2,8 @@
2
2
  import"../chunks/index-7vvt5hhy.js";
3
3
  import {
4
4
  createNameCensus2
5
- } from "../chunks/index-yq8hsd1f.js";
6
- import"../chunks/index-khxa4qjy.js";
5
+ } from "../chunks/index-ztpxgcs1.js";
6
+ import"../chunks/index-yf904dam.js";
7
7
  import { createRequire } from "node:module";
8
8
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
9
9
 
package/dist/index.js CHANGED
@@ -85,7 +85,7 @@ import {
85
85
  readNameCell2,
86
86
  DEFAULT_NAME_FORMAT_THRESHOLD2,
87
87
  deriveNameFormat2
88
- } from "./chunks/index-7sppf1vh.js";
88
+ } from "./chunks/index-vqbvesky.js";
89
89
  import"./chunks/index-qsznkk4s.js";
90
90
  import {
91
91
  composeEvalSet2,
@@ -97,7 +97,7 @@ import {
97
97
  } from "./chunks/index-ebebeamh.js";
98
98
  import {
99
99
  createNameCensus2
100
- } from "./chunks/index-yq8hsd1f.js";
100
+ } from "./chunks/index-ztpxgcs1.js";
101
101
  import {
102
102
  NAME_REFUSED2,
103
103
  stripEveryAside2,
@@ -108,6 +108,7 @@ import {
108
108
  nameFold2,
109
109
  PLATFORM_PLACEHOLDERS2,
110
110
  NAME_PLACEHOLDERS2,
111
+ placeholderOf2,
111
112
  isPlaceholderPrint2,
112
113
  isNoNamePrint2,
113
114
  COMPOUND_SURNAMES2,
@@ -141,7 +142,7 @@ import {
141
142
  defaultPersonNameFactory2,
142
143
  personName2,
143
144
  personNameFromIcao2
144
- } from "./chunks/index-khxa4qjy.js";
145
+ } from "./chunks/index-yf904dam.js";
145
146
  import {
146
147
  TEAM_WORD2,
147
148
  TEAM_DESIGNATION_WORDS2,
@@ -281,6 +282,7 @@ export {
281
282
  personName2 as personName,
282
283
  personNameFromIcao2 as personNameFromIcao,
283
284
  phraseClassifier2 as phraseClassifier,
285
+ placeholderOf2 as placeholderOf,
284
286
  printAttestsOrder2 as printAttestsOrder,
285
287
  probablySame2 as probablySame,
286
288
  readNameCell2 as readNameCell,
@@ -308,5 +310,5 @@ export {
308
310
  traditionOf2 as traditionOf
309
311
  };
310
312
 
311
- //# debugId=168C2BEC179E7C6664756E2164756E21
313
+ //# debugId=1FD95C1969276FF164756E2164756E21
312
314
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "168C2BEC179E7C6664756E2164756E21",
7
+ "debugId": "1FD95C1969276FF164756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -4,8 +4,8 @@ import {
4
4
  } from "../chunks/index-pncn9y2r.js";
5
5
  import {
6
6
  createNameCensus2
7
- } from "../chunks/index-yq8hsd1f.js";
8
- import"../chunks/index-khxa4qjy.js";
7
+ } from "../chunks/index-ztpxgcs1.js";
8
+ import"../chunks/index-yf904dam.js";
9
9
  import"../chunks/index-7vvt5hhy.js";
10
10
  export {
11
11
  composeEvalSet2 as composeEvalSet,
@@ -44,7 +44,7 @@ import {
44
44
  readNameCell2,
45
45
  DEFAULT_NAME_FORMAT_THRESHOLD2,
46
46
  deriveNameFormat2
47
- } from "../chunks/index-7sppf1vh.js";
47
+ } from "../chunks/index-vqbvesky.js";
48
48
  import"../chunks/index-kw6gbrnq.js";
49
49
  import {
50
50
  NAME_REFUSED2,
@@ -56,6 +56,7 @@ import {
56
56
  nameFold2,
57
57
  PLATFORM_PLACEHOLDERS2,
58
58
  NAME_PLACEHOLDERS2,
59
+ placeholderOf2,
59
60
  isPlaceholderPrint2,
60
61
  isNoNamePrint2,
61
62
  COMPOUND_SURNAMES2,
@@ -89,7 +90,7 @@ import {
89
90
  defaultPersonNameFactory2,
90
91
  personName2,
91
92
  personNameFromIcao2
92
- } from "../chunks/index-khxa4qjy.js";
93
+ } from "../chunks/index-yf904dam.js";
93
94
  import {
94
95
  TEAM_WORD2,
95
96
  TEAM_DESIGNATION_WORDS2,
@@ -177,6 +178,7 @@ export {
177
178
  personList2 as personList,
178
179
  personName2 as personName,
179
180
  personNameFromIcao2 as personNameFromIcao,
181
+ placeholderOf2 as placeholderOf,
180
182
  printAttestsOrder2 as printAttestsOrder,
181
183
  probablySame2 as probablySame,
182
184
  readNameCell2 as readNameCell,
@@ -202,5 +204,5 @@ export {
202
204
  traditionLookupOf2 as traditionLookupOf
203
205
  };
204
206
 
205
- //# debugId=F6630C203D8EAD8B64756E2164756E21
207
+ //# debugId=5FE4459EB5725BDA64756E2164756E21
206
208
  //# sourceMappingURL=index.js.map
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "F6630C203D8EAD8B64756E2164756E21",
7
+ "debugId": "5FE4459EB5725BDA64756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -11,7 +11,7 @@ export { type Level, NAME_TRADITIONS, type NamePart, type NameTradition, type Na
11
11
  export { NAME_REFUSED, type ParentheticalHandler, type ScrubOptions, type ScrubResult, type ScrubRule, scrubName, scrubNameDetail, stripEveryAside, stripTrailingCredentials, } from "./name-scrub.ts";
12
12
  export { repairMojibake } from "./name-mojibake.ts";
13
13
  export { type CellVerdict, type NameRefusalRule, type Refusal, classifyCell, } from "./cell-verdict.ts";
14
- export { NAME_PLACEHOLDERS, type NamePlaceholder, PLATFORM_PLACEHOLDERS, isNoNamePrint, isPlaceholderPrint, } from "./name-placeholder.ts";
14
+ export { NAME_PLACEHOLDERS, type NamePlaceholder, PLATFORM_PLACEHOLDERS, isNoNamePrint, isPlaceholderPrint, placeholderOf, } from "./name-placeholder.ts";
15
15
  export { capitalise, nameCase, type SpellingLookup } from "./name-case.ts";
16
16
  export { type DisplayLexicon, GIVEN_SEPARATOR, type PersonNameParts, SURNAME_SEPARATOR, formatPersonDisplay, lexiconKey, parsePersonName, personDisplayName, spellingLookup, titleCaseNamePart, } from "./person-display.ts";
17
17
  export { type CommaReading, type NameOrder, type NameSplit, type ResolvedNameOrder, commaReading, inferNameOrder, resolveNameOrder, spaceAfterComma, splitPersonName, } from "./name-split.ts";
@@ -8,8 +8,8 @@
8
8
  * (`^[^\p{L}]*$`, any Unicode letter, so a name written in a non-Latin script is a
9
9
  * name);
10
10
  * 2. it is a platform sentinel a row's name cell and school cell share (`N/A`, `TBA`,
11
- * `Unknown`, `None`): `PLATFORM_PLACEHOLDERS`, asked through `isPlaceholderPrint`, ONE
12
- * list for both cells so they cannot drift apart;
11
+ * `Unknown`, `None`, `No School`, `Independent`): `PLATFORM_PLACEHOLDERS`, asked through
12
+ * `isPlaceholderPrint`, ONE list for both cells so they cannot drift apart;
13
13
  * 3. it is one of `NAME_PLACEHOLDERS`: the sentinels only a NAME cell prints, each with
14
14
  * where it was measured.
15
15
  *
@@ -26,15 +26,24 @@ export interface NamePlaceholder {
26
26
  readonly print: string;
27
27
  /** where it was seen, so a reviewer can audit the row */
28
28
  readonly authority: string;
29
+ /**
30
+ * `prefix`: the folded print STARTS with this row's words, for an entry form's instruction
31
+ * that runs on (`NO SCHOOL SELECTED - Please change your profile`). Whole words only.
32
+ * Absent: the folded print is exactly this row.
33
+ */
34
+ readonly match?: "prefix";
29
35
  }
30
36
  /**
31
- * THE SHARED SENTINELS: what an entry platform writes where nothing was entered, in a name cell
32
- * or a school cell alike. A school reader asks `isPlaceholderPrint` of its cell, so `N/A` is
33
- * refused on both sides of a row by this one list. A sentinel worded about a school
34
- * (`No School`, `-- Choose One --`) is a school-cell fact and stays with the school reader.
37
+ * THE SHARED SENTINELS: what an entry platform writes where nothing was entered or chosen, in a
38
+ * name cell or a school cell alike. A school reader asks `isPlaceholderPrint` of its cell, so
39
+ * `N/A`, `No School` and `Independent` are refused on both sides of a row by this one list. A
40
+ * sentinel worded about a school is still no name when a name cell prints it, so it is here
41
+ * too and not in a second list. Ordinary prints that merely CONTAIN one of these words are
42
+ * not placeholders: a row matches the whole folded print, or its leading words for `prefix`.
35
43
  *
36
- * Measured 2026-10-01 over every stream of the results corpus (3,776,915 rows): rows per
37
- * cell, matched on the fold.
44
+ * The first five were measured 2026-10-01 over every stream of the results corpus (3,776,915
45
+ * rows), the rest 2026-10-05 over the same corpus (3,586,702 rows): rows per cell, matched on
46
+ * the fold. A row with 0 rows is an entry form's option seen only as a form label.
38
47
  */
39
48
  export declare const PLATFORM_PLACEHOLDERS: readonly NamePlaceholder[];
40
49
  /**
@@ -43,9 +52,15 @@ export declare const PLATFORM_PLACEHOLDERS: readonly NamePlaceholder[];
43
52
  * every stream of the results corpus (3,776,915 rows).
44
53
  */
45
54
  export declare const NAME_PLACEHOLDERS: readonly NamePlaceholder[];
55
+ /**
56
+ * The PLATFORM_PLACEHOLDERS row this print is, or `undefined`. For a reader that records
57
+ * which sentinel refused a cell; `isPlaceholderPrint` is the yes/no.
58
+ */
59
+ export declare function placeholderOf(print: string): NamePlaceholder | undefined;
46
60
  /**
47
61
  * Is this print one of the PLATFORM PLACEHOLDERS a name cell and a school cell share
48
- * (`N/A`, `TBA`, `Unknown`, `None`)? The question a school reader asks of its cell.
62
+ * (`N/A`, `TBA`, `Unknown`, `None`, `No School`, `Independent`)? The question a school reader
63
+ * asks of its cell.
49
64
  */
50
65
  export declare function isPlaceholderPrint(print: string): boolean;
51
66
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finbheara/names",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "A curated lexicon of personal, school and place names, the surname-particle vocabulary, a phrase classifier and a person-name normalizer",
5
5
  "keywords": [
6
6
  "names",