@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/fst/autocomplete.ts
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
* @license AGPL-3.0
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
|
-
* FST-based autocomplete
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* FST-based autocomplete, mailwoman vocabulary over `@mailwoman/ancestrie`'s generic algorithm.
|
|
7
|
+
* The prefix walk, BFS expansion, partial-last-token completion, per-branch capping and dedupe
|
|
8
|
+
* live in ancestrie's `autocomplete`. This module contributes only the storage adapter
|
|
9
|
+
* ({@link FSTMatcher} → `AncestrieReaderLike`) and the mapping back to mailwoman's suggestion
|
|
10
|
+
* shape (name, placetype, referential and encyclopedic scores, WOF ids).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* ancestrie's
|
|
14
|
-
*
|
|
15
|
-
* legitimately
|
|
16
|
-
* The matcher, both deserializers
|
|
17
|
-
*
|
|
12
|
+
* The bytes do not migrate. The shipped artifacts are `FST\0` v1 to v5 (`fst-serialize.ts`), and
|
|
13
|
+
* ancestrie's entries are id-keyed with one record per id. An FST place row is per-(surface,
|
|
14
|
+
* place), because `crossCountryBranches` is a property of the surface, so the same wofID
|
|
15
|
+
* legitimately has different values under different aliases, so it cannot use IDs as keys.
|
|
16
|
+
* The matcher, both deserializers and serializer stay here. The algorithm is the
|
|
17
|
+
* half that migrated.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type {
|
|
@@ -41,16 +41,20 @@ export interface AutocompleteSuggestion {
|
|
|
41
41
|
name: string
|
|
42
42
|
placetype: string
|
|
43
43
|
/**
|
|
44
|
-
* The
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* The referential likelihood the suggestion is ranked by (ROAD_TO_V9 §2).
|
|
45
|
+
*
|
|
46
|
+
* Autocomplete answers "which place does the user mean", so it ranks referentially like everything else.
|
|
47
|
+
* Encyclopedic importance appears in {@link AutocompleteSuggestion.encyclopedic}
|
|
48
|
+
* for display and never enters the order.
|
|
47
49
|
*/
|
|
48
50
|
referential: number
|
|
49
51
|
/**
|
|
50
|
-
* Encyclopedic (Wikipedia) importance, when the FST artifact
|
|
51
|
-
*
|
|
52
|
+
* Encyclopedic (Wikipedia) importance, when the FST artifact stores one for this place.
|
|
53
|
+
*
|
|
54
|
+
* `undefined` means no article, or a pre-v5 binary.
|
|
55
|
+
* It is never 0.
|
|
52
56
|
*/
|
|
53
|
-
encyclopedic
|
|
57
|
+
encyclopedic: number | null
|
|
54
58
|
wofID: number
|
|
55
59
|
parentChain: number[]
|
|
56
60
|
matchDepth: number
|
|
@@ -61,22 +65,28 @@ export interface AutocompleteOpts {
|
|
|
61
65
|
maxSuggestions?: number
|
|
62
66
|
maxExpansionDepth?: number
|
|
63
67
|
/**
|
|
64
|
-
* Collapse same-name suggestions to the single highest-referential one.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
68
|
+
* Collapse same-name suggestions to the single highest-referential one.
|
|
69
|
+
*
|
|
70
|
+
* Off by default, because the CLI surfaces distinct same-name places such as
|
|
71
|
+
* New York the city and New York the county.
|
|
72
|
+
* A typeahead wants it on so the dropdown does not show four "New London"s.
|
|
67
73
|
*/
|
|
68
74
|
dedupeByName?: boolean
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
/**
|
|
72
|
-
* Max accepting entries collected per BFS branch
|
|
78
|
+
* Max accepting entries collected per BFS branch, keeping one dense branch from starving the search.
|
|
73
79
|
*/
|
|
74
80
|
const PER_BRANCH = 4
|
|
75
81
|
|
|
76
82
|
/**
|
|
77
|
-
* The top-`k` entries by
|
|
78
|
-
*
|
|
79
|
-
*
|
|
83
|
+
* The top-`k` entries by referential likelihood (descending).
|
|
84
|
+
*
|
|
85
|
+
* Avoids sorting or allocating when `entries` is small.
|
|
86
|
+
* That shortcut is part of the observable interface.
|
|
87
|
+
*
|
|
88
|
+
* At or under `k`, suggestions retain insertion order.
|
|
89
|
+
* That order decides suggestions among referential ties.
|
|
80
90
|
*/
|
|
81
91
|
function topByReferential(entries: readonly PlaceEntry[], k: number): PlaceEntry[] {
|
|
82
92
|
if (entries.length <= k) return [...entries]
|
|
@@ -85,19 +95,23 @@ function topByReferential(entries: readonly PlaceEntry[], k: number): PlaceEntry
|
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
/**
|
|
88
|
-
* {@link FSTMatcher} presented through ancestrie's storage interface.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
98
|
+
* {@link FSTMatcher} presented through ancestrie's storage interface.
|
|
99
|
+
*
|
|
100
|
+
* Records store the {@link PlaceEntry} itself as the payload, so the entry that wins the
|
|
101
|
+
* algorithm's shallowest-depth rule is the entry whose fields the suggestion reports.
|
|
102
|
+
* A side lookup keyed on id could pick a different surface's row
|
|
103
|
+
* (`crossCountryBranches` differs per surface).
|
|
92
104
|
*/
|
|
93
105
|
class FSTReader implements AncestrieReaderLike<PlaceEntry> {
|
|
94
106
|
readonly #fst: FSTMatcher
|
|
95
107
|
|
|
96
108
|
/**
|
|
97
|
-
* Parent chains of the entries this reader has served, id-keyed.
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
109
|
+
* Parent chains of the entries this reader has served, id-keyed.
|
|
110
|
+
*
|
|
111
|
+
* A place's chain is identical across its surfaces (it is place-row data), so last-write-wins is safe.
|
|
112
|
+
* The algorithm asks {@link FSTReader.ancestorsOf} only for ids it just received
|
|
113
|
+
* from {@link FSTReader.entriesAt}, so serving from this memo answers every
|
|
114
|
+
* real call without an artifact-wide id index.
|
|
101
115
|
*/
|
|
102
116
|
readonly #chains = new Map<number, number[]>()
|
|
103
117
|
|
|
@@ -110,7 +124,8 @@ class FSTReader implements AncestrieReaderLike<PlaceEntry> {
|
|
|
110
124
|
}
|
|
111
125
|
|
|
112
126
|
continuations(stateID: number): AncestrieContinuation[] {
|
|
113
|
-
// Insertion order, verbatim
|
|
127
|
+
// Insertion order, verbatim.
|
|
128
|
+
// BFS visit order under the suggestion budget depends on it.
|
|
114
129
|
return this.#fst.continuations(stateID).map((c) => ({
|
|
115
130
|
token: c.token,
|
|
116
131
|
targetState: c.targetState,
|
|
@@ -140,7 +155,9 @@ class FSTReader implements AncestrieReaderLike<PlaceEntry> {
|
|
|
140
155
|
}
|
|
141
156
|
|
|
142
157
|
/**
|
|
143
|
-
* Autocomplete from the current prefix.
|
|
158
|
+
* Autocomplete from the current prefix.
|
|
159
|
+
*
|
|
160
|
+
* @returns Suggestions ranked referential-descending.
|
|
144
161
|
*/
|
|
145
162
|
export function autocomplete(fst: FSTMatcher, query: string, opts: AutocompleteOpts = {}): AutocompleteResult {
|
|
146
163
|
const normalizedTokens = normalizeTokens(query)
|
|
@@ -149,7 +166,7 @@ export function autocomplete(fst: FSTMatcher, query: string, opts: AutocompleteO
|
|
|
149
166
|
...(opts.maxSuggestions === undefined ? {} : { maxSuggestions: opts.maxSuggestions }),
|
|
150
167
|
...(opts.maxExpansionDepth === undefined ? {} : { maxExpansionDepth: opts.maxExpansionDepth }),
|
|
151
168
|
perBranchLimit: PER_BRANCH,
|
|
152
|
-
// The dedupe key is the
|
|
169
|
+
// The dedupe key is the display name, so two surfaces of one name still collapse.
|
|
153
170
|
...(opts.dedupeByName ? { dedupe: (s: AncestrieSuggestion<PlaceEntry>) => s.payload!.name.toLowerCase() } : {}),
|
|
154
171
|
})
|
|
155
172
|
|
|
@@ -158,14 +175,14 @@ export function autocomplete(fst: FSTMatcher, query: string, opts: AutocompleteO
|
|
|
158
175
|
normalizedTokens,
|
|
159
176
|
depth: result.depth,
|
|
160
177
|
suggestions: result.suggestions.map((s) => {
|
|
161
|
-
// Every record this adapter serves
|
|
178
|
+
// Every record this adapter serves includes its entry, so the non-null assertion holds.
|
|
162
179
|
const entry = s.payload!
|
|
163
180
|
|
|
164
181
|
return {
|
|
165
182
|
name: entry.name,
|
|
166
183
|
placetype: entry.placetype,
|
|
167
184
|
referential: entry.referential,
|
|
168
|
-
|
|
185
|
+
encyclopedic: entry.encyclopedic,
|
|
169
186
|
wofID: s.id,
|
|
170
187
|
parentChain: s.parentIDs,
|
|
171
188
|
matchDepth: s.matchDepth,
|
package/lib/fst/builder.ts
CHANGED
|
@@ -35,8 +35,10 @@ const DEFAULT_PLACETYPES: PlacetypeID[] = [
|
|
|
35
35
|
const DEFAULT_COUNTRIES = ["US"]
|
|
36
36
|
const DEFAULT_LANGUAGES = ["eng", ""]
|
|
37
37
|
/**
|
|
38
|
-
* Ids per `IN (…)` batch.
|
|
39
|
-
*
|
|
38
|
+
* Ids per `IN (…)` batch.
|
|
39
|
+
*
|
|
40
|
+
* SQLITE_MAX_VARIABLE_NUMBER defaults to 32,766. 500 matches the name-load batch a
|
|
41
|
+
* few phases down, so both read paths bind the same shape.
|
|
40
42
|
*/
|
|
41
43
|
const ANCESTOR_CHUNK = 500
|
|
42
44
|
|
|
@@ -70,7 +72,6 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
70
72
|
progress("open", dbPath)
|
|
71
73
|
using db = new DatabaseClient<WOFDatabase>(dbPath, { open: true })
|
|
72
74
|
|
|
73
|
-
// Phase 1: Load all matching SPR rows.
|
|
74
75
|
progress("spr", `Loading places for countries=[${countries}], placetypes=[${placetypes}]`)
|
|
75
76
|
const placeholders = (arr: string[]) => arr.map(() => "?").join(",")
|
|
76
77
|
|
|
@@ -85,20 +86,18 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
85
86
|
const sprRows = allRows<SprRow>(sprStmt, ...countries, ...placetypes)
|
|
86
87
|
progress("spr", `Loaded ${sprRows.length} places`)
|
|
87
88
|
|
|
88
|
-
// Phase 2: Build a lookup for parent chain resolution.
|
|
89
89
|
const sprByID = new Map<number, SprRow>()
|
|
90
90
|
|
|
91
91
|
for (const row of sprRows) {
|
|
92
92
|
sprByID.set(row.id, row)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
//
|
|
95
|
+
// Load parent rows that might be outside the placetype filter, such as a country for a region.
|
|
96
96
|
const parentStmt = db.prepare("SELECT id, name, placetype, parent_id, latitude, longitude FROM spr WHERE id = ?")
|
|
97
97
|
|
|
98
|
-
// Fallback for a sentinel parent_id (-1, -4, …): the ancestors table
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
// per-row query used, with `id` leading so one pass groups the rows.
|
|
98
|
+
// Fallback for a sentinel parent_id (-1, -4, …): the ancestors table,
|
|
99
|
+
// read in chunked `IN (…)` batches once.
|
|
100
|
+
// Sort IDs in county → region → country order so one pass groups the rows.
|
|
102
101
|
const ancestorsByID = new Map<number, number[]>()
|
|
103
102
|
|
|
104
103
|
try {
|
|
@@ -139,12 +138,10 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
139
138
|
|
|
140
139
|
if (!row) return []
|
|
141
140
|
|
|
142
|
-
// If parent_id is a sentinel (≤ 0), use ancestors table.
|
|
143
141
|
if (row.parent_id <= 0) {
|
|
144
142
|
return (ancestorsByID.get(id) ?? []).filter((ancestorID) => ancestorID !== id)
|
|
145
143
|
}
|
|
146
144
|
|
|
147
|
-
// Normal case: walk parent_id chain.
|
|
148
145
|
const chain: number[] = []
|
|
149
146
|
let current = row.parent_id
|
|
150
147
|
const seen = new Set<number>([id])
|
|
@@ -172,13 +169,13 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
172
169
|
return chain
|
|
173
170
|
}
|
|
174
171
|
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
172
|
+
// Load both scores (the two-score split).
|
|
173
|
+
// Referential is always population-anchored and never read out of a legacy
|
|
174
|
+
// `place_importance` column, because a legacy row that got a Wikipedia score overwrote
|
|
175
|
+
// whatever population would have said and the two are indistinguishable afterwards.
|
|
176
|
+
// Encyclopedic importance remains available to consumers and is never handed to the decoder.
|
|
177
|
+
// `loadImportanceSplit` handles all four schema generations.
|
|
178
|
+
// Provenance records the source so the artifact identifies the schema it read.
|
|
182
179
|
progress("importance", "Loading referential + encyclopedic scores")
|
|
183
180
|
const split = loadImportanceSplit(db)
|
|
184
181
|
|
|
@@ -189,7 +186,6 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
189
186
|
")"
|
|
190
187
|
)
|
|
191
188
|
|
|
192
|
-
// Phase 4: Load names for matching places.
|
|
193
189
|
progress("names", "Loading name variants")
|
|
194
190
|
const placeIDs = sprRows.map((r) => r.id)
|
|
195
191
|
const namesByPlace = new Map<number, string[]>()
|
|
@@ -223,12 +219,12 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
223
219
|
|
|
224
220
|
progress("names", `Loaded names for ${namesByPlace.size} places`)
|
|
225
221
|
|
|
226
|
-
// Phase 5: Build the trie.
|
|
227
222
|
progress("trie", "Building trie")
|
|
228
223
|
const nodes: FSTNode[] = [{ edges: new Map(), places: [] }]
|
|
229
224
|
|
|
230
|
-
// Degenerate-surface curation (see BuildFSTOpts.excludeSurfaces).
|
|
231
|
-
//
|
|
225
|
+
// Degenerate-surface curation (see BuildFSTOpts.excludeSurfaces).
|
|
226
|
+
// Applied to the whole normalized surface only.
|
|
227
|
+
// A multi-token name containing a function word ("los angeles") is never affected.
|
|
232
228
|
const excludeSurfaces = opts.excludeSurfaces
|
|
233
229
|
const excludeAllTokensOf = opts.excludeAllTokensOf
|
|
234
230
|
let excludedCount = 0
|
|
@@ -238,14 +234,15 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
238
234
|
|
|
239
235
|
if (excludeSurfaces?.has(tokens.join(" "))) return true
|
|
240
236
|
|
|
241
|
-
if (excludeAllTokensOf
|
|
237
|
+
if (excludeAllTokensOf && tokens.every((t) => excludeAllTokensOf.has(t))) return true
|
|
242
238
|
|
|
243
239
|
return false
|
|
244
240
|
}
|
|
245
241
|
|
|
246
|
-
// Surface-ambiguity classes
|
|
247
|
-
//
|
|
248
|
-
//
|
|
242
|
+
// Surface-ambiguity classes are per-surface facts, so clone the entry for each
|
|
243
|
+
// insertion and attach that surface's count.
|
|
244
|
+
// The same place under "nyc" and "new york city" records a separate ambiguity count for each surface.
|
|
245
|
+
// An absent map means entries have no count for back-compat bytes.
|
|
249
246
|
const surfaceCountryCounts = opts.surfaceCountryCounts
|
|
250
247
|
|
|
251
248
|
function insertName(tokens: string[], entry: PlaceEntry): boolean {
|
|
@@ -272,11 +269,10 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
272
269
|
stateID = next
|
|
273
270
|
}
|
|
274
271
|
|
|
275
|
-
// Deduplicate: don't add the same wofID twice at the same state.
|
|
276
272
|
const existing = nodes[stateID]!.places
|
|
277
273
|
|
|
278
274
|
if (!existing.some((p) => p.wofID === entry.wofID && p.placetype === entry.placetype)) {
|
|
279
|
-
if (surfaceCountryCounts
|
|
275
|
+
if (surfaceCountryCounts) {
|
|
280
276
|
const count = surfaceCountryCounts.get(tokens.join(" "))
|
|
281
277
|
existing.push({ ...entry, crossCountryBranches: Math.min(count ?? 1, 255) })
|
|
282
278
|
} else {
|
|
@@ -300,21 +296,20 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
300
296
|
name: row.name,
|
|
301
297
|
parentChain,
|
|
302
298
|
referential: split.referential.get(row.id) ?? 0,
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
|
|
299
|
+
// A place with no Wikipedia article is `null` rather than a zero.
|
|
300
|
+
// The serializer's per-place presence bit reads `!== null`.
|
|
301
|
+
encyclopedic: encyclopedic ?? null,
|
|
306
302
|
lat: row.latitude,
|
|
307
303
|
lon: row.longitude,
|
|
304
|
+
crossCountryBranches: null,
|
|
308
305
|
}
|
|
309
306
|
|
|
310
|
-
// Insert the primary name from spr.
|
|
311
307
|
const primaryTokens = normalizeTokens(row.name)
|
|
312
308
|
|
|
313
309
|
if (insertName(primaryTokens, entry)) {
|
|
314
310
|
insertCount++
|
|
315
311
|
}
|
|
316
312
|
|
|
317
|
-
// Insert alt names from the names table.
|
|
318
313
|
const altNames = namesByPlace.get(row.id) ?? []
|
|
319
314
|
|
|
320
315
|
for (const altName of altNames) {
|
|
@@ -336,12 +331,12 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
336
331
|
const edgeCount = nodes.reduce((sum, n) => sum + n.edges.size, 0)
|
|
337
332
|
const matcher = FSTMatcher.fromNodes(nodes)
|
|
338
333
|
|
|
339
|
-
// The build stamp
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
// `sourceIdentity` lets a caller that already knows the digest
|
|
344
|
-
// is not a file at all
|
|
334
|
+
// The build stamp.
|
|
335
|
+
// `sourceDB` by itself cannot tell a reader whether this artifact matches the database
|
|
336
|
+
// at that path, because the admin database is sealed and replaced by a rebuild
|
|
337
|
+
// so the path is constant across every generation.
|
|
338
|
+
// `sourceIdentity` lets a caller that already knows the digest, or is building
|
|
339
|
+
// from something that is not a file at all, supply it instead.
|
|
345
340
|
progress("stamp", `Reading source identity for ${dbPath}`)
|
|
346
341
|
const source = opts.sourceIdentity ?? (await readWOFSourceIdentity(dbPath))
|
|
347
342
|
|
|
@@ -358,9 +353,10 @@ export async function buildFSTFromWOF(opts: BuildFSTOpts): Promise<{
|
|
|
358
353
|
sourceDB: dbPath,
|
|
359
354
|
sourceDBMD5: source.md5,
|
|
360
355
|
sourceDBBytes: source.bytes,
|
|
361
|
-
|
|
356
|
+
modelCardVersion: null,
|
|
357
|
+
...(excludeSurfaces || excludeAllTokensOf
|
|
362
358
|
? { exclusionPolicy: opts.exclusionPolicy ?? "unspecified", excludedInsertions: excludedCount }
|
|
363
|
-
: {}),
|
|
359
|
+
: { exclusionPolicy: null, excludedInsertions: null }),
|
|
364
360
|
}
|
|
365
361
|
|
|
366
362
|
return {
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
6
|
* Browser-compatible FST deserializer. Uses DataView + TextDecoder instead of Node's Buffer so the
|
|
7
|
-
* same binary format
|
|
7
|
+
* same binary format loads in the browser through fetch(url).then(r => r.arrayBuffer()).
|
|
8
8
|
*
|
|
9
|
-
* This is a read-only counterpart to fst-serialize.ts
|
|
10
|
-
* build-time operation
|
|
9
|
+
* This is a read-only counterpart to fst-serialize.ts. Serialization stays Node-only because it is
|
|
10
|
+
* a build-time operation.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { tryParsingJSON } from "@mailwoman/core/json"
|
|
@@ -56,7 +56,7 @@ export function deserializeFSTWeb(input: ArrayBuffer | Uint8Array): FSTMatcher {
|
|
|
56
56
|
|
|
57
57
|
const isV2 = version >= 2
|
|
58
58
|
const isSplit = version >= VERSION_TWO_SCORE_SPLIT
|
|
59
|
-
// flags bit0 (
|
|
59
|
+
// flags bit0 (mirrors fst-serialize.ts): place rows include surface-ambiguity data.
|
|
60
60
|
const hasAmbiguity = (view.getUint16(6, true) & 1) === 1
|
|
61
61
|
|
|
62
62
|
const stateCount = view.getUint32(8, true)
|
|
@@ -67,7 +67,6 @@ export function deserializeFSTWeb(input: ArrayBuffer | Uint8Array): FSTMatcher {
|
|
|
67
67
|
|
|
68
68
|
let pos = HEADER_SIZE
|
|
69
69
|
|
|
70
|
-
// Decode the interned string table.
|
|
71
70
|
const strOffsets = new Uint32Array(stringCount + 1)
|
|
72
71
|
|
|
73
72
|
for (let i = 0; i <= stringCount; i++) {
|
|
@@ -86,9 +85,8 @@ export function deserializeFSTWeb(input: ArrayBuffer | Uint8Array): FSTMatcher {
|
|
|
86
85
|
|
|
87
86
|
pos += stringBytes
|
|
88
87
|
|
|
89
|
-
// Decode the state table and its transitions.
|
|
90
88
|
const stateEntrySize = version >= VERSION_WIDE_STATE_COUNTERS ? WIDE_STATE_ENTRY_SIZE : NARROW_STATE_ENTRY_SIZE
|
|
91
|
-
// v5 grew the place entry by the encyclopedic float
|
|
89
|
+
// v5 grew the place entry by the encyclopedic float. v4-and-below files are read at the old stride.
|
|
92
90
|
const placeEntrySize = isSplit ? SPLIT_PLACE_ENTRY_SIZE : LEGACY_PLACE_ENTRY_SIZE
|
|
93
91
|
const stateTableStart = pos
|
|
94
92
|
const edgeTableStart = stateTableStart + stateCount * stateEntrySize
|
|
@@ -127,8 +125,9 @@ export function deserializeFSTWeb(input: ArrayBuffer | Uint8Array): FSTMatcher {
|
|
|
127
125
|
parentChain.push(view.getUint32(pp + 24 + ci * 4, true))
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
// v1 stored a raw population u32 here
|
|
131
|
-
//
|
|
128
|
+
// v1 stored a raw population u32 here. v2-v4 stored the conflated `importance`
|
|
129
|
+
// float. v5 stored the referential score.
|
|
130
|
+
// The Node deserializer explains why a v1 value is genuinely referential.
|
|
132
131
|
const referential = isV2
|
|
133
132
|
? view.getFloat32(pp + 12, true)
|
|
134
133
|
: Math.min(1, Math.log2(1 + view.getUint32(pp + 12, true) / 1000) / 14)
|
|
@@ -144,8 +143,8 @@ export function deserializeFSTWeb(input: ArrayBuffer | Uint8Array): FSTMatcher {
|
|
|
144
143
|
lat: view.getFloat32(pp + 16, true),
|
|
145
144
|
lon: view.getFloat32(pp + 20, true),
|
|
146
145
|
parentChain,
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
crossCountryBranches: hasAmbiguity ? view.getUint8(pp + 6) : null,
|
|
147
|
+
encyclopedic: hasEncyclopedic ? view.getFloat32(pp + ENCYCLOPEDIC_OFFSET, true) : null,
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
|
|
@@ -155,25 +154,25 @@ export function deserializeFSTWeb(input: ArrayBuffer | Uint8Array): FSTMatcher {
|
|
|
155
154
|
return FSTMatcher.fromNodes(nodes)
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
export function readFSTProvenanceWeb(input: ArrayBuffer | Uint8Array): FSTProvenance |
|
|
157
|
+
export function readFSTProvenanceWeb(input: ArrayBuffer | Uint8Array): FSTProvenance | null {
|
|
159
158
|
const bytes = input instanceof ArrayBuffer ? new Uint8Array(input) : input
|
|
160
159
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
|
161
160
|
const decoder = new TextDecoder("utf-8")
|
|
162
161
|
|
|
163
|
-
if (bytes.byteLength < HEADER_SIZE) return
|
|
162
|
+
if (bytes.byteLength < HEADER_SIZE) return null
|
|
164
163
|
const version = view.getUint16(4, true)
|
|
165
164
|
|
|
166
|
-
if (version < VERSION_WITH_METADATA) return
|
|
165
|
+
if (version < VERSION_WITH_METADATA) return null
|
|
167
166
|
const provenanceOffset = view.getUint32(28, true)
|
|
168
167
|
|
|
169
|
-
if (provenanceOffset === 0 || provenanceOffset >= bytes.byteLength) return
|
|
168
|
+
if (provenanceOffset === 0 || provenanceOffset >= bytes.byteLength) return null
|
|
170
169
|
|
|
171
170
|
try {
|
|
172
171
|
const jsonLen = view.getUint32(provenanceOffset, true)
|
|
173
172
|
const jsonStr = decoder.decode(bytes.subarray(provenanceOffset + 4, provenanceOffset + 4 + jsonLen))
|
|
174
173
|
|
|
175
|
-
return tryParsingJSON<FSTProvenance>(jsonStr) ??
|
|
174
|
+
return tryParsingJSON<FSTProvenance>(jsonStr) ?? null
|
|
176
175
|
} catch {
|
|
177
|
-
return
|
|
176
|
+
return null
|
|
178
177
|
}
|
|
179
178
|
}
|
package/lib/fst/format.ts
CHANGED
|
@@ -4,26 +4,33 @@
|
|
|
4
4
|
* @author Teffen Ellis, et al.
|
|
5
5
|
*
|
|
6
6
|
* The FST binary-format constants, shared by the Node serializer/deserializer (`fst-serialize.ts`)
|
|
7
|
-
* and the browser deserializer (`fst-deserialize-web.ts`).
|
|
8
|
-
* module scope
|
|
7
|
+
* and the browser deserializer (`fst-deserialize-web.ts`). This module stays platform-free.
|
|
8
|
+
* It uses no Buffer at module scope. Both runtimes convert {@link FST_MAGIC_BYTES} themselves.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type { PlacetypeID } from "#fst/types"
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Format version this tree
|
|
15
|
-
* an older artifact format-stale without re-typing the number
|
|
16
|
-
* see `fst-freshness.ts`).
|
|
14
|
+
* Format version this tree writes and the maximum either deserializer accepts, published
|
|
15
|
+
* so a freshness guard can call an older artifact format-stale without re-typing the number
|
|
16
|
+
* (mirrors `REQUIRED_PAIR_INDEX_SCHEMA`'s role for PIX1 — see `fst-freshness.ts`).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* One constant for the writer and both readers, deliberately.
|
|
19
|
+
* The browser reader once kept a separate `MAX_VERSION` from the layout branches.
|
|
20
|
+
*
|
|
21
|
+
* It drifted twice.
|
|
22
|
+
* It stayed at 2 after the v4 wide-state layout shipped and rejected every real artifact.
|
|
23
|
+
*
|
|
24
|
+
* It later stayed at 4 through the v5 two-score split until someone updated it by hand.
|
|
25
|
+
*
|
|
26
|
+
* A check that is the writer's version cannot drift from it.
|
|
22
27
|
*/
|
|
23
28
|
export const FST_FORMAT_VERSION = 5
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
|
-
* Fixed header size in bytes
|
|
31
|
+
* Fixed header size in bytes.
|
|
32
|
+
*
|
|
33
|
+
* It stores the magic and version, followed by section offsets.
|
|
27
34
|
*/
|
|
28
35
|
export const HEADER_SIZE = 32
|
|
29
36
|
|
|
@@ -33,8 +40,10 @@ export const HEADER_SIZE = 32
|
|
|
33
40
|
export const EDGE_ENTRY_SIZE = 8
|
|
34
41
|
|
|
35
42
|
/**
|
|
36
|
-
* Format version that widened the per-state edge and place counters from 16 to 32 bits,
|
|
37
|
-
*
|
|
43
|
+
* Format version that widened the per-state edge and place counters from 16 to 32 bits,
|
|
44
|
+
* growing the state entry from 12 to 16 bytes.
|
|
45
|
+
*
|
|
46
|
+
* Readers branch on it to stay backward-compatible with v2/v3 files.
|
|
38
47
|
*/
|
|
39
48
|
export const VERSION_WIDE_STATE_COUNTERS = 4
|
|
40
49
|
|
|
@@ -49,14 +58,15 @@ export const WIDE_STATE_ENTRY_SIZE = 16
|
|
|
49
58
|
export const NARROW_STATE_ENTRY_SIZE = 12
|
|
50
59
|
|
|
51
60
|
/**
|
|
52
|
-
* First format version carrying the trailing metadata block
|
|
61
|
+
* First format version carrying the trailing metadata block.
|
|
62
|
+
* Older files simply have none.
|
|
53
63
|
*/
|
|
54
64
|
export const VERSION_WITH_METADATA = 3
|
|
55
65
|
|
|
56
66
|
/**
|
|
57
|
-
* Format version that split the single `importance` float into `referential` +
|
|
58
|
-
* growing the place entry from 56 to 60 bytes
|
|
59
|
-
* {@link PLACE_FLAG_HAS_ENCYCLOPEDIC}.
|
|
67
|
+
* Format version that split the single `importance` float into `referential` +
|
|
68
|
+
* `encyclopedic` (ROAD_TO_V9 §2 R1), growing the place entry from 56 to 60 bytes
|
|
69
|
+
* and claiming the previously-reserved `pp+7` byte as {@link PLACE_FLAG_HAS_ENCYCLOPEDIC}.
|
|
60
70
|
*/
|
|
61
71
|
export const VERSION_TWO_SCORE_SPLIT = 5
|
|
62
72
|
|
|
@@ -71,25 +81,33 @@ export const SPLIT_PLACE_ENTRY_SIZE = 60
|
|
|
71
81
|
export const LEGACY_PLACE_ENTRY_SIZE = 56
|
|
72
82
|
|
|
73
83
|
/**
|
|
74
|
-
* Byte offset of the encyclopedic float inside a v5 place entry — immediately
|
|
84
|
+
* Byte offset of the encyclopedic float inside a v5 place entry — immediately
|
|
85
|
+
* after the 8-slot parent chain.
|
|
75
86
|
*/
|
|
76
87
|
export const ENCYCLOPEDIC_OFFSET = 56
|
|
77
88
|
|
|
78
89
|
/**
|
|
79
|
-
* `placeFlags` bit 0 (byte `pp+7`, v5+): this place
|
|
80
|
-
*
|
|
81
|
-
*
|
|
90
|
+
* `placeFlags` bit 0 (byte `pp+7`, v5+): this place has an encyclopedic score.
|
|
91
|
+
*
|
|
92
|
+
* Per-place rather than per-file because absence is the common case — roughly 89% of
|
|
93
|
+
* the 2026-08-05 gazetteer has no Wikipedia article — and a file-level flag would
|
|
94
|
+
* force every one of those rows to claim a 0 it never had.
|
|
82
95
|
*/
|
|
83
96
|
export const PLACE_FLAG_HAS_ENCYCLOPEDIC = 1
|
|
84
97
|
|
|
85
98
|
/**
|
|
86
|
-
* File magic, "FST\0" as bytes.
|
|
99
|
+
* File magic, "FST\0" as bytes.
|
|
100
|
+
*
|
|
101
|
+
* A reader rejects anything not starting with these four bytes before parsing further.
|
|
87
102
|
*/
|
|
88
103
|
export const FST_MAGIC_BYTES: readonly number[] = [0x46, 0x53, 0x54, 0x00]
|
|
89
104
|
|
|
90
105
|
/**
|
|
91
|
-
* Placetypes in hierarchy order, largest first.
|
|
92
|
-
*
|
|
106
|
+
* Placetypes in hierarchy order, largest first.
|
|
107
|
+
*
|
|
108
|
+
* The writer stores each placetype's index in a place entry.
|
|
109
|
+
* A different array order invalidates every existing file.
|
|
110
|
+
* Append entries and bump the version.
|
|
93
111
|
*/
|
|
94
112
|
export const PLACETYPE_ORDER: readonly PlacetypeID[] = [
|
|
95
113
|
"country",
|