@finbheara/names 0.14.0 → 0.16.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.
Files changed (37) hide show
  1. package/README.md +12 -6
  2. package/data/bloom/MANIFEST.json +59 -13
  3. package/dist/chunks/{index-7vvt5hhy.js → index-0wpvbdgh.js} +2631 -1395
  4. package/dist/chunks/{index-7vvt5hhy.js.map → index-0wpvbdgh.js.map} +4 -4
  5. package/dist/chunks/{index-kw69ry3j.js → index-74fyytnh.js} +1333 -20
  6. package/dist/chunks/{index-kw69ry3j.js.map → index-74fyytnh.js.map} +5 -4
  7. package/dist/chunks/{index-pncn9y2r.js → index-a6f2y4aa.js} +2 -2
  8. package/dist/chunks/{index-r5fp3znj.js → index-ky754nsf.js} +7 -7
  9. package/dist/chunks/{index-r5fp3znj.js.map → index-ky754nsf.js.map} +3 -3
  10. package/dist/chunks/{index-ka8nzreg.js → index-tk01chxw.js} +2 -2
  11. package/dist/chunks/{index-kw6gbrnq.js → index-tqdbxd92.js} +2 -2
  12. package/dist/chunks/{index-a15g2gp6.js → index-ye6j60jn.js} +3 -3
  13. package/dist/chunks/phrase-2hj26asc.js +11 -0
  14. package/dist/classifier/index.js +3 -3
  15. package/dist/cli/census.js +4 -4
  16. package/dist/index.js +14 -8
  17. package/dist/index.js.map +1 -1
  18. package/dist/lexicon/index.js +4 -2
  19. package/dist/lexicon/index.js.map +1 -1
  20. package/dist/measure/index.js +4 -4
  21. package/dist/normalize/index.js +9 -5
  22. package/dist/normalize/index.js.map +1 -1
  23. package/dist/types/classifier/bf/filters.d.ts +8 -3
  24. package/dist/types/lexicon/flags.d.ts +13 -5
  25. package/dist/types/normalize/given-families.d.ts +48 -0
  26. package/dist/types/normalize/index.d.ts +1 -0
  27. package/dist/types/normalize/name-kinship.d.ts +12 -8
  28. package/docs/NAME-NORMALIZATION.md +36 -7
  29. package/names.txt +2624 -1389
  30. package/package.json +4 -2
  31. package/src/normalize/given-families.MANIFEST.json +46 -0
  32. package/dist/chunks/phrase-672g18kw.js +0 -11
  33. /package/dist/chunks/{index-pncn9y2r.js.map → index-a6f2y4aa.js.map} +0 -0
  34. /package/dist/chunks/{index-ka8nzreg.js.map → index-tk01chxw.js.map} +0 -0
  35. /package/dist/chunks/{index-kw6gbrnq.js.map → index-tqdbxd92.js.map} +0 -0
  36. /package/dist/chunks/{index-a15g2gp6.js.map → index-ye6j60jn.js.map} +0 -0
  37. /package/dist/chunks/{phrase-672g18kw.js.map → phrase-2hj26asc.js.map} +0 -0
