@mailwoman/codex 9.0.0 → 9.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.
Files changed (96) hide show
  1. package/README.md +48 -5
  2. package/ca/index.ts +1 -1
  3. package/ca/postal-code.ts +11 -11
  4. package/country/display-names.ts +150 -0
  5. package/country/index.ts +2 -0
  6. package/country/population.ts +265 -0
  7. package/country/subdivision.ts +59 -0
  8. package/de/index.ts +1 -1
  9. package/de/postleitzahl.ts +3 -3
  10. package/es/codigo-postal.ts +2 -2
  11. package/fr/code-postal.ts +6 -6
  12. package/fr/index.ts +1 -1
  13. package/index.ts +10 -1
  14. package/it/cap.ts +2 -2
  15. package/jp/index.ts +1 -1
  16. package/jp/postal-code.ts +11 -11
  17. package/out/ca/index.d.ts +1 -1
  18. package/out/ca/index.js +1 -1
  19. package/out/ca/postal-code.d.ts +10 -10
  20. package/out/ca/postal-code.js +9 -9
  21. package/out/country/display-names.d.ts +67 -0
  22. package/out/country/display-names.d.ts.map +1 -0
  23. package/out/country/display-names.js +118 -0
  24. package/out/country/display-names.js.map +1 -0
  25. package/out/country/index.d.ts +2 -0
  26. package/out/country/index.d.ts.map +1 -1
  27. package/out/country/index.js +2 -0
  28. package/out/country/index.js.map +1 -1
  29. package/out/country/population.d.ts +16 -0
  30. package/out/country/population.d.ts.map +1 -0
  31. package/out/country/population.js +265 -0
  32. package/out/country/population.js.map +1 -0
  33. package/out/country/subdivision.d.ts +7 -0
  34. package/out/country/subdivision.d.ts.map +1 -1
  35. package/out/country/subdivision.js +49 -0
  36. package/out/country/subdivision.js.map +1 -1
  37. package/out/de/index.d.ts +1 -1
  38. package/out/de/index.js +1 -1
  39. package/out/de/postleitzahl.d.ts +3 -3
  40. package/out/de/postleitzahl.js +2 -2
  41. package/out/es/codigo-postal.d.ts +2 -2
  42. package/out/es/codigo-postal.js +1 -1
  43. package/out/fr/code-postal.d.ts +5 -5
  44. package/out/fr/code-postal.js +6 -6
  45. package/out/fr/index.d.ts +1 -1
  46. package/out/fr/index.js +1 -1
  47. package/out/index.d.ts +1 -1
  48. package/out/index.d.ts.map +1 -1
  49. package/out/index.js +1 -1
  50. package/out/index.js.map +1 -1
  51. package/out/it/cap.d.ts +2 -2
  52. package/out/it/cap.js +1 -1
  53. package/out/jp/index.d.ts +1 -1
  54. package/out/jp/index.js +1 -1
  55. package/out/jp/postal-code.d.ts +11 -11
  56. package/out/jp/postal-code.js +8 -8
  57. package/out/postcode-systems.d.ts +84 -0
  58. package/out/postcode-systems.d.ts.map +1 -1
  59. package/out/postcode-systems.js +106 -0
  60. package/out/postcode-systems.js.map +1 -1
  61. package/out/tools/build-country-surface-lexicon.js +1 -1
  62. package/out/tools/build-country-surface-lexicon.js.map +1 -1
  63. package/out/tools/export-country-surfaces.js +1 -1
  64. package/out/tools/export-country-surfaces.js.map +1 -1
  65. package/out/tools/generate-country-population.d.ts +42 -0
  66. package/out/tools/generate-country-population.d.ts.map +1 -0
  67. package/out/tools/generate-country-population.js +106 -0
  68. package/out/tools/generate-country-population.js.map +1 -0
  69. package/out/tools/generate-country-reference.d.ts.map +1 -1
  70. package/out/tools/generate-country-reference.js +4 -4
  71. package/out/tools/generate-country-reference.js.map +1 -1
  72. package/out/tools/generate-official-languages.d.ts.map +1 -1
  73. package/out/tools/generate-official-languages.js +7 -4
  74. package/out/tools/generate-official-languages.js.map +1 -1
  75. package/out/tools/index.d.ts +2 -2
  76. package/out/tools/index.d.ts.map +1 -1
  77. package/out/tools/index.js +2 -2
  78. package/out/tools/index.js.map +1 -1
  79. package/out/us/street-suffix.d.ts +432 -418
  80. package/out/us/street-suffix.d.ts.map +1 -1
  81. package/out/us/street-suffix.js +28 -216
  82. package/out/us/street-suffix.js.map +1 -1
  83. package/out/us/street-suffix.json +273 -0
  84. package/out/us/zipcode.d.ts +1 -1
  85. package/out/us/zipcode.js +1 -1
  86. package/package.json +328 -4
  87. package/postcode-systems.ts +112 -0
  88. package/tools/build-country-surface-lexicon.ts +1 -1
  89. package/tools/export-country-surfaces.ts +1 -1
  90. package/tools/generate-country-population.ts +143 -0
  91. package/tools/generate-country-reference.ts +5 -3
  92. package/tools/generate-official-languages.ts +8 -4
  93. package/tools/index.ts +2 -2
  94. package/us/street-suffix.json +273 -0
  95. package/us/street-suffix.ts +32 -217
  96. package/us/zipcode.ts +1 -1
