/**
 * Column → role classification.
 *
 * Every column gets at most one role, first match wins, in the precedence
 * below. One role per column is what keeps a profile reproducible: `lat` is
 * geo and never also a numeric metric, `year` is temporal and never a metric.
 *
 * Roles are named after the catalog `dataRoles` ids they feed (geo, metric,
 * category, nodes, links, events, claim, sources, entity). Nothing here maps
 * to a DataProfile field that does not exist — see spec/data-profile.ts.
 */
import { type Table, type TableColumn } from './table.js';
export type ColumnRole = 'link' | 'node' | 'geo' | 'temporal' | 'entity' | 'claim' | 'sources' | 'event' | 'control' | 'label' | 'metric' | 'category' | 'empty';
/** Shared with widget-payload lat/lng marker detection. */
export declare const GEO_LAT_NAMES: readonly ["lat", "latitude"];
export declare const GEO_LNG_NAMES: readonly ["lng", "lon", "long", "longitude"];
export type ClassifiedColumn = {
    column: TableColumn;
    key: string;
    role: ColumnRole;
};
export type Classification = {
    columns: readonly ClassifiedColumn[];
    /** True when the table describes form controls rather than dataset rows. */
    isControlTable: boolean;
};
export declare function classifyColumns(table: Table): Classification;
/** Non-empty cells, trimmed. Blank cells never carry a signal. */
export declare function filled(column: TableColumn): string[];
export declare function distinctCount(column: TableColumn): number;
