@mailwoman/resolver-wof-sqlite 10.0.0 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/lib/address/point/interpolation.ts +45 -39
- package/lib/address/point/schema.ts +17 -40
- package/lib/address/point.ts +316 -0
- package/lib/{address/index.ts → address.ts} +1 -1
- package/lib/ancestry/backfill.ts +20 -86
- package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
- package/lib/build/candidate.ts +122 -174
- package/lib/build/population-corrections.ts +64 -0
- package/lib/build/slim.ts +44 -114
- package/lib/candidate/alias-bags.ts +16 -17
- package/lib/candidate/ancestors/schema.ts +77 -61
- package/lib/candidate/ancestors/sidecar.ts +15 -22
- package/lib/candidate/country-display-names.ts +6 -20
- package/lib/candidate/extract-fold.ts +10 -55
- package/lib/candidate/fts.ts +5 -23
- package/lib/candidate/importance.ts +65 -68
- package/lib/candidate/lookup.ts +124 -415
- package/lib/candidate/name-roles.ts +15 -33
- package/lib/candidate/own-name.ts +35 -32
- package/lib/candidate/place-attrs.ts +20 -13
- package/lib/candidate/schema.ts +29 -65
- package/lib/candidate/scoring.ts +54 -93
- package/lib/capital-schema.ts +21 -17
- package/lib/capitals.ts +29 -27
- package/lib/coincident-roles.ts +85 -55
- package/lib/convention/schema.ts +15 -16
- package/lib/convention.ts +144 -0
- package/lib/coverage-manifest-schema.ts +40 -45
- package/lib/currency-backfill.ts +34 -79
- package/lib/env.ts +1 -1
- package/lib/exact-match.ts +32 -21
- package/lib/extracts.ts +97 -74
- package/lib/fst/autocomplete.ts +54 -37
- package/lib/fst/builder.ts +37 -41
- package/lib/fst/deserialize-web.ts +16 -17
- package/lib/fst/format.ts +41 -23
- package/lib/fst/freshness.ts +43 -120
- package/lib/fst/matcher.ts +7 -5
- package/lib/fst/serialize.ts +54 -74
- package/lib/fst/types.ts +78 -75
- package/lib/{fst/index.ts → fst.ts} +1 -0
- package/lib/fts/query.ts +5 -36
- package/lib/fts.ts +280 -0
- package/lib/geonames/aliases.ts +73 -144
- package/lib/geonames/postal.ts +162 -71
- package/lib/index.ts +9 -8
- package/lib/interpolation.ts +48 -100
- package/lib/lookup.ts +155 -270
- package/lib/name-score.ts +9 -7
- package/lib/nsul/lookup.ts +37 -54
- package/lib/nsul/schema.ts +16 -43
- package/lib/paths.ts +159 -0
- package/lib/place-importance-schema.ts +62 -169
- package/lib/poi/lookup.ts +104 -121
- package/lib/poi/schema.ts +42 -26
- package/lib/polygon-schema.ts +10 -6
- package/lib/postal/city/alias/lookup.ts +22 -40
- package/lib/postal/city/alias/schema.ts +14 -10
- package/lib/postal/city/candidate-schema.ts +26 -20
- package/lib/postcode-point-lookup.ts +8 -27
- package/lib/primary-preference.ts +46 -126
- package/lib/proximity-rerank.ts +44 -33
- package/lib/ranking-weights.ts +105 -78
- package/lib/region-keys.ts +70 -42
- package/lib/reverse.ts +149 -86
- package/lib/schema.ts +73 -50
- package/lib/search-fetch.ts +90 -68
- package/lib/sqlite/convention-source.ts +15 -23
- package/lib/sqlite/utils.ts +19 -22
- package/lib/street/centroid/schema.ts +37 -42
- package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
- package/lib/street/morphology/fst/builder.ts +60 -42
- package/lib/street/morphology/fst/loader.ts +40 -32
- package/lib/street/name-lookup.ts +45 -41
- package/lib/street/normalize.ts +88 -219
- package/lib/street/segment-schema.ts +116 -43
- package/lib/{street/index.ts → street.ts} +1 -1
- package/lib/types.ts +109 -150
- package/lib/unified-schema.ts +29 -29
- package/lib/uprn/existence.ts +30 -19
- package/lib/uprn/lookup.ts +29 -68
- package/lib/uprn/schema.ts +18 -40
- package/lib/weights-overlay-linker.ts +236 -252
- package/out/address/point/interpolation.d.ts +20 -23
- package/out/address/point/interpolation.d.ts.map +1 -1
- package/out/address/point/interpolation.js +42 -39
- package/out/address/point/interpolation.js.map +1 -1
- package/out/address/point/schema.d.ts +12 -35
- package/out/address/point/schema.d.ts.map +1 -1
- package/out/address/point/schema.js +3 -19
- package/out/address/point/schema.js.map +1 -1
- package/out/address/point.d.ts +57 -0
- package/out/address/point.d.ts.map +1 -0
- package/out/address/point.js +206 -0
- package/out/address/point.js.map +1 -0
- package/out/{address/index.js → address.d.ts} +2 -2
- package/out/address.d.ts.map +1 -0
- package/out/{address/index.d.ts → address.js} +2 -2
- package/out/address.js.map +1 -0
- package/out/ancestry/backfill.d.ts +11 -64
- package/out/ancestry/backfill.d.ts.map +1 -1
- package/out/ancestry/backfill.js +14 -74
- package/out/ancestry/backfill.js.map +1 -1
- package/out/ancestry.d.ts +49 -0
- package/out/ancestry.d.ts.map +1 -0
- package/out/ancestry.js +59 -0
- package/out/ancestry.js.map +1 -0
- package/out/build/candidate.d.ts +82 -112
- package/out/build/candidate.d.ts.map +1 -1
- package/out/build/candidate.js +17 -100
- package/out/build/candidate.js.map +1 -1
- package/out/build/population-corrections.d.ts +52 -0
- package/out/build/population-corrections.d.ts.map +1 -0
- package/out/build/population-corrections.js +40 -0
- package/out/build/population-corrections.js.map +1 -0
- package/out/build/slim.d.ts +8 -44
- package/out/build/slim.d.ts.map +1 -1
- package/out/build/slim.js +33 -94
- package/out/build/slim.js.map +1 -1
- package/out/candidate/alias-bags.d.ts +6 -6
- package/out/candidate/alias-bags.d.ts.map +1 -1
- package/out/candidate/alias-bags.js +16 -17
- package/out/candidate/alias-bags.js.map +1 -1
- package/out/candidate/ancestors/schema.d.ts +73 -57
- package/out/candidate/ancestors/schema.d.ts.map +1 -1
- package/out/candidate/ancestors/schema.js +56 -48
- package/out/candidate/ancestors/schema.js.map +1 -1
- package/out/candidate/ancestors/sidecar.d.ts +3 -8
- package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
- package/out/candidate/ancestors/sidecar.js +15 -22
- package/out/candidate/ancestors/sidecar.js.map +1 -1
- package/out/candidate/country-display-names.d.ts +5 -15
- package/out/candidate/country-display-names.d.ts.map +1 -1
- package/out/candidate/country-display-names.js +6 -20
- package/out/candidate/country-display-names.js.map +1 -1
- package/out/candidate/extract-fold.d.ts +7 -15
- package/out/candidate/extract-fold.d.ts.map +1 -1
- package/out/candidate/extract-fold.js +5 -47
- package/out/candidate/extract-fold.js.map +1 -1
- package/out/candidate/fts.d.ts +5 -23
- package/out/candidate/fts.d.ts.map +1 -1
- package/out/candidate/fts.js +5 -23
- package/out/candidate/fts.js.map +1 -1
- package/out/candidate/importance.d.ts +60 -65
- package/out/candidate/importance.d.ts.map +1 -1
- package/out/candidate/importance.js +56 -63
- package/out/candidate/importance.js.map +1 -1
- package/out/candidate/lookup.d.ts +18 -55
- package/out/candidate/lookup.d.ts.map +1 -1
- package/out/candidate/lookup.js +82 -385
- package/out/candidate/lookup.js.map +1 -1
- package/out/candidate/name-roles.d.ts +9 -21
- package/out/candidate/name-roles.d.ts.map +1 -1
- package/out/candidate/name-roles.js +15 -33
- package/out/candidate/name-roles.js.map +1 -1
- package/out/candidate/own-name.d.ts +23 -25
- package/out/candidate/own-name.d.ts.map +1 -1
- package/out/candidate/own-name.js +35 -32
- package/out/candidate/own-name.js.map +1 -1
- package/out/candidate/place-attrs.d.ts +20 -13
- package/out/candidate/place-attrs.d.ts.map +1 -1
- package/out/candidate/place-attrs.js +4 -5
- package/out/candidate/place-attrs.js.map +1 -1
- package/out/candidate/schema.d.ts +27 -62
- package/out/candidate/schema.d.ts.map +1 -1
- package/out/candidate/schema.js +10 -22
- package/out/candidate/schema.js.map +1 -1
- package/out/candidate/scoring.d.ts +7 -8
- package/out/candidate/scoring.d.ts.map +1 -1
- package/out/candidate/scoring.js +52 -89
- package/out/candidate/scoring.js.map +1 -1
- package/out/capital-schema.d.ts +21 -17
- package/out/capital-schema.d.ts.map +1 -1
- package/out/capital-schema.js +17 -15
- package/out/capital-schema.js.map +1 -1
- package/out/capitals.d.ts +27 -25
- package/out/capitals.d.ts.map +1 -1
- package/out/capitals.js +23 -21
- package/out/capitals.js.map +1 -1
- package/out/coincident-roles.d.ts +60 -43
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +72 -50
- package/out/coincident-roles.js.map +1 -1
- package/out/convention/schema.d.ts +14 -14
- package/out/convention/schema.d.ts.map +1 -1
- package/out/convention/schema.js +6 -4
- package/out/convention/schema.js.map +1 -1
- package/out/convention.d.ts +97 -0
- package/out/convention.d.ts.map +1 -0
- package/out/convention.js +81 -0
- package/out/convention.js.map +1 -0
- package/out/coverage-manifest-schema.d.ts +34 -39
- package/out/coverage-manifest-schema.d.ts.map +1 -1
- package/out/coverage-manifest-schema.js +25 -34
- package/out/coverage-manifest-schema.js.map +1 -1
- package/out/currency-backfill.d.ts +16 -38
- package/out/currency-backfill.d.ts.map +1 -1
- package/out/currency-backfill.js +19 -46
- package/out/currency-backfill.js.map +1 -1
- package/out/env.d.ts +1 -1
- package/out/env.js +1 -1
- package/out/exact-match.d.ts +19 -10
- package/out/exact-match.d.ts.map +1 -1
- package/out/exact-match.js +32 -21
- package/out/exact-match.js.map +1 -1
- package/out/extracts.d.ts +66 -55
- package/out/extracts.d.ts.map +1 -1
- package/out/extracts.js +63 -55
- package/out/extracts.js.map +1 -1
- package/out/fst/autocomplete.d.ts +29 -21
- package/out/fst/autocomplete.d.ts.map +1 -1
- package/out/fst/autocomplete.js +39 -28
- package/out/fst/autocomplete.js.map +1 -1
- package/out/fst/builder.d.ts.map +1 -1
- package/out/fst/builder.js +37 -41
- package/out/fst/builder.js.map +1 -1
- package/out/fst/deserialize-web.d.ts +4 -4
- package/out/fst/deserialize-web.d.ts.map +1 -1
- package/out/fst/deserialize-web.js +15 -16
- package/out/fst/deserialize-web.js.map +1 -1
- package/out/fst/format.d.ts +41 -23
- package/out/fst/format.d.ts.map +1 -1
- package/out/fst/format.js +41 -23
- package/out/fst/format.js.map +1 -1
- package/out/fst/freshness.d.ts +19 -81
- package/out/fst/freshness.d.ts.map +1 -1
- package/out/fst/freshness.js +31 -94
- package/out/fst/freshness.js.map +1 -1
- package/out/fst/matcher.d.ts +5 -4
- package/out/fst/matcher.d.ts.map +1 -1
- package/out/fst/matcher.js +2 -2
- package/out/fst/matcher.js.map +1 -1
- package/out/fst/serialize.d.ts +28 -28
- package/out/fst/serialize.d.ts.map +1 -1
- package/out/fst/serialize.js +53 -71
- package/out/fst/serialize.js.map +1 -1
- package/out/fst/types.d.ts +78 -74
- package/out/fst/types.d.ts.map +1 -1
- package/out/fst/types.js +1 -4
- package/out/fst/types.js.map +1 -1
- package/out/{fst/index.js → fst.d.ts} +2 -1
- package/out/fst.d.ts.map +1 -0
- package/out/{fst/index.d.ts → fst.js} +2 -1
- package/out/fst.js.map +1 -0
- package/out/fts/query.d.ts +2 -27
- package/out/fts/query.d.ts.map +1 -1
- package/out/fts/query.js +5 -36
- package/out/fts/query.js.map +1 -1
- package/out/fts.d.ts +126 -0
- package/out/fts.d.ts.map +1 -0
- package/out/fts.js +188 -0
- package/out/fts.js.map +1 -0
- package/out/geonames/aliases.d.ts +26 -62
- package/out/geonames/aliases.d.ts.map +1 -1
- package/out/geonames/aliases.js +45 -117
- package/out/geonames/aliases.js.map +1 -1
- package/out/geonames/postal.d.ts +84 -44
- package/out/geonames/postal.d.ts.map +1 -1
- package/out/geonames/postal.js +115 -73
- package/out/geonames/postal.js.map +1 -1
- package/out/{geonames/index.js → geonames.d.ts} +1 -1
- package/out/geonames.d.ts.map +1 -0
- package/out/{geonames/index.d.ts → geonames.js} +1 -1
- package/out/geonames.js.map +1 -0
- package/out/index.d.ts +9 -8
- package/out/index.d.ts.map +1 -1
- package/out/index.js +6 -5
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +18 -55
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +27 -69
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +23 -51
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +136 -234
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +2 -2
- package/out/name-score.d.ts.map +1 -1
- package/out/name-score.js +9 -7
- package/out/name-score.js.map +1 -1
- package/out/nsul/lookup.d.ts +33 -34
- package/out/nsul/lookup.d.ts.map +1 -1
- package/out/nsul/lookup.js +26 -40
- package/out/nsul/lookup.js.map +1 -1
- package/out/nsul/schema.d.ts +16 -43
- package/out/nsul/schema.d.ts.map +1 -1
- package/out/nsul/schema.js +9 -35
- package/out/nsul/schema.js.map +1 -1
- package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
- package/out/nsul.d.ts.map +1 -0
- package/out/{nsul/index.js → nsul.js} +1 -1
- package/out/nsul.js.map +1 -0
- package/out/paths.d.ts +124 -0
- package/out/paths.d.ts.map +1 -0
- package/out/paths.js +104 -0
- package/out/paths.js.map +1 -0
- package/out/place-importance-schema.d.ts +51 -143
- package/out/place-importance-schema.d.ts.map +1 -1
- package/out/place-importance-schema.js +28 -143
- package/out/place-importance-schema.js.map +1 -1
- package/out/poi/lookup.d.ts +40 -47
- package/out/poi/lookup.d.ts.map +1 -1
- package/out/poi/lookup.js +69 -96
- package/out/poi/lookup.js.map +1 -1
- package/out/poi/schema.d.ts +41 -25
- package/out/poi/schema.d.ts.map +1 -1
- package/out/poi/schema.js +25 -17
- package/out/poi/schema.js.map +1 -1
- package/out/{poi/index.js → poi.d.ts} +1 -1
- package/out/poi.d.ts.map +1 -0
- package/out/{poi/index.d.ts → poi.js} +1 -1
- package/out/poi.js.map +1 -0
- package/out/polygon-schema.d.ts +10 -6
- package/out/polygon-schema.d.ts.map +1 -1
- package/out/polygon-schema.js +2 -2
- package/out/polygon-schema.js.map +1 -1
- package/out/postal/city/alias/lookup.d.ts +20 -23
- package/out/postal/city/alias/lookup.d.ts.map +1 -1
- package/out/postal/city/alias/lookup.js +17 -30
- package/out/postal/city/alias/lookup.js.map +1 -1
- package/out/postal/city/alias/schema.d.ts +14 -10
- package/out/postal/city/alias/schema.d.ts.map +1 -1
- package/out/postal/city/alias/schema.js +10 -8
- package/out/postal/city/alias/schema.js.map +1 -1
- package/out/postal/city/candidate-schema.d.ts +25 -19
- package/out/postal/city/candidate-schema.d.ts.map +1 -1
- package/out/postal/city/candidate-schema.js +21 -17
- package/out/postal/city/candidate-schema.js.map +1 -1
- package/out/{postal/index.d.ts → postal.d.ts} +1 -1
- package/out/postal.d.ts.map +1 -0
- package/out/{postal/index.js → postal.js} +1 -1
- package/out/postal.js.map +1 -0
- package/out/postcode-point-lookup.d.ts +6 -24
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +5 -17
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/primary-preference.d.ts +38 -92
- package/out/primary-preference.d.ts.map +1 -1
- package/out/primary-preference.js +15 -99
- package/out/primary-preference.js.map +1 -1
- package/out/proximity-rerank.d.ts +41 -30
- package/out/proximity-rerank.d.ts.map +1 -1
- package/out/proximity-rerank.js +38 -29
- package/out/proximity-rerank.js.map +1 -1
- package/out/ranking-weights.d.ts +98 -64
- package/out/ranking-weights.d.ts.map +1 -1
- package/out/ranking-weights.js +26 -25
- package/out/ranking-weights.js.map +1 -1
- package/out/region-keys.d.ts +50 -31
- package/out/region-keys.d.ts.map +1 -1
- package/out/region-keys.js +68 -40
- package/out/region-keys.js.map +1 -1
- package/out/reverse.d.ts +78 -50
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +98 -61
- package/out/reverse.js.map +1 -1
- package/out/schema.d.ts +72 -49
- package/out/schema.d.ts.map +1 -1
- package/out/schema.js +4 -5
- package/out/schema.js.map +1 -1
- package/out/search-fetch.d.ts +16 -12
- package/out/search-fetch.d.ts.map +1 -1
- package/out/search-fetch.js +83 -63
- package/out/search-fetch.js.map +1 -1
- package/out/sqlite/convention-source.d.ts +12 -16
- package/out/sqlite/convention-source.d.ts.map +1 -1
- package/out/sqlite/convention-source.js +13 -22
- package/out/sqlite/convention-source.js.map +1 -1
- package/out/sqlite/utils.d.ts +19 -19
- package/out/sqlite/utils.d.ts.map +1 -1
- package/out/sqlite/utils.js +14 -15
- package/out/sqlite/utils.js.map +1 -1
- package/out/street/centroid/schema.d.ts +37 -42
- package/out/street/centroid/schema.d.ts.map +1 -1
- package/out/street/centroid/schema.js +9 -21
- package/out/street/centroid/schema.js.map +1 -1
- package/out/street/centroid.d.ts +30 -0
- package/out/street/centroid.d.ts.map +1 -0
- package/out/street/{centroid/index.js → centroid.js} +13 -24
- package/out/street/centroid.js.map +1 -0
- package/out/street/morphology/fst/builder.d.ts +20 -10
- package/out/street/morphology/fst/builder.d.ts.map +1 -1
- package/out/street/morphology/fst/builder.js +44 -34
- package/out/street/morphology/fst/builder.js.map +1 -1
- package/out/street/morphology/fst/loader.d.ts +33 -26
- package/out/street/morphology/fst/loader.d.ts.map +1 -1
- package/out/street/morphology/fst/loader.js +23 -22
- package/out/street/morphology/fst/loader.js.map +1 -1
- package/out/street/name-lookup.d.ts +24 -18
- package/out/street/name-lookup.d.ts.map +1 -1
- package/out/street/name-lookup.js +34 -35
- package/out/street/name-lookup.js.map +1 -1
- package/out/street/normalize.d.ts +35 -136
- package/out/street/normalize.d.ts.map +1 -1
- package/out/street/normalize.js +77 -194
- package/out/street/normalize.js.map +1 -1
- package/out/street/segment-schema.d.ts +79 -39
- package/out/street/segment-schema.d.ts.map +1 -1
- package/out/street/segment-schema.js +71 -21
- package/out/street/segment-schema.js.map +1 -1
- package/out/{street/index.js → street.d.ts} +2 -2
- package/out/street.d.ts.map +1 -0
- package/out/{street/index.d.ts → street.js} +2 -2
- package/out/street.js.map +1 -0
- package/out/types.d.ts +84 -149
- package/out/types.d.ts.map +1 -1
- package/out/types.js +0 -6
- package/out/types.js.map +1 -1
- package/out/unified-schema.d.ts +8 -12
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +29 -29
- package/out/unified-schema.js.map +1 -1
- package/out/uprn/existence.d.ts +28 -17
- package/out/uprn/existence.d.ts.map +1 -1
- package/out/uprn/existence.js +26 -16
- package/out/uprn/existence.js.map +1 -1
- package/out/uprn/lookup.d.ts +14 -44
- package/out/uprn/lookup.d.ts.map +1 -1
- package/out/uprn/lookup.js +21 -57
- package/out/uprn/lookup.js.map +1 -1
- package/out/uprn/schema.d.ts +18 -40
- package/out/uprn/schema.d.ts.map +1 -1
- package/out/uprn/schema.js +10 -32
- package/out/uprn/schema.js.map +1 -1
- package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
- package/out/uprn.d.ts.map +1 -0
- package/out/{uprn/index.js → uprn.js} +1 -1
- package/out/uprn.js.map +1 -0
- package/out/weights-overlay-linker.d.ts +138 -144
- package/out/weights-overlay-linker.d.ts.map +1 -1
- package/out/weights-overlay-linker.js +105 -159
- package/out/weights-overlay-linker.js.map +1 -1
- package/package.json +91 -596
- package/lib/address/point/index.ts +0 -328
- package/lib/convention/index.ts +0 -154
- package/lib/fts/index.ts +0 -361
- package/out/address/index.d.ts.map +0 -1
- package/out/address/index.js.map +0 -1
- package/out/address/point/index.d.ts +0 -53
- package/out/address/point/index.d.ts.map +0 -1
- package/out/address/point/index.js +0 -222
- package/out/address/point/index.js.map +0 -1
- package/out/ancestry/index.d.ts +0 -45
- package/out/ancestry/index.d.ts.map +0 -1
- package/out/ancestry/index.js +0 -55
- package/out/ancestry/index.js.map +0 -1
- package/out/convention/index.d.ts +0 -106
- package/out/convention/index.d.ts.map +0 -1
- package/out/convention/index.js +0 -93
- package/out/convention/index.js.map +0 -1
- package/out/fst/index.d.ts.map +0 -1
- package/out/fst/index.js.map +0 -1
- package/out/fts/index.d.ts +0 -184
- package/out/fts/index.d.ts.map +0 -1
- package/out/fts/index.js +0 -277
- package/out/fts/index.js.map +0 -1
- package/out/geonames/index.d.ts.map +0 -1
- package/out/geonames/index.js.map +0 -1
- package/out/nsul/index.d.ts.map +0 -1
- package/out/nsul/index.js.map +0 -1
- package/out/poi/index.d.ts.map +0 -1
- package/out/poi/index.js.map +0 -1
- package/out/postal/index.d.ts.map +0 -1
- package/out/postal/index.js.map +0 -1
- package/out/street/centroid/index.d.ts +0 -40
- package/out/street/centroid/index.d.ts.map +0 -1
- package/out/street/centroid/index.js.map +0 -1
- package/out/street/index.d.ts.map +0 -1
- package/out/street/index.js.map +0 -1
- package/out/uprn/index.d.ts.map +0 -1
- package/out/uprn/index.js.map +0 -1
- /package/lib/{geonames/index.ts → geonames.ts} +0 -0
- /package/lib/{nsul/index.ts → nsul.ts} +0 -0
- /package/lib/{poi/index.ts → poi.ts} +0 -0
- /package/lib/{postal/index.ts → postal.ts} +0 -0
- /package/lib/{uprn/index.ts → uprn.ts} +0 -0
package/lib/proximity-rerank.ts
CHANGED
|
@@ -3,23 +3,24 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* filter.
|
|
6
|
+
* Re-order exact-match candidates by population and nearness on one additive scale when bias hints
|
|
7
|
+
* are present (the demo's map viewport, a user location), so an in-view namesake wins a tie
|
|
8
|
+
* without a hard filter. With no bias the order is plain population order, byte-identical.
|
|
9
9
|
*
|
|
10
|
-
* This lives in its own platform-free module because it has to run identically in two places
|
|
11
|
-
* reader and the browser byte-range twin. That is the
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* This lives in its own platform-free module because it has to run identically in two places, the
|
|
11
|
+
* Node candidate reader and the browser byte-range twin. That is the server and demo parity
|
|
12
|
+
* interface held by construction. Constants by themselves were not enough, since the two copies agreed on
|
|
13
|
+
* every literal and still diverged on which field the population term reads and on whether the
|
|
14
|
+
* combined value is written back.
|
|
15
15
|
*
|
|
16
16
|
* Two properties are required and easy to lose when transcribing:
|
|
17
17
|
*
|
|
18
|
-
* 1. The population base is `prominence ?? score
|
|
19
|
-
* primary preference, so reading raw score lets a coincidental foreign alias ride population
|
|
20
|
-
* whenever a viewport hint happens to be present.
|
|
21
|
-
* 2. The combined value is
|
|
22
|
-
* caller that only returns the array in bias order has its
|
|
18
|
+
* 1. The population base is `prominence ?? score`. `prominence` contains the bounded cross-country
|
|
19
|
+
* primary preference, so reading raw score lets a coincidental foreign alias ride population
|
|
20
|
+
* back over a primary whenever a viewport hint happens to be present.
|
|
21
|
+
* 2. The combined value is persisted into `prominence`. The resolver walk re-sorts by
|
|
22
|
+
* `prominence ?? score`, so a caller that only returns the array in bias order has its
|
|
23
|
+
* ordering silently discarded downstream.
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
26
|
import { haversineKm } from "@mailwoman/spatial"
|
|
@@ -35,24 +36,27 @@ export const BIAS_BOOST = 4
|
|
|
35
36
|
export const POP_BOOST = 4
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
* `log10(population + 1)` at which the population term saturates
|
|
39
|
-
*
|
|
39
|
+
* `log10(population + 1)` at which the population term saturates.
|
|
40
|
+
*
|
|
41
|
+
* A value of 6 means a population of one million warrants the whole {@link POP_BOOST},
|
|
42
|
+
* and larger populations warrant no more.
|
|
40
43
|
*/
|
|
41
44
|
export const POP_SCALE_LOG10 = 6
|
|
42
45
|
|
|
43
46
|
/**
|
|
44
47
|
* Distance at which the nearness term halves.
|
|
45
48
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* Sharper than the FTS reader's 100 km on purpose, because the candidate backend's
|
|
50
|
+
* score is log-population by itself with no bm25 document term.
|
|
51
|
+
* This weakens the population signal relative to the bias.
|
|
52
|
+
*
|
|
53
|
+
* At around 30 km the boost reaches only candidates the user is looking at,
|
|
54
|
+
* so an in-view namesake still wins and a distant one does not.
|
|
51
55
|
*/
|
|
52
56
|
export const PROX_SCALE_KM = 30
|
|
53
57
|
|
|
54
58
|
/**
|
|
55
|
-
* One bias hint
|
|
59
|
+
* One bias hint, a coordinate the user is looking at or standing on, optionally weighted.
|
|
56
60
|
*/
|
|
57
61
|
export interface ProximityBias {
|
|
58
62
|
lat: number
|
|
@@ -61,27 +65,31 @@ export interface ProximityBias {
|
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
/**
|
|
64
|
-
* The candidate fields the re-rank reads and writes.
|
|
65
|
-
*
|
|
68
|
+
* The candidate fields the re-rank reads and writes.
|
|
69
|
+
*
|
|
70
|
+
* This is structural, so the Node reader's `PlaceCandidate` and the browser twin's
|
|
71
|
+
* row shape both satisfy it without an adapter.
|
|
66
72
|
*/
|
|
67
73
|
export interface ProximityRerankable {
|
|
68
74
|
lat: number
|
|
69
75
|
lon: number
|
|
70
76
|
score: number
|
|
71
|
-
prominence?: number
|
|
77
|
+
prominence?: number | null
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
/**
|
|
75
|
-
* Population plus nearness on one additive scale.
|
|
76
|
-
*
|
|
81
|
+
* Population plus nearness on one additive scale.
|
|
82
|
+
*
|
|
83
|
+
* Exported for tests and for a caller that wants the value without the sort.
|
|
84
|
+
* Ordinary callers want {@link applyProximityRerank}.
|
|
77
85
|
*/
|
|
78
86
|
export function combinedProminence(candidate: ProximityRerankable, bias: readonly ProximityBias[]): number {
|
|
79
87
|
const popBase = candidate.prominence ?? candidate.score
|
|
80
88
|
const popTerm = POP_BOOST * Math.min(1, Math.max(0, popBase) / POP_SCALE_LOG10)
|
|
81
89
|
let proxTerm = 0
|
|
82
90
|
|
|
83
|
-
// A candidate at the null island has no coordinate,
|
|
84
|
-
//
|
|
91
|
+
// A candidate at the null island has no coordinate, so it warrants no nearness term.
|
|
92
|
+
// A 0,0 pair interpreted as a real coordinate would receive an enormous score.
|
|
85
93
|
if (!(candidate.lat === 0 && candidate.lon === 0)) {
|
|
86
94
|
for (const b of bias) {
|
|
87
95
|
const d = haversineKm(b.lat, b.lon, candidate.lat, candidate.lon)
|
|
@@ -97,10 +105,13 @@ export function combinedProminence(candidate: ProximityRerankable, bias: readonl
|
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
/**
|
|
100
|
-
* Re-order `candidates` in place by {@link combinedProminence}, persisting each
|
|
101
|
-
* resolver walk's own `prominence ?? score`
|
|
102
|
-
*
|
|
103
|
-
*
|
|
108
|
+
* Re-order `candidates` in place by {@link combinedProminence}, persisting each
|
|
109
|
+
* combined value into `prominence` so the resolver walk's own `prominence ?? score`
|
|
110
|
+
* sort preserves the bias order rather than undoing it.
|
|
111
|
+
*
|
|
112
|
+
* Stable within equal prominence, preserving the population order the index already gave.
|
|
113
|
+
* A caller with no bias hints must not call this.
|
|
114
|
+
* The no-bias path is plain population order by construction.
|
|
104
115
|
*/
|
|
105
116
|
export function applyProximityRerank<T extends ProximityRerankable>(
|
|
106
117
|
candidates: T[],
|
|
@@ -112,7 +123,7 @@ export function applyProximityRerank<T extends ProximityRerankable>(
|
|
|
112
123
|
|
|
113
124
|
return { c, i, p: c.prominence }
|
|
114
125
|
})
|
|
115
|
-
// oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array
|
|
126
|
+
// oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array. toSorted would double-allocate on a hot path
|
|
116
127
|
.sort((a, b) => b.p - a.p || a.i - b.i)
|
|
117
128
|
.forEach((x, j) => (candidates[j] = x.c))
|
|
118
129
|
|
package/lib/ranking-weights.ts
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* The locality-ranking weights and their shipped defaults
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The locality-ranking weights and their shipped defaults live here because each value is a measured tuning decision
|
|
7
|
+
* with its rationale attached. This block reads as a reference table outside the lookup's control flow.
|
|
8
|
+
* Tests import it directly to pin one change at a time.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* The weights used to rank `findPlace` results.
|
|
13
|
+
*
|
|
14
|
+
* Tweakable per-instance but defaults match the values declared in the Phase 4.2 plan doc.
|
|
14
15
|
*/
|
|
15
16
|
export interface RankingWeights {
|
|
16
17
|
/**
|
|
@@ -38,83 +39,110 @@ export interface RankingWeights {
|
|
|
38
39
|
*/
|
|
39
40
|
lengthPenaltyWeight: number
|
|
40
41
|
/**
|
|
41
|
-
* Magnitude of the proximity boost when the query
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
42
|
+
* Magnitude of the proximity boost when the query includes `near`.
|
|
43
|
+
*
|
|
44
|
+
* The contribution is `proximityBoost / (1 + distanceKm / proximityScaleKm)`.
|
|
45
|
+
* At distance 0 the boost has full magnitude.
|
|
46
|
+
*
|
|
47
|
+
* At `proximityScaleKm` it is half magnitude.
|
|
48
|
+
* It decays further as distance increases.
|
|
49
|
+
*
|
|
50
|
+
* Its default is tuned so proximity can overcome a typical FTS rank tie
|
|
51
|
+
* but not dominate a strong text match.
|
|
45
52
|
*/
|
|
46
53
|
proximityBoost: number
|
|
47
54
|
/**
|
|
48
|
-
* Magnitude of the bias-hint term inside the exact-tier
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
55
|
+
* Magnitude of the bias-hint term inside the exact-tier prominence sort (the `bias`/viewport path).
|
|
56
|
+
*
|
|
57
|
+
* Deliberately population-scale, so a candidate near the map view
|
|
58
|
+
* or the user beats a distant-but-bigger namesake.
|
|
59
|
+
* "The map view wins" is the feature.
|
|
60
|
+
*
|
|
61
|
+
* Same-region ties, where all candidates are far from every hint, still fall to population.
|
|
62
|
+
*
|
|
63
|
+
* @defaultValue the same value as `populationBoost`
|
|
52
64
|
*/
|
|
53
65
|
biasBoost: number
|
|
54
66
|
/**
|
|
55
|
-
* Distance (km) at which the proximity boost halves.
|
|
67
|
+
* Distance (km) at which the proximity boost halves.
|
|
68
|
+
*
|
|
69
|
+
* Tune to the typical query radius.
|
|
56
70
|
*/
|
|
57
71
|
proximityScaleKm: number
|
|
58
72
|
/**
|
|
59
|
-
* Magnitude of the population boost when the candidate has a known `wof:population`.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
73
|
+
* Magnitude of the population boost when the candidate has a known `wof:population`.
|
|
74
|
+
*
|
|
75
|
+
* The contribution is `populationBoost * log10(1 + population) / populationScaleLog10`,
|
|
76
|
+
* capped at `populationBoost`.
|
|
77
|
+
* WOF records population for about 15% of localities (mostly larger ones),
|
|
78
|
+
* and places without it get +0, never a penalty.
|
|
79
|
+
*
|
|
80
|
+
* Its default is tuned so the famous Springfield, IL (pop ~112k) gets about a 0.42 boost,
|
|
81
|
+
* enough to nudge past tiny same-name peers.
|
|
63
82
|
*/
|
|
64
83
|
populationBoost: number
|
|
65
84
|
/**
|
|
66
|
-
* Population (in log10) at which the boost reaches its full magnitude.
|
|
67
|
-
*
|
|
85
|
+
* Population (in log10) at which the boost reaches its full magnitude.
|
|
86
|
+
*
|
|
87
|
+
* Larger populations cap at the same value (no compounding effect for megacities).
|
|
88
|
+
*
|
|
89
|
+
* @defaultValue `6`, so a population of 1,000,000 gives `populationBoost` exactly
|
|
68
90
|
*/
|
|
69
91
|
populationScaleLog10: number
|
|
70
92
|
/**
|
|
71
|
-
* Tier candidates with an
|
|
72
|
-
* score is consulted.
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* falls outside that window is not rescued. For the region-abbrev case the window is comfortably sufficient (a
|
|
89
|
-
* handful of states match a 2-letter query).
|
|
93
|
+
* Tier candidates with an exact name/alias match above candidates that only match
|
|
94
|
+
* partially, before the weighted-sum score is consulted.
|
|
95
|
+
*
|
|
96
|
+
* The weighted sum adds population as a large additive boost, so famous places
|
|
97
|
+
* surface for unambiguous full-name queries.
|
|
98
|
+
* Population is a prominence prior.
|
|
99
|
+
*
|
|
100
|
+
* Its job is to break ties among candidates that match the query equally well,
|
|
101
|
+
* as in "Springfield" → Springfield IL over Springfield MA.
|
|
102
|
+
*
|
|
103
|
+
* It does not promote a place that matches the query worse.
|
|
104
|
+
* Tiers keep match quality as the primary key and prominence as the secondary key within each tier.
|
|
105
|
+
*
|
|
106
|
+
* Note: tiering re-ranks within the over-fetched candidate window (`limit * 4`),
|
|
107
|
+
* so a pathological exact match outside that window is not rescued.
|
|
108
|
+
*
|
|
109
|
+
* @defaultValue `true`
|
|
90
110
|
*/
|
|
91
111
|
exactMatchTiering: boolean
|
|
92
112
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
113
|
+
* Official-language names count as names.
|
|
114
|
+
*
|
|
115
|
+
* When true, a candidate holding the query as an official name (`names.official = 1`,
|
|
116
|
+
* a preferred-form name in an official language of its country, stamped at ingest)
|
|
117
|
+
* joins the name-exact sub-tier rather than the alias-exact one, provided its
|
|
118
|
+
* population clears {@link officialNameExactFloor}.
|
|
119
|
+
*
|
|
120
|
+
* Fixes unscoped "Åbo" → Turku (its official Swedish name) over a hamlet literally called Åbo.
|
|
121
|
+
* Population still orders within the sub-tier, so Paris → Paris FR is untouched.
|
|
122
|
+
*
|
|
123
|
+
* It requires a gazetteer carrying the `official` ingest bit.
|
|
124
|
+
*
|
|
125
|
+
* On older DBs without that column, the probe fails soft and behavior matches the flag being off.
|
|
126
|
+
*
|
|
127
|
+
* @defaultValue `true`
|
|
103
128
|
*/
|
|
104
129
|
officialNameExact: boolean
|
|
105
130
|
/**
|
|
106
|
-
* Minimum population for a candidate's official names to join the name-exact sub-tier.
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* carrying
|
|
110
|
-
*
|
|
131
|
+
* Minimum population for a candidate's official names to join the name-exact sub-tier.
|
|
132
|
+
*
|
|
133
|
+
* The floor separates the famous-exonym class from a junk-dominated one led by short-form
|
|
134
|
+
* mis-tags, where a place carrying a short form would bury real villages of that name.
|
|
135
|
+
* This is a rank-time knob, tunable without re-ingest.
|
|
136
|
+
* Below-floor official names stay in the alias tier.
|
|
111
137
|
*/
|
|
112
138
|
officialNameExactFloor: number
|
|
113
139
|
}
|
|
114
140
|
|
|
115
141
|
/**
|
|
116
|
-
* The shipped weights.
|
|
117
|
-
*
|
|
142
|
+
* The shipped weights.
|
|
143
|
+
*
|
|
144
|
+
* Every value is a measured decision, so change one and re-run the resolver eval.
|
|
145
|
+
* The per-field docs on {@link RankingWeights} say what each change moves.
|
|
118
146
|
*/
|
|
119
147
|
export const DEFAULT_WEIGHTS: RankingWeights = {
|
|
120
148
|
placetypeMatchBoost: 0.5,
|
|
@@ -126,34 +154,31 @@ export const DEFAULT_WEIGHTS: RankingWeights = {
|
|
|
126
154
|
proximityBoost: 0.8,
|
|
127
155
|
proximityScaleKm: 100,
|
|
128
156
|
biasBoost: 4,
|
|
129
|
-
// populationBoost is intentionally large
|
|
130
|
-
// of 1.5
|
|
131
|
-
// hundreds of alt-name entries that hurt their FTS document score
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
// RankingWeights override.
|
|
135
|
-
//
|
|
136
|
-
// Note: this resolver uses `place_population` directly. The separate `place_importance` table
|
|
137
|
-
// (Wikipedia-derived) is consumed by the FST layer, not here. See
|
|
138
|
-
// docs/articles/concepts/importance-vs-population.md for the two-signal contract.
|
|
157
|
+
// populationBoost is intentionally large.
|
|
158
|
+
// Real WOF showed BM25 gaps of 1.5 to 3.0 between famous places and tiny same-name peers,
|
|
159
|
+
// because the famous ones have hundreds of alt-name entries that hurt their FTS document score.
|
|
160
|
+
// This resolver reads `place_population` directly.
|
|
161
|
+
// The separate Wikipedia-derived `place_importance` table is consumed by the FST layer.
|
|
139
162
|
populationBoost: 4,
|
|
140
163
|
populationScaleLog10: 6,
|
|
141
|
-
// Exact name
|
|
142
|
-
//
|
|
143
|
-
// Fixes the 2-letter-region-abbrev bug ("ME" → Maine, not the more-populous Missouri).
|
|
164
|
+
// Exact name and alias matches outrank partial matches before the weighted sum.
|
|
165
|
+
// This keeps population as an intra-tier prominence tiebreaker instead of a cross-tier promoter.
|
|
144
166
|
exactMatchTiering: true,
|
|
145
|
-
// #936 option 3 — promoted default-ON 2026-07-03 (eval battery PASS; see the RankingWeights docstring).
|
|
146
167
|
officialNameExact: true,
|
|
147
168
|
officialNameExactFloor: 100_000,
|
|
148
169
|
}
|
|
149
170
|
|
|
150
171
|
/**
|
|
151
|
-
* The population contribution as a 0..1 fraction: `min(1, log10(1 + population) / populationScaleLog10)`.
|
|
152
|
-
*
|
|
153
|
-
*
|
|
172
|
+
* The population contribution as a 0..1 fraction: `min(1, log10(1 + population) / populationScaleLog10)`.
|
|
173
|
+
*
|
|
174
|
+
* Returns zero for an absent or non-positive population.
|
|
175
|
+
* It also returns zero for a non-positive scale.
|
|
176
|
+
*
|
|
177
|
+
* A magnitude never represents its own absence.
|
|
178
|
+
* The coordinate-first locality path consumes this fraction directly. {@link populationBoostTerm} scales it.
|
|
154
179
|
*/
|
|
155
180
|
export function populationScaleTerm(
|
|
156
|
-
population: number | null
|
|
181
|
+
population: number | null,
|
|
157
182
|
weights: Pick<RankingWeights, "populationScaleLog10">
|
|
158
183
|
): number {
|
|
159
184
|
if (population == null || population <= 0 || weights.populationScaleLog10 <= 0) return 0
|
|
@@ -162,12 +187,14 @@ export function populationScaleTerm(
|
|
|
162
187
|
}
|
|
163
188
|
|
|
164
189
|
/**
|
|
165
|
-
* The additive population boost: `populationBoost * populationScaleTerm(...)`,
|
|
166
|
-
* `10^populationScaleLog10` people.
|
|
167
|
-
*
|
|
190
|
+
* The additive population boost: `populationBoost * populationScaleTerm(...)`,
|
|
191
|
+
* capped at `populationBoost` magnitude at `10^populationScaleLog10` people.
|
|
192
|
+
*
|
|
193
|
+
* A missing population contributes 0, without a penalty.
|
|
194
|
+
* The one formula behind the Node weighted sum and the wasm re-rank, so the two backends cannot drift.
|
|
168
195
|
*/
|
|
169
196
|
export function populationBoostTerm(
|
|
170
|
-
population: number | null
|
|
197
|
+
population: number | null,
|
|
171
198
|
weights: Pick<RankingWeights, "populationBoost" | "populationScaleLog10">
|
|
172
199
|
): number {
|
|
173
200
|
return weights.populationBoost * populationScaleTerm(population, weights)
|
package/lib/region-keys.ts
CHANGED
|
@@ -3,15 +3,13 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* Lives HERE rather than in `mailwoman` because the dependency points this way: `mailwoman`
|
|
6
|
+
* Both consumers use this expansion to compare parsed region qualifiers with stored keys.
|
|
7
|
+
* Admin-coherence verdicts (`mailwoman/admin-coherence.ts`) fold a qualifier and the winner's ancestry
|
|
8
|
+
* to decide `confirmed` or `contradicted`. The candidate backend's admin-containment re-rank
|
|
9
|
+
* (`candidate-lookup.ts`) uses the same fold to find region-class rows. The shared function keeps
|
|
10
|
+
* both decisions aligned.
|
|
11
|
+
*
|
|
12
|
+
* Lives here rather than in `mailwoman` because the dependency points this way. `mailwoman`
|
|
15
13
|
* depends on `@mailwoman/resolver-wof-sqlite` (which owns the fold and already depends on codex),
|
|
16
14
|
* never the reverse.
|
|
17
15
|
*/
|
|
@@ -21,26 +19,39 @@ import { matchSubdivision, matchSubdivisionIn } from "@mailwoman/codex/country"
|
|
|
21
19
|
import { normalizeLocalityForKey } from "#street/normalize"
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
|
-
* The ancestry placetypes that answer for a parsed `region` qualifier
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* The ancestry placetypes that answer for a parsed `region` qualifier,
|
|
23
|
+
* WOF's admin band between country and locality.
|
|
24
|
+
*
|
|
25
|
+
* The full band covers qualifiers at any grain, such as "Lancashire"
|
|
26
|
+
* (a ceremonial county) or "Thüringen" (a Land).
|
|
27
|
+
* A qualifier may confirm against any level the backend stored.
|
|
28
|
+
*
|
|
29
|
+
* `contradicted` requires every level in the band to miss.
|
|
30
|
+
* A wider band makes the check more conservative.
|
|
28
31
|
*/
|
|
29
32
|
export const REGION_CLASS_PLACETYPES: ReadonlySet<string> = new Set(["region", "macroregion", "county", "macrocounty"])
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
* County-style qualifier prefixes stripped to produce a comparison
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
35
|
+
* County-style qualifier prefixes stripped to produce a comparison variant.
|
|
36
|
+
*
|
|
37
|
+
* Ireland writes `Co. Westmeath` where WOF stores `Westmeath`, so the prefix defeats the fold
|
|
38
|
+
* and every Irish county qualifier would read `contradicted`.
|
|
39
|
+
* The stripped form is added to the key set, never substituted.
|
|
40
|
+
*
|
|
41
|
+
* `County Durham` is a real name that also matches after prefix removal.
|
|
42
|
+
* Set union can only widen confirmation, so the closure is monotone.
|
|
43
|
+
*
|
|
44
|
+
* `contradicted → confirmed` is the only movement it can cause.
|
|
37
45
|
*/
|
|
38
46
|
const COUNTY_QUALIFIER_PREFIXES = ["county", "co.", "co"] as const
|
|
39
47
|
|
|
40
48
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
49
|
+
* Admin-qualifier words at the end, the suffix form of the prefix above.
|
|
50
|
+
*
|
|
51
|
+
* `San José Province` (CR board row) folds against stored `San José` only with the word removed.
|
|
52
|
+
*
|
|
53
|
+
* Same monotone rule.
|
|
54
|
+
* The stripped form joins the set, never replaces the original.
|
|
44
55
|
*/
|
|
45
56
|
const ADMIN_QUALIFIER_SUFFIXES = ["province", "prov.", "prov"] as const
|
|
46
57
|
|
|
@@ -83,14 +94,20 @@ function withoutSuffix(value: string, suffixes: readonly string[]): string {
|
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
/**
|
|
86
|
-
* The comparable keys a region string expands to: its own fold (the shared candidate.db `name_key`
|
|
87
|
-
* {@link normalizeLocalityForKey}
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
97
|
+
* The comparable keys a region string expands to: its own fold (the shared candidate.db `name_key`
|
|
98
|
+
* normalizer, {@link normalizeLocalityForKey}, so build side and check side agree by construction).
|
|
99
|
+
*
|
|
100
|
+
* A county-prefix-stripped variant.
|
|
101
|
+
* The codex subdivision expansions.
|
|
102
|
+
*
|
|
103
|
+
* The disjoint US and CA table always, plus the country-scoped table when the caller knows a country.
|
|
104
|
+
* `WA` under AU is Western Australia, while under US it is Washington,
|
|
105
|
+
* the collision that keeps AU out of the unscoped table.
|
|
106
|
+
*
|
|
107
|
+
* Every expansion lands the canonical name and code folds in the set, so `IL`
|
|
108
|
+
* and `Illinois`, or `WA` and `Western Australia`, meet from either side.
|
|
92
109
|
*/
|
|
93
|
-
export function regionKeys(value: string, countryAlpha2?: string): Set<string> {
|
|
110
|
+
export function regionKeys(value: string, countryAlpha2?: string | null): Set<string> {
|
|
94
111
|
const keys = new Set([normalizeLocalityForKey(value)])
|
|
95
112
|
|
|
96
113
|
for (const stripped of [
|
|
@@ -111,25 +128,36 @@ export function regionKeys(value: string, countryAlpha2?: string): Set<string> {
|
|
|
111
128
|
}
|
|
112
129
|
}
|
|
113
130
|
|
|
114
|
-
// The empty fold stays
|
|
115
|
-
//
|
|
116
|
-
//
|
|
131
|
+
// The empty fold stays in the set on purpose.
|
|
132
|
+
// The admin-coherence verdicts have always compared the empty key
|
|
133
|
+
// (two empty-folding strings intersect → `confirmed`), and this move must not shift a verdict.
|
|
134
|
+
// A consumer probing a table by key filters the empty string out itself.
|
|
117
135
|
return keys
|
|
118
136
|
}
|
|
119
137
|
|
|
120
138
|
/**
|
|
121
|
-
* The
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
139
|
+
* The probe-side expansion for a region qualifier, {@link regionKeys} plus the
|
|
140
|
+
* county-prefixed variant of every key.
|
|
141
|
+
*
|
|
142
|
+
* The verdict implementation intersects two {@link regionKeys} sets, so `Co. Donegal`
|
|
143
|
+
* meets stored `County Donegal` at the shared stripped key `donegal`.
|
|
144
|
+
* A table probe matches the stored fold verbatim in one direction.
|
|
145
|
+
*
|
|
146
|
+
* WOF stores Irish counties under `county donegal`.
|
|
147
|
+
* The table has no bare `donegal` key.
|
|
148
|
+
*
|
|
149
|
+
* The qualifier probe missed every Irish county until this variant landed.
|
|
150
|
+
*
|
|
151
|
+
* The `county <key>` form restores two-sidedness for the one stored-form family with an evidenced case.
|
|
152
|
+
* The union is monotone because a wider qualifier set can only find more bearers.
|
|
153
|
+
*
|
|
154
|
+
* Each bearer must still contain a candidate before anything moves.
|
|
155
|
+
*
|
|
156
|
+
* The suffix sibling (`<key> province`) is deliberately absent.
|
|
157
|
+
* The board has no case for this stored form.
|
|
158
|
+
* Add one before building a change for this suffix.
|
|
131
159
|
*/
|
|
132
|
-
export function regionQualifierProbeKeys(value: string, countryAlpha2?: string): Set<string> {
|
|
160
|
+
export function regionQualifierProbeKeys(value: string, countryAlpha2?: string | null): Set<string> {
|
|
133
161
|
const keys = regionKeys(value, countryAlpha2)
|
|
134
162
|
// Snapshot before widening: the loop adds `county <key>` members that must not themselves be revisited.
|
|
135
163
|
const bare = [...keys]
|