@mailwoman/codex 8.5.0 → 9.0.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 +1 -1
- package/ca/province.ts +2 -12
- package/country/subdivision.ts +1 -12
- package/es/codigo-postal.ts +51 -0
- package/es/index.ts +9 -0
- package/fr/region.ts +2 -12
- package/gb/postcode-area.ts +10 -0
- package/index.ts +1 -0
- package/it/cap.ts +39 -0
- package/it/index.ts +9 -0
- package/normalize.ts +53 -0
- package/nz/delivery-service.ts +17 -17
- package/nz/postcode.ts +4 -4
- package/out/ca/province.d.ts.map +1 -1
- package/out/ca/province.js +1 -11
- package/out/ca/province.js.map +1 -1
- package/out/country/subdivision.d.ts.map +1 -1
- package/out/country/subdivision.js +1 -11
- package/out/country/subdivision.js.map +1 -1
- package/out/es/codigo-postal.d.ts +39 -0
- package/out/es/codigo-postal.d.ts.map +1 -0
- package/out/es/codigo-postal.js +35 -0
- package/out/es/codigo-postal.js.map +1 -0
- package/out/es/index.d.ts +9 -0
- package/out/es/index.d.ts.map +1 -0
- package/out/es/index.js +9 -0
- package/out/es/index.js.map +1 -0
- package/out/fr/region.d.ts.map +1 -1
- package/out/fr/region.js +1 -11
- package/out/fr/region.js.map +1 -1
- package/out/gb/postcode-area.d.ts +9 -0
- package/out/gb/postcode-area.d.ts.map +1 -1
- package/out/gb/postcode-area.js +9 -0
- package/out/gb/postcode-area.js.map +1 -1
- package/out/index.d.ts +1 -0
- package/out/index.d.ts.map +1 -1
- package/out/index.js +1 -0
- package/out/index.js.map +1 -1
- package/out/it/cap.d.ts +32 -0
- package/out/it/cap.d.ts.map +1 -0
- package/out/it/cap.js +25 -0
- package/out/it/cap.js.map +1 -0
- package/out/it/index.d.ts +9 -0
- package/out/it/index.d.ts.map +1 -0
- package/out/it/index.js +9 -0
- package/out/it/index.js.map +1 -0
- package/out/normalize.d.ts +36 -0
- package/out/normalize.d.ts.map +1 -0
- package/out/normalize.js +51 -0
- package/out/normalize.js.map +1 -0
- package/out/nz/delivery-service.d.ts +10 -10
- package/out/nz/delivery-service.js +5 -5
- package/out/nz/postcode.d.ts +3 -3
- package/out/nz/postcode.js +2 -2
- package/out/postcode-systems.js +2 -2
- package/out/tools/build-country-surface-lexicon.js +2 -7
- package/out/tools/build-country-surface-lexicon.js.map +1 -1
- package/out/tools/generate-official-languages.d.ts.map +1 -1
- package/out/tools/generate-official-languages.js +4 -2
- package/out/tools/generate-official-languages.js.map +1 -1
- package/package.json +18 -2
- package/postcode-systems.ts +2 -2
- package/tools/build-country-surface-lexicon.ts +2 -10
- package/tools/generate-official-languages.ts +6 -1
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ questions, different tables.
|
|
|
92
92
|
|
|
93
93
|
- [`@mailwoman/core`](../core) — `ComponentTag` schema, pipeline infrastructure
|
|
94
94
|
- [`@mailwoman/address-id`](../address-id) — uses codex for stable address primary keys
|
|
95
|
-
- [Address system conventions](https://
|
|
95
|
+
- [Address system conventions](https://github.com/sister-software/mailwoman/blob/main/docs/engineering/reference/SCHEMA.mdx)
|
|
96
96
|
|
|
97
97
|
## License
|
|
98
98
|
|
package/ca/province.ts
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
* regions, the Canadian code IS a surface form, not just a resolver key.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { foldName } from "../normalize.ts"
|
|
20
|
+
|
|
19
21
|
/**
|
|
20
22
|
* Per-province record: ISO 3166-2:CA code, English name, and the co-official French name.
|
|
21
23
|
*/
|
|
@@ -68,18 +70,6 @@ export function isCanadianProvinceCode(input: unknown): input is CanadianProvinc
|
|
|
68
70
|
return typeof input === "string" && PROVINCE_CODE_SET.has(input.toUpperCase())
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
/**
|
|
72
|
-
* Strip diacritics + lowercase so `Québec`, `Quebec`, and `quebec` all key alike.
|
|
73
|
-
*/
|
|
74
|
-
function foldName(s: string): string {
|
|
75
|
-
return s
|
|
76
|
-
.toLowerCase()
|
|
77
|
-
.normalize("NFD")
|
|
78
|
-
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
79
|
-
.replaceAll(/[^a-z0-9]+/g, " ")
|
|
80
|
-
.trim()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
73
|
/**
|
|
84
74
|
* Folded province name (English or French) / code → ISO 3166-2:CA code. Built diacritic-insensitive so both co-official
|
|
85
75
|
* names map regardless of accents: `Québec`, `Quebec`, and an unaccented `Nouvelle-Ecosse` all resolve. The two-name
|
package/country/subdivision.ts
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { CA_PROVINCES } from "../ca/province.ts"
|
|
30
|
+
import { foldName } from "../normalize.ts"
|
|
30
31
|
import { US_STATE_BY_ABBREVIATION } from "../us/state.ts"
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -47,18 +48,6 @@ export interface SubdivisionMatch {
|
|
|
47
48
|
country: string
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
-
* Strip diacritics + lowercase so `Québec`, `Quebec`, and `quebec` all key alike (mirrors `ca/province.ts`).
|
|
52
|
-
*/
|
|
53
|
-
function foldName(s: string): string {
|
|
54
|
-
return s
|
|
55
|
-
.toLowerCase()
|
|
56
|
-
.normalize("NFD")
|
|
57
|
-
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
58
|
-
.replaceAll(/[^a-z0-9]+/g, " ")
|
|
59
|
-
.trim()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
51
|
/**
|
|
63
52
|
* Folded surface form (ISO code, English name, or — for CA — co-official French name) → subdivision. Built once. US
|
|
64
53
|
* states are inserted first and never overwritten, so on the (currently empty) event of a future code/name collision
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Spanish postal codes (código postal): the branded type, the shape, and the province prior.
|
|
7
|
+
*
|
|
8
|
+
* The contrast with a German PLZ is the informative part. A PLZ's leading digit maps to a Leitzone
|
|
9
|
+
* that deliberately CROSSES state borders, so it cannot tell you the Bundesland. A Spanish código
|
|
10
|
+
* postal is the opposite: its first TWO digits are the province code, assigned alphabetically
|
|
11
|
+
* (01 Álava … 28 Madrid … 50 Zaragoza), so the province is derivable from the postcode exactly.
|
|
12
|
+
* Code that wants a Spanish region from an address can read it off the postcode; code that wants a
|
|
13
|
+
* German one cannot.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { Tagged } from "type-fest"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A Spanish postal code: five digits, `PPNNN`, where `PP` is the province (`28001` is Madrid).
|
|
20
|
+
*
|
|
21
|
+
* @category Postal
|
|
22
|
+
* @type string
|
|
23
|
+
* @title CodigoPostal
|
|
24
|
+
* @pattern ^\d{5}$
|
|
25
|
+
*/
|
|
26
|
+
export type CodigoPostal = Tagged<string, "CodigoPostal">
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Shape of a Spanish código postal — five digits. Identical in shape to a French code postal, a German PLZ and a US
|
|
30
|
+
* ZIP; disambiguation is the parser's job, not the pattern's.
|
|
31
|
+
*/
|
|
32
|
+
export const CODIGO_POSTAL_PATTERN = /^\d{5}$/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Narrow a string to a {@link CodigoPostal}, or `null` when it is not one.
|
|
36
|
+
*/
|
|
37
|
+
export function parseCodigoPostal(input: string): CodigoPostal | null {
|
|
38
|
+
const s = input.trim()
|
|
39
|
+
|
|
40
|
+
return CODIGO_POSTAL_PATTERN.test(s) ? (s as CodigoPostal) : null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The two-digit province prefix (`"28001"` → `"28"`), or `null` for a non-postcode. Callers map it through their own
|
|
45
|
+
* province table; this module deliberately does not ship one, since the campaign that needed it only needs the shape.
|
|
46
|
+
*/
|
|
47
|
+
export function codigoPostalProvincePrefix(input: string): string | null {
|
|
48
|
+
const code = parseCodigoPostal(input)
|
|
49
|
+
|
|
50
|
+
return code ? code.slice(0, 2) : null
|
|
51
|
+
}
|
package/es/index.ts
ADDED
package/fr/region.ts
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* `code-postal.ts`).
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { foldName } from "../normalize.ts"
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* Per-region record: ISO 3166-2:FR code (sans `FR-` prefix) + French name.
|
|
18
20
|
*/
|
|
@@ -65,18 +67,6 @@ export function isFrenchRegionCode(input: unknown): input is FrenchRegionCode {
|
|
|
65
67
|
return typeof input === "string" && REGION_CODE_SET.has(input.toUpperCase())
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
/**
|
|
69
|
-
* Strip diacritics + lowercase so `Île-de-France`, `ile-de-france`, `Ile de France` all key alike.
|
|
70
|
-
*/
|
|
71
|
-
function foldName(s: string): string {
|
|
72
|
-
return s
|
|
73
|
-
.toLowerCase()
|
|
74
|
-
.normalize("NFD")
|
|
75
|
-
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
76
|
-
.replaceAll(/[^a-z0-9]+/g, " ")
|
|
77
|
-
.trim()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
70
|
/**
|
|
81
71
|
* Folded region name / code → ISO 3166-2:FR code. Built diacritic-insensitive so the resolver's surface form
|
|
82
72
|
* (`Île-de-France`, or an unaccented `Ile-de-France`) maps regardless of accents. Mirrors `de/bundesland.ts`'s
|
package/gb/postcode-area.ts
CHANGED
|
@@ -76,6 +76,16 @@ export const GB_POSTCODE_AREA_COUNTRY: Record<string, UkCountryCode> = {
|
|
|
76
76
|
...Object.fromEntries(WALES_AREAS.map((a) => [a, "WLS" as const])),
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* The two postcode areas whose assignment in {@link GB_POSTCODE_AREA_COUNTRY} is a MAJORITY call rather than a fact —
|
|
81
|
+
* TD (Galashiels) straddles the Scotland/England border and SY (Shrewsbury) straddles the Wales/England border, and
|
|
82
|
+
* both carry real postcodes on the other side of the line. The header above documents them in prose; this is the same
|
|
83
|
+
* knowledge in a form a build can read, so an artifact that ASSERTS ancestry per postcode district can withhold the
|
|
84
|
+
* constituent country here instead of asserting a coin-flip. Consumers that only want the coarse majority answer keep
|
|
85
|
+
* using {@link countryOfPostcodeArea} and ignore this.
|
|
86
|
+
*/
|
|
87
|
+
export const GB_BORDER_STRADDLING_AREAS: ReadonlySet<string> = new Set(["TD", "SY"])
|
|
88
|
+
|
|
79
89
|
/**
|
|
80
90
|
* True when `area` looks like a valid postcode-area string: one or two ASCII letters.
|
|
81
91
|
*/
|
package/index.ts
CHANGED
package/it/cap.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Italian postal codes (Codice di Avviamento Postale, CAP): the branded type and the shape.
|
|
7
|
+
*
|
|
8
|
+
* Five digits like the Spanish, French and German forms, but do NOT infer a province from the
|
|
9
|
+
* leading digits the way `es/codigo-postal.ts` documents for Spain. Italy's large cities are
|
|
10
|
+
* assigned RANGES rather than a single code (Rome spans 00118–00199, Milan 20121–20162), and
|
|
11
|
+
* several provinces share leading digits, so the CAP narrows geography without identifying a
|
|
12
|
+
* province. It is the same trap German PLZ Leitzonen set, in a different disguise.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { Tagged } from "type-fest"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An Italian postal code: five digits (`00184` is Rome, Rione Monti).
|
|
19
|
+
*
|
|
20
|
+
* @category Postal
|
|
21
|
+
* @type string
|
|
22
|
+
* @title CAP
|
|
23
|
+
* @pattern ^\d{5}$
|
|
24
|
+
*/
|
|
25
|
+
export type CAP = Tagged<string, "CAP">
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Shape of an Italian CAP — five digits.
|
|
29
|
+
*/
|
|
30
|
+
export const CAP_PATTERN = /^\d{5}$/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Narrow a string to a {@link CAP}, or `null` when it is not one.
|
|
34
|
+
*/
|
|
35
|
+
export function parseCAP(input: string): CAP | null {
|
|
36
|
+
const s = input.trim()
|
|
37
|
+
|
|
38
|
+
return CAP_PATTERN.test(s) ? (s as CAP) : null
|
|
39
|
+
}
|
package/it/index.ts
ADDED
package/normalize.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Name-normalization primitives shared across the codex tables and the lexicon builders that read
|
|
7
|
+
* them.
|
|
8
|
+
*
|
|
9
|
+
* These live in `@mailwoman/codex` rather than in `core` or `normalize` for one reason: codex is
|
|
10
|
+
* the zero-runtime-dependency reference package, and everything that needs to match a name against
|
|
11
|
+
* a codex table already depends on it. Putting the folding rules next to the tables they fold
|
|
12
|
+
* means a lookup and its table can never disagree about what counts as the same name.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Fold a name to its ASCII match key: lower-cased, accents stripped, every run of non-alphanumerics collapsed to a
|
|
18
|
+
* single space.
|
|
19
|
+
*
|
|
20
|
+
* This is the aggressive fold used to match a user's surface form against a codex table — `"Québec"` and `"QUEBEC"` and
|
|
21
|
+
* `"quebec"` all become `"quebec"`. It is lossy by design and never used to render anything back to a user.
|
|
22
|
+
*/
|
|
23
|
+
export function foldName(s: string): string {
|
|
24
|
+
return s
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.normalize("NFD")
|
|
27
|
+
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
28
|
+
.replaceAll(/[^a-z0-9]+/g, " ")
|
|
29
|
+
.trim()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Strip leading and trailing punctuation from every whitespace-separated word, dropping words that were nothing but
|
|
34
|
+
* punctuation, and rejoin on single spaces.
|
|
35
|
+
*
|
|
36
|
+
* Unlike {@link foldName} this preserves case and non-Latin scripts — it works on Unicode letter and number classes, so
|
|
37
|
+
* `"Кыргызстан,"` and `"日本 。"` survive with their content intact. That is what makes it the right normalizer for
|
|
38
|
+
* building surface lexicons, where the entry has to remain renderable, and the wrong one for building a match key.
|
|
39
|
+
*/
|
|
40
|
+
export function wordNorm(s: string): string {
|
|
41
|
+
return s
|
|
42
|
+
.split(/\s+/)
|
|
43
|
+
.map((w) => w.replaceAll(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu, ""))
|
|
44
|
+
.filter(Boolean)
|
|
45
|
+
.join(" ")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* {@link wordNorm}, lower-cased — the case-insensitive lexicon key.
|
|
50
|
+
*/
|
|
51
|
+
export function wordNormLower(s: string): string {
|
|
52
|
+
return wordNorm(s).toLowerCase()
|
|
53
|
+
}
|
package/nz/delivery-service.ts
CHANGED
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
/**
|
|
46
46
|
* Identifier requirement per ADV358's Delivery Service Elements rules.
|
|
47
47
|
*/
|
|
48
|
-
export type
|
|
48
|
+
export type NZIdentifierRule = "required-if-allocated" | "optional" | "not-used"
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* One Delivery Service Type row from ADV358.
|
|
52
52
|
*/
|
|
53
|
-
export interface
|
|
53
|
+
export interface NZDeliveryServiceType {
|
|
54
54
|
/**
|
|
55
55
|
* The Delivery Service Type, verbatim casing per ADV358 ("PO Box", "Private Bag", "CMB").
|
|
56
56
|
*/
|
|
@@ -64,7 +64,7 @@ export interface NzDeliveryServiceType {
|
|
|
64
64
|
* none ("not used … for Private Bags that do not have an identifier allocated by New Zealand Post"); Counter Delivery
|
|
65
65
|
* and Poste Restante never carry one.
|
|
66
66
|
*/
|
|
67
|
-
identifier:
|
|
67
|
+
identifier: NZIdentifierRule
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
@@ -89,12 +89,12 @@ export const NZ_DELIVERY_SERVICE_TYPES = [
|
|
|
89
89
|
description: "Hold for Poste Restante collection - international mail",
|
|
90
90
|
identifier: "not-used",
|
|
91
91
|
},
|
|
92
|
-
] as const satisfies readonly
|
|
92
|
+
] as const satisfies readonly NZDeliveryServiceType[]
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
95
|
* A canonical NZ Delivery Service Type.
|
|
96
96
|
*/
|
|
97
|
-
export type
|
|
97
|
+
export type NZDeliveryServiceTypeName = (typeof NZ_DELIVERY_SERVICE_TYPES)[number]["type"]
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
100
|
* Metadata for the colloquial "Private Box" alias (see the module header and operator ruling 2026-06-11). Kept separate
|
|
@@ -121,7 +121,7 @@ export const NZ_PRIVATE_BOX_ALIAS = {
|
|
|
121
121
|
/**
|
|
122
122
|
* Identifier rule mirrors PO Box: a number is expected when the alias is used with one.
|
|
123
123
|
*/
|
|
124
|
-
identifier: "required-if-allocated" satisfies
|
|
124
|
+
identifier: "required-if-allocated" satisfies NZIdentifierRule,
|
|
125
125
|
/**
|
|
126
126
|
* True — this form is NOT valid per ADV358 or NZ Post's live standards pages (accessed 2026-06-11).
|
|
127
127
|
*/
|
|
@@ -136,7 +136,7 @@ export const NZ_PRIVATE_BOX_ALIAS = {
|
|
|
136
136
|
* The colloquial "Private Box" alias is included for recognition (see {@link NZ_PRIVATE_BOX_ALIAS} and operator ruling
|
|
137
137
|
* 2026-06-11); it maps to a distinct synthetic type string so callers can distinguish it from the ADV358 types.
|
|
138
138
|
*/
|
|
139
|
-
const TYPE_PATTERNS: ReadonlyArray<readonly [
|
|
139
|
+
const TYPE_PATTERNS: ReadonlyArray<readonly [NZDeliveryServiceTypeName | "Private Box", string]> = [
|
|
140
140
|
["PO Box", String.raw`p\.?\s*o\.?\s*box|post\s+box`],
|
|
141
141
|
["Private Bag", String.raw`private\s+bag`],
|
|
142
142
|
["Private Box", String.raw`private\s+box`],
|
|
@@ -149,9 +149,9 @@ const TYPE_PATTERNS: ReadonlyArray<readonly [NzDeliveryServiceTypeName | "Privat
|
|
|
149
149
|
/**
|
|
150
150
|
* Extended type name union including the colloquial alias recognized for parsing.
|
|
151
151
|
*/
|
|
152
|
-
export type
|
|
152
|
+
export type NZDeliveryServiceMatchTypeName = NZDeliveryServiceTypeName | "Private Box"
|
|
153
153
|
|
|
154
|
-
const IDENTIFIER_RULES = new Map<
|
|
154
|
+
const IDENTIFIER_RULES = new Map<NZDeliveryServiceMatchTypeName, NZIdentifierRule>([
|
|
155
155
|
...NZ_DELIVERY_SERVICE_TYPES.map((t) => [t.type, t.identifier] as const),
|
|
156
156
|
// "Private Box" mirrors PO Box identifier rules (required-if-allocated) per the alias metadata.
|
|
157
157
|
["Private Box", NZ_PRIVATE_BOX_ALIAS.identifier],
|
|
@@ -161,7 +161,7 @@ const IDENTIFIER_RULES = new Map<NzDeliveryServiceMatchTypeName, NzIdentifierRul
|
|
|
161
161
|
* One anchored regex per type. The identifier shape follows ADV358 (alphanumeric, no spaces or separators — `24999`,
|
|
162
162
|
* `B99`); the identifier-less counter services take no tail at all.
|
|
163
163
|
*/
|
|
164
|
-
const MATCHERS: ReadonlyArray<{ type:
|
|
164
|
+
const MATCHERS: ReadonlyArray<{ type: NZDeliveryServiceMatchTypeName; re: RegExp }> = TYPE_PATTERNS.map(
|
|
165
165
|
([type, src]) => {
|
|
166
166
|
const rule = IDENTIFIER_RULES.get(type)!
|
|
167
167
|
const tail = rule === "not-used" ? "" : String.raw`(?:\s+([\dA-Za-z]+))${rule === "optional" ? "?" : ""}`
|
|
@@ -173,7 +173,7 @@ const MATCHERS: ReadonlyArray<{ type: NzDeliveryServiceMatchTypeName; re: RegExp
|
|
|
173
173
|
/**
|
|
174
174
|
* Result of an NZ delivery-service parse.
|
|
175
175
|
*/
|
|
176
|
-
export interface
|
|
176
|
+
export interface NZDeliveryServiceMatch {
|
|
177
177
|
/**
|
|
178
178
|
* The designator phrase as it appeared ("PO Box", "private bag", "Private Box").
|
|
179
179
|
*/
|
|
@@ -183,7 +183,7 @@ export interface NzDeliveryServiceMatch {
|
|
|
183
183
|
* `type` is "Private Box", `colloquial` is true and `officiallyInvalid` is true — the form is not a valid ADV358
|
|
184
184
|
* type.
|
|
185
185
|
*/
|
|
186
|
-
type:
|
|
186
|
+
type: NZDeliveryServiceMatchTypeName
|
|
187
187
|
/**
|
|
188
188
|
* The Delivery Service Identifier when present ("24999", "B99").
|
|
189
189
|
*/
|
|
@@ -204,7 +204,7 @@ export interface NzDeliveryServiceMatch {
|
|
|
204
204
|
* Delivery Service Type; see {@link NZ_PRIVATE_BOX_ALIAS} and operator ruling 2026-06-11). Callers that want only
|
|
205
205
|
* formally-valid ADV358 types should check `!result.colloquial`.
|
|
206
206
|
*/
|
|
207
|
-
export function
|
|
207
|
+
export function matchNZDeliveryService(input: unknown): NZDeliveryServiceMatch | null {
|
|
208
208
|
if (typeof input !== "string") return null
|
|
209
209
|
|
|
210
210
|
for (const { type, re } of MATCHERS) {
|
|
@@ -222,16 +222,16 @@ export function matchNzDeliveryService(input: unknown): NzDeliveryServiceMatch |
|
|
|
222
222
|
/**
|
|
223
223
|
* Type-predicate: does the input look like a standalone NZ delivery-service address line?
|
|
224
224
|
*/
|
|
225
|
-
export function
|
|
226
|
-
return
|
|
225
|
+
export function isNZDeliveryService(input: unknown): boolean {
|
|
226
|
+
return matchNZDeliveryService(input) !== null
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
/**
|
|
230
230
|
* Normalize a recognized phrase to the ADV358 form (`"p.o. box 24999"` → `"PO Box 24999"`). Returns the input unchanged
|
|
231
231
|
* if it isn't a delivery-service phrase.
|
|
232
232
|
*/
|
|
233
|
-
export function
|
|
234
|
-
const m =
|
|
233
|
+
export function normalizeNZDeliveryService(input: string): string {
|
|
234
|
+
const m = matchNZDeliveryService(input)
|
|
235
235
|
|
|
236
236
|
if (!m) return input
|
|
237
237
|
|
package/nz/postcode.ts
CHANGED
|
@@ -23,7 +23,7 @@ import type { Tagged } from "type-fest"
|
|
|
23
23
|
* @title New Zealand postcode
|
|
24
24
|
* @pattern ^\d{4}$
|
|
25
25
|
*/
|
|
26
|
-
export type
|
|
26
|
+
export type NZPostcode = Tagged<string, "NZPostcode">
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* The NZ postcode shape: exactly four digits.
|
|
@@ -33,16 +33,16 @@ export const NZ_POSTCODE_PATTERN = /^\d{4}$/
|
|
|
33
33
|
/**
|
|
34
34
|
* Normalize a postcode surface form (trim only — NZ has no country-prefix courtesy form).
|
|
35
35
|
*/
|
|
36
|
-
export function
|
|
36
|
+
export function normalizeNZPostcode(raw: unknown): NZPostcode | null {
|
|
37
37
|
if (typeof raw !== "string") return null
|
|
38
38
|
const s = raw.trim()
|
|
39
39
|
|
|
40
|
-
return NZ_POSTCODE_PATTERN.test(s) ? (s as
|
|
40
|
+
return NZ_POSTCODE_PATTERN.test(s) ? (s as NZPostcode) : null
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Type-predicate for a (normalized) New Zealand postcode.
|
|
45
45
|
*/
|
|
46
|
-
export function
|
|
46
|
+
export function isNZPostcode(input: unknown): input is NZPostcode {
|
|
47
47
|
return typeof input === "string" && NZ_POSTCODE_PATTERN.test(input)
|
|
48
48
|
}
|
package/out/ca/province.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"province.d.ts","sourceRoot":"","sources":["../../ca/province.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"province.d.ts","sourceRoot":"","sources":["../../ca/province.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAcgC,CAAA;AAEzD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,YAAY,CAAA;AAI5D;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,oBAAoB,CAEpF;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAW3E,CAAA;AAEJ;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,oBAAoB,GAAG,IAAI,CAOpG"}
|
package/out/ca/province.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* is the abbreviation people actually write on the address line — so unlike German or French
|
|
16
16
|
* regions, the Canadian code IS a surface form, not just a resolver key.
|
|
17
17
|
*/
|
|
18
|
+
import { foldName } from "../normalize.js";
|
|
18
19
|
/**
|
|
19
20
|
* ISO 3166-2:CA code → province/territory info, for all 13 subdivisions (10 provinces + 3 territories). Codes are the
|
|
20
21
|
* official subdivision codes minus the `CA-` prefix.
|
|
@@ -41,17 +42,6 @@ const PROVINCE_CODE_SET = new Set(Object.keys(CA_PROVINCES));
|
|
|
41
42
|
export function isCanadianProvinceCode(input) {
|
|
42
43
|
return typeof input === "string" && PROVINCE_CODE_SET.has(input.toUpperCase());
|
|
43
44
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Strip diacritics + lowercase so `Québec`, `Quebec`, and `quebec` all key alike.
|
|
46
|
-
*/
|
|
47
|
-
function foldName(s) {
|
|
48
|
-
return s
|
|
49
|
-
.toLowerCase()
|
|
50
|
-
.normalize("NFD")
|
|
51
|
-
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
52
|
-
.replaceAll(/[^a-z0-9]+/g, " ")
|
|
53
|
-
.trim();
|
|
54
|
-
}
|
|
55
45
|
/**
|
|
56
46
|
* Folded province name (English or French) / code → ISO 3166-2:CA code. Built diacritic-insensitive so both co-official
|
|
57
47
|
* names map regardless of accents: `Québec`, `Quebec`, and an unaccented `Nouvelle-Ecosse` all resolve. The two-name
|
package/out/ca/province.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"province.js","sourceRoot":"","sources":["../../ca/province.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"province.js","sourceRoot":"","sources":["../../ca/province.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subdivision.d.ts","sourceRoot":"","sources":["../../country/subdivision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;
|
|
1
|
+
{"version":3,"file":"subdivision.d.ts","sourceRoot":"","sources":["../../country/subdivision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;CACf;AAkCD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,gBAAgB,GAAG,IAAI,CAI1F"}
|
|
@@ -26,18 +26,8 @@
|
|
|
26
26
|
* re-keys those two existing tables into one subdivision→country view.
|
|
27
27
|
*/
|
|
28
28
|
import { CA_PROVINCES } from "../ca/province.js";
|
|
29
|
+
import { foldName } from "../normalize.js";
|
|
29
30
|
import { US_STATE_BY_ABBREVIATION } from "../us/state.js";
|
|
30
|
-
/**
|
|
31
|
-
* Strip diacritics + lowercase so `Québec`, `Quebec`, and `quebec` all key alike (mirrors `ca/province.ts`).
|
|
32
|
-
*/
|
|
33
|
-
function foldName(s) {
|
|
34
|
-
return s
|
|
35
|
-
.toLowerCase()
|
|
36
|
-
.normalize("NFD")
|
|
37
|
-
.replaceAll(/[\u0300-\u036F]/g, "")
|
|
38
|
-
.replaceAll(/[^a-z0-9]+/g, " ")
|
|
39
|
-
.trim();
|
|
40
|
-
}
|
|
41
31
|
/**
|
|
42
32
|
* Folded surface form (ISO code, English name, or — for CA — co-official French name) → subdivision. Built once. US
|
|
43
33
|
* states are inserted first and never overwritten, so on the (currently empty) event of a future code/name collision
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subdivision.js","sourceRoot":"","sources":["../../country/subdivision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"subdivision.js","sourceRoot":"","sources":["../../country/subdivision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAoBzD;;;;GAIG;AACH,MAAM,kBAAkB,GAA0C,CAAC,GAAG,EAAE;IACvE,MAAM,GAAG,GAAG,IAAI,GAAG,EAA4B,CAAA;IAE/C,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,KAAuB,EAAQ,EAAE;QAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;QAE5B,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QACvB,CAAC;IACF,CAAC,CAAA;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,CAAC;QACrE,MAAM,KAAK,GAAqB,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAC7D,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAChB,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACjB,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAChD,MAAM,KAAK,GAAqB,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACnF,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACrB,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACrB,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACxB,CAAC;IAED,OAAO,GAAG,CAAA;AACX,CAAC,CAAC,EAAE,CAAA;AAEJ;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgC;IAChE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAEpD,OAAO,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAA;AACvD,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Spanish postal codes (código postal): the branded type, the shape, and the province prior.
|
|
7
|
+
*
|
|
8
|
+
* The contrast with a German PLZ is the informative part. A PLZ's leading digit maps to a Leitzone
|
|
9
|
+
* that deliberately CROSSES state borders, so it cannot tell you the Bundesland. A Spanish código
|
|
10
|
+
* postal is the opposite: its first TWO digits are the province code, assigned alphabetically
|
|
11
|
+
* (01 Álava … 28 Madrid … 50 Zaragoza), so the province is derivable from the postcode exactly.
|
|
12
|
+
* Code that wants a Spanish region from an address can read it off the postcode; code that wants a
|
|
13
|
+
* German one cannot.
|
|
14
|
+
*/
|
|
15
|
+
import type { Tagged } from "type-fest";
|
|
16
|
+
/**
|
|
17
|
+
* A Spanish postal code: five digits, `PPNNN`, where `PP` is the province (`28001` is Madrid).
|
|
18
|
+
*
|
|
19
|
+
* @category Postal
|
|
20
|
+
* @type string
|
|
21
|
+
* @title CodigoPostal
|
|
22
|
+
* @pattern ^\d{5}$
|
|
23
|
+
*/
|
|
24
|
+
export type CodigoPostal = Tagged<string, "CodigoPostal">;
|
|
25
|
+
/**
|
|
26
|
+
* Shape of a Spanish código postal — five digits. Identical in shape to a French code postal, a German PLZ and a US
|
|
27
|
+
* ZIP; disambiguation is the parser's job, not the pattern's.
|
|
28
|
+
*/
|
|
29
|
+
export declare const CODIGO_POSTAL_PATTERN: RegExp;
|
|
30
|
+
/**
|
|
31
|
+
* Narrow a string to a {@link CodigoPostal}, or `null` when it is not one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseCodigoPostal(input: string): CodigoPostal | null;
|
|
34
|
+
/**
|
|
35
|
+
* The two-digit province prefix (`"28001"` → `"28"`), or `null` for a non-postcode. Callers map it through their own
|
|
36
|
+
* province table; this module deliberately does not ship one, since the campaign that needed it only needs the shape.
|
|
37
|
+
*/
|
|
38
|
+
export declare function codigoPostalProvincePrefix(input: string): string | null;
|
|
39
|
+
//# sourceMappingURL=codigo-postal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codigo-postal.d.ts","sourceRoot":"","sources":["../../es/codigo-postal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEvC;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;AAEzD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAY,CAAA;AAE9C;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAIpE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIvE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Spanish postal codes (código postal): the branded type, the shape, and the province prior.
|
|
7
|
+
*
|
|
8
|
+
* The contrast with a German PLZ is the informative part. A PLZ's leading digit maps to a Leitzone
|
|
9
|
+
* that deliberately CROSSES state borders, so it cannot tell you the Bundesland. A Spanish código
|
|
10
|
+
* postal is the opposite: its first TWO digits are the province code, assigned alphabetically
|
|
11
|
+
* (01 Álava … 28 Madrid … 50 Zaragoza), so the province is derivable from the postcode exactly.
|
|
12
|
+
* Code that wants a Spanish region from an address can read it off the postcode; code that wants a
|
|
13
|
+
* German one cannot.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Shape of a Spanish código postal — five digits. Identical in shape to a French code postal, a German PLZ and a US
|
|
17
|
+
* ZIP; disambiguation is the parser's job, not the pattern's.
|
|
18
|
+
*/
|
|
19
|
+
export const CODIGO_POSTAL_PATTERN = /^\d{5}$/;
|
|
20
|
+
/**
|
|
21
|
+
* Narrow a string to a {@link CodigoPostal}, or `null` when it is not one.
|
|
22
|
+
*/
|
|
23
|
+
export function parseCodigoPostal(input) {
|
|
24
|
+
const s = input.trim();
|
|
25
|
+
return CODIGO_POSTAL_PATTERN.test(s) ? s : null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The two-digit province prefix (`"28001"` → `"28"`), or `null` for a non-postcode. Callers map it through their own
|
|
29
|
+
* province table; this module deliberately does not ship one, since the campaign that needed it only needs the shape.
|
|
30
|
+
*/
|
|
31
|
+
export function codigoPostalProvincePrefix(input) {
|
|
32
|
+
const code = parseCodigoPostal(input);
|
|
33
|
+
return code ? code.slice(0, 2) : null;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=codigo-postal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codigo-postal.js","sourceRoot":"","sources":["../../es/codigo-postal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAcH;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAA;AAE9C;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC9C,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAEtB,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAkB,CAAC,CAAC,CAAC,IAAI,CAAA;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAa;IACvD,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA;IAErC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../es/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,oBAAoB,CAAA"}
|
package/out/es/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../es/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,oBAAoB,CAAA"}
|
package/out/fr/region.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"region.d.ts","sourceRoot":"","sources":["../../fr/region.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"region.d.ts","sourceRoot":"","sources":["../../fr/region.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;CACZ;AAED;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmB8B,CAAA;AAErD;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,UAAU,CAAA;AAItD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CASrE,CAAA;AAEJ;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,gBAAgB,GAAG,IAAI,CAO5F"}
|