@mailwoman/resolver-wof-sqlite 9.1.0 → 9.3.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.
Files changed (501) hide show
  1. package/README.md +36 -20
  2. package/lib/address/index.ts +9 -0
  3. package/{address-point-interpolation.ts → lib/address/point-interpolation.ts} +40 -28
  4. package/{address-point-schema.ts → lib/address/point-schema.ts} +34 -8
  5. package/lib/address/point.ts +280 -0
  6. package/{ancestry-backfill.ts → lib/ancestry/backfill.ts} +14 -19
  7. package/{ancestry.ts → lib/ancestry/index.ts} +13 -8
  8. package/{build-candidate.ts → lib/build-candidate.ts} +243 -199
  9. package/{build-slim.ts → lib/build-slim.ts} +153 -168
  10. package/lib/candidate/alias-bags.ts +56 -0
  11. package/lib/candidate/ancestors-sidecar.ts +204 -0
  12. package/lib/candidate/country-display-names.ts +79 -0
  13. package/lib/candidate/extract-fold.ts +138 -0
  14. package/lib/candidate/name-roles.ts +238 -0
  15. package/lib/candidate/own-name.ts +146 -0
  16. package/lib/candidate/place-attrs.ts +44 -0
  17. package/lib/candidate-ancestors-schema.ts +195 -0
  18. package/{candidate-fts.ts → lib/candidate-fts.ts} +7 -5
  19. package/{candidate-importance.ts → lib/candidate-importance.ts} +54 -57
  20. package/lib/candidate-lookup.ts +976 -0
  21. package/{candidate-schema.ts → lib/candidate-schema.ts} +34 -6
  22. package/lib/candidate-scoring.ts +261 -0
  23. package/lib/capital-schema.ts +89 -0
  24. package/lib/capitals.ts +148 -0
  25. package/{coincident-roles.ts → lib/coincident-roles.ts} +75 -19
  26. package/{convention.ts → lib/convention/index.ts} +5 -5
  27. package/lib/convention/schema.ts +72 -0
  28. package/{coverage-manifest-schema.ts → lib/coverage-manifest-schema.ts} +15 -16
  29. package/lib/currency-backfill.ts +334 -0
  30. package/lib/env.ts +50 -0
  31. package/lib/exact-match.ts +113 -0
  32. package/{sharding.ts → lib/extracts.ts} +63 -60
  33. package/lib/fst/autocomplete.ts +176 -0
  34. package/{fst-builder.ts → lib/fst/builder.ts} +30 -27
  35. package/{fst-deserialize-web.ts → lib/fst/deserialize-web.ts} +27 -87
  36. package/lib/fst/format.ts +106 -0
  37. package/{fst-freshness.ts → lib/fst/freshness.ts} +42 -75
  38. package/lib/fst/index.ts +14 -0
  39. package/{fst-matcher.ts → lib/fst/matcher.ts} +1 -1
  40. package/{fst-serialize.ts → lib/fst/serialize.ts} +37 -115
  41. package/{fst-types.ts → lib/fst/types.ts} +4 -2
  42. package/{fts.ts → lib/fts/index.ts} +28 -23
  43. package/{fts-query.ts → lib/fts/query.ts} +2 -2
  44. package/{geonames-aliases.ts → lib/geonames/aliases.ts} +13 -13
  45. package/lib/geonames/index.ts +8 -0
  46. package/{geonames-postal.ts → lib/geonames/postal.ts} +16 -15
  47. package/{index.ts → lib/index.ts} +52 -48
  48. package/{interpolation.ts → lib/interpolation.ts} +137 -41
  49. package/lib/lookup.ts +861 -0
  50. package/{name-score.ts → lib/name-score.ts} +6 -4
  51. package/lib/nsul/index.ts +8 -0
  52. package/lib/nsul/lookup.ts +144 -0
  53. package/lib/nsul/schema.ts +130 -0
  54. package/{place-importance-schema.ts → lib/place-importance-schema.ts} +70 -22
  55. package/lib/poi/index.ts +8 -0
  56. package/{poi-lookup.ts → lib/poi/lookup.ts} +32 -39
  57. package/{poi-schema.ts → lib/poi/schema.ts} +10 -6
  58. package/lib/polygon-schema.ts +47 -0
  59. package/{postal-city-alias-lookup.ts → lib/postal/city-alias-lookup.ts} +15 -21
  60. package/{postal-city-candidate-schema.ts → lib/postal/city-candidate-schema.ts} +4 -2
  61. package/lib/postal/index.ts +9 -0
  62. package/{postcode-point-lookup.ts → lib/postcode-point-lookup.ts} +17 -15
  63. package/lib/primary-preference.ts +226 -0
  64. package/lib/proximity-rerank.ts +120 -0
  65. package/{ranking-weights.ts → lib/ranking-weights.ts} +30 -4
  66. package/lib/region-keys.ts +144 -0
  67. package/{reverse.ts → lib/reverse.ts} +45 -56
  68. package/{schema.ts → lib/schema.ts} +11 -1
  69. package/lib/search-fetch.ts +257 -0
  70. package/{sqlite-convention-source.ts → lib/sqlite-convention-source.ts} +9 -10
  71. package/lib/sqlite-utils.ts +83 -0
  72. package/{street-centroid-schema.ts → lib/street/centroid-schema.ts} +12 -6
  73. package/{street-centroid.ts → lib/street/centroid.ts} +26 -28
  74. package/lib/street/index.ts +13 -0
  75. package/{street-morphology-fst-builder.ts → lib/street/morphology-fst-builder.ts} +24 -14
  76. package/{street-morphology-fst-loader.ts → lib/street/morphology-fst-loader.ts} +14 -12
  77. package/{street-name-lookup.ts → lib/street/name-lookup.ts} +14 -30
  78. package/lib/street/normalize.ts +572 -0
  79. package/{street-segment-schema.ts → lib/street/segment-schema.ts} +13 -8
  80. package/{types.ts → lib/types.ts} +49 -9
  81. package/{unified-schema.ts → lib/unified-schema.ts} +21 -25
  82. package/lib/uprn/existence.ts +84 -0
  83. package/lib/uprn/index.ts +9 -0
  84. package/lib/uprn/lookup.ts +206 -0
  85. package/lib/uprn/schema.ts +124 -0
  86. package/lib/weights-overlay-linker.ts +878 -0
  87. package/out/address/index.d.ts +9 -0
  88. package/out/address/index.d.ts.map +1 -0
  89. package/out/address/index.js +9 -0
  90. package/out/address/index.js.map +1 -0
  91. package/out/{address-point-interpolation.d.ts → address/point-interpolation.d.ts} +11 -10
  92. package/out/address/point-interpolation.d.ts.map +1 -0
  93. package/out/{address-point-interpolation.js → address/point-interpolation.js} +29 -23
  94. package/out/address/point-interpolation.js.map +1 -0
  95. package/out/{address-point-schema.d.ts → address/point-schema.d.ts} +30 -10
  96. package/out/address/point-schema.d.ts.map +1 -0
  97. package/out/{address-point-schema.js → address/point-schema.js} +7 -3
  98. package/out/address/point-schema.js.map +1 -0
  99. package/out/{address-point.d.ts → address/point.d.ts} +16 -8
  100. package/out/address/point.d.ts.map +1 -0
  101. package/out/address/point.js +191 -0
  102. package/out/address/point.js.map +1 -0
  103. package/out/{ancestry-backfill.d.ts → ancestry/backfill.d.ts} +7 -5
  104. package/out/ancestry/backfill.d.ts.map +1 -0
  105. package/out/{ancestry-backfill.js → ancestry/backfill.js} +12 -16
  106. package/out/ancestry/backfill.js.map +1 -0
  107. package/out/{ancestry.d.ts → ancestry/index.d.ts} +6 -5
  108. package/out/ancestry/index.d.ts.map +1 -0
  109. package/out/{ancestry.js → ancestry/index.js} +7 -7
  110. package/out/ancestry/index.js.map +1 -0
  111. package/out/build-candidate.d.ts +88 -7
  112. package/out/build-candidate.d.ts.map +1 -1
  113. package/out/build-candidate.js +145 -149
  114. package/out/build-candidate.js.map +1 -1
  115. package/out/build-slim.d.ts +5 -5
  116. package/out/build-slim.d.ts.map +1 -1
  117. package/out/build-slim.js +127 -142
  118. package/out/build-slim.js.map +1 -1
  119. package/out/candidate/alias-bags.d.ts +19 -0
  120. package/out/candidate/alias-bags.d.ts.map +1 -0
  121. package/out/candidate/alias-bags.js +39 -0
  122. package/out/candidate/alias-bags.js.map +1 -0
  123. package/out/candidate/ancestors-sidecar.d.ts +32 -0
  124. package/out/candidate/ancestors-sidecar.d.ts.map +1 -0
  125. package/out/candidate/ancestors-sidecar.js +140 -0
  126. package/out/candidate/ancestors-sidecar.js.map +1 -0
  127. package/out/candidate/country-display-names.d.ts +35 -0
  128. package/out/candidate/country-display-names.d.ts.map +1 -0
  129. package/out/candidate/country-display-names.js +59 -0
  130. package/out/candidate/country-display-names.js.map +1 -0
  131. package/out/candidate/extract-fold.d.ts +32 -0
  132. package/out/candidate/extract-fold.d.ts.map +1 -0
  133. package/out/candidate/extract-fold.js +104 -0
  134. package/out/candidate/extract-fold.js.map +1 -0
  135. package/out/candidate/name-roles.d.ts +57 -0
  136. package/out/candidate/name-roles.d.ts.map +1 -0
  137. package/out/candidate/name-roles.js +166 -0
  138. package/out/candidate/name-roles.js.map +1 -0
  139. package/out/candidate/own-name.d.ts +50 -0
  140. package/out/candidate/own-name.d.ts.map +1 -0
  141. package/out/candidate/own-name.js +132 -0
  142. package/out/candidate/own-name.js.map +1 -0
  143. package/out/candidate/place-attrs.d.ts +43 -0
  144. package/out/candidate/place-attrs.d.ts.map +1 -0
  145. package/out/candidate/place-attrs.js +15 -0
  146. package/out/candidate/place-attrs.js.map +1 -0
  147. package/out/candidate-ancestors-schema.d.ts +150 -0
  148. package/out/candidate-ancestors-schema.d.ts.map +1 -0
  149. package/out/candidate-ancestors-schema.js +123 -0
  150. package/out/candidate-ancestors-schema.js.map +1 -0
  151. package/out/candidate-fts.d.ts +7 -5
  152. package/out/candidate-fts.d.ts.map +1 -1
  153. package/out/candidate-fts.js +5 -3
  154. package/out/candidate-fts.js.map +1 -1
  155. package/out/candidate-importance.d.ts +16 -16
  156. package/out/candidate-importance.d.ts.map +1 -1
  157. package/out/candidate-importance.js +47 -52
  158. package/out/candidate-importance.js.map +1 -1
  159. package/out/candidate-lookup.d.ts +31 -52
  160. package/out/candidate-lookup.d.ts.map +1 -1
  161. package/out/candidate-lookup.js +380 -172
  162. package/out/candidate-lookup.js.map +1 -1
  163. package/out/candidate-schema.d.ts +31 -7
  164. package/out/candidate-schema.d.ts.map +1 -1
  165. package/out/candidate-schema.js +3 -0
  166. package/out/candidate-schema.js.map +1 -1
  167. package/out/candidate-scoring.d.ts +34 -0
  168. package/out/candidate-scoring.d.ts.map +1 -0
  169. package/out/candidate-scoring.js +196 -0
  170. package/out/candidate-scoring.js.map +1 -0
  171. package/out/capital-schema.d.ts +51 -0
  172. package/out/capital-schema.d.ts.map +1 -0
  173. package/out/capital-schema.js +63 -0
  174. package/out/capital-schema.js.map +1 -0
  175. package/out/capitals.d.ts +69 -0
  176. package/out/capitals.d.ts.map +1 -0
  177. package/out/capitals.js +98 -0
  178. package/out/capitals.js.map +1 -0
  179. package/out/coincident-roles.d.ts +12 -4
  180. package/out/coincident-roles.d.ts.map +1 -1
  181. package/out/coincident-roles.js +43 -11
  182. package/out/coincident-roles.js.map +1 -1
  183. package/out/{convention.d.ts → convention/index.d.ts} +5 -5
  184. package/out/convention/index.d.ts.map +1 -0
  185. package/out/{convention.js → convention/index.js} +4 -4
  186. package/out/convention/index.js.map +1 -0
  187. package/out/convention/schema.d.ts +51 -0
  188. package/out/convention/schema.d.ts.map +1 -0
  189. package/out/convention/schema.js +34 -0
  190. package/out/convention/schema.js.map +1 -0
  191. package/out/coverage-manifest-schema.d.ts +8 -8
  192. package/out/coverage-manifest-schema.d.ts.map +1 -1
  193. package/out/coverage-manifest-schema.js +6 -10
  194. package/out/coverage-manifest-schema.js.map +1 -1
  195. package/out/currency-backfill.d.ts +90 -0
  196. package/out/currency-backfill.d.ts.map +1 -0
  197. package/out/currency-backfill.js +196 -0
  198. package/out/currency-backfill.js.map +1 -0
  199. package/out/env.d.ts +43 -0
  200. package/out/env.d.ts.map +1 -0
  201. package/out/env.js +48 -0
  202. package/out/env.js.map +1 -0
  203. package/out/exact-match.d.ts +25 -0
  204. package/out/exact-match.d.ts.map +1 -0
  205. package/out/exact-match.js +88 -0
  206. package/out/exact-match.js.map +1 -0
  207. package/out/extracts.d.ts +114 -0
  208. package/out/extracts.d.ts.map +1 -0
  209. package/out/{sharding.js → extracts.js} +38 -38
  210. package/out/extracts.js.map +1 -0
  211. package/out/{fst-autocomplete.d.ts → fst/autocomplete.d.ts} +13 -13
  212. package/out/fst/autocomplete.d.ts.map +1 -0
  213. package/out/fst/autocomplete.js +113 -0
  214. package/out/fst/autocomplete.js.map +1 -0
  215. package/out/{fst-builder.d.ts → fst/builder.d.ts} +5 -5
  216. package/out/fst/builder.d.ts.map +1 -0
  217. package/out/{fst-builder.js → fst/builder.js} +24 -24
  218. package/out/fst/builder.js.map +1 -0
  219. package/out/{fst-deserialize-web.d.ts → fst/deserialize-web.d.ts} +3 -3
  220. package/out/fst/deserialize-web.d.ts.map +1 -0
  221. package/out/{fst-deserialize-web.js → fst/deserialize-web.js} +10 -74
  222. package/out/fst/deserialize-web.js.map +1 -0
  223. package/out/fst/format.d.ts +80 -0
  224. package/out/fst/format.d.ts.map +1 -0
  225. package/out/fst/format.js +91 -0
  226. package/out/fst/format.js.map +1 -0
  227. package/out/{fst-freshness.d.ts → fst/freshness.d.ts} +11 -14
  228. package/out/fst/freshness.d.ts.map +1 -0
  229. package/out/{fst-freshness.js → fst/freshness.js} +42 -74
  230. package/out/fst/freshness.js.map +1 -0
  231. package/out/fst/index.d.ts +14 -0
  232. package/out/fst/index.d.ts.map +1 -0
  233. package/out/fst/index.js +14 -0
  234. package/out/fst/index.js.map +1 -0
  235. package/out/{fst-matcher.d.ts → fst/matcher.d.ts} +2 -2
  236. package/out/fst/matcher.d.ts.map +1 -0
  237. package/out/{fst-matcher.js → fst/matcher.js} +1 -1
  238. package/out/fst/matcher.js.map +1 -0
  239. package/out/{fst-serialize.d.ts → fst/serialize.d.ts} +5 -10
  240. package/out/fst/serialize.d.ts.map +1 -0
  241. package/out/{fst-serialize.js → fst/serialize.js} +18 -98
  242. package/out/fst/serialize.js.map +1 -0
  243. package/out/{fst-types.d.ts → fst/types.d.ts} +4 -3
  244. package/out/fst/types.d.ts.map +1 -0
  245. package/out/{fst-types.js → fst/types.js} +1 -1
  246. package/out/fst/types.js.map +1 -0
  247. package/out/{fts.d.ts → fts/index.d.ts} +20 -13
  248. package/out/fts/index.d.ts.map +1 -0
  249. package/out/{fts.js → fts/index.js} +20 -15
  250. package/out/fts/index.js.map +1 -0
  251. package/out/{fts-query.d.ts → fts/query.d.ts} +2 -2
  252. package/out/fts/query.d.ts.map +1 -0
  253. package/out/{fts-query.js → fts/query.js} +2 -2
  254. package/out/fts/query.js.map +1 -0
  255. package/out/{geonames-aliases.d.ts → geonames/aliases.d.ts} +8 -6
  256. package/out/geonames/aliases.d.ts.map +1 -0
  257. package/out/{geonames-aliases.js → geonames/aliases.js} +7 -7
  258. package/out/geonames/aliases.js.map +1 -0
  259. package/out/geonames/index.d.ts +8 -0
  260. package/out/geonames/index.d.ts.map +1 -0
  261. package/out/geonames/index.js +8 -0
  262. package/out/geonames/index.js.map +1 -0
  263. package/out/{geonames-postal.d.ts → geonames/postal.d.ts} +12 -10
  264. package/out/geonames/postal.d.ts.map +1 -0
  265. package/out/{geonames-postal.js → geonames/postal.js} +11 -11
  266. package/out/geonames/postal.js.map +1 -0
  267. package/out/index.d.ts +32 -31
  268. package/out/index.d.ts.map +1 -1
  269. package/out/index.js +24 -24
  270. package/out/index.js.map +1 -1
  271. package/out/interpolation.d.ts +18 -9
  272. package/out/interpolation.d.ts.map +1 -1
  273. package/out/interpolation.js +108 -36
  274. package/out/interpolation.js.map +1 -1
  275. package/out/lookup.d.ts +25 -25
  276. package/out/lookup.d.ts.map +1 -1
  277. package/out/lookup.js +174 -558
  278. package/out/lookup.js.map +1 -1
  279. package/out/name-score.d.ts +0 -10
  280. package/out/name-score.d.ts.map +1 -1
  281. package/out/name-score.js +6 -4
  282. package/out/name-score.js.map +1 -1
  283. package/out/nsul/index.d.ts +8 -0
  284. package/out/nsul/index.d.ts.map +1 -0
  285. package/out/nsul/index.js +8 -0
  286. package/out/nsul/index.js.map +1 -0
  287. package/out/nsul/lookup.d.ts +83 -0
  288. package/out/nsul/lookup.d.ts.map +1 -0
  289. package/out/nsul/lookup.js +80 -0
  290. package/out/nsul/lookup.js.map +1 -0
  291. package/out/nsul/schema.d.ts +100 -0
  292. package/out/nsul/schema.d.ts.map +1 -0
  293. package/out/nsul/schema.js +78 -0
  294. package/out/nsul/schema.js.map +1 -0
  295. package/out/place-importance-schema.d.ts +47 -10
  296. package/out/place-importance-schema.d.ts.map +1 -1
  297. package/out/place-importance-schema.js +56 -10
  298. package/out/place-importance-schema.js.map +1 -1
  299. package/out/poi/index.d.ts +8 -0
  300. package/out/poi/index.d.ts.map +1 -0
  301. package/out/poi/index.js +8 -0
  302. package/out/poi/index.js.map +1 -0
  303. package/out/{poi-lookup.d.ts → poi/lookup.d.ts} +8 -10
  304. package/out/poi/lookup.d.ts.map +1 -0
  305. package/out/{poi-lookup.js → poi/lookup.js} +24 -29
  306. package/out/poi/lookup.js.map +1 -0
  307. package/out/{poi-schema.d.ts → poi/schema.d.ts} +10 -6
  308. package/out/poi/schema.d.ts.map +1 -0
  309. package/out/{poi-schema.js → poi/schema.js} +1 -1
  310. package/out/poi/schema.js.map +1 -0
  311. package/out/polygon-schema.d.ts +37 -0
  312. package/out/polygon-schema.d.ts.map +1 -0
  313. package/out/polygon-schema.js +23 -0
  314. package/out/polygon-schema.js.map +1 -0
  315. package/out/{postal-city-alias-lookup.d.ts → postal/city-alias-lookup.d.ts} +7 -6
  316. package/out/postal/city-alias-lookup.d.ts.map +1 -0
  317. package/out/{postal-city-alias-lookup.js → postal/city-alias-lookup.js} +12 -16
  318. package/out/postal/city-alias-lookup.js.map +1 -0
  319. package/out/{postal-city-alias-schema.d.ts → postal/city-alias-schema.d.ts} +1 -1
  320. package/out/{postal-city-alias-schema.d.ts.map → postal/city-alias-schema.d.ts.map} +1 -1
  321. package/out/{postal-city-alias-schema.js → postal/city-alias-schema.js} +1 -1
  322. package/out/{postal-city-alias-schema.js.map → postal/city-alias-schema.js.map} +1 -1
  323. package/out/{postal-city-candidate-schema.d.ts → postal/city-candidate-schema.d.ts} +4 -3
  324. package/out/postal/city-candidate-schema.d.ts.map +1 -0
  325. package/out/{postal-city-candidate-schema.js → postal/city-candidate-schema.js} +2 -2
  326. package/out/{postal-city-candidate-schema.js.map → postal/city-candidate-schema.js.map} +1 -1
  327. package/out/postal/index.d.ts +9 -0
  328. package/out/postal/index.d.ts.map +1 -0
  329. package/out/postal/index.js +9 -0
  330. package/out/postal/index.js.map +1 -0
  331. package/out/postcode-point-lookup.d.ts +10 -10
  332. package/out/postcode-point-lookup.d.ts.map +1 -1
  333. package/out/postcode-point-lookup.js +13 -13
  334. package/out/postcode-point-lookup.js.map +1 -1
  335. package/out/primary-preference.d.ts +133 -0
  336. package/out/primary-preference.d.ts.map +1 -0
  337. package/out/primary-preference.js +146 -0
  338. package/out/primary-preference.js.map +1 -0
  339. package/out/proximity-rerank.d.ts +77 -0
  340. package/out/proximity-rerank.d.ts.map +1 -0
  341. package/out/proximity-rerank.js +86 -0
  342. package/out/proximity-rerank.js.map +1 -0
  343. package/out/ranking-weights.d.ts +15 -3
  344. package/out/ranking-weights.d.ts.map +1 -1
  345. package/out/ranking-weights.js +21 -3
  346. package/out/ranking-weights.js.map +1 -1
  347. package/out/region-keys.d.ts +47 -0
  348. package/out/region-keys.d.ts.map +1 -0
  349. package/out/region-keys.js +121 -0
  350. package/out/region-keys.js.map +1 -0
  351. package/out/reverse.d.ts +6 -6
  352. package/out/reverse.d.ts.map +1 -1
  353. package/out/reverse.js +23 -35
  354. package/out/reverse.js.map +1 -1
  355. package/out/schema.d.ts +10 -1
  356. package/out/schema.d.ts.map +1 -1
  357. package/out/schema.js.map +1 -1
  358. package/out/search-fetch.d.ts +59 -0
  359. package/out/search-fetch.d.ts.map +1 -0
  360. package/out/search-fetch.js +184 -0
  361. package/out/search-fetch.js.map +1 -0
  362. package/out/sqlite-convention-source.d.ts +7 -7
  363. package/out/sqlite-convention-source.d.ts.map +1 -1
  364. package/out/sqlite-convention-source.js +5 -5
  365. package/out/sqlite-convention-source.js.map +1 -1
  366. package/out/sqlite-utils.d.ts +24 -6
  367. package/out/sqlite-utils.d.ts.map +1 -1
  368. package/out/sqlite-utils.js +24 -7
  369. package/out/sqlite-utils.js.map +1 -1
  370. package/out/{street-centroid-schema.d.ts → street/centroid-schema.d.ts} +12 -7
  371. package/out/street/centroid-schema.d.ts.map +1 -0
  372. package/out/{street-centroid-schema.js → street/centroid-schema.js} +5 -5
  373. package/out/{street-centroid-schema.js.map → street/centroid-schema.js.map} +1 -1
  374. package/out/{street-centroid.d.ts → street/centroid.d.ts} +6 -6
  375. package/out/street/centroid.d.ts.map +1 -0
  376. package/out/{street-centroid.js → street/centroid.js} +18 -24
  377. package/out/street/centroid.js.map +1 -0
  378. package/out/street/index.d.ts +13 -0
  379. package/out/street/index.d.ts.map +1 -0
  380. package/out/street/index.js +13 -0
  381. package/out/street/index.js.map +1 -0
  382. package/out/{street-morphology-fst-builder.d.ts → street/morphology-fst-builder.d.ts} +4 -4
  383. package/out/street/morphology-fst-builder.d.ts.map +1 -0
  384. package/out/{street-morphology-fst-builder.js → street/morphology-fst-builder.js} +18 -13
  385. package/out/street/morphology-fst-builder.js.map +1 -0
  386. package/out/{street-morphology-fst-loader.d.ts → street/morphology-fst-loader.d.ts} +5 -5
  387. package/out/street/morphology-fst-loader.d.ts.map +1 -0
  388. package/out/{street-morphology-fst-loader.js → street/morphology-fst-loader.js} +11 -10
  389. package/out/street/morphology-fst-loader.js.map +1 -0
  390. package/out/{street-name-lookup.d.ts → street/name-lookup.d.ts} +4 -7
  391. package/out/street/name-lookup.d.ts.map +1 -0
  392. package/out/{street-name-lookup.js → street/name-lookup.js} +9 -23
  393. package/out/street/name-lookup.js.map +1 -0
  394. package/out/street/normalize.d.ts +179 -0
  395. package/out/street/normalize.d.ts.map +1 -0
  396. package/out/street/normalize.js +457 -0
  397. package/out/street/normalize.js.map +1 -0
  398. package/out/{street-segment-schema.d.ts → street/segment-schema.d.ts} +13 -9
  399. package/out/street/segment-schema.d.ts.map +1 -0
  400. package/out/{street-segment-schema.js → street/segment-schema.js} +4 -4
  401. package/out/{street-segment-schema.js.map → street/segment-schema.js.map} +1 -1
  402. package/out/types.d.ts +49 -9
  403. package/out/types.d.ts.map +1 -1
  404. package/out/types.js.map +1 -1
  405. package/out/unified-schema.d.ts +6 -5
  406. package/out/unified-schema.d.ts.map +1 -1
  407. package/out/unified-schema.js +16 -19
  408. package/out/unified-schema.js.map +1 -1
  409. package/out/uprn/existence.d.ts +53 -0
  410. package/out/uprn/existence.d.ts.map +1 -0
  411. package/out/uprn/existence.js +61 -0
  412. package/out/uprn/existence.js.map +1 -0
  413. package/out/uprn/index.d.ts +9 -0
  414. package/out/uprn/index.d.ts.map +1 -0
  415. package/out/uprn/index.js +9 -0
  416. package/out/uprn/index.js.map +1 -0
  417. package/out/uprn/lookup.d.ts +85 -0
  418. package/out/uprn/lookup.d.ts.map +1 -0
  419. package/out/uprn/lookup.js +149 -0
  420. package/out/uprn/lookup.js.map +1 -0
  421. package/out/uprn/schema.d.ts +93 -0
  422. package/out/uprn/schema.d.ts.map +1 -0
  423. package/out/uprn/schema.js +78 -0
  424. package/out/uprn/schema.js.map +1 -0
  425. package/out/weights-overlay-linker.d.ts +299 -0
  426. package/out/weights-overlay-linker.d.ts.map +1 -0
  427. package/out/weights-overlay-linker.js +511 -0
  428. package/out/weights-overlay-linker.js.map +1 -0
  429. package/package.json +622 -154
  430. package/address-point.ts +0 -125
  431. package/candidate-lookup.ts +0 -720
  432. package/fst-autocomplete.ts +0 -204
  433. package/geo.ts +0 -121
  434. package/lookup.ts +0 -1354
  435. package/out/address-point-interpolation.d.ts.map +0 -1
  436. package/out/address-point-interpolation.js.map +0 -1
  437. package/out/address-point-schema.d.ts.map +0 -1
  438. package/out/address-point-schema.js.map +0 -1
  439. package/out/address-point.d.ts.map +0 -1
  440. package/out/address-point.js +0 -84
  441. package/out/address-point.js.map +0 -1
  442. package/out/ancestry-backfill.d.ts.map +0 -1
  443. package/out/ancestry-backfill.js.map +0 -1
  444. package/out/ancestry.d.ts.map +0 -1
  445. package/out/ancestry.js.map +0 -1
  446. package/out/convention.d.ts.map +0 -1
  447. package/out/convention.js.map +0 -1
  448. package/out/fst-autocomplete.d.ts.map +0 -1
  449. package/out/fst-autocomplete.js +0 -130
  450. package/out/fst-autocomplete.js.map +0 -1
  451. package/out/fst-builder.d.ts.map +0 -1
  452. package/out/fst-builder.js.map +0 -1
  453. package/out/fst-deserialize-web.d.ts.map +0 -1
  454. package/out/fst-deserialize-web.js.map +0 -1
  455. package/out/fst-freshness.d.ts.map +0 -1
  456. package/out/fst-freshness.js.map +0 -1
  457. package/out/fst-matcher.d.ts.map +0 -1
  458. package/out/fst-matcher.js.map +0 -1
  459. package/out/fst-serialize.d.ts.map +0 -1
  460. package/out/fst-serialize.js.map +0 -1
  461. package/out/fst-types.d.ts.map +0 -1
  462. package/out/fst-types.js.map +0 -1
  463. package/out/fts-query.d.ts.map +0 -1
  464. package/out/fts-query.js.map +0 -1
  465. package/out/fts.d.ts.map +0 -1
  466. package/out/fts.js.map +0 -1
  467. package/out/geo.d.ts +0 -74
  468. package/out/geo.d.ts.map +0 -1
  469. package/out/geo.js +0 -71
  470. package/out/geo.js.map +0 -1
  471. package/out/geonames-aliases.d.ts.map +0 -1
  472. package/out/geonames-aliases.js.map +0 -1
  473. package/out/geonames-postal.d.ts.map +0 -1
  474. package/out/geonames-postal.js.map +0 -1
  475. package/out/poi-lookup.d.ts.map +0 -1
  476. package/out/poi-lookup.js.map +0 -1
  477. package/out/poi-schema.d.ts.map +0 -1
  478. package/out/poi-schema.js.map +0 -1
  479. package/out/postal-city-alias-lookup.d.ts.map +0 -1
  480. package/out/postal-city-alias-lookup.js.map +0 -1
  481. package/out/postal-city-candidate-schema.d.ts.map +0 -1
  482. package/out/sharding.d.ts +0 -114
  483. package/out/sharding.d.ts.map +0 -1
  484. package/out/sharding.js.map +0 -1
  485. package/out/street-centroid-schema.d.ts.map +0 -1
  486. package/out/street-centroid.d.ts.map +0 -1
  487. package/out/street-centroid.js.map +0 -1
  488. package/out/street-morphology-fst-builder.d.ts.map +0 -1
  489. package/out/street-morphology-fst-builder.js.map +0 -1
  490. package/out/street-morphology-fst-loader.d.ts.map +0 -1
  491. package/out/street-morphology-fst-loader.js.map +0 -1
  492. package/out/street-name-lookup.d.ts.map +0 -1
  493. package/out/street-name-lookup.js.map +0 -1
  494. package/out/street-normalize.d.ts +0 -95
  495. package/out/street-normalize.d.ts.map +0 -1
  496. package/out/street-normalize.js +0 -272
  497. package/out/street-normalize.js.map +0 -1
  498. package/out/street-segment-schema.d.ts.map +0 -1
  499. package/sqlite-utils.ts +0 -46
  500. package/street-normalize.ts +0 -318
  501. /package/{postal-city-alias-schema.ts → lib/postal/city-alias-schema.ts} +0 -0