@@ -23,6 +23,7 @@ import { readFileSync, writeFileSync } from "node:fs"
23
23
  import { join } from "node:path"
24
24
  import { fileURLToPath } from "node:url"
25
25
 
26
+ import { APIClient, pluckResponseData } from "@mailwoman/core/api"
26
27
  import { parseJSONStrict } from "@mailwoman/core/objects"
27
28
 
28
29
  /**
@@ -59,6 +60,12 @@ export interface GenerateOfficialLanguagesSummary {
59
60
  outPath: string
60
61
  }
61
62
 
63
+ /**
64
+ * One call per CLDR supplemental file, against a CDN that throttles. Retry only — the caller makes a handful of
65
+ * requests, so a rate budget would be ceremony over a burst that never happens.
66
+ */
67
+ const cldrClient = new APIClient({ displayName: "cldr", retry: true })
68
+
62
69
  interface LanguagePopulation {
63
70
  _officialStatus?: string
64
71
  }
@@ -69,11 +76,8 @@ async function loadCLDR(file: string, cldrDir: string | undefined, cldrVersion:
69
76
  }
70
77
 
71
78
  const url = `https://cdn.jsdelivr.net/npm/cldr-core@${cldrVersion}/supplemental/${file}.json`
72
- const res = await fetch(url)
73
-
74
- if (!res.ok) throw new Error(`${url}: HTTP ${res.status}`)
75
79
 
76
- return res.json()
80
+ return cldrClient.fetch<unknown>({ url }).then(pluckResponseData)
77
81
  }
78
82
 
79
83
  /**
package/tools/index.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
6
  * Codex operator tools — the `run()`-style modules behind `mailwoman dev generate …` commands. No
7
- * argv, no `process.exit`: commands own parsing, rendering, and exit codes (see the 2026-07-09
8
- * scripts→Pastel spec).
7
+ * argv, no `process.exit`: commands own parsing, rendering, and exit codes.
9
8
  */
10
9
 
10
+ export * from "./generate-country-population.ts"
11
11
  export * from "./generate-country-reference.ts"
12
12
  export * from "./generate-official-languages.ts"
