@mailwoman/corpus 8.6.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/out/src/adapter.d.ts +41 -0
- package/out/src/adapter.d.ts.map +1 -1
- package/out/src/adapter.js +46 -1
- package/out/src/adapter.js.map +1 -1
- package/out/src/adapters/ban/adapter.d.ts +4 -3
- package/out/src/adapters/ban/adapter.d.ts.map +1 -1
- package/out/src/adapters/ban/adapter.js +60 -67
- package/out/src/adapters/ban/adapter.js.map +1 -1
- package/out/src/adapters/ban/street-decompose.d.ts.map +1 -1
- package/out/src/adapters/ban/street-decompose.js +18 -25
- package/out/src/adapters/ban/street-decompose.js.map +1 -1
- package/out/src/adapters/fcc-bdc/adapter.d.ts +0 -6
- package/out/src/adapters/fcc-bdc/adapter.d.ts.map +1 -1
- package/out/src/adapters/fcc-bdc/adapter.js +2 -24
- package/out/src/adapters/fcc-bdc/adapter.js.map +1 -1
- package/out/src/adapters/geonames/adapter.d.ts.map +1 -1
- package/out/src/adapters/geonames/adapter.js +70 -76
- package/out/src/adapters/geonames/adapter.js.map +1 -1
- package/out/src/adapters/geonames-postal/adapter.d.ts.map +1 -1
- package/out/src/adapters/geonames-postal/adapter.js +44 -49
- package/out/src/adapters/geonames-postal/adapter.js.map +1 -1
- package/out/src/adapters/gnaf/adapter.d.ts.map +1 -1
- package/out/src/adapters/gnaf/adapter.js +4 -7
- package/out/src/adapters/gnaf/adapter.js.map +1 -1
- package/out/src/adapters/gnaf/assemble.d.ts.map +1 -1
- package/out/src/adapters/gnaf/assemble.js +6 -11
- package/out/src/adapters/gnaf/assemble.js.map +1 -1
- package/out/src/adapters/openaddresses/adapter.d.ts.map +1 -1
- package/out/src/adapters/openaddresses/adapter.js +2 -7
- package/out/src/adapters/openaddresses/adapter.js.map +1 -1
- package/out/src/adapters/overture/adapter.d.ts.map +1 -1
- package/out/src/adapters/overture/adapter.js +3 -7
- package/out/src/adapters/overture/adapter.js.map +1 -1
- package/out/src/adapters/state-hi-schools/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-hi-schools/adapter.js +55 -73
- package/out/src/adapters/state-hi-schools/adapter.js.map +1 -1
- package/out/src/adapters/state-ia-contractors/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-ia-contractors/adapter.js +58 -76
- package/out/src/adapters/state-ia-contractors/adapter.js.map +1 -1
- package/out/src/adapters/state-ny-notaries/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-ny-notaries/adapter.js +67 -85
- package/out/src/adapters/state-ny-notaries/adapter.js.map +1 -1
- package/out/src/adapters/state-tx-notaries/adapter.d.ts.map +1 -1
- package/out/src/adapters/state-tx-notaries/adapter.js +69 -87
- package/out/src/adapters/state-tx-notaries/adapter.js.map +1 -1
- package/out/src/adapters/synth-po-box/adapter.d.ts.map +1 -1
- package/out/src/adapters/synth-po-box/adapter.js +7 -15
- package/out/src/adapters/synth-po-box/adapter.js.map +1 -1
- package/out/src/adapters/tiger/street-decompose.d.ts.map +1 -1
- package/out/src/adapters/tiger/street-decompose.js +18 -27
- package/out/src/adapters/tiger/street-decompose.js.map +1 -1
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.d.ts +3 -3
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.js +62 -80
- package/out/src/adapters/usgov-hrsa-fqhc/adapter.js.map +1 -1
- package/out/src/adapters/usgov-imls-pls/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-imls-pls/adapter.js +60 -82
- package/out/src/adapters/usgov-imls-pls/adapter.js.map +1 -1
- package/out/src/adapters/usgov-irs-bmf/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-irs-bmf/adapter.js +58 -65
- package/out/src/adapters/usgov-irs-bmf/adapter.js.map +1 -1
- package/out/src/adapters/usgov-nad/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-nad/adapter.js +5 -8
- package/out/src/adapters/usgov-nad/adapter.js.map +1 -1
- package/out/src/adapters/usgov-nppes/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-nppes/adapter.js +58 -76
- package/out/src/adapters/usgov-nppes/adapter.js.map +1 -1
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.d.ts.map +1 -1
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.js +51 -71
- package/out/src/adapters/usgov-samhsa-treatment-locator/adapter.js.map +1 -1
- package/out/src/adapters/wof-admin-jp/adapter.d.ts.map +1 -1
- package/out/src/adapters/wof-admin-jp/adapter.js +24 -6
- package/out/src/adapters/wof-admin-jp/adapter.js.map +1 -1
- package/out/src/build.d.ts.map +1 -1
- package/out/src/build.js +2 -1
- package/out/src/build.js.map +1 -1
- package/out/src/golden.d.ts +5 -0
- package/out/src/golden.d.ts.map +1 -1
- package/out/src/golden.js +23 -9
- package/out/src/golden.js.map +1 -1
- package/out/src/parquet-wrapper/reader.d.ts +8 -0
- package/out/src/parquet-wrapper/reader.d.ts.map +1 -1
- package/out/src/parquet-wrapper/reader.js +16 -0
- package/out/src/parquet-wrapper/reader.js.map +1 -1
- package/out/src/parquet-wrapper/schema.d.ts +4 -0
- package/out/src/parquet-wrapper/schema.d.ts.map +1 -1
- package/out/src/parquet-wrapper/schema.js.map +1 -1
- package/out/src/parquet.d.ts.map +1 -1
- package/out/src/parquet.js +2 -13
- package/out/src/parquet.js.map +1 -1
- package/out/src/shard-recipes/anchor-absorption.d.ts.map +1 -1
- package/out/src/shard-recipes/anchor-absorption.js +2 -1
- package/out/src/shard-recipes/anchor-absorption.js.map +1 -1
- package/out/src/shard-recipes/country-balanced.d.ts.map +1 -1
- package/out/src/shard-recipes/country-balanced.js +68 -60
- package/out/src/shard-recipes/country-balanced.js.map +1 -1
- package/out/src/shard-recipes/fr-fragment.d.ts.map +1 -1
- package/out/src/shard-recipes/fr-fragment.js +8 -5
- package/out/src/shard-recipes/fr-fragment.js.map +1 -1
- package/out/src/shard-recipes/fr-order.d.ts.map +1 -1
- package/out/src/shard-recipes/fr-order.js +14 -58
- package/out/src/shard-recipes/fr-order.js.map +1 -1
- package/out/src/shard-recipes/german.d.ts.map +1 -1
- package/out/src/shard-recipes/german.js +11 -58
- package/out/src/shard-recipes/german.js.map +1 -1
- package/out/src/shard-recipes/index.d.ts.map +1 -1
- package/out/src/shard-recipes/index.js +2 -0
- package/out/src/shard-recipes/index.js.map +1 -1
- package/out/src/shard-recipes/intersection.d.ts +2 -2
- package/out/src/shard-recipes/intersection.d.ts.map +1 -1
- package/out/src/shard-recipes/intersection.js +24 -62
- package/out/src/shard-recipes/intersection.js.map +1 -1
- package/out/src/shard-recipes/locale.d.ts.map +1 -1
- package/out/src/shard-recipes/locale.js +14 -16
- package/out/src/shard-recipes/locale.js.map +1 -1
- package/out/src/shard-recipes/no-fragment.d.ts.map +1 -1
- package/out/src/shard-recipes/no-fragment.js +8 -5
- package/out/src/shard-recipes/no-fragment.js.map +1 -1
- package/out/src/shard-recipes/no-street-led.d.ts.map +1 -1
- package/out/src/shard-recipes/no-street-led.js +8 -5
- package/out/src/shard-recipes/no-street-led.js.map +1 -1
- package/out/src/shard-recipes/po-box-cedex.d.ts +3 -3
- package/out/src/shard-recipes/po-box-cedex.d.ts.map +1 -1
- package/out/src/shard-recipes/po-box-cedex.js +51 -94
- package/out/src/shard-recipes/po-box-cedex.js.map +1 -1
- package/out/src/shard-recipes/scaffold.d.ts +59 -9
- package/out/src/shard-recipes/scaffold.d.ts.map +1 -1
- package/out/src/shard-recipes/scaffold.js +51 -30
- package/out/src/shard-recipes/scaffold.js.map +1 -1
- package/out/src/shard-recipes/street-affix.d.ts.map +1 -1
- package/out/src/shard-recipes/street-affix.js +56 -82
- package/out/src/shard-recipes/street-affix.js.map +1 -1
- package/out/src/shard-recipes/sub-venue-sources.d.ts +231 -0
- package/out/src/shard-recipes/sub-venue-sources.d.ts.map +1 -0
- package/out/src/shard-recipes/sub-venue-sources.js +669 -0
- package/out/src/shard-recipes/sub-venue-sources.js.map +1 -0
- package/out/src/shard-recipes/sub-venue.d.ts +269 -0
- package/out/src/shard-recipes/sub-venue.d.ts.map +1 -0
- package/out/src/shard-recipes/sub-venue.js +709 -0
- package/out/src/shard-recipes/sub-venue.js.map +1 -0
- package/out/src/shard-recipes/unit.d.ts +1 -1
- package/out/src/shard-recipes/unit.d.ts.map +1 -1
- package/out/src/shard-recipes/unit.js +22 -64
- package/out/src/shard-recipes/unit.js.map +1 -1
- package/out/src/split.d.ts +7 -0
- package/out/src/split.d.ts.map +1 -1
- package/out/src/split.js +7 -0
- package/out/src/split.js.map +1 -1
- package/out/src/synthesize.d.ts.map +1 -1
- package/out/src/synthesize.js +1 -12
- package/out/src/synthesize.js.map +1 -1
- package/out/src/tools/align-shard.d.ts.map +1 -1
- package/out/src/tools/align-shard.js +3 -7
- package/out/src/tools/align-shard.js.map +1 -1
- package/out/src/tools/audit.d.ts.map +1 -1
- package/out/src/tools/audit.js +4 -4
- package/out/src/tools/audit.js.map +1 -1
- package/out/src/tools/corpus-stats.d.ts +2 -2
- package/out/src/tools/corpus-stats.d.ts.map +1 -1
- package/out/src/tools/corpus-stats.js +18 -31
- package/out/src/tools/corpus-stats.js.map +1 -1
- package/out/src/tools/fetch/download.d.ts.map +1 -1
- package/out/src/tools/fetch/download.js +5 -6
- package/out/src/tools/fetch/download.js.map +1 -1
- package/out/src/tools/fetch/imls-pls.d.ts.map +1 -1
- package/out/src/tools/fetch/imls-pls.js +2 -2
- package/out/src/tools/fetch/imls-pls.js.map +1 -1
- package/out/src/tools/fetch/index.d.ts +14 -1
- package/out/src/tools/fetch/index.d.ts.map +1 -1
- package/out/src/tools/fetch/index.js +14 -1
- package/out/src/tools/fetch/index.js.map +1 -1
- package/out/src/tools/fetch/nad.d.ts +1 -1
- package/out/src/tools/fetch/nad.js +1 -1
- package/out/src/tools/fetch/nppes.d.ts.map +1 -1
- package/out/src/tools/fetch/nppes.js +2 -1
- package/out/src/tools/fetch/nppes.js.map +1 -1
- package/out/src/tools/fetch/openaddresses.d.ts +1 -1
- package/out/src/tools/fetch/openaddresses.js +1 -1
- package/out/src/tools/fetch/ourairports.d.ts +45 -0
- package/out/src/tools/fetch/ourairports.d.ts.map +1 -0
- package/out/src/tools/fetch/ourairports.js +123 -0
- package/out/src/tools/fetch/ourairports.js.map +1 -0
- package/out/src/tools/fetch/wikidata-subvenue.d.ts +171 -0
- package/out/src/tools/fetch/wikidata-subvenue.d.ts.map +1 -0
- package/out/src/tools/fetch/wikidata-subvenue.js +275 -0
- package/out/src/tools/fetch/wikidata-subvenue.js.map +1 -0
- package/out/src/tools/golden-expand.d.ts.map +1 -1
- package/out/src/tools/golden-expand.js +18 -16
- package/out/src/tools/golden-expand.js.map +1 -1
- package/out/src/tools/golden-promote.d.ts.map +1 -1
- package/out/src/tools/golden-promote.js +12 -6
- package/out/src/tools/golden-promote.js.map +1 -1
- package/out/src/tools/golden-relabel-street.d.ts +196 -0
- package/out/src/tools/golden-relabel-street.d.ts.map +1 -0
- package/out/src/tools/golden-relabel-street.js +513 -0
- package/out/src/tools/golden-relabel-street.js.map +1 -0
- package/out/src/tools/index.d.ts +4 -0
- package/out/src/tools/index.d.ts.map +1 -1
- package/out/src/tools/index.js +4 -0
- package/out/src/tools/index.js.map +1 -1
- package/out/src/tools/jsonl-to-parquet.d.ts.map +1 -1
- package/out/src/tools/jsonl-to-parquet.js +3 -2
- package/out/src/tools/jsonl-to-parquet.js.map +1 -1
- package/out/src/tools/lint-shard-vocab.d.ts.map +1 -1
- package/out/src/tools/lint-shard-vocab.js +3 -2
- package/out/src/tools/lint-shard-vocab.js.map +1 -1
- package/out/src/tools/lint-shard.d.ts +3 -3
- package/out/src/tools/lint-shard.d.ts.map +1 -1
- package/out/src/tools/lint-shard.js +23 -32
- package/out/src/tools/lint-shard.js.map +1 -1
- package/out/src/tools/overlay-manifest.d.ts.map +1 -1
- package/out/src/tools/overlay-manifest.js +2 -1
- package/out/src/tools/overlay-manifest.js.map +1 -1
- package/out/src/tools/overture-subvenue.d.ts +112 -0
- package/out/src/tools/overture-subvenue.d.ts.map +1 -0
- package/out/src/tools/overture-subvenue.js +144 -0
- package/out/src/tools/overture-subvenue.js.map +1 -0
- package/out/src/tools/shard-kryptonite.d.ts +1 -1
- package/out/src/tools/shard-kryptonite.d.ts.map +1 -1
- package/out/src/tools/shard-kryptonite.js +5 -4
- package/out/src/tools/shard-kryptonite.js.map +1 -1
- package/out/src/tools/shard-translit.d.ts +6 -3
- package/out/src/tools/shard-translit.d.ts.map +1 -1
- package/out/src/tools/shard-translit.js +8 -6
- package/out/src/tools/shard-translit.js.map +1 -1
- package/out/src/tools/sub-venue-lexicon.d.ts +507 -0
- package/out/src/tools/sub-venue-lexicon.d.ts.map +1 -0
- package/out/src/tools/sub-venue-lexicon.js +817 -0
- package/out/src/tools/sub-venue-lexicon.js.map +1 -0
- package/out/src/tools/sub-venue-promotions.d.ts +94 -0
- package/out/src/tools/sub-venue-promotions.d.ts.map +1 -0
- package/out/src/tools/sub-venue-promotions.js +266 -0
- package/out/src/tools/sub-venue-promotions.js.map +1 -0
- package/out/src/wof-json.d.ts +2 -2
- package/out/src/wof-json.d.ts.map +1 -1
- package/out/src/wof-json.js +5 -8
- package/out/src/wof-json.js.map +1 -1
- package/package.json +8 -8
- package/src/adapter.ts +58 -1
- package/src/adapters/ban/adapter.ts +55 -65
- package/src/adapters/ban/street-decompose.ts +17 -25
- package/src/adapters/fcc-bdc/adapter.ts +2 -33
- package/src/adapters/geonames/adapter.ts +64 -72
- package/src/adapters/geonames-postal/adapter.ts +42 -50
- package/src/adapters/gnaf/adapter.ts +4 -7
- package/src/adapters/gnaf/assemble.ts +6 -10
- package/src/adapters/openaddresses/adapter.ts +2 -7
- package/src/adapters/overture/adapter.ts +3 -6
- package/src/adapters/state-hi-schools/adapter.ts +50 -73
- package/src/adapters/state-ia-contractors/adapter.ts +52 -76
- package/src/adapters/state-ny-notaries/adapter.ts +61 -85
- package/src/adapters/state-tx-notaries/adapter.ts +60 -84
- package/src/adapters/synth-po-box/adapter.ts +7 -17
- package/src/adapters/tiger/street-decompose.ts +21 -31
- package/src/adapters/usgov-hrsa-fqhc/adapter.ts +61 -84
- package/src/adapters/usgov-imls-pls/adapter.ts +54 -82
- package/src/adapters/usgov-irs-bmf/adapter.ts +53 -63
- package/src/adapters/usgov-nad/adapter.ts +5 -8
- package/src/adapters/usgov-nppes/adapter.ts +51 -75
- package/src/adapters/usgov-samhsa-treatment-locator/adapter.ts +45 -71
- package/src/adapters/wof-admin-jp/adapter.ts +34 -8
- package/src/build.ts +2 -1
- package/src/golden.ts +24 -9
- package/src/parquet-wrapper/reader.ts +19 -0
- package/src/parquet-wrapper/schema.ts +4 -0
- package/src/parquet.ts +3 -16
- package/src/shard-recipes/anchor-absorption.ts +2 -1
- package/src/shard-recipes/country-balanced.ts +69 -70
- package/src/shard-recipes/fr-fragment.ts +10 -7
- package/src/shard-recipes/fr-order.ts +13 -63
- package/src/shard-recipes/german.ts +12 -65
- package/src/shard-recipes/index.ts +2 -0
- package/src/shard-recipes/intersection.ts +32 -60
- package/src/shard-recipes/locale.ts +14 -16
- package/src/shard-recipes/no-fragment.ts +10 -7
- package/src/shard-recipes/no-street-led.ts +10 -7
- package/src/shard-recipes/po-box-cedex.ts +68 -119
- package/src/shard-recipes/scaffold.ts +82 -28
- package/src/shard-recipes/street-affix.ts +58 -95
- package/src/shard-recipes/sub-venue-sources.ts +895 -0
- package/src/shard-recipes/sub-venue.ts +982 -0
- package/src/shard-recipes/unit.ts +22 -70
- package/src/split.ts +7 -0
- package/src/synthesize.ts +1 -15
- package/src/tools/align-shard.ts +3 -6
- package/src/tools/audit.ts +6 -5
- package/src/tools/corpus-stats.ts +25 -33
- package/src/tools/fetch/download.ts +7 -5
- package/src/tools/fetch/imls-pls.ts +2 -2
- package/src/tools/fetch/index.ts +14 -1
- package/src/tools/fetch/nad.ts +1 -1
- package/src/tools/fetch/nppes.ts +2 -1
- package/src/tools/fetch/openaddresses.ts +1 -1
- package/src/tools/fetch/ourairports.ts +166 -0
- package/src/tools/fetch/wikidata-subvenue.ts +386 -0
- package/src/tools/golden-expand.ts +18 -13
- package/src/tools/golden-promote.ts +15 -6
- package/src/tools/golden-relabel-street.ts +748 -0
- package/src/tools/index.ts +4 -0
- package/src/tools/jsonl-to-parquet.ts +3 -2
- package/src/tools/lint-shard-vocab.ts +3 -2
- package/src/tools/lint-shard.ts +33 -36
- package/src/tools/overlay-manifest.ts +2 -1
- package/src/tools/overture-subvenue.ts +215 -0
- package/src/tools/shard-kryptonite.ts +5 -4
- package/src/tools/shard-translit.ts +12 -7
- package/src/tools/sub-venue-lexicon.ts +1250 -0
- package/src/tools/sub-venue-promotions.ts +330 -0
- package/src/wof-json.ts +5 -8
|
@@ -15,11 +15,9 @@
|
|
|
15
15
|
* License: stamped `"Public Domain"` per Texas state government open-data terms.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { CSVSpliterator } from "spliterator"
|
|
19
19
|
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
import { stableSourceID } from "../../adapter.ts"
|
|
20
|
+
import { splitStreetLine, stableSourceID } from "../../adapter.ts"
|
|
23
21
|
import { lookupStateAbbreviation } from "../../codex/us-fips-state.ts"
|
|
24
22
|
import { reconcileComponents } from "../../format.ts"
|
|
25
23
|
import type { AdapterOptions, CanonicalRow, CorpusAdapter } from "../../types.ts"
|
|
@@ -35,8 +33,6 @@ export const STATE_TX_NOTARIES_ADAPTER_ID = "state-tx-notaries"
|
|
|
35
33
|
*/
|
|
36
34
|
export const STATE_TX_NOTARIES_DEFAULT_LICENSE = "Public Domain"
|
|
37
35
|
|
|
38
|
-
const HOUSE_NUMBER_PREFIX = /^(\d+(?:-\d+)?[A-Za-z]?)\s+(.+)$/
|
|
39
|
-
|
|
40
36
|
/**
|
|
41
37
|
* Match trailing "CITY, ST ZIP" or "CITY, ST" at the end of an address line.
|
|
42
38
|
*/
|
|
@@ -49,17 +45,6 @@ interface TxNotaryRow {
|
|
|
49
45
|
Address: string
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
function splitAddress(address: string): { house_number?: string; street: string } | null {
|
|
53
|
-
const trimmed = address.trim()
|
|
54
|
-
|
|
55
|
-
if (!trimmed) return null
|
|
56
|
-
const m = HOUSE_NUMBER_PREFIX.exec(trimmed)
|
|
57
|
-
|
|
58
|
-
if (m) return { house_number: m[1], street: m[2]!.trim() }
|
|
59
|
-
|
|
60
|
-
return { street: trimmed }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
48
|
export function createStateTxNotariesAdapter(): CorpusAdapter {
|
|
64
49
|
return {
|
|
65
50
|
id: STATE_TX_NOTARIES_ADAPTER_ID,
|
|
@@ -72,99 +57,90 @@ export function createStateTxNotariesAdapter(): CorpusAdapter {
|
|
|
72
57
|
throw new Error(`state-tx-notaries adapter: only US supported, got country=${opts.country}`)
|
|
73
58
|
}
|
|
74
59
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
skip_empty_lines: true,
|
|
81
|
-
relax_quotes: true,
|
|
82
|
-
relax_column_count: true,
|
|
83
|
-
})
|
|
84
|
-
)
|
|
60
|
+
const rows = CSVSpliterator.fromAsync(opts.inputPath, {
|
|
61
|
+
mode: "object",
|
|
62
|
+
normalizeKeys: false,
|
|
63
|
+
enableQuoteHandling: true,
|
|
64
|
+
})
|
|
85
65
|
|
|
86
66
|
let emitted = 0
|
|
87
67
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (opts.signal?.aborted) break
|
|
91
|
-
|
|
92
|
-
if (opts.limit !== undefined && emitted >= opts.limit) break
|
|
68
|
+
for await (const record of rows as AsyncIterable<TxNotaryRow>) {
|
|
69
|
+
if (opts.signal?.aborted) break
|
|
93
70
|
|
|
94
|
-
|
|
71
|
+
if (opts.limit !== undefined && emitted >= opts.limit) break
|
|
95
72
|
|
|
96
|
-
|
|
73
|
+
const rawAddress = (record.Address ?? "").trim()
|
|
97
74
|
|
|
98
|
-
|
|
99
|
-
const lastName = (record["Last Name"] ?? "").trim()
|
|
100
|
-
const notaryID = (record["Notary ID"] ?? "").trim()
|
|
75
|
+
if (!rawAddress) continue
|
|
101
76
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const cszMatch = CITY_STATE_ZIP_SUFFIX.exec(addrSingleLine)
|
|
77
|
+
const firstName = (record["First Name"] ?? "").trim()
|
|
78
|
+
const lastName = (record["Last Name"] ?? "").trim()
|
|
79
|
+
const notaryID = (record["Notary ID"] ?? "").trim()
|
|
106
80
|
|
|
107
|
-
|
|
81
|
+
// Parse embedded city/state/zip from the trailing portion of the address.
|
|
82
|
+
// Addresses look like: "1215 MCMILLAN DR\nCEDAR HILL, TX 75104"
|
|
83
|
+
const addrSingleLine = rawAddress.replaceAll("\n", ", ")
|
|
84
|
+
const cszMatch = CITY_STATE_ZIP_SUFFIX.exec(addrSingleLine)
|
|
108
85
|
|
|
109
|
-
|
|
110
|
-
const stateAbbr = (cszMatch[2] ?? "").trim()
|
|
111
|
-
const zip = (cszMatch[3] ?? "").trim()
|
|
86
|
+
if (!cszMatch) continue
|
|
112
87
|
|
|
113
|
-
|
|
88
|
+
const city = (cszMatch[1] ?? "").trim()
|
|
89
|
+
const stateAbbr = (cszMatch[2] ?? "").trim()
|
|
90
|
+
const zip = (cszMatch[3] ?? "").trim()
|
|
114
91
|
|
|
115
|
-
|
|
92
|
+
if (!city || !stateAbbr) continue
|
|
116
93
|
|
|
117
|
-
|
|
94
|
+
const state = lookupStateAbbreviation(stateAbbr)
|
|
118
95
|
|
|
119
|
-
|
|
120
|
-
const streetPortion = addrSingleLine.slice(0, cszMatch.index).replace(/,\s*$/, "").trim()
|
|
96
|
+
if (!state) continue
|
|
121
97
|
|
|
122
|
-
|
|
98
|
+
// Extract the street portion (everything before the city/state/zip)
|
|
99
|
+
const streetPortion = addrSingleLine.slice(0, cszMatch.index).replace(/,\s*$/, "").trim()
|
|
123
100
|
|
|
124
|
-
|
|
101
|
+
if (!streetPortion) continue
|
|
125
102
|
|
|
126
|
-
|
|
103
|
+
const split = splitStreetLine(streetPortion)
|
|
127
104
|
|
|
128
|
-
|
|
105
|
+
if (!split) continue
|
|
129
106
|
|
|
130
|
-
|
|
131
|
-
...(venue ? { venue } : {}),
|
|
132
|
-
...(split.house_number ? { house_number: split.house_number } : {}),
|
|
133
|
-
street: split.street,
|
|
134
|
-
locality: city,
|
|
135
|
-
region: state.abbreviation,
|
|
136
|
-
...(zip ? { postcode: zip } : {}),
|
|
137
|
-
}
|
|
107
|
+
const venue = [firstName, lastName].filter(Boolean).join(" ") || undefined
|
|
138
108
|
|
|
139
|
-
|
|
109
|
+
const components: CanonicalRow["components"] = {
|
|
110
|
+
...(venue ? { venue } : {}),
|
|
111
|
+
...(split.house_number ? { house_number: split.house_number } : {}),
|
|
112
|
+
street: split.street,
|
|
113
|
+
locality: city,
|
|
114
|
+
region: state.abbreviation,
|
|
115
|
+
...(zip ? { postcode: zip } : {}),
|
|
116
|
+
}
|
|
140
117
|
|
|
141
|
-
|
|
142
|
-
.filter(Boolean)
|
|
143
|
-
.join(", ")
|
|
118
|
+
const streetPart = [split.house_number, split.street].filter(Boolean).join(" ").trim()
|
|
144
119
|
|
|
145
|
-
|
|
120
|
+
const raw = [venue, streetPart, [city, [stateAbbr, zip].filter(Boolean).join(" ")].filter(Boolean).join(", ")]
|
|
121
|
+
.filter(Boolean)
|
|
122
|
+
.join(", ")
|
|
146
123
|
|
|
147
|
-
|
|
124
|
+
const aligned = reconcileComponents(components, raw)
|
|
148
125
|
|
|
149
|
-
|
|
150
|
-
? `${STATE_TX_NOTARIES_ADAPTER_ID}-${notaryID}`
|
|
151
|
-
: stableSourceID(STATE_TX_NOTARIES_ADAPTER_ID, aligned)
|
|
126
|
+
if (Object.keys(aligned).length <= 2) continue
|
|
152
127
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
country: "US",
|
|
157
|
-
locale: "en-US",
|
|
158
|
-
source: STATE_TX_NOTARIES_ADAPTER_ID,
|
|
159
|
-
source_id: sourceID,
|
|
160
|
-
corpus_version: "",
|
|
161
|
-
license: STATE_TX_NOTARIES_DEFAULT_LICENSE,
|
|
162
|
-
}
|
|
128
|
+
const sourceID = notaryID
|
|
129
|
+
? `${STATE_TX_NOTARIES_ADAPTER_ID}-${notaryID}`
|
|
130
|
+
: stableSourceID(STATE_TX_NOTARIES_ADAPTER_ID, aligned)
|
|
163
131
|
|
|
164
|
-
|
|
132
|
+
yield {
|
|
133
|
+
raw,
|
|
134
|
+
components: aligned,
|
|
135
|
+
country: "US",
|
|
136
|
+
locale: "en-US",
|
|
137
|
+
source: STATE_TX_NOTARIES_ADAPTER_ID,
|
|
138
|
+
source_id: sourceID,
|
|
139
|
+
corpus_version: "",
|
|
140
|
+
license: STATE_TX_NOTARIES_DEFAULT_LICENSE,
|
|
165
141
|
}
|
|
166
|
-
|
|
167
|
-
|
|
142
|
+
|
|
143
|
+
emitted++
|
|
168
144
|
}
|
|
169
145
|
},
|
|
170
146
|
}
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
* carries a `street` field.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { tryParsingJSON } from "@mailwoman/core/objects"
|
|
24
|
+
import { makeLcg } from "@mailwoman/core/utils"
|
|
23
25
|
import { TextSpliterator } from "spliterator"
|
|
24
26
|
|
|
25
27
|
import { stableSourceID } from "../../adapter.ts"
|
|
@@ -73,16 +75,6 @@ export interface SynthPoBoxAdapterOptions {
|
|
|
73
75
|
militaryRatio?: number
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
function makeRandom(seed: number): () => number {
|
|
77
|
-
let s = seed
|
|
78
|
-
|
|
79
|
-
return () => {
|
|
80
|
-
s = (s * 1_664_525 + 1_013_904_223) % 4_294_967_296
|
|
81
|
-
|
|
82
|
-
return s / 4_294_967_296
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
78
|
export function createSynthPoBoxAdapter(opts: SynthPoBoxAdapterOptions = {}): CorpusAdapter {
|
|
87
79
|
const variantsPerInput = opts.variantsPerInput ?? 1
|
|
88
80
|
const pmbRatio = opts.pmbRatio ?? 0.15
|
|
@@ -95,10 +87,10 @@ export function createSynthPoBoxAdapter(opts: SynthPoBoxAdapterOptions = {}): Co
|
|
|
95
87
|
"Synthetic PO box / PMB / Apartado / Boîte Postale rows. Consumes JSONL of (locality, region, postcode, country) tuples and emits locale-appropriate PO box variants.",
|
|
96
88
|
|
|
97
89
|
async *rows(options: AdapterOptions): AsyncIterable<CanonicalRow> {
|
|
98
|
-
const random =
|
|
90
|
+
const random = makeLcg(opts.seed ?? Date.now())
|
|
99
91
|
|
|
100
|
-
// TextSpliterator streams string lines; the per-line
|
|
101
|
-
// tolerant of malformed rows (skipped++), so TextSpliterator +
|
|
92
|
+
// TextSpliterator streams string lines; the per-line tryParsingJSON below keeps this reader
|
|
93
|
+
// tolerant of malformed rows (skipped++), so TextSpliterator + a non-throwing parse — not
|
|
102
94
|
// JSONSpliterator, which would throw on the first bad line.
|
|
103
95
|
const lines = TextSpliterator.fromAsync(options.inputPath)
|
|
104
96
|
|
|
@@ -115,11 +107,9 @@ export function createSynthPoBoxAdapter(opts: SynthPoBoxAdapterOptions = {}): Co
|
|
|
115
107
|
|
|
116
108
|
if (!trimmed) continue
|
|
117
109
|
|
|
118
|
-
|
|
110
|
+
const input = tryParsingJSON<PoBoxInputRow>(trimmed)
|
|
119
111
|
|
|
120
|
-
|
|
121
|
-
input = JSON.parse(trimmed) as PoBoxInputRow
|
|
122
|
-
} catch {
|
|
112
|
+
if (input === null) {
|
|
123
113
|
skipped++
|
|
124
114
|
|
|
125
115
|
continue
|
|
@@ -17,45 +17,35 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { readFileSync } from "node:fs"
|
|
20
|
-
import { resolve } from "node:path"
|
|
21
20
|
|
|
22
21
|
import { resourceDictionaryPath } from "@mailwoman/core/utils"
|
|
22
|
+
import { TextSpliterator } from "spliterator"
|
|
23
23
|
|
|
24
24
|
function loadDictionary(filename: string): Set<string> {
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for (const line of text.split("\n")) {
|
|
38
|
-
const trimmed = line.trim()
|
|
39
|
-
|
|
40
|
-
if (!trimmed || trimmed.startsWith("#")) continue
|
|
41
|
-
|
|
42
|
-
// libpostal format: canonical|abbr|abbr|... — index all forms
|
|
43
|
-
for (const form of trimmed.split("|")) {
|
|
44
|
-
const f = form.trim().toLowerCase()
|
|
45
|
-
|
|
46
|
-
if (f) {
|
|
47
|
-
set.add(f)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
25
|
+
// `resourceDictionaryPath` already resolves both layouts — `core/data/...` from source and from the
|
|
26
|
+
// packaged `out/` tree. The candidate list this replaced named it TWICE and then guessed a third path
|
|
27
|
+
// off `process.cwd()`, and swallowed every error while probing, so a corrupt dictionary reported as a
|
|
28
|
+
// missing one.
|
|
29
|
+
const text = readFileSync(resourceDictionaryPath("libpostal", "en", filename), "utf8")
|
|
30
|
+
const set = new Set<string>()
|
|
31
|
+
|
|
32
|
+
// The largest libpostal dictionary is 8.4 KB, and this runs once per process at module load.
|
|
33
|
+
for (const line of TextSpliterator.from(text)) {
|
|
34
|
+
const trimmed = line.trim()
|
|
35
|
+
|
|
36
|
+
if (!trimmed || trimmed.startsWith("#")) continue
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
// libpostal format: canonical|abbr|abbr|... — index all forms
|
|
39
|
+
for (const form of trimmed.split("|")) {
|
|
40
|
+
const f = form.trim().toLowerCase()
|
|
41
|
+
|
|
42
|
+
if (f) {
|
|
43
|
+
set.add(f)
|
|
44
|
+
}
|
|
55
45
|
}
|
|
56
46
|
}
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
return set
|
|
59
49
|
}
|
|
60
50
|
|
|
61
51
|
const DIRECTIONALS = loadDictionary("directionals.txt")
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* Federally Qualified Health Centers (FQHCs) are HRSA-funded community health programs that
|
|
9
9
|
* self-report site addresses to the HRSA Data Warehouse. The published CSV (`data.hrsa.gov`)
|
|
10
10
|
* carries the site name, the postal-formatted street address, and the locality/region/postcode
|
|
11
|
-
* quad.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* quad. The source earns its place on adversarial-value-per-row (#22): every facility name is a
|
|
12
|
+
* human-typed venue string and the addresses pass through enough hands to accumulate the
|
|
13
|
+
* abbreviation drift + suite designator chaos that pure gazetteer data does not.
|
|
14
14
|
*
|
|
15
15
|
* The adapter consumes a CSV file the operator pre-downloads. The HRSA data is published as a
|
|
16
16
|
* single national CSV (~10K rows), small enough that the operator can re-fetch on every corpus
|
|
@@ -29,11 +29,9 @@
|
|
|
29
29
|
* terms.
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
-
import {
|
|
32
|
+
import { CSVSpliterator } from "spliterator"
|
|
33
33
|
|
|
34
|
-
import {
|
|
35
|
-
|
|
36
|
-
import { stableSourceID } from "../../adapter.ts"
|
|
34
|
+
import { splitStreetLine, stableSourceID } from "../../adapter.ts"
|
|
37
35
|
import { lookupStateAbbreviation } from "../../codex/us-fips-state.ts"
|
|
38
36
|
import { reconcileComponents } from "../../format.ts"
|
|
39
37
|
import type { AdapterOptions, CanonicalRow, CorpusAdapter } from "../../types.ts"
|
|
@@ -70,23 +68,11 @@ interface HrsaSiteRow {
|
|
|
70
68
|
* Split a "123 Main St Suite 4" surface form into `(house_number, street)`. The regex tolerates one trailing letter on
|
|
71
69
|
* the number (`"123A Main St"`) and a hyphenated form (`"40-12 Bell Blvd"`); anything else falls back to street-only.
|
|
72
70
|
*
|
|
73
|
-
* Suite / Apt / Unit designators stay on `street`
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
71
|
+
* Suite / Apt / Unit designators stay on `street` — Mailwoman's `unit` component exists but the address-formatter does
|
|
72
|
+
* not have a clean slot for it, and HRSA addresses do not separate the suite into its own column. Leaving the surface
|
|
73
|
+
* form intact in `street` preserves the adversarial training signal (the model learns that a trailing "Suite 4" is part
|
|
74
|
+
* of the road line in this distribution).
|
|
77
75
|
*/
|
|
78
|
-
const HOUSE_NUMBER_PREFIX = /^(\d+(?:-\d+)?[A-Za-z]?)\s+(.+)$/
|
|
79
|
-
|
|
80
|
-
function splitAddress(address: string): { house_number?: string; street: string } | null {
|
|
81
|
-
const trimmed = address.trim()
|
|
82
|
-
|
|
83
|
-
if (!trimmed) return null
|
|
84
|
-
const m = HOUSE_NUMBER_PREFIX.exec(trimmed)
|
|
85
|
-
|
|
86
|
-
if (m) return { house_number: m[1], street: m[2]!.trim() }
|
|
87
|
-
|
|
88
|
-
return { street: trimmed }
|
|
89
|
-
}
|
|
90
76
|
|
|
91
77
|
/**
|
|
92
78
|
* Compose the raw envelope-style address line. Format:
|
|
@@ -122,78 +108,69 @@ export function createUsgovHrsaFqhcAdapter(): CorpusAdapter {
|
|
|
122
108
|
throw new Error(`usgov-hrsa-fqhc adapter: only US supported, got country=${opts.country}`)
|
|
123
109
|
}
|
|
124
110
|
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
skip_empty_lines: true,
|
|
131
|
-
relax_quotes: true,
|
|
132
|
-
relax_column_count: true,
|
|
133
|
-
})
|
|
134
|
-
)
|
|
111
|
+
const rows = CSVSpliterator.fromAsync(opts.inputPath, {
|
|
112
|
+
mode: "object",
|
|
113
|
+
normalizeKeys: false,
|
|
114
|
+
enableQuoteHandling: true,
|
|
115
|
+
})
|
|
135
116
|
|
|
136
117
|
let emitted = 0
|
|
137
118
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const raw = composeRaw(venue, split.house_number, split.street, city, state.abbreviation, postcode)
|
|
119
|
+
for await (const record of rows as AsyncIterable<HrsaSiteRow>) {
|
|
120
|
+
if (opts.signal?.aborted) break
|
|
121
|
+
|
|
122
|
+
if (opts.limit !== undefined && emitted >= opts.limit) break
|
|
123
|
+
|
|
124
|
+
const venue = (record["Site Name"] ?? "").trim()
|
|
125
|
+
const split = splitStreetLine(record["Site Address"] ?? "")
|
|
126
|
+
const city = (record["Site City"] ?? "").trim()
|
|
127
|
+
const stateAbbr = (record["Site State Abbreviation"] ?? "").trim()
|
|
128
|
+
const postcode = (record["Site Postal Code"] ?? "").trim()
|
|
129
|
+
|
|
130
|
+
if (!venue || !split || !city || !postcode) continue
|
|
131
|
+
const state = lookupStateAbbreviation(stateAbbr)
|
|
132
|
+
|
|
133
|
+
if (!state) continue
|
|
134
|
+
|
|
135
|
+
// Insertion order matters here. `venue` first so alignment claims its span
|
|
136
|
+
// (which may contain a token like "Buffalo") before `locality` runs its
|
|
137
|
+
// search — the kryptonite case `Buffalo Health Clinic, Buffalo NY`
|
|
138
|
+
// otherwise mis-labels the venue's "Buffalo" as locality.
|
|
139
|
+
const components: CanonicalRow["components"] = {
|
|
140
|
+
venue,
|
|
141
|
+
...(split.house_number ? { house_number: split.house_number } : {}),
|
|
142
|
+
street: split.street,
|
|
143
|
+
locality: city,
|
|
144
|
+
region: state.abbreviation,
|
|
145
|
+
postcode,
|
|
146
|
+
}
|
|
169
147
|
|
|
170
|
-
|
|
148
|
+
const raw = composeRaw(venue, split.house_number, split.street, city, state.abbreviation, postcode)
|
|
171
149
|
|
|
172
|
-
|
|
150
|
+
if (!raw) continue
|
|
173
151
|
|
|
174
|
-
|
|
152
|
+
const aligned = reconcileComponents(components, raw)
|
|
175
153
|
|
|
176
|
-
|
|
154
|
+
if (!Object.keys(aligned).length) continue
|
|
177
155
|
|
|
178
|
-
|
|
179
|
-
? `${USGOV_HRSA_FQHC_ADAPTER_ID}-${siteID}`
|
|
180
|
-
: stableSourceID(USGOV_HRSA_FQHC_ADAPTER_ID, aligned)
|
|
156
|
+
const siteID = (record["Site ID"] ?? "").trim()
|
|
181
157
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
country: "US",
|
|
186
|
-
locale: "en-US",
|
|
187
|
-
source: USGOV_HRSA_FQHC_ADAPTER_ID,
|
|
188
|
-
source_id: sourceID,
|
|
189
|
-
corpus_version: "",
|
|
190
|
-
license: USGOV_HRSA_FQHC_DEFAULT_LICENSE,
|
|
191
|
-
}
|
|
158
|
+
const sourceID = siteID
|
|
159
|
+
? `${USGOV_HRSA_FQHC_ADAPTER_ID}-${siteID}`
|
|
160
|
+
: stableSourceID(USGOV_HRSA_FQHC_ADAPTER_ID, aligned)
|
|
192
161
|
|
|
193
|
-
|
|
162
|
+
yield {
|
|
163
|
+
raw,
|
|
164
|
+
components: aligned,
|
|
165
|
+
country: "US",
|
|
166
|
+
locale: "en-US",
|
|
167
|
+
source: USGOV_HRSA_FQHC_ADAPTER_ID,
|
|
168
|
+
source_id: sourceID,
|
|
169
|
+
corpus_version: "",
|
|
170
|
+
license: USGOV_HRSA_FQHC_DEFAULT_LICENSE,
|
|
194
171
|
}
|
|
195
|
-
|
|
196
|
-
|
|
172
|
+
|
|
173
|
+
emitted++
|
|
197
174
|
}
|
|
198
175
|
},
|
|
199
176
|
}
|