@@ -1,272 +0,0 @@
1
- /**
2
- * @copyright Sister Software
3
- * @license AGPL-3.0
4
- * @author Teffen Ellis, et al.
5
- *
6
- * THE street normalizer for the address-point tier (#476). One function, used by BOTH the shard
7
- * builder (`scripts/build-address-point-shard.ts`) and the lookup tier (`address-point.ts`) —
8
- * never two implementations (the PLACETYPE_ORDER lesson: parallel copies silently corrupt).
9
- *
10
- * Normalization contract (deliberately aggressive — both sides apply the same function, so
11
- * collisions only need to be _consistent_, not linguistically perfect):
12
- *
13
- * 1. Lowercase, NFKD-fold diacritics, collapse whitespace, strip punctuation (periods, commas,
14
- * apostrophes).
15
- * 2. Expand USPS directional abbreviations at the FIRST and LAST token position (`n` → `north`, `se` →
16
- * `southeast`) — Overture sources abbreviate inconsistently.
17
- * 3. Canonicalize a trailing USPS street-type token via the codex suffix table to its canonical full
18
- * form (`st`/`str`/`street` → `street`).
19
- *
20
- * Numbered streets are left as digits (`5th` stays `5th`); a SPELLED ordinal before a street suffix
21
- * folds to its digit form (`tenth street` → `10th street`, #723) so the grid-city ordinal
22
- * cross-streets the source data spells with digits become reachable.
23
- */
24
- import { AbbreviationToDirectional, US_STREET_SUFFIX_LOOKUP } from "@mailwoman/codex/us";
25
- /**
26
- * Token count a street must exceed before its trailing pair is merged. At or below it the pair IS the whole street
27
- * name, and merging would leave nothing to match on.
28
- */
29
- const MIN_TOKENS_FOR_TAIL_MERGE = 3;
30
- /**
31
- * Spelled ordinal street names → their digit-ordinal form ("tenth" → "10th"), applied ONLY when a street-type suffix
32
- * follows (#723 admin-tail) — so the ordinal cross-streets common in grid cities ("Tenth Street", "Fifth Avenue") match
33
- * the shards' digit keys, WITHOUT rewriting ordinal-WORD names where the next token is not a suffix ("First National
34
- * Bank Rd" stays "first national …"). Digit-source shards are unaffected (a digit token isn't in this map), so the
35
- * existing keys need no rebuild; a future rebuild folds any spelled-source key the same way (the one-function
36
- * discipline).
37
- */
38
- const SPELLED_ORDINAL_TO_DIGIT = new Map([
39
- ["first", "1st"],
40
- ["second", "2nd"],
41
- ["third", "3rd"],
42
- ["fourth", "4th"],
43
- ["fifth", "5th"],
44
- ["sixth", "6th"],
45
- ["seventh", "7th"],
46
- ["eighth", "8th"],
47
- ["ninth", "9th"],
48
- ["tenth", "10th"],
49
- ["eleventh", "11th"],
50
- ["twelfth", "12th"],
51
- ["thirteenth", "13th"],
52
- ["fourteenth", "14th"],
53
- ["fifteenth", "15th"],
54
- ["sixteenth", "16th"],
55
- ["seventeenth", "17th"],
56
- ["eighteenth", "18th"],
57
- ["nineteenth", "19th"],
58
- ["twentieth", "20th"],
59
- ["thirtieth", "30th"],
60
- ["fortieth", "40th"],
61
- ["fiftieth", "50th"],
62
- ["sixtieth", "60th"],
63
- ["seventieth", "70th"],
64
- ["eightieth", "80th"],
65
- ["ninetieth", "90th"],
66
- ["hundredth", "100th"],
67
- ]);
68
- /**
69
- * Lowercase + diacritic-fold + punctuation strip + whitespace collapse.
70
- */
71
- function fold(input) {
72
- return input
73
- .normalize("NFKD")
74
- .replaceAll(/[̀-ͯ]/g, "")
75
- .toLowerCase()
76
- .replaceAll(/[.,'’]/g, "")
77
- .replaceAll(/\s+/g, " ")
78
- .trim();
79
- }
80
- /**
81
- * Normalize a street name for address-point keying. Same function at build time and lookup time — see module docstring
82
- * for the contract.
83
- */
84
- export function normalizeStreetForKey(street) {
85
- const tokens = fold(street).split(" ");
86
- if (!tokens.length)
87
- return "";
88
- // Spelled-ordinal street names → digit form when a street suffix follows ("Tenth Street" →
89
- // "10th street", #723). Gated on the next token being a suffix so ordinal-WORD names are untouched.
90
- for (let i = 0; i < tokens.length - 1; i++) {
91
- const digit = SPELLED_ORDINAL_TO_DIGIT.get(tokens[i]);
92
- if (digit && US_STREET_SUFFIX_LOOKUP.has(tokens[i + 1])) {
93
- tokens[i] = digit;
94
- }
95
- }
96
- // Directional expansion at the edges only ("N Main St" / "Main St N" — never interior
97
- // tokens, where "W" may be an initial in a person-named street). The codex expands
98
- // compounds to two words ("SE" → "SOUTH EAST"); we key on the spaceless form
99
- // ("southeast"), and also merge an already-written two-token pair ("South East …").
100
- const edgeDirectional = (raw) => AbbreviationToDirectional.get(raw.toUpperCase())?.toLowerCase().replace(" ", "");
101
- const mergePair = (a, b) => a && b && /^(north|south)$/.test(a) && /^(east|west)$/.test(b) ? a + b : undefined;
102
- const leadPair = mergePair(tokens[0], tokens[1]);
103
- if (leadPair && tokens.length > 2) {
104
- tokens.splice(0, 2, leadPair);
105
- }
106
- const first = edgeDirectional(tokens[0]);
107
- if (first && tokens.length > 1) {
108
- tokens[0] = first;
109
- }
110
- const tailPair = mergePair(tokens.at(-2), tokens.at(-1));
111
- if (tailPair && tokens.length > MIN_TOKENS_FOR_TAIL_MERGE) {
112
- tokens.splice(-2, 2, tailPair);
113
- }
114
- if (tokens.length > 2) {
115
- const last = edgeDirectional(tokens.at(-1));
116
- if (last) {
117
- tokens[tokens.length - 1] = last;
118
- }
119
- }
120
- // Street-type canonicalization via the codex table (lowercase keys, UPPER canonical
121
- // values). The suffix is usually the last token, but sits second-to-last when a trailing
122
- // directional follows ("Main St N") — check both positions, canonicalize the first hit.
123
- for (const at of [tokens.length - 1, tokens.length - 2]) {
124
- if (at < 1)
125
- continue; // never canonicalize the only/first token ("Street Road" exists)
126
- const canonical = US_STREET_SUFFIX_LOOKUP.get(tokens[at]);
127
- if (canonical) {
128
- tokens[at] = canonical.toLowerCase();
129
- break;
130
- }
131
- }
132
- return tokens.join(" ");
133
- }
134
- /**
135
- * French street-type abbreviations → canonical full form, applied per token after {@link fold}. French address types
136
- * LEAD the name ("Av. de…", "Bd …", "Pl. …") and "St"/"Ste" abbreviate Saint/Sainte inside names ("Rue St-Honoré" →
137
- * "rue saint honore"). fold() has already stripped the trailing period, so the keys are point-free ("av", "bd").
138
- */
139
- const FR_STREET_ABBREV = new Map([
140
- ["av", "avenue"],
141
- ["ave", "avenue"],
142
- ["bd", "boulevard"],
143
- ["bld", "boulevard"],
144
- ["bvd", "boulevard"],
145
- ["boul", "boulevard"],
146
- ["pl", "place"],
147
- ["imp", "impasse"],
148
- ["all", "allee"],
149
- ["ch", "chemin"],
150
- ["che", "chemin"],
151
- ["sq", "square"],
152
- ["pas", "passage"],
153
- ["fg", "faubourg"],
154
- ["fbg", "faubourg"],
155
- ["rte", "route"],
156
- ["st", "saint"],
157
- ["ste", "sainte"],
158
- ["sts", "saints"],
159
- ]);
160
- /**
161
- * Normalize a street name for the address-point key in a non-US locale. Same function build-side and probe-side (the
162
- * one-function discipline). US delegates to {@link normalizeStreetForKey}.
163
- *
164
- * - **en** — the shared English address-key pipeline (directionals + suffix aliases), currently identical to US.
165
- * - **fr** — fold + expand leading type abbreviations and Saint/Sainte (token map).
166
- * - **de** — fold + ß→ss + canonicalize the GLUED `-str(.)` suffix to `-strasse` ("Lindenstr." → "lindenstrasse",
167
- * "Lindenstraße" → "lindenstrasse"); an already-full "-strasse" is left intact.
168
- * - **nl** — fold + canonicalize the glued `-str` suffix to `-straat` ("Kerkstr." → "kerkstraat").
169
- */
170
- export function normalizeStreetForKeyLocale(street, locale) {
171
- if (locale === "us" || locale === "en")
172
- return normalizeStreetForKey(street);
173
- // Hyphen → space so a compound name keys the same whether the source or the query writes the
174
- // hyphen ("Champs-Élysées", "St-Honoré") or a space — both sides fold identically, so this is pure
175
- // robustness. It also splits a hyphenated abbreviation ("St-Honoré" → "st honore") into tokens the
176
- // per-locale type/Saint map can see.
177
- const tokens = fold(street).replaceAll("ß", "ss").replaceAll("-", " ").split(/\s+/).filter(Boolean);
178
- if (!tokens.length)
179
- return "";
180
- switch (locale) {
181
- case "fr":
182
- for (let i = 0; i < tokens.length; i++) {
183
- tokens[i] = FR_STREET_ABBREV.get(tokens[i]) ?? tokens[i];
184
- }
185
- break;
186
- case "de":
187
- for (let i = 0; i < tokens.length; i++) {
188
- const t = tokens[i];
189
- if (t.endsWith("str") && !t.endsWith("strasse")) {
190
- tokens[i] = t.replace(/str$/, "strasse");
191
- }
192
- }
193
- break;
194
- case "nl":
195
- for (let i = 0; i < tokens.length; i++) {
196
- const t = tokens[i];
197
- if (t.endsWith("str") && !t.endsWith("straat")) {
198
- tokens[i] = t.replace(/str$/, "straat");
199
- }
200
- }
201
- break;
202
- }
203
- return tokens.join(" ");
204
- }
205
- /**
206
- * Normalize a locality name for address-point keying (fold only — no street semantics).
207
- */
208
- export function normalizeLocalityForKey(locality) {
209
- return fold(locality);
210
- }
211
- /**
212
- * Strip a trailing French arrondissement designator from a FOLDED commune key ("paris 8e arrondissement" → "paris",
213
- * "lyon 1er arrondissement" → "lyon", "marseille 10e arrondissement" → "marseille"). Paris, Lyon and Marseille are the
214
- * only French communes subdivided into _arrondissements municipaux_; a national register (BAN) names each row per
215
- * arrondissement, but a query names the base commune ("Place Bellecour, Lyon", never "…, Lyon 2e"). Applied on BOTH
216
- * sides of the #1042 street-centroid key — build-side (deriving the `locality_base` column) and query-side (folding the
217
- * probe commune) — so the two agree by construction (the one-function discipline). Input must already be folded
218
- * (lower-case, diacritic-stripped); a no-op for every other commune. Returns the input unchanged if the strip would
219
- * empty it.
220
- */
221
- export function stripArrondissement(localityNorm) {
222
- const stripped = localityNorm.replace(/\s+\d+(?:er|e)\s+arrondissement$/, "").trim();
223
- return stripped || localityNorm;
224
- }
225
- /**
226
- * Strip a locality QUALIFIER for a query-side fallback — when an OA locality's exact normalized name misses the
227
- * gazetteer's canonical name, retry with the qualifier removed. OA address data carries disambiguating qualifiers the
228
- * gazetteer's canonical name omits: Austrian `Kraubath/Mur` and `Hart b.Graz` → `Hart`; Swiss `Lenk im Simmental` →
229
- * `Lenk`, `Roche VD` → `Roche`; Danish `Odense S`, `Hurup Thy`. A FALLBACK ONLY — the exact name is tried first, and
230
- * the region-bbox disambiguation resolves any base-name ambiguity downstream. The candidate table is unchanged (this is
231
- * purely query-side); feed the result back through {@link normalizeLocalityForKey}. Returns "" when nothing was stripped
232
- * (no point re-probing the identical key).
233
- *
234
- * Measured (`scripts/eval/candidate-recall.ts --strip-fallback`, EU OA holdouts): recovers AT 74.1→88.2% (+14.1pp), DK
235
- * 91.5→96.2%, CH 90.4→92.6%; +1.3pp overall (diluted by the already-100% locales). Conservative by design — only the
236
- * qualifier forms above; FI/PT/SI misses are untouched.
237
- */
238
- export function stripLocalityQualifier(locality) {
239
- let s = locality.trim();
240
- if (s.includes("/")) {
241
- s = s.split("/")[0].trim();
242
- }
243
- // "Kraubath/Mur", "St.Kanzian/Klopeiner See"
244
- s = s.replace(/\s+[a-zà-ÿ]\.\s*\S.*$/iu, ""); // abbreviated " b.Graz" / " o.Bleiburg" / " a.d. …"
245
- s = s.replace(/\s+(im|an der|ob|bei|in der|unter|vor)\s+\S.*$/iu, ""); // " im Simmental", " bei Graz"
246
- s = s.replace(/\s+(S|N|E|W|V|Ø|Sø|Fyn|Thy|Sjælland|Jylland|[A-ZÅÄÖ]{2})$/u, ""); // " S", " VD", " Thy"
247
- s = s.trim();
248
- return s === locality.trim() ? "" : s;
249
- }
250
- /**
251
- * Fold numbered-route designators to a canonical key, applied AFTER {@link normalizeStreetForKey}. Sources disagree
252
- * systematically on how they spell a route: TIGER says `State Rte 100` / `US Hwy 5` where E911/Overture say `VT ROUTE
253
- * 100` / `US ROUTE 5` — the dominant street-name miss class in the #483 interpolation eval (rural addresses live on
254
- * routes). `us <designator> N…` folds to `us route N…`; `state <designator> N…` and `<2-letter-prefix> <designator> N…`
255
- * (the state abbreviation form) fold to `state route N…`. Only digit-leading route numbers fold — `State Street` and
256
- * friends never match.
257
- *
258
- * Used by BOTH the segment-shard builder (`scripts/build-interpolation-shard.ts`) and the interpolation lookup — same
259
- * one-function discipline as {@link normalizeStreetForKey}. The address-point tier (#476) does NOT apply it yet:
260
- * adopting it there requires a shard rebuild (noted on #483).
261
- *
262
- * A same-numbered US and state route stay DISTINCT keys (`us route 5` vs `state route 5`); only the BARE `route N` form
263
- * is ambiguous (designator unknown) and it stays unfolded — a bare-route query therefore misses rather than guessing a
264
- * designator.
265
- */
266
- export function canonicalizeRouteKey(streetNorm) {
267
- const match = /^(us|state|[a-z]{2}) (?:route|rte|rt|highway|hwy) (\d.*)$/.exec(streetNorm);
268
- if (!match)
269
- return streetNorm;
270
- return `${match[1] === "us" ? "us" : "state"} route ${match[2]}`;
271
- }
272
- //# sourceMappingURL=street-normalize.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"street-normalize.js","sourceRoot":"","sources":["../street-normalize.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"street-segment-schema.d.ts","sourceRoot":"","sources":["../street-segment-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEpC;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,cAAc,EAAE,kBAAkB,CAAA;IAClC,kBAAkB,EAAE,oBAAoB,CAAA;CACxC;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,8JAczB,CAAA;AAEV;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,MAAM,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/F;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC3C,EAAE,EAAE,MAAM,CAAC,qBAAqB,CAAC,EACjC,GAAG,EAAE,oBAAoB,GACvB,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,MAAM,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjG"}
package/sqlite-utils.ts DELETED
@@ -1,46 +0,0 @@
1
- /**
2
- * @copyright Sister Software
3
- * @license AGPL-3.0
4
- * @author Teffen Ellis, et al.
5
- *
6
- * Small shared helpers for the SQLite-backed lookups.
7
- */
8
-
9
- import type { DatabaseSync } from "node:sqlite"
10
-
11
- /**
12
- * True when `name` is a table in the open database. The street-level lookups use this to degrade gracefully on an
13
- * empty/tableless shard — an interrupted `build-*-shard.ts`, or a stray 0-byte file (e.g. `sqlite3 <missing>.db "…"`
14
- * CREATES one) — rather than throwing `no such table` at construction and taking down a whole state's geocode (#568). A
15
- * missing table makes the lookup a no-op miss.
16
- */
17
- export function hasTable(db: DatabaseSync, name: string): boolean {
18
- try {
19
- const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1").get(name)
20
-
21
- return row !== undefined
22
- } catch {
23
- return false
24
- }
25
- }
26
-
27
- /**
28
- * True when `table` exists in the open database AND carries `column`.
29
- *
30
- * The column-level sibling of {@link hasTable}, and it exists for the same reason one layer down: an artifact built
31
- * before a column was added is still a VALID artifact, and a reader that unconditionally names the new column in its
32
- * `SELECT` turns "this gazetteer is a build behind" into `no such column` at the first keystroke. Probe once at
33
- * construction and shape the query — `table_info` is a PRAGMA, so it must not sit on a per-query path.
34
- *
35
- * Note the interpolation: PRAGMA does not take bound parameters, so `table` is spliced. Every caller passes a
36
- * module-level constant; never pass user input.
37
- */
38
- export function hasColumn(db: DatabaseSync, table: string, column: string): boolean {
39
- try {
40
- const rows = db.prepare(`PRAGMA table_info(${table})`).all() as unknown as Array<{ name: string }>
41
-
42
- return rows.some((r) => String(r.name) === column)
43
- } catch {
44
- return false
45
- }
46
- }
@@ -1,318 +0,0 @@
1
- /**
2
- * @copyright Sister Software
3
- * @license AGPL-3.0
4
- * @author Teffen Ellis, et al.
5
- *
6
- * THE street normalizer for the address-point tier (#476). One function, used by BOTH the shard
7
- * builder (`scripts/build-address-point-shard.ts`) and the lookup tier (`address-point.ts`) —
8
- * never two implementations (the PLACETYPE_ORDER lesson: parallel copies silently corrupt).
9
- *
10
- * Normalization contract (deliberately aggressive — both sides apply the same function, so
11
- * collisions only need to be _consistent_, not linguistically perfect):
12
- *
13
- * 1. Lowercase, NFKD-fold diacritics, collapse whitespace, strip punctuation (periods, commas,
14
- * apostrophes).
15
- * 2. Expand USPS directional abbreviations at the FIRST and LAST token position (`n` → `north`, `se` →
16
- * `southeast`) — Overture sources abbreviate inconsistently.
17
- * 3. Canonicalize a trailing USPS street-type token via the codex suffix table to its canonical full
18
- * form (`st`/`str`/`street` → `street`).
19
- *
20
- * Numbered streets are left as digits (`5th` stays `5th`); a SPELLED ordinal before a street suffix
21
- * folds to its digit form (`tenth street` → `10th street`, #723) so the grid-city ordinal
22
- * cross-streets the source data spells with digits become reachable.
23
- */
24
-
25
- import { AbbreviationToDirectional, US_STREET_SUFFIX_LOOKUP } from "@mailwoman/codex/us"
26
-
27
- /**
28
- * Token count a street must exceed before its trailing pair is merged. At or below it the pair IS the whole street
29
- * name, and merging would leave nothing to match on.
30
- */
31
- const MIN_TOKENS_FOR_TAIL_MERGE = 3
32
-
33
- /**
34
- * Spelled ordinal street names → their digit-ordinal form ("tenth" → "10th"), applied ONLY when a street-type suffix
35
- * follows (#723 admin-tail) — so the ordinal cross-streets common in grid cities ("Tenth Street", "Fifth Avenue") match
36
- * the shards' digit keys, WITHOUT rewriting ordinal-WORD names where the next token is not a suffix ("First National
37
- * Bank Rd" stays "first national …"). Digit-source shards are unaffected (a digit token isn't in this map), so the
38
- * existing keys need no rebuild; a future rebuild folds any spelled-source key the same way (the one-function
39
- * discipline).
40
- */
41
- const SPELLED_ORDINAL_TO_DIGIT = new Map<string, string>([
42
- ["first", "1st"],
43
- ["second", "2nd"],
44
- ["third", "3rd"],
45
- ["fourth", "4th"],
46
- ["fifth", "5th"],
47
- ["sixth", "6th"],
48
- ["seventh", "7th"],
49
- ["eighth", "8th"],
50
- ["ninth", "9th"],
51
- ["tenth", "10th"],
52
- ["eleventh", "11th"],
53
- ["twelfth", "12th"],
54
- ["thirteenth", "13th"],
55
- ["fourteenth", "14th"],
56
- ["fifteenth", "15th"],
57
- ["sixteenth", "16th"],
58
- ["seventeenth", "17th"],
59
- ["eighteenth", "18th"],
60
- ["nineteenth", "19th"],
61
- ["twentieth", "20th"],
62
- ["thirtieth", "30th"],
63
- ["fortieth", "40th"],
64
- ["fiftieth", "50th"],
65
- ["sixtieth", "60th"],
66
- ["seventieth", "70th"],
67
- ["eightieth", "80th"],
68
- ["ninetieth", "90th"],
69
- ["hundredth", "100th"],
70
- ])
71
-
72
- /**
73
- * Lowercase + diacritic-fold + punctuation strip + whitespace collapse.
74
- */
75
- function fold(input: string): string {
76
- return input
77
- .normalize("NFKD")
78
- .replaceAll(/[̀-ͯ]/g, "")
79
- .toLowerCase()
80
- .replaceAll(/[.,'’]/g, "")
81
- .replaceAll(/\s+/g, " ")
82
- .trim()
83
- }
84
-
85
- /**
86
- * Normalize a street name for address-point keying. Same function at build time and lookup time — see module docstring
87
- * for the contract.
88
- */
89
- export function normalizeStreetForKey(street: string): string {
90
- const tokens = fold(street).split(" ")
91
-
92
- if (!tokens.length) return ""
93
-
94
- // Spelled-ordinal street names → digit form when a street suffix follows ("Tenth Street" →
95
- // "10th street", #723). Gated on the next token being a suffix so ordinal-WORD names are untouched.
96
- for (let i = 0; i < tokens.length - 1; i++) {
97
- const digit = SPELLED_ORDINAL_TO_DIGIT.get(tokens[i]!)
98
-
99
- if (digit && US_STREET_SUFFIX_LOOKUP.has(tokens[i + 1]!)) {
100
- tokens[i] = digit
101
- }
102
- }
103
-
104
- // Directional expansion at the edges only ("N Main St" / "Main St N" — never interior
105
- // tokens, where "W" may be an initial in a person-named street). The codex expands
106
- // compounds to two words ("SE" → "SOUTH EAST"); we key on the spaceless form
107
- // ("southeast"), and also merge an already-written two-token pair ("South East …").
108
- const edgeDirectional = (raw: string) =>
109
- AbbreviationToDirectional.get(raw.toUpperCase())?.toLowerCase().replace(" ", "")
110
-
111
- const mergePair = (a?: string, b?: string) =>
112
- a && b && /^(north|south)$/.test(a) && /^(east|west)$/.test(b) ? a + b : undefined
113
-
114
- const leadPair = mergePair(tokens[0], tokens[1])
115
-
116
- if (leadPair && tokens.length > 2) {
117
- tokens.splice(0, 2, leadPair)
118
- }
119
-
120
- const first = edgeDirectional(tokens[0]!)
121
-
122
- if (first && tokens.length > 1) {
123
- tokens[0] = first
124
- }
125
-
126
- const tailPair = mergePair(tokens.at(-2), tokens.at(-1))
127
-
128
- if (tailPair && tokens.length > MIN_TOKENS_FOR_TAIL_MERGE) {
129
- tokens.splice(-2, 2, tailPair)
130
- }
131
-
132
- if (tokens.length > 2) {
133
- const last = edgeDirectional(tokens.at(-1)!)
134
-
135
- if (last) {
136
- tokens[tokens.length - 1] = last
137
- }
138
- }
139
-
140
- // Street-type canonicalization via the codex table (lowercase keys, UPPER canonical
141
- // values). The suffix is usually the last token, but sits second-to-last when a trailing
142
- // directional follows ("Main St N") — check both positions, canonicalize the first hit.
143
- for (const at of [tokens.length - 1, tokens.length - 2]) {
144
- if (at < 1) continue // never canonicalize the only/first token ("Street Road" exists)
145
- const canonical = US_STREET_SUFFIX_LOOKUP.get(tokens[at]!)
146
-
147
- if (canonical) {
148
- tokens[at] = canonical.toLowerCase()
149
-
150
- break
151
- }
152
- }
153
-
154
- return tokens.join(" ")
155
- }
156
-
157
- /**
158
- * Street-name locale for the address-point key. The US path is the full USPS pipeline ({@link normalizeStreetForKey});
159
- * the international paths fold + apply a SMALL, consistent per-locale type-token canonicalization. Same discipline as
160
- * the US normalizer: build side and probe side call the identical function, so the key only needs to be CONSISTENT, not
161
- * linguistically perfect — a folded "rue du chevaleret" keys the same on both sides whether or not we reorder the
162
- * article, so no salient-token / multi-key index is built yet (deferred until probing shows the normalizer can't absorb
163
- * the false-negatives).
164
- */
165
- export type StreetLocale = "us" | "en" | "fr" | "de" | "nl"
166
-
167
- /**
168
- * French street-type abbreviations → canonical full form, applied per token after {@link fold}. French address types
169
- * LEAD the name ("Av. de…", "Bd …", "Pl. …") and "St"/"Ste" abbreviate Saint/Sainte inside names ("Rue St-Honoré" →
170
- * "rue saint honore"). fold() has already stripped the trailing period, so the keys are point-free ("av", "bd").
171
- */
172
- const FR_STREET_ABBREV = new Map<string, string>([
173
- ["av", "avenue"],
174
- ["ave", "avenue"],
175
- ["bd", "boulevard"],
176
- ["bld", "boulevard"],
177
- ["bvd", "boulevard"],
178
- ["boul", "boulevard"],
179
- ["pl", "place"],
180
- ["imp", "impasse"],
181
- ["all", "allee"],
182
- ["ch", "chemin"],
183
- ["che", "chemin"],
184
- ["sq", "square"],
185
- ["pas", "passage"],
186
- ["fg", "faubourg"],
187
- ["fbg", "faubourg"],
188
- ["rte", "route"],
189
- ["st", "saint"],
190
- ["ste", "sainte"],
191
- ["sts", "saints"],
192
- ])
193
-
194
- /**
195
- * Normalize a street name for the address-point key in a non-US locale. Same function build-side and probe-side (the
196
- * one-function discipline). US delegates to {@link normalizeStreetForKey}.
197
- *
198
- * - **en** — the shared English address-key pipeline (directionals + suffix aliases), currently identical to US.
199
- * - **fr** — fold + expand leading type abbreviations and Saint/Sainte (token map).
200
- * - **de** — fold + ß→ss + canonicalize the GLUED `-str(.)` suffix to `-strasse` ("Lindenstr." → "lindenstrasse",
201
- * "Lindenstraße" → "lindenstrasse"); an already-full "-strasse" is left intact.
202
- * - **nl** — fold + canonicalize the glued `-str` suffix to `-straat` ("Kerkstr." → "kerkstraat").
203
- */
204
- export function normalizeStreetForKeyLocale(street: string, locale: StreetLocale): string {
205
- if (locale === "us" || locale === "en") return normalizeStreetForKey(street)
206
-
207
- // Hyphen → space so a compound name keys the same whether the source or the query writes the
208
- // hyphen ("Champs-Élysées", "St-Honoré") or a space — both sides fold identically, so this is pure
209
- // robustness. It also splits a hyphenated abbreviation ("St-Honoré" → "st honore") into tokens the
210
- // per-locale type/Saint map can see.
211
- const tokens = fold(street).replaceAll("ß", "ss").replaceAll("-", " ").split(/\s+/).filter(Boolean)
212
-
213
- if (!tokens.length) return ""
214
-
215
- switch (locale) {
216
- case "fr":
217
- for (let i = 0; i < tokens.length; i++) {
218
- tokens[i] = FR_STREET_ABBREV.get(tokens[i]!) ?? tokens[i]!
219
- }
220
- break
221
- case "de":
222
- for (let i = 0; i < tokens.length; i++) {
223
- const t = tokens[i]!
224
-
225
- if (t.endsWith("str") && !t.endsWith("strasse")) {
226
- tokens[i] = t.replace(/str$/, "strasse")
227
- }
228
- }
229
- break
230
- case "nl":
231
- for (let i = 0; i < tokens.length; i++) {
232
- const t = tokens[i]!
233
-
234
- if (t.endsWith("str") && !t.endsWith("straat")) {
235
- tokens[i] = t.replace(/str$/, "straat")
236
- }
237
- }
238
- break
239
- }
240
-
241
- return tokens.join(" ")
242
- }
243
-
244
- /**
245
- * Normalize a locality name for address-point keying (fold only — no street semantics).
246
- */
247
- export function normalizeLocalityForKey(locality: string): string {
248
- return fold(locality)
249
- }
250
-
251
- /**
252
- * Strip a trailing French arrondissement designator from a FOLDED commune key ("paris 8e arrondissement" → "paris",
253
- * "lyon 1er arrondissement" → "lyon", "marseille 10e arrondissement" → "marseille"). Paris, Lyon and Marseille are the
254
- * only French communes subdivided into _arrondissements municipaux_; a national register (BAN) names each row per
255
- * arrondissement, but a query names the base commune ("Place Bellecour, Lyon", never "…, Lyon 2e"). Applied on BOTH
256
- * sides of the #1042 street-centroid key — build-side (deriving the `locality_base` column) and query-side (folding the
257
- * probe commune) — so the two agree by construction (the one-function discipline). Input must already be folded
258
- * (lower-case, diacritic-stripped); a no-op for every other commune. Returns the input unchanged if the strip would
259
- * empty it.
260
- */
261
- export function stripArrondissement(localityNorm: string): string {
262
- const stripped = localityNorm.replace(/\s+\d+(?:er|e)\s+arrondissement$/, "").trim()
263
-
264
- return stripped || localityNorm
265
- }
266
-
267
- /**
268
- * Strip a locality QUALIFIER for a query-side fallback — when an OA locality's exact normalized name misses the
269
- * gazetteer's canonical name, retry with the qualifier removed. OA address data carries disambiguating qualifiers the
270
- * gazetteer's canonical name omits: Austrian `Kraubath/Mur` and `Hart b.Graz` → `Hart`; Swiss `Lenk im Simmental` →
271
- * `Lenk`, `Roche VD` → `Roche`; Danish `Odense S`, `Hurup Thy`. A FALLBACK ONLY — the exact name is tried first, and
272
- * the region-bbox disambiguation resolves any base-name ambiguity downstream. The candidate table is unchanged (this is
273
- * purely query-side); feed the result back through {@link normalizeLocalityForKey}. Returns "" when nothing was stripped
274
- * (no point re-probing the identical key).
275
- *
276
- * Measured (`scripts/eval/candidate-recall.ts --strip-fallback`, EU OA holdouts): recovers AT 74.1→88.2% (+14.1pp), DK
277
- * 91.5→96.2%, CH 90.4→92.6%; +1.3pp overall (diluted by the already-100% locales). Conservative by design — only the
278
- * qualifier forms above; FI/PT/SI misses are untouched.
279
- */
280
- export function stripLocalityQualifier(locality: string): string {
281
- let s = locality.trim()
282
-
283
- if (s.includes("/")) {
284
- s = s.split("/")[0]!.trim()
285
- }
286
-
287
- // "Kraubath/Mur", "St.Kanzian/Klopeiner See"
288
- s = s.replace(/\s+[a-zà-ÿ]\.\s*\S.*$/iu, "") // abbreviated " b.Graz" / " o.Bleiburg" / " a.d. …"
289
- s = s.replace(/\s+(im|an der|ob|bei|in der|unter|vor)\s+\S.*$/iu, "") // " im Simmental", " bei Graz"
290
- s = s.replace(/\s+(S|N|E|W|V|Ø|Sø|Fyn|Thy|Sjælland|Jylland|[A-ZÅÄÖ]{2})$/u, "") // " S", " VD", " Thy"
291
- s = s.trim()
292
-
293
- return s === locality.trim() ? "" : s
294
- }
295
-
296
- /**
297
- * Fold numbered-route designators to a canonical key, applied AFTER {@link normalizeStreetForKey}. Sources disagree
298
- * systematically on how they spell a route: TIGER says `State Rte 100` / `US Hwy 5` where E911/Overture say `VT ROUTE
299
- * 100` / `US ROUTE 5` — the dominant street-name miss class in the #483 interpolation eval (rural addresses live on
300
- * routes). `us <designator> N…` folds to `us route N…`; `state <designator> N…` and `<2-letter-prefix> <designator> N…`
301
- * (the state abbreviation form) fold to `state route N…`. Only digit-leading route numbers fold — `State Street` and
302
- * friends never match.
303
- *
304
- * Used by BOTH the segment-shard builder (`scripts/build-interpolation-shard.ts`) and the interpolation lookup — same
305
- * one-function discipline as {@link normalizeStreetForKey}. The address-point tier (#476) does NOT apply it yet:
306
- * adopting it there requires a shard rebuild (noted on #483).
307
- *
308
- * A same-numbered US and state route stay DISTINCT keys (`us route 5` vs `state route 5`); only the BARE `route N` form
309
- * is ambiguous (designator unknown) and it stays unfolded — a bare-route query therefore misses rather than guessing a
310
- * designator.
311
- */
312
- export function canonicalizeRouteKey(streetNorm: string): string {
313
- const match = /^(us|state|[a-z]{2}) (?:route|rte|rt|highway|hwy) (\d.*)$/.exec(streetNorm)
314
-
315
- if (!match) return streetNorm
316
-
317
- return `${match[1] === "us" ? "us" : "state"} route ${match[2]}`
318
- }