@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
|
@@ -2,26 +2,13 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* SQLite implementation of core's `StreetCentroidLookup` (#1042): the street-level tier BELOW the
|
|
7
|
-
* exact address-point tier and ABOVE admin-centroid resolution. Given a street name (no house
|
|
8
|
-
* number) plus a postcode/commune scope, it returns the street's CENTROID + an honest extent-derived
|
|
9
|
-
* uncertainty from the derived `street-centroids-<cc>.db` roll-up.
|
|
10
|
-
*
|
|
11
|
-
* Query-side normalization is THE shared normalizer (`street-normalize.ts`), selected per the extract's
|
|
12
|
-
* `streetLocale`, so build-side and probe-side keys agree by construction. The commune scope folds
|
|
13
|
-
* through `normalizeLocalityForKey` + `stripArrondissement` (BAN names Paris/Lyon/Marseille per
|
|
14
|
-
* arrondissement; a query names the base commune).
|
|
15
|
-
*
|
|
16
|
-
* Scope order is most-selective first: `postcode`, then the base commune. Each scope WEIGHTED-
|
|
17
|
-
* aggregates (by `point_count`) across the matched rows in SQL, so a commune-scope probe returns the
|
|
18
|
-
* street's grand centroid over every postcode/arrondissement it spans — one row, one hit. Matching is
|
|
19
|
-
* exact-after-normalization only (no fuzzy street matching in this tier).
|
|
5
|
+
* @file SQLite implementation of core's `StreetCentroidLookup`.
|
|
20
6
|
*/
|
|
21
7
|
|
|
22
8
|
import type { StreetCentroidHit, StreetCentroidLookup } from "@mailwoman/core/resolver"
|
|
23
9
|
import { haversineKm } from "@mailwoman/spatial"
|
|
24
10
|
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
11
|
+
import type { PathBuilderLike } from "path-ts"
|
|
25
12
|
|
|
26
13
|
import { hasTable, prepareGet, type PreparedGet } from "#sqlite-utils"
|
|
27
14
|
import type { StreetCentroidDatabase } from "#street/centroid/schema"
|
|
@@ -36,7 +23,8 @@ import {
|
|
|
36
23
|
} from "#street/normalize"
|
|
37
24
|
|
|
38
25
|
/**
|
|
39
|
-
* The weighted
|
|
26
|
+
* The weighted centroid, extent and provenance an aggregate probe returns;
|
|
27
|
+
* `lat` is null when no row matched.
|
|
40
28
|
*/
|
|
41
29
|
interface AggRow {
|
|
42
30
|
lat: number | null
|
|
@@ -50,7 +38,8 @@ interface AggRow {
|
|
|
50
38
|
}
|
|
51
39
|
|
|
52
40
|
/**
|
|
53
|
-
*
|
|
41
|
+
* The aggregate columns that weight each row's centroid by `point_count` to
|
|
42
|
+
* reconstruct the combined centroid.
|
|
54
43
|
*/
|
|
55
44
|
const AGG_SELECT =
|
|
56
45
|
"SUM(lat * point_count) / SUM(point_count) AS lat, " +
|
|
@@ -59,12 +48,16 @@ const AGG_SELECT =
|
|
|
59
48
|
"MAX(source) AS source, MAX(release) AS release"
|
|
60
49
|
|
|
61
50
|
/**
|
|
62
|
-
* Half the
|
|
51
|
+
* Half the bounding-box diagonal in meters, used as a coarse uncertainty radius for a street centroid.
|
|
63
52
|
*/
|
|
64
53
|
function extentRadiusM(minLat: number, maxLat: number, minLon: number, maxLon: number): number {
|
|
65
54
|
return Math.round(haversineKm(minLat, minLon, maxLat, maxLon) * 500)
|
|
66
55
|
}
|
|
67
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Finds a street's centroid and extent-based uncertainty by street name,
|
|
59
|
+
* scoped by postcode and then by base commune.
|
|
60
|
+
*/
|
|
68
61
|
export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
|
|
69
62
|
readonly #db: DatabaseClient<StreetCentroidDatabase>
|
|
70
63
|
readonly #locale: StreetLocale
|
|
@@ -72,16 +65,14 @@ export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
|
|
|
72
65
|
readonly #byLocality: PreparedGet<[locality: NameKey, street: StreetKey], AggRow> | undefined
|
|
73
66
|
|
|
74
67
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* misses. Defaults to `"fr"` (BAN is the French national register; the tier is FR-only today).
|
|
68
|
+
* The extract defaults to the `fr` street-normalization locale.
|
|
69
|
+
* A mismatch with the extract's locale makes every key miss.
|
|
78
70
|
*/
|
|
79
|
-
constructor(dbPath:
|
|
71
|
+
constructor(dbPath: PathBuilderLike, opts: { streetLocale?: StreetLocale } = {}) {
|
|
80
72
|
this.#db = new DatabaseClient<StreetCentroidDatabase>(dbPath, { readOnly: true })
|
|
81
73
|
this.#locale = opts.streetLocale ?? "fr"
|
|
82
74
|
|
|
83
|
-
//
|
|
84
|
-
// `street_centroid` table this lookup is a no-op miss, not a crash (mirrors the address-point reader).
|
|
75
|
+
// An extract without a `street_centroid` table makes every lookup miss.
|
|
85
76
|
if (hasTable(this.#db, "street_centroid")) {
|
|
86
77
|
this.#byPostcode = prepareGet(
|
|
87
78
|
this.#db,
|
|
@@ -101,7 +92,7 @@ export class StreetCentroidSqliteLookup implements StreetCentroidLookup {
|
|
|
101
92
|
|
|
102
93
|
if (!streetNorm) return null
|
|
103
94
|
|
|
104
|
-
let row: AggRow |
|
|
95
|
+
let row: AggRow | null = null
|
|
105
96
|
|
|
106
97
|
if (query.postcode?.trim()) {
|
|
107
98
|
row = this.#byPostcode(query.postcode.trim(), streetNorm)
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Build a street-morphology FST from libpostal's street_types dictionaries. The morphology FST maps
|
|
7
7
|
* street-typing affixes (Street/Avenue/rue/Calle/Straße/...) to a single synthetic placetype
|
|
8
|
-
* `"street_affix"
|
|
8
|
+
* `"street_affix"`. Its source data and purpose differ from the admin FST.
|
|
9
|
+
* It also produces a separate binary artifact.
|
|
9
10
|
*
|
|
10
11
|
* The morphology FST closes the inference-time vacuum identified by the v0.6.1 postmortem: street
|
|
11
12
|
* tokens have no admin-FST anchor, so synth-street training pushed the model toward over-emitting
|
|
12
13
|
* `dependent_locality` on subcomponents. With the morphology FST, the neural decoder gets
|
|
13
14
|
* positive evidence for street-typing affixes and the adjacent name tokens, plus negative
|
|
14
|
-
* evidence away from `dependent_locality` on the same
|
|
15
|
+
* evidence away from `dependent_locality` on the same neighbors.
|
|
15
16
|
*
|
|
16
17
|
* Design rationale + the four-layer street-supplement architecture lives in
|
|
17
18
|
* `docs/articles/concepts/street-supplement-architecture.md`.
|
|
@@ -23,8 +24,9 @@
|
|
|
23
24
|
* `fst-street-morphology.bin`.
|
|
24
25
|
*/
|
|
25
26
|
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
27
|
+
import { readLocalTextFile } from "@mailwoman/core/fs/readers"
|
|
28
|
+
import { isDirectory, isFile } from "@mailwoman/core/fs/readers/stat"
|
|
29
|
+
import { PathBuilder, type PathBuilderLike } from "path-ts"
|
|
28
30
|
import { TextSpliterator } from "spliterator"
|
|
29
31
|
import { Globerator } from "spliterator/node/fs"
|
|
30
32
|
|
|
@@ -33,9 +35,11 @@ import { FSTMatcher, normalizeTokens } from "#fst/matcher"
|
|
|
33
35
|
import type { FSTProvenance, PlaceEntry } from "#fst/types"
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
|
-
* Reserved synthetic wofID base for street-morphology entries. 32-bit unsigned,
|
|
37
|
-
*
|
|
38
|
-
*
|
|
38
|
+
* Reserved synthetic wofID base for street-morphology entries. 32-bit unsigned,
|
|
39
|
+
* well above any realistic WOF allocation.
|
|
40
|
+
*
|
|
41
|
+
* The same base across rebuilds keeps IDs stable for consumers that cache them.
|
|
42
|
+
* See [[project-schema-storage-decision]] for the reserved range policy.
|
|
39
43
|
*/
|
|
40
44
|
const STREET_AFFIX_WOFID_BASE = 1_900_000_000
|
|
41
45
|
|
|
@@ -45,19 +49,27 @@ export interface BuildStreetMorphologyFSTOpts {
|
|
|
45
49
|
/**
|
|
46
50
|
* Path to the `core/data/libpostal/dictionaries` directory containing per-locale subfolders.
|
|
47
51
|
*/
|
|
48
|
-
dictionariesDir:
|
|
52
|
+
dictionariesDir: PathBuilderLike
|
|
49
53
|
/**
|
|
50
|
-
* Optional locale filter — only ingest these locale subfolders.
|
|
54
|
+
* Optional locale filter — only ingest these locale subfolders.
|
|
55
|
+
*
|
|
56
|
+
* @defaultValue all that have a `street_types.txt`.
|
|
51
57
|
*/
|
|
52
58
|
locales?: string[]
|
|
53
59
|
/**
|
|
54
|
-
* Minimum length (in characters, post-normalization) of variant surface forms to insert into the trie.
|
|
60
|
+
* Minimum length (in characters, post-normalization) of variant surface forms to insert into the trie.
|
|
61
|
+
*
|
|
62
|
+
* Rationale: libpostal's street_types dictionaries contain 1-2 character abbreviations
|
|
63
|
+
* (`a`, `b`, `av`, `bd`, `br`, ...) that collide with non-affix tokens at parse time,
|
|
64
|
+
* including US state abbreviations (`or`, `CA`, `ND`, `NY`).
|
|
65
|
+
* Single-letter unit designators and other short tokens also collide.
|
|
66
|
+
*
|
|
67
|
+
* Empirically these collisions push the morphology prior to mis-tag state
|
|
68
|
+
* abbreviations as `street_suffix`.
|
|
69
|
+
*
|
|
70
|
+
* A minimum length of 3 retains useful forms (`ave`, `blvd`, `rue`, `str`) while filtering out the noise.
|
|
55
71
|
*
|
|
56
|
-
*
|
|
57
|
-
* ...) that collide with non-affix tokens at parse time — notably US state abbreviations (`OR`, `CA`, `ND`, `NY`),
|
|
58
|
-
* single-letter unit designators, and arbitrary short tokens. Empirically these collisions push the morphology prior
|
|
59
|
-
* to mis-tag state abbreviations as `street_suffix`. A minimum length of 3 retains useful forms (`ave`, `blvd`,
|
|
60
|
-
* `rue`, `str`) while filtering out the noise.
|
|
72
|
+
* @defaultValue `3`
|
|
61
73
|
*/
|
|
62
74
|
minVariantLength?: number
|
|
63
75
|
/**
|
|
@@ -76,20 +88,19 @@ export interface BuildStreetMorphologyFSTResult {
|
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
/**
|
|
79
|
-
* Parse one `street_types.txt` line into `{ canonical, variants }`.
|
|
80
|
-
*
|
|
91
|
+
* Parse one `street_types.txt` line into `{ canonical, variants }`.
|
|
92
|
+
*
|
|
93
|
+
* Canonical is the first token (pre-`|`); variants are all whitespace-stripped
|
|
94
|
+
* non-empty tokens including the canonical.
|
|
81
95
|
*
|
|
82
96
|
* Lines with no `|` are treated as a single-form entry where canonical == variant.
|
|
83
97
|
*/
|
|
84
98
|
function parseLine(line: string): { canonical: string; variants: string[] } | null {
|
|
85
99
|
const trimmed = line.trim()
|
|
86
100
|
|
|
87
|
-
if (!trimmed
|
|
101
|
+
if (!trimmed || trimmed.startsWith("#")) return null
|
|
88
102
|
|
|
89
|
-
const parts = trimmed
|
|
90
|
-
.split("|")
|
|
91
|
-
.map((s) => s.trim())
|
|
92
|
-
.filter((s) => s.length > 0)
|
|
103
|
+
const parts = TextSpliterator.from(trimmed, { delimiter: "|" }).toArray()
|
|
93
104
|
|
|
94
105
|
if (!parts.length) return null
|
|
95
106
|
|
|
@@ -101,6 +112,7 @@ export async function buildStreetMorphologyFST(
|
|
|
101
112
|
): Promise<BuildStreetMorphologyFSTResult> {
|
|
102
113
|
const progress = opts.onProgress ?? (() => {})
|
|
103
114
|
const minVariantLength = opts.minVariantLength ?? 3
|
|
115
|
+
const dictionariesDir = PathBuilder.from(opts.dictionariesDir)
|
|
104
116
|
|
|
105
117
|
// Discover locales — either provided explicitly, or all directories containing street_types.txt.
|
|
106
118
|
let locales: string[]
|
|
@@ -110,7 +122,7 @@ export async function buildStreetMorphologyFST(
|
|
|
110
122
|
locales = opts.locales
|
|
111
123
|
} else {
|
|
112
124
|
const entries = await Globerator.from("*", {
|
|
113
|
-
cwd:
|
|
125
|
+
cwd: dictionariesDir,
|
|
114
126
|
absolute: false,
|
|
115
127
|
onlyFiles: false,
|
|
116
128
|
}).toArray()
|
|
@@ -118,7 +130,7 @@ export async function buildStreetMorphologyFST(
|
|
|
118
130
|
const localeProbes: Array<[string, boolean]> = []
|
|
119
131
|
|
|
120
132
|
for (const entry of entries) {
|
|
121
|
-
const localePath =
|
|
133
|
+
const localePath = dictionariesDir(entry)
|
|
122
134
|
|
|
123
135
|
if (!(await isDirectory(localePath))) {
|
|
124
136
|
localeProbes.push([entry, false])
|
|
@@ -126,13 +138,7 @@ export async function buildStreetMorphologyFST(
|
|
|
126
138
|
continue
|
|
127
139
|
}
|
|
128
140
|
|
|
129
|
-
|
|
130
|
-
await statPath(join(localePath, STREET_TYPES_FILENAME))
|
|
131
|
-
|
|
132
|
-
localeProbes.push([entry, true])
|
|
133
|
-
} catch {
|
|
134
|
-
localeProbes.push([entry, false])
|
|
135
|
-
}
|
|
141
|
+
localeProbes.push([entry, await isFile(localePath(STREET_TYPES_FILENAME))])
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
locales = localeProbes.filter(([, hasFile]) => hasFile).map(([entry]) => entry)
|
|
@@ -140,12 +146,12 @@ export async function buildStreetMorphologyFST(
|
|
|
140
146
|
|
|
141
147
|
progress("discover", `Found ${locales.length} locales with ${STREET_TYPES_FILENAME}`)
|
|
142
148
|
|
|
143
|
-
// Collect canonical → set-of-variants across all locales.
|
|
144
|
-
// multiple locales (e.g. "avenue" in en/fr); we union the variant sets.
|
|
149
|
+
// Collect canonical → set-of-variants across all locales.
|
|
150
|
+
// Same canonical form may appear in multiple locales (e.g. "avenue" in en/fr); we union the variant sets.
|
|
145
151
|
const canonicalToVariants = new Map<string, Set<string>>()
|
|
146
152
|
|
|
147
153
|
for (const locale of locales) {
|
|
148
|
-
const filePath =
|
|
154
|
+
const filePath = dictionariesDir(locale, STREET_TYPES_FILENAME)
|
|
149
155
|
const content = await readLocalTextFile(filePath)
|
|
150
156
|
|
|
151
157
|
for (const line of TextSpliterator.from(content)) {
|
|
@@ -164,7 +170,8 @@ export async function buildStreetMorphologyFST(
|
|
|
164
170
|
|
|
165
171
|
progress("collect", `Collected ${canonicalToVariants.size} canonical affixes`)
|
|
166
172
|
|
|
167
|
-
// Assign stable synthetic wofIDs.
|
|
173
|
+
// Assign stable synthetic wofIDs.
|
|
174
|
+
// Sort canonicals for determinism.
|
|
168
175
|
const sortedCanonicals = [...canonicalToVariants.keys()].toSorted()
|
|
169
176
|
const canonicalToWOFID = new Map<string, number>()
|
|
170
177
|
|
|
@@ -172,8 +179,9 @@ export async function buildStreetMorphologyFST(
|
|
|
172
179
|
canonicalToWOFID.set(sortedCanonicals[i]!, STREET_AFFIX_WOFID_BASE + i)
|
|
173
180
|
}
|
|
174
181
|
|
|
175
|
-
// Build the trie.
|
|
176
|
-
//
|
|
182
|
+
// Build the trie.
|
|
183
|
+
// Each variant is inserted as a token sequence pointing to its canonical's PlaceEntry —
|
|
184
|
+
// so all variants of "avenue" (av/ave/aven/...) lead to the same terminal entry.
|
|
177
185
|
const nodes: FSTNode[] = [{ edges: new Map(), places: [] }]
|
|
178
186
|
|
|
179
187
|
function insertName(tokens: string[], entry: PlaceEntry): void {
|
|
@@ -212,13 +220,16 @@ export async function buildStreetMorphologyFST(
|
|
|
212
220
|
placetype: "street_affix",
|
|
213
221
|
name: canonical,
|
|
214
222
|
parentChain: [],
|
|
215
|
-
// Fixed referential score: street affixes are structurally unambiguous
|
|
216
|
-
// never anything but street-typing).
|
|
217
|
-
//
|
|
218
|
-
//
|
|
223
|
+
// Fixed referential score: street affixes are structurally unambiguous
|
|
224
|
+
// (Avenue is almost never anything but street-typing).
|
|
225
|
+
// The morphology prior caps bias separately.
|
|
226
|
+
// This value just feeds the cap formula `referential * cap`.
|
|
227
|
+
// No encyclopedic score — a street affix is not a place and has no article.
|
|
219
228
|
referential: 1,
|
|
229
|
+
encyclopedic: null,
|
|
220
230
|
lat: 0,
|
|
221
231
|
lon: 0,
|
|
232
|
+
crossCountryBranches: null,
|
|
222
233
|
}
|
|
223
234
|
|
|
224
235
|
for (const variant of variants) {
|
|
@@ -251,7 +262,14 @@ export async function buildStreetMorphologyFST(
|
|
|
251
262
|
edgeCount,
|
|
252
263
|
nameInsertions: insertCount,
|
|
253
264
|
importanceMatches: 0, // No importance scoring for morphology — fixed at 1.0.
|
|
254
|
-
|
|
265
|
+
encyclopedicMatches: null,
|
|
266
|
+
importanceSource: null,
|
|
267
|
+
sourceDB: dictionariesDir.toString(),
|
|
268
|
+
sourceDBMD5: null,
|
|
269
|
+
sourceDBBytes: null,
|
|
270
|
+
modelCardVersion: null,
|
|
271
|
+
exclusionPolicy: null,
|
|
272
|
+
excludedInsertions: null,
|
|
255
273
|
}
|
|
256
274
|
|
|
257
275
|
return {
|
|
@@ -3,57 +3,64 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (`fst-street-morphology.bin`, built by `mailwoman gazetteer build street-morphology`) replaces
|
|
10
|
-
* those per-process builds; this loader is the ONE resolution ladder every node call site shares:
|
|
6
|
+
* Runtime loader for the street-morphology FST. The sealed artifact
|
|
7
|
+
* (`fst-street-morphology.bin`, built by `mailwoman gazetteer build street-morphology`) is the one
|
|
8
|
+
* resolution ladder every node call site shares.
|
|
11
9
|
*
|
|
12
|
-
* 1. An explicit `artifactPath
|
|
13
|
-
* `NeuralAddressClassifier.streetMorphologyPath
|
|
14
|
-
* 2. Otherwise the staged sealed artifact at `$MAILWOMAN_DATA_ROOT/wof/fst-street-morphology.bin`.
|
|
15
|
-
* 3.
|
|
16
|
-
* `street_types.txt` files
|
|
17
|
-
*
|
|
10
|
+
* 1. An explicit `artifactPath`, e.g. the weights-package sibling surfaced by
|
|
11
|
+
* `NeuralAddressClassifier.streetMorphologyPath`. When given, it is the only artifact probed.
|
|
12
|
+
* 2. Otherwise the staged sealed artifact at `$MAILWOMAN_DATA_ROOT/db/wof/fst-street-morphology.bin`.
|
|
13
|
+
* 3. A build-from-dictionaries fallback: `buildStreetMorphologyFST` over core's bundled libpostal
|
|
14
|
+
* `street_types.txt` files, kept so a missing artifact degrades to a per-process build instead
|
|
15
|
+
* of a crash.
|
|
18
16
|
*
|
|
19
17
|
* A present-but-unreadable artifact reports through `onWarn` and falls through to the build rung.
|
|
20
|
-
* Browsers
|
|
21
|
-
* `fst-deserialize-web.ts` (see the docs demo loader).
|
|
18
|
+
* Browsers cannot take the fallback because they have no filesystem API. They deserialize the same
|
|
19
|
+
* artifact through `fst-deserialize-web.ts` (see the docs demo loader).
|
|
22
20
|
*/
|
|
23
21
|
|
|
24
|
-
import {
|
|
25
|
-
import { pathExists
|
|
22
|
+
import { readLocalBuffer } from "@mailwoman/core/fs/readers"
|
|
23
|
+
import { pathExists } from "@mailwoman/core/fs/readers/stat"
|
|
26
24
|
import { resourceDictionaryPath } from "@mailwoman/core/paths"
|
|
25
|
+
import type { PathBuilder, PathBuilderLike } from "path-ts"
|
|
27
26
|
|
|
28
27
|
import type { FSTMatcher } from "#fst/matcher"
|
|
29
28
|
import { deserializeFST, readFSTProvenance } from "#fst/serialize"
|
|
30
29
|
import type { FSTProvenance } from "#fst/types"
|
|
30
|
+
import { wofDatabasePath } from "#paths"
|
|
31
31
|
import { buildStreetMorphologyFST } from "#street/morphology/fst/builder"
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* The sealed artifact's canonical filename
|
|
34
|
+
* The sealed artifact's canonical filename, identical in the data-root staging dir
|
|
35
|
+
* and as a weights-package sibling.
|
|
35
36
|
*/
|
|
36
37
|
export const STREET_MORPHOLOGY_ARTIFACT_FILENAME = "fst-street-morphology.bin"
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
|
-
* The staged artifact's default location: `$MAILWOMAN_DATA_ROOT/wof/fst-street-morphology.bin`.
|
|
40
|
+
* The staged artifact's default location: `$MAILWOMAN_DATA_ROOT/db/wof/fst-street-morphology.bin`.
|
|
40
41
|
*/
|
|
41
|
-
export function defaultStreetMorphologyArtifactPath():
|
|
42
|
-
return
|
|
42
|
+
export function defaultStreetMorphologyArtifactPath(): PathBuilder {
|
|
43
|
+
return wofDatabasePath(STREET_MORPHOLOGY_ARTIFACT_FILENAME)
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export interface LoadStreetMorphologyFSTOpts {
|
|
46
47
|
/**
|
|
47
|
-
* Explicit artifact path (e.g.
|
|
48
|
-
*
|
|
48
|
+
* Explicit artifact path (e.g. A weights-package sibling).
|
|
49
|
+
*
|
|
50
|
+
* When given, it is the only artifact probed.
|
|
51
|
+
* A missing or unreadable artifact degrades straight to the dictionary build, never a throw.
|
|
49
52
|
*/
|
|
50
|
-
artifactPath?:
|
|
53
|
+
artifactPath?: PathBuilderLike
|
|
51
54
|
/**
|
|
52
|
-
* Dictionaries dir for the build fallback.
|
|
55
|
+
* Dictionaries dir for the build fallback.
|
|
56
|
+
*
|
|
57
|
+
* @defaultValue core's bundled libpostal dictionaries.
|
|
53
58
|
*/
|
|
54
|
-
dictionariesDir?:
|
|
59
|
+
dictionariesDir?: PathBuilderLike
|
|
55
60
|
/**
|
|
56
|
-
* Unreadable-artifact diagnostics.
|
|
61
|
+
* Unreadable-artifact diagnostics.
|
|
62
|
+
*
|
|
63
|
+
* @defaultValue silent (the caller owns its warn channel).
|
|
57
64
|
*/
|
|
58
65
|
onWarn?: (message: string) => void
|
|
59
66
|
}
|
|
@@ -67,15 +74,16 @@ export interface LoadedStreetMorphologyFST {
|
|
|
67
74
|
/**
|
|
68
75
|
* The artifact path when `source === "artifact"`.
|
|
69
76
|
*/
|
|
70
|
-
path
|
|
77
|
+
path: PathBuilderLike | null
|
|
71
78
|
/**
|
|
72
|
-
* Build provenance
|
|
79
|
+
* Build provenance, read from the artifact trailer or copied from the fallback build.
|
|
73
80
|
*/
|
|
74
|
-
provenance
|
|
81
|
+
provenance: FSTProvenance | null
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
/**
|
|
78
|
-
* Load the street-morphology matcher: sealed artifact first, per-process
|
|
85
|
+
* Load the street-morphology matcher: sealed artifact first, per-process
|
|
86
|
+
* dictionary build as the degrade path.
|
|
79
87
|
*/
|
|
80
88
|
export async function loadStreetMorphologyFST(
|
|
81
89
|
opts: LoadStreetMorphologyFSTOpts = {}
|
|
@@ -89,7 +97,7 @@ export async function loadStreetMorphologyFST(
|
|
|
89
97
|
const matcher = deserializeFST(buf)
|
|
90
98
|
const provenance = readFSTProvenance(buf)
|
|
91
99
|
|
|
92
|
-
return { matcher, source: "artifact", path: artifactPath,
|
|
100
|
+
return { matcher, source: "artifact", path: artifactPath, provenance }
|
|
93
101
|
} catch (error) {
|
|
94
102
|
warn(
|
|
95
103
|
`street-morphology artifact at ${artifactPath} unreadable (${(error as Error).message}) — falling back to the dictionary build`
|
|
@@ -98,8 +106,8 @@ export async function loadStreetMorphologyFST(
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
const built = await buildStreetMorphologyFST({
|
|
101
|
-
dictionariesDir: opts.dictionariesDir ?? resourceDictionaryPath("libpostal"),
|
|
109
|
+
dictionariesDir: (opts.dictionariesDir ?? resourceDictionaryPath("libpostal")).toString(),
|
|
102
110
|
})
|
|
103
111
|
|
|
104
|
-
return { matcher: built.matcher, source: "built", provenance: built.provenance }
|
|
112
|
+
return { matcher: built.matcher, source: "built", path: null, provenance: built.provenance }
|
|
105
113
|
}
|
|
@@ -3,68 +3,79 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* The SQLite backend for {@link StreetLocalityEvidence}.
|
|
7
7
|
*
|
|
8
|
-
* Reads a street-name index (the FR instance
|
|
8
|
+
* Reads a street-name index (the FR instance is 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
|
-
* exist as a name" for the k-best rerank.
|
|
11
|
-
*
|
|
10
|
+
* exist as a name" for the k-best rerank. It is sync-by-interface and read-only, uses prepared
|
|
11
|
+
* statements. It also degrades gracefully on a tableless extract, following the same reader discipline as
|
|
12
|
+
* `AddressPointSqliteLookup`.
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* apostrophe'd street silently misses. The
|
|
16
|
-
*
|
|
17
|
-
* `foldStreetSurface` + a `street_norm` index before this backend is wired in production. Until
|
|
18
|
-
* then this class is correct-by-construction against a fixture built with the contract fold, and
|
|
19
|
-
* the production rebuild is a tracked BAN-sdk follow-up.
|
|
14
|
+
* The fold interface: the surface is folded with {@link foldStreetSurface} (the shared function),
|
|
15
|
+
* so the DB's `street_norm` column must have been built with that same fold or every hyphenated
|
|
16
|
+
* or apostrophe'd street silently misses. The column also needs a `street_norm` index before this
|
|
17
|
+
* backend is wired in production.
|
|
20
18
|
*/
|
|
21
19
|
|
|
22
20
|
import { foldStreetSurface, type StreetEvidenceScope, type StreetLocalityEvidence } from "@mailwoman/resolver"
|
|
23
|
-
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
21
|
+
import type { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
22
|
+
import { SQLiteLookup } from "@mailwoman/sqlite/lookup"
|
|
23
|
+
import type { PathBuilderLike } from "path-ts"
|
|
24
24
|
|
|
25
25
|
import type { WOFDatabase } from "#schema"
|
|
26
26
|
import { hasColumn, hasTable } from "#sqlite-utils"
|
|
27
27
|
|
|
28
28
|
export interface SQLiteStreetNameLookupOpts {
|
|
29
29
|
/**
|
|
30
|
-
* ISO-2 (upper-case) countries this index answers for.
|
|
30
|
+
* ISO-2 (upper-case) countries this index answers for.
|
|
31
|
+
*
|
|
32
|
+
* @defaultValue `["FR"]` (the BAN street-centroids instance).
|
|
31
33
|
*/
|
|
32
34
|
countries?: Iterable<string>
|
|
33
35
|
/**
|
|
34
|
-
* Table name.
|
|
36
|
+
* Table name.
|
|
37
|
+
*
|
|
38
|
+
* @defaultValue `street_centroid`
|
|
35
39
|
*/
|
|
36
40
|
table?: string
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
|
-
* A {@link StreetLocalityEvidence} backed by a street-name SQLite index.
|
|
41
|
-
*
|
|
44
|
+
* A {@link StreetLocalityEvidence} backed by a street-name SQLite index.
|
|
45
|
+
*
|
|
46
|
+
* Positive evidence only: any doubt (missing table, read miss) returns `false`,
|
|
47
|
+
* so the rerank fails open to the model's ranking.
|
|
42
48
|
*/
|
|
43
|
-
export class SQLiteStreetNameLookup implements StreetLocalityEvidence
|
|
49
|
+
export class SQLiteStreetNameLookup extends SQLiteLookup<WOFDatabase> implements StreetLocalityEvidence {
|
|
44
50
|
readonly countries: ReadonlySet<string>
|
|
45
|
-
readonly #db: DatabaseClient<WOFDatabase>
|
|
46
51
|
readonly #byName: ReturnType<DatabaseClient["prepare"]> | undefined
|
|
47
52
|
readonly #byNameLocality: ReturnType<DatabaseClient["prepare"]> | undefined
|
|
48
53
|
readonly #byNamePostcode: ReturnType<DatabaseClient["prepare"]> | undefined
|
|
49
54
|
|
|
50
|
-
constructor(dbPath:
|
|
55
|
+
constructor(dbPath: PathBuilderLike, opts: SQLiteStreetNameLookupOpts = {}) {
|
|
56
|
+
super({ databasePath: dbPath })
|
|
51
57
|
this.countries = new Set([...(opts.countries ?? ["FR"])].map((c) => c.toUpperCase()))
|
|
52
|
-
this.#db = new DatabaseClient<WOFDatabase>(dbPath, { readOnly: true })
|
|
53
58
|
const table = opts.table ?? "street_centroid"
|
|
54
59
|
|
|
55
|
-
// Degrade gracefully on an empty
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
// Degrade gracefully on an empty or tableless extract.
|
|
61
|
+
// A no-op miss, never a crash.
|
|
62
|
+
if (hasTable(this.database, table)) {
|
|
63
|
+
// Prefer the `name_key` column (built with `foldStreetSurface`
|
|
64
|
+
// and indexed by `idx_sc_name` for a direct seek).
|
|
65
|
+
// On a pre-rebuild extract, `street_norm` is a correct fallback.
|
|
66
|
+
// It uses a skip-scan.
|
|
67
|
+
// The fold that built `name_key` must match `foldStreetSurface` here.
|
|
68
|
+
// This is the fold-parity interface.
|
|
69
|
+
const keyCol = hasColumn(this.database, table, "name_key") ? "name_key" : "street_norm"
|
|
70
|
+
this.#byName = this.database.prepare(`SELECT 1 FROM ${table} WHERE ${keyCol} = ? LIMIT 1`)
|
|
62
71
|
|
|
63
|
-
this.#byNameLocality = this
|
|
72
|
+
this.#byNameLocality = this.database.prepare(
|
|
64
73
|
`SELECT 1 FROM ${table} WHERE ${keyCol} = ? AND locality_base = ? LIMIT 1`
|
|
65
74
|
)
|
|
66
75
|
|
|
67
|
-
this.#byNamePostcode = this
|
|
76
|
+
this.#byNamePostcode = this.database.prepare(
|
|
77
|
+
`SELECT 1 FROM ${table} WHERE ${keyCol} = ? AND postcode = ? LIMIT 1`
|
|
78
|
+
)
|
|
68
79
|
}
|
|
69
80
|
}
|
|
70
81
|
|
|
@@ -74,24 +85,17 @@ export class SQLiteStreetNameLookup implements StreetLocalityEvidence, Disposabl
|
|
|
74
85
|
|
|
75
86
|
if (!norm) return false
|
|
76
87
|
|
|
77
|
-
// Scoped lookups tighten precision when the hypothesis
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.#byNameLocality &&
|
|
82
|
-
this.#byNameLocality.get(norm, foldStreetSurface(scope.locality)) !== undefined
|
|
83
|
-
) {
|
|
88
|
+
// Scoped lookups tighten precision when the hypothesis includes a locality/postcode.
|
|
89
|
+
// A scoped miss falls back to the unscoped probe.
|
|
90
|
+
// The scope column may be incomplete, so a miss there does not establish absence.
|
|
91
|
+
if (scope?.locality && this.#byNameLocality && this.#byNameLocality.get(norm, foldStreetSurface(scope.locality))) {
|
|
84
92
|
return true
|
|
85
93
|
}
|
|
86
94
|
|
|
87
|
-
if (scope?.postcode && this.#byNamePostcode && this.#byNamePostcode.get(norm, scope.postcode)
|
|
95
|
+
if (scope?.postcode && this.#byNamePostcode && this.#byNamePostcode.get(norm, scope.postcode)) {
|
|
88
96
|
return true
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
return this.#byName.get(norm) !== undefined
|
|
92
100
|
}
|
|
93
|
-
|
|
94
|
-
[Symbol.dispose](): void {
|
|
95
|
-
this.#db[Symbol.dispose]()
|
|
96
|
-
}
|
|
97
101
|
}
|