/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * Extract `(postcode, locality, region, country)` tuples for the `trailing-region` recipe. * * Each tuple is stamped with its country's {@link PostcodePlacement}, because the same digits change tag with position. */ import { PathBuilder, type PathBuilderLike } from "path-ts"; import type { PostcodePlacement } from "#recipes/scaffold"; /** * One extracted tuple, in the shape `readTuples` yields and the recipe consumes. */ export interface PostcodeTriple { postcode: string; /** * The segment before the locality, when the source has one. * * A recipe output whose every row begins with the locality teaches that the first segment is the locality. */ dependentLocality?: string; locality: string; region: string; country: string; cc: string; locale: string; postcodePlacement: PostcodePlacement; } /** * The GeoNames postal column that contains the locality for a country. * * `admin2` is the default. * For the US it is the inverse, because column 3 is the city and admin2 the county, * so taking the default would train counties as cities. */ export type GeonamesLocalityColumn = "place" | "admin2"; /** * Records where a country writes the postcode. * It also records the locale tag in its rows. * * A country is in this table only when a gauntlet board row attests its surface, because extracting * an absent country with the wrong placement teaches a convention that country does not use. */ export declare const POSTCODE_CONVENTIONS: ReadonlyMap; /** * How many postcodes one locality may contribute. * * A quota rather than a cutoff: it bounds repetition without deleting a locality. */ export declare const DEFAULT_LOCALITY_QUOTA = 24; /** * Take at most `quota` tuples per locality, in the order they arrive. * * Both readers walk their source in id/file order. * That order is stable across runs, so the same quota selects the same rows. */ export declare function applyLocalityQuota(triples: readonly T[], quota?: number): T[]; /** * Take at most `budget` tuples per country, in the order they arrive. * * Applied after {@link applyLocalityQuota}, and spent BY region in rounds so a cap * smaller than the source still reaches every region rather than one corner. * `subKey` adds a second round-robin dimension so the budget spreads across `(region, subKey)`. */ export declare function applyCountryBudget(triples: readonly T[], budget: number | ReadonlyMap, subKey?: (triple: T) => string): T[]; /** * A place's preferred names in the languages its addresses are written in, * read from the gazetteer's `names` table. */ interface PreferredNames { /** * Preferred names in the country's official languages, in the table's order. */ official: readonly string[]; /** * Preferred names in the region's co-official languages. */ coOfficial: readonly string[]; } /** * The surfaces a region is written as: its preferred names in the official language(s), * then the region's co-official languages, then the gazetteer's own `spr.name` * (the English exonym), deduplicated with order kept. * * An input that uses only `spr.name` teaches stripped exonyms (`Balearic Islands`, `Cordoba`) * against the forms a user writes. */ export declare function regionWrittenForms(sprName: string, names: PreferredNames): string[]; /** * The surface a locality is written as: the official-language preferred name matching * `spr.name` folded, else the first official-language name, else `spr.name`. */ export declare function localityWrittenForm(sprName: string, names: PreferredNames): string; /** * Read triples out of `postalcode-intl.db` by following each postcode's `parent_id` * into the admin gazetteer and that place's ancestry to a region. * * A postcode whose parent does not resolve, or whose parent has no region ancestor, * is dropped rather than emitted with a blank. */ export declare function readTriplesFromParentJoin(countries: readonly string[], options?: { postcodeDB?: PathBuilderLike; adminDB?: PathBuilderLike; }): Promise; /** * One extracted `(locality, region, country)` pair, carrying no postcode. */ export type AdminPair = Omit; /** * Read `(locality, region, country)` pairs for a country straight from the * admin gazetteer, with no postcode. * * Produces one pair per region surface, following {@link readTriplesFromParentJoin}. * The reader synthesizes no postcode. */ export declare function readPairsFromAdmin(countries: readonly string[], options?: { adminDB?: PathBuilderLike; locale?: (cc: string) => string; }): Promise; /** * A predicate answering whether a name is a locality the admin gazetteer knows, for one country. * * The parent-join reader supplies this field directly. * The GeoNames reader requires this correction because treating a colonia as `locality` * teaches the wrong locality/dependent_locality boundary. * * @throws When the gazetteer is not on disk, because a predicate that accepted every * name would emit unfiltered rows as though the filter had run. */ export declare function createKnownLocalityCheck(country: string, adminDB?: PathBuilderLike): Promise<(name: string) => boolean>; /** * Read triples straight out of a GeoNames `.txt` export, with no join. * * `admin2` supplies the locality, `admin1` supplies the region and column 3 supplies the dependent locality. * A locality value from column 3 taught `Mahatma Gandhi Road` as a city. * * A country whose export lacks admin1 or admin2 yields zero from this reader. * That result is correct and needs no fallback. * * Hyphen-format countries publish each code twice, so the first surface of a code wins. */ export declare function readTriplesFromGeonames(country: string, path: PathBuilderLike, countryName: string, options?: { isKnownLocality?: (name: string) => boolean; }): Promise; /** * Resolve a GeoNames export path under the standard fetch out-root. */ export declare function geonamesPostalPath(country: string, sourcesRoot?: PathBuilderLike): PathBuilder; export {}; //# sourceMappingURL=postcode-triples.d.ts.map