@mailwoman/resolver-wof-sqlite 9.2.0 → 9.4.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 +16 -19
- package/lib/address/index.ts +9 -0
- package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +25 -24
- package/{address-point-schema.ts → lib/address/point-schema.ts} +18 -4
- package/lib/address/point.ts +328 -0
- package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
- package/{ancestry.ts → lib/ancestry/index.ts} +5 -4
- package/{build-candidate.ts → lib/build-candidate.ts} +99 -79
- package/{build-slim.ts → lib/build-slim.ts} +150 -165
- package/{candidate → lib/candidate}/alias-bags.ts +8 -6
- package/{candidate → lib/candidate}/ancestors-sidecar.ts +13 -15
- package/{candidate → lib/candidate}/country-display-names.ts +2 -2
- package/lib/candidate/extract-fold.ts +219 -0
- package/{candidate → lib/candidate}/name-roles.ts +17 -16
- package/{candidate → lib/candidate}/own-name.ts +2 -1
- package/{candidate → lib/candidate}/place-attrs.ts +3 -3
- package/{candidate-ancestors-schema.ts → lib/candidate-ancestors-schema.ts} +4 -4
- package/{candidate-fts.ts → lib/candidate-fts.ts} +3 -3
- package/{candidate-importance.ts → lib/candidate-importance.ts} +53 -57
- package/{candidate-lookup.ts → lib/candidate-lookup.ts} +84 -80
- package/{candidate-schema.ts → lib/candidate-schema.ts} +6 -6
- package/{candidate-scoring.ts → lib/candidate-scoring.ts} +15 -22
- package/{capital-schema.ts → lib/capital-schema.ts} +5 -6
- package/{capitals.ts → lib/capitals.ts} +2 -2
- package/{coincident-roles.ts → lib/coincident-roles.ts} +9 -13
- package/{convention.ts → lib/convention/index.ts} +3 -3
- package/{convention-schema.ts → lib/convention/schema.ts} +2 -2
- package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +10 -10
- package/{currency-backfill.ts → lib/currency-backfill.ts} +126 -41
- package/lib/env.ts +50 -0
- package/{exact-match.ts → lib/exact-match.ts} +23 -14
- package/{sharding.ts → lib/extracts.ts} +61 -58
- package/{fst-autocomplete.ts → lib/fst/autocomplete.ts} +4 -4
- package/{fst-builder.ts → lib/fst/builder.ts} +17 -16
- package/{fst-deserialize-web.ts → lib/fst/deserialize-web.ts} +27 -87
- package/lib/fst/format.ts +106 -0
- package/{fst-freshness.ts → lib/fst/freshness.ts} +40 -74
- package/lib/fst/index.ts +14 -0
- package/{fst-matcher.ts → lib/fst/matcher.ts} +1 -1
- package/{fst-serialize.ts → lib/fst/serialize.ts} +37 -115
- package/{fst-types.ts → lib/fst/types.ts} +4 -2
- package/{fts.ts → lib/fts/index.ts} +24 -19
- package/{fts-query.ts → lib/fts/query.ts} +1 -1
- package/{geonames-aliases.ts → lib/geonames/aliases.ts} +13 -13
- package/lib/geonames/index.ts +8 -0
- package/{geonames-postal.ts → lib/geonames/postal.ts} +14 -13
- package/{index.ts → lib/index.ts} +37 -37
- package/{interpolation.ts → lib/interpolation.ts} +28 -26
- package/{lookup.ts → lib/lookup.ts} +130 -142
- package/lib/nsul/index.ts +8 -0
- package/lib/nsul/lookup.ts +144 -0
- package/lib/nsul/schema.ts +130 -0
- package/{place-importance-schema.ts → lib/place-importance-schema.ts} +7 -16
- package/lib/poi/index.ts +8 -0
- package/{poi-lookup.ts → lib/poi/lookup.ts} +22 -29
- package/{poi-schema.ts → lib/poi/schema.ts} +3 -4
- package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +14 -20
- package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +2 -2
- package/lib/postal/index.ts +9 -0
- package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
- package/{primary-preference.ts → lib/primary-preference.ts} +43 -14
- package/{proximity-rerank.ts → lib/proximity-rerank.ts} +2 -2
- package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
- package/{region-keys.ts → lib/region-keys.ts} +9 -9
- package/{reverse.ts → lib/reverse.ts} +34 -47
- package/{schema.ts → lib/schema.ts} +10 -0
- package/{search-fetch.ts → lib/search-fetch.ts} +29 -29
- package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
- package/{sqlite-utils.ts → lib/sqlite-utils.ts} +14 -19
- package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +5 -5
- package/{street-centroid.ts → lib/street/centroid.ts} +15 -22
- package/lib/street/index.ts +13 -0
- package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
- package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
- package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
- package/{street-normalize.ts → lib/street/normalize.ts} +86 -20
- package/{street-segment-schema.ts → lib/street/segment-schema.ts} +7 -7
- package/{types.ts → lib/types.ts} +18 -12
- package/{unified-schema.ts → lib/unified-schema.ts} +20 -24
- package/lib/uprn/existence.ts +84 -0
- package/lib/uprn/index.ts +9 -0
- package/{uprn-lookup.ts → lib/uprn/lookup.ts} +14 -19
- package/{uprn-schema.ts → lib/uprn/schema.ts} +3 -3
- package/lib/weights-overlay-linker.ts +879 -0
- package/out/address/index.d.ts +9 -0
- package/out/address/index.d.ts.map +1 -0
- package/out/address/index.js +9 -0
- package/out/address/index.js.map +1 -0
- package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +12 -11
- package/out/address/point-interpolation.d.ts.map +1 -0
- package/out/{address-point-interpolation.js → address/point-interpolation.js} +18 -18
- package/out/address/point-interpolation.js.map +1 -0
- package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +16 -6
- package/out/address/point-schema.d.ts.map +1 -0
- package/out/{address-point-schema.js → address/point-schema.js} +7 -3
- package/out/address/point-schema.js.map +1 -0
- package/out/{address-point.d.ts → address/point.d.ts} +19 -9
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +222 -0
- package/out/address/point.js.map +1 -0
- package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
- package/out/ancestry/backfill.d.ts.map +1 -0
- package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
- package/out/ancestry/backfill.js.map +1 -0
- package/out/{ancestry.d.ts → ancestry/index.d.ts} +4 -3
- package/out/ancestry/index.d.ts.map +1 -0
- package/out/{ancestry.js → ancestry/index.js} +3 -2
- package/out/ancestry/index.js.map +1 -0
- package/out/build-candidate.d.ts +32 -24
- package/out/build-candidate.d.ts.map +1 -1
- package/out/build-candidate.js +60 -54
- package/out/build-candidate.js.map +1 -1
- package/out/build-slim.d.ts +4 -4
- package/out/build-slim.d.ts.map +1 -1
- package/out/build-slim.js +124 -139
- package/out/build-slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +5 -3
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +2 -2
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors-sidecar.d.ts +9 -10
- package/out/candidate/ancestors-sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors-sidecar.js +7 -7
- package/out/candidate/ancestors-sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +1 -1
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +1 -1
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +41 -0
- package/out/candidate/extract-fold.d.ts.map +1 -0
- package/out/candidate/extract-fold.js +153 -0
- package/out/candidate/extract-fold.js.map +1 -0
- package/out/candidate/name-roles.d.ts +13 -11
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +11 -10
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +1 -1
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +2 -1
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +3 -3
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +1 -1
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate-ancestors-schema.d.ts +4 -4
- package/out/candidate-ancestors-schema.d.ts.map +1 -1
- package/out/candidate-ancestors-schema.js +2 -2
- package/out/candidate-ancestors-schema.js.map +1 -1
- package/out/candidate-fts.d.ts +3 -3
- package/out/candidate-fts.d.ts.map +1 -1
- package/out/candidate-fts.js +1 -1
- package/out/candidate-fts.js.map +1 -1
- package/out/candidate-importance.d.ts +16 -16
- package/out/candidate-importance.d.ts.map +1 -1
- package/out/candidate-importance.js +46 -51
- package/out/candidate-importance.js.map +1 -1
- package/out/candidate-lookup.d.ts +16 -14
- package/out/candidate-lookup.d.ts.map +1 -1
- package/out/candidate-lookup.js +67 -63
- package/out/candidate-lookup.js.map +1 -1
- package/out/candidate-schema.d.ts +6 -6
- package/out/candidate-schema.d.ts.map +1 -1
- package/out/candidate-schema.js +1 -1
- package/out/candidate-schema.js.map +1 -1
- package/out/candidate-scoring.d.ts +7 -7
- package/out/candidate-scoring.d.ts.map +1 -1
- package/out/candidate-scoring.js +10 -14
- package/out/candidate-scoring.js.map +1 -1
- package/out/capital-schema.d.ts +3 -3
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +2 -2
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +1 -1
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +2 -2
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +7 -6
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +2 -4
- package/out/coincident-roles.js.map +1 -1
- package/out/{convention.d.ts → convention/index.d.ts} +4 -4
- package/out/convention/index.d.ts.map +1 -0
- package/out/{convention.js → convention/index.js} +2 -2
- package/out/convention/index.js.map +1 -0
- package/out/{convention-schema.d.ts → convention/schema.d.ts} +2 -2
- package/out/convention/schema.d.ts.map +1 -0
- package/out/{convention-schema.js → convention/schema.js} +3 -3
- package/out/convention/schema.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +8 -8
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +5 -4
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +51 -7
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +65 -49
- package/out/currency-backfill.js.map +1 -1
- package/out/env.d.ts +43 -0
- package/out/env.d.ts.map +1 -0
- package/out/env.js +48 -0
- package/out/env.js.map +1 -0
- package/out/exact-match.d.ts +5 -5
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +10 -11
- package/out/exact-match.js.map +1 -1
- package/out/extracts.d.ts +114 -0
- package/out/extracts.d.ts.map +1 -0
- package/out/{sharding.js → extracts.js} +38 -38
- package/out/extracts.js.map +1 -0
- package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +2 -2
- package/out/fst/autocomplete.d.ts.map +1 -0
- package/out/{fst-autocomplete.js → fst/autocomplete.js} +3 -3
- package/out/fst/autocomplete.js.map +1 -0
- package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
- package/out/fst/builder.d.ts.map +1 -0
- package/out/{fst-builder.js → fst/builder.js} +14 -13
- package/out/fst/builder.js.map +1 -0
- package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
- package/out/fst/deserialize-web.d.ts.map +1 -0
- package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
- package/out/fst/deserialize-web.js.map +1 -0
- package/out/fst/format.d.ts +80 -0
- package/out/fst/format.d.ts.map +1 -0
- package/out/fst/format.js +91 -0
- package/out/fst/format.js.map +1 -0
- package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +9 -13
- package/out/fst/freshness.d.ts.map +1 -0
- package/out/{fst-freshness.js → fst/freshness.js} +40 -73
- package/out/fst/freshness.js.map +1 -0
- package/out/fst/index.d.ts +14 -0
- package/out/fst/index.d.ts.map +1 -0
- package/out/fst/index.js +14 -0
- package/out/fst/index.js.map +1 -0
- package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
- package/out/fst/matcher.d.ts.map +1 -0
- package/out/{fst-matcher.js → fst/matcher.js} +1 -1
- package/out/fst/matcher.js.map +1 -0
- package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
- package/out/fst/serialize.d.ts.map +1 -0
- package/out/{fst-serialize.js → fst/serialize.js} +18 -98
- package/out/fst/serialize.js.map +1 -0
- package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
- package/out/fst/types.d.ts.map +1 -0
- package/out/{fst-types.js → fst/types.js} +1 -1
- package/out/fst/types.js.map +1 -0
- package/out/{fts.d.ts → fts/index.d.ts} +16 -9
- package/out/fts/index.d.ts.map +1 -0
- package/out/{fts.js → fts/index.js} +16 -11
- package/out/fts/index.js.map +1 -0
- package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
- package/out/fts/query.d.ts.map +1 -0
- package/out/{fts-query.js → fts/query.js} +1 -1
- package/out/fts/query.js.map +1 -0
- package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
- package/out/geonames/aliases.d.ts.map +1 -0
- package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
- package/out/geonames/aliases.js.map +1 -0
- package/out/geonames/index.d.ts +8 -0
- package/out/geonames/index.d.ts.map +1 -0
- package/out/geonames/index.js +8 -0
- package/out/geonames/index.js.map +1 -0
- package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +10 -8
- package/out/geonames/postal.d.ts.map +1 -0
- package/out/{geonames-postal.js → geonames/postal.js} +9 -9
- package/out/geonames/postal.js.map +1 -0
- package/out/index.d.ts +32 -32
- package/out/index.d.ts.map +1 -1
- package/out/index.js +24 -24
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +11 -10
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +20 -20
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +22 -21
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +103 -113
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js.map +1 -1
- package/out/nsul/index.d.ts +8 -0
- package/out/nsul/index.d.ts.map +1 -0
- package/out/nsul/index.js +8 -0
- package/out/nsul/index.js.map +1 -0
- package/out/nsul/lookup.d.ts +83 -0
- package/out/nsul/lookup.d.ts.map +1 -0
- package/out/nsul/lookup.js +80 -0
- package/out/nsul/lookup.js.map +1 -0
- package/out/nsul/schema.d.ts +100 -0
- package/out/nsul/schema.d.ts.map +1 -0
- package/out/nsul/schema.js +78 -0
- package/out/nsul/schema.js.map +1 -0
- package/out/place-importance-schema.d.ts +5 -6
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +3 -4
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/index.d.ts +8 -0
- package/out/poi/index.d.ts.map +1 -0
- package/out/poi/index.js +8 -0
- package/out/poi/index.js.map +1 -0
- package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
- package/out/poi/lookup.d.ts.map +1 -0
- package/out/{poi-lookup.js → poi/lookup.js} +14 -18
- package/out/poi/lookup.js.map +1 -0
- package/out/{poi-schema.d.ts → poi/schema.d.ts} +4 -4
- package/out/poi/schema.d.ts.map +1 -0
- package/out/{poi-schema.js → poi/schema.js} +1 -1
- package/out/poi/schema.js.map +1 -0
- package/out/polygon-schema.d.ts.map +1 -1
- package/out/polygon-schema.js.map +1 -1
- package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +6 -5
- package/out/postal/city-alias-lookup.d.ts.map +1 -0
- package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +11 -15
- package/out/postal/city-alias-lookup.js.map +1 -0
- package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
- package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
- package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
- package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
- package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +3 -3
- package/out/{postal-city-candidate-schema.d.ts.map → postal/city-candidate-schema.d.ts.map} +1 -1
- package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
- package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
- package/out/postal/index.d.ts +9 -0
- package/out/postal/index.d.ts.map +1 -0
- package/out/postal/index.js +9 -0
- package/out/postal/index.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +10 -10
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +13 -13
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +15 -7
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +28 -12
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +2 -2
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +2 -2
- package/out/proximity-rerank.js.map +1 -1
- package/out/ranking-weights.d.ts +15 -3
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +21 -3
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +8 -8
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +9 -9
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +6 -6
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +20 -29
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +9 -0
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +12 -10
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +21 -20
- package/out/search-fetch.js.map +1 -1
- package/out/sqlite-convention-source.d.ts +7 -7
- package/out/sqlite-convention-source.d.ts.map +1 -1
- package/out/sqlite-convention-source.js +5 -5
- package/out/sqlite-convention-source.js.map +1 -1
- package/out/sqlite-utils.d.ts +8 -9
- package/out/sqlite-utils.d.ts.map +1 -1
- package/out/sqlite-utils.js +6 -10
- package/out/sqlite-utils.js.map +1 -1
- package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +6 -6
- package/out/{street-centroid-schema.d.ts.map → street/centroid-schema.d.ts.map} +1 -1
- package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
- package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
- package/out/{street-centroid.d.ts → street/centroid.d.ts} +7 -7
- package/out/street/centroid.d.ts.map +1 -0
- package/out/{street-centroid.js → street/centroid.js} +13 -19
- package/out/street/centroid.js.map +1 -0
- package/out/street/index.d.ts +13 -0
- package/out/street/index.d.ts.map +1 -0
- package/out/street/index.js +13 -0
- package/out/street/index.js.map +1 -0
- package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
- package/out/street/morphology-fst-builder.d.ts.map +1 -0
- package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
- package/out/street/morphology-fst-builder.js.map +1 -0
- package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
- package/out/street/morphology-fst-loader.d.ts.map +1 -0
- package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
- package/out/street/morphology-fst-loader.js.map +1 -0
- package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
- package/out/street/name-lookup.d.ts.map +1 -0
- package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
- package/out/street/name-lookup.js.map +1 -0
- package/out/{street-normalize.d.ts → street/normalize.d.ts} +38 -15
- package/out/street/normalize.d.ts.map +1 -0
- package/out/{street-normalize.js → street/normalize.js} +73 -17
- package/out/street/normalize.js.map +1 -0
- package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +8 -8
- package/out/{street-segment-schema.d.ts.map → street/segment-schema.d.ts.map} +1 -1
- package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
- package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
- package/out/types.d.ts +18 -12
- package/out/types.d.ts.map +1 -1
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +5 -4
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +15 -18
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +53 -0
- package/out/uprn/existence.d.ts.map +1 -0
- package/out/uprn/existence.js +61 -0
- package/out/uprn/existence.js.map +1 -0
- package/out/uprn/index.d.ts +9 -0
- package/out/uprn/index.d.ts.map +1 -0
- package/out/uprn/index.js +9 -0
- package/out/uprn/index.js.map +1 -0
- package/out/{uprn-lookup.d.ts → uprn/lookup.d.ts} +4 -4
- package/out/uprn/lookup.d.ts.map +1 -0
- package/out/{uprn-lookup.js → uprn/lookup.js} +11 -14
- package/out/uprn/lookup.js.map +1 -0
- package/out/{uprn-schema.d.ts → uprn/schema.d.ts} +4 -4
- package/out/uprn/schema.d.ts.map +1 -0
- package/out/{uprn-schema.js → uprn/schema.js} +4 -4
- package/out/uprn/schema.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +184 -26
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +339 -86
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +465 -269
- package/address-point.ts +0 -218
- package/candidate/shard-fold.ts +0 -137
- package/out/address-point-interpolation.d.ts.map +0 -1
- package/out/address-point-interpolation.js.map +0 -1
- package/out/address-point-schema.d.ts.map +0 -1
- package/out/address-point-schema.js.map +0 -1
- package/out/address-point.d.ts.map +0 -1
- package/out/address-point.js +0 -140
- package/out/address-point.js.map +0 -1
- package/out/ancestry-backfill.d.ts.map +0 -1
- package/out/ancestry-backfill.js.map +0 -1
- package/out/ancestry.d.ts.map +0 -1
- package/out/ancestry.js.map +0 -1
- package/out/candidate/shard-fold.d.ts +0 -31
- package/out/candidate/shard-fold.d.ts.map +0 -1
- package/out/candidate/shard-fold.js +0 -104
- package/out/candidate/shard-fold.js.map +0 -1
- package/out/convention-schema.d.ts.map +0 -1
- package/out/convention-schema.js.map +0 -1
- package/out/convention.d.ts.map +0 -1
- package/out/convention.js.map +0 -1
- package/out/fst-autocomplete.d.ts.map +0 -1
- package/out/fst-autocomplete.js.map +0 -1
- package/out/fst-builder.d.ts.map +0 -1
- package/out/fst-builder.js.map +0 -1
- package/out/fst-deserialize-web.d.ts.map +0 -1
- package/out/fst-deserialize-web.js.map +0 -1
- package/out/fst-freshness.d.ts.map +0 -1
- package/out/fst-freshness.js.map +0 -1
- package/out/fst-matcher.d.ts.map +0 -1
- package/out/fst-matcher.js.map +0 -1
- package/out/fst-serialize.d.ts.map +0 -1
- package/out/fst-serialize.js.map +0 -1
- package/out/fst-types.d.ts.map +0 -1
- package/out/fst-types.js.map +0 -1
- package/out/fts-query.d.ts.map +0 -1
- package/out/fts-query.js.map +0 -1
- package/out/fts.d.ts.map +0 -1
- package/out/fts.js.map +0 -1
- package/out/geonames-aliases.d.ts.map +0 -1
- package/out/geonames-aliases.js.map +0 -1
- package/out/geonames-postal.d.ts.map +0 -1
- package/out/geonames-postal.js.map +0 -1
- package/out/poi-lookup.d.ts.map +0 -1
- package/out/poi-lookup.js.map +0 -1
- package/out/poi-schema.d.ts.map +0 -1
- package/out/poi-schema.js.map +0 -1
- package/out/postal-city-alias-lookup.d.ts.map +0 -1
- package/out/postal-city-alias-lookup.js.map +0 -1
- package/out/sharding.d.ts +0 -114
- package/out/sharding.d.ts.map +0 -1
- package/out/sharding.js.map +0 -1
- package/out/street-centroid.d.ts.map +0 -1
- package/out/street-centroid.js.map +0 -1
- package/out/street-morphology-fst-builder.d.ts.map +0 -1
- package/out/street-morphology-fst-builder.js.map +0 -1
- package/out/street-morphology-fst-loader.d.ts.map +0 -1
- package/out/street-morphology-fst-loader.js.map +0 -1
- package/out/street-name-lookup.d.ts.map +0 -1
- package/out/street-name-lookup.js.map +0 -1
- package/out/street-normalize.d.ts.map +0 -1
- package/out/street-normalize.js.map +0 -1
- package/out/uprn-lookup.d.ts.map +0 -1
- package/out/uprn-lookup.js.map +0 -1
- package/out/uprn-schema.d.ts.map +0 -1
- package/out/uprn-schema.js.map +0 -1
- package/weights-overlay-linker.ts +0 -377
- /package/{name-score.ts → lib/name-score.ts} +0 -0
- /package/{polygon-schema.ts → lib/polygon-schema.ts} +0 -0
- /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
|
@@ -6,13 +6,12 @@
|
|
|
6
6
|
* Small shared helpers for the SQLite-backed lookups.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { DatabaseSync, SQLInputValue } from "node:sqlite"
|
|
10
|
-
|
|
11
9
|
import { allRows, getRow } from "@mailwoman/core/utils"
|
|
10
|
+
import type { DatabaseClient, SQLInputValue } from "@mailwoman/sqlite/client"
|
|
11
|
+
import { hasColumn as columnExists, tableExists } from "@mailwoman/sqlite/introspection"
|
|
12
12
|
|
|
13
13
|
// The row-shape assertion itself lives in `core` so the readers that cannot depend on this package reach the same
|
|
14
|
-
//
|
|
15
|
-
export { allRows, getRow } from "@mailwoman/core/utils"
|
|
14
|
+
// helper; re-exported here because this module is where this package's readers already look for it.
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* A prepared single-row query whose parameter tuple remains visible to TypeScript. `StatementSync` accepts only the
|
|
@@ -23,8 +22,8 @@ export type PreparedGet<Parameters extends SQLInputValue[], Row> = (...parameter
|
|
|
23
22
|
/**
|
|
24
23
|
* Prepare a single-row query while preserving its exact parameter tuple at every call site.
|
|
25
24
|
*/
|
|
26
|
-
export function prepareGet<Parameters extends SQLInputValue[], Row>(
|
|
27
|
-
db:
|
|
25
|
+
export function prepareGet<Parameters extends SQLInputValue[], Row, DB>(
|
|
26
|
+
db: DatabaseClient<DB>,
|
|
28
27
|
sql: string
|
|
29
28
|
): PreparedGet<Parameters, Row> {
|
|
30
29
|
const statement = db.prepare(sql)
|
|
@@ -40,8 +39,8 @@ export type PreparedAll<Parameters extends SQLInputValue[], Row> = (...parameter
|
|
|
40
39
|
/**
|
|
41
40
|
* Prepare a multi-row query while preserving its exact parameter tuple at every call site.
|
|
42
41
|
*/
|
|
43
|
-
export function prepareAll<Parameters extends SQLInputValue[], Row>(
|
|
44
|
-
db:
|
|
42
|
+
export function prepareAll<Parameters extends SQLInputValue[], Row, DB>(
|
|
43
|
+
db: DatabaseClient<DB>,
|
|
45
44
|
sql: string
|
|
46
45
|
): PreparedAll<Parameters, Row> {
|
|
47
46
|
const statement = db.prepare(sql)
|
|
@@ -51,15 +50,13 @@ export function prepareAll<Parameters extends SQLInputValue[], Row>(
|
|
|
51
50
|
|
|
52
51
|
/**
|
|
53
52
|
* True when `name` is a table in the open database. The street-level lookups use this to degrade gracefully on an
|
|
54
|
-
* empty/tableless
|
|
55
|
-
* CREATES one) — rather than throwing `no such table` at construction and taking down a whole state's geocode
|
|
56
|
-
* missing table makes the lookup a no-op miss.
|
|
53
|
+
* empty/tableless extract — an interrupted `build-*-extract.ts`, or a stray 0-byte file (e.g. `sqlite3 <missing>.db
|
|
54
|
+
* "…"` CREATES one) — rather than throwing `no such table` at construction and taking down a whole state's geocode
|
|
55
|
+
* (#568). A missing table makes the lookup a no-op miss.
|
|
57
56
|
*/
|
|
58
|
-
export function hasTable(db:
|
|
57
|
+
export function hasTable<DB>(db: DatabaseClient<DB>, name: string): boolean {
|
|
59
58
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return row !== undefined
|
|
59
|
+
return tableExists(db, name)
|
|
63
60
|
} catch {
|
|
64
61
|
return false
|
|
65
62
|
}
|
|
@@ -76,11 +73,9 @@ export function hasTable(db: DatabaseSync, name: string): boolean {
|
|
|
76
73
|
* Note the interpolation: PRAGMA does not take bound parameters, so `table` is spliced. Every caller passes a
|
|
77
74
|
* module-level constant; never pass user input.
|
|
78
75
|
*/
|
|
79
|
-
export function hasColumn(db:
|
|
76
|
+
export function hasColumn<DB>(db: DatabaseClient<DB>, table: string, column: string): boolean {
|
|
80
77
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return rows.some((r) => String(r.name) === column)
|
|
78
|
+
return columnExists(db, table, column)
|
|
84
79
|
} catch {
|
|
85
80
|
return false
|
|
86
81
|
}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Typed schema for the DERIVED STREET-CENTROID
|
|
7
|
-
* `ban/scripts/build-street-centroid-
|
|
8
|
-
* FR queries deserve a street-level answer"). The
|
|
9
|
-
* sealed rooftop address-point
|
|
6
|
+
* Typed schema for the DERIVED STREET-CENTROID extract (`street-centroids-<cc>.db`, built by
|
|
7
|
+
* `ban/scripts/build-street-centroid-extract.ts` — the #1042 street-level tier behind "street-only
|
|
8
|
+
* FR queries deserve a street-level answer"). The extract is a `GROUP BY street` roll-up of the
|
|
9
|
+
* sealed rooftop address-point extract: one row per (street, postcode, commune) carrying the street's
|
|
10
10
|
* CENTROID + bounding-box EXTENT + member-point count. No new data source — a derived artifact.
|
|
11
11
|
*
|
|
12
12
|
* Single source of truth for the columns shared by the BUILDER (a positional prepared INSERT for
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import type { Kysely } from "kysely"
|
|
24
24
|
|
|
25
|
-
import type { NameKey, StreetKey } from "
|
|
25
|
+
import type { NameKey, StreetKey } from "#street/normalize"
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* One street roll-up. `(street_norm, postcode, locality_base)` is unique. `lat`/`lon` are the UNWEIGHTED mean of the
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* number) plus a postcode/commune scope, it returns the street's CENTROID + an honest extent-derived
|
|
9
9
|
* uncertainty from the derived `street-centroids-<cc>.db` roll-up.
|
|
10
10
|
*
|
|
11
|
-
* Query-side normalization is THE shared normalizer (`street-normalize.ts`), selected per the
|
|
11
|
+
* Query-side normalization is THE shared normalizer (`street-normalize.ts`), selected per the extract's
|
|
12
12
|
* `streetLocale`, so build-side and probe-side keys agree by construction. The commune scope folds
|
|
13
13
|
* through `normalizeLocalityForKey` + `stripArrondissement` (BAN names Paris/Lyon/Marseille per
|
|
14
14
|
* arrondissement; a query names the base commune).
|
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
* exact-after-normalization only (no fuzzy street matching in this tier).
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import type { StreetCentroidHit, StreetCentroidLookup } from "@mailwoman/core/resolver"
|
|
23
|
+
import { haversineKm } from "@mailwoman/spatial"
|
|
24
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
23
25
|
|
|
24
|
-
import
|
|
25
|
-
|
|
26
|
-
import { hasTable, prepareGet, type PreparedGet } from "./sqlite-utils.ts"
|
|
26
|
+
import { hasTable, prepareGet, type PreparedGet } from "#sqlite-utils"
|
|
27
|
+
import type { StreetCentroidDatabase } from "#street/centroid-schema"
|
|
27
28
|
import {
|
|
28
29
|
normalizeLocalityForKey,
|
|
29
30
|
normalizeStreetForKeyLocale,
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
streetLocaleForSurface,
|
|
33
34
|
type StreetLocale,
|
|
34
35
|
stripArrondissement,
|
|
35
|
-
} from "
|
|
36
|
+
} from "#street/normalize"
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* The weighted-centroid + extent + provenance an aggregate probe projects. `lat` is null when nothing matched.
|
|
@@ -61,33 +62,25 @@ const AGG_SELECT =
|
|
|
61
62
|
* Half the bbox diagonal, in METERS — an honest coarse radius for a street centroid.
|
|
62
63
|
*/
|
|
63
64
|
function extentRadiusM(minLat: number, maxLat: number, minLon: number, maxLon: number): number {
|
|
64
|
-
|
|
65
|
-
const toRad = (d: number): number => (d * Math.PI) / 180
|
|
66
|
-
const dLat = toRad(maxLat - minLat)
|
|
67
|
-
const dLon = toRad(maxLon - minLon)
|
|
68
|
-
const midLat = toRad((minLat + maxLat) / 2)
|
|
69
|
-
const a = Math.sin(dLat / 2) ** 2 + Math.cos(midLat) ** 2 * Math.sin(dLon / 2) ** 2
|
|
70
|
-
const diag = 2 * R * Math.asin(Math.min(1, Math.sqrt(a)))
|
|
71
|
-
|
|
72
|
-
return Math.round(diag / 2)
|
|
65
|
+
return Math.round(haversineKm(minLat, minLon, maxLat, maxLon) * 500)
|
|
73
66
|
}
|
|
74
67
|
|
|
75
68
|
export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
|
|
76
|
-
readonly #db:
|
|
69
|
+
readonly #db: DatabaseClient<StreetCentroidDatabase>
|
|
77
70
|
readonly #locale: StreetLocale
|
|
78
71
|
readonly #byPostcode: PreparedGet<[postcode: string, street: StreetKey], AggRow> | undefined
|
|
79
72
|
readonly #byLocality: PreparedGet<[locality: NameKey, street: StreetKey], AggRow> | undefined
|
|
80
73
|
|
|
81
74
|
/**
|
|
82
|
-
* @param dbPath
|
|
83
|
-
* @param opts.streetLocale The street-normalization locale this
|
|
75
|
+
* @param dbPath Extract path.
|
|
76
|
+
* @param opts.streetLocale The street-normalization locale this extract was BUILT with — must match, or every key
|
|
84
77
|
* misses. Defaults to `"fr"` (BAN is the French national register; the tier is FR-only today).
|
|
85
78
|
*/
|
|
86
79
|
constructor(dbPath: string, opts: { streetLocale?: StreetLocale } = {}) {
|
|
87
|
-
this.#db = new
|
|
80
|
+
this.#db = new DatabaseClient<StreetCentroidDatabase>(dbPath, { readOnly: true })
|
|
88
81
|
this.#locale = opts.streetLocale ?? "fr"
|
|
89
82
|
|
|
90
|
-
// Degrade gracefully on an empty/tableless
|
|
83
|
+
// Degrade gracefully on an empty/tableless extract (interrupted build, stray 0-byte file): with no
|
|
91
84
|
// `street_centroid` table this lookup is a no-op miss, not a crash (mirrors the address-point reader).
|
|
92
85
|
if (hasTable(this.#db, "street_centroid")) {
|
|
93
86
|
this.#byPostcode = prepareGet(
|
|
@@ -130,7 +123,7 @@ export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
|
|
|
130
123
|
}
|
|
131
124
|
}
|
|
132
125
|
|
|
133
|
-
|
|
134
|
-
this.#db.
|
|
126
|
+
[Symbol.dispose](): void {
|
|
127
|
+
this.#db[Symbol.dispose]()
|
|
135
128
|
}
|
|
136
129
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export * from "#street/centroid"
|
|
8
|
+
export * from "#street/centroid-schema"
|
|
9
|
+
export * from "#street/morphology-fst-builder"
|
|
10
|
+
export * from "#street/morphology-fst-loader"
|
|
11
|
+
export * from "#street/name-lookup"
|
|
12
|
+
export * from "#street/normalize"
|
|
13
|
+
export * from "#street/segment-schema"
|
|
@@ -23,14 +23,13 @@
|
|
|
23
23
|
* `fst-street-morphology.bin`.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {
|
|
27
|
-
import { join } from "
|
|
28
|
-
|
|
26
|
+
import { isDirectory, readDirectory, readLocalTextFile, statPath } from "@mailwoman/core/fs/readers"
|
|
27
|
+
import { join } from "path-ts"
|
|
29
28
|
import { TextSpliterator } from "spliterator"
|
|
30
29
|
|
|
31
|
-
import type { FSTNode } from "
|
|
32
|
-
import { FSTMatcher, normalizeTokens } from "
|
|
33
|
-
import type { FSTProvenance, PlaceEntry } from "
|
|
30
|
+
import type { FSTNode } from "#fst/matcher"
|
|
31
|
+
import { FSTMatcher, normalizeTokens } from "#fst/matcher"
|
|
32
|
+
import type { FSTProvenance, PlaceEntry } from "#fst/types"
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
35
|
* Reserved synthetic wofID base for street-morphology entries. 32-bit unsigned, well above any realistic WOF
|
|
@@ -96,7 +95,9 @@ function parseLine(line: string): { canonical: string; variants: string[] } | nu
|
|
|
96
95
|
return { canonical: parts[0]!, variants: parts }
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
export function buildStreetMorphologyFST(
|
|
98
|
+
export async function buildStreetMorphologyFST(
|
|
99
|
+
opts: BuildStreetMorphologyFSTOpts
|
|
100
|
+
): Promise<BuildStreetMorphologyFSTResult> {
|
|
100
101
|
const progress = opts.onProgress ?? (() => {})
|
|
101
102
|
const minVariantLength = opts.minVariantLength ?? 3
|
|
102
103
|
|
|
@@ -107,19 +108,28 @@ export function buildStreetMorphologyFST(opts: BuildStreetMorphologyFSTOpts): Bu
|
|
|
107
108
|
if (opts.locales && opts.locales.length) {
|
|
108
109
|
locales = opts.locales
|
|
109
110
|
} else {
|
|
110
|
-
|
|
111
|
+
const entries = await readDirectory(opts.dictionariesDir)
|
|
112
|
+
const localeProbes: Array<[string, boolean]> = []
|
|
113
|
+
|
|
114
|
+
for (const entry of entries) {
|
|
111
115
|
const localePath = join(opts.dictionariesDir, entry)
|
|
112
116
|
|
|
113
|
-
if (!
|
|
117
|
+
if (!(await isDirectory(localePath))) {
|
|
118
|
+
localeProbes.push([entry, false])
|
|
119
|
+
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
114
122
|
|
|
115
123
|
try {
|
|
116
|
-
|
|
124
|
+
await statPath(join(localePath, STREET_TYPES_FILENAME))
|
|
117
125
|
|
|
118
|
-
|
|
126
|
+
localeProbes.push([entry, true])
|
|
119
127
|
} catch {
|
|
120
|
-
|
|
128
|
+
localeProbes.push([entry, false])
|
|
121
129
|
}
|
|
122
|
-
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
locales = localeProbes.filter(([, hasFile]) => hasFile).map(([entry]) => entry)
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
progress("discover", `Found ${locales.length} locales with ${STREET_TYPES_FILENAME}`)
|
|
@@ -130,7 +140,7 @@ export function buildStreetMorphologyFST(opts: BuildStreetMorphologyFSTOpts): Bu
|
|
|
130
140
|
|
|
131
141
|
for (const locale of locales) {
|
|
132
142
|
const filePath = join(opts.dictionariesDir, locale, STREET_TYPES_FILENAME)
|
|
133
|
-
const content =
|
|
143
|
+
const content = await readLocalTextFile(filePath)
|
|
134
144
|
|
|
135
145
|
for (const line of TextSpliterator.from(content)) {
|
|
136
146
|
const parsed = parseLine(line)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Unified runtime loader for the street-morphology FST — the #1315 street-context
|
|
6
|
+
* Unified runtime loader for the street-morphology FST — the #1315 street-context check's signal
|
|
7
7
|
* source, previously rebuilt from the libpostal dictionaries per process at three duplicate call
|
|
8
8
|
* sites (runtime pipeline / parity eval / neural harness). The sealed artifact
|
|
9
9
|
* (`fst-street-morphology.bin`, built by `mailwoman gazetteer build street-morphology`) replaces
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
* `fst-deserialize-web.ts` (see the docs demo loader).
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import { dataRootPath } from "@mailwoman/core/data-root"
|
|
25
|
+
import { pathExists, readLocalBuffer } from "@mailwoman/core/fs/readers"
|
|
26
|
+
import { resourceDictionaryPath } from "@mailwoman/core/paths"
|
|
25
27
|
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
import type {
|
|
29
|
-
import {
|
|
30
|
-
import type { FSTProvenance } from "./fst-types.ts"
|
|
31
|
-
import { buildStreetMorphologyFST } from "./street-morphology-fst-builder.ts"
|
|
28
|
+
import type { FSTMatcher } from "#fst/matcher"
|
|
29
|
+
import { deserializeFST, readFSTProvenance } from "#fst/serialize"
|
|
30
|
+
import type { FSTProvenance } from "#fst/types"
|
|
31
|
+
import { buildStreetMorphologyFST } from "#street/morphology-fst-builder"
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* The sealed artifact's canonical filename — identical in the data-root staging dir and as a weights-package sibling.
|
|
@@ -77,13 +77,15 @@ export interface LoadedStreetMorphologyFST {
|
|
|
77
77
|
/**
|
|
78
78
|
* Load the street-morphology matcher: sealed artifact first, per-process dictionary build as the degrade path.
|
|
79
79
|
*/
|
|
80
|
-
export function loadStreetMorphologyFST(
|
|
80
|
+
export async function loadStreetMorphologyFST(
|
|
81
|
+
opts: LoadStreetMorphologyFSTOpts = {}
|
|
82
|
+
): Promise<LoadedStreetMorphologyFST> {
|
|
81
83
|
const warn = opts.onWarn ?? (() => {})
|
|
82
84
|
const artifactPath = opts.artifactPath ?? defaultStreetMorphologyArtifactPath()
|
|
83
85
|
|
|
84
|
-
if (
|
|
86
|
+
if (await pathExists(artifactPath)) {
|
|
85
87
|
try {
|
|
86
|
-
const buf =
|
|
88
|
+
const buf = await readLocalBuffer(artifactPath)
|
|
87
89
|
const matcher = deserializeFST(buf)
|
|
88
90
|
const provenance = readFSTProvenance(buf)
|
|
89
91
|
|
|
@@ -95,7 +97,7 @@ export function loadStreetMorphologyFST(opts: LoadStreetMorphologyFSTOpts = {}):
|
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
const built = buildStreetMorphologyFST({
|
|
100
|
+
const built = await buildStreetMorphologyFST({
|
|
99
101
|
dictionariesDir: opts.dictionariesDir ?? resourceDictionaryPath("libpostal"),
|
|
100
102
|
})
|
|
101
103
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Reads a street-name index (the FR instance = BAN `street-centroids-fr.db`, a `street_centroid`
|
|
9
9
|
* table of `street_norm × locality_base × postcode` rows) and answers "does this street surface
|
|
10
10
|
* exist as a name" for the k-best rerank. Sync-by-interface, `readOnly`, prepared statements,
|
|
11
|
-
* graceful-degrade on a tableless
|
|
11
|
+
* graceful-degrade on a tableless extract — the same reader discipline as `AddressPointSqliteLookup`.
|
|
12
12
|
*
|
|
13
13
|
* THE FOLD CONTRACT: the surface is folded with {@link foldStreetSurface} (the shared function),
|
|
14
14
|
* and the DB's `street_norm` column MUST have been built with that SAME fold or every hyphenated /
|
|
@@ -19,24 +19,11 @@
|
|
|
19
19
|
* the production rebuild is a tracked BAN-sdk follow-up.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { DatabaseSync } from "node:sqlite"
|
|
23
|
-
|
|
24
22
|
import { foldStreetSurface, type StreetEvidenceScope, type StreetLocalityEvidence } from "@mailwoman/resolver"
|
|
23
|
+
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return row !== undefined
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function hasColumn(db: DatabaseSync, table: string, column: string): boolean {
|
|
33
|
-
// `table` is a caller-controlled identifier (default `street_centroid`), not user input — safe to interpolate.
|
|
34
|
-
for (const row of db.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>) {
|
|
35
|
-
if (row.name === column) return true
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
25
|
+
import type { WOFDatabase } from "#schema"
|
|
26
|
+
import { hasColumn, hasTable } from "#sqlite-utils"
|
|
40
27
|
|
|
41
28
|
export interface SQLiteStreetNameLookupOpts {
|
|
42
29
|
/**
|
|
@@ -53,22 +40,22 @@ export interface SQLiteStreetNameLookupOpts {
|
|
|
53
40
|
* A {@link StreetLocalityEvidence} backed by a street-name SQLite index. Positive evidence only: any doubt (missing
|
|
54
41
|
* table, read miss) returns `false`, so the rerank fails open to the model's ranking.
|
|
55
42
|
*/
|
|
56
|
-
export class SQLiteStreetNameLookup implements StreetLocalityEvidence {
|
|
43
|
+
export class SQLiteStreetNameLookup implements StreetLocalityEvidence, Disposable {
|
|
57
44
|
readonly countries: ReadonlySet<string>
|
|
58
|
-
readonly #db:
|
|
59
|
-
readonly #byName: ReturnType<
|
|
60
|
-
readonly #byNameLocality: ReturnType<
|
|
61
|
-
readonly #byNamePostcode: ReturnType<
|
|
45
|
+
readonly #db: DatabaseClient<WOFDatabase>
|
|
46
|
+
readonly #byName: ReturnType<DatabaseClient["prepare"]> | undefined
|
|
47
|
+
readonly #byNameLocality: ReturnType<DatabaseClient["prepare"]> | undefined
|
|
48
|
+
readonly #byNamePostcode: ReturnType<DatabaseClient["prepare"]> | undefined
|
|
62
49
|
|
|
63
50
|
constructor(dbPath: string, opts: SQLiteStreetNameLookupOpts = {}) {
|
|
64
51
|
this.countries = new Set([...(opts.countries ?? ["FR"])].map((c) => c.toUpperCase()))
|
|
65
|
-
this.#db = new
|
|
52
|
+
this.#db = new DatabaseClient<WOFDatabase>(dbPath, { readOnly: true })
|
|
66
53
|
const table = opts.table ?? "street_centroid"
|
|
67
54
|
|
|
68
|
-
// Degrade gracefully on an empty/tableless
|
|
55
|
+
// Degrade gracefully on an empty/tableless extract — a no-op miss, never a crash (#568 discipline).
|
|
69
56
|
if (hasTable(this.#db, table)) {
|
|
70
57
|
// Prefer the #727 phase-4c `name_key` column (foldStreetSurface, indexed by `idx_sc_name` for a direct seek);
|
|
71
|
-
// fall back to `street_norm` on a pre-rebuild
|
|
58
|
+
// fall back to `street_norm` on a pre-rebuild extract (a skip-scan, but correct). The fold used to build
|
|
72
59
|
// `name_key` MUST match `foldStreetSurface` here (the fold-parity contract).
|
|
73
60
|
const keyCol = hasColumn(this.#db, table, "name_key") ? "name_key" : "street_norm"
|
|
74
61
|
this.#byName = this.#db.prepare(`SELECT 1 FROM ${table} WHERE ${keyCol} = ? LIMIT 1`)
|
|
@@ -104,10 +91,7 @@ export class SQLiteStreetNameLookup implements StreetLocalityEvidence {
|
|
|
104
91
|
return this.#byName.get(norm) !== undefined
|
|
105
92
|
}
|
|
106
93
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
*/
|
|
110
|
-
close(): void {
|
|
111
|
-
this.#db.close()
|
|
94
|
+
[Symbol.dispose](): void {
|
|
95
|
+
this.#db[Symbol.dispose]()
|
|
112
96
|
}
|
|
113
97
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* THE street normalizer for the address-point tier (#476). One function, used by BOTH the
|
|
7
|
-
* builder (`scripts/build-address-point-
|
|
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
8
|
* never two implementations (the PLACETYPE_ORDER lesson: parallel copies silently corrupt).
|
|
9
9
|
*
|
|
10
10
|
* Normalization contract (deliberately aggressive — both sides apply the same function, so
|
|
@@ -27,13 +27,13 @@ import type { Tagged } from "type-fest"
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* A place name folded by {@link normalizeLocalityForKey} — the value stored in, and required to probe, every
|
|
30
|
-
* `name_key`-style column: the candidate gazetteer, the postal-city side-index, the street-centroid
|
|
31
|
-
* chain's `parent_name_key`, and the address-point locality scope.
|
|
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
32
|
*
|
|
33
33
|
* The brand is here because the fold is applied at BUILD time and is therefore mandatory at QUERY time, while a
|
|
34
34
|
* near-miss approximation of it (`toLowerCase()`, `trim()`) is still a `string`: it binds to the parameter, returns
|
|
35
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
|
|
36
|
+
* brand at the boundary turns that silent under-match into a compile error. Mint one only by calling the fold.
|
|
37
37
|
*/
|
|
38
38
|
export type NameKey = Tagged<string, "NameKey">
|
|
39
39
|
|
|
@@ -64,8 +64,8 @@ const MIN_TOKENS_FOR_TAIL_MERGE = 3
|
|
|
64
64
|
/**
|
|
65
65
|
* Spelled ordinal street names → their digit-ordinal form ("tenth" → "10th"), applied ONLY when a street-type suffix
|
|
66
66
|
* follows (#723 admin-tail) — so the ordinal cross-streets common in grid cities ("Tenth Street", "Fifth Avenue") match
|
|
67
|
-
* the
|
|
68
|
-
* Bank Rd" stays "first national …"). Digit-source
|
|
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
69
|
* existing keys need no rebuild; a future rebuild folds any spelled-source key the same way (the one-function
|
|
70
70
|
* discipline).
|
|
71
71
|
*/
|
|
@@ -123,7 +123,7 @@ export function normalizeStreetForKey(street: string): StreetKey {
|
|
|
123
123
|
if (!tokens.length) return "" as StreetKey
|
|
124
124
|
|
|
125
125
|
// Spelled-ordinal street names → digit form when a street suffix follows ("Tenth Street" →
|
|
126
|
-
// "10th street", #723).
|
|
126
|
+
// "10th street", #723). Conditioned on the next token being a suffix so ordinal-WORD names are untouched.
|
|
127
127
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
128
128
|
const digit = SPELLED_ORDINAL_TO_DIGIT.get(tokens[i]!)
|
|
129
129
|
|
|
@@ -193,7 +193,42 @@ export function normalizeStreetForKey(street: string): StreetKey {
|
|
|
193
193
|
* article, so no salient-token / multi-key index is built yet (deferred until probing shows the normalizer can't absorb
|
|
194
194
|
* the false-negatives).
|
|
195
195
|
*/
|
|
196
|
-
export type StreetLocale = "us" | "en" | "fr" | "de" | "nl" | "pl" | "vn" | "id"
|
|
196
|
+
export type StreetLocale = "us" | "en" | "fr" | "de" | "nl" | "pl" | "vn" | "id" | "zh"
|
|
197
|
+
|
|
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
|
+
function foldHan(input: string): string {
|
|
205
|
+
return input.normalize("NFKC").replaceAll("臺", "台").replaceAll(/\s+/g, "").toLowerCase()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Country → street-locale registry surface for the acquisition SDKs (BAN, OSM). Each SDK keeps its own map — membership
|
|
210
|
+
* is a per-register decision — and this factory owns the lookup discipline: throw for an unsupported country rather
|
|
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.
|
|
214
|
+
*/
|
|
215
|
+
export function createStreetLocaleRegistry(
|
|
216
|
+
registry: ReadonlyMap<string, StreetLocale>,
|
|
217
|
+
label: string
|
|
218
|
+
): { localeFor: (countryCode: string) => StreetLocale; supported: () => string[] } {
|
|
219
|
+
return {
|
|
220
|
+
localeFor: (countryCode) => {
|
|
221
|
+
const locale = registry.get(countryCode.toLowerCase())
|
|
222
|
+
|
|
223
|
+
if (!locale) {
|
|
224
|
+
throw new Error(`No street-normalization locale registered for country "${countryCode}". ${label}`)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return locale
|
|
228
|
+
},
|
|
229
|
+
supported: () => [...registry.keys()],
|
|
230
|
+
}
|
|
231
|
+
}
|
|
197
232
|
|
|
198
233
|
/**
|
|
199
234
|
* French street-type abbreviations → canonical full form, applied per token after {@link fold}. French address types
|
|
@@ -223,7 +258,7 @@ const FR_STREET_ABBREV = new Map<string, string>([
|
|
|
223
258
|
])
|
|
224
259
|
|
|
225
260
|
/**
|
|
226
|
-
* Polish leading street-type tokens, STRIPPED rather than expanded. Measured on the 5.56M-row PL OSM
|
|
261
|
+
* Polish leading street-type tokens, STRIPPED rather than expanded. Measured on the 5.56M-row PL OSM extract
|
|
227
262
|
* (2026-08-19): OSM Poland tags `addr:street` BARE — `ulica%` covers 22 rows and `ul.%` eight, so an EXPANSION rule
|
|
228
263
|
* makes a typed query ("ul. Świętokrzyska" → "ulica swietokrzyska") miss the 3,846 bare "swietokrzyska" rows. Stripping
|
|
229
264
|
* the leading type on BOTH sides keys typed and bare surfaces identically. The full words are stripped too: the
|
|
@@ -255,7 +290,7 @@ const ID_STREET_ABBREV = new Map<string, string>([
|
|
|
255
290
|
* {@link PL_LEADING_TYPE} for the measured reason expansion was wrong for this source.
|
|
256
291
|
* - **vn** — fold + đ→d AND ð→d (both non-decomposing, and OSM mixes the two codepoints inside single values — see the
|
|
257
292
|
* branch comment). Deliberately NO type-abbreviation map yet: the common abbreviation is the single letter "Đ." for
|
|
258
|
-
* Đường, and expanding a bare folded "d" token would rewrite initials — measure the miss rate on the built
|
|
293
|
+
* Đường, and expanding a bare folded "d" token would rewrite initials — measure the miss rate on the built extract
|
|
259
294
|
* before adding anything.
|
|
260
295
|
* - **id** — fold + expand leading type abbreviations (jl/jln→jalan, gg→gang); Indonesian street surfaces are otherwise
|
|
261
296
|
* ASCII-clean.
|
|
@@ -263,12 +298,16 @@ const ID_STREET_ABBREV = new Map<string, string>([
|
|
|
263
298
|
export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale): StreetKey {
|
|
264
299
|
if (locale === "us" || locale === "en") return normalizeStreetForKey(street)
|
|
265
300
|
|
|
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
|
+
if (locale === "zh") return foldHan(street) as StreetKey
|
|
304
|
+
|
|
266
305
|
// Hyphen → space so a compound name keys the same whether the source or the query writes the
|
|
267
306
|
// hyphen ("Champs-Élysées", "St-Honoré") or a space — both sides fold identically, so this is pure
|
|
268
307
|
// robustness. It also splits a hyphenated abbreviation ("St-Honoré" → "st honore") into tokens the
|
|
269
308
|
// per-locale type/Saint map can see. Letter maps for non-decomposing letters (ß, ł, đ) live in the
|
|
270
309
|
// per-locale branches, NEVER here: widening the shared pipeline would silently change keys under
|
|
271
|
-
// every already-built
|
|
310
|
+
// every already-built extract of the other locales.
|
|
272
311
|
const tokens = fold(street)
|
|
273
312
|
.replaceAll("ß", "ss")
|
|
274
313
|
.replaceAll("-", " ")
|
|
@@ -317,7 +356,7 @@ export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale
|
|
|
317
356
|
break
|
|
318
357
|
case "vn":
|
|
319
358
|
// đ (U+0111, d-with-stroke) AND ð (U+00F0, eth): OSM Vietnamese data mixes the two visually
|
|
320
|
-
// identical codepoints inside single values — the 2026-08-19
|
|
359
|
+
// identical codepoints inside single values — the 2026-08-19 extract measured `Đường Trần Hưng
|
|
321
360
|
// Đạo` carrying d-with-stroke at the front and ETH in `Đạo`, splitting the country's most
|
|
322
361
|
// common street into two keys with the MAJORITY variant (630 vs 421 rows) unreachable by a
|
|
323
362
|
// correctly-typed query. No abbreviation map — see the locale table.
|
|
@@ -337,6 +376,33 @@ export function normalizeLocalityForKey(locality: string): NameKey {
|
|
|
337
376
|
return fold(locality) as NameKey
|
|
338
377
|
}
|
|
339
378
|
|
|
379
|
+
/**
|
|
380
|
+
* The locality key under a street locale: the Han fold for `zh`, {@link normalizeLocalityForKey} for every other.
|
|
381
|
+
* Separate from the shared fold on purpose — the candidate gazetteer's `name_key` column is the shared fold, and a Han
|
|
382
|
+
* rule inside it would re-key every 臺 name under an extract built without the rule.
|
|
383
|
+
*/
|
|
384
|
+
export function normalizeLocalityForKeyLocale(locality: string, locale: StreetLocale): NameKey {
|
|
385
|
+
return locale === "zh" ? (foldHan(locality) as NameKey) : normalizeLocalityForKey(locality)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* The house-number key under a street locale. Every Latin register stores a lower-cased, trimmed number and the reader
|
|
390
|
+
* probes the same; `zh` additionally folds width and drops the trailing 號 the Taiwanese registers write on the number
|
|
391
|
+
* itself (`122號`), which a parse also carries on the `house_number` span (`122號`). Both sides key `122`.
|
|
392
|
+
*/
|
|
393
|
+
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
|
+
if (locale === "zh") {
|
|
398
|
+
return foldHan(number)
|
|
399
|
+
.replace(/^(\d+)號([之附]\d+)$/u, "$1$2")
|
|
400
|
+
.replace(/號$/u, "")
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return number.trim().toLowerCase()
|
|
404
|
+
}
|
|
405
|
+
|
|
340
406
|
/**
|
|
341
407
|
* Leading French street-type token. French types LEAD the name ("avenue du Parc", "boul Saint-Laurent") while English
|
|
342
408
|
* types TRAIL ("Fifth Avenue", "Grosvenor Place"), so a leading type-token is the discriminating signal — "1 Avenue NE"
|
|
@@ -347,7 +413,7 @@ const FRENCH_LEAD_TYPE =
|
|
|
347
413
|
/^(?: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
|
|
348
414
|
|
|
349
415
|
/**
|
|
350
|
-
* Surface-driven street-locale ROUTER for bilingual
|
|
416
|
+
* Surface-driven street-locale ROUTER for bilingual extracts — the Québec finishing move on the CA rooftop extract.
|
|
351
417
|
*
|
|
352
418
|
* A country registers ONE street locale, but Canada's street surfaces are two languages: under the `en` rules a French
|
|
353
419
|
* surface passes through mostly unchanged (both sides fold identically, so those rows stay reachable), and what breaks
|
|
@@ -355,11 +421,11 @@ const FRENCH_LEAD_TYPE =
|
|
|
355
421
|
* misses a full-word row and vice versa. Routing on the SURFACE (not the province) also carries bilingual NB and the
|
|
356
422
|
* French street names outside Québec for free.
|
|
357
423
|
*
|
|
358
|
-
* ONE function, called by the
|
|
424
|
+
* ONE function, called by the extract BUILDER and the query PROBE alike — the #861 discipline: routing is part of the
|
|
359
425
|
* fold contract, and two transcriptions of this predicate would diverge exactly where it matters. Only an `en` base
|
|
360
|
-
* re-routes: a `fr`/`de`/`nl`
|
|
426
|
+
* re-routes: a `fr`/`de`/`nl` extract already speaks its own rules, and the US pipeline stays untouched.
|
|
361
427
|
*
|
|
362
|
-
* Measured basis (CA
|
|
428
|
+
* Measured basis (CA extract, 2026-08-19): 183,963 distinct surfaces, 43,762 French-lead; 29,682 fold differently under
|
|
363
429
|
* fr-vs-en (888,265 rows), and the non-French half of those are English surfaces this router keeps on `en` unchanged.
|
|
364
430
|
*/
|
|
365
431
|
export function streetLocaleForSurface(street: string, base: StreetLocale): StreetLocale {
|
|
@@ -453,9 +519,9 @@ export function stripLocalityQualifier(locality: string): string {
|
|
|
453
519
|
* (the state abbreviation form) fold to `state route N…`. Only digit-leading route numbers fold — `State Street` and
|
|
454
520
|
* friends never match.
|
|
455
521
|
*
|
|
456
|
-
* Used by BOTH the segment-
|
|
457
|
-
* one-function discipline as {@link normalizeStreetForKey}. The address-point tier (#476) does NOT apply it yet:
|
|
458
|
-
* adopting it there requires a
|
|
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).
|
|
459
525
|
*
|
|
460
526
|
* A same-numbered US and state route stay DISTINCT keys (`us route 5` vs `state route 5`); only the BARE `route N` form
|
|
461
527
|
* is ambiguous (designator unknown) and it stays unfolded — a bare-route query therefore misses rather than guessing a
|