@@ -0,0 +1,273 @@
1
+ {
2
+ "variants": {
3
+ "ALLEY": ["ALY", "ALLEE", "ALLY"],
4
+ "ANEX": ["ANX", "ANNEX", "ANNX"],
5
+ "ARCADE": ["ARC"],
6
+ "AVENUE": ["AVE", "AV", "AVEN", "AVENU", "AVN", "AVNUE"],
7
+ "BAYOU": ["BYU", "BAYOO"],
8
+ "BEACH": ["BCH"],
9
+ "BEND": ["BND"],
10
+ "BLUFF": ["BLF", "BLUF"],
11
+ "BLUFFS": ["BLFS"],
12
+ "BOTTOM": ["BTM", "BOT", "BOTTM"],
13
+ "BOULEVARD": ["BLVD", "BOUL", "BOULV"],
14
+ "BRANCH": ["BR", "BRNCH"],
15
+ "BRIDGE": ["BRG", "BRDGE"],
16
+ "BROOK": ["BRK"],
17
+ "BROOKS": ["BRKS"],
18
+ "BURG": ["BG"],
19
+ "BURGS": ["BGS"],
20
+ "BYPASS": ["BYP", "BYPA", "BYPAS", "BYPS"],
21
+ "CAMP": ["CP", "CMP"],
22
+ "CANYON": ["CYN", "CANYN", "CNYN"],
23
+ "CAPE": ["CPE"],
24
+ "CAUSEWAY": ["CSWY", "CAUSWA"],
25
+ "CENTER": ["CTR", "CEN", "CENT", "CENTR", "CENTRE", "CNTER", "CNTR"],
26
+ "CENTERS": ["CTRS"],
27
+ "CIRCLE": ["CIR", "CIRC", "CIRCL", "CRCL", "CRCLE"],
28
+ "CIRCLES": ["CIRS"],
29
+ "CLIFF": ["CLF"],
30
+ "CLIFFS": ["CLFS"],
31
+ "CLUB": ["CLB"],
32
+ "COMMON": ["CMN"],
33
+ "COMMONS": ["CMNS"],
34
+ "CORNER": ["COR"],
35
+ "CORNERS": ["CORS"],
36
+ "COURSE": ["CRSE"],
37
+ "COURT": ["CT"],
38
+ "COURTS": ["CTS"],
39
+ "COVE": ["CV"],
40
+ "COVES": ["CVS"],
41
+ "CREEK": ["CRK"],
42
+ "CRESCENT": ["CRES", "CRSENT", "CRSNT"],
43
+ "CREST": ["CRST"],
44
+ "CROSSING": ["XING", "CRSSNG"],
45
+ "CROSSROAD": ["XRD"],
46
+ "CROSSROADS": ["XRDS"],
47
+ "CURVE": ["CURV"],
48
+ "DALE": ["DL"],
49
+ "DAM": ["DM"],
50
+ "DIVIDE": ["DV", "DIV", "DVD"],
51
+ "DRIVE": ["DR", "DRIV", "DRV"],
52
+ "DRIVES": ["DRS"],
53
+ "ESTATE": ["EST"],
54
+ "ESTATES": ["ESTS"],
55
+ "EXPRESSWAY": ["EXPY", "EXP", "EXPR", "EXPRESS", "EXPW"],
56
+ "EXTENSION": ["EXT", "EXTN", "EXTNSN"],
57
+ "EXTENSIONS": ["EXTS"],
58
+ "FALL": ["FALL"],
59
+ "FALLS": ["FLS"],
60
+ "FERRY": ["FRY", "FRRY"],
61
+ "FIELD": ["FLD"],
62
+ "FIELDS": ["FLDS"],
63
+ "FLAT": ["FLT"],
64
+ "FLATS": ["FLTS"],
65
+ "FORD": ["FRD"],
66
+ "FORDS": ["FRDS"],
67
+ "FOREST": ["FRST", "FORESTS"],
68
+ "FORGE": ["FRG", "FORG"],
69
+ "FORGES": ["FRGS"],
70
+ "FORK": ["FRK"],
71
+ "FORKS": ["FRKS"],
72
+ "FORT": ["FT", "FRT"],
73
+ "FREEWAY": ["FWY", "FREEWY", "FRWAY", "FRWY"],
74
+ "GARDEN": ["GDN", "GARDN", "GRDEN", "GRDN"],
75
+ "GARDENS": ["GDNS", "GRDNS"],
76
+ "GATEWAY": ["GTWY", "GATEWY", "GATWAY", "GTWAY"],
77
+ "GLEN": ["GLN"],
78
+ "GLENS": ["GLNS"],
79
+ "GREEN": ["GRN"],
80
+ "GREENS": ["GRNS"],
81
+ "GROVE": ["GRV", "GROV"],
82
+ "GROVES": ["GRVS"],
83
+ "HARBOR": ["HBR", "HARB", "HARBR", "HRBOR"],
84
+ "HARBORS": ["HBRS"],
85
+ "HAVEN": ["HVN"],
86
+ "HEIGHTS": ["HTS", "HT"],
87
+ "HIGHWAY": ["HWY", "HIGHWY", "HIWAY", "HIWY", "HWAY"],
88
+ "HILL": ["HL"],
89
+ "HILLS": ["HLS"],
90
+ "HOLLOW": ["HOLW", "HLLW", "HOLLOWS", "HOLWS"],
91
+ "INLET": ["INLT"],
92
+ "ISLAND": ["IS", "ISLND"],
93
+ "ISLANDS": ["ISS", "ISLNDS"],
94
+ "ISLE": ["ISLE", "ISLES"],
95
+ "JUNCTION": ["JCT", "JCTION", "JCTN", "JUNCTN", "JUNCTON"],
96
+ "JUNCTIONS": ["JCTS", "JCTNS"],
97
+ "KEY": ["KY"],
98
+ "KEYS": ["KYS"],
99
+ "KNOLL": ["KNL", "KNOL"],
100
+ "KNOLLS": ["KNLS"],
101
+ "LAKE": ["LK"],
102
+ "LAKES": ["LKS"],
103
+ "LAND": ["LAND"],
104
+ "LANDING": ["LNDG", "LNDNG"],
105
+ "LANE": ["LN"],
106
+ "LIGHT": ["LGT"],
107
+ "LIGHTS": ["LGTS"],
108
+ "LOAF": ["LF"],
109
+ "LOCK": ["LCK"],
110
+ "LOCKS": ["LCKS"],
111
+ "LODGE": ["LDG", "LDGE", "LODG"],
112
+ "LOOP": ["LOOP", "LOOPS"],
113
+ "MALL": ["MALL"],
114
+ "MANOR": ["MNR"],
115
+ "MANORS": ["MNRS"],
116
+ "MEADOW": ["MDW"],
117
+ "MEADOWS": ["MDWS", "MDW", "MEDOWS"],
118
+ "MEWS": ["MEWS"],
119
+ "MILL": ["ML"],
120
+ "MILLS": ["MLS"],
121
+ "MISSION": ["MSN", "MISSN", "MSSN"],
122
+ "MOTORWAY": ["MTWY"],
123
+ "MOUNT": ["MT", "MNT"],
124
+ "MOUNTAIN": ["MTN", "MNTAIN", "MNTN", "MOUNTIN", "MTIN"],
125
+ "MOUNTAINS": ["MTNS", "MNTNS"],
126
+ "NECK": ["NCK"],
127
+ "ORCHARD": ["ORCH", "ORCHRD"],
128
+ "OVAL": ["OVAL", "OVL"],
129
+ "OVERPASS": ["OPAS"],
130
+ "PARK": ["PARK", "PRK", "PARKS"],
131
+ "PARKWAY": ["PKWY", "PARKWY", "PKWAY", "PKY"],
132
+ "PARKWAYS": ["PKWY", "PKWYS"],
133
+ "PASS": ["PASS"],
134
+ "PASSAGE": ["PSGE"],
135
+ "PATH": ["PATH", "PATHS"],
136
+ "PIKE": ["PIKE", "PIKES"],
137
+ "PINE": ["PNE"],
138
+ "PINES": ["PNES"],
139
+ "PLACE": ["PL"],
140
+ "PLAIN": ["PLN"],
141
+ "PLAINS": ["PLNS"],
142
+ "PLAZA": ["PLZ", "PLZA"],
143
+ "POINT": ["PT"],
144
+ "POINTS": ["PTS"],
145
+ "PORT": ["PRT"],
146
+ "PORTS": ["PRTS"],
147
+ "PRAIRIE": ["PR", "PRR"],
148
+ "RADIAL": ["RADL", "RAD", "RADIEL"],
149
+ "RAMP": ["RAMP"],
150
+ "RANCH": ["RNCH", "RANCHES", "RNCHS"],
151
+ "RAPID": ["RPD"],
152
+ "RAPIDS": ["RPDS"],
153
+ "REST": ["RST"],
154
+ "RIDGE": ["RDG", "RDGE"],
155
+ "RIDGES": ["RDGS"],
156
+ "RIVER": ["RIV", "RVR", "RIVR"],
157
+ "ROAD": ["RD"],
158
+ "ROADS": ["RDS"],
159
+ "ROUTE": ["RTE"],
160
+ "ROW": ["ROW"],
161
+ "RUE": ["RUE"],
162
+ "RUN": ["RUN"],
163
+ "SHOAL": ["SHL"],
164
+ "SHOALS": ["SHLS"],
165
+ "SHORE": ["SHR", "SHOAR"],
166
+ "SHORES": ["SHRS", "SHOARS"],
167
+ "SKYWAY": ["SKWY"],
168
+ "SPRING": ["SPG", "SPNG", "SPRNG"],
169
+ "SPRINGS": ["SPGS", "SPNGS", "SPRNGS"],
170
+ "SPUR": ["SPUR"],
171
+ "SPURS": ["SPUR"],
172
+ "SQUARE": ["SQ", "SQR", "SQRE", "SQU"],
173
+ "SQUARES": ["SQS", "SQRS"],
174
+ "STATION": ["STA", "STATN", "STN"],
175
+ "STRAVENUE": ["STRA", "STRAV", "STRAVEN", "STRAVN", "STRVN", "STRVNUE"],
176
+ "STREAM": ["STRM", "STREME"],
177
+ "STREET": ["ST", "STRT", "STR"],
178
+ "STREETS": ["STS"],
179
+ "SUMMIT": ["SMT", "SUMIT", "SUMITT"],
180
+ "TERRACE": ["TER", "TERR"],
181
+ "THROUGHWAY": ["TRWY"],
182
+ "TRACE": ["TRCE", "TRACES"],
183
+ "TRACK": ["TRAK", "TRACKS", "TRK", "TRKS"],
184
+ "TRAFFICWAY": ["TRFY"],
185
+ "TRAIL": ["TRL", "TRAILS", "TRLS"],
186
+ "TRAILER": ["TRLR", "TRLRS"],
187
+ "TUNNEL": ["TUNL", "TUNEL", "TUNLS", "TUNNELS", "TUNNL"],
188
+ "TURNPIKE": ["TPKE", "TRNPK", "TURNPK"],
189
+ "UNDERPASS": ["UPAS"],
190
+ "UNION": ["UN"],
191
+ "UNIONS": ["UNS"],
192
+ "VALLEY": ["VLY", "VALLY", "VLLY"],
193
+ "VALLEYS": ["VLYS"],
194
+ "VIADUCT": ["VIA", "VDCT", "VIADCT"],
195
+ "VIEW": ["VW"],
196
+ "VIEWS": ["VWS"],
197
+ "VILLAGE": ["VLG", "VILL", "VILLAG", "VILLG", "VILLIAGE"],
198
+ "VILLAGES": ["VLGS"],
199
+ "VILLE": ["VL"],
200
+ "VISTA": ["VIS", "VIST", "VST", "VSTA"],
201
+ "WALK": ["WALK"],
202
+ "WALKS": ["WALK"],
203
+ "WALL": ["WALL"],
204
+ "WAY": ["WAY", "WY"],
205
+ "WAYS": ["WAYS"],
206
+ "WELL": ["WL"],
207
+ "WELLS": ["WLS"]
208
+ },
209
+ "nameProneCanonicals": [
210
+ "BEACH",
211
+ "BROOK",
212
+ "BROOKS",
213
+ "CAMP",
214
+ "CENTER",
215
+ "CENTERS",
216
+ "CLUB",
217
+ "COMMON",
218
+ "COMMONS",
219
+ "CREEK",
220
+ "CROSSING",
221
+ "ESTATE",
222
+ "ESTATES",
223
+ "FIELD",
224
+ "FIELDS",
225
+ "FOREST",
226
+ "GARDEN",
227
+ "GARDENS",
228
+ "GLEN",
229
+ "GREEN",
230
+ "GREENS",
231
+ "GROVE",
232
+ "GROVES",
233
+ "HARBOR",
234
+ "HEIGHTS",
235
+ "HILL",
236
+ "HILLS",
237
+ "HOLLOW",
238
+ "ISLAND",
239
+ "ISLANDS",
240
+ "ISLE",
241
+ "JUNCTION",
242
+ "LAKE",
243
+ "LAKES",
244
+ "LANDING",
245
+ "MALL",
246
+ "MANOR",
247
+ "MEADOW",
248
+ "MEADOWS",
249
+ "MILL",
250
+ "MILLS",
251
+ "MISSION",
252
+ "ORCHARD",
253
+ "PARK",
254
+ "PASS",
255
+ "PLAZA",
256
+ "POINT",
257
+ "POINTS",
258
+ "RANCH",
259
+ "RIDGE",
260
+ "SHORE",
261
+ "SHORES",
262
+ "SPRING",
263
+ "SPRINGS",
264
+ "SQUARE",
265
+ "STATION",
266
+ "SUMMIT",
267
+ "VALLEY",
268
+ "VIEW",
269
+ "VIEWS",
270
+ "VILLAGE",
271
+ "VISTA"
272
+ ]
273
+ }
@@ -5,234 +5,47 @@
5
5
  *
