/** * Data-to-geometry joins, and diagnostics for when they fail. * * Roughly nine in ten real-world map failures are join failures: "Ivory Coast" * against "Côte d'Ivoire", ISO-2 against ISO-3, or a FIPS code that lost its * leading zero in a spreadsheet round-trip. Every library today renders the * unmatched features in no-data grey and says nothing, so the developer spends * an hour diffing strings. * * Design rules: * * - **Matching is exact by default.** Silent fuzzy matching would trade an * obvious failure for a plausible wrong answer, which is worse. * - **Every mismatch is reported, with a suggestion.** Normalisation, a curated * alias table and edit distance are used to explain failures, not to hide them. * - **Opt-in `fuzzy: true` applies normalised matches**, and logs exactly what * it did, so the convenience is auditable. * * @module data/Join */ import type { JoinSpec, NormalizedFeature } from '../types'; export interface JoinSuggestion { featureKey: string; name?: string; /** 0..1, higher is closer. */ score: number; reason: 'alias' | 'normalized' | 'padded' | 'similar'; } export interface UnmatchedRow { key: string; row: unknown; suggestions: JoinSuggestion[]; } export interface JoinResult { /** Feature key to datum. */ index: Map; /** Feature position to datum, for rendering. */ byFeatureIndex: Map; matched: number; totalData: number; totalFeatures: number; unmatchedData: UnmatchedRow[]; unmatchedFeatures: { key: string; name?: string; }[]; /** * Keys held by more than one feature, and the features holding them. * * This is a property of published geometry, not a mistake: Natural Earth gives * Australia, the Indian Ocean Territories and Ashmore and Cartier Islands the * same `iso_a3`, and Lord Howe Island carries `AU-NSW` alongside New South * Wales. One data row legitimately colours all of them. It is reported because * a developer counting polygons will otherwise wonder why 4 rows lit up 7 * shapes. */ sharedKeys: { key: string; count: number; names: string[]; }[]; /** Substitutions that were applied, so the convenience stays auditable. */ applied: string[]; geoKeyField: string; dataKeyField: string; /** Human-readable multi-line diagnostic. */ report: () => string; } /** * Aggressive normalisation used only for suggestions and opt-in fuzzy matching: * strip diacritics, lowercase, drop everything that is not alphanumeric. * */ export declare function normalizeKey(value: unknown): string; /** * Levenshtein distance with a two-row buffer. * */ export declare function levenshtein(a: string, b: string): number; /** Similarity in 0..1. */ export declare function similarity(a: string, b: string): number; /** * Detect the zero-padded-numeric-code shape (FIPS, GEOID, some postcodes). * * Returns the common width when every feature key is a fixed-width numeric * string and at least one carries a leading zero. That combination is the * signature of a code system that a spreadsheet will happily destroy. * */ export declare function detectPaddedNumericWidth(keys: string[]): number | null; /** * Resolve which field on the data rows holds the join key. * */ export declare function resolveDataKeyField(data: readonly unknown[], explicit?: string): string; /** * Join data rows to normalized features. * */ export declare function resolveJoin({ features, data, joinBy, geoKeyField, fuzzy, maxSuggestions, }: { features: NormalizedFeature[]; data: readonly unknown[]; joinBy?: JoinSpec; /** Field the geometry keys came from, used in messages. */ geoKeyField?: string; /** Apply normalised and alias matches. Default false. */ fuzzy?: boolean; maxSuggestions?: number; }): JoinResult; //# sourceMappingURL=Join.d.ts.map