@@ -2,6 +2,8 @@ import {
2
2
  repairMojibake2,
3
3
  sameGivenFamily2,
4
4
  givenFamilyTable2,
5
+ createGivenFamilyList2,
6
+ givenFamilyList2,
5
7
  comparePosition2,
6
8
  nameRelation2,
7
9
  MAX_READINGS2,
@@ -49,8 +51,8 @@ import {
49
51
  readNameCell2,
50
52
  DEFAULT_NAME_FORMAT_THRESHOLD2,
51
53
  deriveNameFormat2
52
- } from "../chunks/index-kw69ry3j.js";
53
- import"../chunks/index-kw6gbrnq.js";
54
+ } from "../chunks/index-74fyytnh.js";
55
+ import"../chunks/index-tqdbxd92.js";
54
56
  import {
55
57
  NAME_REFUSED2,
56
58
  stripEveryAside2,
@@ -95,7 +97,7 @@ import {
95
97
  defaultPersonNameFactory2,
96
98
  personName2,
97
99
  personNameFromIcao2
98
- } from "../chunks/index-ka8nzreg.js";
100
+ } from "../chunks/index-tk01chxw.js";
99
101
  import {
100
102
  TEAM_WORD2,
101
103
  TEAM_DESIGNATION_WORDS2,
@@ -108,7 +110,7 @@ import {
108
110
  } from "../chunks/index-0phgwy52.js";
109
111
  import {
110
112
  lexiconKey2
111
- } from "../chunks/index-7vvt5hhy.js";
113
+ } from "../chunks/index-0wpvbdgh.js";
112
114
  export {
113
115
  COMPOUND_SURNAMES2 as COMPOUND_SURNAMES,
114
116
  DEFAULT_NAME_FORMAT_THRESHOLD2 as DEFAULT_NAME_FORMAT_THRESHOLD,
@@ -140,6 +142,7 @@ export {
140
142
  composeReadings2 as composeReadings,
141
143
  compoundGiven2 as compoundGiven,
142
144
  createCachingPersonNameFactory2 as createCachingPersonNameFactory,
145
+ createGivenFamilyList2 as createGivenFamilyList,
143
146
  createNameClusters2 as createNameClusters,
144
147
  createNameIndex2 as createNameIndex,
145
148
  createNameKinship2 as createNameKinship,
@@ -152,6 +155,7 @@ export {
152
155
  foldNameKey2 as foldNameKey,
153
156
  formatPersonDisplay2 as formatPersonDisplay,
154
157
  givenAbbreviates2 as givenAbbreviates,
158
+ givenFamilyList2 as givenFamilyList,
155
159
  givenFamilyTable2 as givenFamilyTable,
156
160
  givenKeyAbbreviates2 as givenKeyAbbreviates,
157
161
  infeasibleClass2 as infeasibleClass,
@@ -214,5 +218,5 @@ export {
214
218
  traditionLookupOf2 as traditionLookupOf
215
219
  };
216
220
 
217
- //# debugId=6CAF39AD5BAB8B2064756E2164756E21
221
+ //# debugId=9549507E34EB444A64756E2164756E21
218
222
  //# sourceMappingURL=index.js.map
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "6CAF39AD5BAB8B2064756E2164756E21",
7
+ "debugId": "9549507E34EB444A64756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -1,10 +1,15 @@
1
1
  /**
2
2
  * Bloom filters for name classification
3
- * Generated: 2026-01-03T00:32:31.659Z
3
+ * Built by scripts/build-blooms.ts from the source lists recorded in
4
+ * data/bloom/MANIFEST.json, which also holds each table's item count.
4
5
  * Target FPP: 0.01
5
- * Total items: 484,270
6
- * Total bits: 4,641,758 (566.6 KB)
7
6
  */
7
+ /**
8
+ * The key a name table holds and is asked: lower-cased, NFD, combining marks dropped,
9
+ * the ASCII apostrophe dropped. `scripts/build-blooms.ts` builds the tables with it, so
10
+ * a lookup and a build cannot disagree.
11
+ */
12
+ export declare function normalize(s: string): string;
8
13
  /** Check if word is a known surname (151k entries) */
9
14
  export declare function isSurname(word: string): boolean;
10
15
  /** Check if word is in the human names list (197k first+last names) */
@@ -2,19 +2,22 @@
2
2
  * The flag alphabet, typed, and the predicates over one entry's flag string.
3
3
  *
4
4
  * FLAGS ARE CASE-SENSITIVE. Upper case classifies; a digit is a tradition
5
- * footnote. `S` and `X` are marks that classify nothing.
5
+ * footnote. `S`, `X` and `D` are marks that classify nothing.
6
6
  *
7
7
  * A FLAGLESS ENTRY IS A FEMALE GIVEN NAME. The header says so outright, so every
8
8
  * predicate here reads `""` (or a string with no class letter) as `F`.
9
9
  */
10
10
  /** The classification namespace: what KIND of thing the entry is. */
11
11
  export declare const CLASS_FLAGS: "FMNLAGTCB";
12
- /** Marks: `S` a typo kept on purpose, `X` excluded from the renderer round trip. */
13
- export declare const MARK_FLAGS: "SX";
12
+ /**
13
+ * Marks: `S` a typo kept on purpose, `X` excluded from the renderer round trip, `D` a given
14
+ * name in a diminutive table (`given-diminutives.json` or `given-families.json`).
15
+ */
16
+ export declare const MARK_FLAGS: "SXD";
14
17
  /** Every letter the file issues. */
15
- export declare const CLASSIFICATION_FLAGS: "FMNLATGCBSX";
18
+ export declare const CLASSIFICATION_FLAGS: "FMNLATGCBSXD";
16
19
  export type ClassFlag = "F" | "M" | "N" | "L" | "A" | "G" | "T" | "C" | "B";
17
- export type MarkFlag = "S" | "X";
20
+ export type MarkFlag = "S" | "X" | "D";
18
21
  export type Flag = ClassFlag | MarkFlag;
19
22
  /**
20
23
  * The tradition namespace: a FOOTNOTE INDEX naming which onomastic tradition
@@ -53,6 +56,11 @@ export declare const isMultiWord: (flags: string) => boolean;
53
56
  export declare const isSuspicious: (flags: string) => boolean;
54
57
  /** `X`: excluded from the renderer round trip. */
55
58
  export declare const isRoundTripException: (flags: string) => boolean;
59
+ /**
60
+ * `D`: a given name that a diminutive table holds, as a root, a form or a spelling. It says
61
+ * the tables know the name; which names it relates to is the tables' answer, never the flag's.
62
+ */
63
+ export declare const isInDiminutiveTable: (flags: string) => boolean;
56
64
  /**
57
65
  * Any person class: `F`, `M`, `N`, `L` or `A`. An entry with no class at all is
58
66
  * a female given name and so a person.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * given-families.ts — THE EXTENDED GIVEN-NAME FAMILY LIST, read by the TypeScript side.
3
+ *
4
+ * `./given-families.json` is the list and this file is its reader; `scripts/given-families.ts`
5
+ * builds the list and `./given-families.MANIFEST.json` records its sources.
6
+ *
7
+ * TWO TIERS OF GIVEN-NAME KNOWLEDGE. `./given-diminutives.json` is the GATE tier: pairs this
8
+ * package is sure of, curated by hand, some of them admitted at an identity gate. This list
9
+ * is the EXTENDED tier: every family the sources record for English, Irish, Scottish, Welsh,
10
+ * French, Italian, Spanish, German, Dutch and Polish usage, about 2,600 names. A pair it
11
+ * relates MAY be one name, and the answer is `given-maybe`, which no gate admits.
12
+ *
13
+ * AN EXACT LIST, NOT A FILTER. A bloom filter of the same pairs at 8 KB answers about fifty
14
+ * false partners for every given name it is asked about; the exact list is a few KB more
15
+ * and answers none.
16
+ *
17
+ * A FAMILY IS CLOSED. Two names relate when they are a root and its form, or two forms of
18
+ * one root (`Kate` / `Katie`, both Catherine's). A form under several roots meets each
19
+ * root's family, and nothing is transitive across families: `Kit` meets Catherine's and
20
+ * Christopher's, and `Kate` / `Chris` stay apart.
21
+ *
22
+ * A TIER BOUNDS HOW RARE A FORM MAY BE. Each form carries 1 (common), 2 (uncommon) or 3
23
+ * (rare); a pair's tier is its rarer member's, the root counting as 1, and where two names
24
+ * share several families the commonest counts. `maxTier` admits pairs up to that tier.
25
+ */
26
+ /** How common a form is: 1 common, 2 uncommon, 3 rare. */
27
+ export type GivenFamilyTier = 1 | 2 | 3;
28
+ export interface GivenFamilyListOptions {
29
+ /** The rarest tier admitted. Default 3: every pair the list holds. */
30
+ readonly maxTier?: GivenFamilyTier;
31
+ /**
32
+ * The families, one `ROOT,FORM:TIER,…` line each, NN3 upper case. Default: the shipped
33
+ * `given-families.json`. A caller with its own list passes it here.
34
+ */
35
+ readonly families?: readonly string[];
36
+ }
37
+ /** A given-name provider over the extended list: `given-maybe` or `null`. */
38
+ export type GivenFamilyList = (a: string, b: string) => "given-maybe" | null;
39
+ /**
40
+ * The extended list as a `GivenProvider` for `createNameKinship`: `given-maybe` where two
41
+ * DIFFERENT names (NN3) share a family within `maxTier`, `null` otherwise. Two equal names
42
+ * answer `null`, as `givenFamilyTable`'s do.
43
+ *
44
+ * The list is parsed on the first question, once per provider.
45
+ */
46
+ export declare function createGivenFamilyList(options?: GivenFamilyListOptions): GivenFamilyList;
47
+ /** The shipped list, every tier: the second given-name provider of `nameKinship`. */
48
+ export declare const givenFamilyList: GivenFamilyList;
@@ -19,6 +19,7 @@ export { TEAM_DESIGNATION_WORDS, TEAM_WORD, type TeamSuffixPartition, canonicalT
19
19
  export { foldNameKey, nameFold } from "./name-fold.ts";
20
20
  export { COMPOUND_SURNAMES, isCompoundSurname } from "./compound-surnames.ts";
21
21
  export { givenFamilyTable, sameGivenFamily } from "./given-diminutives.ts";
22
+ export { type GivenFamilyList, type GivenFamilyListOptions, type GivenFamilyTier, createGivenFamilyList, givenFamilyList, } from "./given-families.ts";
22
23
  export { type ClusterLinkage, type Clusters, type NameIndex, type NameIndexOptions, type NameMap, type NameMatch, type NameSet, createNameClusters, createNameIndex, createNameMap, createNameSet, nameCompare, probablySame, } from "./name-compare.ts";
23
24
  export { type NameReading, type NameRelation, type NameRelationReason, comparePosition, nameRelation, } from "./name-middle.ts";
24
25
  export { type GivenProvider, type GivenVia, KINSHIP_VIAS, type KinshipReason, type KinshipVia, type MiddleVia, type MiddleViasAreNn5Reasons, type NameKinship, type NameKinshipOptions, type NameKinshipRelation, createNameKinship, nameKinship, } from "./name-kinship.ts";
@@ -32,14 +32,14 @@
32
32
  * narrower: every tolerance used is one this package's own gate comparators already admit —
33
33
  * a middle name `probablySame(…, "nn5")` admits, a given-name family `sameGivenFamily`
34
34
  * admits, a compound the print itself carries. A table form that is a name in its own right
35
- * (`given-family-not-gate`) or a probabilistic source (`given-maybe`) is a lead for the rest
36
- * of the evidence and never a gate.
35
+ * (`given-family-not-gate`) or the extended family list (`given-maybe`) is a lead for the
36
+ * rest of the evidence and never a gate.
37
37
  *
38
38
  * ## THE GIVEN-NAME TOLERANCE IS INJECTED
39
39
  *
40
- * Which given names are one family is DATA, and the data will move: a probabilistic source
41
- * of diminutive pairs is expected beside the curated table, and the table may shrink. So the
42
- * relation asks an ordered list of `GivenProvider`s fixed by `createNameKinship`'s options,
40
+ * Which given names are one family is DATA, and the data will move: the curated table
41
+ * (`given-diminutives.json`) is the gate tier, the extended family list (`given-families.json`)
42
+ * stands beside it, and either may grow or shrink. So the relation asks an ordered list of `GivenProvider`s fixed by `createNameKinship`'s options,
43
43
  * and the core knows no table. A new provider is an option; a new kind of answer is one
44
44
  * line in `KINSHIP_VIAS`, which also carries its gate-safety, so no branch here changes.
45
45
  *
@@ -79,7 +79,7 @@ export declare const KINSHIP_VIAS: Readonly<{
79
79
  field: "given";
80
80
  gateSafe: false;
81
81
  }>;
82
- /** a probabilistic source says the two MAY be one family; reserved for one */
82
+ /** the extended family list says the two MAY be one family (`./given-families.ts`) */
83
83
  readonly "given-maybe": Readonly<{
84
84
  field: "given";
85
85
  gateSafe: false;
@@ -136,7 +136,8 @@ export type GivenProvider = (a: string, b: string) => GivenVia | null;
136
136
  export interface NameKinshipOptions {
137
137
  /**
138
138
  * The given-name tolerances, asked in order; THE FIRST NON-NULL ANSWER WINS, so a caller
139
- * lists its most trusted source first. Default `[givenFamilyTable]`; `[]` tolerates no
139
+ * lists its most trusted source first. Default `[givenFamilyTable, givenFamilyList]`: the
140
+ * curated table, then the extended list for what the table does not relate. `[]` tolerates no
140
141
  * given name.
141
142
  */
142
143
  readonly given?: readonly GivenProvider[];
@@ -158,7 +159,10 @@ export type NameKinshipRelation = (a: PersonName, b: PersonName) => NameKinship;
158
159
  * | otherwise | `candidate`, via every tolerance used |
159
160
  */
160
161
  export declare function createNameKinship(options?: NameKinshipOptions): NameKinshipRelation;
161
- /** The tolerant relation over the curated given-name table, `givenFamilyTable`. */
162
+ /**
163
+ * The tolerant relation over the curated given-name table, `givenFamilyTable`, then the
164
+ * extended family list, `givenFamilyList`.
165
+ */
162
166
  export declare const nameKinship: NameKinshipRelation;
163
167
  /**
164
168
  * THE MIDDLE VIAS ARE NN5'S CANDIDATE REASONS, ASSERTED IN TYPECHECKED SOURCE. A middle
@@ -471,7 +471,7 @@ interface NameKinship {
471
471
  | `given-variant` | given | yes | the two first given names are two spellings of one name (`Connor` / `Conor`) |
472
472
  | `given-family` | given | yes | a provider says the two first given names are one family, and a gate admits them |
473
473
  | `given-family-not-gate` | given | no | the table relates them only through a `notAtGate` form |
474
- | `given-maybe` | given | no | a probabilistic source says they MAY be one family |
474
+ | `given-maybe` | given | no | the extended family list says they MAY be one family |
475
475
  | `middle-absent` | middle | yes | NN5's: one side carries no middle |
476
476
  | `initial-agrees` | middle | yes | NN5's: an initial against a full middle that starts with it |
477
477
 
@@ -486,9 +486,10 @@ interface NameKinship {
486
486
  - The given-name tolerance is INJECTED: `createNameKinship({ given: [p1, p2, …] })` asks
487
487
  each `GivenProvider` in order and the first non-null answer wins. A provider is asked
488
488
  once per pair, with the two NN3 first given names in code-unit order, and never with two
489
- equal names. The default is `[givenFamilyTable]`, which answers from
490
- `given-diminutives.json`; `sameGivenFamily(a, b)` is exactly "`givenFamilyTable(a, b)` is
491
- `given-variant` or `given-family`". `[]` tolerates no given name.
489
+ equal names. The default is `[givenFamilyTable, givenFamilyList]`: the curated table
490
+ (`given-diminutives.json`) first, then the extended family list (`given-families.json`) for
491
+ a pair the table does not relate. `sameGivenFamily(a, b)` is exactly "`givenFamilyTable(a, b)`
492
+ is `given-variant` or `given-family`". `[]` tolerates no given name.
492
493
  - A new kind of `via` is one entry in `KINSHIP_VIAS`, which carries its field and its
493
494
  gate-safety. The relation's rules do not change.
494
495
  - With no tolerance used, the answer is `nameRelation`'s. `head-differs` is split into
@@ -520,9 +521,37 @@ interface NameKinship {
520
521
  `Kate` and `Katie` are Catherine's, and `Katelyn` is a spelling of Caitlin. They meet below
521
522
  the gate through Caitlin as a form of Catherine, so `Kate` / `Katherine` keeps its gate.
522
523
 
523
- Over the 421 forms and spellings of the table (88,410 distinct pairs), `givenFamilyTable`
524
- answers `given-variant` for 90 pairs, `given-family` for 371, `given-family-not-gate` for 553,
525
- and `null` for the rest; `sameGivenFamily` admits 461.
524
+ Over the 541 roots, forms and spellings of the table (146,070 distinct pairs),
525
+ `givenFamilyTable` answers `given-variant` for 127 pairs, `given-family` for 540,
526
+ `given-family-not-gate` for 725, and `null` for the rest; `sameGivenFamily` admits 667.
527
+
528
+ ### The extended family list
529
+
530
+ The table is the GATE tier: pairs this package is sure of. `given-families.json` is the
531
+ EXTENDED tier: every family its sources record for English, Irish, Scottish, Welsh, French,
532
+ Italian, Spanish, German, Dutch and Polish usage — 1,171 families over 2,613 names, the table's
533
+ own families and spellings among them. `givenFamilyList(a, b)` answers `given-maybe` where two
534
+ names share a family, and `null` otherwise; no gate admits it.
535
+
536
+ - One line per family, `ROOT,FORM:TIER,…`, NN3. A TIER says how common the form is: 1 common,
537
+ 2 uncommon, 3 rare. `createGivenFamilyList({ maxTier })` admits pairs up to that tier; a
538
+ pair's tier is its rarer member's, the root counting as 1, and where two names share several
539
+ families the commonest counts. The default admits every tier.
540
+ - A family is CLOSED: two forms of one root relate (`Kate` / `Katie`), as well as a root and
541
+ its form. Nothing is transitive across families: `Kit` meets Catherine's and Christopher's,
542
+ and `Kate` / `Chris` stay apart.
543
+ - It is an exact list, not a filter. An 8 KB bloom filter of 6,980 such pairs, asked about
544
+ every pair of the 4,730 given names in the 0.14.0 `names.txt`, answered 50.6 false partners
545
+ per name; the list is 11.8 KB gzipped and answers none.
546
+ - `given-families.MANIFEST.json` beside it records the sources, their tiers and the names it
547
+ excludes; `scripts/given-families.ts` rebuilds it from them.
548
+
549
+ Every name either table holds is in `names.txt` as a given name carrying the `D` mark, and
550
+ only those carry it (`test/golden.spec.ts`). A SURNAME STAYS A SURNAME: a name `names.txt`
551
+ holds only as a surname (an `L` entry, none on its key with `F`, `M`, `N` or `A`) is in neither
552
+ table, and every pair through it goes with it (`Ward:LT`, so `Ward` / `Eduard` is not related).
553
+ A genuine given name is made one in `names.txt` first (`Henry:AMD`, read `L` before), and the
554
+ list rebuilt.
526
555
 
527
556
  ### The tolerant lookup
528
557