6
6
  * USPS Publication 28, Appendix C — Postal Service Standard Suffix Abbreviations.
7
7
  *
8
- * For each canonical suffix the value lists every recognized variant in USPS-published order; the
9
- * first variant is the preferred USPS abbreviation (e.g. `AVENUE ["AVE", "AV", "AVEN", "AVENU",
10
- * "AVN", "AVNUE"]` — `AVE` is what the post office prints).
8
+ * The DATA lives in `./street-suffix.json` so non-TS consumers (the Python training loader's
9
+ * lexicon builder, audits) read the identical record no hand-mirrored copies. Two keys:
11
10
  *
12
- * This module is the single home for the USPS suffix table. It carries both the synthesis-layer
13
- * helpers (`US_STREET_SUFFIX_PREFERRED_ABBR`, `matchCase`, `matchTrailingSuffix` used by
14
- * `@mailwoman/corpus`) and the richer branded-type lookup (`StreetSuffix`, `lookupStreetSuffix`,
15
- * `isStreetSuffix`) The data is verbatim USPS Pub-28; the two APIs share one underlying record.
11
+ * - `variants` verbatim USPS Pub-28: canonical suffix every recognized variant in
12
+ * USPS-published order; the first variant is the preferred USPS abbreviation (e.g.
13
+ * `AVENUE ["AVE", ...]` `AVE` is what the post office prints).
14
+ * - `nameProneCanonicals` OUR curation, not Pub-28: canonicals also observed as ordinary
15
+ * proper-name heads in street names (PARK, HILL, CREEK…), from golden v0.1.3 + the OA street
16
+ * pool. Shared by the golden relabel flags, the #1569 shard recipe, and (via the
17
+ * `gazetteer affix-relabel` v2 lexicon) the Python relabel pass, so the instrument and the
18
+ * training feed cannot drift onto different definitions of the ambiguous class.
19
+ *
20
+ * This module remains the single TS home for the table: the synthesis-layer helpers
21
+ * (`US_STREET_SUFFIX_PREFERRED_ABBR`, `matchCase`, `matchTrailingSuffix` — used by
22
+ * `@mailwoman/corpus`) and the richer branded-type lookup (`StreetSuffix`,
23
+ * `lookupStreetSuffix`, `isStreetSuffix`) share the one underlying JSON record.
16
24
  * @see {@link https://pe.usps.com/text/pub28/28apc_002.htm USPS Street Suffix Abbreviations}
17
25
  */
18
26
 
27
+ import streetSuffixData from "./street-suffix.json" with { type: "json" }
28
+
19
29
  /**
20
30
  * Canonical USPS street suffix → list of recognized variants. The first variant in each list is the preferred USPS
21
- * abbreviation. Keys + values are uppercase per the publication.
31
+ * abbreviation. Keys + values are uppercase per the publication. Data: `./street-suffix.json`.
22
32
  */
23
- export const US_STREET_SUFFIX_VARIANTS = {
24
- ALLEY: ["ALY", "ALLEE", "ALLY"],
25
- ANEX: ["ANX", "ANNEX", "ANNX"],
26
- ARCADE: ["ARC"],
27
- AVENUE: ["AVE", "AV", "AVEN", "AVENU", "AVN", "AVNUE"],
28
- BAYOU: ["BYU", "BAYOO"],
29
- BEACH: ["BCH"],
30
- BEND: ["BND"],
31
- BLUFF: ["BLF", "BLUF"],
32
- BLUFFS: ["BLFS"],
33
- BOTTOM: ["BTM", "BOT", "BOTTM"],
34
- BOULEVARD: ["BLVD", "BOUL", "BOULV"],
35
- BRANCH: ["BR", "BRNCH"],
36
- BRIDGE: ["BRG", "BRDGE"],
37
- BROOK: ["BRK"],
38
- BROOKS: ["BRKS"],
39
- BURG: ["BG"],
40
- BURGS: ["BGS"],
41
- BYPASS: ["BYP", "BYPA", "BYPAS", "BYPS"],
42
- CAMP: ["CP", "CMP"],
43
- CANYON: ["CYN", "CANYN", "CNYN"],
44
- CAPE: ["CPE"],
45
- CAUSEWAY: ["CSWY", "CAUSWA"],
46
- CENTER: ["CTR", "CEN", "CENT", "CENTR", "CENTRE", "CNTER", "CNTR"],
47
- CENTERS: ["CTRS"],
48
- CIRCLE: ["CIR", "CIRC", "CIRCL", "CRCL", "CRCLE"],
49
- CIRCLES: ["CIRS"],
50
- CLIFF: ["CLF"],
51
- CLIFFS: ["CLFS"],
52
- CLUB: ["CLB"],
53
- COMMON: ["CMN"],
54
- COMMONS: ["CMNS"],
55
- CORNER: ["COR"],
56
- CORNERS: ["CORS"],
57
- COURSE: ["CRSE"],
58
- COURT: ["CT"],
59
- COURTS: ["CTS"],
60
- COVE: ["CV"],
61
- COVES: ["CVS"],
62
- CREEK: ["CRK"],
63
- CRESCENT: ["CRES", "CRSENT", "CRSNT"],
64
- CREST: ["CRST"],
65
- CROSSING: ["XING", "CRSSNG"],
66
- CROSSROAD: ["XRD"],
67
- CROSSROADS: ["XRDS"],
68
- CURVE: ["CURV"],
69
- DALE: ["DL"],
70
- DAM: ["DM"],
71
- DIVIDE: ["DV", "DIV", "DVD"],
72
- DRIVE: ["DR", "DRIV", "DRV"],
73
- DRIVES: ["DRS"],
74
- ESTATE: ["EST"],
75
- ESTATES: ["ESTS"],
76
- EXPRESSWAY: ["EXPY", "EXP", "EXPR", "EXPRESS", "EXPW"],
77
- EXTENSION: ["EXT", "EXTN", "EXTNSN"],
78
- EXTENSIONS: ["EXTS"],
79
- FALL: ["FALL"],
80
- FALLS: ["FLS"],
81
- FERRY: ["FRY", "FRRY"],
82
- FIELD: ["FLD"],
83
- FIELDS: ["FLDS"],
84
- FLAT: ["FLT"],
85
- FLATS: ["FLTS"],
86
- FORD: ["FRD"],
87
- FORDS: ["FRDS"],
88
- FOREST: ["FRST", "FORESTS"],
89
- FORGE: ["FRG", "FORG"],
90
- FORGES: ["FRGS"],
91
- FORK: ["FRK"],
92
- FORKS: ["FRKS"],
93
- FORT: ["FT", "FRT"],
94
- FREEWAY: ["FWY", "FREEWY", "FRWAY", "FRWY"],
95
- GARDEN: ["GDN", "GARDN", "GRDEN", "GRDN"],
96
- GARDENS: ["GDNS", "GRDNS"],
97
- GATEWAY: ["GTWY", "GATEWY", "GATWAY", "GTWAY"],
98
- GLEN: ["GLN"],
99
- GLENS: ["GLNS"],
100
- GREEN: ["GRN"],
101
- GREENS: ["GRNS"],
102
- GROVE: ["GRV", "GROV"],
103
- GROVES: ["GRVS"],
104
- HARBOR: ["HBR", "HARB", "HARBR", "HRBOR"],
105
- HARBORS: ["HBRS"],
106
- HAVEN: ["HVN"],
107
- HEIGHTS: ["HTS", "HT"],
108
- HIGHWAY: ["HWY", "HIGHWY", "HIWAY", "HIWY", "HWAY"],
109
- HILL: ["HL"],
110
- HILLS: ["HLS"],
111
- HOLLOW: ["HOLW", "HLLW", "HOLLOWS", "HOLWS"],
112
- INLET: ["INLT"],
113
- ISLAND: ["IS", "ISLND"],
114
- ISLANDS: ["ISS", "ISLNDS"],
115
- ISLE: ["ISLE", "ISLES"],
116
- JUNCTION: ["JCT", "JCTION", "JCTN", "JUNCTN", "JUNCTON"],
117
- JUNCTIONS: ["JCTS", "JCTNS"],
118
- KEY: ["KY"],
119
- KEYS: ["KYS"],
120
- KNOLL: ["KNL", "KNOL"],
121
- KNOLLS: ["KNLS"],
122
- LAKE: ["LK"],
123
- LAKES: ["LKS"],
124
- LAND: ["LAND"],
125
- LANDING: ["LNDG", "LNDNG"],
126
- LANE: ["LN"],
127
- LIGHT: ["LGT"],
128
- LIGHTS: ["LGTS"],
129
- LOAF: ["LF"],
130
- LOCK: ["LCK"],
131
- LOCKS: ["LCKS"],
132
- LODGE: ["LDG", "LDGE", "LODG"],
133
- LOOP: ["LOOP", "LOOPS"],
134
- MALL: ["MALL"],
135
- MANOR: ["MNR"],
136
- MANORS: ["MNRS"],
137
- MEADOW: ["MDW"],
138
- MEADOWS: ["MDWS", "MDW", "MEDOWS"],
139
- MEWS: ["MEWS"],
140
- MILL: ["ML"],
141
- MILLS: ["MLS"],
142
- MISSION: ["MSN", "MISSN", "MSSN"],
143
- MOTORWAY: ["MTWY"],
144
- MOUNT: ["MT", "MNT"],
145
- MOUNTAIN: ["MTN", "MNTAIN", "MNTN", "MOUNTIN", "MTIN"],
146
- MOUNTAINS: ["MTNS", "MNTNS"],
147
- NECK: ["NCK"],
148
- ORCHARD: ["ORCH", "ORCHRD"],
149
- OVAL: ["OVAL", "OVL"],
150
- OVERPASS: ["OPAS"],
151
- PARK: ["PARK", "PRK", "PARKS"],
152
- PARKWAY: ["PKWY", "PARKWY", "PKWAY", "PKY"],
153
- PARKWAYS: ["PKWY", "PKWYS"],
154
- PASS: ["PASS"],
155
- PASSAGE: ["PSGE"],
156
- PATH: ["PATH", "PATHS"],
157
- PIKE: ["PIKE", "PIKES"],
158
- PINE: ["PNE"],
159
- PINES: ["PNES"],
160
- PLACE: ["PL"],
161
- PLAIN: ["PLN"],
162
- PLAINS: ["PLNS"],
163
- PLAZA: ["PLZ", "PLZA"],
164
- POINT: ["PT"],
165
- POINTS: ["PTS"],
166
- PORT: ["PRT"],
167
- PORTS: ["PRTS"],
168
- PRAIRIE: ["PR", "PRR"],
169
- RADIAL: ["RADL", "RAD", "RADIEL"],
170
- RAMP: ["RAMP"],
171
- RANCH: ["RNCH", "RANCHES", "RNCHS"],
172
- RAPID: ["RPD"],
173
- RAPIDS: ["RPDS"],
174
- REST: ["RST"],
175
- RIDGE: ["RDG", "RDGE"],
176
- RIDGES: ["RDGS"],
177
- RIVER: ["RIV", "RVR", "RIVR"],
178
- ROAD: ["RD"],
179
- ROADS: ["RDS"],
180
- ROUTE: ["RTE"],
181
- ROW: ["ROW"],
182
- RUE: ["RUE"],
183
- RUN: ["RUN"],
184
- SHOAL: ["SHL"],
185
- SHOALS: ["SHLS"],
186
- SHORE: ["SHR", "SHOAR"],
187
- SHORES: ["SHRS", "SHOARS"],
188
- SKYWAY: ["SKWY"],
189
- SPRING: ["SPG", "SPNG", "SPRNG"],
190
- SPRINGS: ["SPGS", "SPNGS", "SPRNGS"],
191
- SPUR: ["SPUR"],
192
- SPURS: ["SPUR"],
193
- SQUARE: ["SQ", "SQR", "SQRE", "SQU"],
194
- SQUARES: ["SQS", "SQRS"],
195
- STATION: ["STA", "STATN", "STN"],
196
- STRAVENUE: ["STRA", "STRAV", "STRAVEN", "STRAVN", "STRVN", "STRVNUE"],
197
- STREAM: ["STRM", "STREME"],
198
- STREET: ["ST", "STRT", "STR"],
199
- STREETS: ["STS"],
200
- SUMMIT: ["SMT", "SUMIT", "SUMITT"],
201
- TERRACE: ["TER", "TERR"],
202
- THROUGHWAY: ["TRWY"],
203
- TRACE: ["TRCE", "TRACES"],
204
- TRACK: ["TRAK", "TRACKS", "TRK", "TRKS"],
205
- TRAFFICWAY: ["TRFY"],
206
- TRAIL: ["TRL", "TRAILS", "TRLS"],
207
- TRAILER: ["TRLR", "TRLRS"],
208
- TUNNEL: ["TUNL", "TUNEL", "TUNLS", "TUNNELS", "TUNNL"],
209
- TURNPIKE: ["TPKE", "TRNPK", "TURNPK"],
210
- UNDERPASS: ["UPAS"],
211
- UNION: ["UN"],
212
- UNIONS: ["UNS"],
213
- VALLEY: ["VLY", "VALLY", "VLLY"],
214
- VALLEYS: ["VLYS"],
215
- VIADUCT: ["VIA", "VDCT", "VIADCT"],
216
- VIEW: ["VW"],
217
- VIEWS: ["VWS"],
218
- VILLAGE: ["VLG", "VILL", "VILLAG", "VILLG", "VILLIAGE"],
219
- VILLAGES: ["VLGS"],
220
- VILLE: ["VL"],
221
- VISTA: ["VIS", "VIST", "VST", "VSTA"],
222
- WALK: ["WALK"],
223
- WALKS: ["WALK"],
224
- WALL: ["WALL"],
225
- WAY: ["WAY", "WY"],
226
- WAYS: ["WAYS"],
227
- WELL: ["WL"],
228
- WELLS: ["WLS"],
229
- } as const satisfies Record<string, readonly string[]>
33
+ export const US_STREET_SUFFIX_VARIANTS = streetSuffixData.variants
230
34
 
231
35
  /**
232
36
  * Canonical USPS suffix (full word, uppercase per the publication).
233
37
  */
234
38
  export type USStreetSuffix = keyof typeof US_STREET_SUFFIX_VARIANTS
235
39
 
40
+ /**
41
+ * Pub-28 canonicals that are also common head nouns in street/place names ("Menlo PARK Road", "Blue HILL Rd") — the
42
+ * ambiguous class behind #1569. Curated (golden v0.1.3 + OA street pool), NOT part of the USPS publication; see
43
+ * `nameProneCanonicals` in `./street-suffix.json`.
44
+ */
45
+ export const NAME_PRONE_US_SUFFIXES: ReadonlySet<USStreetSuffix> = new Set(
46
+ streetSuffixData.nameProneCanonicals as USStreetSuffix[]
47
+ )
48
+
236
49
  /**
237
50
  * Inverse lookup: every variant abbreviation OR full canonical word → its canonical key. Built once at module load,
238
51
  * lowercase-keyed for case-insensitive matching (`street` → `"STREET"`, `st` → `"STREET"`, `strt` → `"STREET"`, …).
@@ -260,7 +73,9 @@ export const US_STREET_SUFFIX_LOOKUP: ReadonlyMap<string, USStreetSuffix> = (()
260
73
  * Preferred USPS abbreviation per canonical (`AVENUE → "AVE"`, `STREET → "ST"`).
261
74
  */
262
75
  export const US_STREET_SUFFIX_PREFERRED_ABBR: Readonly<Record<USStreetSuffix, string>> = Object.fromEntries(
263
- (Object.keys(US_STREET_SUFFIX_VARIANTS) as USStreetSuffix[]).map((k) => [k, US_STREET_SUFFIX_VARIANTS[k][0]])
76
+ // Every Pub-28 canonical carries >= 1 variant (the preferred abbreviation is first); the JSON
77
+ // import types values as string[], so assert the head's presence.
78
+ (Object.keys(US_STREET_SUFFIX_VARIANTS) as USStreetSuffix[]).map((k) => [k, US_STREET_SUFFIX_VARIANTS[k][0]!])
264
79
  ) as Readonly<Record<USStreetSuffix, string>>
265
80
 
266
81
  /**
@@ -345,7 +160,7 @@ export function lookupStreetSuffix(input: string | null | undefined): StreetSuff
345
160
 
346
161
  if (!suffix) return null
347
162
 
348
- return { suffix, abbreviation: US_STREET_SUFFIX_VARIANTS[suffix][0] }
163
+ return { suffix, abbreviation: US_STREET_SUFFIX_VARIANTS[suffix][0]! }
349
164
  }
350
165
 
351
166
  /**
package/us/zipcode.ts CHANGED
@@ -191,7 +191,7 @@ export interface PluckedStateZIPCodeResult {
191
191
  }
192
192
 
193
193
  /**
194
- * Given an address string like `"NY"`, `"CA 94016"`, attempts to match the state abbreviation and postal code, if
194
+ * Given an address string like `"NY"`, `"CA 94016"`, attempts to match the state abbreviation and postcode, if
195
195
  * applicable.
196
196
  *
197
197
  * @see {@linkcode isUSStateAbbreviation} to validate the state abbreviation.