@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
|
@@ -3,33 +3,28 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Node reader over the
|
|
6
|
+
* Node reader over the postal-city alias table (`postal-city-alias-<cc>.db`) — the observed
|
|
7
7
|
* `postal_city → geo_locality` aliases per postcode (`build-postal-city-alias.ts`). Consumed by
|
|
8
8
|
* {@link WOFSQLitePlaceLookup}'s coordinate-first locality scorer: a user-typed postal city
|
|
9
9
|
* ("Antioch", postcode 37013) becomes a name-match alias for the geographic locality the postcode
|
|
10
|
-
* actually sits in ("Nashville"), so the right place tiers to the top instead of a same
|
|
11
|
-
* town in another state. Opt-in — the lookup is only constructed when a path is supplied
|
|
10
|
+
* actually sits in ("Nashville"), so the right place tiers to the top instead of a place with the same name
|
|
11
|
+
* town in another state. Opt-in — the lookup is only constructed when a path is supplied.
|
|
12
12
|
* absent it the resolver is byte-identical.
|
|
13
13
|
*
|
|
14
|
-
* The reader returns RAW divergent rows for a postcode
|
|
14
|
+
* The reader returns RAW divergent rows for a postcode. normalization + name-matching against the
|
|
15
15
|
* candidate localities is the scorer's job (it owns the case/diacritic fold the soft name score
|
|
16
16
|
* uses), keeping one normalizer in one place.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { SQLiteLookup, type SQLiteLookupOptions } from "@mailwoman/sqlite/lookup"
|
|
20
20
|
|
|
21
21
|
import type { PostalCityAliasDatabase } from "#postal/city/alias/schema"
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Pre-opened handle (tests / shared connections). Mutually exclusive with `databasePath`.
|
|
30
|
-
*/
|
|
31
|
-
database?: DatabaseClient<PostalCityAliasDatabase>
|
|
32
|
-
}
|
|
23
|
+
/**
|
|
24
|
+
* Where a {@link WOFPostalCityAliasLookup} reads from: a `postal-city-alias-<cc>.db` built by
|
|
25
|
+
* `build-postal-city-alias.ts`, opened read-only, or a connection the caller already holds.
|
|
26
|
+
*/
|
|
27
|
+
export type WOFPostalCityAliasLookupOpts = SQLiteLookupOptions<PostalCityAliasDatabase>
|
|
33
28
|
|
|
34
29
|
/**
|
|
35
30
|
* One divergent alias edge: the postal-system name and the geographic locality it maps to.
|
|
@@ -50,38 +45,29 @@ export interface PostalCityAlias {
|
|
|
50
45
|
}
|
|
51
46
|
|
|
52
47
|
/**
|
|
53
|
-
* Reader over `postal_city_alias`.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
48
|
+
* Reader over `postal_city_alias`.
|
|
49
|
+
*
|
|
50
|
+
* The only query is a postcode-scoped probe for divergent rows
|
|
51
|
+
* (where the postal name differs from the geographic name — the rows that provide alias signal),
|
|
52
|
+
* issued via the typed Kysely query builder against {@link PostalCityAliasDatabase}.
|
|
56
53
|
*/
|
|
57
|
-
export class WOFPostalCityAliasLookup
|
|
58
|
-
#db: DatabaseClient<PostalCityAliasDatabase>
|
|
59
|
-
/**
|
|
60
|
-
* Resources this instance opened. A connection handed in by a caller is NOT in here, so disposal cannot reach it —
|
|
61
|
-
* ownership is membership rather than a flag a later branch has to check.
|
|
62
|
-
*/
|
|
63
|
-
readonly #resources = new DisposableStack()
|
|
64
|
-
|
|
54
|
+
export class WOFPostalCityAliasLookup extends SQLiteLookup<PostalCityAliasDatabase> {
|
|
65
55
|
constructor(opts: WOFPostalCityAliasLookupOpts) {
|
|
66
|
-
|
|
67
|
-
this.#db = opts.database
|
|
68
|
-
} else if (opts.databasePath) {
|
|
69
|
-
this.#db = this.#resources.use(new DatabaseClient<PostalCityAliasDatabase>(opts.databasePath, { readOnly: true }))
|
|
70
|
-
} else {
|
|
71
|
-
throw new Error("WOFPostalCityAliasLookup needs `databasePath` or `database`")
|
|
72
|
-
}
|
|
56
|
+
super(opts)
|
|
73
57
|
}
|
|
74
58
|
|
|
75
59
|
/**
|
|
76
|
-
* Divergent postal-city aliases for a postcode (empty when the postcode isn't in the table).
|
|
77
|
-
*
|
|
60
|
+
* Divergent postal-city aliases for a postcode (empty when the postcode isn't in the table).
|
|
61
|
+
*
|
|
62
|
+
* The scorer groups these by normalized `geoLocality` and appends the `postalCity`
|
|
63
|
+
* surfaces to the matching candidate locality's alias set.
|
|
78
64
|
*/
|
|
79
65
|
async getDivergentAliases(postcode: string): Promise<PostalCityAlias[]> {
|
|
80
66
|
const pc = postcode.trim()
|
|
81
67
|
|
|
82
68
|
if (!pc) return []
|
|
83
69
|
|
|
84
|
-
const rows = await this
|
|
70
|
+
const rows = await this.database
|
|
85
71
|
.selectFrom("postal_city_alias")
|
|
86
72
|
.select(["postal_city", "geo_locality", "n"])
|
|
87
73
|
.where("postcode", "=", pc)
|
|
@@ -90,8 +76,4 @@ export class WOFPostalCityAliasLookup implements Disposable {
|
|
|
90
76
|
|
|
91
77
|
return rows.map((r) => ({ postalCity: String(r.postal_city), geoLocality: String(r.geo_locality), n: Number(r.n) }))
|
|
92
78
|
}
|
|
93
|
-
|
|
94
|
-
[Symbol.dispose](): void {
|
|
95
|
-
this.#resources[Symbol.dispose]()
|
|
96
|
-
}
|
|
97
79
|
}
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Typed schema for the
|
|
6
|
+
* Typed schema for the postal-city alias table (`postal-city-alias-<cc>.db`, built by
|
|
7
7
|
* `scripts/build-postal-city-alias.ts`) — the single source of truth for the columns shared by
|
|
8
|
-
* the
|
|
9
|
-
*
|
|
8
|
+
* the builder and the reader ({@link WOFPostalCityAliasLookup}). Like {@link CandidateTable}, the
|
|
9
|
+
* interface is a Kysely `Database` interface plus the table DDL as a string, so a column rename in
|
|
10
10
|
* the builder is a compile error in the reader.
|
|
11
11
|
*
|
|
12
|
-
* Provenance discipline (provenance-first): this is a
|
|
12
|
+
* Provenance discipline (provenance-first): this is a sibling table to the PIP-derived
|
|
13
13
|
* `postcode_locality` data, never mixed into it — one table, one provenance class. Each row is an
|
|
14
|
-
*
|
|
14
|
+
* observed `(postcode, postal_city, geo_locality)` aggregate from Overture's `postal_city` field
|
|
15
15
|
* with a usage count `n`; `divergent = 1` exactly when `postal_city != geo_locality` (the alias
|
|
16
16
|
* signal — the only rows the resolver consumes).
|
|
17
17
|
*/
|
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
import type { Kysely } from "kysely"
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* One observed postal-city aggregate.
|
|
23
|
-
*
|
|
22
|
+
* One observed postal-city aggregate.
|
|
23
|
+
*
|
|
24
|
+
* The natural key is `(postcode, postal_city, geo_locality)`; the builder enforces a
|
|
25
|
+
* `MIN_COUNT` floor on `n`, so every row is a non-trivial usage.
|
|
24
26
|
*/
|
|
25
27
|
export interface PostalCityAliasTable {
|
|
26
28
|
/**
|
|
@@ -61,7 +63,7 @@ export interface PostalCityAliasDatabase {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/**
|
|
64
|
-
* The `postal_city_alias` column order — the builder's
|
|
66
|
+
* The `postal_city_alias` column order — the builder's insert derives its column list from this.
|
|
65
67
|
*/
|
|
66
68
|
export const POSTAL_CITY_ALIAS_COLUMNS = [
|
|
67
69
|
"postcode",
|
|
@@ -74,8 +76,10 @@ export const POSTAL_CITY_ALIAS_COLUMNS = [
|
|
|
74
76
|
] as const
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
|
-
* Create the `postal_city_alias` table + its two probe indexes.
|
|
78
|
-
*
|
|
79
|
+
* Create the `postal_city_alias` table + its two probe indexes.
|
|
80
|
+
*
|
|
81
|
+
* Kept here (not only in the builder) so tests can stand up a fixture DB with the exact production shape.
|
|
82
|
+
* Pass a {@link DatabaseClient} (or any `Kysely`) over the alias DB.
|
|
79
83
|
*/
|
|
80
84
|
export async function createPostalCityAliasTable(db: Kysely<PostalCityAliasDatabase>): Promise<void> {
|
|
81
85
|
await db.schema
|
|
@@ -3,19 +3,18 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* Typed schema for the
|
|
7
|
-
*
|
|
8
|
-
* candidate-backend resolver (the demo
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Typed schema for the postal-city candidate side-index, a small `(name_key, postcode)` →
|
|
7
|
+
* geo-locality table alongside the byte-range `candidate` table.
|
|
8
|
+
* The candidate-backend resolver (the demo and CLI default) can then match the FTS coordinate-first scorer.
|
|
9
|
+
* It resolves a user-typed postal city ("Antioch", 37013) to the geographic locality the postcode
|
|
10
|
+
* resolve a user-typed postal city ("Antioch", 37013) to the geographic locality the postcode
|
|
11
|
+
* sits in ("Nashville").
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* entirely — consulted only when the query carries a postcode, so the common no-postcode path is
|
|
18
|
-
* untouched.
|
|
13
|
+
* The `candidate` B-tree is keyed `(name_key, country_id, region_id, placetype_id, …)` and ranked
|
|
14
|
+
* population-first, so it has no postcode dimension. A cloned alias row cannot satisfy both
|
|
15
|
+
* purposes, because a sentinel rank is bare-name-safe and then loses to any in-region homonym.
|
|
16
|
+
* The exact `(name_key, postcode)` probe bypasses population and region ranking entirely.
|
|
17
|
+
* It runs only when the query includes a postcode, leaving the common no-postcode path untouched.
|
|
19
18
|
*/
|
|
20
19
|
|
|
21
20
|
import { sql, type Kysely } from "kysely"
|
|
@@ -23,12 +22,14 @@ import { sql, type Kysely } from "kysely"
|
|
|
23
22
|
import type { NameKey } from "#street/normalize"
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
|
-
* One postal-city → geo-locality edge, keyed exactly by `(name_key, postcode)`.
|
|
27
|
-
*
|
|
25
|
+
* One postal-city → geo-locality edge, keyed exactly by `(name_key, postcode)`.
|
|
26
|
+
*
|
|
27
|
+
* The probe returns the geographic locality directly.
|
|
28
|
+
* The denormalized name/coord avoid a join back to `candidate`.
|
|
28
29
|
*/
|
|
29
30
|
export interface PostalCityCandidateTable {
|
|
30
31
|
/**
|
|
31
|
-
* {@link normalizeLocalityForKey} of the postal-city name
|
|
32
|
+
* {@link normalizeLocalityForKey} of the postal-city name, the build/query-consistent probe key.
|
|
32
33
|
*/
|
|
33
34
|
name_key: NameKey
|
|
34
35
|
/**
|
|
@@ -60,7 +61,7 @@ export interface PostalCityCandidateDatabase {
|
|
|
60
61
|
export const POSTAL_CITY_CANDIDATE_TABLE = "postal_city_candidate"
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
|
-
* Column order for the builder's positional
|
|
64
|
+
* Column order for the builder's positional insert.
|
|
64
65
|
*/
|
|
65
66
|
export const POSTAL_CITY_CANDIDATE_COLUMNS = [
|
|
66
67
|
"name_key",
|
|
@@ -72,9 +73,14 @@ export const POSTAL_CITY_CANDIDATE_COLUMNS = [
|
|
|
72
73
|
] as const
|
|
73
74
|
|
|
74
75
|
/**
|
|
75
|
-
* Create the side-index
|
|
76
|
-
*
|
|
77
|
-
*
|
|
76
|
+
* Create the side-index, a clustered `without rowid` B-tree on `(name_key, postcode)`
|
|
77
|
+
* so the resolve is a single exact probe.
|
|
78
|
+
*
|
|
79
|
+
* Idempotent (`if not exists`).
|
|
80
|
+
* Pass a {@link DatabaseClient} (or any `Kysely`) over the candidate DB.
|
|
81
|
+
*
|
|
82
|
+
* The Kysely schema-builder is the house idiom for table creation.
|
|
83
|
+
* See `agents.md` on inline SQL and Kysely.
|
|
78
84
|
*/
|
|
79
85
|
export async function createPostalCityCandidateTable(db: Kysely<PostalCityCandidateDatabase>): Promise<void> {
|
|
80
86
|
await db.schema
|
|
@@ -87,7 +93,7 @@ export async function createPostalCityCandidateTable(db: Kysely<PostalCityCandid
|
|
|
87
93
|
.addColumn("latitude", "real", (c) => c.notNull())
|
|
88
94
|
.addColumn("longitude", "real", (c) => c.notNull())
|
|
89
95
|
.addPrimaryKeyConstraint("postal_city_candidate_pk", ["name_key", "postcode"])
|
|
90
|
-
// `
|
|
96
|
+
// `without rowid` has no first-class builder. The raw modifier is the idiomatic fallback.
|
|
91
97
|
.modifyEnd(sql`without rowid`)
|
|
92
98
|
.execute()
|
|
93
99
|
}
|
|
@@ -2,53 +2,34 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* SQLite-backed postcode lookup for the postcode anchor (#240). A thin exact-match resolver over
|
|
7
|
-
* one or more `postalcode-*.db` extracts (the `spr` schema built by `build-unified-wof --placetypes
|
|
8
|
-
* postalcode`, then centroid-backfilled by `scripts/backfill-postcode-centroids.ts`).
|
|
9
|
-
*
|
|
10
|
-
* This is the production implementation of the `PostcodeResolver` interface consumed by
|
|
11
|
-
* `@mailwoman/neural`'s `extractPostcodeAnchors`. It is deliberately dumb: an indexed exact-match
|
|
12
|
-
* on the postcode string across every extract, unioned. No FTS, no ranking, no proximity — the
|
|
13
|
-
* anchor only needs "does this string exist as a postcode, in which countries, near where". A
|
|
14
|
-
* future WASM build swaps this for an FST-backed resolver behind the same `lookup()` interface.
|
|
15
|
-
*
|
|
16
|
-
* Why multiple extracts instead of the multi-extract `WOFSQLitePlaceLookup`: that resolver routes a
|
|
17
|
-
* query to ONE extract by placetype, but every postcode extract shares `placetype='postalcode'`, so a
|
|
18
|
-
* single query could only ever hit one country's extract. The anchor needs the union across
|
|
19
|
-
* countries to build its country posterior, so it queries each extract directly.
|
|
20
5
|
*/
|
|
21
6
|
|
|
7
|
+
import type { PostcodePlace } from "@mailwoman/core/resolver"
|
|
22
8
|
import { DatabaseClient } from "@mailwoman/sqlite/client"
|
|
9
|
+
import type { PathBuilderLike } from "path-ts"
|
|
23
10
|
|
|
24
11
|
import type { WOFDatabase } from "#schema"
|
|
25
12
|
|
|
26
|
-
/**
|
|
27
|
-
* A gazetteer hit. `lat`/`lon` of 0 means the postcode is known but has no centroid (no admin parent).
|
|
28
|
-
*/
|
|
29
|
-
export interface PostcodePlace {
|
|
30
|
-
country: string
|
|
31
|
-
lat: number
|
|
32
|
-
lon: number
|
|
33
|
-
}
|
|
34
|
-
|
|
35
13
|
const LOOKUP_SQL =
|
|
36
14
|
"SELECT country, latitude AS lat, longitude AS lon FROM spr WHERE name = ? AND placetype = 'postalcode' AND is_current != 0"
|
|
37
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Looks up current WOF `postalcode` places by exact name across one or more read-only gazetteer databases.
|
|
18
|
+
*/
|
|
38
19
|
export class WOFPostcodeLookup {
|
|
39
20
|
readonly #dbs: DatabaseClient<WOFDatabase>[]
|
|
40
21
|
readonly #stmts: ReturnType<DatabaseClient["prepare"]>[]
|
|
41
22
|
|
|
42
23
|
/**
|
|
43
|
-
*
|
|
24
|
+
* Opens each database read-only and prepares its exact-match statement.
|
|
44
25
|
*/
|
|
45
|
-
constructor(dbPaths: readonly
|
|
26
|
+
constructor(dbPaths: readonly PathBuilderLike[]) {
|
|
46
27
|
this.#dbs = dbPaths.map((p) => new DatabaseClient<WOFDatabase>(p, { readOnly: true }))
|
|
47
28
|
this.#stmts = this.#dbs.map((db) => db.prepare(LOOKUP_SQL))
|
|
48
29
|
}
|
|
49
30
|
|
|
50
31
|
/**
|
|
51
|
-
*
|
|
32
|
+
* Returns the union of exact-name matches for `postcode` across every database, without deduplication.
|
|
52
33
|
*/
|
|
53
34
|
lookup(postcode: string): PostcodePlace[] {
|
|
54
35
|
const out: PostcodePlace[] = []
|
|
@@ -2,146 +2,91 @@
|
|
|
2
2
|
* @copyright Sister Software
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
|
-
*
|
|
6
|
-
* Bounded cross-country PRIMARY-NAME preference over a population-ordered candidate row set — the
|
|
7
|
-
* `is_primary` ranking signal, PURE and platform-free so the Node candidate lookup
|
|
8
|
-
* (`candidate-lookup.ts`) and the browser twin (`packages/resolver-wof-wasm/lib/httpvfs/resolver.ts`) rank with
|
|
9
|
-
* the SAME function rather than two copies that drift (the #861 server↔browser parity contract).
|
|
10
|
-
*
|
|
11
|
-
* Only type imports and arithmetic live here: anything with a `node:` import stays out.
|
|
12
5
|
*/
|
|
13
6
|
|
|
14
7
|
import type { CandidateTable } from "#candidate/schema"
|
|
15
8
|
|
|
16
9
|
/**
|
|
17
|
-
* The row
|
|
18
|
-
*
|
|
19
|
-
*
|
|
10
|
+
* The candidate-row fields that {@link rankByPrimaryPreference} reads.
|
|
11
|
+
*
|
|
12
|
+
* `is_primary` is optional, so an older artifact without the column skips the re-rank without an error.
|
|
20
13
|
*/
|
|
21
14
|
export type PrimaryPreferenceRow = Pick<CandidateTable, "neg_rank" | "country_id"> &
|
|
22
15
|
Partial<Pick<CandidateTable, "is_primary" | "placetype_id" | "population" | "name_role">>
|
|
23
16
|
|
|
24
17
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* The raw candidate order is population-first (`neg_rank ASC`) and treats an ALIAS row (a place's alt-name / exonym,
|
|
28
|
-
* `is_primary=0`) and a PRIMARY-name row (`is_primary=1`) on equal footing. So a foreign place whose transliterated
|
|
29
|
-
* exonym coincidentally normalizes to a query — Changchun CN stores the Turkish exonym "Çançun" (`name_key="cancun"`),
|
|
30
|
-
* 4.19 M pop — outranks the PRIMARY-name place the query actually means (Cancún MX, 0.89 M pop). This penalty makes a
|
|
31
|
-
* same-key alias have to clear a population MARGIN over a foreign primary before it wins.
|
|
18
|
+
* The log10-population penalty applied to an alias row when the top primary-name
|
|
19
|
+
* row for the same key is in another country.
|
|
32
20
|
*
|
|
33
|
-
*
|
|
34
|
-
* every alias and break the alt-names users depend on — "NYC"→New York, "LA"→Los Angeles, "Frisco"→San Francisco). Two
|
|
35
|
-
* bounds keep it a soft prior:
|
|
36
|
-
*
|
|
37
|
-
* 1. **Cross-country only.** The penalty applies to an alias ONLY when the top-population primary sharing the key is in a
|
|
38
|
-
* DIFFERENT country. A SAME-country nickname contest (San Francisco's alias "Frisco" vs the primary Frisco, TX —
|
|
39
|
-
* both US) is left on pure population, so the legitimate alias still wins.
|
|
40
|
-
* 2. **Population-bounded.** The penalty is {@link PRIMARY_PREFERENCE_LOG10} in log10-population units — an alias must be
|
|
41
|
-
* at least 10x more populous than the foreign primary to still win. So a genuinely dominant alias keeps winning
|
|
42
|
-
* ("Los Angeles" over La, Ghana — gap 1.6; "Las Vegas" over Vegas, Cuba — gap 2.4) while a near-tie coincidental
|
|
43
|
-
* collision defers to the primary (Cancún over Changchun — gap 0.7).
|
|
21
|
+
* An alias at least 10 times as populous still wins, so alternate names such as "LA" keep working.
|
|
44
22
|
*/
|
|
45
23
|
export const PRIMARY_PREFERENCE_LOG10 = 1
|
|
46
24
|
|
|
47
|
-
/**
|
|
48
|
-
* The placetype the seat preference promotes: the populated-place tier a district duplicate shares its name and its
|
|
49
|
-
* population with. Named rather than inlined because narrowing the term to this ONE tier is what keeps it off the
|
|
50
|
-
* region/county and locality/neighbourhood contests — see `rankByPrimaryPreference` for the measurement.
|
|
51
|
-
*/
|
|
52
25
|
const SEAT_PLACETYPE = "locality"
|
|
53
26
|
|
|
54
27
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
28
|
+
* The number of population-ordered rows fetched per name key before
|
|
29
|
+
* {@link rankByPrimaryPreference} re-ranks them.
|
|
30
|
+
*
|
|
31
|
+
* A fetch of only the caller's `limit` could miss the intended primary behind more populous foreign aliases.
|
|
59
32
|
*/
|
|
60
33
|
export const RERANK_FETCH = 64
|
|
61
34
|
|
|
62
35
|
/**
|
|
63
|
-
* A candidate row
|
|
36
|
+
* A candidate row with its re-ranked `effectiveNegRank` and its `demoted` flag.
|
|
64
37
|
*/
|
|
65
38
|
export type RankedRow<R> = R & {
|
|
66
39
|
/**
|
|
67
|
-
* `neg_rank` plus
|
|
68
|
-
*
|
|
69
|
-
*
|
|
40
|
+
* `neg_rank` plus any cross-country alias penalty.
|
|
41
|
+
*
|
|
42
|
+
* Rows are ordered by this value.
|
|
43
|
+
* The emitted `prominence` derives from it.
|
|
44
|
+
*
|
|
45
|
+
* The raw `neg_rank` stays on the row for the resolver's minimum winning score.
|
|
70
46
|
*/
|
|
71
47
|
effectiveNegRank: number
|
|
48
|
+
|
|
72
49
|
/**
|
|
73
|
-
* True when this row is a cross-country alias that
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
50
|
+
* True when this row is a cross-country alias that the penalty moved behind
|
|
51
|
+
* the top primary for the same key.
|
|
52
|
+
*
|
|
53
|
+
* A demoted row loses `exactMatch`, so the resolver's country pin cannot promote
|
|
54
|
+
* a coincidental foreign exonym back over the primary.
|
|
55
|
+
* A dominant alias and a same-country alias are never demoted.
|
|
79
56
|
*/
|
|
80
57
|
demoted: boolean
|
|
58
|
+
|
|
81
59
|
/**
|
|
82
|
-
* True when this row came from the
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* has always done and what every `exactMatch`-filtering consumer assumed.
|
|
60
|
+
* True when this row came from the typo-correction fallback.
|
|
61
|
+
* The fallback runs only after the exact probes miss.
|
|
62
|
+
*
|
|
63
|
+
* The row is still returned and ranked, but it never claims `exactMatch`.
|
|
87
64
|
*/
|
|
88
65
|
fuzzy?: boolean
|
|
66
|
+
|
|
89
67
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
68
|
+
* Whether the row lies inside the query's region qualifier.
|
|
69
|
+
*
|
|
70
|
+
* The candidate lookup sets it when the artifact has the ancestors sidecar.
|
|
71
|
+
*
|
|
72
|
+
* When the field is absent, containment was not checked.
|
|
94
73
|
*/
|
|
95
74
|
containedByQualifier?: boolean
|
|
75
|
+
|
|
96
76
|
/**
|
|
97
|
-
*
|
|
98
|
-
* `exemptVariantAliases` prevented it. PRESENT only when the exemption changed this row's treatment; absent on every
|
|
99
|
-
* row it merely inspected — an in-country variant, a primary, a set with no foreign top primary. The winner-level
|
|
100
|
-
* receipt downstream (`mechanism_fired_on.variant_alias_exemption`) counts this mark only when it survives onto the
|
|
101
|
-
* selected candidate.
|
|
77
|
+
* Set only when the variant-alias exemption spared this row the cross-country alias penalty.
|
|
102
78
|
*/
|
|
103
79
|
variantExempted?: true
|
|
104
80
|
}
|
|
105
81
|
|
|
106
82
|
/**
|
|
107
|
-
*
|
|
108
|
-
* `candidate-lookup.test.ts` can exercise it on synthetic rows. `rows` arrive population-ordered (`neg_rank ASC`); an
|
|
109
|
-
* alias (`is_primary=0`) is pushed back by `delta` in log10-population units ONLY when the top-population primary
|
|
110
|
-
* sharing the key is in a different country, and is `demoted` out of the exact tier when that penalty leaves it BEHIND
|
|
111
|
-
* the primary. Returns the top `limit` after the re-rank, each annotated.
|
|
83
|
+
* Re-ranks population-ordered candidate rows.
|
|
112
84
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* {@link SEAT_PLACETYPE} row carrying a real population outranks every other placetype. Omit the map and every row
|
|
116
|
-
* scores 0, the term cancels, and the order is exactly the population-then-scan-order it was before.
|
|
85
|
+
* A cross-country alias must beat the top primary by `delta` in log10 population.
|
|
86
|
+
* The function returns the top `limit` rows.
|
|
117
87
|
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* (`referentialFromPopulation` is a pure function of population). Turkey's `Of` is the measured case — locality
|
|
121
|
-
* 8114738869649 and its parent county 8837168432019 both hold population 44212 — and 358 locality/parent-county pairs
|
|
122
|
-
* across 15 countries share the shape in `admin-global-priority.db` (TR 162, CA 77, US 47, HR 24, DO 14). Without the
|
|
123
|
-
* term their order is whatever the scan hands the sorter.
|
|
124
|
-
*
|
|
125
|
-
* WHERE THE TERM DECIDES, AND WHERE IT CANNOT (#1729). It binds inside `findPlace`, so it orders every row set that
|
|
126
|
-
* actually CONTAINS the tie — but the resolver walk's probes all carry a placetype filter, and
|
|
127
|
-
* `PLACETYPE_FILTER_GROUPS` (core/resolver) never mixes `locality` with `county`: the `Of`-shape locality/county pair
|
|
128
|
-
* is PARTITIONED before this ranker runs, the locality probe fetches one row, and the walk's own `locality` request
|
|
129
|
-
* selects the seat by construction — the same winner, decided upstream. The tie that reaches an end-to-end answer
|
|
130
|
-
* through this term is the IN-GROUP residue: a locality/localadmin (or borough) duplicate whose `importance` values
|
|
131
|
-
* also tie. Downstream the resolver re-sorts by importance (`resolver/toponym-prior.ts`) but is stable on equal keys,
|
|
132
|
-
* so the order stamped here is the order that answers — inverting this term moves bare `Pu-cheng-hsien` 1,100 km
|
|
133
|
-
* (locality Pucheng over the 浦城县 localadmin, identical population and importance). Where importance separates the pair,
|
|
134
|
-
* the fame prior overrides by design; a probe with NO placetype filter (the browser cascade's last resort, the dev
|
|
135
|
-
* lookup tools) presents the full tie and this term is all that breaks it.
|
|
136
|
-
*
|
|
137
|
-
* BOTH CONDITIONS ARE required, and a plain "finer placetype wins" measured wrong before this shape was settled: it
|
|
138
|
-
* moved the top slot on 11,377 keys in `candidate.db`, of which only 722 were the seat/district duplicate. The rest
|
|
139
|
-
* were contests between genuinely distinct places that merely tie — 2,885 `locality → neighbourhood` (a bare city name
|
|
140
|
-
* losing to a same-named hood), 2,973 `region → county`, 2,662 `postalcode → locality` — and 7,179 of the 11,377 sat at
|
|
141
|
-
* population 0, where a tie means NO EVIDENCE rather than equal evidence. Requiring a real population keeps the term
|
|
142
|
-
* off every no-evidence tie; promoting the populated-place tier specifically, rather than whatever is finer, keeps it
|
|
143
|
-
* off the admin-tier and hood contests. It can never reach a pair population separates: it does not override a
|
|
144
|
-
* population gap, it replaces an undetermined order with a stated one.
|
|
88
|
+
* When `placetypes` is given, an exact tie prefers a populated `locality`.
|
|
89
|
+
* This places a seat town ahead of a district with the same name and population.
|
|
145
90
|
*/
|
|
146
91
|
export function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(
|
|
147
92
|
rows: readonly R[],
|
|
@@ -150,9 +95,7 @@ export function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(
|
|
|
150
95
|
placetypes?: ReadonlyMap<number, string>,
|
|
151
96
|
exemptVariantAliases = false
|
|
152
97
|
): Array<RankedRow<R>> {
|
|
153
|
-
|
|
154
|
-
// when the set has no primary → nothing to prefer, penalty is 0, order stays population-first (today's behavior).
|
|
155
|
-
let topPrimary: R | undefined
|
|
98
|
+
let topPrimary: R | null = null
|
|
156
99
|
|
|
157
100
|
for (const r of rows) {
|
|
158
101
|
if (r.is_primary === 1 && (topPrimary == null || r.neg_rank < topPrimary.neg_rank)) {
|
|
@@ -162,14 +105,6 @@ export function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(
|
|
|
162
105
|
|
|
163
106
|
const topCountry = topPrimary?.country_id
|
|
164
107
|
|
|
165
|
-
// A cross-country alias (different country than the top primary) is penalized; it is DEMOTED when even after — i.e.
|
|
166
|
-
// the penalty leaves its effective rank behind the primary's raw rank (it lost the bounded population contest).
|
|
167
|
-
//
|
|
168
|
-
// #1882 exemption (opt-in): a `name_role = 'variant'` alias is the holder's OWN primary name in another
|
|
169
|
-
// orthography (`Брэст` → `brest`, `George Town` → `georgetown` — the build's own-name detector), so the
|
|
170
|
-
// query is naming THAT place, not colliding with it; the penalty exists for the coincidental-collision
|
|
171
|
-
// class ("Çançun"/`cancun`), which the detector's measured threshold keeps un-stamped. An artifact
|
|
172
|
-
// predating the role column carries no 'variant' rows, so the flag no-ops there by construction.
|
|
173
108
|
const wouldPenalize = (r: R): boolean =>
|
|
174
109
|
typeof topCountry === "number" && r.is_primary !== 1 && r.country_id !== topCountry
|
|
175
110
|
|
|
@@ -180,10 +115,6 @@ export function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(
|
|
|
180
115
|
const penalized = isCrossCountryAlias(r)
|
|
181
116
|
const effectiveNegRank = r.neg_rank + (penalized ? delta : 0)
|
|
182
117
|
|
|
183
|
-
// The firing mark (#1893): this row WOULD have taken the cross-country penalty and the exemption
|
|
184
|
-
// prevented it — conditions the winner-level receipt needs, computed where the decision is made. A
|
|
185
|
-
// variant row that was in-country, primary, or keyed under a set with no foreign primary never
|
|
186
|
-
// fired, and stays unmarked.
|
|
187
118
|
const exempted = !penalized && exemptVariantAliases && r.name_role === "variant" && wouldPenalize(r)
|
|
188
119
|
|
|
189
120
|
return {
|
|
@@ -194,12 +125,8 @@ export function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(
|
|
|
194
125
|
}
|
|
195
126
|
}
|
|
196
127
|
|
|
197
|
-
// 1 for a populated-place row that can BE a district's seat, 0 for everything else — no code map, no
|
|
198
|
-
// placetype on the row, an id the map does not carry, a placetype that is not the seat tier, or no
|
|
199
|
-
// recorded population. Every row scoring 0 cancels the term, leaving exactly the
|
|
200
|
-
// population-then-scan-order the sort had before it existed.
|
|
201
128
|
const seatPreference = (r: R): number =>
|
|
202
|
-
placetypes
|
|
129
|
+
placetypes &&
|
|
203
130
|
typeof r.placetype_id === "number" &&
|
|
204
131
|
typeof r.population === "number" &&
|
|
205
132
|
r.population > 0 &&
|
|
@@ -207,21 +134,14 @@ export function rankByPrimaryPreference<R extends PrimaryPreferenceRow>(
|
|
|
207
134
|
? 1
|
|
208
135
|
: 0
|
|
209
136
|
|
|
210
|
-
// 1 for a PRIMARY-name row whose prominence is unmeasured (population 0), 0 for everything else. Two unmeasured
|
|
211
|
-
// rows tie on `neg_rank`, and that tie used to fall through to scan order — the B-tree's `spr_id`, which is no
|
|
212
|
-
// evidence about either place. A row that IS named X ranks ahead of one merely also-known-as X when nothing else
|
|
213
|
-
// separates them: Taiwan's 溪州鄉 township row (its own name, unmeasured) over the village 溪洲 30 km away that
|
|
214
|
-
// carries `溪州鄉` as an alias (unmeasured), which the lower WOF id had been winning. Populated ties are untouched —
|
|
215
|
-
// a populated alias ("NYC") never reaches this term, and two populated rows keep the order they had.
|
|
216
137
|
const unmeasuredPrimary = (r: R): number =>
|
|
217
138
|
r.is_primary === 1 && typeof r.population === "number" && r.population === 0 ? 1 : 0
|
|
218
139
|
|
|
219
140
|
return (
|
|
220
141
|
rows
|
|
221
142
|
.map((r, i) => ({ row: annotate(r), i }))
|
|
222
|
-
|
|
223
|
-
//
|
|
224
|
-
// oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array; toSorted would double-allocate on a hot path
|
|
143
|
+
|
|
144
|
+
// oxlint-disable-next-line unicorn/no-array-sort -- sorts a freshly-built array. toSorted would double-allocate on a hot path
|
|
225
145
|
.sort(
|
|
226
146
|
(a, b) =>
|
|
227
147
|
a.row.effectiveNegRank - b.row.effectiveNegRank ||
|