@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.
Files changed (477) hide show
  1. package/README.md +9 -8
  2. package/lib/address/point/interpolation.ts +45 -39
  3. package/lib/address/point/schema.ts +17 -40
  4. package/lib/address/point.ts +316 -0
  5. package/lib/{address/index.ts → address.ts} +1 -1
  6. package/lib/ancestry/backfill.ts +20 -86
  7. package/lib/{ancestry/index.ts → ancestry.ts} +19 -15
  8. package/lib/build/candidate.ts +122 -174
  9. package/lib/build/population-corrections.ts +64 -0
  10. package/lib/build/slim.ts +44 -114
  11. package/lib/candidate/alias-bags.ts +16 -17
  12. package/lib/candidate/ancestors/schema.ts +77 -61
  13. package/lib/candidate/ancestors/sidecar.ts +15 -22
  14. package/lib/candidate/country-display-names.ts +6 -20
  15. package/lib/candidate/extract-fold.ts +10 -55
  16. package/lib/candidate/fts.ts +5 -23
  17. package/lib/candidate/importance.ts +65 -68
  18. package/lib/candidate/lookup.ts +124 -415
  19. package/lib/candidate/name-roles.ts +15 -33
  20. package/lib/candidate/own-name.ts +35 -32
  21. package/lib/candidate/place-attrs.ts +20 -13
  22. package/lib/candidate/schema.ts +29 -65
  23. package/lib/candidate/scoring.ts +54 -93
  24. package/lib/capital-schema.ts +21 -17
  25. package/lib/capitals.ts +29 -27
  26. package/lib/coincident-roles.ts +85 -55
  27. package/lib/convention/schema.ts +15 -16
  28. package/lib/convention.ts +144 -0
  29. package/lib/coverage-manifest-schema.ts +40 -45
  30. package/lib/currency-backfill.ts +34 -79
  31. package/lib/env.ts +1 -1
  32. package/lib/exact-match.ts +32 -21
  33. package/lib/extracts.ts +97 -74
  34. package/lib/fst/autocomplete.ts +54 -37
  35. package/lib/fst/builder.ts +37 -41
  36. package/lib/fst/deserialize-web.ts +16 -17
  37. package/lib/fst/format.ts +41 -23
  38. package/lib/fst/freshness.ts +43 -120
  39. package/lib/fst/matcher.ts +7 -5
  40. package/lib/fst/serialize.ts +54 -74
  41. package/lib/fst/types.ts +78 -75
  42. package/lib/{fst/index.ts → fst.ts} +1 -0
  43. package/lib/fts/query.ts +5 -36
  44. package/lib/fts.ts +280 -0
  45. package/lib/geonames/aliases.ts +73 -144
  46. package/lib/geonames/postal.ts +162 -71
  47. package/lib/index.ts +9 -8
  48. package/lib/interpolation.ts +48 -100
  49. package/lib/lookup.ts +155 -270
  50. package/lib/name-score.ts +9 -7
  51. package/lib/nsul/lookup.ts +37 -54
  52. package/lib/nsul/schema.ts +16 -43
  53. package/lib/paths.ts +159 -0
  54. package/lib/place-importance-schema.ts +62 -169
  55. package/lib/poi/lookup.ts +104 -121
  56. package/lib/poi/schema.ts +42 -26
  57. package/lib/polygon-schema.ts +10 -6
  58. package/lib/postal/city/alias/lookup.ts +22 -40
  59. package/lib/postal/city/alias/schema.ts +14 -10
  60. package/lib/postal/city/candidate-schema.ts +26 -20
  61. package/lib/postcode-point-lookup.ts +8 -27
  62. package/lib/primary-preference.ts +46 -126
  63. package/lib/proximity-rerank.ts +44 -33
  64. package/lib/ranking-weights.ts +105 -78
  65. package/lib/region-keys.ts +70 -42
  66. package/lib/reverse.ts +149 -86
  67. package/lib/schema.ts +73 -50
  68. package/lib/search-fetch.ts +90 -68
  69. package/lib/sqlite/convention-source.ts +15 -23
  70. package/lib/sqlite/utils.ts +19 -22
  71. package/lib/street/centroid/schema.ts +37 -42
  72. package/lib/street/{centroid/index.ts → centroid.ts} +16 -25
  73. package/lib/street/morphology/fst/builder.ts +60 -42
  74. package/lib/street/morphology/fst/loader.ts +40 -32
  75. package/lib/street/name-lookup.ts +45 -41
  76. package/lib/street/normalize.ts +88 -219
  77. package/lib/street/segment-schema.ts +116 -43
  78. package/lib/{street/index.ts → street.ts} +1 -1
  79. package/lib/types.ts +109 -150
  80. package/lib/unified-schema.ts +29 -29
  81. package/lib/uprn/existence.ts +30 -19
  82. package/lib/uprn/lookup.ts +29 -68
  83. package/lib/uprn/schema.ts +18 -40
  84. package/lib/weights-overlay-linker.ts +236 -252
  85. package/out/address/point/interpolation.d.ts +20 -23
  86. package/out/address/point/interpolation.d.ts.map +1 -1
  87. package/out/address/point/interpolation.js +42 -39
  88. package/out/address/point/interpolation.js.map +1 -1
  89. package/out/address/point/schema.d.ts +12 -35
  90. package/out/address/point/schema.d.ts.map +1 -1
  91. package/out/address/point/schema.js +3 -19
  92. package/out/address/point/schema.js.map +1 -1
  93. package/out/address/point.d.ts +57 -0
  94. package/out/address/point.d.ts.map +1 -0
  95. package/out/address/point.js +206 -0
  96. package/out/address/point.js.map +1 -0
  97. package/out/{address/index.js → address.d.ts} +2 -2
  98. package/out/address.d.ts.map +1 -0
  99. package/out/{address/index.d.ts → address.js} +2 -2
  100. package/out/address.js.map +1 -0
  101. package/out/ancestry/backfill.d.ts +11 -64
  102. package/out/ancestry/backfill.d.ts.map +1 -1
  103. package/out/ancestry/backfill.js +14 -74
  104. package/out/ancestry/backfill.js.map +1 -1
  105. package/out/ancestry.d.ts +49 -0
  106. package/out/ancestry.d.ts.map +1 -0
  107. package/out/ancestry.js +59 -0
  108. package/out/ancestry.js.map +1 -0
  109. package/out/build/candidate.d.ts +82 -112
  110. package/out/build/candidate.d.ts.map +1 -1
  111. package/out/build/candidate.js +17 -100
  112. package/out/build/candidate.js.map +1 -1
  113. package/out/build/population-corrections.d.ts +52 -0
  114. package/out/build/population-corrections.d.ts.map +1 -0
  115. package/out/build/population-corrections.js +40 -0
  116. package/out/build/population-corrections.js.map +1 -0
  117. package/out/build/slim.d.ts +8 -44
  118. package/out/build/slim.d.ts.map +1 -1
  119. package/out/build/slim.js +33 -94
  120. package/out/build/slim.js.map +1 -1
  121. package/out/candidate/alias-bags.d.ts +6 -6
  122. package/out/candidate/alias-bags.d.ts.map +1 -1
  123. package/out/candidate/alias-bags.js +16 -17
  124. package/out/candidate/alias-bags.js.map +1 -1
  125. package/out/candidate/ancestors/schema.d.ts +73 -57
  126. package/out/candidate/ancestors/schema.d.ts.map +1 -1
  127. package/out/candidate/ancestors/schema.js +56 -48
  128. package/out/candidate/ancestors/schema.js.map +1 -1
  129. package/out/candidate/ancestors/sidecar.d.ts +3 -8
  130. package/out/candidate/ancestors/sidecar.d.ts.map +1 -1
  131. package/out/candidate/ancestors/sidecar.js +15 -22
  132. package/out/candidate/ancestors/sidecar.js.map +1 -1
  133. package/out/candidate/country-display-names.d.ts +5 -15
  134. package/out/candidate/country-display-names.d.ts.map +1 -1
  135. package/out/candidate/country-display-names.js +6 -20
  136. package/out/candidate/country-display-names.js.map +1 -1
  137. package/out/candidate/extract-fold.d.ts +7 -15
  138. package/out/candidate/extract-fold.d.ts.map +1 -1
  139. package/out/candidate/extract-fold.js +5 -47
  140. package/out/candidate/extract-fold.js.map +1 -1
  141. package/out/candidate/fts.d.ts +5 -23
  142. package/out/candidate/fts.d.ts.map +1 -1
  143. package/out/candidate/fts.js +5 -23
  144. package/out/candidate/fts.js.map +1 -1
  145. package/out/candidate/importance.d.ts +60 -65
  146. package/out/candidate/importance.d.ts.map +1 -1
  147. package/out/candidate/importance.js +56 -63
  148. package/out/candidate/importance.js.map +1 -1
  149. package/out/candidate/lookup.d.ts +18 -55
  150. package/out/candidate/lookup.d.ts.map +1 -1
  151. package/out/candidate/lookup.js +82 -385
  152. package/out/candidate/lookup.js.map +1 -1
  153. package/out/candidate/name-roles.d.ts +9 -21
  154. package/out/candidate/name-roles.d.ts.map +1 -1
  155. package/out/candidate/name-roles.js +15 -33
  156. package/out/candidate/name-roles.js.map +1 -1
  157. package/out/candidate/own-name.d.ts +23 -25
  158. package/out/candidate/own-name.d.ts.map +1 -1
  159. package/out/candidate/own-name.js +35 -32
  160. package/out/candidate/own-name.js.map +1 -1
  161. package/out/candidate/place-attrs.d.ts +20 -13
  162. package/out/candidate/place-attrs.d.ts.map +1 -1
  163. package/out/candidate/place-attrs.js +4 -5
  164. package/out/candidate/place-attrs.js.map +1 -1
  165. package/out/candidate/schema.d.ts +27 -62
  166. package/out/candidate/schema.d.ts.map +1 -1
  167. package/out/candidate/schema.js +10 -22
  168. package/out/candidate/schema.js.map +1 -1
  169. package/out/candidate/scoring.d.ts +7 -8
  170. package/out/candidate/scoring.d.ts.map +1 -1
  171. package/out/candidate/scoring.js +52 -89
  172. package/out/candidate/scoring.js.map +1 -1
  173. package/out/capital-schema.d.ts +21 -17
  174. package/out/capital-schema.d.ts.map +1 -1
  175. package/out/capital-schema.js +17 -15
  176. package/out/capital-schema.js.map +1 -1
  177. package/out/capitals.d.ts +27 -25
  178. package/out/capitals.d.ts.map +1 -1
  179. package/out/capitals.js +23 -21
  180. package/out/capitals.js.map +1 -1
  181. package/out/coincident-roles.d.ts +60 -43
  182. package/out/coincident-roles.d.ts.map +1 -1
  183. package/out/coincident-roles.js +72 -50
  184. package/out/coincident-roles.js.map +1 -1
  185. package/out/convention/schema.d.ts +14 -14
  186. package/out/convention/schema.d.ts.map +1 -1
  187. package/out/convention/schema.js +6 -4
  188. package/out/convention/schema.js.map +1 -1
  189. package/out/convention.d.ts +97 -0
  190. package/out/convention.d.ts.map +1 -0
  191. package/out/convention.js +81 -0
  192. package/out/convention.js.map +1 -0
  193. package/out/coverage-manifest-schema.d.ts +34 -39
  194. package/out/coverage-manifest-schema.d.ts.map +1 -1
  195. package/out/coverage-manifest-schema.js +25 -34
  196. package/out/coverage-manifest-schema.js.map +1 -1
  197. package/out/currency-backfill.d.ts +16 -38
  198. package/out/currency-backfill.d.ts.map +1 -1
  199. package/out/currency-backfill.js +19 -46
  200. package/out/currency-backfill.js.map +1 -1
  201. package/out/env.d.ts +1 -1
  202. package/out/env.js +1 -1
  203. package/out/exact-match.d.ts +19 -10
  204. package/out/exact-match.d.ts.map +1 -1
  205. package/out/exact-match.js +32 -21
  206. package/out/exact-match.js.map +1 -1
  207. package/out/extracts.d.ts +66 -55
  208. package/out/extracts.d.ts.map +1 -1
  209. package/out/extracts.js +63 -55
  210. package/out/extracts.js.map +1 -1
  211. package/out/fst/autocomplete.d.ts +29 -21
  212. package/out/fst/autocomplete.d.ts.map +1 -1
  213. package/out/fst/autocomplete.js +39 -28
  214. package/out/fst/autocomplete.js.map +1 -1
  215. package/out/fst/builder.d.ts.map +1 -1
  216. package/out/fst/builder.js +37 -41
  217. package/out/fst/builder.js.map +1 -1
  218. package/out/fst/deserialize-web.d.ts +4 -4
  219. package/out/fst/deserialize-web.d.ts.map +1 -1
  220. package/out/fst/deserialize-web.js +15 -16
  221. package/out/fst/deserialize-web.js.map +1 -1
  222. package/out/fst/format.d.ts +41 -23
  223. package/out/fst/format.d.ts.map +1 -1
  224. package/out/fst/format.js +41 -23
  225. package/out/fst/format.js.map +1 -1
  226. package/out/fst/freshness.d.ts +19 -81
  227. package/out/fst/freshness.d.ts.map +1 -1
  228. package/out/fst/freshness.js +31 -94
  229. package/out/fst/freshness.js.map +1 -1
  230. package/out/fst/matcher.d.ts +5 -4
  231. package/out/fst/matcher.d.ts.map +1 -1
  232. package/out/fst/matcher.js +2 -2
  233. package/out/fst/matcher.js.map +1 -1
  234. package/out/fst/serialize.d.ts +28 -28
  235. package/out/fst/serialize.d.ts.map +1 -1
  236. package/out/fst/serialize.js +53 -71
  237. package/out/fst/serialize.js.map +1 -1
  238. package/out/fst/types.d.ts +78 -74
  239. package/out/fst/types.d.ts.map +1 -1
  240. package/out/fst/types.js +1 -4
  241. package/out/fst/types.js.map +1 -1
  242. package/out/{fst/index.js → fst.d.ts} +2 -1
  243. package/out/fst.d.ts.map +1 -0
  244. package/out/{fst/index.d.ts → fst.js} +2 -1
  245. package/out/fst.js.map +1 -0
  246. package/out/fts/query.d.ts +2 -27
  247. package/out/fts/query.d.ts.map +1 -1
  248. package/out/fts/query.js +5 -36
  249. package/out/fts/query.js.map +1 -1
  250. package/out/fts.d.ts +126 -0
  251. package/out/fts.d.ts.map +1 -0
  252. package/out/fts.js +188 -0
  253. package/out/fts.js.map +1 -0
  254. package/out/geonames/aliases.d.ts +26 -62
  255. package/out/geonames/aliases.d.ts.map +1 -1
  256. package/out/geonames/aliases.js +45 -117
  257. package/out/geonames/aliases.js.map +1 -1
  258. package/out/geonames/postal.d.ts +84 -44
  259. package/out/geonames/postal.d.ts.map +1 -1
  260. package/out/geonames/postal.js +115 -73
  261. package/out/geonames/postal.js.map +1 -1
  262. package/out/{geonames/index.js → geonames.d.ts} +1 -1
  263. package/out/geonames.d.ts.map +1 -0
  264. package/out/{geonames/index.d.ts → geonames.js} +1 -1
  265. package/out/geonames.js.map +1 -0
  266. package/out/index.d.ts +9 -8
  267. package/out/index.d.ts.map +1 -1
  268. package/out/index.js +6 -5
  269. package/out/index.js.map +1 -1
  270. package/out/interpolation.d.ts +18 -55
  271. package/out/interpolation.d.ts.map +1 -1
  272. package/out/interpolation.js +27 -69
  273. package/out/interpolation.js.map +1 -1
  274. package/out/lookup.d.ts +23 -51
  275. package/out/lookup.d.ts.map +1 -1
  276. package/out/lookup.js +136 -234
  277. package/out/lookup.js.map +1 -1
  278. package/out/name-score.d.ts +2 -2
  279. package/out/name-score.d.ts.map +1 -1
  280. package/out/name-score.js +9 -7
  281. package/out/name-score.js.map +1 -1
  282. package/out/nsul/lookup.d.ts +33 -34
  283. package/out/nsul/lookup.d.ts.map +1 -1
  284. package/out/nsul/lookup.js +26 -40
  285. package/out/nsul/lookup.js.map +1 -1
  286. package/out/nsul/schema.d.ts +16 -43
  287. package/out/nsul/schema.d.ts.map +1 -1
  288. package/out/nsul/schema.js +9 -35
  289. package/out/nsul/schema.js.map +1 -1
  290. package/out/{nsul/index.d.ts → nsul.d.ts} +1 -1
  291. package/out/nsul.d.ts.map +1 -0
  292. package/out/{nsul/index.js → nsul.js} +1 -1
  293. package/out/nsul.js.map +1 -0
  294. package/out/paths.d.ts +124 -0
  295. package/out/paths.d.ts.map +1 -0
  296. package/out/paths.js +104 -0
  297. package/out/paths.js.map +1 -0
  298. package/out/place-importance-schema.d.ts +51 -143
  299. package/out/place-importance-schema.d.ts.map +1 -1
  300. package/out/place-importance-schema.js +28 -143
  301. package/out/place-importance-schema.js.map +1 -1
  302. package/out/poi/lookup.d.ts +40 -47
  303. package/out/poi/lookup.d.ts.map +1 -1
  304. package/out/poi/lookup.js +69 -96
  305. package/out/poi/lookup.js.map +1 -1
  306. package/out/poi/schema.d.ts +41 -25
  307. package/out/poi/schema.d.ts.map +1 -1
  308. package/out/poi/schema.js +25 -17
  309. package/out/poi/schema.js.map +1 -1
  310. package/out/{poi/index.js → poi.d.ts} +1 -1
  311. package/out/poi.d.ts.map +1 -0
  312. package/out/{poi/index.d.ts → poi.js} +1 -1
  313. package/out/poi.js.map +1 -0
  314. package/out/polygon-schema.d.ts +10 -6
  315. package/out/polygon-schema.d.ts.map +1 -1
  316. package/out/polygon-schema.js +2 -2
  317. package/out/polygon-schema.js.map +1 -1
  318. package/out/postal/city/alias/lookup.d.ts +20 -23
  319. package/out/postal/city/alias/lookup.d.ts.map +1 -1
  320. package/out/postal/city/alias/lookup.js +17 -30
  321. package/out/postal/city/alias/lookup.js.map +1 -1
  322. package/out/postal/city/alias/schema.d.ts +14 -10
  323. package/out/postal/city/alias/schema.d.ts.map +1 -1
  324. package/out/postal/city/alias/schema.js +10 -8
  325. package/out/postal/city/alias/schema.js.map +1 -1
  326. package/out/postal/city/candidate-schema.d.ts +25 -19
  327. package/out/postal/city/candidate-schema.d.ts.map +1 -1
  328. package/out/postal/city/candidate-schema.js +21 -17
  329. package/out/postal/city/candidate-schema.js.map +1 -1
  330. package/out/{postal/index.d.ts → postal.d.ts} +1 -1
  331. package/out/postal.d.ts.map +1 -0
  332. package/out/{postal/index.js → postal.js} +1 -1
  333. package/out/postal.js.map +1 -0
  334. package/out/postcode-point-lookup.d.ts +6 -24
  335. package/out/postcode-point-lookup.d.ts.map +1 -1
  336. package/out/postcode-point-lookup.js +5 -17
  337. package/out/postcode-point-lookup.js.map +1 -1
  338. package/out/primary-preference.d.ts +38 -92
  339. package/out/primary-preference.d.ts.map +1 -1
  340. package/out/primary-preference.js +15 -99
  341. package/out/primary-preference.js.map +1 -1
  342. package/out/proximity-rerank.d.ts +41 -30
  343. package/out/proximity-rerank.d.ts.map +1 -1
  344. package/out/proximity-rerank.js +38 -29
  345. package/out/proximity-rerank.js.map +1 -1
  346. package/out/ranking-weights.d.ts +98 -64
  347. package/out/ranking-weights.d.ts.map +1 -1
  348. package/out/ranking-weights.js +26 -25
  349. package/out/ranking-weights.js.map +1 -1
  350. package/out/region-keys.d.ts +50 -31
  351. package/out/region-keys.d.ts.map +1 -1
  352. package/out/region-keys.js +68 -40
  353. package/out/region-keys.js.map +1 -1
  354. package/out/reverse.d.ts +78 -50
  355. package/out/reverse.d.ts.map +1 -1
  356. package/out/reverse.js +98 -61
  357. package/out/reverse.js.map +1 -1
  358. package/out/schema.d.ts +72 -49
  359. package/out/schema.d.ts.map +1 -1
  360. package/out/schema.js +4 -5
  361. package/out/schema.js.map +1 -1
  362. package/out/search-fetch.d.ts +16 -12
  363. package/out/search-fetch.d.ts.map +1 -1
  364. package/out/search-fetch.js +83 -63
  365. package/out/search-fetch.js.map +1 -1
  366. package/out/sqlite/convention-source.d.ts +12 -16
  367. package/out/sqlite/convention-source.d.ts.map +1 -1
  368. package/out/sqlite/convention-source.js +13 -22
  369. package/out/sqlite/convention-source.js.map +1 -1
  370. package/out/sqlite/utils.d.ts +19 -19
  371. package/out/sqlite/utils.d.ts.map +1 -1
  372. package/out/sqlite/utils.js +14 -15
  373. package/out/sqlite/utils.js.map +1 -1
  374. package/out/street/centroid/schema.d.ts +37 -42
  375. package/out/street/centroid/schema.d.ts.map +1 -1
  376. package/out/street/centroid/schema.js +9 -21
  377. package/out/street/centroid/schema.js.map +1 -1
  378. package/out/street/centroid.d.ts +30 -0
  379. package/out/street/centroid.d.ts.map +1 -0
  380. package/out/street/{centroid/index.js → centroid.js} +13 -24
  381. package/out/street/centroid.js.map +1 -0
  382. package/out/street/morphology/fst/builder.d.ts +20 -10
  383. package/out/street/morphology/fst/builder.d.ts.map +1 -1
  384. package/out/street/morphology/fst/builder.js +44 -34
  385. package/out/street/morphology/fst/builder.js.map +1 -1
  386. package/out/street/morphology/fst/loader.d.ts +33 -26
  387. package/out/street/morphology/fst/loader.d.ts.map +1 -1
  388. package/out/street/morphology/fst/loader.js +23 -22
  389. package/out/street/morphology/fst/loader.js.map +1 -1
  390. package/out/street/name-lookup.d.ts +24 -18
  391. package/out/street/name-lookup.d.ts.map +1 -1
  392. package/out/street/name-lookup.js +34 -35
  393. package/out/street/name-lookup.js.map +1 -1
  394. package/out/street/normalize.d.ts +35 -136
  395. package/out/street/normalize.d.ts.map +1 -1
  396. package/out/street/normalize.js +77 -194
  397. package/out/street/normalize.js.map +1 -1
  398. package/out/street/segment-schema.d.ts +79 -39
  399. package/out/street/segment-schema.d.ts.map +1 -1
  400. package/out/street/segment-schema.js +71 -21
  401. package/out/street/segment-schema.js.map +1 -1
  402. package/out/{street/index.js → street.d.ts} +2 -2
  403. package/out/street.d.ts.map +1 -0
  404. package/out/{street/index.d.ts → street.js} +2 -2
  405. package/out/street.js.map +1 -0
  406. package/out/types.d.ts +84 -149
  407. package/out/types.d.ts.map +1 -1
  408. package/out/types.js +0 -6
  409. package/out/types.js.map +1 -1
  410. package/out/unified-schema.d.ts +8 -12
  411. package/out/unified-schema.d.ts.map +1 -1
  412. package/out/unified-schema.js +29 -29
  413. package/out/unified-schema.js.map +1 -1
  414. package/out/uprn/existence.d.ts +28 -17
  415. package/out/uprn/existence.d.ts.map +1 -1
  416. package/out/uprn/existence.js +26 -16
  417. package/out/uprn/existence.js.map +1 -1
  418. package/out/uprn/lookup.d.ts +14 -44
  419. package/out/uprn/lookup.d.ts.map +1 -1
  420. package/out/uprn/lookup.js +21 -57
  421. package/out/uprn/lookup.js.map +1 -1
  422. package/out/uprn/schema.d.ts +18 -40
  423. package/out/uprn/schema.d.ts.map +1 -1
  424. package/out/uprn/schema.js +10 -32
  425. package/out/uprn/schema.js.map +1 -1
  426. package/out/{uprn/index.d.ts → uprn.d.ts} +1 -1
  427. package/out/uprn.d.ts.map +1 -0
  428. package/out/{uprn/index.js → uprn.js} +1 -1
  429. package/out/uprn.js.map +1 -0
  430. package/out/weights-overlay-linker.d.ts +138 -144
  431. package/out/weights-overlay-linker.d.ts.map +1 -1
  432. package/out/weights-overlay-linker.js +105 -159
  433. package/out/weights-overlay-linker.js.map +1 -1
  434. package/package.json +91 -596
  435. package/lib/address/point/index.ts +0 -328
  436. package/lib/convention/index.ts +0 -154
  437. package/lib/fts/index.ts +0 -361
  438. package/out/address/index.d.ts.map +0 -1
  439. package/out/address/index.js.map +0 -1
  440. package/out/address/point/index.d.ts +0 -53
  441. package/out/address/point/index.d.ts.map +0 -1
  442. package/out/address/point/index.js +0 -222
  443. package/out/address/point/index.js.map +0 -1
  444. package/out/ancestry/index.d.ts +0 -45
  445. package/out/ancestry/index.d.ts.map +0 -1
  446. package/out/ancestry/index.js +0 -55
  447. package/out/ancestry/index.js.map +0 -1
  448. package/out/convention/index.d.ts +0 -106
  449. package/out/convention/index.d.ts.map +0 -1
  450. package/out/convention/index.js +0 -93
  451. package/out/convention/index.js.map +0 -1
  452. package/out/fst/index.d.ts.map +0 -1
  453. package/out/fst/index.js.map +0 -1
  454. package/out/fts/index.d.ts +0 -184
  455. package/out/fts/index.d.ts.map +0 -1
  456. package/out/fts/index.js +0 -277
  457. package/out/fts/index.js.map +0 -1
  458. package/out/geonames/index.d.ts.map +0 -1
  459. package/out/geonames/index.js.map +0 -1
  460. package/out/nsul/index.d.ts.map +0 -1
  461. package/out/nsul/index.js.map +0 -1
  462. package/out/poi/index.d.ts.map +0 -1
  463. package/out/poi/index.js.map +0 -1
  464. package/out/postal/index.d.ts.map +0 -1
  465. package/out/postal/index.js.map +0 -1
  466. package/out/street/centroid/index.d.ts +0 -40
  467. package/out/street/centroid/index.d.ts.map +0 -1
  468. package/out/street/centroid/index.js.map +0 -1
  469. package/out/street/index.d.ts.map +0 -1
  470. package/out/street/index.js.map +0 -1
  471. package/out/uprn/index.d.ts.map +0 -1
  472. package/out/uprn/index.js.map +0 -1
  473. /package/lib/{geonames/index.ts → geonames.ts} +0 -0
  474. /package/lib/{nsul/index.ts → nsul.ts} +0 -0
  475. /package/lib/{poi/index.ts → poi.ts} +0 -0
  476. /package/lib/{postal/index.ts → postal.ts} +0 -0
  477. /package/lib/{uprn/index.ts → uprn.ts} +0 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ * @file SQLite implementation of core's `AddressPointLookup`.
