@mailwoman/corpus 10.6.0 → 10.7.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/data/PROVENANCE.md +24 -0
- package/data/address-source-register.json +18948 -8757
- package/data/corpus-source-inputs.json +4756 -0
- package/data/license-decisions.json +7260 -0
- package/data/licenses/whosonfirst-licenses.md +3 -2
- package/data/reviewed-ve-postcode-tuples.json +5 -72
- package/data/source-additions.json +2450 -0
- package/data/source-resolutions.json +87 -0
- package/data/training-manifests/v0.7.10-gb-county.effective.json +2335 -0
- package/data/training-manifests/v0.7.10-gb-county.json +1132 -0
- package/data/training-manifests/v0.7.2-address-systems.effective.json +3 -2
- package/data/training-manifests/v0.7.7-no-ppd.json +550 -0
- package/data/training-manifests/v0.7.8-rights-clean.json +538 -0
- package/data/training-manifests/v0.7.9-country-gap.json +1132 -0
- package/data/us-situs-sources.json +128 -0
- package/lib/adapters/cordis/adapter.ts +1 -1
- package/lib/adapters/libpostal-dictionary.ts +23 -3
- package/lib/adapters/osm/adapter.ts +42 -11
- package/lib/adapters.ts +14 -0
- package/lib/az/adapters/opendata/adapter.ts +389 -0
- package/lib/bs/adapters/gbpa/adapter.ts +248 -0
- package/lib/build/types.ts +16 -0
- package/lib/build.ts +21 -0
- package/lib/ee/adapters/ads/adapter.ts +18 -0
- package/lib/fo/adapters/adressur/adapter.ts +242 -0
- package/lib/gb/adapters/os-open/adapter.ts +12 -0
- package/lib/gb/county.ts +59 -0
- package/lib/gb/os-open/open/names.ts +41 -0
- package/lib/gu/adapters/bsp/adapter.ts +434 -0
- package/lib/im/adapters/land-registry/adapter.ts +340 -0
- package/lib/international/recipes/locale.ts +164 -19
- package/lib/li/adapters/llv/adapter.ts +246 -0
- package/lib/recipes/bare/postcode.ts +10 -34
- package/lib/recipes/country-balanced.ts +95 -78
- package/lib/recipes/intersection.ts +22 -30
- package/lib/recipes/po/box/cedex/recipe.ts +8 -5
- package/lib/recipes/po/box/cedex/sources.ts +2 -23
- package/lib/recipes/scaffold.ts +28 -3
- package/lib/recipes/sources.ts +112 -1
- package/lib/recipes/street/affix.ts +17 -29
- package/lib/recipes/sub/venue/context.ts +33 -9
- package/lib/recipes/sub/venue/sources.ts +54 -13
- package/lib/recipes/sub/venue.ts +68 -23
- package/lib/recipes/unit.ts +20 -7
- package/lib/registers.ts +33 -0
- package/lib/source-register/corpus-inputs.ts +528 -0
- package/lib/source-register/effective-manifest.ts +37 -5
- package/lib/source-register/types.ts +20 -0
- package/lib/south-asia/recipes/register.ts +1 -1
- package/lib/tools/overlay/manifest.ts +109 -1
- package/lib/tools/source-register/build.ts +47 -1
- package/lib/tools/variety-sample.ts +633 -0
- package/lib/us/adapters/usgov/nad/adapter.ts +39 -10
- package/lib/us/recipes/skeleton-sources.ts +156 -0
- package/lib/us/tools/nad-skeletons.ts +395 -0
- package/lib/uy/adapters/ide/adapter.ts +275 -0
- package/lib/ve/recipes/reviewed-postcode-tail.ts +29 -6
- package/out/adapters/cordis/adapter.d.ts +1 -1
- package/out/adapters/cordis/adapter.js +1 -1
- package/out/adapters/libpostal-dictionary.d.ts +9 -0
- package/out/adapters/libpostal-dictionary.d.ts.map +1 -1
- package/out/adapters/libpostal-dictionary.js +19 -3
- package/out/adapters/libpostal-dictionary.js.map +1 -1
- package/out/adapters/osm/adapter.d.ts +12 -1
- package/out/adapters/osm/adapter.d.ts.map +1 -1
- package/out/adapters/osm/adapter.js +30 -13
- package/out/adapters/osm/adapter.js.map +1 -1
- package/out/adapters.d.ts.map +1 -1
- package/out/adapters.js +14 -0
- package/out/adapters.js.map +1 -1
- package/out/az/adapters/opendata/adapter.d.ts +88 -0
- package/out/az/adapters/opendata/adapter.d.ts.map +1 -0
- package/out/az/adapters/opendata/adapter.js +282 -0
- package/out/az/adapters/opendata/adapter.js.map +1 -0
- package/out/bs/adapters/gbpa/adapter.d.ts +64 -0
- package/out/bs/adapters/gbpa/adapter.d.ts.map +1 -0
- package/out/bs/adapters/gbpa/adapter.js +187 -0
- package/out/bs/adapters/gbpa/adapter.js.map +1 -0
- package/out/build/types.d.ts +15 -0
- package/out/build/types.d.ts.map +1 -1
- package/out/build/types.js.map +1 -1
- package/out/build.d.ts.map +1 -1
- package/out/build.js +17 -0
- package/out/build.js.map +1 -1
- package/out/ee/adapters/ads/adapter.d.ts +6 -0
- package/out/ee/adapters/ads/adapter.d.ts.map +1 -1
- package/out/ee/adapters/ads/adapter.js +16 -0
- package/out/ee/adapters/ads/adapter.js.map +1 -1
- package/out/fo/adapters/adressur/adapter.d.ts +63 -0
- package/out/fo/adapters/adressur/adapter.d.ts.map +1 -0
- package/out/fo/adapters/adressur/adapter.js +177 -0
- package/out/fo/adapters/adressur/adapter.js.map +1 -0
- package/out/gb/adapters/os-open/adapter.d.ts +8 -0
- package/out/gb/adapters/os-open/adapter.d.ts.map +1 -1
- package/out/gb/adapters/os-open/adapter.js +11 -0
- package/out/gb/adapters/os-open/adapter.js.map +1 -1
- package/out/gb/county.d.ts +30 -0
- package/out/gb/county.d.ts.map +1 -0
- package/out/gb/county.js +51 -0
- package/out/gb/county.js.map +1 -0
- package/out/gb/os-open/open/names.d.ts +17 -0
- package/out/gb/os-open/open/names.d.ts.map +1 -1
- package/out/gb/os-open/open/names.js +19 -0
- package/out/gb/os-open/open/names.js.map +1 -1
- package/out/gu/adapters/bsp/adapter.d.ts +83 -0
- package/out/gu/adapters/bsp/adapter.d.ts.map +1 -0
- package/out/gu/adapters/bsp/adapter.js +346 -0
- package/out/gu/adapters/bsp/adapter.js.map +1 -0
- package/out/im/adapters/land-registry/adapter.d.ts +68 -0
- package/out/im/adapters/land-registry/adapter.d.ts.map +1 -0
- package/out/im/adapters/land-registry/adapter.js +261 -0
- package/out/im/adapters/land-registry/adapter.js.map +1 -0
- package/out/international/recipes/locale.d.ts +24 -4
- package/out/international/recipes/locale.d.ts.map +1 -1
- package/out/international/recipes/locale.js +107 -15
- package/out/international/recipes/locale.js.map +1 -1
- package/out/li/adapters/llv/adapter.d.ts +69 -0
- package/out/li/adapters/llv/adapter.d.ts.map +1 -0
- package/out/li/adapters/llv/adapter.js +181 -0
- package/out/li/adapters/llv/adapter.js.map +1 -0
- package/out/recipes/bare/postcode.d.ts.map +1 -1
- package/out/recipes/bare/postcode.js +9 -30
- package/out/recipes/bare/postcode.js.map +1 -1
- package/out/recipes/country-balanced.d.ts.map +1 -1
- package/out/recipes/country-balanced.js +82 -73
- package/out/recipes/country-balanced.js.map +1 -1
- package/out/recipes/intersection.d.ts +3 -2
- package/out/recipes/intersection.d.ts.map +1 -1
- package/out/recipes/intersection.js +20 -26
- package/out/recipes/intersection.js.map +1 -1
- package/out/recipes/po/box/cedex/recipe.d.ts.map +1 -1
- package/out/recipes/po/box/cedex/recipe.js +5 -4
- package/out/recipes/po/box/cedex/recipe.js.map +1 -1
- package/out/recipes/po/box/cedex/sources.d.ts +2 -45
- package/out/recipes/po/box/cedex/sources.d.ts.map +1 -1
- package/out/recipes/po/box/cedex/sources.js +0 -20
- package/out/recipes/po/box/cedex/sources.js.map +1 -1
- package/out/recipes/scaffold.d.ts +15 -2
- package/out/recipes/scaffold.d.ts.map +1 -1
- package/out/recipes/scaffold.js +21 -1
- package/out/recipes/scaffold.js.map +1 -1
- package/out/recipes/sources.d.ts.map +1 -1
- package/out/recipes/sources.js +112 -1
- package/out/recipes/sources.js.map +1 -1
- package/out/recipes/street/affix.d.ts.map +1 -1
- package/out/recipes/street/affix.js +8 -20
- package/out/recipes/street/affix.js.map +1 -1
- package/out/recipes/sub/venue/context.d.ts +14 -3
- package/out/recipes/sub/venue/context.d.ts.map +1 -1
- package/out/recipes/sub/venue/context.js +29 -9
- package/out/recipes/sub/venue/context.js.map +1 -1
- package/out/recipes/sub/venue/sources.d.ts +41 -8
- package/out/recipes/sub/venue/sources.d.ts.map +1 -1
- package/out/recipes/sub/venue/sources.js +26 -7
- package/out/recipes/sub/venue/sources.js.map +1 -1
- package/out/recipes/sub/venue.d.ts.map +1 -1
- package/out/recipes/sub/venue.js +35 -14
- package/out/recipes/sub/venue.js.map +1 -1
- package/out/recipes/unit.d.ts +4 -0
- package/out/recipes/unit.d.ts.map +1 -1
- package/out/recipes/unit.js +7 -6
- package/out/recipes/unit.js.map +1 -1
- package/out/registers.d.ts +33 -0
- package/out/registers.d.ts.map +1 -1
- package/out/registers.js +33 -0
- package/out/registers.js.map +1 -1
- package/out/source-register/corpus-inputs.d.ts +240 -0
- package/out/source-register/corpus-inputs.d.ts.map +1 -0
- package/out/source-register/corpus-inputs.js +275 -0
- package/out/source-register/corpus-inputs.js.map +1 -0
- package/out/source-register/effective-manifest.d.ts +2 -0
- package/out/source-register/effective-manifest.d.ts.map +1 -1
- package/out/source-register/effective-manifest.js +33 -4
- package/out/source-register/effective-manifest.js.map +1 -1
- package/out/source-register/types.d.ts +21 -1
- package/out/source-register/types.d.ts.map +1 -1
- package/out/source-register/types.js +20 -0
- package/out/source-register/types.js.map +1 -1
- package/out/south-asia/recipes/register.js +1 -1
- package/out/south-asia/recipes/register.js.map +1 -1
- package/out/tools/overlay/manifest.d.ts +7 -0
- package/out/tools/overlay/manifest.d.ts.map +1 -1
- package/out/tools/overlay/manifest.js +72 -1
- package/out/tools/overlay/manifest.js.map +1 -1
- package/out/tools/source-register/build.d.ts +9 -0
- package/out/tools/source-register/build.d.ts.map +1 -1
- package/out/tools/source-register/build.js +25 -3
- package/out/tools/source-register/build.js.map +1 -1
- package/out/tools/variety-sample.d.ts +196 -0
- package/out/tools/variety-sample.d.ts.map +1 -0
- package/out/tools/variety-sample.js +417 -0
- package/out/tools/variety-sample.js.map +1 -0
- package/out/us/adapters/usgov/nad/adapter.d.ts +80 -0
- package/out/us/adapters/usgov/nad/adapter.d.ts.map +1 -1
- package/out/us/adapters/usgov/nad/adapter.js +27 -8
- package/out/us/adapters/usgov/nad/adapter.js.map +1 -1
- package/out/us/recipes/skeleton-sources.d.ts +92 -0
- package/out/us/recipes/skeleton-sources.d.ts.map +1 -0
- package/out/us/recipes/skeleton-sources.js +121 -0
- package/out/us/recipes/skeleton-sources.js.map +1 -0
- package/out/us/tools/nad-skeletons.d.ts +120 -0
- package/out/us/tools/nad-skeletons.d.ts.map +1 -0
- package/out/us/tools/nad-skeletons.js +262 -0
- package/out/us/tools/nad-skeletons.js.map +1 -0
- package/out/uy/adapters/ide/adapter.d.ts +64 -0
- package/out/uy/adapters/ide/adapter.d.ts.map +1 -0
- package/out/uy/adapters/ide/adapter.js +206 -0
- package/out/uy/adapters/ide/adapter.js.map +1 -0
- package/out/ve/recipes/reviewed-postcode-tail.d.ts +6 -2
- package/out/ve/recipes/reviewed-postcode-tail.d.ts.map +1 -1
- package/out/ve/recipes/reviewed-postcode-tail.js +16 -5
- package/out/ve/recipes/reviewed-postcode-tail.js.map +1 -1
- package/package.json +14 -14
- package/lib/recipes/unit/sources.ts +0 -44
- package/lib/tools/fetch/ppd.ts +0 -121
- package/out/recipes/unit/sources.d.ts +0 -28
- package/out/recipes/unit/sources.d.ts.map +0 -1
- package/out/recipes/unit/sources.js +0 -30
- package/out/recipes/unit/sources.js.map +0 -1
- package/out/tools/fetch/ppd.d.ts +0 -15
- package/out/tools/fetch/ppd.d.ts.map +0 -1
- package/out/tools/fetch/ppd.js +0 -86
- package/out/tools/fetch/ppd.js.map +0 -1
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `opendata-az`: `Azərbaycanda obyektlər və məkanlar` (objects and places in Azerbaijan), a GeoJSON of
|
|
7
|
+
* 11,807 points of interest in Baku, Sumgayit and Absheron that the Ministry of Ecology and Natural
|
|
8
|
+
* Resources publishes on opendata.az.
|
|
9
|
+
*
|
|
10
|
+
* Each point holds a place's name (`NAME`) and its address in English transliteration: `STRT_NAME` and
|
|
11
|
+
* `STRT_ADDR` for the street and number, `STATE` for the city district or settlement and `CITY` for the
|
|
12
|
+
* city. The adapter reads `NAME` as the venue, `STRT_NAME` as the street, `STRT_ADDR` as the house
|
|
13
|
+
* number, the last comma part of `STATE` (`Sabunchu,Zabrat` names the settlement Zabrat) as the dependent
|
|
14
|
+
* locality and `CITY` as the locality. Absheron is a district rather than a city, so an Absheron row
|
|
15
|
+
* takes its settlement (`Khirdalan`, `Masazir`) as the locality.
|
|
16
|
+
*
|
|
17
|
+
* `STRT_ADDR` writes `0` where the point has no number. Some street values carry the number after a
|
|
18
|
+
* comma (`Zarifa Aliyeva,38`) or a building's name in parentheses (`Azadlig Avenue(Hilton Baku)`): the
|
|
19
|
+
* number is read from the street when `STRT_ADDR` has none, and the parenthetical is removed. A block
|
|
20
|
+
* code (`558-ci0mehelle030`) is not a house number. A row with neither a number nor a venue is refused.
|
|
21
|
+
*
|
|
22
|
+
* `NAME` names a point of interest of the type `TYPE` states (`Cafe Gorush`, `School 93`, `Library by
|
|
23
|
+
* A. P. Chekhov`). No value in the 2025-08-05 file is a person's given name and surname alone: of the
|
|
24
|
+
* three that read `<Word> <surname-ending>`, each is a category word and a name (`Cafe Beyzade`,
|
|
25
|
+
* `Monument Rahimov`). A value with no run of three letters is a code and is dropped.
|
|
26
|
+
*
|
|
27
|
+
* Ninety-two points also carry their street in Azerbaijani spelling (`STRT_N_AZ`); each of those
|
|
28
|
+
* emits a second row in that spelling, with `NAME_AZ`, `STATE_AZ` and `CITY_AZ` where present
|
|
29
|
+
* (`Bakı` for `Baku`), when it renders differently from the first.
|
|
30
|
+
*
|
|
31
|
+
* The file holds no postcode. The CKAN record states `license_id: cc-by`, `Creative Commons Attribution`,
|
|
32
|
+
* with no version, so the rows carry a LicenseRef rather than an SPDX id that would assert a version.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { formatAddressRow } from "@mailwoman/codex/address/format"
|
|
36
|
+
import { readLocalTextFile } from "@mailwoman/core/fs/readers"
|
|
37
|
+
import { parseJSONStrict } from "@mailwoman/core/json"
|
|
38
|
+
import { resolvePath } from "path-ts"
|
|
39
|
+
|
|
40
|
+
import { UnsupportedCountryError } from "#adapters/errors"
|
|
41
|
+
import { stableSourceIDFromParts } from "#adapters/source-id"
|
|
42
|
+
import { SourceRegister } from "#registers"
|
|
43
|
+
import {
|
|
44
|
+
AddressRole,
|
|
45
|
+
type AdapterOptions,
|
|
46
|
+
type CanonicalRow,
|
|
47
|
+
type CorpusAdapter,
|
|
48
|
+
countDropped,
|
|
49
|
+
SurfaceOrigin,
|
|
50
|
+
} from "#types"
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Registry id for this adapter, stamped into every row it emits.
|
|
54
|
+
*/
|
|
55
|
+
export const OPENDATA_AZ_ADAPTER_ID = "opendata-az"
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The publisher's license, Creative Commons Attribution, whose version the record leaves unstated.
|
|
59
|
+
*/
|
|
60
|
+
export const OPENDATA_AZ_LICENSE = "LicenseRef-CC-BY-unstated-version"
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Every jurisdiction this adapter emits, checked against a caller's `--country`.
|
|
64
|
+
*/
|
|
65
|
+
export const OPENDATA_AZ_COUNTRIES: readonly string[] = ["AZ"]
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The feature properties the adapter reads.
|
|
69
|
+
*/
|
|
70
|
+
export interface AzerbaijanPlaceRecord {
|
|
71
|
+
OBJECTID?: number | null
|
|
72
|
+
CITY?: string | null
|
|
73
|
+
STATE?: string | null
|
|
74
|
+
STRT_NAME?: string | null
|
|
75
|
+
STRT_ADDR?: string | null
|
|
76
|
+
NAME?: string | null
|
|
77
|
+
NAME_AZ?: string | null
|
|
78
|
+
STATE_AZ?: string | null
|
|
79
|
+
STRT_N_AZ?: string | null
|
|
80
|
+
CITY_AZ?: string | null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface AzerbaijanFeatureCollection {
|
|
84
|
+
features?: Array<{
|
|
85
|
+
properties?: AzerbaijanPlaceRecord | null
|
|
86
|
+
geometry?: { coordinates?: readonly number[] } | null
|
|
87
|
+
}>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The spelling a row is rendered in.
|
|
92
|
+
*/
|
|
93
|
+
export const AzerbaijanSpelling = {
|
|
94
|
+
/**
|
|
95
|
+
* `STRT_NAME`, `NAME`, `STATE` and `CITY`: English transliteration.
|
|
96
|
+
*/
|
|
97
|
+
Transliterated: "transliterated",
|
|
98
|
+
/**
|
|
99
|
+
* `STRT_N_AZ`, `NAME_AZ`, `STATE_AZ` and `CITY_AZ`: Azerbaijani.
|
|
100
|
+
*/
|
|
101
|
+
Azerbaijani: "azerbaijani",
|
|
102
|
+
} as const
|
|
103
|
+
|
|
104
|
+
export type AzerbaijanSpelling = (typeof AzerbaijanSpelling)[keyof typeof AzerbaijanSpelling]
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A value with its whitespace collapsed, or null when the file leaves it blank (a single space).
|
|
108
|
+
*/
|
|
109
|
+
function present(value: string | number | null | undefined): string | null {
|
|
110
|
+
const collapsed = value == null ? "" : String(value).replaceAll(/\s+/gu, " ").trim()
|
|
111
|
+
|
|
112
|
+
return collapsed || null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A house number: digits with an optional letter, and an optional second number
|
|
117
|
+
* after a slash, backslash or hyphen (`4/66`, `23-33`, `20\116`, `8/5A`).
|
|
118
|
+
*/
|
|
119
|
+
const HOUSE_NUMBER = /^\d+\p{L}?(?:[/\\-]\d+\p{L}?)?$/u
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* A street value that carries the house number after a comma, as `Zarifa Aliyeva,38`.
|
|
123
|
+
*/
|
|
124
|
+
const STREET_WITH_NUMBER = /^(.+?),\s*(\d+\p{L}?(?:\/\d+\p{L}?)?)$/u
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* A block (`məhəllə`) code in the number column, as `558-ci0mehelle030`.
|
|
128
|
+
*/
|
|
129
|
+
const BLOCK_CODE = /mehelle/iu
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The house number `STRT_ADDR` states, with a backslash read as the slash it stands for,
|
|
133
|
+
* or null when the value is absent, `0`, or not a house number.
|
|
134
|
+
*/
|
|
135
|
+
function houseNumberFrom(value: string | null, tally: Pick<AdapterOptions, "dropped">): string | null {
|
|
136
|
+
if (!value || value === "0") return null
|
|
137
|
+
|
|
138
|
+
if (BLOCK_CODE.test(value)) {
|
|
139
|
+
countDropped(tally, "component:house_number:block-code")
|
|
140
|
+
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!HOUSE_NUMBER.test(value)) {
|
|
145
|
+
countDropped(tally, "component:house_number:not-a-number")
|
|
146
|
+
|
|
147
|
+
return null
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return value.replaceAll("\\", "/")
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The fields of one spelling: the street, venue, district and city columns it reads.
|
|
155
|
+
*/
|
|
156
|
+
interface SpellingFields {
|
|
157
|
+
street: string | null
|
|
158
|
+
venue: string | null
|
|
159
|
+
state: string | null
|
|
160
|
+
city: string | null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function fieldsFor(record: AzerbaijanPlaceRecord, spelling: AzerbaijanSpelling): SpellingFields {
|
|
164
|
+
if (spelling === AzerbaijanSpelling.Azerbaijani) {
|
|
165
|
+
return {
|
|
166
|
+
street: present(record.STRT_N_AZ),
|
|
167
|
+
venue: present(record.NAME_AZ),
|
|
168
|
+
state: present(record.STATE_AZ) ?? present(record.STATE),
|
|
169
|
+
city: present(record.CITY_AZ) ?? present(record.CITY),
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
street: present(record.STRT_NAME),
|
|
175
|
+
venue: present(record.NAME),
|
|
176
|
+
state: present(record.STATE),
|
|
177
|
+
city: present(record.CITY),
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Whether a city value is the Absheron district, in either spelling.
|
|
183
|
+
*/
|
|
184
|
+
function isAbsheron(city: string): boolean {
|
|
185
|
+
return /^Ab(?:sh|ş)eron$/iu.test(city)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Maps one record onto the components the corpus asserts in one spelling,
|
|
190
|
+
* or returns null when the row is refused.
|
|
191
|
+
*
|
|
192
|
+
* Each refusal and each dropped component increments its reason in `dropped`.
|
|
193
|
+
*/
|
|
194
|
+
export function componentsForAzerbaijanRecord(
|
|
195
|
+
record: AzerbaijanPlaceRecord,
|
|
196
|
+
dropped?: Pick<AdapterOptions, "dropped">,
|
|
197
|
+
spelling: AzerbaijanSpelling = AzerbaijanSpelling.Transliterated
|
|
198
|
+
): CanonicalRow["components"] | null {
|
|
199
|
+
const tally = dropped ?? {}
|
|
200
|
+
const fields = fieldsFor(record, spelling)
|
|
201
|
+
let street = fields.street
|
|
202
|
+
|
|
203
|
+
if (!street) {
|
|
204
|
+
countDropped(tally, "row:no-street")
|
|
205
|
+
|
|
206
|
+
return null
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (/[{@]/u.test(street)) {
|
|
210
|
+
countDropped(tally, "row:street-markup")
|
|
211
|
+
|
|
212
|
+
return null
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let houseNumber = houseNumberFrom(present(record.STRT_ADDR), tally)
|
|
216
|
+
const carried = STREET_WITH_NUMBER.exec(street)
|
|
217
|
+
|
|
218
|
+
if (carried) {
|
|
219
|
+
street = carried[1]!.trim()
|
|
220
|
+
houseNumber ??= carried[2]!
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (/\(/u.test(street)) {
|
|
224
|
+
street = street.replaceAll(/\s*\([^)]*\)\s*/gu, " ").trim()
|
|
225
|
+
countDropped(tally, "component:street:parenthetical-removed")
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (!street || street.includes(",")) {
|
|
229
|
+
countDropped(tally, "row:street-holds-several-parts")
|
|
230
|
+
|
|
231
|
+
return null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const components: CanonicalRow["components"] = { street }
|
|
235
|
+
|
|
236
|
+
if (houseNumber) {
|
|
237
|
+
components.house_number = houseNumber
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const venue = fields.venue
|
|
241
|
+
|
|
242
|
+
// A value with no run of three letters (`555`, `SM`, `T T`) is a code rather than a name.
|
|
243
|
+
if (venue && !/\p{L}{3}/u.test(venue)) {
|
|
244
|
+
countDropped(tally, "component:venue:code")
|
|
245
|
+
} else if (venue) {
|
|
246
|
+
components.venue = venue
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!components.house_number && !components.venue) {
|
|
250
|
+
countDropped(tally, "row:no-house-number-or-venue")
|
|
251
|
+
|
|
252
|
+
return null
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const city = fields.city
|
|
256
|
+
const district = fields.state?.split(",").pop()?.trim() || null
|
|
257
|
+
|
|
258
|
+
if (!city) {
|
|
259
|
+
countDropped(tally, "row:no-city")
|
|
260
|
+
|
|
261
|
+
return null
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (isAbsheron(city)) {
|
|
265
|
+
components.locality = district ?? city
|
|
266
|
+
} else {
|
|
267
|
+
components.locality = city
|
|
268
|
+
|
|
269
|
+
if (district && district.toLowerCase() !== city.toLowerCase() && !/^Sum[gq]ayit$/iu.test(district)) {
|
|
270
|
+
components.dependent_locality = district
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return components
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function createAzerbaijanPlacesAdapter(): CorpusAdapter {
|
|
278
|
+
return {
|
|
279
|
+
id: OPENDATA_AZ_ADAPTER_ID,
|
|
280
|
+
defaultLicense: OPENDATA_AZ_LICENSE,
|
|
281
|
+
addressRole: AddressRole.Premise,
|
|
282
|
+
register: SourceRegister.AzerbaijanObjectsAndPlaces,
|
|
283
|
+
surface: SurfaceOrigin.Rendered,
|
|
284
|
+
description:
|
|
285
|
+
"Azərbaycanda obyektlər və məkanlar (Ministry of Ecology and Natural Resources, opendata.az): addressed places in Baku, Sumgayit and Absheron.",
|
|
286
|
+
|
|
287
|
+
async *rows(opts: AdapterOptions): AsyncIterable<CanonicalRow> {
|
|
288
|
+
if (opts.country && !OPENDATA_AZ_COUNTRIES.includes(opts.country)) {
|
|
289
|
+
throw new UnsupportedCountryError(OPENDATA_AZ_ADAPTER_ID, OPENDATA_AZ_COUNTRIES, opts.country)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// The publication is one 5 MB file, so it is parsed whole.
|
|
293
|
+
const path = resolvePath(opts.inputPath)
|
|
294
|
+
const collection = parseJSONStrict<AzerbaijanFeatureCollection>(await readLocalTextFile(path))
|
|
295
|
+
|
|
296
|
+
if (!Array.isArray(collection.features)) {
|
|
297
|
+
throw new TypeError(`${OPENDATA_AZ_ADAPTER_ID} adapter: ${path} holds no GeoJSON features array`)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
let emitted = 0
|
|
301
|
+
|
|
302
|
+
for (const feature of collection.features) {
|
|
303
|
+
const record = feature.properties
|
|
304
|
+
|
|
305
|
+
if (!record) {
|
|
306
|
+
countDropped(opts, "row:no-properties")
|
|
307
|
+
|
|
308
|
+
continue
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const [lon, lat] = feature.geometry?.coordinates ?? []
|
|
312
|
+
let transliterated: string | null = null
|
|
313
|
+
|
|
314
|
+
const spellings = present(record.STRT_N_AZ)
|
|
315
|
+
? [AzerbaijanSpelling.Transliterated, AzerbaijanSpelling.Azerbaijani]
|
|
316
|
+
: [AzerbaijanSpelling.Transliterated]
|
|
317
|
+
|
|
318
|
+
for (const spelling of spellings) {
|
|
319
|
+
if (opts.signal?.aborted) return
|
|
320
|
+
|
|
321
|
+
if (opts.limit !== undefined && emitted >= opts.limit) return
|
|
322
|
+
|
|
323
|
+
// The Azerbaijani row is counted under its own prefix, so its refusals
|
|
324
|
+
// do not read as refusals of records.
|
|
325
|
+
const tally = spelling === AzerbaijanSpelling.Azerbaijani ? { dropped: new Map<string, number>() } : opts
|
|
326
|
+
const components = componentsForAzerbaijanRecord(record, tally, spelling)
|
|
327
|
+
|
|
328
|
+
if (spelling === AzerbaijanSpelling.Azerbaijani) {
|
|
329
|
+
for (const [reason, count] of tally.dropped ?? []) {
|
|
330
|
+
const key = `azerbaijani-spelling:${reason}`
|
|
331
|
+
|
|
332
|
+
opts.dropped?.set(key, (opts.dropped.get(key) ?? 0) + count)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (!components) continue
|
|
337
|
+
|
|
338
|
+
const rendered = formatAddressRow(components, "AZ", { singleLine: true })
|
|
339
|
+
|
|
340
|
+
if (!rendered) {
|
|
341
|
+
countDropped(opts, "row:render-failed")
|
|
342
|
+
|
|
343
|
+
continue
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
for (const tag of rendered.unplaced) {
|
|
347
|
+
countDropped(opts, `component:${tag}:not-rendered`)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const { raw, components: aligned } = rendered
|
|
351
|
+
|
|
352
|
+
if (spelling === AzerbaijanSpelling.Transliterated) {
|
|
353
|
+
transliterated = raw
|
|
354
|
+
} else if (raw === transliterated) {
|
|
355
|
+
countDropped(opts, "azerbaijani-spelling:row:renders-as-transliterated")
|
|
356
|
+
|
|
357
|
+
continue
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
yield {
|
|
361
|
+
raw,
|
|
362
|
+
components: aligned,
|
|
363
|
+
country: "AZ",
|
|
364
|
+
locale: spelling === AzerbaijanSpelling.Azerbaijani ? "az-AZ" : "en-AZ",
|
|
365
|
+
source: OPENDATA_AZ_ADAPTER_ID,
|
|
366
|
+
// `OBJECTID` is unique per feature.
|
|
367
|
+
// The spelling separates a feature's two rows.
|
|
368
|
+
source_id: stableSourceIDFromParts(OPENDATA_AZ_ADAPTER_ID, {
|
|
369
|
+
...aligned,
|
|
370
|
+
objectid: present(record.OBJECTID) ?? "",
|
|
371
|
+
spelling,
|
|
372
|
+
lat: typeof lat === "number" ? String(lat) : "",
|
|
373
|
+
lon: typeof lon === "number" ? String(lon) : "",
|
|
374
|
+
}),
|
|
375
|
+
corpus_version: "",
|
|
376
|
+
license: OPENDATA_AZ_LICENSE,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
emitted++
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* The configured adapter instance registered with the corpus builder.
|
|
388
|
+
*/
|
|
389
|
+
export const azerbaijanPlacesAdapter = createAzerbaijanPlacesAdapter()
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `gbpa-bs`: the address points of the Grand Bahama Port Authority (GBPA), covering the City of Freeport
|
|
7
|
+
* and Lucaya on Grand Bahama, which the GBPA publishes in its `GBPA/gis-datafiles` repository on GitHub.
|
|
8
|
+
* The adapter reads the CSV export, `CSV/addresses.csv`.
|
|
9
|
+
*
|
|
10
|
+
* A Freeport address number is a block and a parcel joined by a hyphen (`8-29 Seagull Drive`), and either
|
|
11
|
+
* part may be lettered (`UU-3`, `13-43C`, `W-A-10`). The adapter reads `AddressNum` as the house number,
|
|
12
|
+
* `FullStName` as the street, `City` as the locality, `Island` as the region and `AltName` as a venue
|
|
13
|
+
* (`Lucayan International School`, `Shoreline`). The export truncates some parcel ids to five characters and
|
|
14
|
+
* a star (`Minis*`), and those numbers are dropped.
|
|
15
|
+
*
|
|
16
|
+
* The export repeats the street's name in a few records (`Rippindale Rippindale`, and across an embedded
|
|
17
|
+
* line break `Santa Maria \r\nSanta Maria Avenue`). The adapter collapses the repeat and counts it.
|
|
18
|
+
*
|
|
19
|
+
* The GBPA licenses the data under CC BY 4.0 and asks for the statement "Data Provided by The Grand Bahama
|
|
20
|
+
* Port Authority". Every row records that license.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { formatAddressRow } from "@mailwoman/codex/address/format"
|
|
24
|
+
import { readLocalBuffer } from "@mailwoman/core/fs/readers"
|
|
25
|
+
import { resolvePath } from "path-ts"
|
|
26
|
+
import { CSVSpliterator } from "spliterator"
|
|
27
|
+
|
|
28
|
+
import { UnsupportedCountryError } from "#adapters/errors"
|
|
29
|
+
import { stableSourceIDFromParts } from "#adapters/source-id"
|
|
30
|
+
import { SourceRegister } from "#registers"
|
|
31
|
+
import {
|
|
32
|
+
AddressRole,
|
|
33
|
+
type AdapterOptions,
|
|
34
|
+
type CanonicalRow,
|
|
35
|
+
type CorpusAdapter,
|
|
36
|
+
countDropped,
|
|
37
|
+
SurfaceOrigin,
|
|
38
|
+
} from "#types"
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Registry id for this adapter, stamped into every row it emits.
|
|
42
|
+
*/
|
|
43
|
+
export const GBPA_BS_ADAPTER_ID = "gbpa-bs"
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The license the GBPA publishes the repository's data under.
|
|
47
|
+
*/
|
|
48
|
+
export const GBPA_BS_LICENSE = "CC-BY-4.0"
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The attribution statement the GBPA asks for.
|
|
52
|
+
*/
|
|
53
|
+
export const GBPA_BS_ATTRIBUTION = "Data Provided by The Grand Bahama Port Authority"
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Every jurisdiction this adapter emits, checked against a caller's `--country`.
|
|
57
|
+
*/
|
|
58
|
+
export const GBPA_BS_COUNTRIES: readonly string[] = ["BS"]
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The columns the adapter reads from `CSV/addresses.csv`.
|
|
62
|
+
*/
|
|
63
|
+
export interface GBPAAddressRecord {
|
|
64
|
+
Y: string
|
|
65
|
+
X: string
|
|
66
|
+
AddID: string
|
|
67
|
+
AltName: string
|
|
68
|
+
Suffix: string
|
|
69
|
+
FullStName: string
|
|
70
|
+
AddressNum: string
|
|
71
|
+
City: string
|
|
72
|
+
Island: string
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A value with its whitespace, including the export's embedded line breaks, collapsed, or null when empty.
|
|
77
|
+
*/
|
|
78
|
+
function present(value: string | undefined): string | null {
|
|
79
|
+
const trimmed = value?.replaceAll(/\s+/gu, " ").trim() ?? ""
|
|
80
|
+
|
|
81
|
+
return trimmed || null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* A block and parcel number: alphanumeric parts joined by hyphens (`8-29`, `UU-3`, `W-A-10`, `G-3B10`, `L`).
|
|
86
|
+
*/
|
|
87
|
+
const ADDRESS_NUMBER = /^[A-Z\d]+(?:-[A-Z\d]+)*$/iu
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A street's name repeated before its type (`Santa Maria Santa Maria Avenue`)
|
|
91
|
+
* or after it (`Wragby Wragby`).
|
|
92
|
+
*/
|
|
93
|
+
const REPEATED_NAME = /^(.+?) \1(?= |$)/u
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A street value that is only a type word, with no name before it.
|
|
97
|
+
*/
|
|
98
|
+
const TYPE_WORD_ONLY = /^(?:road|lane|drive|avenue|street|court|close|way|place|circle|terrace|crescent)$/iu
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Initials and a surname alone (`J.S. Johnson`) name a person rather than a place or a business.
|
|
102
|
+
*/
|
|
103
|
+
const INITIALS_AND_SURNAME = /^(?:\p{Lu}\.\s*)+\p{Lu}\p{Ll}+$/u
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Maps one record onto the components the corpus asserts, or returns null when the row is refused.
|
|
107
|
+
*
|
|
108
|
+
* Each refusal and each dropped or repaired component increments its reason in `dropped`.
|
|
109
|
+
*/
|
|
110
|
+
export function componentsForGBPARecord(
|
|
111
|
+
record: GBPAAddressRecord,
|
|
112
|
+
dropped?: Pick<AdapterOptions, "dropped">
|
|
113
|
+
): CanonicalRow["components"] | null {
|
|
114
|
+
const tally = dropped ?? {}
|
|
115
|
+
let street = present(record.FullStName)
|
|
116
|
+
|
|
117
|
+
if (!street) {
|
|
118
|
+
countDropped(tally, "row:no-street")
|
|
119
|
+
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (REPEATED_NAME.test(street)) {
|
|
124
|
+
street = street.replace(REPEATED_NAME, "$1")
|
|
125
|
+
countDropped(tally, "component:street:repeated-name-collapsed")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (TYPE_WORD_ONLY.test(street)) {
|
|
129
|
+
countDropped(tally, "row:street-is-a-type-word")
|
|
130
|
+
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const components: CanonicalRow["components"] = { street }
|
|
135
|
+
const number = present(record.AddressNum)
|
|
136
|
+
|
|
137
|
+
if (number && ADDRESS_NUMBER.test(number)) {
|
|
138
|
+
components.house_number = number
|
|
139
|
+
} else if (number?.includes("*")) {
|
|
140
|
+
countDropped(tally, "component:house_number:truncated")
|
|
141
|
+
} else if (number) {
|
|
142
|
+
countDropped(tally, "component:house_number:not-a-block-parcel-number")
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const venue = present(record.AltName)
|
|
146
|
+
|
|
147
|
+
if (venue && !/\p{L}{3}/u.test(venue)) {
|
|
148
|
+
countDropped(tally, "component:venue:code")
|
|
149
|
+
} else if (venue && /(\p{L})\1{3,}$/u.test(venue)) {
|
|
150
|
+
// `Bellevue Gifts & Suppliesccccc` carries a run of repeated keystrokes.
|
|
151
|
+
countDropped(tally, "component:venue:malformed")
|
|
152
|
+
} else if (venue && INITIALS_AND_SURNAME.test(venue)) {
|
|
153
|
+
countDropped(tally, "component:venue:names-a-person")
|
|
154
|
+
} else if (venue) {
|
|
155
|
+
components.venue = venue
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!components.house_number && !components.venue) {
|
|
159
|
+
countDropped(tally, "row:no-house-number-or-name")
|
|
160
|
+
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const locality = present(record.City)
|
|
165
|
+
const region = present(record.Island)
|
|
166
|
+
|
|
167
|
+
if (locality) {
|
|
168
|
+
components.locality = locality
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (region) {
|
|
172
|
+
components.region = region
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!components.locality) {
|
|
176
|
+
countDropped(tally, "row:no-locality")
|
|
177
|
+
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return components
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function createGBPAAdapter(): CorpusAdapter {
|
|
185
|
+
return {
|
|
186
|
+
id: GBPA_BS_ADAPTER_ID,
|
|
187
|
+
defaultLicense: GBPA_BS_LICENSE,
|
|
188
|
+
addressRole: AddressRole.Premise,
|
|
189
|
+
register: SourceRegister.GrandBahamaPortAuthorityAddresses,
|
|
190
|
+
surface: SurfaceOrigin.Rendered,
|
|
191
|
+
description: "Grand Bahama Port Authority address points (Freeport and Lucaya), GBPA/gis-datafiles CSV export.",
|
|
192
|
+
|
|
193
|
+
async *rows(opts: AdapterOptions): AsyncIterable<CanonicalRow> {
|
|
194
|
+
if (opts.country && !GBPA_BS_COUNTRIES.includes(opts.country)) {
|
|
195
|
+
throw new UnsupportedCountryError(GBPA_BS_ADAPTER_ID, GBPA_BS_COUNTRIES, opts.country)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// The file is 8 MB, so it is decoded whole.
|
|
199
|
+
// The BOM would otherwise prefix the first header.
|
|
200
|
+
const text = (await readLocalBuffer(resolvePath(opts.inputPath))).toString("utf8").replace(/^/u, "")
|
|
201
|
+
const records = CSVSpliterator.from<GBPAAddressRecord>(Buffer.from(text, "utf8"), { normalizeKeys: false })
|
|
202
|
+
let emitted = 0
|
|
203
|
+
|
|
204
|
+
for (const record of records) {
|
|
205
|
+
if (opts.signal?.aborted) return
|
|
206
|
+
|
|
207
|
+
if (opts.limit !== undefined && emitted >= opts.limit) return
|
|
208
|
+
|
|
209
|
+
const components = componentsForGBPARecord(record, opts)
|
|
210
|
+
|
|
211
|
+
if (!components) continue
|
|
212
|
+
|
|
213
|
+
const rendered = formatAddressRow(components, "BS", { singleLine: true })
|
|
214
|
+
|
|
215
|
+
if (!rendered) {
|
|
216
|
+
countDropped(opts, "row:render-failed")
|
|
217
|
+
|
|
218
|
+
continue
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
for (const tag of rendered.unplaced) {
|
|
222
|
+
countDropped(opts, `component:${tag}:not-rendered`)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const { raw, components: aligned } = rendered
|
|
226
|
+
|
|
227
|
+
yield {
|
|
228
|
+
raw,
|
|
229
|
+
components: aligned,
|
|
230
|
+
country: "BS",
|
|
231
|
+
locale: "en-BS",
|
|
232
|
+
source: GBPA_BS_ADAPTER_ID,
|
|
233
|
+
// The GBPA's own address id separates two points the rendered components cannot.
|
|
234
|
+
source_id: stableSourceIDFromParts(GBPA_BS_ADAPTER_ID, { ...aligned, add_id: record.AddID ?? "" }),
|
|
235
|
+
corpus_version: "",
|
|
236
|
+
license: GBPA_BS_LICENSE,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
emitted++
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The configured adapter instance registered with the corpus builder.
|
|
247
|
+
*/
|
|
248
|
+
export const gbpaAdapter = createGBPAAdapter()
|
package/lib/build/types.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { PathBuilderLike } from "path-ts"
|
|
|
13
13
|
|
|
14
14
|
import type { ParquetManifest } from "#parquet/writers"
|
|
15
15
|
import type { AdapterRunManifest } from "#runner"
|
|
16
|
+
import type { SourceRightsRecord } from "#source-register/corpus-inputs"
|
|
16
17
|
import type { AdapterOptions, CorpusAdapter } from "#types"
|
|
17
18
|
import type { LicensePolicy, LicenseRefusalKind } from "#utils/license"
|
|
18
19
|
import type { SplitManifest } from "#utils/split"
|
|
@@ -142,6 +143,16 @@ export interface BuildCorpusOptions {
|
|
|
142
143
|
* @defaultValue {@linkcode BuildProfile.Exploratory}
|
|
143
144
|
*/
|
|
144
145
|
profile?: BuildProfile
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Why a local experiment admits sources whose register rows lack an elected
|
|
149
|
+
* decision permitting `transform` and `train`.
|
|
150
|
+
*
|
|
151
|
+
* Without it the build refuses such a source before any adapter runs.
|
|
152
|
+
* With it the build logs every gap and records the corpus as not shippable
|
|
153
|
+
* in {@linkcode BuildCorpusManifest.source_rights}.
|
|
154
|
+
*/
|
|
155
|
+
unshippableReason?: string
|
|
145
156
|
}
|
|
146
157
|
|
|
147
158
|
/**
|
|
@@ -231,4 +242,9 @@ export interface BuildCorpusManifest {
|
|
|
231
242
|
* That file is the frozen record of which sources contributed and under which terms.
|
|
232
243
|
*/
|
|
233
244
|
training_manifest_digest: string
|
|
245
|
+
/**
|
|
246
|
+
* Whether every source this build emitted reads only register sources whose decisions permit
|
|
247
|
+
* `transform` and `train`, and the gaps an `unshippableReason` admitted when they do not.
|
|
248
|
+
*/
|
|
249
|
+
source_rights: SourceRightsRecord
|
|
234
250
|
}
|