import type { LayerMeta, LayerFilter, LayerCategoryFilter } from "./ir"; import type { LayerSchema, PropDescriptor } from "./layer-registry"; import type { Shape } from "./expr"; /** Sweeps the shared caches down to exactly the keys still referenced by the current manifest (Q4). */ export declare function sweepAccessorCache(liveKeys: ReadonlySet): void; /** * Reserved attributes whose FEATURE is design-only (spec'd, not built). * Reserved-ness suppresses the unknown-attribute warning — which is exactly * how the streaming attributes (`source`/`key`/`flush`) sat silently inert * for weeks before implementation. This list turns a dead promise into a * loud one: both the live resolver and the validator warn from it, and * implementing the feature means deleting its entry here (the traceability * table in the spec tracks the same state). */ export declare const INERT_RESERVED_ATTRS: Map; /** Attributes with library-level meaning that never reach deck.gl as a prop. */ export declare const RESERVED_ATTRS: Set; /** * Filtering (spec: "Filtering") is universal across every layer type — not * tied to one schema's props like `pickable` — so it's resolved directly * here rather than via `schema.props`, and excluded from the typo-check the * same way `RESERVED_ATTRS` is. `filter-field`/`filter-range`/ * `filter-soft-range` are the single-dimension surface; `filter-fields` is * the multi-dimension one (up to 4 — `DataFilterExtension`'s own ceiling), * a JSON array of `{field, range, softRange?}` objects. Categorical * filtering (`filter-category`/`filter-categories`) is a separate slot, * unrelated to the numeric dimension count. */ export declare const FILTER_ATTRS: Set; /** * Dashed lines (`dash="[6, 3]"`) are universal across the path-rendering layers, * like filtering — resolved here, not per-schema, and excluded from the * typo-check the same way. Dashes come from `@deck.gl/extensions`' * `PathStyleExtension` (already bundled for DataFilterExtension), which only * applies to layers that stroke a path. */ /** `data-emit`-style attribute name → camelCase (shared by om-map's payload reads and om-story's step parsing — both DOM-lane, one regex). */ export declare function kebabToCamel(name: string): string; export declare const DASH_ATTRS: Set; /** Classified symbology (spec: issue #12; src/classify.ts) — universal layer attributes like `filter-*`, resolved where the data is in hand (parse-manifest / descriptorToIR), never per-schema deck props. */ export declare const CLASSIFY_ATTRS: Set; /** Layer types whose deck class strokes a path, so PathStyleExtension's dash takes effect (GeoJsonLayer/PolygonLayer dash their line/stroke sublayers). */ export declare const DASH_CAPABLE_LAYERS: Set; /** A dash pattern authored as a JSON array (`[6, 3]`) OR an SVG-style token list (`6 3`, `6,3`) → `[dashLength, gapLength]`; undefined if it isn't two finite positive numbers. */ export declare function parseDashArray(raw: string): [number, number] | undefined; /** Already-coerced dash declaration — attribute strings (DOM) or typed values (programmatic). */ export interface LayerDashSpec { /** `[dashLength, gapLength]` in line-width units, or undefined when no dash is authored. */ dashArray?: [number, number]; /** Stretch each segment's dashes to start and end on a dash (deck `dashJustified`). */ dashJustified?: boolean; } /** * Mount PathStyleExtension + set the dash accessor when a path-capable layer * authored `dash`. Mirrors applyFilterWiring: dedup the extension, set the deck * props, and share one definition between the DOM and programmatic front-ends. * `dash` on a non-path layer is a no-op with a warning (deck would silently * ignore it otherwise — the invisible-attribute class of confusion). */ export declare function applyDashWiring(props: Record, spec: LayerDashSpec, layerType: string, warnLabel: string): void; /** One numeric filter dimension, already-coerced (attribute strings or typed programmatic values). */ export interface LayerFilterFieldSpec { field: string; range?: [number, number]; softRange?: [number, number]; } /** * Already-coerced filter declaration — attribute strings (DOM front-end) or * typed values (programmatic front-end). `filterField`/`filterRange`/ * `filterSoftRange` are the original single-dimension surface (still fully * supported, zero migration needed); `filterFields` is the multi-dimension * one. If both are present `filterFields` wins outright (validation warns * separately about the ambiguity) — `applyFilterWiring` never merges them * into a combined set, since which slot the singular field would occupy is * not a well-defined question. */ export interface LayerFilterSpec { filterField?: string; filterRange?: [number, number]; filterSoftRange?: [number, number]; filterFields?: LayerFilterFieldSpec[]; filterCategoryField?: string; filterCategories?: unknown[]; filterCategoryFields?: LayerCategoryFilterFieldSpec[]; } /** One categorical filter dimension, already-coerced. `categories` absent = declared but not yet ranged, mirroring the numeric case — dropped from the active filter with a warning, since deck.gl's category mechanism has no "wide open" value to fall back to (unlike a numeric [-Infinity, Infinity] range). */ export interface LayerCategoryFilterFieldSpec { field: string; categories?: (string | number)[]; } /** * Parses the DOM front-end's `filter-fields` JSON attribute — an array of * `{field, range, softRange?}` objects — dropping (with a warning, never a * throw) any entry that isn't shaped like one, so a single malformed entry * degrades to "that dimension is missing" rather than breaking the whole * layer's filter or crashing the reconcile. */ export declare function parseFilterFieldsAttr(raw: string, warnLabel: string): LayerFilterFieldSpec[] | undefined; /** * Parses the DOM front-end's `filter-category-fields` JSON attribute — an * array of `{field, categories}` objects — same defensive shape as * `parseFilterFieldsAttr`: a malformed entry is dropped with a warning, never * a throw. */ export declare function parseFilterCategoryFieldsAttr(raw: string, warnLabel: string): LayerCategoryFilterFieldSpec[] | undefined; /** * GPU filter wiring (spec: "Filtering"), shared by both front-ends (HU2). * `filterRange` is a plain prop (not an accessor): the filter-layer action * just rewrites its attribute, which flows through the normal reconcile -> * deck.gl setProps() diff as a cheap uniform update, never touching * updateTriggers. * * EVERY layer mounts the extension at birth, filtered or not: adding or * removing an extension on a LIVE layer recompiles shaders and corrupts * attribute state (the per-feature-trace washed-out-fill bug), while an * idle numeric slot is free — deck's default getFilterValue is the * CONSTANT 0 (no attribute buffer) inside the default filterRange * [-1, 1], so nothing is culled. A later filter-layer action then only * swaps accessor + range props on the same shaders. The category slot is * NOT pre-mounted: an idle categorySize binds a uint attribute against a * float constant (GL_INVALID_OPERATION in real WebGL), so declaring a * category filter re-mounts the extension — churn accepted for the rare * case, never for the common numeric one. * * `filterSize` (1-4, the count of numeric dimensions) is a deck.gl * *constructor* option that compiles straight into a GLSL define * (`DATAFILTER_TYPE float|vec2|vec3|vec4` — verified against * `@deck.gl/extensions`' own source, not assumed), the same category of * shader-recompile-on-change as `categorySize` above — and empirically * confirmed safe to change on an already-mounted layer the same way * categorySize already is (a `DataFilterExtension` config-value change, * NOT an `extensions` array composition change — the latter is the * documented-elsewhere case that corrupts state, e.g. adding a * `ClipBoxExtension` alongside an already-mounted one; this isn't that). * So `filterSize` is simply `min(dims.length, 4)`, recomputed fresh every * reconcile, no special remount handling needed. The one thing v1 * deliberately does NOT support is an author changing the number of * *declared* dimensions through the `filter-layer` action's merge path — * that's a `filter-layer` contract choice (see `actions.ts`), not a * limitation of this function. * * The unfiltered baseline is a FUNCTION accessor (a buffer of zeros, 4 * bytes/row) plus a baseline trigger — never deck's constant-0 default. * Two empirically-found deck behaviors force this: trigger keys absent * from the NEW props aren't diffed (a cleared patch would keep its stale * buffer), and a buffer→constant accessor transition doesn't rebind the * vertex attribute (the attribute state SAYS constant 0, the GPU still * draws the old buffer). Function→function with a trigger change is the * one transition that recomputes reliably, so every state a layer can * reach — unfiltered, authored filter, runtime populate sweep — is * buffer-backed. * * `categorySize` (0-4) mirrors `filterSize` structurally — same packed * single-value-at-1/array-at->1 accessor and prop shape, same truncate-past-4 * behavior — but is a GENUINELY different mechanism (deck.gl's discrete * bitmask membership test, `FilterCategory = number | string`, NOT a range * comparison), so it's wired independently and returned separately: a layer * can have an active numeric filter, an active categorical filter, both, or * neither, and `ctx`'s coherence rule ANDs whichever are present. Unlike * `filterSize` there is no floor of 1 — 0 (unmounted) is category's true * idle state, so introducing or clearing categorical filtering re-mounts the * extension (see the doc comment above); a category dimension with no * `categories` list is dropped from the active set entirely (warned), since * there's no "wide open" value the way a numeric range has [-Infinity, * Infinity] — an empty/absent keep-list has no honest non-excluding meaning * in a membership test. */ export interface LayerFilterResult { filter?: LayerFilter; categoryFilter?: LayerCategoryFilter; } export declare function applyFilterWiring(props: Record, updateTriggers: Record, shape: Shape, spec: LayerFilterSpec, warnLabel: string): LayerFilterResult; /** * Standard global HTML attributes an author (or the library itself, e.g. * OmLayerElement setting `style.display = "none"`) may set for reasons * unrelated to the layer schema. Never a typo signal. */ export declare const GLOBAL_HTML_ATTRS: Set; /** Shared by the live typo-warning below and the standalone validator (validation.ts) — same signal, two surfaces. */ export declare function isUnknownLayerAttr(attrName: string, schema: LayerSchema): boolean; /** * `transition="get-fill-color 800ms, get-radius 400ms"` → deck.gl's * `transitions` prop (GPU-interpolated per-prop animation — spec: "Map * Stories / Animation primitives"). A deck SPECIAL prop invisible to * defaultProps-derived schemas, so it's a universal library attribute like * `label`/`color`. Prop names accept kebab or camel. Shared by the live * resolver and the validator — same grammar, two surfaces. */ export declare function parseTransitionAttr(raw: string): { transitions: Record; invalid: string[]; }; /** * The js/unsafe-on-columnar rule, stated once for both surfaces (the * isUnknownLayerAttr precedent): a full-JS accessor block is an opaque * `d => ...` — there is no row object to hand it on a columnar layer, and * materializing one per accessor call would silently forfeit the zero-copy * path. Restricted accessors are fine: the compiler rewrites them to column * access. The live resolver logs it and skips the block; the validator emits * it as a structured error — same rule, guaranteed in sync. */ export declare const FULL_JS_COLUMNAR_RULE: { applies: (isJs: boolean, shape: Shape) => boolean; message: string; fix: string; }; /** Coerce a raw attribute string to a primitive: bare/true/false, JSON array/object, number, or string. */ export declare function coerceValue(raw: string, hint?: PropDescriptor["type"], attrName?: string): unknown; export interface ResolvedAttributes { props: Record; meta: LayerMeta; /** deckProp -> fingerprint, to attach as the layer's `updateTriggers`. */ updateTriggers: Record; /** Every cache key this layer currently references — feeds the global mark-and-sweep. */ liveKeys: Set; /** The layer's active declarative filter, if `filter-field`/`filter-range` are present. */ filter?: LayerFilter; /** The layer's active categorical filter, if `filter-category`/`filter-category-fields` are present. */ categoryFilter?: LayerCategoryFilter; } export declare function resolveLayerAttributes(el: Element, schema: LayerSchema, shape: Shape): ResolvedAttributes;