@mailwoman/codex 9.1.0 → 9.3.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/README.md +51 -8
- package/{address-system-conventions.ts → lib/address-system-conventions.ts} +9 -9
- package/{au → lib/au}/index.ts +4 -4
- package/{ca → lib/ca}/index.ts +4 -4
- package/{ca → lib/ca}/postal-code.ts +12 -12
- package/{ca → lib/ca}/province.ts +1 -1
- package/{ca → lib/ca}/street-type.ts +10 -12
- package/{country → lib/country}/codes.ts +1 -1
- package/{country → lib/country}/country.ts +43 -14
- package/lib/country/display-names.ts +150 -0
- package/lib/country/index.ts +17 -0
- package/lib/country/population.ts +265 -0
- package/{country → lib/country}/reference.ts +2 -2
- package/{country → lib/country}/subdivision.ts +62 -3
- package/{de → lib/de}/index.ts +4 -4
- package/{de → lib/de}/postleitzahl.ts +3 -3
- package/{es → lib/es}/codigo-postal.ts +24 -6
- package/{es → lib/es}/index.ts +1 -1
- package/{fr → lib/fr}/cedex.ts +1 -1
- package/{fr → lib/fr}/code-postal.ts +8 -8
- package/{fr → lib/fr}/departement.ts +5 -2
- package/{fr → lib/fr}/index.ts +6 -6
- package/{fr → lib/fr}/region.ts +1 -1
- package/{fr → lib/fr}/voie.ts +5 -13
- package/{gb → lib/gb}/country.ts +2 -10
- package/{gb → lib/gb}/index.ts +4 -4
- package/{gb → lib/gb}/postcode-area.ts +1 -1
- package/{gb → lib/gb}/street-type.ts +1 -1
- package/{index.ts → lib/index.ts} +22 -12
- package/{it → lib/it}/cap.ts +23 -5
- package/{it → lib/it}/index.ts +1 -1
- package/{jp → lib/jp}/index.ts +4 -4
- package/{jp → lib/jp}/postal-code.ts +11 -11
- package/{jp → lib/jp}/prefecture.ts +7 -5
- package/{normalize.ts → lib/normalize.ts} +15 -1
- package/{nz → lib/nz}/delivery-service.ts +1 -1
- package/{nz → lib/nz}/index.ts +2 -2
- package/lib/postcode-systems.ts +198 -0
- package/{tools → lib/tools}/build-country-surface-lexicon.ts +10 -9
- package/{tools → lib/tools}/export-country-surfaces.ts +8 -8
- package/lib/tools/generate-country-population.ts +142 -0
- package/{tools → lib/tools}/generate-country-reference.ts +8 -7
- package/{tools → lib/tools}/generate-official-languages.ts +15 -13
- package/{tools → lib/tools}/index.ts +4 -4
- package/{us → lib/us}/index.ts +8 -8
- package/{us → lib/us}/po-box.ts +1 -1
- package/{us → lib/us}/street-directional.ts +2 -2
- package/{us → lib/us}/street-suffix.ts +1 -1
- package/{us → lib/us}/unit-designator.ts +1 -1
- package/{us → lib/us}/zipcode.ts +2 -2
- package/out/address-system-conventions.d.ts +1 -1
- package/out/address-system-conventions.d.ts.map +1 -1
- package/out/address-system-conventions.js +8 -8
- package/out/address-system-conventions.js.map +1 -1
- package/out/au/delivery-service.d.ts.map +1 -1
- package/out/au/delivery-service.js.map +1 -1
- package/out/au/index.d.ts +4 -4
- package/out/au/index.d.ts.map +1 -1
- package/out/au/index.js +4 -4
- package/out/au/index.js.map +1 -1
- package/out/au/level-designator.d.ts.map +1 -1
- package/out/au/level-designator.js.map +1 -1
- package/out/au/postcode.d.ts.map +1 -1
- package/out/au/postcode.js.map +1 -1
- package/out/au/state.d.ts.map +1 -1
- package/out/au/state.js.map +1 -1
- package/out/ca/index.d.ts +4 -4
- package/out/ca/index.d.ts.map +1 -1
- package/out/ca/index.js +4 -4
- package/out/ca/index.js.map +1 -1
- package/out/ca/postal-code.d.ts +11 -11
- package/out/ca/postal-code.d.ts.map +1 -1
- package/out/ca/postal-code.js +9 -9
- package/out/ca/postal-code.js.map +1 -1
- package/out/ca/province.d.ts.map +1 -1
- package/out/ca/province.js +1 -1
- package/out/ca/province.js.map +1 -1
- package/out/ca/street-type.d.ts.map +1 -1
- package/out/ca/street-type.js +9 -12
- package/out/ca/street-type.js.map +1 -1
- package/out/country/codes.d.ts.map +1 -1
- package/out/country/codes.js.map +1 -1
- package/out/country/country.d.ts +13 -11
- package/out/country/country.d.ts.map +1 -1
- package/out/country/country.js +35 -13
- package/out/country/country.js.map +1 -1
- package/out/country/display-names.d.ts +67 -0
- package/out/country/display-names.d.ts.map +1 -0
- package/out/country/display-names.js +118 -0
- package/out/country/display-names.js.map +1 -0
- package/out/country/index.d.ts +10 -8
- package/out/country/index.d.ts.map +1 -1
- package/out/country/index.js +10 -8
- package/out/country/index.js.map +1 -1
- package/out/country/names.d.ts.map +1 -1
- package/out/country/names.js.map +1 -1
- package/out/country/official-languages.d.ts.map +1 -1
- package/out/country/official-languages.js.map +1 -1
- package/out/country/population.d.ts +16 -0
- package/out/country/population.d.ts.map +1 -0
- package/out/country/population.js +265 -0
- package/out/country/population.js.map +1 -0
- package/out/country/reference-data.d.ts.map +1 -1
- package/out/country/reference-data.js.map +1 -1
- package/out/country/reference.d.ts +1 -1
- package/out/country/reference.d.ts.map +1 -1
- package/out/country/reference.js +2 -2
- package/out/country/reference.js.map +1 -1
- package/out/country/subdivision.d.ts +7 -0
- package/out/country/subdivision.d.ts.map +1 -1
- package/out/country/subdivision.js +52 -3
- package/out/country/subdivision.js.map +1 -1
- package/out/de/bundesland.d.ts.map +1 -1
- package/out/de/bundesland.js.map +1 -1
- package/out/de/index.d.ts +4 -4
- package/out/de/index.d.ts.map +1 -1
- package/out/de/index.js +4 -4
- package/out/de/index.js.map +1 -1
- package/out/de/postleitzahl.d.ts +3 -3
- package/out/de/postleitzahl.d.ts.map +1 -1
- package/out/de/postleitzahl.js +2 -2
- package/out/de/postleitzahl.js.map +1 -1
- package/out/de/street-type.d.ts.map +1 -1
- package/out/de/street-type.js.map +1 -1
- package/out/es/codigo-postal.d.ts +13 -2
- package/out/es/codigo-postal.d.ts.map +1 -1
- package/out/es/codigo-postal.js +21 -4
- package/out/es/codigo-postal.js.map +1 -1
- package/out/es/index.d.ts +1 -1
- package/out/es/index.d.ts.map +1 -1
- package/out/es/index.js +1 -1
- package/out/es/index.js.map +1 -1
- package/out/fr/cedex.d.ts +1 -1
- package/out/fr/cedex.d.ts.map +1 -1
- package/out/fr/cedex.js +1 -1
- package/out/fr/cedex.js.map +1 -1
- package/out/fr/code-postal.d.ts +7 -7
- package/out/fr/code-postal.d.ts.map +1 -1
- package/out/fr/code-postal.js +8 -8
- package/out/fr/code-postal.js.map +1 -1
- package/out/fr/departement.d.ts +2 -2
- package/out/fr/departement.d.ts.map +1 -1
- package/out/fr/departement.js +3 -0
- package/out/fr/departement.js.map +1 -1
- package/out/fr/index.d.ts +6 -6
- package/out/fr/index.d.ts.map +1 -1
- package/out/fr/index.js +6 -6
- package/out/fr/index.js.map +1 -1
- package/out/fr/region.d.ts.map +1 -1
- package/out/fr/region.js +1 -1
- package/out/fr/region.js.map +1 -1
- package/out/fr/voie.d.ts.map +1 -1
- package/out/fr/voie.js +4 -11
- package/out/fr/voie.js.map +1 -1
- package/out/gb/country.d.ts.map +1 -1
- package/out/gb/country.js +1 -9
- package/out/gb/country.js.map +1 -1
- package/out/gb/index.d.ts +4 -4
- package/out/gb/index.d.ts.map +1 -1
- package/out/gb/index.js +4 -4
- package/out/gb/index.js.map +1 -1
- package/out/gb/postcode-area.d.ts +1 -1
- package/out/gb/postcode-area.d.ts.map +1 -1
- package/out/gb/postcode-area.js.map +1 -1
- package/out/gb/postcode.d.ts.map +1 -1
- package/out/gb/postcode.js.map +1 -1
- package/out/gb/street-type.d.ts +1 -1
- package/out/gb/street-type.d.ts.map +1 -1
- package/out/gb/street-type.js +1 -1
- package/out/gb/street-type.js.map +1 -1
- package/out/index.d.ts +12 -12
- package/out/index.d.ts.map +1 -1
- package/out/index.js +12 -12
- package/out/index.js.map +1 -1
- package/out/it/cap.d.ts +13 -2
- package/out/it/cap.d.ts.map +1 -1
- package/out/it/cap.js +20 -3
- package/out/it/cap.js.map +1 -1
- package/out/it/index.d.ts +1 -1
- package/out/it/index.d.ts.map +1 -1
- package/out/it/index.js +1 -1
- package/out/it/index.js.map +1 -1
- package/out/jp/address-unit.d.ts.map +1 -1
- package/out/jp/address-unit.js.map +1 -1
- package/out/jp/index.d.ts +4 -4
- package/out/jp/index.d.ts.map +1 -1
- package/out/jp/index.js +4 -4
- package/out/jp/index.js.map +1 -1
- package/out/jp/postal-code.d.ts +11 -11
- package/out/jp/postal-code.d.ts.map +1 -1
- package/out/jp/postal-code.js +8 -8
- package/out/jp/postal-code.js.map +1 -1
- package/out/jp/prefecture.d.ts +4 -1
- package/out/jp/prefecture.d.ts.map +1 -1
- package/out/jp/prefecture.js +6 -5
- package/out/jp/prefecture.js.map +1 -1
- package/out/level-semantics.d.ts.map +1 -1
- package/out/level-semantics.js.map +1 -1
- package/out/normalize.d.ts +8 -0
- package/out/normalize.d.ts.map +1 -1
- package/out/normalize.js +14 -1
- package/out/normalize.js.map +1 -1
- package/out/nz/delivery-service.d.ts +1 -1
- package/out/nz/delivery-service.d.ts.map +1 -1
- package/out/nz/delivery-service.js +1 -1
- package/out/nz/delivery-service.js.map +1 -1
- package/out/nz/index.d.ts +2 -2
- package/out/nz/index.d.ts.map +1 -1
- package/out/nz/index.js +2 -2
- package/out/nz/index.js.map +1 -1
- package/out/nz/postcode.d.ts.map +1 -1
- package/out/nz/postcode.js.map +1 -1
- package/out/postcode-systems.d.ts +99 -4
- package/out/postcode-systems.d.ts.map +1 -1
- package/out/postcode-systems.js +132 -11
- package/out/postcode-systems.js.map +1 -1
- package/out/tools/build-country-surface-lexicon.d.ts +1 -1
- package/out/tools/build-country-surface-lexicon.d.ts.map +1 -1
- package/out/tools/build-country-surface-lexicon.js +10 -9
- package/out/tools/build-country-surface-lexicon.js.map +1 -1
- package/out/tools/export-country-surfaces.d.ts +1 -1
- package/out/tools/export-country-surfaces.d.ts.map +1 -1
- package/out/tools/export-country-surfaces.js +7 -7
- package/out/tools/export-country-surfaces.js.map +1 -1
- package/out/tools/generate-country-population.d.ts +42 -0
- package/out/tools/generate-country-population.d.ts.map +1 -0
- package/out/tools/generate-country-population.js +106 -0
- package/out/tools/generate-country-population.js.map +1 -0
- package/out/tools/generate-country-reference.d.ts.map +1 -1
- package/out/tools/generate-country-reference.js +8 -8
- package/out/tools/generate-country-reference.js.map +1 -1
- package/out/tools/generate-official-languages.d.ts.map +1 -1
- package/out/tools/generate-official-languages.js +14 -11
- package/out/tools/generate-official-languages.js.map +1 -1
- package/out/tools/index.d.ts +4 -4
- package/out/tools/index.d.ts.map +1 -1
- package/out/tools/index.js +4 -4
- package/out/tools/index.js.map +1 -1
- package/out/us/floor-designator.d.ts.map +1 -1
- package/out/us/floor-designator.js.map +1 -1
- package/out/us/index.d.ts +8 -8
- package/out/us/index.d.ts.map +1 -1
- package/out/us/index.js +8 -8
- package/out/us/index.js.map +1 -1
- package/out/us/military-address.d.ts.map +1 -1
- package/out/us/military-address.js.map +1 -1
- package/out/us/po-box.d.ts +1 -1
- package/out/us/po-box.d.ts.map +1 -1
- package/out/us/po-box.js +1 -1
- package/out/us/po-box.js.map +1 -1
- package/out/us/state.d.ts.map +1 -1
- package/out/us/state.js.map +1 -1
- package/out/us/street-directional.d.ts.map +1 -1
- package/out/us/street-directional.js +2 -2
- package/out/us/street-directional.js.map +1 -1
- package/out/us/street-suffix.d.ts +1 -1
- package/out/us/street-suffix.d.ts.map +1 -1
- package/out/us/street-suffix.js +1 -1
- package/out/us/street-suffix.js.map +1 -1
- package/out/us/unit-designator.d.ts +1 -1
- package/out/us/unit-designator.d.ts.map +1 -1
- package/out/us/unit-designator.js +1 -1
- package/out/us/unit-designator.js.map +1 -1
- package/out/us/zipcode.d.ts +2 -2
- package/out/us/zipcode.d.ts.map +1 -1
- package/out/us/zipcode.js +2 -2
- package/out/us/zipcode.js.map +1 -1
- package/package.json +129 -6
- package/country/index.ts +0 -15
- package/postcode-systems.ts +0 -70
- /package/{au → lib/au}/delivery-service.ts +0 -0
- /package/{au → lib/au}/level-designator.ts +0 -0
- /package/{au → lib/au}/postcode.ts +0 -0
- /package/{au → lib/au}/state.ts +0 -0
- /package/{country → lib/country}/names.ts +0 -0
- /package/{country → lib/country}/official-languages.ts +0 -0
- /package/{country → lib/country}/reference-data.ts +0 -0
- /package/{de → lib/de}/bundesland.ts +0 -0
- /package/{de → lib/de}/street-type.ts +0 -0
- /package/{gb → lib/gb}/postcode.ts +0 -0
- /package/{jp → lib/jp}/address-unit.ts +0 -0
- /package/{level-semantics.ts → lib/level-semantics.ts} +0 -0
- /package/{nz → lib/nz}/postcode.ts +0 -0
- /package/{us → lib/us}/floor-designator.ts +0 -0
- /package/{us → lib/us}/military-address.ts +0 -0
- /package/{us → lib/us}/state.ts +0 -0
- /package/{us → lib/us}/street-suffix.json +0 -0
|
@@ -25,16 +25,26 @@ export {
|
|
|
25
25
|
ADDRESS_SYSTEM_CONVENTIONS,
|
|
26
26
|
conventionsForSystem,
|
|
27
27
|
type AddressSystemConventions,
|
|
28
|
-
} from "
|
|
28
|
+
} from "#address-system-conventions"
|
|
29
29
|
|
|
30
|
-
export * from "
|
|
31
|
-
export * as au from "
|
|
32
|
-
export * as ca from "
|
|
33
|
-
export * as de from "
|
|
34
|
-
export * as fr from "
|
|
35
|
-
export * as gb from "
|
|
36
|
-
export * as jp from "
|
|
37
|
-
export * as levels from "
|
|
38
|
-
export * as nz from "
|
|
39
|
-
|
|
40
|
-
export
|
|
30
|
+
export * from "#normalize"
|
|
31
|
+
export * as au from "#au/index"
|
|
32
|
+
export * as ca from "#ca/index"
|
|
33
|
+
export * as de from "#de/index"
|
|
34
|
+
export * as fr from "#fr/index"
|
|
35
|
+
export * as gb from "#gb/index"
|
|
36
|
+
export * as jp from "#jp/index"
|
|
37
|
+
export * as levels from "#level-semantics"
|
|
38
|
+
export * as nz from "#nz/index"
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
AREA_POSTCODE_FINER_THAN_LOCALITY,
|
|
42
|
+
areaPostcodeLeadsLocality,
|
|
43
|
+
candidateSystemsForPostcode,
|
|
44
|
+
isUnitGradePostcodeHit,
|
|
45
|
+
SYSTEM_CODES,
|
|
46
|
+
type SystemCode,
|
|
47
|
+
UNIT_GRADE_POSTCODE,
|
|
48
|
+
} from "#postcode-systems"
|
|
49
|
+
|
|
50
|
+
export * as us from "#us/index"
|
package/{it → lib/it}/cap.ts
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Italian
|
|
6
|
+
* Italian postcodes (Codice di Avviamento Postale, CAP): the branded type and the shape.
|
|
7
7
|
*
|
|
8
8
|
* Five digits like the Spanish, French and German forms, but do NOT infer a province from the
|
|
9
9
|
* leading digits the way `es/codigo-postal.ts` documents for Spain. Italy's large cities are
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import type { Tagged } from "type-fest"
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* An Italian
|
|
18
|
+
* An Italian postcode: five digits (`00184` is Rome, Rione Monti).
|
|
19
19
|
*
|
|
20
20
|
* @category Postal
|
|
21
21
|
* @type string
|
|
@@ -30,10 +30,28 @@ export type CAP = Tagged<string, "CAP">
|
|
|
30
30
|
export const CAP_PATTERN = /^\d{5}$/
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Normalize a CAP surface form to the bare five digits: trim surrounding whitespace (`" 00184 "` → `"00184"`). Returns
|
|
34
|
+
* null when the result is not a five-digit code.
|
|
34
35
|
*/
|
|
35
|
-
export function
|
|
36
|
-
|
|
36
|
+
export function normalizeCAP(raw: unknown): CAP | null {
|
|
37
|
+
if (typeof raw !== "string") return null
|
|
38
|
+
const s = raw.trim()
|
|
37
39
|
|
|
38
40
|
return CAP_PATTERN.test(s) ? (s as CAP) : null
|
|
39
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Type-predicate for a (normalized) Italian CAP.
|
|
45
|
+
*/
|
|
46
|
+
export function isCAP(input: unknown): input is CAP {
|
|
47
|
+
return typeof input === "string" && CAP_PATTERN.test(input)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Narrow a string to a {@link CAP}, or `null` when it is not one.
|
|
52
|
+
*
|
|
53
|
+
* @deprecated Use {@link normalizeCAP}.
|
|
54
|
+
*/
|
|
55
|
+
export function parseCAP(input: string): CAP | null {
|
|
56
|
+
return normalizeCAP(input)
|
|
57
|
+
}
|
package/{it → lib/it}/index.ts
RENAMED
package/{jp → lib/jp}/index.ts
RENAMED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* The Japanese address system (Japan Post / ISO 3166-2:JP): the 47 prefectures, the
|
|
6
|
+
* The Japanese address system (Japan Post / ISO 3166-2:JP): the 47 prefectures, the postcode
|
|
7
7
|
* that is the country's most reliable geographic anchor, and the address-unit markers that stand
|
|
8
8
|
* in for the street names Japan does not use.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
export * from "
|
|
12
|
-
export * from "
|
|
13
|
-
export * from "
|
|
11
|
+
export * from "#jp/address-unit"
|
|
12
|
+
export * from "#jp/postal-code"
|
|
13
|
+
export * from "#jp/prefecture"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Japanese
|
|
6
|
+
* Japanese postcodes (郵便番号, yūbin-bangō): the branded type, the shape, normalization, and the
|
|
7
7
|
* first-digit → coarse-region prior.
|
|
8
8
|
*
|
|
9
9
|
* This file is the far end of a spectrum whose other end is `us/zipcode.ts`. A US address leans on
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* navigate by named streets; you navigate by nested administrative areas and numbered
|
|
17
17
|
* blocks/lots (丁目 / 番地 / 号 — see `address-unit.ts`).
|
|
18
18
|
*
|
|
19
|
-
* With no street name to anchor on and a reverse field order, the **
|
|
19
|
+
* With no street name to anchor on and a reverse field order, the **postcode is the single most
|
|
20
20
|
* reliable geographic anchor** for a Japanese address — it pins the chōme-level area directly,
|
|
21
21
|
* far tighter than a US ZIP pins a US address. So where the US parser treats the postcode as a
|
|
22
22
|
* tie-breaker behind the street, the Japan parser should treat it as the primary key.
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
import type { Tagged } from "type-fest"
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* A Japanese
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* A Japanese postcode: three digits, a hyphen, then four digits (`100-0001`), conventionally written after the 〒 mark
|
|
29
|
+
* (`〒100-0001`). Branded so a normalized code is distinct from an arbitrary string — the 7-digit shape alone does not
|
|
30
|
+
* prove a code is real, only well-formed.
|
|
31
31
|
*
|
|
32
32
|
* @category Postal
|
|
33
33
|
* @type string
|
|
@@ -57,17 +57,17 @@ export function normalizeJpPostalCode(raw: unknown): PostalCode | null {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
* Type-predicate for a Japanese
|
|
60
|
+
* Type-predicate for a Japanese postcode (hyphen optional, `100-0001` or `1000001`).
|
|
61
61
|
*/
|
|
62
62
|
export function isJpPostalCode(input: unknown): input is PostalCode {
|
|
63
63
|
return typeof input === "string" && JP_POSTAL_CODE_PATTERN.test(input)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* First digit of the
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
67
|
+
* First digit of the postcode → a coarse region label. Japan Post's numbering grows roughly outward from Tokyo (`1xx`)
|
|
68
|
+
* and is **approximate** at this granularity — a single leading digit spans large, irregular areas and the boundaries
|
|
69
|
+
* are postal-routing, not administrative. Use it as a weak prior, never as a hard region assignment; the full code is
|
|
70
|
+
* what actually anchors the address.
|
|
71
71
|
*
|
|
72
72
|
* Approximate — the labels below are illustrative routing regions, not precise prefecture sets.
|
|
73
73
|
*/
|
|
@@ -85,7 +85,7 @@ export const JP_FIRST_DIGIT_REGION: Record<string, string> = {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* The coarse region label for a
|
|
88
|
+
* The coarse region label for a postcode's first digit, or null if the input is not a Japanese postcode. A weak,
|
|
89
89
|
* approximate prior (see {@link JP_FIRST_DIGIT_REGION}); the full code anchors the address.
|
|
90
90
|
*/
|
|
91
91
|
export function firstDigitRegion(postalCode: unknown): string | null {
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* The 47 Japanese prefectures (都道府県, todōfuken), keyed by their ISO 3166-2:JP code — the two-digit
|
|
7
7
|
* numeric string `"01"`..`"47"` standing in for `JP-01`..`JP-47`.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Compared to `fr/region.ts`, `de/bundesland.ts`, and `us/state.ts`,
|
|
10
|
+
* this is a more complex case because the top-level admin unit comes in four legally distinct flavours,
|
|
11
|
+
* and the prefecture name is written on the address line (not inferred from postcode).
|
|
12
|
+
*
|
|
10
13
|
* "都道府県" is four kanji because the top-level admin unit comes in four legally distinct flavours,
|
|
11
14
|
* even though all 47 are peers in practice:
|
|
12
15
|
*
|
|
@@ -23,6 +26,8 @@
|
|
|
23
26
|
* `postal-code.ts` for why the postcode is nonetheless the single most reliable anchor.
|
|
24
27
|
*/
|
|
25
28
|
|
|
29
|
+
import { foldToken } from "#normalize"
|
|
30
|
+
|
|
26
31
|
/**
|
|
27
32
|
* A to/dō/fu/ken classification of the top-level admin unit.
|
|
28
33
|
*/
|
|
@@ -130,10 +135,7 @@ export function isJapanesePrefectureCode(input: unknown): input is JapanesePrefe
|
|
|
130
135
|
* them. We never strip from an unseparated bare name, so `kyoto` stays `kyoto`.
|
|
131
136
|
*/
|
|
132
137
|
function foldRomaji(s: string): string {
|
|
133
|
-
const lowered = s
|
|
134
|
-
.toLowerCase()
|
|
135
|
-
.normalize("NFD")
|
|
136
|
-
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
138
|
+
const lowered = foldToken(s)
|
|
137
139
|
|
|
138
140
|
// Strip an appended type-suffix only when a separator (hyphen / space / middle dot) precedes it.
|
|
139
141
|
const desuffixed = lowered.replace(/[-\s·][\s]*(to|do|fu|ken)$/, "")
|
|
@@ -41,7 +41,7 @@ export function wordNorm(s: string): string {
|
|
|
41
41
|
return s
|
|
42
42
|
.split(/\s+/)
|
|
43
43
|
.map((w) => w.replaceAll(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu, ""))
|
|
44
|
-
.filter(
|
|
44
|
+
.filter((w) => w.length > 0)
|
|
45
45
|
.join(" ")
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -51,3 +51,17 @@ export function wordNorm(s: string): string {
|
|
|
51
51
|
export function wordNormLower(s: string): string {
|
|
52
52
|
return wordNorm(s).toLowerCase()
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Fold a single token to its lowercase, diacritic-free form: lower-cased, NFD-decomposed, combining marks stripped —
|
|
57
|
+
* `"Côte"` → `"cote"`, `"Tōkyō"` → `"tokyo"`.
|
|
58
|
+
*
|
|
59
|
+
* The shared core of the per-country token matchers. Unlike {@link foldName} it does not touch punctuation or whitespace
|
|
60
|
+
* — each matcher layers its own character filtering (letters-only, hyphen-keeping, suffix-stripping) on top.
|
|
61
|
+
*/
|
|
62
|
+
export function foldToken(s: string): string {
|
|
63
|
+
return s
|
|
64
|
+
.toLowerCase()
|
|
65
|
+
.normalize("NFD")
|
|
66
|
+
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
67
|
+
}
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* mail, accessed 2026-06-11) name only the six types above. However, real NZ mail and the postal
|
|
34
34
|
* arena's gold rows carry "Private Box" as a colloquial synonym for a numbered PO Box (same
|
|
35
35
|
* numbered format, different label). Operator ruling 2026-06-11: "Private Box = recognize-as-used
|
|
36
|
-
* — codex documents it unofficial/colloquial WITH the 'officially invalid' citation; the
|
|
36
|
+
* — codex documents it unofficial/colloquial WITH the 'officially invalid' citation; the extract
|
|
37
37
|
* teaches recognition (validity and recognition are separate disciplines, same as the AU legacy
|
|
38
38
|
* flags)." This is encoded in {@link NZ_PRIVATE_BOX_ALIAS} — a distinct export from
|
|
39
39
|
* {@link NZ_DELIVERY_SERVICE_TYPES} so callers can choose whether to include the unofficial form.
|
package/{nz → lib/nz}/index.ts
RENAMED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The inverse of the per-slice postcode patterns: given a postcode string, which address SYSTEMS
|
|
7
|
+
* could it belong to? Each codex slice owns its own postcode shape (`us` accepts
|
|
8
|
+
* `\d{5}(-\d{4})?`, `ca` accepts `A1A 1A1`, `jp` accepts `NNN-NNNN`, …); this is the single place
|
|
9
|
+
* that asks all of them at once and collects the matches.
|
|
10
|
+
*
|
|
11
|
+
* It is the shared source of truth for "which systems can this shape be" — consumed by the postcode
|
|
12
|
+
* anchor (to narrow which systems' street vocabularies it checks) and, in time, by the runtime
|
|
13
|
+
* pipeline's `@mailwoman/locale-hint` stage (so its format→locale scoring derives from the same patterns rather than
|
|
14
|
+
* a second, divergent copy). The point is to unify the DATA, not to couple the modules: callers
|
|
15
|
+
* depend on this pure function, never on each other.
|
|
16
|
+
*
|
|
17
|
+
* Note this is a SHAPE test, not a gazetteer-membership test. A bare `68161` matches the US,
|
|
18
|
+
* German, French, Spanish and Italian 5-digit shapes, so it returns `["us", "de", "fr", "es", "it"]` —
|
|
19
|
+
* the shape alone cannot split the numeric-postcode systems. The anchor uses real gazetteer membership for the finer
|
|
20
|
+
* call; this function answers the coarser, model-free "which systems is this shape even eligible
|
|
21
|
+
* for".
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { normalizeAuPostcode } from "#au/index"
|
|
25
|
+
import { normalizeCaPostalCode } from "#ca/index"
|
|
26
|
+
import { normalizePLZ } from "#de/index"
|
|
27
|
+
import { normalizeCodigoPostal } from "#es/index"
|
|
28
|
+
import { normalizeCodePostal } from "#fr/index"
|
|
29
|
+
import { normalizeUkPostcode } from "#gb/index"
|
|
30
|
+
import { normalizeCAP } from "#it/index"
|
|
31
|
+
import { normalizeJpPostalCode } from "#jp/index"
|
|
32
|
+
import { normalizeNZPostcode } from "#nz/index"
|
|
33
|
+
import { isZipCode } from "#us/index"
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A codex address-system code — the subpath under `@mailwoman/codex/<system>`.
|
|
37
|
+
*/
|
|
38
|
+
export type SystemCode = "us" | "de" | "fr" | "es" | "it" | "ca" | "gb" | "jp" | "au" | "nz"
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Per-system membership test: each entry returns true when the string is accepted by that system's own postcode shape
|
|
42
|
+
* (after that system's normalization — so `D-68161` reaches `de`, `1012 LM` reaches nothing here since NL has no slice
|
|
43
|
+
* yet, etc.). Ordered for a stable, alphabetical-ish result.
|
|
44
|
+
*/
|
|
45
|
+
const SYSTEM_ACCEPTS: ReadonlyArray<readonly [SystemCode, (s: string) => boolean]> = [
|
|
46
|
+
["us", (s) => isZipCode(s)],
|
|
47
|
+
["de", (s) => normalizePLZ(s) !== null],
|
|
48
|
+
["fr", (s) => normalizeCodePostal(s) !== null],
|
|
49
|
+
["es", (s) => normalizeCodigoPostal(s) !== null],
|
|
50
|
+
["it", (s) => normalizeCAP(s) !== null],
|
|
51
|
+
["ca", (s) => normalizeCaPostalCode(s) !== null],
|
|
52
|
+
["gb", (s) => normalizeUkPostcode(s) !== null],
|
|
53
|
+
["jp", (s) => normalizeJpPostalCode(s) !== null],
|
|
54
|
+
["au", (s) => normalizeAuPostcode(s) !== null],
|
|
55
|
+
["nz", (s) => normalizeNZPostcode(s) !== null],
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Every address system with a postcode shape, in {@link SYSTEM_ACCEPTS} order. The one list a consumer that needs the
|
|
60
|
+
* universe of systems (rather than the systems a given code fits) should read, so it cannot drift from the table.
|
|
61
|
+
*/
|
|
62
|
+
export const SYSTEM_CODES: readonly SystemCode[] = SYSTEM_ACCEPTS.map(([system]) => system)
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Every address system whose own postcode shape accepts `postcode`. Empty when no system recognizes the shape (e.g. a
|
|
66
|
+
* bare `27`, or a 7-digit run). O(number of systems) — a handful of cheap regex tests, run only on the few
|
|
67
|
+
* postcode-shaped spans an address contains.
|
|
68
|
+
*/
|
|
69
|
+
export function candidateSystemsForPostcode(postcode: string): SystemCode[] {
|
|
70
|
+
if (typeof postcode !== "string" || !postcode.length) return []
|
|
71
|
+
const out: SystemCode[] = []
|
|
72
|
+
|
|
73
|
+
for (const [system, accepts] of SYSTEM_ACCEPTS) {
|
|
74
|
+
if (accepts(postcode)) {
|
|
75
|
+
out.push(system)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return out
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Postcode shapes whose code is UNIT-GRADE — a delivery-walk or street-block unit, categorically tighter than any
|
|
84
|
+
* locality centroid, so an EXACT hit on one may lead the admin ladder instead of following the locality-first epoch
|
|
85
|
+
* convention.
|
|
86
|
+
*
|
|
87
|
+
* The convention exists because most postal systems are AREA-class: an FR 5-digit zone is coarser than the commune it
|
|
88
|
+
* contains, so promoting it would trade a good answer for a worse one. Two systems are the other way round, and
|
|
89
|
+
* membership here is earned by MEASUREMENT of the code's granularity, never by "the code has letters in it":
|
|
90
|
+
*
|
|
91
|
+
* - **NL PC6** (`1012 LG`) — ~8 addresses per code; the CBS polygon centroid (#977, the original carve-out).
|
|
92
|
+
* - **GB unit** (`N7 0BT`) — ~15 addresses per code, 1,751,733 shipped from OS Code-Point Open. Measured 2026-08-10
|
|
93
|
+
* against the panel-v2 GB rooftop truth: unit centroid within 1 km on 15/15 rows, median 38 m, max 100 m, while the
|
|
94
|
+
* locality centroid the ladder returned instead was 5.1–14.6 km out.
|
|
95
|
+
* - **CA URBAN LDU** (`M1J 1A8`) — 843,739 six-character codes. Measured on 879 graded rows of the CA OSM-rooftop panel,
|
|
96
|
+
* through the production candidate backend, ladder arm against ladder arm:
|
|
97
|
+
*
|
|
98
|
+
* | 732 URBAN rows | p50 | p75 | p90 | ≤1 km | | -------------- | ---: | ---: | ---: | ---: | | locality-first | 2.51
|
|
99
|
+
* km | 5.42 km | 9.53 km | 26.4% | | postcode-first | **78 m** | **162 m** | **373 m** | **94.7%** |
|
|
100
|
+
*
|
|
101
|
+
* Closer on 90.4% of them. That is GB's tier on a sample fifty times larger than GB's.
|
|
102
|
+
*
|
|
103
|
+
* **CA RURAL is excluded, and the code says which.** Canada Post puts a `0` in the SECOND position of a rural forward
|
|
104
|
+
* sortation area, so `T0H 1M0` is rural and `M1J 1A8` is not — no lookup required. A rural LDU serves a delivery route
|
|
105
|
+
* rather than a block face, and it measures like one. On the same panel, the 114 rural rows:
|
|
106
|
+
*
|
|
107
|
+
* | 114 RURAL rows | p50 | p75 | p90 | ≤1 km |
|
|
108
|
+
* | -------------- | --------: | ----------: | ----------: | --------: |
|
|
109
|
+
* | locality-first | **929 m** | **2.02 km** | **5.73 km** | **53.5%** |
|
|
110
|
+
* | postcode-first | 2.08 km | 4.79 km | 8.11 km | 25.4% |
|
|
111
|
+
*
|
|
112
|
+
* Postcode-first is closer on only 26.3% of them, so the pattern below admits `[1-9]` in that position and nothing
|
|
113
|
+
* else. `509 Main Street South-West Falher AB T0H 1M0` is the worked case: 0.29 km from the locality centroid and 43.18
|
|
114
|
+
* km from its own postal code.
|
|
115
|
+
*
|
|
116
|
+
* The pooled CA number hides that entirely — 0.10 km p50 across both populations reads as a uniform win and is not one.
|
|
117
|
+
* A tier claim that averages two granularities is the thing this table exists to prevent.
|
|
118
|
+
*
|
|
119
|
+
* Lives in codex (per-address-system postal reference) so the Node result assembly (`mailwoman/geocode-core`) and the
|
|
120
|
+
* demo's pin ranking consume ONE tier definition — the 2026-08-11 staged-repoint e2e measured the two disagreeing.
|
|
121
|
+
*/
|
|
122
|
+
export const UNIT_GRADE_POSTCODE: ReadonlyArray<RegExp> = [
|
|
123
|
+
// NL PC6 — `1012 LG` / `1012LG`.
|
|
124
|
+
/^\d{4}\s?[A-Z]{2}$/i,
|
|
125
|
+
// GB unit — outward (1-2 letters + digit + optional alnum) + inward `\d[A-Z]{2}`, the same shape
|
|
126
|
+
// `@mailwoman/codex/gb`'s UK_POSTCODE_PATTERN anchors, restated here so this module stays
|
|
127
|
+
// dependency-free within the package (the slices import THIS, never the reverse).
|
|
128
|
+
/^[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2}$/i,
|
|
129
|
+
// CA urban LDU — `M1J 1A8`. The `[1-9]` in the second position is the whole tier claim: a `0` there marks a RURAL
|
|
130
|
+
// forward sortation area, which measures 2.08 km p50 against the locality's 929 m and does not belong here.
|
|
131
|
+
/^[A-Z][1-9][A-Z]\s?\d[A-Z]\d$/i,
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Strip everything but letters and digits, upper-cased — the comparison surface for "did the resolver hit the FULL code
|
|
136
|
+
* or a coarser stem?". `N7 0BT` and `N70BT` are the same code; `N7` is not.
|
|
137
|
+
*/
|
|
138
|
+
const alnum = (s: string): string => s.replaceAll(/[^\p{L}\p{N}]/gu, "").toUpperCase()
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* True when a resolved postcode is an EXACT hit on a unit-grade code — the #977 three-way guard, shared by the Node
|
|
142
|
+
* ladder and the demo pin ranking:
|
|
143
|
+
*
|
|
144
|
+
* 1. The PARSED span is a full unit shape ({@link UNIT_GRADE_POSTCODE}), not a stem the user typed;
|
|
145
|
+
* 2. The node resolved (a coordinate is present — checked by the caller); and
|
|
146
|
+
* 3. The resolver's own hit is the FULL code, not a coarsened prefix (a 4-digit NL stem or a GB outward district is
|
|
147
|
+
* AREA-class, and promoting it is the exact trade the epoch convention forbids).
|
|
148
|
+
*/
|
|
149
|
+
export function isUnitGradePostcodeHit(parsed: string, resolverName: string | undefined): boolean {
|
|
150
|
+
const value = parsed.trim()
|
|
151
|
+
|
|
152
|
+
if (!value || !UNIT_GRADE_POSTCODE.some((re) => re.test(value))) return false
|
|
153
|
+
|
|
154
|
+
return alnum(resolverName ?? "") === alnum(value)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Address systems whose AREA-grade postal code is still FINER than the locality containing it — the third granularity
|
|
159
|
+
* tier, between {@link UNIT_GRADE_POSTCODE} and the locality-first default.
|
|
160
|
+
*
|
|
161
|
+
* Whether a postal zone is coarser than its locality is a fact about a country's ADMINISTRATIVE geography, not about
|
|
162
|
+
* its postal system, and code length does not predict it: FR and DE are both 5-digit and land on opposite sides. France
|
|
163
|
+
* has ~35,000 communes and one code postal often spans several, so the commune is finer. A German Gemeinde can be
|
|
164
|
+
* enormous — Berlin is one WOF locality — so the PLZ is finer by a wide margin.
|
|
165
|
+
*
|
|
166
|
+
* Membership is earned by a full-panel measurement, the same bar {@link UNIT_GRADE_POSTCODE} sets for CA. Coordinate
|
|
167
|
+
* p50 on the OpenAddresses panels, locality-first (the default) against the postcode point:
|
|
168
|
+
*
|
|
169
|
+
* | country | rows | locality-first | postcode point | verdict |
|
|
170
|
+
* | ------- | ----: | -------------: | -------------: | ---------------------------------------------------------------------- |
|
|
171
|
+
* | **DE** | 2,997 | 5.84 km | **1.24 km** | postcode, on EVERY percentile incl. p99 (21.50 → 10.57) |
|
|
172
|
+
* | FR | 3,000 | **0.97 km** | 2.64 km | locality, closer on 77.5% of rows |
|
|
173
|
+
* | IT | 2,833 | **1.34 km** | 3.05 km | locality, closer on 66.4% |
|
|
174
|
+
* | ES | 2,929 | **0.68 km** | 0.97 km | locality, but near a coin flip — 46.1% of rows prefer the postcode |
|
|
175
|
+
* | US | 577 | **2.28 km** | 4.15 km | locality (see below) |
|
|
176
|
+
* | **JP** | 586 | 4.93 km | **0.48 km** | postcode, closer on 97.3% of rows (p90 13.55 → 1.21, p99 19.63 → 3.54) |
|
|
177
|
+
*
|
|
178
|
+
* **The US row is measured on the population production actually sends to the ladder.** Its rooftop cascade is US-only
|
|
179
|
+
* by construction (`selectAddressPointsDB` composes `address-points-us-<slug>.db`), and it serves 94.2% of US queries,
|
|
180
|
+
* so only 577 of 10,000 panel rows reach an admin decision at all. Those are the rows no rooftop or interpolation
|
|
181
|
+
* extract could place, which skews rural — exactly where a locality centroid sits close and a ZIP zone is wide.
|
|
182
|
+
* Measured over all 10,000 rows instead, the US looks like a postcode-first country (2.41 km vs 3.63); that is a
|
|
183
|
+
* selection effect, and it is why this table reports 577 rows for the US and full panels for the others, which have no
|
|
184
|
+
* such cascade.
|
|
185
|
+
*
|
|
186
|
+
* **The JP row is the JP board through the served path** (`jp-served-resolve.run.ts`, 2,000 rows, seed 42): the 586
|
|
187
|
+
* rows carrying a postcode the candidate table keys, graded on the row's own entrance point — the locality-first answer
|
|
188
|
+
* is the municipality centroid, the postcode answer the code's 町域 centroid from the WOF extract.
|
|
189
|
+
*/
|
|
190
|
+
export const AREA_POSTCODE_FINER_THAN_LOCALITY: ReadonlySet<string> = new Set(["DE", "JP"])
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* True when this country's area-grade postal code outranks its locality. Absent or unknown country → false, so the
|
|
194
|
+
* locality-first convention is what an unscoped query gets.
|
|
195
|
+
*/
|
|
196
|
+
export function areaPostcodeLeadsLocality(country: string | undefined): boolean {
|
|
197
|
+
return country !== undefined && AREA_POSTCODE_FINER_THAN_LOCALITY.has(country.trim().toUpperCase())
|
|
198
|
+
}
|
|
@@ -34,18 +34,19 @@
|
|
|
34
34
|
*
|
|
35
35
|
* Source of truth: `@mailwoman/codex` (COUNTRY_SURFACE_FORMS + ISO2_TO_NAME) — the SAME data the
|
|
36
36
|
* corpus-python bridge `country-surfaces.json` is generated from (export-country-surfaces.ts), so
|
|
37
|
-
* the channel and the corpus
|
|
37
|
+
* the channel and the corpus extract synthesizer cannot diverge on what a country surface IS.
|
|
38
38
|
*
|
|
39
39
|
* Output: data/gazetteer/country-surface-lexicon-v1.json (small, committed, provenance-tracked).
|
|
40
40
|
* Regenerate: `node codex/tools/build-country-surface-lexicon.ts`
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
43
|
+
import { makeDirectories, writeLocalTextFile } from "@mailwoman/core/fs/writers"
|
|
44
|
+
import { repoRootPath } from "@mailwoman/core/paths"
|
|
45
|
+
import { dirname } from "path-ts"
|
|
45
46
|
|
|
46
|
-
import { COUNTRY_SURFACE_FORMS, ISO2_TO_NAME } from "
|
|
47
|
-
import { wordNorm, wordNormLower } from "
|
|
48
|
-
import { US_STATE_ABBREVIATIONS, US_STATE_NAMES } from "
|
|
47
|
+
import { COUNTRY_SURFACE_FORMS, ISO2_TO_NAME } from "#country/country"
|
|
48
|
+
import { wordNorm, wordNormLower } from "#normalize"
|
|
49
|
+
import { US_STATE_ABBREVIATIONS, US_STATE_NAMES } from "#us/state"
|
|
49
50
|
|
|
50
51
|
/**
|
|
51
52
|
* Ambiguous entries printed before the list is truncated.
|
|
@@ -64,7 +65,7 @@ const SLOTS = ["country_surface", "country_ambiguous"]
|
|
|
64
65
|
* Committed output path (a codex-derived artifact, like export-country-surfaces.ts — no argv, so the no-process-globals
|
|
65
66
|
* lint policy holds; codex stays zero-runtime-dep).
|
|
66
67
|
*/
|
|
67
|
-
const OUTPUT =
|
|
68
|
+
const OUTPUT = repoRootPath("data", "gazetteer", "country-surface-lexicon-v1.json")
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* THE shared word-normalization rule (identical to build-gazetteer-anchor-lexicon.mjs and mirrored in
|
|
@@ -167,8 +168,8 @@ const lexicon = {
|
|
|
167
168
|
code_entries: Object.fromEntries([...codeEntries].toSorted(([a], [b]) => a.localeCompare(b))),
|
|
168
169
|
}
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
|
|
171
|
+
await makeDirectories(dirname(OUTPUT))
|
|
172
|
+
await writeLocalTextFile(JSON.stringify(lexicon, null, 1) + "\n", OUTPUT)
|
|
172
173
|
|
|
173
174
|
process.stderr.write(
|
|
174
175
|
`wrote ${OUTPUT}: ${entries.size} entries + ${codeEntries.size} code_entries, ` +
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
6
|
* codex → corpus-python bridge: emit the authoritative country surface forms as JSON so the Python
|
|
7
|
-
*
|
|
7
|
+
* extract generators can synthesize address tails ("…, USA" / "…, United States of America") without
|
|
8
8
|
* re-deriving the country name/alias data. `@mailwoman/codex` stays the single source of truth
|
|
9
9
|
* (COUNTRY_SURFACE_FORMS + ISO2_TO_NAME, salvaged from isp-nexus spatial/countries); this writes a
|
|
10
10
|
* snapshot the language boundary can't import directly.
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* Regenerate: `node codex/tools/export-country-surfaces.ts` (writes the corpus-python data file).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { writeLocalTextFile } from "@mailwoman/core/fs/writers"
|
|
16
|
+
import { repoRootPath } from "@mailwoman/core/paths"
|
|
17
17
|
|
|
18
|
-
import { COUNTRY_SURFACE_FORMS, ISO2_TO_NAME } from "
|
|
18
|
+
import { COUNTRY_SURFACE_FORMS, ISO2_TO_NAME } from "#country/country"
|
|
19
19
|
|
|
20
20
|
// Merge: rich surface forms where the codex curates them, else the canonical English name for every
|
|
21
21
|
// ISO 3166-1 alpha-2. Canonical-name-first (the codex's own ordering) so the common form leads.
|
|
@@ -31,10 +31,9 @@ for (const [iso2, name] of ISO2_TO_NAME) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const out =
|
|
34
|
+
const out = repoRootPath("corpus-python", "src", "mailwoman_train", "data", "country-surfaces.json")
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
out,
|
|
36
|
+
await writeLocalTextFile(
|
|
38
37
|
JSON.stringify(
|
|
39
38
|
{
|
|
40
39
|
_generated: "codex/tools/export-country-surfaces.ts from @mailwoman/codex COUNTRY_SURFACE_FORMS + ISO2_TO_NAME",
|
|
@@ -42,7 +41,8 @@ writeFileSync(
|
|
|
42
41
|
},
|
|
43
42
|
null,
|
|
44
43
|
2
|
|
45
|
-
) + "\n"
|
|
44
|
+
) + "\n",
|
|
45
|
+
out
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
process.stderr.write(`wrote ${Object.keys(surfaces).length} countries → ${out}\n`)
|