@mailwoman/record 8.1.0 → 8.2.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.
- package/address.ts +54 -18
- package/name.ts +41 -17
- package/organization.ts +24 -12
- package/out/address.d.ts +54 -18
- package/out/address.d.ts.map +1 -1
- package/out/address.js +3 -1
- package/out/address.js.map +1 -1
- package/out/name.d.ts +24 -8
- package/out/name.d.ts.map +1 -1
- package/out/name.js +13 -9
- package/out/name.js.map +1 -1
- package/out/organization.d.ts +15 -5
- package/out/organization.d.ts.map +1 -1
- package/out/organization.js +9 -7
- package/out/organization.js.map +1 -1
- package/package.json +2 -2
package/address.ts
CHANGED
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
import { type ComponentDict, type FormatAddressOptions, canonicalKey, formatAddress } from "@mailwoman/formatter"
|
|
21
21
|
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* A geographic coordinate (WGS84 decimal degrees).
|
|
24
|
+
*/
|
|
23
25
|
export interface GeoCoordinate {
|
|
24
26
|
latitude: number
|
|
25
27
|
longitude: number
|
|
@@ -33,24 +35,36 @@ export interface GeoCoordinate {
|
|
|
33
35
|
*/
|
|
34
36
|
export type ResolutionTier = "address_point" | "interpolated" | "street" | "admin"
|
|
35
37
|
|
|
36
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* One resolved admin-hierarchy ancestor (most specific first), for spelling-invariant blocking.
|
|
40
|
+
*/
|
|
37
41
|
export interface HierarchyNode {
|
|
38
42
|
tag: string
|
|
39
43
|
value: string
|
|
40
44
|
placeID?: string
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* A resolved geocode attached to an address record — the location signal the matcher scores on.
|
|
49
|
+
*/
|
|
44
50
|
export interface AddressGeocode {
|
|
45
51
|
coordinate: GeoCoordinate
|
|
46
52
|
tier: ResolutionTier
|
|
47
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Calibrated uncertainty radius in meters; `null` for the admin tier (no sub-locality estimate).
|
|
55
|
+
*/
|
|
48
56
|
uncertaintyMeters: number | null
|
|
49
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Resolved admin hierarchy, locality → country (most specific first).
|
|
59
|
+
*/
|
|
50
60
|
hierarchy?: HierarchyNode[]
|
|
51
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* A delivery point, not a building — weakens location agreement even at a precise coordinate.
|
|
63
|
+
*/
|
|
52
64
|
poBox?: boolean
|
|
53
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* A multi-unit building where many records share one coordinate — weakens unit-level agreement.
|
|
67
|
+
*/
|
|
54
68
|
multiUnit?: boolean
|
|
55
69
|
}
|
|
56
70
|
|
|
@@ -59,27 +73,47 @@ export interface AddressGeocode {
|
|
|
59
73
|
* form, and an optional resolved geocode. Plain data — no behavior.
|
|
60
74
|
*/
|
|
61
75
|
export interface PostalAddress {
|
|
62
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Parsed address components (`ComponentTag`-keyed).
|
|
78
|
+
*/
|
|
63
79
|
components: ComponentDict
|
|
64
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Normalized, deterministic match key for blocking (from `@mailwoman/formatter`).
|
|
82
|
+
*/
|
|
65
83
|
canonicalKey: string
|
|
66
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Optional human-readable single-line form, for display.
|
|
86
|
+
*/
|
|
67
87
|
formatted?: string
|
|
68
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Resolved location, when geocoded.
|
|
90
|
+
*/
|
|
69
91
|
geocode?: AddressGeocode
|
|
70
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* The original free-text input, when known (provenance).
|
|
94
|
+
*/
|
|
71
95
|
raw?: string
|
|
72
96
|
}
|
|
73
97
|
|
|
74
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* Options for {@linkcode toPostalAddress}.
|
|
100
|
+
*/
|
|
75
101
|
export interface ToPostalAddressOptions {
|
|
76
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Country (ISO-2 or name) for formatting. Defaults to the `country` component, else unset.
|
|
104
|
+
*/
|
|
77
105
|
country?: string
|
|
78
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* The original free-text input to retain as provenance.
|
|
108
|
+
*/
|
|
79
109
|
raw?: string
|
|
80
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Also compute a human-readable `formatted` string. Default `true`.
|
|
112
|
+
*/
|
|
81
113
|
format?: boolean
|
|
82
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Formatting options forwarded to the formatter. Defaults to single-line (`", "`).
|
|
116
|
+
*/
|
|
83
117
|
formatOptions?: FormatAddressOptions
|
|
84
118
|
}
|
|
85
119
|
|
|
@@ -110,7 +144,9 @@ export function toPostalAddress(components: ComponentDict, opts: ToPostalAddress
|
|
|
110
144
|
return record
|
|
111
145
|
}
|
|
112
146
|
|
|
113
|
-
/**
|
|
147
|
+
/**
|
|
148
|
+
* Attach (or replace) a resolved geocode on an address record, returning a new record.
|
|
149
|
+
*/
|
|
114
150
|
export function withGeocode(record: PostalAddress, geocode: AddressGeocode): PostalAddress {
|
|
115
151
|
return { ...record, geocode }
|
|
116
152
|
}
|
package/name.ts
CHANGED
|
@@ -25,25 +25,43 @@
|
|
|
25
25
|
* professional suffixes) without a model.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* A parsed person name. All fields optional — the parser fills what it can identify.
|
|
30
|
+
*/
|
|
29
31
|
export interface PersonName {
|
|
30
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Title / salutation that preceded the name (`Dr`, `Mr`, `Capt`).
|
|
34
|
+
*/
|
|
31
35
|
prefix?: string
|
|
32
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* First / given name.
|
|
38
|
+
*/
|
|
33
39
|
given?: string
|
|
34
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Middle name(s) or initial.
|
|
42
|
+
*/
|
|
35
43
|
middle?: string
|
|
36
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Surname, _without_ any particle (`Vega`, not `de la Vega`).
|
|
46
|
+
*/
|
|
37
47
|
family?: string
|
|
38
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Surname particle, stored separately (`de la`, `van der`, `von`).
|
|
50
|
+
*/
|
|
39
51
|
familyParticle?: string
|
|
40
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Generational or professional suffix (`Jr`, `III`, `PhD`, `MD`).
|
|
54
|
+
*/
|
|
41
55
|
suffix?: string
|
|
42
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* A parenthetical or quoted nickname (`"Gob"` in `George "Gob" Bluth`).
|
|
58
|
+
*/
|
|
43
59
|
nickname?: string
|
|
44
60
|
}
|
|
45
61
|
|
|
46
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Titles / salutations that lead a name. Matched case-insensitively, trailing `.` ignored.
|
|
64
|
+
*/
|
|
47
65
|
const TITLES = new Set([
|
|
48
66
|
"airman",
|
|
49
67
|
"br",
|
|
@@ -100,7 +118,9 @@ const TITLES = new Set([
|
|
|
100
118
|
"sister",
|
|
101
119
|
])
|
|
102
120
|
|
|
103
|
-
/**
|
|
121
|
+
/**
|
|
122
|
+
* Generational + professional suffixes that trail a name.
|
|
123
|
+
*/
|
|
104
124
|
const SUFFIXES = new Set([
|
|
105
125
|
// generational
|
|
106
126
|
"jr",
|
|
@@ -194,21 +214,21 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
194
214
|
|
|
195
215
|
// 1. Extract a parenthetical "(Jim)" or quoted "Jim" nickname, then strip it out.
|
|
196
216
|
let working = input
|
|
197
|
-
.
|
|
217
|
+
.replaceAll(/\s*\(([^)]+)\)\s*/g, (_m, n: string) => {
|
|
198
218
|
if (!result.nickname) {
|
|
199
219
|
result.nickname = n.trim()
|
|
200
220
|
}
|
|
201
221
|
|
|
202
222
|
return " "
|
|
203
223
|
})
|
|
204
|
-
.
|
|
224
|
+
.replaceAll(/\s*"([^"]+)"\s*/g, (_m, n: string) => {
|
|
205
225
|
if (!result.nickname) {
|
|
206
226
|
result.nickname = n.trim()
|
|
207
227
|
}
|
|
208
228
|
|
|
209
229
|
return " "
|
|
210
230
|
})
|
|
211
|
-
.
|
|
231
|
+
.replaceAll(/\s+/g, " ")
|
|
212
232
|
.trim()
|
|
213
233
|
|
|
214
234
|
// 2. Resolve a single comma: "Last, First" inversion, unless the tail is a known suffix
|
|
@@ -226,7 +246,7 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
226
246
|
|
|
227
247
|
const tokens = working.split(/\s+/).filter(Boolean)
|
|
228
248
|
|
|
229
|
-
if (tokens.length
|
|
249
|
+
if (!tokens.length) return Object.keys(result).length ? result : null
|
|
230
250
|
|
|
231
251
|
// 3. Leading titles → prefix.
|
|
232
252
|
const prefixParts: string[] = []
|
|
@@ -242,7 +262,7 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
242
262
|
// 4. Trailing suffixes → suffix (a single name token must remain).
|
|
243
263
|
const suffixParts: string[] = []
|
|
244
264
|
|
|
245
|
-
while (tokens.length > 1 && SUFFIXES.has(norm(tokens
|
|
265
|
+
while (tokens.length > 1 && SUFFIXES.has(norm(tokens.at(-1)!))) {
|
|
246
266
|
suffixParts.unshift(tokens.pop()!)
|
|
247
267
|
}
|
|
248
268
|
|
|
@@ -250,7 +270,7 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
250
270
|
result.suffix = isPresent(result.suffix) ? `${suffixParts.join(" ")} ${result.suffix}` : suffixParts.join(" ")
|
|
251
271
|
}
|
|
252
272
|
|
|
253
|
-
if (tokens.length
|
|
273
|
+
if (!tokens.length) return result
|
|
254
274
|
|
|
255
275
|
// 5. Locate the surname particle run; everything from it onward is the (particled) surname.
|
|
256
276
|
let particleStart = -1
|
|
@@ -259,6 +279,7 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
259
279
|
// A particle only starts a surname if a bare-surname token follows it.
|
|
260
280
|
if (PARTICLES.has(norm(tokens[i]!)) && i < tokens.length - 1) {
|
|
261
281
|
particleStart = i
|
|
282
|
+
|
|
262
283
|
break
|
|
263
284
|
}
|
|
264
285
|
}
|
|
@@ -269,8 +290,10 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
269
290
|
|
|
270
291
|
while (i < tokens.length - 1 && PARTICLES.has(norm(tokens[i]!))) {
|
|
271
292
|
particleParts.push(tokens[i]!)
|
|
293
|
+
|
|
272
294
|
i++
|
|
273
295
|
}
|
|
296
|
+
|
|
274
297
|
result.familyParticle = particleParts.join(" ")
|
|
275
298
|
result.family = tokens.slice(i).join(" ")
|
|
276
299
|
const before = tokens.slice(0, particleStart)
|
|
@@ -292,8 +315,9 @@ export function parsePersonName(input: string | null | undefined): PersonName |
|
|
|
292
315
|
|
|
293
316
|
return result
|
|
294
317
|
}
|
|
318
|
+
|
|
295
319
|
result.given = tokens[0]
|
|
296
|
-
result.family = tokens
|
|
320
|
+
result.family = tokens.at(-1)
|
|
297
321
|
|
|
298
322
|
if (tokens.length > 2) {
|
|
299
323
|
result.middle = tokens.slice(1, -1).join(" ")
|
package/organization.ts
CHANGED
|
@@ -38,15 +38,25 @@
|
|
|
38
38
|
* epic).
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* A canonicalized organization name.
|
|
43
|
+
*/
|
|
42
44
|
export interface OrganizationName {
|
|
43
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* The original input, verbatim.
|
|
47
|
+
*/
|
|
44
48
|
raw: string
|
|
45
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Normalized, designation-stripped key for blocking and comparison.
|
|
51
|
+
*/
|
|
46
52
|
canonical: string
|
|
47
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Legal designations that were stripped (`llc`, `inc`, `gmbh`), in encounter order.
|
|
55
|
+
*/
|
|
48
56
|
designations: string[]
|
|
49
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* The `doing business as` / trade-name clause, canonicalized, when one was present.
|
|
59
|
+
*/
|
|
50
60
|
dba?: string
|
|
51
61
|
}
|
|
52
62
|
|
|
@@ -192,7 +202,9 @@ function resolveDesignations(options?: CanonicalizeOptions): ReadonlySet<string>
|
|
|
192
202
|
return set
|
|
193
203
|
}
|
|
194
204
|
|
|
195
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Splits a `doing business as` / trade-name clause from a legal name.
|
|
207
|
+
*/
|
|
196
208
|
const DBA_PATTERN = /\s+(?:d\/b\/a|dba|doing business as|t\/a|trading as|a\/k\/a|aka|fka|f\/k\/a)\s+/i
|
|
197
209
|
|
|
198
210
|
/**
|
|
@@ -205,15 +217,15 @@ function canonicalizeFragment(
|
|
|
205
217
|
): { canonical: string; designations: string[] } {
|
|
206
218
|
const normalized = fragment
|
|
207
219
|
.normalize("NFKD")
|
|
208
|
-
.
|
|
220
|
+
.replaceAll(/[̀-ͯ]/g, "")
|
|
209
221
|
.toLowerCase()
|
|
210
222
|
// connective punctuation joins words rather than vanishing: "AT&T" → "at and t"
|
|
211
|
-
.
|
|
212
|
-
.
|
|
223
|
+
.replaceAll("&", " and ")
|
|
224
|
+
.replaceAll("+", " and ")
|
|
213
225
|
// periods + apostrophes are intra-token, so remove (not space): "S.A." → "sa", "Macy's" → "macys"
|
|
214
|
-
.
|
|
215
|
-
.
|
|
216
|
-
.
|
|
226
|
+
.replaceAll(/[.'’]/g, "")
|
|
227
|
+
.replaceAll(/[^a-z0-9\s]/g, " ")
|
|
228
|
+
.replaceAll(/\s+/g, " ")
|
|
217
229
|
.trim()
|
|
218
230
|
.replace(/^the\s+/, "")
|
|
219
231
|
|
package/out/address.d.ts
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
* at all (the NAACCR precedent, see the geocode-first record-matching concept doc).
|
|
18
18
|
*/
|
|
19
19
|
import { type ComponentDict, type FormatAddressOptions } from "@mailwoman/formatter";
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* A geographic coordinate (WGS84 decimal degrees).
|
|
22
|
+
*/
|
|
21
23
|
export interface GeoCoordinate {
|
|
22
24
|
latitude: number;
|
|
23
25
|
longitude: number;
|
|
@@ -29,23 +31,35 @@ export interface GeoCoordinate {
|
|
|
29
31
|
* coarser than a house-number estimate, finer than an admin centroid.)
|
|
30
32
|
*/
|
|
31
33
|
export type ResolutionTier = "address_point" | "interpolated" | "street" | "admin";
|
|
32
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* One resolved admin-hierarchy ancestor (most specific first), for spelling-invariant blocking.
|
|
36
|
+
*/
|
|
33
37
|
export interface HierarchyNode {
|
|
34
38
|
tag: string;
|
|
35
39
|
value: string;
|
|
36
40
|
placeID?: string;
|
|
37
41
|
}
|
|
38
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* A resolved geocode attached to an address record — the location signal the matcher scores on.
|
|
44
|
+
*/
|
|
39
45
|
export interface AddressGeocode {
|
|
40
46
|
coordinate: GeoCoordinate;
|
|
41
47
|
tier: ResolutionTier;
|
|
42
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Calibrated uncertainty radius in meters; `null` for the admin tier (no sub-locality estimate).
|
|
50
|
+
*/
|
|
43
51
|
uncertaintyMeters: number | null;
|
|
44
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Resolved admin hierarchy, locality → country (most specific first).
|
|
54
|
+
*/
|
|
45
55
|
hierarchy?: HierarchyNode[];
|
|
46
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* A delivery point, not a building — weakens location agreement even at a precise coordinate.
|
|
58
|
+
*/
|
|
47
59
|
poBox?: boolean;
|
|
48
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* A multi-unit building where many records share one coordinate — weakens unit-level agreement.
|
|
62
|
+
*/
|
|
49
63
|
multiUnit?: boolean;
|
|
50
64
|
}
|
|
51
65
|
/**
|
|
@@ -53,26 +67,46 @@ export interface AddressGeocode {
|
|
|
53
67
|
* form, and an optional resolved geocode. Plain data — no behavior.
|
|
54
68
|
*/
|
|
55
69
|
export interface PostalAddress {
|
|
56
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Parsed address components (`ComponentTag`-keyed).
|
|
72
|
+
*/
|
|
57
73
|
components: ComponentDict;
|
|
58
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Normalized, deterministic match key for blocking (from `@mailwoman/formatter`).
|
|
76
|
+
*/
|
|
59
77
|
canonicalKey: string;
|
|
60
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* Optional human-readable single-line form, for display.
|
|
80
|
+
*/
|
|
61
81
|
formatted?: string;
|
|
62
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Resolved location, when geocoded.
|
|
84
|
+
*/
|
|
63
85
|
geocode?: AddressGeocode;
|
|
64
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* The original free-text input, when known (provenance).
|
|
88
|
+
*/
|
|
65
89
|
raw?: string;
|
|
66
90
|
}
|
|
67
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Options for {@linkcode toPostalAddress}.
|
|
93
|
+
*/
|
|
68
94
|
export interface ToPostalAddressOptions {
|
|
69
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* Country (ISO-2 or name) for formatting. Defaults to the `country` component, else unset.
|
|
97
|
+
*/
|
|
70
98
|
country?: string;
|
|
71
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* The original free-text input to retain as provenance.
|
|
101
|
+
*/
|
|
72
102
|
raw?: string;
|
|
73
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Also compute a human-readable `formatted` string. Default `true`.
|
|
105
|
+
*/
|
|
74
106
|
format?: boolean;
|
|
75
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Formatting options forwarded to the formatter. Defaults to single-line (`", "`).
|
|
109
|
+
*/
|
|
76
110
|
formatOptions?: FormatAddressOptions;
|
|
77
111
|
}
|
|
78
112
|
/**
|
|
@@ -80,6 +114,8 @@ export interface ToPostalAddressOptions {
|
|
|
80
114
|
* form (unless disabled). Attach a geocode separately with {@linkcode withGeocode} once the address is resolved.
|
|
81
115
|
*/
|
|
82
116
|
export declare function toPostalAddress(components: ComponentDict, opts?: ToPostalAddressOptions): PostalAddress;
|
|
83
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Attach (or replace) a resolved geocode on an address record, returning a new record.
|
|
119
|
+
*/
|
|
84
120
|
export declare function withGeocode(record: PostalAddress, geocode: AddressGeocode): PostalAddress;
|
|
85
121
|
//# sourceMappingURL=address.d.ts.map
|
package/out/address.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../address.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAA+B,MAAM,sBAAsB,CAAA;AAEjH
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../address.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAA+B,MAAM,sBAAsB,CAAA;AAEjH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,cAAc,GAAG,QAAQ,GAAG,OAAO,CAAA;AAElF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,aAAa,CAAA;IACzB,IAAI,EAAE,cAAc,CAAA;IACpB;;OAEG;IACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;IAC3B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B;;OAEG;IACH,UAAU,EAAE,aAAa,CAAA;IACzB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;OAEG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAA;CACpC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,aAAa,EAAE,IAAI,GAAE,sBAA2B,GAAG,aAAa,CAqB3G;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,CAEzF"}
|
package/out/address.js
CHANGED
|
@@ -38,7 +38,9 @@ export function toPostalAddress(components, opts = {}) {
|
|
|
38
38
|
}
|
|
39
39
|
return record;
|
|
40
40
|
}
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Attach (or replace) a resolved geocode on an address record, returning a new record.
|
|
43
|
+
*/
|
|
42
44
|
export function withGeocode(record, geocode) {
|
|
43
45
|
return { ...record, geocode };
|
|
44
46
|
}
|
package/out/address.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address.js","sourceRoot":"","sources":["../address.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAiD,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"address.js","sourceRoot":"","sources":["../address.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAiD,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAoGjH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,UAAyB,EAAE,OAA+B,EAAE;IAC3F,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC,OAAO,IAAI,EAAE,CAAA;IAExD,MAAM,MAAM,GAAkB;QAC7B,UAAU;QACV,YAAY,EAAE,YAAY,CAAC,UAAU,CAAC;KACtC,CAAA;IAED,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IACtB,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAE/F,IAAI,SAAS,EAAE,CAAC;YACf,MAAM,CAAC,SAAS,GAAG,SAAS,CAAA;QAC7B,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAA;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAAqB,EAAE,OAAuB;IACzE,OAAO,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAA;AAC9B,CAAC"}
|
package/out/name.d.ts
CHANGED
|
@@ -24,21 +24,37 @@
|
|
|
24
24
|
* positional parser covers the documented hard cases (inversion, particles, generational +
|
|
25
25
|
* professional suffixes) without a model.
|
|
26
26
|
*/
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* A parsed person name. All fields optional — the parser fills what it can identify.
|
|
29
|
+
*/
|
|
28
30
|
export interface PersonName {
|
|
29
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Title / salutation that preceded the name (`Dr`, `Mr`, `Capt`).
|
|
33
|
+
*/
|
|
30
34
|
prefix?: string;
|
|
31
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* First / given name.
|
|
37
|
+
*/
|
|
32
38
|
given?: string;
|
|
33
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Middle name(s) or initial.
|
|
41
|
+
*/
|
|
34
42
|
middle?: string;
|
|
35
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Surname, _without_ any particle (`Vega`, not `de la Vega`).
|
|
45
|
+
*/
|
|
36
46
|
family?: string;
|
|
37
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Surname particle, stored separately (`de la`, `van der`, `von`).
|
|
49
|
+
*/
|
|
38
50
|
familyParticle?: string;
|
|
39
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Generational or professional suffix (`Jr`, `III`, `PhD`, `MD`).
|
|
53
|
+
*/
|
|
40
54
|
suffix?: string;
|
|
41
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* A parenthetical or quoted nickname (`"Gob"` in `George "Gob" Bluth`).
|
|
57
|
+
*/
|
|
42
58
|
nickname?: string;
|
|
43
59
|
}
|
|
44
60
|
/**
|
package/out/name.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH
|
|
1
|
+
{"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB;AAkJD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI,CAqHnF"}
|
package/out/name.js
CHANGED
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
* positional parser covers the documented hard cases (inversion, particles, generational +
|
|
25
25
|
* professional suffixes) without a model.
|
|
26
26
|
*/
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Titles / salutations that lead a name. Matched case-insensitively, trailing `.` ignored.
|
|
29
|
+
*/
|
|
28
30
|
const TITLES = new Set([
|
|
29
31
|
"airman",
|
|
30
32
|
"br",
|
|
@@ -80,7 +82,9 @@ const TITLES = new Set([
|
|
|
80
82
|
"sir",
|
|
81
83
|
"sister",
|
|
82
84
|
]);
|
|
83
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Generational + professional suffixes that trail a name.
|
|
87
|
+
*/
|
|
84
88
|
const SUFFIXES = new Set([
|
|
85
89
|
// generational
|
|
86
90
|
"jr",
|
|
@@ -170,19 +174,19 @@ export function parsePersonName(input) {
|
|
|
170
174
|
const result = {};
|
|
171
175
|
// 1. Extract a parenthetical "(Jim)" or quoted "Jim" nickname, then strip it out.
|
|
172
176
|
let working = input
|
|
173
|
-
.
|
|
177
|
+
.replaceAll(/\s*\(([^)]+)\)\s*/g, (_m, n) => {
|
|
174
178
|
if (!result.nickname) {
|
|
175
179
|
result.nickname = n.trim();
|
|
176
180
|
}
|
|
177
181
|
return " ";
|
|
178
182
|
})
|
|
179
|
-
.
|
|
183
|
+
.replaceAll(/\s*"([^"]+)"\s*/g, (_m, n) => {
|
|
180
184
|
if (!result.nickname) {
|
|
181
185
|
result.nickname = n.trim();
|
|
182
186
|
}
|
|
183
187
|
return " ";
|
|
184
188
|
})
|
|
185
|
-
.
|
|
189
|
+
.replaceAll(/\s+/g, " ")
|
|
186
190
|
.trim();
|
|
187
191
|
// 2. Resolve a single comma: "Last, First" inversion, unless the tail is a known suffix
|
|
188
192
|
// ("John Smith, Jr."), in which case keep order and treat the tail as a suffix.
|
|
@@ -197,7 +201,7 @@ export function parsePersonName(input) {
|
|
|
197
201
|
}
|
|
198
202
|
}
|
|
199
203
|
const tokens = working.split(/\s+/).filter(Boolean);
|
|
200
|
-
if (tokens.length
|
|
204
|
+
if (!tokens.length)
|
|
201
205
|
return Object.keys(result).length ? result : null;
|
|
202
206
|
// 3. Leading titles → prefix.
|
|
203
207
|
const prefixParts = [];
|
|
@@ -209,13 +213,13 @@ export function parsePersonName(input) {
|
|
|
209
213
|
}
|
|
210
214
|
// 4. Trailing suffixes → suffix (a single name token must remain).
|
|
211
215
|
const suffixParts = [];
|
|
212
|
-
while (tokens.length > 1 && SUFFIXES.has(norm(tokens
|
|
216
|
+
while (tokens.length > 1 && SUFFIXES.has(norm(tokens.at(-1)))) {
|
|
213
217
|
suffixParts.unshift(tokens.pop());
|
|
214
218
|
}
|
|
215
219
|
if (suffixParts.length) {
|
|
216
220
|
result.suffix = isPresent(result.suffix) ? `${suffixParts.join(" ")} ${result.suffix}` : suffixParts.join(" ");
|
|
217
221
|
}
|
|
218
|
-
if (tokens.length
|
|
222
|
+
if (!tokens.length)
|
|
219
223
|
return result;
|
|
220
224
|
// 5. Locate the surname particle run; everything from it onward is the (particled) surname.
|
|
221
225
|
let particleStart = -1;
|
|
@@ -250,7 +254,7 @@ export function parsePersonName(input) {
|
|
|
250
254
|
return result;
|
|
251
255
|
}
|
|
252
256
|
result.given = tokens[0];
|
|
253
|
-
result.family = tokens
|
|
257
|
+
result.family = tokens.at(-1);
|
|
254
258
|
if (tokens.length > 2) {
|
|
255
259
|
result.middle = tokens.slice(1, -1).join(" ");
|
|
256
260
|
}
|
package/out/name.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"name.js","sourceRoot":"","sources":["../name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;
|
|
1
|
+
{"version":3,"file":"name.js","sourceRoot":"","sources":["../name.ts"],"names":[],"mappings":"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"}
|
package/out/organization.d.ts
CHANGED
|
@@ -37,15 +37,25 @@
|
|
|
37
37
|
* matching — are deferred to a follow-up (a dedicated org-matching research pass + the matcher
|
|
38
38
|
* epic).
|
|
39
39
|
*/
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* A canonicalized organization name.
|
|
42
|
+
*/
|
|
41
43
|
export interface OrganizationName {
|
|
42
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* The original input, verbatim.
|
|
46
|
+
*/
|
|
43
47
|
raw: string;
|
|
44
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Normalized, designation-stripped key for blocking and comparison.
|
|
50
|
+
*/
|
|
45
51
|
canonical: string;
|
|
46
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Legal designations that were stripped (`llc`, `inc`, `gmbh`), in encounter order.
|
|
54
|
+
*/
|
|
47
55
|
designations: string[];
|
|
48
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* The `doing business as` / trade-name clause, canonicalized, when one was present.
|
|
58
|
+
*/
|
|
49
59
|
dba?: string;
|
|
50
60
|
}
|
|
51
61
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organization.d.ts","sourceRoot":"","sources":["../organization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH
|
|
1
|
+
{"version":3,"file":"organization.d.ts","sourceRoot":"","sources":["../organization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAA;AAExD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC1B;AAmKD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,mBAAmB,GAC3B,gBAAgB,GAAG,IAAI,CAoBzB"}
|
package/out/organization.js
CHANGED
|
@@ -147,7 +147,9 @@ function resolveDesignations(options) {
|
|
|
147
147
|
}
|
|
148
148
|
return set;
|
|
149
149
|
}
|
|
150
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* Splits a `doing business as` / trade-name clause from a legal name.
|
|
152
|
+
*/
|
|
151
153
|
const DBA_PATTERN = /\s+(?:d\/b\/a|dba|doing business as|t\/a|trading as|a\/k\/a|aka|fka|f\/k\/a)\s+/i;
|
|
152
154
|
/**
|
|
153
155
|
* Canonicalize one name fragment: lowercase, strip accents, connectives → `and`, drop punctuation, remove a leading
|
|
@@ -156,15 +158,15 @@ const DBA_PATTERN = /\s+(?:d\/b\/a|dba|doing business as|t\/a|trading as|a\/k\/a
|
|
|
156
158
|
function canonicalizeFragment(fragment, designationSet) {
|
|
157
159
|
const normalized = fragment
|
|
158
160
|
.normalize("NFKD")
|
|
159
|
-
.
|
|
161
|
+
.replaceAll(/[̀-ͯ]/g, "")
|
|
160
162
|
.toLowerCase()
|
|
161
163
|
// connective punctuation joins words rather than vanishing: "AT&T" → "at and t"
|
|
162
|
-
.
|
|
163
|
-
.
|
|
164
|
+
.replaceAll("&", " and ")
|
|
165
|
+
.replaceAll("+", " and ")
|
|
164
166
|
// periods + apostrophes are intra-token, so remove (not space): "S.A." → "sa", "Macy's" → "macys"
|
|
165
|
-
.
|
|
166
|
-
.
|
|
167
|
-
.
|
|
167
|
+
.replaceAll(/[.'’]/g, "")
|
|
168
|
+
.replaceAll(/[^a-z0-9\s]/g, " ")
|
|
169
|
+
.replaceAll(/\s+/g, " ")
|
|
168
170
|
.trim()
|
|
169
171
|
.replace(/^the\s+/, "");
|
|
170
172
|
const designations = [];
|
package/out/organization.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organization.js","sourceRoot":"","sources":["../organization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;
|
|
1
|
+
{"version":3,"file":"organization.js","sourceRoot":"","sources":["../organization.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mailwoman/record",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.2.0",
|
|
4
4
|
"description": "Lean, plain-TypeScript record schema + per-field normalizers for the geocode-first matcher. Address-first: the canonical PostalAddress record composes parser components, the formatter's match key, and a resolved geocode; organization + contact records build on the same canonical record.",
|
|
5
5
|
"license": "AGPL-3.0-only OR LicenseRef-Commercial",
|
|
6
6
|
"repository": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@mailwoman/formatter": "8.
|
|
68
|
+
"@mailwoman/formatter": "8.2.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": ">=26.1.1"
|