@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/lib/address/point/interpolation.ts +45 -39
- package/lib/address/point/schema.ts +17 -40
- package/lib/address/point.ts +316 -0
- package/lib/{address/index.ts → address.ts} +1 -1
- package/lib/ancestry/backfill.ts +20 -86
- package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
- package/lib/build/candidate.ts +122 -174
- package/lib/build/population-corrections.ts +64 -0
- package/lib/build/slim.ts +44 -114
- package/lib/candidate/alias-bags.ts +16 -17
- package/lib/candidate/ancestors/schema.ts +77 -61
- package/lib/candidate/ancestors/sidecar.ts +15 -22
- package/lib/candidate/country-display-names.ts +6 -20
- package/lib/candidate/extract-fold.ts +10 -55
- package/lib/candidate/fts.ts +5 -23
- package/lib/candidate/importance.ts +65 -68
- package/lib/candidate/lookup.ts +124 -415
- package/lib/candidate/name-roles.ts +15 -33
- package/lib/candidate/own-name.ts +35 -32
- package/lib/candidate/place-attrs.ts +20 -13
- package/lib/candidate/schema.ts +29 -65
- package/lib/candidate/scoring.ts +54 -93
- package/lib/capital-schema.ts +21 -17
- package/lib/capitals.ts +29 -27
- package/lib/coincident-roles.ts +85 -55
- package/lib/convention/schema.ts +15 -16
- package/lib/convention.ts +144 -0
- package/lib/coverage-manifest-schema.ts +40 -45
- package/lib/currency-backfill.ts +34 -79
- package/lib/env.ts +1 -1
- package/lib/exact-match.ts +32 -21
- package/lib/extracts.ts +97 -74
- package/lib/fst/autocomplete.ts +54 -37
- package/lib/fst/builder.ts +37 -41
- package/lib/fst/deserialize-web.ts +16 -17
- package/lib/fst/format.ts +41 -23
- package/lib/fst/freshness.ts +43 -120
- package/lib/fst/matcher.ts +7 -5
- package/lib/fst/serialize.ts +54 -74
- package/lib/fst/types.ts +78 -75
- package/lib/{fst/index.ts → fst.ts} +1 -0
- package/lib/fts/query.ts +5 -36
- package/lib/fts.ts +280 -0
- package/lib/geonames/aliases.ts +73 -144
- package/lib/geonames/postal.ts +162 -71
- package/lib/index.ts +9 -8
- package/lib/interpolation.ts +48 -100
- package/lib/lookup.ts +155 -270
- package/lib/name-score.ts +9 -7
- package/lib/nsul/lookup.ts +37 -54
- package/lib/nsul/schema.ts +16 -43
- package/lib/paths.ts +159 -0
- package/lib/place-importance-schema.ts +62 -169
- package/lib/poi/lookup.ts +104 -121
- package/lib/poi/schema.ts +42 -26
- package/lib/polygon-schema.ts +10 -6
- package/lib/postal/city/alias/lookup.ts +22 -40
- package/lib/postal/city/alias/schema.ts +14 -10
- package/lib/postal/city/candidate-schema.ts +26 -20
- package/lib/postcode-point-lookup.ts +8 -27
- package/lib/primary-preference.ts +46 -126
- package/lib/proximity-rerank.ts +44 -33
- package/lib/ranking-weights.ts +105 -78
- package/lib/region-keys.ts +70 -42
- package/lib/reverse.ts +149 -86
- package/lib/schema.ts +73 -50
- package/lib/search-fetch.ts +90 -68
- package/lib/sqlite/convention-source.ts +15 -23
- package/lib/sqlite/utils.ts +19 -22
- package/lib/street/centroid/schema.ts +37 -42
- package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
- package/lib/street/morphology/fst/builder.ts +60 -42
- package/lib/street/morphology/fst/loader.ts +40 -32
- package/lib/street/name-lookup.ts +45 -41
- package/lib/street/normalize.ts +88 -219
- package/lib/street/segment-schema.ts +116 -43
- package/lib/{street/index.ts → street.ts} +1 -1
- package/lib/types.ts +109 -150
- package/lib/unified-schema.ts +29 -29
- package/lib/uprn/existence.ts +30 -19
- package/lib/uprn/lookup.ts +29 -68
- package/lib/uprn/schema.ts +18 -40
- package/lib/weights-overlay-linker.ts +236 -252
- package/out/address/point/interpolation.d.ts +20 -23
- package/out/address/point/interpolation.d.ts.map +1 -1
- package/out/address/point/interpolation.js +42 -39
- package/out/address/point/interpolation.js.map +1 -1
- package/out/address/point/schema.d.ts +12 -35
- package/out/address/point/schema.d.ts.map +1 -1
- package/out/address/point/schema.js +3 -19
- package/out/address/point/schema.js.map +1 -1
- package/out/address/point.d.ts +57 -0
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +206 -0
- package/out/address/point.js.map +1 -0
- package/out/{address/index.js → address.d.ts} +2 -2
- package/out/address.d.ts.map +1 -0
- package/out/{address/index.d.ts → address.js} +2 -2
- package/out/address.js.map +1 -0
- package/out/ancestry/backfill.d.ts +11 -64
- package/out/ancestry/backfill.d.ts.map +1 -1
- package/out/ancestry/backfill.js +14 -74
- package/out/ancestry/backfill.js.map +1 -1
- package/out/ancestry.d.ts +49 -0
- package/out/ancestry.d.ts.map +1 -0
- package/out/ancestry.js +59 -0
- package/out/ancestry.js.map +1 -0
- package/out/build/candidate.d.ts +82 -112
- package/out/build/candidate.d.ts.map +1 -1
- package/out/build/candidate.js +17 -100
- package/out/build/candidate.js.map +1 -1
- package/out/build/population-corrections.d.ts +52 -0
- package/out/build/population-corrections.d.ts.map +1 -0
- package/out/build/population-corrections.js +40 -0
- package/out/build/population-corrections.js.map +1 -0
- package/out/build/slim.d.ts +8 -44
- package/out/build/slim.d.ts.map +1 -1
- package/out/build/slim.js +33 -94
- package/out/build/slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +6 -6
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +16 -17
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors/schema.d.ts +73 -57
- package/out/candidate/ancestors/schema.d.ts.map +1 -1
- package/out/candidate/ancestors/schema.js +56 -48
- package/out/candidate/ancestors/schema.js.map +1 -1
- package/out/candidate/ancestors/sidecar.d.ts +3 -8
- package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors/sidecar.js +15 -22
- package/out/candidate/ancestors/sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +5 -15
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +6 -20
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +7 -15
- package/out/candidate/extract-fold.d.ts.map +1 -1
- package/out/candidate/extract-fold.js +5 -47
- package/out/candidate/extract-fold.js.map +1 -1
- package/out/candidate/fts.d.ts +5 -23
- package/out/candidate/fts.d.ts.map +1 -1
- package/out/candidate/fts.js +5 -23
- package/out/candidate/fts.js.map +1 -1
- package/out/candidate/importance.d.ts +60 -65
- package/out/candidate/importance.d.ts.map +1 -1
- package/out/candidate/importance.js +56 -63
- package/out/candidate/importance.js.map +1 -1
- package/out/candidate/lookup.d.ts +18 -55
- package/out/candidate/lookup.d.ts.map +1 -1
- package/out/candidate/lookup.js +82 -385
- package/out/candidate/lookup.js.map +1 -1
- package/out/candidate/name-roles.d.ts +9 -21
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +15 -33
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +23 -25
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +35 -32
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +20 -13
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +4 -5
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate/schema.d.ts +27 -62
- package/out/candidate/schema.d.ts.map +1 -1
- package/out/candidate/schema.js +10 -22
- package/out/candidate/schema.js.map +1 -1
- package/out/candidate/scoring.d.ts +7 -8
- package/out/candidate/scoring.d.ts.map +1 -1
- package/out/candidate/scoring.js +52 -89
- package/out/candidate/scoring.js.map +1 -1
- package/out/capital-schema.d.ts +21 -17
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +17 -15
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +27 -25
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +23 -21
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +60 -43
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +72 -50
- package/out/coincident-roles.js.map +1 -1
- package/out/convention/schema.d.ts +14 -14
- package/out/convention/schema.d.ts.map +1 -1
- package/out/convention/schema.js +6 -4
- package/out/convention/schema.js.map +1 -1
- package/out/convention.d.ts +97 -0
- package/out/convention.d.ts.map +1 -0
- package/out/convention.js +81 -0
- package/out/convention.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +34 -39
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +25 -34
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +16 -38
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +19 -46
- package/out/currency-backfill.js.map +1 -1
- package/out/env.d.ts +1 -1
- package/out/env.js +1 -1
- package/out/exact-match.d.ts +19 -10
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +32 -21
- package/out/exact-match.js.map +1 -1
- package/out/extracts.d.ts +66 -55
- package/out/extracts.d.ts.map +1 -1
- package/out/extracts.js +63 -55
- package/out/extracts.js.map +1 -1
- package/out/fst/autocomplete.d.ts +29 -21
- package/out/fst/autocomplete.d.ts.map +1 -1
- package/out/fst/autocomplete.js +39 -28
- package/out/fst/autocomplete.js.map +1 -1
- package/out/fst/builder.d.ts.map +1 -1
- package/out/fst/builder.js +37 -41
- package/out/fst/builder.js.map +1 -1
- package/out/fst/deserialize-web.d.ts +4 -4
- package/out/fst/deserialize-web.d.ts.map +1 -1
- package/out/fst/deserialize-web.js +15 -16
- package/out/fst/deserialize-web.js.map +1 -1
- package/out/fst/format.d.ts +41 -23
- package/out/fst/format.d.ts.map +1 -1
- package/out/fst/format.js +41 -23
- package/out/fst/format.js.map +1 -1
- package/out/fst/freshness.d.ts +19 -81
- package/out/fst/freshness.d.ts.map +1 -1
- package/out/fst/freshness.js +31 -94
- package/out/fst/freshness.js.map +1 -1
- package/out/fst/matcher.d.ts +5 -4
- package/out/fst/matcher.d.ts.map +1 -1
- package/out/fst/matcher.js +2 -2
- package/out/fst/matcher.js.map +1 -1
- package/out/fst/serialize.d.ts +28 -28
- package/out/fst/serialize.d.ts.map +1 -1
- package/out/fst/serialize.js +53 -71
- package/out/fst/serialize.js.map +1 -1
- package/out/fst/types.d.ts +78 -74
- package/out/fst/types.d.ts.map +1 -1
- package/out/fst/types.js +1 -4
- package/out/fst/types.js.map +1 -1
- package/out/{fst/index.js → fst.d.ts} +2 -1
- package/out/fst.d.ts.map +1 -0
- package/out/{fst/index.d.ts → fst.js} +2 -1
- package/out/fst.js.map +1 -0
- package/out/fts/query.d.ts +2 -27
- package/out/fts/query.d.ts.map +1 -1
- package/out/fts/query.js +5 -36
- package/out/fts/query.js.map +1 -1
- package/out/fts.d.ts +126 -0
- package/out/fts.d.ts.map +1 -0
- package/out/fts.js +188 -0
- package/out/fts.js.map +1 -0
- package/out/geonames/aliases.d.ts +26 -62
- package/out/geonames/aliases.d.ts.map +1 -1
- package/out/geonames/aliases.js +45 -117
- package/out/geonames/aliases.js.map +1 -1
- package/out/geonames/postal.d.ts +84 -44
- package/out/geonames/postal.d.ts.map +1 -1
- package/out/geonames/postal.js +115 -73
- package/out/geonames/postal.js.map +1 -1
- package/out/{geonames/index.js → geonames.d.ts} +1 -1
- package/out/geonames.d.ts.map +1 -0
- package/out/{geonames/index.d.ts → geonames.js} +1 -1
- package/out/geonames.js.map +1 -0
- package/out/index.d.ts +9 -8
- package/out/index.d.ts.map +1 -1
- package/out/index.js +6 -5
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +18 -55
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +27 -69
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +23 -51
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +136 -234
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +2 -2
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +9 -7
- package/out/name-score.js.map +1 -1
- package/out/nsul/lookup.d.ts +33 -34
- package/out/nsul/lookup.d.ts.map +1 -1
- package/out/nsul/lookup.js +26 -40
- package/out/nsul/lookup.js.map +1 -1
- package/out/nsul/schema.d.ts +16 -43
- package/out/nsul/schema.d.ts.map +1 -1
- package/out/nsul/schema.js +9 -35
- package/out/nsul/schema.js.map +1 -1
- package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
- package/out/nsul.d.ts.map +1 -0
- package/out/{nsul/index.js → nsul.js} +1 -1
- package/out/nsul.js.map +1 -0
- package/out/paths.d.ts +124 -0
- package/out/paths.d.ts.map +1 -0
- package/out/paths.js +104 -0
- package/out/paths.js.map +1 -0
- package/out/place-importance-schema.d.ts +51 -143
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +28 -143
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/lookup.d.ts +40 -47
- package/out/poi/lookup.d.ts.map +1 -1
- package/out/poi/lookup.js +69 -96
- package/out/poi/lookup.js.map +1 -1
- package/out/poi/schema.d.ts +41 -25
- package/out/poi/schema.d.ts.map +1 -1
- package/out/poi/schema.js +25 -17
- package/out/poi/schema.js.map +1 -1
- package/out/{poi/index.js → poi.d.ts} +1 -1
- package/out/poi.d.ts.map +1 -0
- package/out/{poi/index.d.ts → poi.js} +1 -1
- package/out/poi.js.map +1 -0
- package/out/polygon-schema.d.ts +10 -6
- package/out/polygon-schema.d.ts.map +1 -1
- package/out/polygon-schema.js +2 -2
- package/out/polygon-schema.js.map +1 -1
- package/out/postal/city/alias/lookup.d.ts +20 -23
- package/out/postal/city/alias/lookup.d.ts.map +1 -1
- package/out/postal/city/alias/lookup.js +17 -30
- package/out/postal/city/alias/lookup.js.map +1 -1
- package/out/postal/city/alias/schema.d.ts +14 -10
- package/out/postal/city/alias/schema.d.ts.map +1 -1
- package/out/postal/city/alias/schema.js +10 -8
- package/out/postal/city/alias/schema.js.map +1 -1
- package/out/postal/city/candidate-schema.d.ts +25 -19
- package/out/postal/city/candidate-schema.d.ts.map +1 -1
- package/out/postal/city/candidate-schema.js +21 -17
- package/out/postal/city/candidate-schema.js.map +1 -1
- package/out/{postal/index.d.ts → postal.d.ts} +1 -1
- package/out/postal.d.ts.map +1 -0
- package/out/{postal/index.js → postal.js} +1 -1
- package/out/postal.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +6 -24
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +5 -17
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +38 -92
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +15 -99
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +41 -30
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +38 -29
- package/out/proximity-rerank.js.map +1 -1
- package/out/ranking-weights.d.ts +98 -64
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +26 -25
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +50 -31
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +68 -40
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +78 -50
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +98 -61
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +72 -49
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js +4 -5
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +16 -12
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +83 -63
- package/out/search-fetch.js.map +1 -1
- package/out/sqlite/convention-source.d.ts +12 -16
- package/out/sqlite/convention-source.d.ts.map +1 -1
- package/out/sqlite/convention-source.js +13 -22
- package/out/sqlite/convention-source.js.map +1 -1
- package/out/sqlite/utils.d.ts +19 -19
- package/out/sqlite/utils.d.ts.map +1 -1
- package/out/sqlite/utils.js +14 -15
- package/out/sqlite/utils.js.map +1 -1
- package/out/street/centroid/schema.d.ts +37 -42
- package/out/street/centroid/schema.d.ts.map +1 -1
- package/out/street/centroid/schema.js +9 -21
- package/out/street/centroid/schema.js.map +1 -1
- package/out/street/centroid.d.ts +30 -0
- package/out/street/centroid.d.ts.map +1 -0
- package/out/street/{centroid/index.js → centroid.js} +13 -24
- package/out/street/centroid.js.map +1 -0
- package/out/street/morphology/fst/builder.d.ts +20 -10
- package/out/street/morphology/fst/builder.d.ts.map +1 -1
- package/out/street/morphology/fst/builder.js +44 -34
- package/out/street/morphology/fst/builder.js.map +1 -1
- package/out/street/morphology/fst/loader.d.ts +33 -26
- package/out/street/morphology/fst/loader.d.ts.map +1 -1
- package/out/street/morphology/fst/loader.js +23 -22
- package/out/street/morphology/fst/loader.js.map +1 -1
- package/out/street/name-lookup.d.ts +24 -18
- package/out/street/name-lookup.d.ts.map +1 -1
- package/out/street/name-lookup.js +34 -35
- package/out/street/name-lookup.js.map +1 -1
- package/out/street/normalize.d.ts +35 -136
- package/out/street/normalize.d.ts.map +1 -1
- package/out/street/normalize.js +77 -194
- package/out/street/normalize.js.map +1 -1
- package/out/street/segment-schema.d.ts +79 -39
- package/out/street/segment-schema.d.ts.map +1 -1
- package/out/street/segment-schema.js +71 -21
- package/out/street/segment-schema.js.map +1 -1
- package/out/{street/index.js → street.d.ts} +2 -2
- package/out/street.d.ts.map +1 -0
- package/out/{street/index.d.ts → street.js} +2 -2
- package/out/street.js.map +1 -0
- package/out/types.d.ts +84 -149
- package/out/types.d.ts.map +1 -1
- package/out/types.js +0 -6
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +8 -12
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +29 -29
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +28 -17
- package/out/uprn/existence.d.ts.map +1 -1
- package/out/uprn/existence.js +26 -16
- package/out/uprn/existence.js.map +1 -1
- package/out/uprn/lookup.d.ts +14 -44
- package/out/uprn/lookup.d.ts.map +1 -1
- package/out/uprn/lookup.js +21 -57
- package/out/uprn/lookup.js.map +1 -1
- package/out/uprn/schema.d.ts +18 -40
- package/out/uprn/schema.d.ts.map +1 -1
- package/out/uprn/schema.js +10 -32
- package/out/uprn/schema.js.map +1 -1
- package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
- package/out/uprn.d.ts.map +1 -0
- package/out/{uprn/index.js → uprn.js} +1 -1
- package/out/uprn.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +138 -144
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +105 -159
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +91 -596
- package/lib/address/point/index.ts +0 -328
- package/lib/convention/index.ts +0 -154
- package/lib/fts/index.ts +0 -361
- package/out/address/index.d.ts.map +0 -1
- package/out/address/index.js.map +0 -1
- package/out/address/point/index.d.ts +0 -53
- package/out/address/point/index.d.ts.map +0 -1
- package/out/address/point/index.js +0 -222
- package/out/address/point/index.js.map +0 -1
- package/out/ancestry/index.d.ts +0 -45
- package/out/ancestry/index.d.ts.map +0 -1
- package/out/ancestry/index.js +0 -55
- package/out/ancestry/index.js.map +0 -1
- package/out/convention/index.d.ts +0 -106
- package/out/convention/index.d.ts.map +0 -1
- package/out/convention/index.js +0 -93
- package/out/convention/index.js.map +0 -1
- package/out/fst/index.d.ts.map +0 -1
- package/out/fst/index.js.map +0 -1
- package/out/fts/index.d.ts +0 -184
- package/out/fts/index.d.ts.map +0 -1
- package/out/fts/index.js +0 -277
- package/out/fts/index.js.map +0 -1
- package/out/geonames/index.d.ts.map +0 -1
- package/out/geonames/index.js.map +0 -1
- package/out/nsul/index.d.ts.map +0 -1
- package/out/nsul/index.js.map +0 -1
- package/out/poi/index.d.ts.map +0 -1
- package/out/poi/index.js.map +0 -1
- package/out/postal/index.d.ts.map +0 -1
- package/out/postal/index.js.map +0 -1
- package/out/street/centroid/index.d.ts +0 -40
- package/out/street/centroid/index.d.ts.map +0 -1
- package/out/street/centroid/index.js.map +0 -1
- package/out/street/index.d.ts.map +0 -1
- package/out/street/index.js.map +0 -1
- package/out/uprn/index.d.ts.map +0 -1
- package/out/uprn/index.js.map +0 -1
- /package/lib/{geonames/index.ts → geonames.ts} +0 -0
- /package/lib/{nsul/index.ts → nsul.ts} +0 -0
- /package/lib/{poi/index.ts → poi.ts} +0 -0
- /package/lib/{postal/index.ts → postal.ts} +0 -0
- /package/lib/{uprn/index.ts → uprn.ts} +0 -0
package/lib/street/normalize.ts
CHANGED
|
@@ -2,73 +2,31 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* THE street normalizer for the address-point tier (#476). One function, used by BOTH the extract
|
|
7
|
-
* builder (`scripts/build-address-point-extract.ts`) and the lookup tier (`address-point.ts`) —
|
|
8
|
-
* never two implementations (the PLACETYPE_ORDER lesson: parallel copies silently corrupt).
|
|
9
|
-
*
|
|
10
|
-
* Normalization contract (deliberately aggressive — both sides apply the same function, so
|
|
11
|
-
* collisions only need to be _consistent_, not linguistically perfect):
|
|
12
|
-
*
|
|
13
|
-
* 1. Lowercase, NFKD-fold diacritics, collapse whitespace, strip punctuation (periods, commas,
|
|
14
|
-
* apostrophes).
|
|
15
|
-
* 2. Expand USPS directional abbreviations at the FIRST and LAST token position (`n` → `north`, `se` →
|
|
16
|
-
* `southeast`) — Overture sources abbreviate inconsistently.
|
|
17
|
-
* 3. Canonicalize a trailing USPS street-type token via the codex suffix table to its canonical full
|
|
18
|
-
* form (`st`/`str`/`street` → `street`).
|
|
19
|
-
*
|
|
20
|
-
* Numbered streets are left as digits (`5th` stays `5th`); a SPELLED ordinal before a street suffix
|
|
21
|
-
* folds to its digit form (`tenth street` → `10th street`, #723) so the grid-city ordinal
|
|
22
|
-
* cross-streets the source data spells with digits become reachable.
|
|
23
5
|
*/
|
|
24
6
|
|
|
25
7
|
import { AbbreviationToDirectional, US_STREET_SUFFIX_LOOKUP } from "@mailwoman/codex/us"
|
|
26
8
|
import type { Tagged } from "type-fest"
|
|
27
9
|
|
|
28
10
|
/**
|
|
29
|
-
* A place name folded by {@link normalizeLocalityForKey}
|
|
30
|
-
* `name_key`-style column: the candidate gazetteer, the postal-city side-index, the street-centroid extract, an
|
|
31
|
-
* ancestor chain's `parent_name_key`, and the address-point locality scope.
|
|
32
|
-
*
|
|
33
|
-
* The brand is here because the fold is applied at BUILD time and is therefore mandatory at QUERY time, while a
|
|
34
|
-
* near-miss approximation of it (`toLowerCase()`, `trim()`) is still a `string`: it binds to the parameter, returns
|
|
35
|
-
* fewer rows, and the shortfall reads as a coverage gap in the data rather than a defect in the probe. Requiring the
|
|
36
|
-
* brand at the boundary turns that silent under-match into a compile error. Mint one only by calling the fold.
|
|
11
|
+
* A place name folded by {@link normalizeLocalityForKey}, minted only by calling the fold.
|
|
37
12
|
*/
|
|
38
13
|
export type NameKey = Tagged<string, "NameKey">
|
|
39
14
|
|
|
40
15
|
/**
|
|
41
|
-
* A street name folded by {@link normalizeStreetForKey}
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* Distinct from {@link RouteKey}: the route fold is a FURTHER canonicalization applied to some columns and not others,
|
|
45
|
-
* so the two are not interchangeable even though both are folded streets.
|
|
16
|
+
* A street name folded by {@link normalizeStreetForKey} or {@link normalizeStreetForKeyLocale},
|
|
17
|
+
* the form an address-point `street_norm` column stores.
|
|
18
|
+
* Do not substitute {@link RouteKey} for this type.
|
|
46
19
|
*/
|
|
47
20
|
export type StreetKey = Tagged<string, "StreetKey">
|
|
48
21
|
|
|
49
22
|
/**
|
|
50
|
-
* A street key that has
|
|
51
|
-
*
|
|
52
|
-
* A separate brand from {@link StreetKey} because it identifies a DIFFERENT set of columns, and the two folds disagree
|
|
53
|
-
* exactly on the rows that motivate the route fold: binding a plain street key to a route-folded column silently misses
|
|
54
|
-
* every row whose source spelled the route differently, which is the miss class the fold exists to close.
|
|
23
|
+
* A street key that has also passed {@link canonicalizeRouteKey}; binding a plain
|
|
24
|
+
* {@link StreetKey} to a route-folded column silently misses rows whose route spelling differs.
|
|
55
25
|
*/
|
|
56
26
|
export type RouteKey = Tagged<string, "RouteKey">
|
|
57
27
|
|
|
58
|
-
/**
|
|
59
|
-
* Token count a street must exceed before its trailing pair is merged. At or below it the pair IS the whole street
|
|
60
|
-
* name, and merging would leave nothing to match on.
|
|
61
|
-
*/
|
|
62
28
|
const MIN_TOKENS_FOR_TAIL_MERGE = 3
|
|
63
29
|
|
|
64
|
-
/**
|
|
65
|
-
* Spelled ordinal street names → their digit-ordinal form ("tenth" → "10th"), applied ONLY when a street-type suffix
|
|
66
|
-
* follows (#723 admin-tail) — so the ordinal cross-streets common in grid cities ("Tenth Street", "Fifth Avenue") match
|
|
67
|
-
* the extracts' digit keys, WITHOUT rewriting ordinal-WORD names where the next token is not a suffix ("First National
|
|
68
|
-
* Bank Rd" stays "first national …"). Digit-source extracts are unaffected (a digit token isn't in this map), so the
|
|
69
|
-
* existing keys need no rebuild; a future rebuild folds any spelled-source key the same way (the one-function
|
|
70
|
-
* discipline).
|
|
71
|
-
*/
|
|
72
30
|
const SPELLED_ORDINAL_TO_DIGIT = new Map<string, string>([
|
|
73
31
|
["first", "1st"],
|
|
74
32
|
["second", "2nd"],
|
|
@@ -100,9 +58,6 @@ const SPELLED_ORDINAL_TO_DIGIT = new Map<string, string>([
|
|
|
100
58
|
["hundredth", "100th"],
|
|
101
59
|
])
|
|
102
60
|
|
|
103
|
-
/**
|
|
104
|
-
* Lowercase + diacritic-fold + punctuation strip + whitespace collapse.
|
|
105
|
-
*/
|
|
106
61
|
function fold(input: string): string {
|
|
107
62
|
return input
|
|
108
63
|
.normalize("NFKD")
|
|
@@ -114,16 +69,15 @@ function fold(input: string): string {
|
|
|
114
69
|
}
|
|
115
70
|
|
|
116
71
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
72
|
+
* Normalizes a US or English street name into an address-point key, folding directionals,
|
|
73
|
+
* spelled ordinals and the USPS street-type suffix.
|
|
74
|
+
* The extract builder and the probe must both call it.
|
|
119
75
|
*/
|
|
120
76
|
export function normalizeStreetForKey(street: string): StreetKey {
|
|
121
77
|
const tokens = fold(street).split(" ")
|
|
122
78
|
|
|
123
79
|
if (!tokens.length) return "" as StreetKey
|
|
124
80
|
|
|
125
|
-
// Spelled-ordinal street names → digit form when a street suffix follows ("Tenth Street" →
|
|
126
|
-
// "10th street", #723). Conditioned on the next token being a suffix so ordinal-WORD names are untouched.
|
|
127
81
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
128
82
|
const digit = SPELLED_ORDINAL_TO_DIGIT.get(tokens[i]!)
|
|
129
83
|
|
|
@@ -132,10 +86,6 @@ export function normalizeStreetForKey(street: string): StreetKey {
|
|
|
132
86
|
}
|
|
133
87
|
}
|
|
134
88
|
|
|
135
|
-
// Directional expansion at the edges only ("N Main St" / "Main St N" — never interior
|
|
136
|
-
// tokens, where "W" may be an initial in a person-named street). The codex expands
|
|
137
|
-
// compounds to two words ("SE" → "SOUTH EAST"); we key on the spaceless form
|
|
138
|
-
// ("southeast"), and also merge an already-written two-token pair ("South East …").
|
|
139
89
|
const edgeDirectional = (raw: string) =>
|
|
140
90
|
AbbreviationToDirectional.get(raw.toUpperCase())?.toLowerCase().replace(" ", "")
|
|
141
91
|
|
|
@@ -168,11 +118,8 @@ export function normalizeStreetForKey(street: string): StreetKey {
|
|
|
168
118
|
}
|
|
169
119
|
}
|
|
170
120
|
|
|
171
|
-
// Street-type canonicalization via the codex table (lowercase keys, UPPER canonical
|
|
172
|
-
// values). The suffix is usually the last token, but sits second-to-last when a trailing
|
|
173
|
-
// directional follows ("Main St N") — check both positions, canonicalize the first hit.
|
|
174
121
|
for (const at of [tokens.length - 1, tokens.length - 2]) {
|
|
175
|
-
if (at < 1) continue
|
|
122
|
+
if (at < 1) continue
|
|
176
123
|
const canonical = US_STREET_SUFFIX_LOOKUP.get(tokens[at]!)
|
|
177
124
|
|
|
178
125
|
if (canonical) {
|
|
@@ -186,31 +133,18 @@ export function normalizeStreetForKey(street: string): StreetKey {
|
|
|
186
133
|
}
|
|
187
134
|
|
|
188
135
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* the US normalizer: build side and probe side call the identical function, so the key only needs to be CONSISTENT, not
|
|
192
|
-
* linguistically perfect — a folded "rue du chevaleret" keys the same on both sides whether or not we reorder the
|
|
193
|
-
* article, so no salient-token / multi-key index is built yet (deferred until probing shows the normalizer can't absorb
|
|
194
|
-
* the false-negatives).
|
|
136
|
+
* Names the rule set {@link normalizeStreetForKeyLocale} uses to fold a street
|
|
137
|
+
* name into an address-point key.
|
|
195
138
|
*/
|
|
196
|
-
export type StreetLocale = "us" | "en" | "fr" | "de" | "nl" | "pl" | "vn" | "id" | "zh"
|
|
139
|
+
export type StreetLocale = "us" | "en" | "es" | "fr" | "de" | "it" | "nl" | "pl" | "vn" | "id" | "zh"
|
|
197
140
|
|
|
198
|
-
/**
|
|
199
|
-
* The Han fold shared by every `zh` key: NFKC so a full-width digit or letter keys as its ASCII form (the Taiwanese
|
|
200
|
-
* civil-affairs registers write `122`, a person types `122`), 臺 → 台 (the register writes 臺北市, the common hand writes
|
|
201
|
-
* 台北市), and no whitespace at all, because a Han surface carries none and a stray space would split one key into two.
|
|
202
|
-
* Kanji numerals stay as written: the register spells a road section `一段`, and so does a query.
|
|
203
|
-
*/
|
|
204
141
|
function foldHan(input: string): string {
|
|
205
142
|
return input.normalize("NFKC").replaceAll("臺", "台").replaceAll(/\s+/g, "").toLowerCase()
|
|
206
143
|
}
|
|
207
144
|
|
|
208
145
|
/**
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* than silently folding with the wrong rules, because a extract built with the wrong normalizer keys every street
|
|
212
|
-
* incorrectly and looks fine until a probe misses. `label` is the SDK's own registration instructions, appended to the
|
|
213
|
-
* error verbatim.
|
|
146
|
+
* Creates a country-to-street-locale lookup for an acquisition SDK, throwing
|
|
147
|
+
* rather than falling back so a misregistered locale cannot key every street wrongly.
|
|
214
148
|
*/
|
|
215
149
|
export function createStreetLocaleRegistry(
|
|
216
150
|
registry: ReadonlyMap<string, StreetLocale>,
|
|
@@ -230,11 +164,6 @@ export function createStreetLocaleRegistry(
|
|
|
230
164
|
}
|
|
231
165
|
}
|
|
232
166
|
|
|
233
|
-
/**
|
|
234
|
-
* French street-type abbreviations → canonical full form, applied per token after {@link fold}. French address types
|
|
235
|
-
* LEAD the name ("Av. de…", "Bd …", "Pl. …") and "St"/"Ste" abbreviate Saint/Sainte inside names ("Rue St-Honoré" →
|
|
236
|
-
* "rue saint honore"). fold() has already stripped the trailing period, so the keys are point-free ("av", "bd").
|
|
237
|
-
*/
|
|
238
167
|
const FR_STREET_ABBREV = new Map<string, string>([
|
|
239
168
|
["av", "avenue"],
|
|
240
169
|
["ave", "avenue"],
|
|
@@ -257,19 +186,45 @@ const FR_STREET_ABBREV = new Map<string, string>([
|
|
|
257
186
|
["sts", "saints"],
|
|
258
187
|
])
|
|
259
188
|
|
|
189
|
+
const PL_LEADING_TYPE = new Set(["ul", "ulica", "al", "aleja", "aleje", "pl", "plac", "os", "osiedle"])
|
|
190
|
+
|
|
260
191
|
/**
|
|
261
|
-
*
|
|
262
|
-
* (2026-08-19): OSM Poland tags `addr:street` BARE — `ulica%` covers 22 rows and `ul.%` eight, so an EXPANSION rule
|
|
263
|
-
* makes a typed query ("ul. Świętokrzyska" → "ulica swietokrzyska") miss the 3,846 bare "swietokrzyska" rows. Stripping
|
|
264
|
-
* the leading type on BOTH sides keys typed and bare surfaces identically. The full words are stripped too: the
|
|
265
|
-
* aleja/plac/osiedle populations (48,597 / 26,815 / 39,552 rows) spell the word out, and "Plac Zamkowy" must key the
|
|
266
|
-
* same as a query's "plac zamkowy" or bare "Zamkowy". Never stripped when it is the only token.
|
|
192
|
+
* Italian street types in the abbreviated spellings a person types, mapped to the spelling ANNCSU publishes.
|
|
267
193
|
*/
|
|
268
|
-
const
|
|
194
|
+
const IT_STREET_TYPE_ABBREV = new Map<string, string>([
|
|
195
|
+
["v", "via"],
|
|
196
|
+
["vle", "viale"],
|
|
197
|
+
["vl", "viale"],
|
|
198
|
+
["vic", "vicolo"],
|
|
199
|
+
["vlo", "vicolo"],
|
|
200
|
+
["str", "strada"],
|
|
201
|
+
["pza", "piazza"],
|
|
202
|
+
["pzza", "piazza"],
|
|
203
|
+
["p", "piazza"],
|
|
204
|
+
["ple", "piazzale"],
|
|
205
|
+
["cso", "corso"],
|
|
206
|
+
["c", "corso"],
|
|
207
|
+
["lgo", "largo"],
|
|
208
|
+
["loc", "localita"],
|
|
209
|
+
["fraz", "frazione"],
|
|
210
|
+
["cda", "contrada"],
|
|
211
|
+
["lungarno", "lungarno"],
|
|
212
|
+
])
|
|
269
213
|
|
|
270
214
|
/**
|
|
271
|
-
*
|
|
215
|
+
* Spanish street-type abbreviations whose expansion is the same token in every language
|
|
216
|
+
* the register writes after `fold`; `c/`, `av`, and `pl` are deliberately absent
|
|
217
|
+
* because they expand differently by region.
|
|
272
218
|
*/
|
|
219
|
+
const ES_STREET_TYPE_ABBREV = new Map<string, string>([
|
|
220
|
+
["ctra", "carretera"],
|
|
221
|
+
["crta", "carretera"],
|
|
222
|
+
["rbla", "rambla"],
|
|
223
|
+
["gta", "glorieta"],
|
|
224
|
+
["cjon", "callejon"],
|
|
225
|
+
["rda", "ronda"],
|
|
226
|
+
])
|
|
227
|
+
|
|
273
228
|
const ID_STREET_ABBREV = new Map<string, string>([
|
|
274
229
|
["jl", "jalan"],
|
|
275
230
|
["jln", "jalan"],
|
|
@@ -277,42 +232,19 @@ const ID_STREET_ABBREV = new Map<string, string>([
|
|
|
277
232
|
])
|
|
278
233
|
|
|
279
234
|
/**
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
* - **en** — the shared English address-key pipeline (directionals + suffix aliases), currently identical to US.
|
|
284
|
-
* - **fr** — fold + expand leading type abbreviations and Saint/Sainte (token map).
|
|
285
|
-
* - **de** — fold + ß→ss + canonicalize the GLUED `-str(.)` suffix to `-strasse` ("Lindenstr." → "lindenstrasse",
|
|
286
|
-
* "Lindenstraße" → "lindenstrasse"); an already-full "-strasse" is left intact.
|
|
287
|
-
* - **nl** — fold + canonicalize the glued `-str` suffix to `-straat` ("Kerkstr." → "kerkstraat").
|
|
288
|
-
* - **pl** — fold + ł→l (Ł does not NFKD-decompose, so the generic fold keeps it and an undiacritized query would miss;
|
|
289
|
-
* every other Polish diacritic is a combining form the fold already strips) + STRIP the leading type token — see
|
|
290
|
-
* {@link PL_LEADING_TYPE} for the measured reason expansion was wrong for this source.
|
|
291
|
-
* - **vn** — fold + đ→d AND ð→d (both non-decomposing, and OSM mixes the two codepoints inside single values — see the
|
|
292
|
-
* branch comment). Deliberately NO type-abbreviation map yet: the common abbreviation is the single letter "Đ." for
|
|
293
|
-
* Đường, and expanding a bare folded "d" token would rewrite initials — measure the miss rate on the built extract
|
|
294
|
-
* before adding anything.
|
|
295
|
-
* - **id** — fold + expand leading type abbreviations (jl/jln→jalan, gg→gang); Indonesian street surfaces are otherwise
|
|
296
|
-
* ASCII-clean.
|
|
235
|
+
* Normalizes a street name into an address-point key under the given locale, delegating `us`
|
|
236
|
+
* and `en` to {@link normalizeStreetForKey}; the extract builder and the probe must both call it.
|
|
297
237
|
*/
|
|
298
238
|
export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale): StreetKey {
|
|
299
239
|
if (locale === "us" || locale === "en") return normalizeStreetForKey(street)
|
|
300
240
|
|
|
301
|
-
// A Han street name has no tokens, no type abbreviation and no diacritics; the Latin pipeline below would only
|
|
302
|
-
// split it on whitespace it never carries. `zh` keys are the Han fold and nothing else.
|
|
303
241
|
if (locale === "zh") return foldHan(street) as StreetKey
|
|
304
242
|
|
|
305
|
-
// Hyphen → space so a compound name keys the same whether the source or the query writes the
|
|
306
|
-
// hyphen ("Champs-Élysées", "St-Honoré") or a space — both sides fold identically, so this is pure
|
|
307
|
-
// robustness. It also splits a hyphenated abbreviation ("St-Honoré" → "st honore") into tokens the
|
|
308
|
-
// per-locale type/Saint map can see. Letter maps for non-decomposing letters (ß, ł, đ) live in the
|
|
309
|
-
// per-locale branches, NEVER here: widening the shared pipeline would silently change keys under
|
|
310
|
-
// every already-built extract of the other locales.
|
|
311
243
|
const tokens = fold(street)
|
|
312
244
|
.replaceAll("ß", "ss")
|
|
313
245
|
.replaceAll("-", " ")
|
|
314
246
|
.split(/\s+/)
|
|
315
|
-
.filter((value) => value.length
|
|
247
|
+
.filter((value) => value.length)
|
|
316
248
|
|
|
317
249
|
if (!tokens.length) return "" as StreetKey
|
|
318
250
|
|
|
@@ -331,6 +263,20 @@ export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale
|
|
|
331
263
|
}
|
|
332
264
|
}
|
|
333
265
|
break
|
|
266
|
+
case "it":
|
|
267
|
+
// The leading type is expanded and kept, unlike `pl`, because dropping it
|
|
268
|
+
// merges distinct streets that share a name.
|
|
269
|
+
if (tokens.length > 1) {
|
|
270
|
+
tokens[0] = IT_STREET_TYPE_ABBREV.get(tokens[0]!) ?? tokens[0]!
|
|
271
|
+
}
|
|
272
|
+
break
|
|
273
|
+
case "es":
|
|
274
|
+
// Keep the leading type, as `it` does and more strongly, because `Calle Mayor`
|
|
275
|
+
// and `Plaza Mayor` often share a municipio.
|
|
276
|
+
if (tokens.length > 1) {
|
|
277
|
+
tokens[0] = ES_STREET_TYPE_ABBREV.get(tokens[0]!) ?? tokens[0]!
|
|
278
|
+
}
|
|
279
|
+
break
|
|
334
280
|
case "nl":
|
|
335
281
|
for (let i = 0; i < tokens.length; i++) {
|
|
336
282
|
const t = tokens[i]!
|
|
@@ -355,11 +301,6 @@ export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale
|
|
|
355
301
|
}
|
|
356
302
|
break
|
|
357
303
|
case "vn":
|
|
358
|
-
// đ (U+0111, d-with-stroke) AND ð (U+00F0, eth): OSM Vietnamese data mixes the two visually
|
|
359
|
-
// identical codepoints inside single values — the 2026-08-19 extract measured `Đường Trần Hưng
|
|
360
|
-
// Đạo` carrying d-with-stroke at the front and ETH in `Đạo`, splitting the country's most
|
|
361
|
-
// common street into two keys with the MAJORITY variant (630 vs 421 rows) unreachable by a
|
|
362
|
-
// correctly-typed query. No abbreviation map — see the locale table.
|
|
363
304
|
for (let i = 0; i < tokens.length; i++) {
|
|
364
305
|
tokens[i] = tokens[i]!.replaceAll("đ", "d").replaceAll("ð", "d")
|
|
365
306
|
}
|
|
@@ -370,30 +311,27 @@ export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale
|
|
|
370
311
|
}
|
|
371
312
|
|
|
372
313
|
/**
|
|
373
|
-
* Normalize a locality name for address-point keying
|
|
314
|
+
* Normalize a locality name for address-point keying, fold only with no street semantics.
|
|
374
315
|
*/
|
|
375
316
|
export function normalizeLocalityForKey(locality: string): NameKey {
|
|
376
317
|
return fold(locality) as NameKey
|
|
377
318
|
}
|
|
378
319
|
|
|
379
320
|
/**
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
321
|
+
* Folds a locality name into a {@link NameKey} with the Han fold for `zh`
|
|
322
|
+
* and {@link normalizeLocalityForKey} otherwise.
|
|
323
|
+
*
|
|
324
|
+
* The Han rule stays out of the shared fold so existing columns are not re-keyed.
|
|
383
325
|
*/
|
|
384
326
|
export function normalizeLocalityForKeyLocale(locality: string, locale: StreetLocale): NameKey {
|
|
385
327
|
return locale === "zh" ? (foldHan(locality) as NameKey) : normalizeLocalityForKey(locality)
|
|
386
328
|
}
|
|
387
329
|
|
|
388
330
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* itself (`122號`), which a parse also carries on the `house_number` span (`122號`). Both sides key `122`.
|
|
331
|
+
* Folds a house number into an address-point key, additionally width-folding
|
|
332
|
+
* and dropping the trailing 號 for `zh`.
|
|
392
333
|
*/
|
|
393
334
|
export function normalizeHouseNumberForKey(number: string, locale: StreetLocale): string {
|
|
394
|
-
// The sub-number is written two ways — `30之19號` and `30號之19` — and an attached number a third (`30附40號`,
|
|
395
|
-
// `55之23附1號`); the register stores the base `30` with the rest in `unit`. Every form keys with the 號 dropped and
|
|
396
|
-
// the base number first, which the reader's sub-number rung then falls from.
|
|
397
335
|
if (locale === "zh") {
|
|
398
336
|
return foldHan(number)
|
|
399
337
|
.replace(/^(\d+)號([之附]\d+)$/u, "$1$2")
|
|
@@ -403,45 +341,21 @@ export function normalizeHouseNumberForKey(number: string, locale: StreetLocale)
|
|
|
403
341
|
return number.trim().toLowerCase()
|
|
404
342
|
}
|
|
405
343
|
|
|
406
|
-
/**
|
|
407
|
-
* Leading French street-type token. French types LEAD the name ("avenue du Parc", "boul Saint-Laurent") while English
|
|
408
|
-
* types TRAIL ("Fifth Avenue", "Grosvenor Place"), so a leading type-token is the discriminating signal — "1 Avenue NE"
|
|
409
|
-
* starts with a digit and never matches. The separator lookahead is explicit rather than `\b` because a word boundary
|
|
410
|
-
* after an accented final letter ("carré") is not one to an ASCII-word `\b`.
|
|
411
|
-
*/
|
|
412
344
|
const FRENCH_LEAD_TYPE =
|
|
413
345
|
/^(?:rue|ruelle|av|ave|avenue|boul|bd|boulevard|ch|che|chemin|all[ée]e|imp|impasse|mont[ée]e|c[ôo]te|pl|place|prom|promenade|rang|rte|route|autoroute|carr[eé]|croissant|terrasse|sentier)(?=[\s.-]|$)/i
|
|
414
346
|
|
|
415
347
|
/**
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
* surface passes through mostly unchanged (both sides fold identically, so those rows stay reachable), and what breaks
|
|
420
|
-
* is abbreviation variance — the `en` rules cannot fold "boul"/"Ste-" to the full French word, so an abbreviated query
|
|
421
|
-
* misses a full-word row and vice versa. Routing on the SURFACE (not the province) also carries bilingual NB and the
|
|
422
|
-
* French street names outside Québec for free.
|
|
423
|
-
*
|
|
424
|
-
* ONE function, called by the extract BUILDER and the query PROBE alike — the #861 discipline: routing is part of the
|
|
425
|
-
* fold contract, and two transcriptions of this predicate would diverge exactly where it matters. Only an `en` base
|
|
426
|
-
* re-routes: a `fr`/`de`/`nl` extract already speaks its own rules, and the US pipeline stays untouched.
|
|
427
|
-
*
|
|
428
|
-
* Measured basis (CA extract, 2026-08-19): 183,963 distinct surfaces, 43,762 French-lead; 29,682 fold differently under
|
|
429
|
-
* fr-vs-en (888,265 rows), and the non-French half of those are English surfaces this router keeps on `en` unchanged.
|
|
348
|
+
* Routes an `en` street surface leading with a French type word to the `fr` locale
|
|
349
|
+
* and returns any other base unchanged, routing on the surface rather than the province
|
|
350
|
+
* so bilingual Canadian extracts fold consistently.
|
|
430
351
|
*/
|
|
431
352
|
export function streetLocaleForSurface(street: string, base: StreetLocale): StreetLocale {
|
|
432
353
|
return base === "en" && FRENCH_LEAD_TYPE.test(street.trimStart()) ? "fr" : base
|
|
433
354
|
}
|
|
434
355
|
|
|
435
356
|
/**
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
* only French communes subdivided into _arrondissements municipaux_; a national register (BAN) names each row per
|
|
439
|
-
* arrondissement, but a query names the base commune ("Place Bellecour, Lyon", never "…, Lyon 2e"). Applied on BOTH
|
|
440
|
-
* sides of the #1042 street-centroid key — build-side (deriving the `locality_base` column) and query-side (folding the
|
|
441
|
-
* probe commune) — so the two agree by construction (the one-function discipline). The {@link NameKey} parameter is the
|
|
442
|
-
* enforcement of "must already be folded": stripping an arrondissement off an unfolded surface yields a key neither
|
|
443
|
-
* side stores. A no-op for every other commune, and the strip leaves a fold fixed point, so the result is still a
|
|
444
|
-
* {@link NameKey}. Returns the input unchanged if the strip would empty it.
|
|
357
|
+
* Strips a trailing French arrondissement designator from a folded commune key,
|
|
358
|
+
* returning the input unchanged when the strip would leave no text.
|
|
445
359
|
*/
|
|
446
360
|
export function stripArrondissement(localityNorm: NameKey): NameKey {
|
|
447
361
|
const stripped = localityNorm.replace(/\s+\d+(?:er|e)\s+arrondissement$/, "").trim() as NameKey
|
|
@@ -450,17 +364,10 @@ export function stripArrondissement(localityNorm: NameKey): NameKey {
|
|
|
450
364
|
}
|
|
451
365
|
|
|
452
366
|
/**
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
* gazetteer's canonical name omits: Austrian `Kraubath/Mur` and `Hart b.Graz` → `Hart`; Swiss `Lenk im Simmental` →
|
|
456
|
-
* `Lenk`, `Roche VD` → `Roche`; Danish `Odense S`, `Hurup Thy`. A FALLBACK ONLY — the exact name is tried first, and
|
|
457
|
-
* the region-bbox disambiguation resolves any base-name ambiguity downstream. The candidate table is unchanged (this is
|
|
458
|
-
* purely query-side); feed the result back through {@link normalizeLocalityForKey}. Returns "" when nothing was stripped
|
|
459
|
-
* (no point re-probing the identical key).
|
|
367
|
+
* Strips a disambiguating qualifier from a locality name for a query-side retry,
|
|
368
|
+
* returning an empty string when no text was stripped.
|
|
460
369
|
*
|
|
461
|
-
*
|
|
462
|
-
* 91.5→96.2%, CH 90.4→92.6%; +1.3pp overall (diluted by the already-100% locales). Conservative by design — only the
|
|
463
|
-
* qualifier forms above; FI/PT/SI misses are untouched.
|
|
370
|
+
* The result must be refolded with {@link normalizeLocalityForKey} before probing.
|
|
464
371
|
*/
|
|
465
372
|
export function stripLocalityQualifier(locality: string): string {
|
|
466
373
|
let s = locality.trim()
|
|
@@ -470,7 +377,7 @@ export function stripLocalityQualifier(locality: string): string {
|
|
|
470
377
|
}
|
|
471
378
|
|
|
472
379
|
const words = [...s.matchAll(/\S+/gu)].map((match) => ({ value: match[0], index: match.index }))
|
|
473
|
-
let qualifierStart: number |
|
|
380
|
+
let qualifierStart: number | null = null
|
|
474
381
|
|
|
475
382
|
for (let index = 1; index < words.length; index++) {
|
|
476
383
|
const word = words[index]!
|
|
@@ -493,7 +400,7 @@ export function stripLocalityQualifier(locality: string): string {
|
|
|
493
400
|
const suffix = words.at(-1)
|
|
494
401
|
|
|
495
402
|
if (
|
|
496
|
-
qualifierStart ===
|
|
403
|
+
qualifierStart === null &&
|
|
497
404
|
suffix &&
|
|
498
405
|
words.length > 1 &&
|
|
499
406
|
(["S", "N", "E", "W", "V", "Ø", "Sø", "Fyn", "Thy", "Sjælland", "Jylland"].includes(suffix.value) ||
|
|
@@ -502,7 +409,7 @@ export function stripLocalityQualifier(locality: string): string {
|
|
|
502
409
|
qualifierStart = suffix.index
|
|
503
410
|
}
|
|
504
411
|
|
|
505
|
-
if (qualifierStart !==
|
|
412
|
+
if (qualifierStart !== null) {
|
|
506
413
|
s = s.slice(0, qualifierStart).trimEnd()
|
|
507
414
|
}
|
|
508
415
|
|
|
@@ -512,57 +419,24 @@ export function stripLocalityQualifier(locality: string): string {
|
|
|
512
419
|
}
|
|
513
420
|
|
|
514
421
|
/**
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
* 100` / `US ROUTE 5` — the dominant street-name miss class in the #483 interpolation eval (rural addresses live on
|
|
518
|
-
* routes). `us <designator> N…` folds to `us route N…`; `state <designator> N…` and `<2-letter-prefix> <designator> N…`
|
|
519
|
-
* (the state abbreviation form) fold to `state route N…`. Only digit-leading route numbers fold — `State Street` and
|
|
520
|
-
* friends never match.
|
|
521
|
-
*
|
|
522
|
-
* Used by BOTH the segment-extract builder (`scripts/build-interpolation-extract.ts`) and the interpolation lookup —
|
|
523
|
-
* same one-function discipline as {@link normalizeStreetForKey}. The address-point tier (#476) does NOT apply it yet:
|
|
524
|
-
* adopting it there requires a extract rebuild (noted on #483).
|
|
525
|
-
*
|
|
526
|
-
* A same-numbered US and state route stay DISTINCT keys (`us route 5` vs `state route 5`); only the BARE `route N` form
|
|
527
|
-
* is ambiguous (designator unknown) and it stays unfolded — a bare-route query therefore misses rather than guessing a
|
|
528
|
-
* designator.
|
|
422
|
+
* Folds a numbered-route designator in a street key to `us route N` or `state route N`;
|
|
423
|
+
* only digit-leading numbers after a `us`, `state`, or two-letter prefix fold.
|
|
529
424
|
*/
|
|
530
425
|
export function canonicalizeRouteKey(streetNorm: StreetKey): RouteKey {
|
|
531
426
|
const match = /^(us|state|[a-z]{2}) (?:route|rte|rt|highway|hwy) (\d.*)$/.exec(streetNorm)
|
|
532
427
|
|
|
533
|
-
// A street naming no route is already its own route key. {@link StreetKey} and {@link RouteKey} are
|
|
534
|
-
// SIBLING brands rather than nested ones — precisely so neither column accepts the other's key — so
|
|
535
|
-
// re-minting here is an explicit hop through the unbranded string.
|
|
536
428
|
if (!match) return streetNorm as string as RouteKey
|
|
537
429
|
|
|
538
430
|
return `${match[1] === "us" ? "us" : "state"} route ${match[2]}` as RouteKey
|
|
539
431
|
}
|
|
540
432
|
|
|
541
|
-
/**
|
|
542
|
-
* The canonical street-type words (lowercase) — the VALUE side of the codex suffix table. Membership means "this
|
|
543
|
-
* normalized token is a fully-spelled street type" ("place", "street", "road" …), which is how the doubled-type
|
|
544
|
-
* collapse below recognizes its shape without any parse-tree knowledge.
|
|
545
|
-
*/
|
|
546
433
|
const CANONICAL_TYPE_WORDS: ReadonlySet<string> = new Set(
|
|
547
434
|
[...US_STREET_SUFFIX_LOOKUP.values()].map((v) => v.toLowerCase())
|
|
548
435
|
)
|
|
549
436
|
|
|
550
437
|
/**
|
|
551
|
-
*
|
|
552
|
-
*
|
|
553
|
-
* queries (2026-08-14):
|
|
554
|
-
*
|
|
555
|
-
* - **Doubled type** — a user types the type twice ("Saint Pauls PL St"), and the normalizer canonicalizes only the LAST
|
|
556
|
-
* type token, leaving `saint pauls pl street`, which matches nothing anywhere. The signature is visible in the key
|
|
557
|
-
* itself: a canonical type word in last position DIRECTLY after an uncanonicalized type abbreviation. The variant
|
|
558
|
-
* drops the trailing word and canonicalizes what remains (`saint pauls place`). A street genuinely named with two
|
|
559
|
-
* types keys identically on both sides and is caught by the primary probe first.
|
|
560
|
-
* - **Saint↔St register split** — the artifacts preserve each SOURCE's spelling (NYC situs keys `st pauls place`, Nassau
|
|
561
|
-
* keys `saint pauls place`), and a query arrives in whichever register the user typed. A leading `saint` or `st`
|
|
562
|
-
* token is swapped for its sibling; leading position only — a leading `st` is always the hagionym in US street names,
|
|
563
|
-
* and interior tokens ("Mount Saint Helens Dr") are out of scope until measured.
|
|
564
|
-
*
|
|
565
|
-
* Deduplicated and ordered most-literal-first, so probing the list in order preserves the primary key's precedence.
|
|
438
|
+
* Lists the lookup keys to probe for a street span, most literal first, adding doubled-type
|
|
439
|
+
* and Saint/St-swap recovery forms for `us` and `en`.
|
|
566
440
|
*/
|
|
567
441
|
export function streetKeyVariants(street: string, locale: StreetLocale = "us"): StreetKey[] {
|
|
568
442
|
const primary = locale === "us" ? normalizeStreetForKey(street) : normalizeStreetForKeyLocale(street, locale)
|
|
@@ -589,8 +463,6 @@ export function streetKeyVariants(street: string, locale: StreetLocale = "us"):
|
|
|
589
463
|
}
|
|
590
464
|
}
|
|
591
465
|
|
|
592
|
-
// Snapshot before the swap pass — it appends while reading, and iterating the live array would
|
|
593
|
-
// re-visit its own additions.
|
|
594
466
|
const preSwap = variants.slice()
|
|
595
467
|
|
|
596
468
|
for (const variant of preSwap) {
|
|
@@ -598,9 +470,6 @@ export function streetKeyVariants(street: string, locale: StreetLocale = "us"):
|
|
|
598
470
|
const swapped = head === "saint" ? "st" : head === "st" ? "saint" : null
|
|
599
471
|
|
|
600
472
|
if (swapped && rest.length) {
|
|
601
|
-
// Substituting a leading hagionym token in an already-normalized key leaves a fold fixed point —
|
|
602
|
-
// the suffix pass never rewrites position 0 — so the swap yields a {@link StreetKey} without
|
|
603
|
-
// re-folding.
|
|
604
473
|
const candidate = [swapped, ...rest].join(" ") as StreetKey
|
|
605
474
|
|
|
606
475
|
if (!variants.includes(candidate)) {
|