6
+ */
7
+ import { DatabaseClient } from "@mailwoman/sqlite/client";
8
+ import { hasTable, prepareGet } from "#sqlite-utils";
9
+ import { normalizeHouseNumberForKey, normalizeLocalityForKey, normalizeLocalityForKeyLocale, streetKeyVariants, streetLocaleForSurface, stripArrondissement, } from "#street/normalize";
10
+ /**
11
+ * The column list every prepared SELECT uses.
12
+ * It must match the fields of `AddressPointRow`.
13
+ */
14
+ const SELECT_COLS = "lat, lon, source, release, locality_norm, postcode";
15
+ /**
16
+ * Finds an address point by exact normalized `(street, number)` within a postcode,
17
+ * a locality, or a bounding box.
18
+ *
19
+ * Query normalization uses the extract's `streetLocale`, which must match the
20
+ * locale the extract was built with.
21
+ * Street matching is exact after normalization.
22
+ *
23
+ * Scopes are tried from most to least selective: postcode, locality, locality suffix, then bounding box.
24
+ * When several rows match, any one of them can answer, because unit siblings share the building coordinate.
25
+ */
26
+ export class AddressPointSqliteLookup {
27
+ #db;
28
+ #locale;
29
+ #localityKeys;
30
+ #byPostcode;
31
+ #byPostcodeLocality;
32
+ #byLocality;
33
+ /**
34
+ * This query matches the locality key by its suffix, for a `zh` query that gives the 鄉鎮市區 without its 縣市.
35
+ *
36
+ * The (street, number) index narrows the rows first, so the `LIKE` scans only rows that share the pair.
37
+ */
38
+ #byLocalityTail;
39
+ #byBbox;
40
+ /**
41
+ * @param dbPath Extract path.
42
+ * @param opts.streetLocale The street-normalization locale the extract was built with.
43
+ * A mismatch makes every key miss.
44
+ * @param opts.localityKeys Whether the extract's `locality_norm` holds full place names.
45
+ * With `"abbreviated"`, a row's locality can select a row but never rejects one.
46
+ * The US situs extract uses NAD city fields.
47
+ * Some counties abbreviate them (`addi` for Addison).
48
+ * Other counties replace them with the parent town.
49
+ *
50
+ * @defaultValue `"us"`
51
+ * @defaultValue `"abbreviated"` for `"us"` and `"full"` for every other locale.
52
+ */
53
+ constructor(dbPath, opts = {}) {
54
+ this.#db = new DatabaseClient(dbPath, { readOnly: true });
55
+ this.#locale = opts.streetLocale ?? "us";
56
+ this.#localityKeys = opts.localityKeys ?? (this.#locale === "us" ? "abbreviated" : "full");
57
+ // An extract without an `address_point` table, such as an interrupted build, makes every lookup miss.
58
+ if (hasTable(this.#db, "address_point")) {
59
+ this.#byPostcode = prepareGet(this.#db, `SELECT ${SELECT_COLS} FROM address_point
60
+ WHERE postcode = ? AND street_norm = ? AND number = ? LIMIT 1`);
61
+ this.#byPostcodeLocality = prepareGet(this.#db, `SELECT ${SELECT_COLS} FROM address_point
62
+ WHERE postcode = ? AND locality_norm = ? AND street_norm = ? AND number = ? LIMIT 1`);
63
+ this.#byLocality = prepareGet(this.#db, `SELECT ${SELECT_COLS} FROM address_point
64
+ WHERE locality_norm = ? AND street_norm = ? AND number = ? LIMIT 1`);
65
+ this.#byBbox = prepareGet(this.#db, `SELECT ${SELECT_COLS} FROM address_point
66
+ WHERE street_norm = ? AND number = ? AND lat BETWEEN ? AND ? AND lon BETWEEN ? AND ? LIMIT 1`);
67
+ this.#byLocalityTail = prepareGet(this.#db, `SELECT ${SELECT_COLS} FROM address_point
68
+ WHERE street_norm = ? AND number = ? AND locality_norm LIKE ? LIMIT 1`);
69
+ }
70
+ }
71
+ find(query) {
72
+ if (!this.#byPostcode || !this.#byLocality || !this.#byBbox)
73
+ return null;
74
+ const number = normalizeHouseNumberForKey(query.number, this.#locale);
75
+ if (!number)
76
+ return null;
77
+ // A `zh` extract keys locality as 縣市 + 鄉鎮市區.
78
+ // The parser tags 縣市 as `region` and 鄉鎮市區 as `subregion`.
79
+ // The Taiwanese register has no postcode, so this pair becomes the locality key.
80
+ // A query with only the 鄉鎮市區 matches the stored key by its suffix.
81
+ const scoped = this.#locale === "zh" && !query.locality && query.subregion
82
+ ? query.region
83
+ ? { ...query, locality: `${query.region}${query.subregion}` }
84
+ : { ...query, localityTail: normalizeLocalityForKeyLocale(query.subregion, "zh") }
85
+ : query;
86
+ // `streetKeyVariants` yields the literal key first.
87
+ // Each variant runs the full number fallback sequence.
88
+ // The first variant with a match wins.
89
+ let row = null;
90
+ for (const streetNorm of streetKeyVariants(query.street, streetLocaleForSurface(query.street, this.#locale))) {
91
+ row = this.#findForKey(streetNorm, number, scoped);
92
+ if (row)
93
+ break;
94
+ }
95
+ if (!row)
96
+ return null;
97
+ return {
98
+ lat: row.lat,
99
+ lon: row.lon,
100
+ source: row.source,
101
+ release: row.release,
102
+ localityNorm: row.locality_norm || null,
103
+ postcode: row.postcode || null,
104
+ };
105
+ }
106
+ /**
107
+ * Tries one normalized street key with the exact number, then fallback number forms.
108
+ * Each fallback runs only after the previous forms missed.
109
+ */
110
+ #findForKey(streetNorm, number, query) {
111
+ let row = this.#probe(streetNorm, number, query);
112
+ // The registers store one number per point, so a range such as "385-387" falls back to its low end.
113
+ if (!row) {
114
+ const low = /^(\d+[a-z]?)-\d+[a-z]?$/.exec(number)?.[1];
115
+ if (low) {
116
+ row = this.#probe(streetNorm, low, query);
117
+ }
118
+ }
119
+ // BAN stores a letter suffix as "3 a", while G-NAF and most OA sources store "3a".
120
+ // For a number of digits plus one letter, the lookup retries the other spacing
121
+ // and then the bare number.
122
+ if (!row) {
123
+ const joined = /^(\d+)\s+([a-z])$/.exec(number);
124
+ const spaced = /^(\d+)([a-z])$/.exec(number);
125
+ if (joined) {
126
+ row = this.#probe(streetNorm, `${joined[1]}${joined[2]}`, query) ?? this.#probe(streetNorm, joined[1], query);
127
+ }
128
+ else if (spaced) {
129
+ row = this.#probe(streetNorm, `${spaced[1]} ${spaced[2]}`, query) ?? this.#probe(streetNorm, spaced[1], query);
130
+ }
131
+ }
132
+ // The Taiwanese register stores `14之12` and `30附40` as numbers `14` and `30`.
133
+ // It stores the rest in `unit`.
134
+ // A query number that still includes the sub-number falls back to the base number.
135
+ // That result is approximate.
136
+ if (!row && this.#locale === "zh") {
137
+ const base = /^(\d+)(?:[之附]\d+)+$/u.exec(number)?.[1];
138
+ if (base) {
139
+ row = this.#probe(streetNorm, base, query);
140
+ }
141
+ }
142
+ return row;
143
+ }
144
+ /**
145
+ * Probes one (street, number) key by postcode, then locality, then locality suffix, then bounding box.
146
+ * Each scope runs only when the previous ones missed.
147
+ */
148
+ #probe(streetNorm, number, query) {
149
+ let row = null;
150
+ if (query.postcode) {
151
+ const postcode = query.postcode.trim();
152
+ const localityKey = query.locality ? this.#localityKey(query.locality) : null;
153
+ // One postcode can cover several places with the same street and number,
154
+ // so a row whose locality agrees with the query is tried first.
155
+ // The postcode-only row answers only if `#scopeContradicts` accepts it.
156
+ const agreeing = localityKey ? this.#byPostcodeLocality(postcode, localityKey, streetNorm, number) : null;
157
+ const candidate = agreeing ?? this.#byPostcode(postcode, streetNorm, number);
158
+ row = candidate && !this.#scopeContradicts(candidate, query) ? candidate : null;
159
+ }
160
+ if (!row && query.locality) {
161
+ row = this.#byLocality(this.#localityKey(query.locality), streetNorm, number);
162
+ }
163
+ if (!row && query.localityTail && this.#byLocalityTail) {
164
+ // A Han key contains no `%` or `_`, so the pattern matches a literal suffix.
165
+ row = this.#byLocalityTail(streetNorm, number, `%${query.localityTail}`);
166
+ }
167
+ // The bounding box serves extracts whose points have no postcode or locality, such as OSM.
168
+ if (!row && query.bbox) {
169
+ const b = query.bbox;
170
+ const candidate = this.#byBbox(streetNorm, number, b.minLat, b.maxLat, b.minLon, b.maxLon);
171
+ // A row with its own scope that the scoped probes missed is a different address in the same box.
172
+ row = candidate && !this.#scopeContradicts(candidate, query) ? candidate : null;
173
+ }
174
+ return row;
175
+ }
176
+ /**
177
+ * Folds the query's locality the way the extract's builder folded `locality_norm`.
178
+ *
179
+ * FR extracts key arrondissements at the base city, so "Paris 13e Arrondissement"
180
+ * and "Paris" produce the same key.
181
+ */
182
+ #localityKey(locality) {
183
+ if (this.#locale === "fr")
184
+ return stripArrondissement(normalizeLocalityForKey(locality));
185
+ return normalizeLocalityForKeyLocale(locality, this.#locale);
186
+ }
187
+ /**
188
+ * Returns whether the row's own postcode or locality differs from the query's.
189
+ *
190
+ * A row field that is empty never contradicts.
191
+ * The locality is compared only when the extract's `localityKeys` is `"full"`,
192
+ * because abbreviated keys would reject correct rows.
193
+ */
194
+ #scopeContradicts(row, query) {
195
+ if (query.postcode && row.postcode && row.postcode.trim() !== query.postcode.trim())
196
+ return true;
197
+ if (this.#localityKeys === "full" && query.locality && row.locality_norm) {
198
+ return row.locality_norm !== this.#localityKey(query.locality);
199
+ }
200
+ return false;
201
+ }
202
+ [Symbol.dispose]() {
203
+ this.#db[Symbol.dispose]();
204
+ }
205
+ }
206
+ //# sourceMappingURL=point.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"point.js","sourceRoot":"","sources":["../../lib/address/point.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
- export * from "#address/point/index";
6
+ export * from "#address/point";
7
7
  export * from "#address/point/interpolation";
8
8
  export * from "#address/point/schema";
9
- //# sourceMappingURL=index.js.map
9
+ //# sourceMappingURL=address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../lib/address.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uBAAuB,CAAA"}
@@ -3,7 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
- export * from "#address/point/index";
6
+ export * from "#address/point";
7
7
  export * from "#address/point/interpolation";
8
8
  export * from "#address/point/schema";
9
- //# sourceMappingURL=index.d.ts.map
9
+ //# sourceMappingURL=address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../lib/address.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uBAAuB,CAAA"}
@@ -3,85 +3,32 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Repair the truncated ancestry that {@link populateAncestors} (the parent_id closure in
7
- * unified-schema.ts) leaves wherever the closure dead-ends before reaching the top.
8
- *
9
- * Root cause (#440 / #832): a place that straddles multiple parents — New York City spans five
10
- * counties (its boroughs), London 30+ — carries `wof:parent_id = -4`, so the parent_id closure
11
- * dead-ends and the place gets NO region/county/country ancestry. The resolver's region-descendant
12
- * filter then can't reach it: given "New York, NY", NYC (with no NY-state ancestor) is excluded and
13
- * a correctly-parented namesake ("New York Mills", pop 3,190) wins over NYC's 8.8M. The same defect
14
- * orphans London, Singapore, and ~2,850 other localities — the most demo-visible queries.
15
- *
16
- * **The dead end is inherited by children (#1445).** Repairing the `-4` place itself does not repair
17
- * anything BELOW it: the closure walks Brooklyn → New York and stops, because New York's own
18
- * `parent_id` is `-4`. Brooklyn-the-borough (pop 2.5M) therefore carried exactly two ancestor rows —
19
- * itself and New York — with no county, region or country, and the only US locality-tier place named
20
- * "Brooklyn" that survived a New-York-State descendant filter was Pillar Point, a Jefferson County
21
- * hamlet 411 km away carrying "Brooklyn" as an alternate name. All five NYC boroughs, every London
22
- * borough and Hyderabad's zones were in the same state.
23
- *
24
- * So the candidate test is NOT "has only a self ancestor" — that misses every child of a repaired
25
- * place, which by construction has two. It is **"has no `country`-tier ancestor"**. Country is the
26
- * universal terminal for every non-{@link TOP_PLACETYPES} placetype, so its absence is exactly the
27
- * signal that the chain dead-ended somewhere, at whatever depth. On a wide-coverage build this
28
- * selects ~24k places against 2.55M rows.
29
- *
30
- * A place whose `wof:hierarchy` genuinely stops short is NOT a candidate and needs no repair: the
31
- * source is the authority on what a place should have. American Samoa's localities, for instance,
32
- * have `{country_id, locality_id}` and no region in WOF itself — the artifact matching that is
33
- * correct, not truncated.
34
- *
35
- * The authoritative hierarchy IS in the source geojson: `wof:hierarchy` is an array of branches,
36
- * each a `<placetype>_id` → id map (region_id, county_id, country_id, …), fully populated even when
37
- * parent_id is -4. This reads it for every candidate and inserts the missing ancestor rows (one per
38
- * distinct ancestor across branches).
39
- *
40
- * MUST run AFTER populateAncestors and BEFORE the build freezes (VACUUM INTO), so the rows land in
41
- * the shipped artifact — `scripts/build-unified-wof.ts` Phase 3 calls it inline. The standalone
42
- * `scripts/backfill-ancestors-from-hierarchy.ts` is a thin CLI over the same function for ad-hoc
43
- * repair of an already-built DB. Idempotent by the per-pair existence check, not by the candidate
44
- * test: each (id, ancestor_id) is inserted at most once, so a second run over the same DB adds
45
- * nothing.
6
+ * Repair the truncated ancestry left by the `parent_id` closure. Must run after `populateAncestors` and before the build freezes.
46
7
  */
47
8
  import type { DatabaseClient } from "@mailwoman/sqlite/client";
48
- import { type PathBuilderLike } from "path-ts";
9
+ import { PathBuilder, type PathBuilderLike } from "path-ts";
49
10
  import type { WOFDatabase } from "#schema";
50
11
  export interface AncestryBackfillResult {
51
- /**
52
- * Places that gained at least one ancestor row.
53
- */
54
12
  placesFixed: number;
55
- /**
56
- * Total ancestor rows inserted.
57
- */
58
13
  rowsAdded: number;
59
14
  /**
60
- * Candidates whose source geojson could not be found (non-WOF backfilled places, or repos not present locally) —
61
- * skipped, not an error.
15
+ * Candidates whose source geojson was not found (non-WOF backfilled places or absent repos),
16
+ * skipped rather than treated as an error.
62
17
  */
63
18
  noGeojson: number;
64
19
  }
65
20
  /**
66
- * Discover the `data` directories under a WOF repos root that hold attached geojson, e.g.
67
- * `<root>/whosonfirst-data/whosonfirst-data-admin-us/data`. Resolves an id to its geojson via these roots. Accepts both
68
- * the nested lab layout (a `whosonfirst-data` group dir holding the admin repos) and a flat layout (admin repos
69
- * directly under the root); searches at most two directory levels deep.
21
+ * Discover the `data` directories under a WOF repos root that hold attached geojson,
22
+ * accepting both the nested lab layout and a flat layout at most two directory levels deep.
70
23
  */
71
- export declare function discoverAdminDataRoots(reposRoot: PathBuilderLike): Promise<string[]>;
24
+ export declare function discoverAdminDataRoots(reposRoot: PathBuilderLike): Promise<PathBuilder[]>;
72
25
  /**
73
- * Insert missing ancestor rows for every place whose ancestry chain dead-ended before reaching a country, by reading
74
- * `wof:hierarchy` from its source geojson under `geojsonRoots` (see {@link discoverAdminDataRoots}). Runs inside a
75
- * single transaction; caller owns connection lifecycle (open, WAL checkpoint, close).
26
+ * Insert missing ancestor rows for places whose ancestry chain ended before reaching a country.
76
27
  *
77
- * `opts.maxID` bounds the candidate scan to ids BELOW it — pass the synthetic-id base (`OVERTURE_ID_BASE`, 8e12) so the
78
- * backfill considers only real WOF places. Overture/GeoNames rows carry synthetic ids and have NO `wof:hierarchy`
79
- * geojson, so probing them is pure waste: on a wide-coverage DB the country-less set is millions of Overture/GeoNames
80
- * leaf localities, and the per-candidate geojson probe across every repo root turns a seconds-long WOF-only pass into a
81
- * ~40-minute one (their ancestry comes from the parent_id closure, not this backfill). Correctness-preserving — the
82
- * skipped rows would have `noGeojson`-skipped anyway. Omit `maxID` (default) for the legacy WOF-only DBs.
28
+ * The function reads `wof:hierarchy` and runs in one transaction under the caller's connection.
29
+ * `opts.maxID` bounds the scan to avoid probing synthetic-id Overture and GeoNames rows.
83
30
  */
84
- export declare function backfillAncestorsFromHierarchy(db: DatabaseClient<WOFDatabase>, geojsonRoots: readonly string[], opts?: {
31
+ export declare function backfillAncestorsFromHierarchy(db: DatabaseClient<WOFDatabase>, geojsonRoots: readonly PathBuilderLike[], opts?: {
85
32
  maxID?: number;
86
33
  }): Promise<AncestryBackfillResult>;
87
34
  //# sourceMappingURL=backfill.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../lib/ancestry/backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAGjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAO1C,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA8B1F;AAYD;;;;;;;;;;;GAWG;AACH,wBAAsB,8BAA8B,CACnD,EAAE,EAAE,cAAc,CAAC,WAAW,CAAC,EAC/B,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3B,OAAO,CAAC,sBAAsB,CAAC,CAkHjC"}
1
+ {"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../lib/ancestry/backfill.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAG3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,MAAM,WAAW,sBAAsB;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA8B/F;AAUD;;;;;GAKG;AACH,wBAAsB,8BAA8B,CACnD,EAAE,EAAE,cAAc,CAAC,WAAW,CAAC,EAC/B,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3B,OAAO,CAAC,sBAAsB,CAAC,CA0GjC"}
@@ -3,59 +3,15 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Repair the truncated ancestry that {@link populateAncestors} (the parent_id closure in
7
- * unified-schema.ts) leaves wherever the closure dead-ends before reaching the top.
8
- *
9
- * Root cause (#440 / #832): a place that straddles multiple parents — New York City spans five
10
- * counties (its boroughs), London 30+ — carries `wof:parent_id = -4`, so the parent_id closure
11
- * dead-ends and the place gets NO region/county/country ancestry. The resolver's region-descendant
12
- * filter then can't reach it: given "New York, NY", NYC (with no NY-state ancestor) is excluded and
13
- * a correctly-parented namesake ("New York Mills", pop 3,190) wins over NYC's 8.8M. The same defect
14
- * orphans London, Singapore, and ~2,850 other localities — the most demo-visible queries.
15
- *
16
- * **The dead end is inherited by children (#1445).** Repairing the `-4` place itself does not repair
17
- * anything BELOW it: the closure walks Brooklyn → New York and stops, because New York's own
18
- * `parent_id` is `-4`. Brooklyn-the-borough (pop 2.5M) therefore carried exactly two ancestor rows —
19
- * itself and New York — with no county, region or country, and the only US locality-tier place named
20
- * "Brooklyn" that survived a New-York-State descendant filter was Pillar Point, a Jefferson County
21
- * hamlet 411 km away carrying "Brooklyn" as an alternate name. All five NYC boroughs, every London
22
- * borough and Hyderabad's zones were in the same state.
23
- *
24
- * So the candidate test is NOT "has only a self ancestor" — that misses every child of a repaired
25
- * place, which by construction has two. It is **"has no `country`-tier ancestor"**. Country is the
26
- * universal terminal for every non-{@link TOP_PLACETYPES} placetype, so its absence is exactly the
27
- * signal that the chain dead-ended somewhere, at whatever depth. On a wide-coverage build this
28
- * selects ~24k places against 2.55M rows.
29
- *
30
- * A place whose `wof:hierarchy` genuinely stops short is NOT a candidate and needs no repair: the
31
- * source is the authority on what a place should have. American Samoa's localities, for instance,
32
- * have `{country_id, locality_id}` and no region in WOF itself — the artifact matching that is
33
- * correct, not truncated.
34
- *
35
- * The authoritative hierarchy IS in the source geojson: `wof:hierarchy` is an array of branches,
36
- * each a `<placetype>_id` → id map (region_id, county_id, country_id, …), fully populated even when
37
- * parent_id is -4. This reads it for every candidate and inserts the missing ancestor rows (one per
38
- * distinct ancestor across branches).
39
- *
40
- * MUST run AFTER populateAncestors and BEFORE the build freezes (VACUUM INTO), so the rows land in
41
- * the shipped artifact — `scripts/build-unified-wof.ts` Phase 3 calls it inline. The standalone
42
- * `scripts/backfill-ancestors-from-hierarchy.ts` is a thin CLI over the same function for ad-hoc
43
- * repair of an already-built DB. Idempotent by the per-pair existence check, not by the candidate
44
- * test: each (id, ancestor_id) is inserted at most once, so a second run over the same DB adds
45
- * nothing.
6
+ * Repair the truncated ancestry left by the `parent_id` closure. Must run after `populateAncestors` and before the build freezes.
46
7
  */
47
8
  import { readWOFFeature } from "@mailwoman/core/resources/whosonfirst";
48
- import { join, resolvePath } from "path-ts";
9
+ import { PathBuilder } from "path-ts";
49
10
  import { Globerator } from "spliterator/node/fs";
50
- /**
51
- * Genuinely top-level placetypes — they never have (or need) an ancestor, so skip them.
52
- */
53
11
  const TOP_PLACETYPES = new Set(["country", "continent", "empire", "ocean", "marinearea", "planet"]);
54
12
  /**
55
- * Discover the `data` directories under a WOF repos root that hold attached geojson, e.g.
56
- * `<root>/whosonfirst-data/whosonfirst-data-admin-us/data`. Resolves an id to its geojson via these roots. Accepts both
57
- * the nested lab layout (a `whosonfirst-data` group dir holding the admin repos) and a flat layout (admin repos
58
- * directly under the root); searches at most two directory levels deep.
13
+ * Discover the `data` directories under a WOF repos root that hold attached geojson,
14
+ * accepting both the nested lab layout and a flat layout at most two directory levels deep.
59
15
  */
60
16
  export async function discoverAdminDataRoots(reposRoot) {
61
17
  const roots = [];
@@ -72,7 +28,7 @@ export async function discoverAdminDataRoots(reposRoot) {
72
28
  return;
73
29
  }
74
30
  for (const name of names) {
75
- const child = join(dir, name);
31
+ const child = dir(name);
76
32
  if (name === "data") {
77
33
  roots.push(child);
78
34
  }
@@ -81,36 +37,25 @@ export async function discoverAdminDataRoots(reposRoot) {
81
37
  }
82
38
  }
83
39
  };
84
- await visit(resolvePath(reposRoot), 0);
40
+ await visit(PathBuilder.from(reposRoot), 0);
85
41
  return roots;
86
42
  }
87
- // `<placetype>_id` key → ancestor placetype. WOF hierarchy keys are e.g. region_id, county_id. Self
88
- // is filtered downstream by the `aid === id` check, so we do NOT special-case locality here: for a
89
- // locality candidate `locality_id` IS self (dropped by aid===id), but for a neighbourhood candidate
90
- // `locality_id` is its PARENT locality — a real ancestor we must keep.
43
+ // The `aid === id` check filters out a place's own `locality_id`.
44
+ // For a neighborhood, that id identifies a real ancestor.
91
45
  function placetypeFromKey(key) {
92
46
  if (!key.endsWith("_id"))
93
47
  return null;
94
48
  return key.slice(0, -3);
95
49
  }
96
50
  /**
97
- * Insert missing ancestor rows for every place whose ancestry chain dead-ended before reaching a country, by reading
98
- * `wof:hierarchy` from its source geojson under `geojsonRoots` (see {@link discoverAdminDataRoots}). Runs inside a
99
- * single transaction; caller owns connection lifecycle (open, WAL checkpoint, close).
51
+ * Insert missing ancestor rows for places whose ancestry chain ended before reaching a country.
100
52
  *
101
- * `opts.maxID` bounds the candidate scan to ids BELOW it — pass the synthetic-id base (`OVERTURE_ID_BASE`, 8e12) so the
102
- * backfill considers only real WOF places. Overture/GeoNames rows carry synthetic ids and have NO `wof:hierarchy`
103
- * geojson, so probing them is pure waste: on a wide-coverage DB the country-less set is millions of Overture/GeoNames
104
- * leaf localities, and the per-candidate geojson probe across every repo root turns a seconds-long WOF-only pass into a
105
- * ~40-minute one (their ancestry comes from the parent_id closure, not this backfill). Correctness-preserving — the
106
- * skipped rows would have `noGeojson`-skipped anyway. Omit `maxID` (default) for the legacy WOF-only DBs.
53
+ * The function reads `wof:hierarchy` and runs in one transaction under the caller's connection.
54
+ * `opts.maxID` bounds the scan to avoid probing synthetic-id Overture and GeoNames rows.
107
55
  */
108
56
  export async function backfillAncestorsFromHierarchy(db, geojsonRoots, opts = {}) {
109
57
  const maxID = opts.maxID ?? Number.MAX_SAFE_INTEGER;
110
- // "No country-tier ancestor" is the dead-end signal at any depth — see the module docstring. The
111
- // earlier "<= 1 ancestor row" test only caught the dead end's origin, never the children that
112
- // inherit it (a child of a repaired -4 place has two rows: itself and that parent) (#1445).
113
- // The id bound is stated first so SQLite prunes by the PK index before the NOT EXISTS runs at all.
58
+ // The id bound is stated first so SQLite prunes by the PK index before the not-exists runs.
114
59
  const candidateBase = db
115
60
  .selectFrom("spr")
116
61
  .where("id", "<", maxID)
@@ -120,12 +65,8 @@ export async function backfillAncestorsFromHierarchy(db, geojsonRoots, opts = {}
120
65
  .whereRef("a.id", "=", "spr.id")
121
66
  .where("a.ancestor_placetype", "=", "country"))));
122
67
  const candidates = await candidateBase.select(["id", "placetype"]).execute();
123
- // Every candidate's existing ancestors in ONE query rather than an indexed read each. The widened
124
- // candidate test made that per-candidate read the dominant cost of the pass, and the set is bounded:
125
- // a candidate reaching this point has a handful of rows at most. The candidate set rides in as the
126
- // SAME predicate re-issued as a subquery, never a materialized `IN (?, ?, …)` list — node:sqlite
127
- // caps a statement at 32,766 bound variables and the wide-coverage build has 67,521 candidates
128
- // (measured 2026-08-04).
68
+ // Keep the candidate set as a subquery instead of materializing an `IN` list.
69
+ // node:sqlite limits bound variables to 32,766.
129
70
  const alreadyPresent = new Map();
130
71
  for (const row of await db
131
72
  .selectFrom("ancestors")
@@ -155,7 +96,6 @@ export async function backfillAncestorsFromHierarchy(db, geojsonRoots, opts = {}
155
96
  }
156
97
  continue;
157
98
  }
158
- // Collect distinct (ancestor_id, placetype) across all hierarchy branches, excluding self.
159
99
  const seen = new Map();
160
100
  for (const branch of hierarchy) {
161
101
  for (const [key, val] of Object.entries(branch)) {
@@ -1 +1 @@
1
- {"version":3,"file":"backfill.js","sourceRoot":"","sources":["../../lib/ancestry/backfill.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backfill.js","sourceRoot":"","sources":["../../lib/ancestry/backfill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * The shared ancestor-lineage walk over the WOF `ancestors` table: one place's containment chain
7
+ * joined with `spr` for canonical names and centroids, ordered nearest-first with the deepest
8
+ * placetype first and the country last.
9
+ *
10
+ * The reverse geocoder and `WOFSQLitePlaceLookup.ancestors()` share this walk. Placetype
11
+ * specificity lives here in `PLACETYPE_DEPTH`, a single TypeScript map that extends below
12
+ * `localadmin` so locality, borough, neighborhood and microhood rank correctly. Forward
13
+ * resolution rarely sees those as ancestor placetypes, while reverse geocoding always does.
14
+ */
15
+ import type { DatabaseClient } from "@mailwoman/sqlite/client";
16
+ /**
17
+ * WOF placetype → containment depth, coarsest = 1.
18
+ *
19
+ * Higher = finer. Placetypes we never resolve (continent, empire, …) map to 0 and sort last.
20
+ *
21
+ * This differs from the FST's `PLACETYPE_ORDER` (fst-serialize.ts), which is a serialization order.
22
+ * This one is containment depth.
23
+ */
24
+ export declare const PLACETYPE_DEPTH: Readonly<Record<string, number>>;
25
+ /**
26
+ * Containment depth for a placetype, 0 when unknown (sorts coarsest).
27
+ */
28
+ export declare function placetypeDepth(placetype: string): number;
29
+ /**
30
+ * One ancestor row, enriched with the `spr` columns both consumers need.
31
+ */
32
+ export interface AncestorPlaceRow {
33
+ id: number;
34
+ placetype: string;
35
+ name: string;
36
+ country: string;
37
+ lat: number;
38
+ lon: number;
39
+ }
40
+ /**
41
+ * The ancestor lineage of `id`, self excluded, nearest-first.
42
+ *
43
+ * @returns `[]` when the place has no recorded ancestry.
44
+ * Not memoized here.
45
+ * `WOFSQLitePlaceLookup` keeps its own per-id cache.
46
+ */
47
+ export declare function ancestorLineage<DB>(db: DatabaseClient<DB>, id: number, schemaName?: string): AncestorPlaceRow[];
48
+ export * from "#ancestry/backfill";
49
+ //# sourceMappingURL=ancestry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ancestry.d.ts","sourceRoot":"","sources":["../lib/ancestry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAY5D,CAAA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACX;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,SAAS,GAAG,gBAAgB,EAAE,CAc/G;AAED,cAAc,oBAAoB,CAAA"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * The shared ancestor-lineage walk over the WOF `ancestors` table: one place's containment chain
7
+ * joined with `spr` for canonical names and centroids, ordered nearest-first with the deepest
8
+ * placetype first and the country last.
9
+ *
10
+ * The reverse geocoder and `WOFSQLitePlaceLookup.ancestors()` share this walk. Placetype
11
+ * specificity lives here in `PLACETYPE_DEPTH`, a single TypeScript map that extends below
12
+ * `localadmin` so locality, borough, neighborhood and microhood rank correctly. Forward
13
+ * resolution rarely sees those as ancestor placetypes, while reverse geocoding always does.
14
+ */
15
+ import { allRows } from "@mailwoman/core/utils";
16
+ /**
17
+ * WOF placetype → containment depth, coarsest = 1.
18
+ *
19
+ * Higher = finer. Placetypes we never resolve (continent, empire, …) map to 0 and sort last.
20
+ *
21
+ * This differs from the FST's `PLACETYPE_ORDER` (fst-serialize.ts), which is a serialization order.
22
+ * This one is containment depth.
23
+ */
24
+ export const PLACETYPE_DEPTH = {
25
+ country: 1,
26
+ macroregion: 2,
27
+ region: 3,
28
+ macrocounty: 4,
29
+ county: 5,
30
+ localadmin: 6,
31
+ locality: 7,
32
+ borough: 8,
33
+ macrohood: 9,
34
+ neighbourhood: 10,
35
+ microhood: 11,
36
+ };
37
+ /**
38
+ * Containment depth for a placetype, 0 when unknown (sorts coarsest).
39
+ */
40
+ export function placetypeDepth(placetype) {
41
+ return PLACETYPE_DEPTH[placetype] ?? 0;
42
+ }
43
+ /**
44
+ * The ancestor lineage of `id`, self excluded, nearest-first.
45
+ *
46
+ * @returns `[]` when the place has no recorded ancestry.
47
+ * Not memoized here.
48
+ * `WOFSQLitePlaceLookup` keeps its own per-id cache.
49
+ */
50
+ export function ancestorLineage(db, id, schemaName = "main") {
51
+ const rows = allRows(db.prepare(`SELECT a.ancestor_id AS id, a.ancestor_placetype AS placetype, s.name AS name,
52
+ s.country AS country, s.latitude AS lat, s.longitude AS lon
53
+ FROM ${schemaName}.ancestors a JOIN ${schemaName}.spr s ON s.id = a.ancestor_id
54
+ WHERE a.id = ? AND a.ancestor_id != a.id`), id);
55
+ rows.sort((a, b) => placetypeDepth(b.placetype) - placetypeDepth(a.placetype));
56
+ return rows;
57
+ }
58
+ export * from "#ancestry/backfill";
59
+ //# sourceMappingURL=ancestry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ancestry.js","sourceRoot":"","sources":["../lib/ancestry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAG/C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAqC;IAChE,OAAO,EAAE,CAAC;IACV,WAAW,EAAE,CAAC;IACd,MAAM,EAAE,CAAC;IACT,WAAW,EAAE,CAAC;IACd,MAAM,EAAE,CAAC;IACT,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,CAAC;IACZ,aAAa,EAAE,EAAE;IACjB,SAAS,EAAE,EAAE;CACb,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC/C,OAAO,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAK,EAAsB,EAAE,EAAU,EAAE,UAAU,GAAG,MAAM;IAC1F,MAAM,IAAI,GAAG,OAAO,CACnB,EAAE,CAAC,OAAO,CACT;;UAEO,UAAU,qBAAqB,UAAU;4CACP,CACzC,EACD,EAAE,CACF,CAAA;IAED,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;IAE9E,OAAO,IAAI,CAAA;AACZ,CAAC;AAED,cAAc,oBAAoB,CAAA"}