Core engine API
Every function exported by @tensorgrid/core — the TypeScript port of the Polars GridDataEngine,
parity-verified against golden fixtures. These are the building blocks the adapters compose: tree
build, pivot, sorting, filtering, windowing, drill-through, editing, formatting, conditional-format
scales, the formula DSL, and CSV serialization. Use them directly for a fully custom surface.
| Name | Type | Description |
|---|---|---|
addSyntheticColumnsAggregation | (tree: TreeNode[], synthetic: Record<string, (node: TreeNode) => unknown>) => TreeNode[] | Attach computed synthetic columns to every node of a built tree. Each name->fn(node) is evaluated on every node (recursively) and stored as jsonSafe(fn(node)), in insertion order, children after the parent. An escape hatch for any display value (does not cross the wire). Mirrors add_synthetic_columns. |
aggregateCellsAggregation | (cells: CellDescriptor, funcs?: readonly AggFunc[]) => CellsResult | Aggregate a selected range's already-extracted (wire) values into per-field + overall stats ({ fields, overall }). funcs defaults to all five (sum/mean/min/max/count); count_all always present; an unknown func throws. Field-less values feed overall only. Byte-identical to GridDataEngine.aggregate_cells. |
aggregateLevelAggregation | (rows: Row[], dimension: string, aggs: Record<string, string>) => Row[] | Group rows by dimension and reduce each measure. Returns one record { [dimension]: key, ...measures } per distinct dimension value, ascending by dimension. |
buildAdjacencyTreeAggregation | (rows: AdjNode[], idField: string, parentField: string, opts?: BuildAdjacencyOptions) => unknown[] | Build a nested tree from a flat parent-pointer (adjacency-list) frame. opts: measures ({field:agg} or list, default 'sum'; rolls interior nodes bottom-up), labelField (copied onto each node as label), orphans ('root' default | 'drop' for rows with an absent parent id). |
calcAggregation | (expr: string) => (measures: Record<string, unknown>) => unknown | Compile a formula-DSL string into (measures) => value for a calculated measure / having predicate. A small SAFE expression interpreter (tokenizer + recursive-descent parser + evaluator) mirroring Python operator semantics exactly (safe / // %, Python floor-div/modulo sign, and/or returning an operand, chained comparisons, a if c else b, function table abs/min/max/round/sqrt/floor/ceil/log/log10/exp/pow + coalesce/clamp/sign). Anything outside the allow-list throws FormulaError. agg()/sql() are NOT ported (backend-only). |
CellAccAggregation | class CellAcc { add(v: unknown): void; result(funcs: readonly AggFunc[]): CellStats } | Streaming accumulator for one field's cell aggregates. Mirrors _CellAcc: a null value contributes nothing (not even to count_all); a non-null non-numeric value increments count_all only; a finite numeric value feeds sum/mean/min/max/count and count_all. result() builds stats for the requested funcs (unselected keys omitted; count_all always present). |
columnFooterAggregation | (input: FooterInput, aggs: Record<string, string>) => Record<string, WireValue> | Aggregate each { column: agg } over the whole frame into a JSON-safe { column: value } footer. agg is a built-in name (sum/mean/min/max/count/n_unique/median/first/last); other specs (std/var/product/mode/concat/quantile + expr/callable) are backend-evaluated and rejected here. A numeric-only agg on a non-numeric column is skipped. FooterInput = { columns: Record<string, WireValue[]>, numeric: string[] }. |
FormulaErrorAggregation | class FormulaError extends Error | Thrown by calc for invalid syntax, a disallowed construct/function, or (at call time) an unknown name — the same safety model as the Python calc. |
FRONTEND_AGGAggregation | Readonly<Record<string, string>> | Built-in agg-name -> client-side aggregation-fn name. Mirrors engine _FRONTEND_AGG. Runtime-registered aggregations (register_aggregation) are Polars-factory-based and out of wire scope; a host can extend this table. |
gridGrandTotalAggregation | (rows: Record<string, unknown>[], aggs: Record<string, string>, calculated?: Record<string, CalcFn>) => Record<string, WireValue> | Aggregate every measure over the WHOLE frame into a JSON-safe { measure: value } footer (for backend-tree mode, where client-side auto-compute over pre-aggregated leaves would give mean-of-means). Optional calculated runs on the base measures. Reuses reduceColumn. |
isNumericOnlyAggAggregation | (agg: string) => boolean | True if agg is a numeric-only aggregation (incl. quantile specs). For the footer skip. |
iterCellsAggregation | (cells: CellDescriptor) => Generator<[string | null, WireValue]> | Yield [field, value] pairs from a liberal cells descriptor. Mirrors _iter_cells: a { field: [values] } mapping, or a sequence of { value, field? } objects (the range_selection shape) or bare scalars (field-less). |
nodeDimKeyAggregation | (node: TreeNode) => string | null | The dimension-value key of a node (first non-numeric, non-meta key). Mirrors _node_dim_key. |
nodeMeasureKeysAggregation | (node: TreeNode) => string[] | Numeric measure keys of a node (not dimension / id / meta). Mirrors _node_measure_keys. |
NUMERIC_ONLY_AGGSAggregation | ReadonlySet<string> | Aggregations meaningful only over a numeric column (a footer skips them for text/bool). Mirrors the engine's _NUMERIC_ONLY_AGGS. |
parseQuantileAggregation | (spec: string) => number | null | The quantile q in [0,1] for a parametric spec ('quantile:0.9' / 'p90'), else null. Mirrors the engine's _parse_quantile. |
reduceColumnAggregation | (values: readonly unknown[], agg: string) => unknown | Reduce values by the built-in aggregation agg (case-insensitive). Full vocabulary: sum/mean/min/max/count/n_unique/median/first/last/product/std/var/quantile/mode/concat (+ quantile:0.9 / p90 specs). Returns a raw (not-yet-json-safe) value. Throws for an unknown agg, mirroring the engine's 'Unknown aggregation' ValueError. |
sortDimensionKeysAggregation | (keys: unknown[]) => unknown[] | Order distinct group keys to mirror Polars group_by(dimension).agg(...).sort(dimension): a null key sorts FIRST, then numeric keys ascending numerically / string keys lexicographically. |
SUPPORTED_REDUCERSAggregation | ReadonlySet<string> | Built-in aggregation NAMES this core reduces directly (quantile specs handled dynamically via parseQuantile). Covers the full _AGG_FACTORIES vocabulary. |
topNChildrenAggregation | (tree: TreeNode[], by: string, n: number, opts?: { descending?: boolean; others?: boolean; othersLabel?: string }) => TreeNode[] | Keep the top n children (by `by`) at every level; optionally roll the rest into a single 'Others' node that SUMS the numeric measures. Recurses into children first, then reorders/drops the current level. Mirrors top_n_children. |
treePayloadAggregation | (rows: Row[], groupBy: string[], aggs: Record<string,string>, opts?: TreePayloadOptions) => TreeNode[] | Build the nested aggregation tree. groupBy = ordered dimension columns; aggs maps a measure/column name to a built-in string aggregation (applied at every level). Options: calculated (post-aggregation measures name->fn(measures)), grandTotal (prepend a 'Total' row), lazy + expanded (Mode-B: realise only expanded nodes' children), having (formula-DSL prune). Returns JSON-safe root nodes. |
sparklineCell-viz | (values: unknown, opts?: SparklineOptions) => string | null | An inline sparkline SVG STRING for an array of numbers, or null when there are fewer than 2 finite numbers. Wraps sparklineData; host-supplied colors are escaped. For the HTML string renderer. |
sparklineDataCell-viz | (values: unknown, opts?: SparklineOptions) => SparklineData | null | The STRUCTURED sparkline geometry (points / fillPoints / rects, color, dims) for an array of numbers, or null when fewer than 2 finite numbers. Line by default; type:'bar' for a mini column chart. Color auto-picks up/down (green/red) unless color is set. React/Vue build the SVG via elements (XSS-safe). |
SparklineOptionsCell-viz | { type?: 'line'|'bar'; width?: number; height?: number; color?: string; colorUp?: string; colorDown?: string; fill?: boolean; lineWidth?: number; from?: 'cell'|'children' } | Options for sparkline / sparklineData. type default 'line'; width default 80; height default 22; color overrides up/down auto-color; colorUp/colorDown default green/red; fill (line only) default false; lineWidth default 1.5; from 'cell' (default, the cell's array value) or 'children' (gather this measure's values across the node's child rows — the OLAP trend). |
GROUP_COLUMN_KEYColumn | const GROUP_COLUMN_KEY = '__group__' | The columnWidths / data-resize-key key for the auto-group (dimension) column, which has no accessorKey. Adapters use this to persist + apply the group column's resize width. |
makeActionColumnColumn | (actions: ActionItem[], header?: string, colId?: string) => ActionColumnDef | Build an action-button column def (type sentinel 'action'). Mirrors make_action_column: actions is a list of { id, label?, ... }; clicking one sets the component's action_triggered prop. Append the result to the list from makeColumnDefs. |
makeColumnDefsColumn | (schema: GridSchema, args: MakeColumnDefsArgs) => ColumnDef[] | Build the leaf/group column definitions (TanStack-style). schema = wire-portable { columns, colTypes, dateDefaultCols?, distinct? } (the backend-extracted stand-in for self.df); args = { groupBy, agg, calculated?, formats?, headers?, pivot?, filters? }. Mirrors make_column_defs exactly, incl. the always-present (possibly-null) formatStr and the dim/measure/calculated/pivot ordering. |
pyTitleColumn | (s: string) => string | Faithful port of Python str.title(): the first cased char of each run titlecased, the rest lowercased; any non-cased char resets the run — so 'max_order' -> 'Max Order'. Used to derive default headers. |
reorderMeasureColsColumn | <T extends { accessorKey?: string }>(cols: readonly T[], order: readonly string[] | undefined) => T[] | Reorder measure column defs by order (a list of accessorKeys) — the shared primitive behind every adapter's column-reorder feature (drag / setColumnOrder / saved-view columnOrder). Listed keys come first in that order, then remaining defs in original order; unknown/duplicate keys ignored. PURE. |
ColorScaleSpecConditional-format | { min: string; max: string; mid?: string; domainMin?: number; domainMax?: number; domainMid?: number } | A two- or three-stop linear color scale over a measure column. min/max = CSS hex colors at the domain ends; mid = optional diverging midpoint color; domainMin/domainMax fix the domain ends; domainMid = the value at which mid sits (default the domain midpoint; ignored without mid). |
dataBarBackgroundConditional-format | (value: unknown, colMax: number, spec: DataBarSpec) => string | null | The CSS background (a linear-gradient bar) for one cell, or null when null/non-numeric. Domain [domainMin ?? 0, domainMax ?? colMax]; value clamped; a degenerate domain yields null. Without origin the bar is LEFT-ANCHORED; with origin it DIVERGES (above paints rightward in color, below leftward in negativeColor ?? color; a value AT origin yields null). |
DataBarSpecConditional-format | { color: string; domainMin?: number; domainMax?: number; origin?: number; negativeColor?: string } | An in-cell data bar over a measure column. color = fill (above-origin side for a diverging bar); domainMin (default 0) / domainMax (default column max) fix the domain; origin = the baseline value for a diverging bar; negativeColor = the below-origin fill (default color). |
evalCellStyleConditional-format | (value: unknown, rules: CellStyleRule[]) => CellStyleResult | null | First-match-wins: return the { style, className, icon } of the first rule whose op is satisfied by value, else null. Numeric-vs-text mode inferred from the OPERATOR (= / < numeric; equals / contains textual). A value-needing operator with no value matches every cell. Reuses the filter's evalCondition — one operator vocabulary. |
iconSetConditional-format | (value: unknown, lo: number, hi: number, spec: IconSetSpec) => { icon: string; color: string } | null | The { icon, color } for one cell's value on a 3-level icon set, or null when null/non-numeric. lo/hi are the column domain ends; the level is chosen by thresholds (explicit or the domain thirds); reverse flips the mapping (low = good). Mirrors the Dash component's iconSet conditionalFormat. |
IconSetSpecConditional-format | { set?: 'arrows'|'triangles'|'traffic'; thresholds?: [number, number]; colors?: [string,string,string]; icons?: [string,string,string]; reverse?: boolean } | A 3-level icon set over a measure column. set = named preset (default 'arrows', overridden by icons); thresholds = explicit level boundaries (default the domain thirds); colors = per-level (default red/amber/green); icons = per-level glyphs; reverse = flip level→icon/color so a LOW value is 'good'. |
numericRangeConditional-format | (values: unknown[]) => { min: number; max: number } | null | The numeric range of a column's values (nulls / non-numbers ignored), or null if none are numeric. Adapters use it to compute the domain for scaleColor / dataBarBackground / iconSet. |
scaleColorConditional-format | (value: unknown, lo: number, hi: number, spec: ColorScaleSpec) => string | null | The CSS background color for one cell on a color scale, or null when the value is null/non-numeric. lo/hi are the domain ends (from numericRange, or spec.domainMin/domainMax). The value is clamped to [lo,hi]; a degenerate domain maps to mid ?? min. With mid, the low half interpolates min→mid and the high half mid→max. Presentation only. |
inferSchemaData | (rows: Row[], input: SchemaInput, opts?: InferSchemaOptions) => InferredSchema | Classify rows into { dimensions, measures }. Dimensions = the kept non-numeric columns ordered by ascending cardinality (stable); measures = the explicit agg or every numeric column at defaultAgg (default 'sum'). Drives the adapters' autoGroup. input = { columns, numeric }; opts = { agg?, maxLevels?, defaultAgg? }. |
TreeNodeData | interface TreeNode { [key: string]: unknown; subRows?: TreeNode[] } | A tree node: arbitrary measure/dimension keys plus optional children. Engine-added markers include id, _level, _hasChildren, _isGrandTotal, _isOthers, _loading. The unit of every core tree transform. |
applyEditEditing | (rows: Row[], groupBy: string[], edit: CellEdit, opts?: { validationRules?: Record<string, ValidationRule[]> }) => Row[] | Apply one source-cell edit and return a NEW rows array (structural sharing: only the edited row object is replaced). Throws on a path longer than groupBy, a rowIndex past the node's matching rows, an unknown column, a stale oldValue, or (with opts.validationRules) a failed ValidationRule (EditRejected). The engine re-derives every aggregate; the frontend does ZERO math on edit. |
CellEditEditing | { path: unknown[]; rowIndex: number; column: string; oldValue: unknown; newValue: unknown } | One source-cell edit. path = group-key path of the drilled node (JSON.parse of its id; may be a parent prefix); rowIndex = zero-based index within the node's drill-through order; column = source column (dimension columns allowed — the row REGROUPS on rebuild); oldValue = the value the editor saw (wire form) — a mismatch means a stale edit and throws. |
EditRejectedEditing | class EditRejected extends Error { readonly code: string; readonly column: string; readonly rule: string | null } | A source-cell edit rejected by a ValidationRule (mirrors Python EditValidationError). Carries machine-branchable metadata (code, column, rule) for a structured wire rejection. |
validateEditEditing | (candidateRow: Record<string, unknown>, column: string, newValue: unknown, rules: ValidationRule[]) => void | Evaluate column's validation rules against a candidate edit; throw EditRejected on the FIRST failing rule, else return. candidateRow is the post-edit row env (value aliases the edited cell; other columns in scope for cross-field predicate rules). Mirrors GridDataEngine._validate_edit (default messages match the oracle verbatim). |
pivotToCsvExport | (pivot: PivotResult, rowDims: string[], opts?: PivotCsvOptions) => string | Serialize a pivotGrid result to CSV — the flat, complete cross-tab. One column per ROW dimension (full ancestor path) + one per pivoted MEASURE leaf, named by its flattened group-path ('2024 / Q1 / Revenue'; groupSeparator default ' / '). Every node at every level. Default RAW; { format: true } emits DISPLAYED values. |
toCsvExport | (rows: Row[], opts?: { columns?: string[]; floatColumns?: string[] }) => string | Serialize materialized rows to a CSV string matching Polars write_csv: a header row; comma-separated; RFC-4180 quoting; null -> empty field; true/false booleans; trailing \n after every row. opts.columns picks the column subset/order; opts.floatColumns names float columns (for .0 fidelity on whole values). Byte-identical to Polars on the fixtures. |
treeToCsvExport | (nodes: TreeNode[], groupBy: string[], measures: TreeCsvColumn[], opts?: CsvExportOptions) => string | Serialize an aggregated roll-up TREE to CSV — the 'what you see' export of the grid view. One column per groupBy dimension (each row carrying its full ancestor path; a parent/subtotal row leaves deeper cells empty) + one column per measures entry. Every node at every level (subtotals included), RFC-4180. Default RAW numerics; { format: true } emits DISPLAYED values (each measure's formatStr). |
andPredicatesFiltering | (...predicates: (NodePredicate | null | undefined)[]) => NodePredicate | AND-combine predicates (null/undefined entries skipped; empty input matches all). |
applyHavingFiltering | (tree: TreeNode[], having: string, measureKeys: string[]) => TreeNode[] | Prune tree nodes whose measures fail the `having` predicate (a formula-DSL string), keeping any node on the path to a surviving descendant. Mirrors _apply_having (string path only; the callable path is backend-only). measureKeys are the keys the predicate may reference. |
applyWindowFiltersFiltering | (rows: Row[], filters: Record<string, ColumnFilter>, columns: Set<string>) => Row[] | Per-column server-side filter model. Mirrors _apply_window_filters. Exported so facetCounts can reuse the exact same predicates for its faceted (other-column) frame. |
buildFilterDescriptorsFiltering | (columnDefs: ColumnDef[], rows: Row[], filters?: FilterState) => FilterDescriptor[] | Build one FilterDescriptor ({ column, filterType, header?, value?, facet?, options? }) per filterable leaf column: which control to render, its current value, the facet (value list / bounds, faceted over the OTHER columns via facetCounts), and any static filterOptions. The adapter renders framework-idiomatic controls FROM the descriptors. |
buildRootFilterControlFiltering | React: (ctx: RootFilterControlCtx) => ReactNode; Vue: (h, ctx) => VNode | Shared root-dimension filter control builder for the adapters (the grid's filter row and the virtual grid's filter bar). Renders one of the rootFilter variants (text / select / set / conditions / date), reading/writing the core FilterState through the passed-in ctx { col, rootFilter, filters, setFilter, clearFilter, rootValues }. Does ZERO math. |
columnFilterPredicateFiltering | (filters: Record<string, ColumnFilter>) => NodePredicate | A per-COLUMN filter predicate over the same { column: { type, value|min|max } } model the server row window uses. Semantics mirror the engine: text = case-insensitive substring; range = numeric min/max; select/equals = stringified equality; blank/absent value deactivates a spec; active specs AND together. On the client tree it sees AGGREGATED node values (matching-parent-keeps-subtree applies). |
conditionsMatchFiltering | (v: unknown, fv: Record<string, unknown>, numeric: boolean) => boolean | { op1, val1, join, op2, val2 } -> condition 1 AND / OR condition 2 (an empty op1 matches all). |
evalConditionFiltering | (v: unknown, op: string, target: unknown, numeric: boolean) => boolean | Evaluate ONE condition: blank / notBlank, numeric ops (= != > >= < <=, inclusive between over [lo,hi]), or case-insensitive text ops. A blank/unparseable value yields no constraint (matches every row). Byte-identical to the engine's _condition_expr; single-sourced for the server row window + the adapters' condition controls. |
FACET_TOPNFiltering | const FACET_TOPN = 200 | Default top-N cap on a `set` facet list — the high-cardinality guard (mirrors _FACET_TOPN). |
facetCountsFiltering | (rows: Row[], column: string, opts?: { filters?; kind?: 'set'|'range'; limit? }) => FacetCountsResult | Faceted values + counts ('set') or min/max bounds ('range') for column, over the frame matching every OTHER filter (never column's own). set values ordered count-desc then value-asc; NULL dropped; capped at opts.limit (default FACET_TOPN=200) with truncated flagging more distinct values. Feeds the select/set filter controls. |
filterControlTypeFiltering | (def: ColumnDef) => FilterType | The control to render for a column: its explicit filterType, else derived from the type. |
filterReducerFiltering | (state: FilterState, action: FilterAction) => FilterState | Pure reducer over the per-column filter state (set / clear / clearAll; new object on change, same ref on no-op). An adapter drives it from useReducer (React) or a reactive ref (Vue). |
filterTreeFiltering | (nodes: TreeNode[], predicate: NodePredicate) => TreeNode[] | Return a new tree keeping nodes that match predicate or have a surviving descendant, PRESERVING ancestor paths. A MATCHING node keeps its ENTIRE subtree. PURE (new arrays, parents shallow-copied). Grand-total rows get no special treatment. |
inferNumericFiltering | (rows: Row[], col: string) => boolean | Numeric-vs-text mode from the first non-null cell (mirrors the engine's dtype check). |
NUMERIC_OPERATORSFiltering | readonly NumericConditionOperator[] | Operator list for a numeric column (order = the control's dropdown order): = != > >= < <= between. |
operatorNeedsValueFiltering | (op: string) => boolean | True when op needs a value input (i.e. is not blank/notBlank/empty) — the control hides the value input otherwise. |
quickFilterPredicateFiltering | (query: string, keys: string[]) => NodePredicate | A quick-filter predicate: case-insensitive substring test of query over the given node keys (values stringified; null/undefined never match). An empty/blank query matches all. |
RootFilterKindFiltering | 'text' | 'select' | 'set' | 'conditions' | 'date' | The root-dimension control variant. select/set need rootValues; the rest do not. |
TEXT_OPERATORSFiltering | readonly TextConditionOperator[] | Operator list for a text column (contains / startsWith / endsWith / equals / … , blank / notBlank). |
useColumnFiltersFiltering | (initial?: FilterState) => UseColumnFilters | React (useReducer) / Vue (shallowRef) binding for the core filterReducer over the typed FilterState. Returns { filters, setFilter(column, value), clearFilter(column), clearAll() }. Pure state — no DOM. Backs a grid's per-column filter state. |
UseColumnFiltersFiltering | { filters: FilterState; setFilter(column, value: FilterValue): void; clearFilter(column): void; clearAll(): void } | Return shape of useColumnFilters: the current per-column filter state plus set/clear/clearAll actions. |
VALUELESS_OPERATORSFiltering | readonly ConditionOperator[] | Operators that take no value (blank / notBlank) — the control hides the value input. |
formatValueFormatting | (value: unknown, formatStr?: string | null, opts?: { locale?: string; currency?: string; nullText?: string }) => string | Format a raw value by either supported formatStr grammar: (1) the Dash component's kind[:arg][:flag…][;modifier…] grammar (number/currency/percentage/date; flags compact/accounting/sign; unit=; date token patterns like YYYY-MM-DD); (2) numeral-style strings ('0,0.00','$0,0.00','0.0%' plus (…) accounting, trailing 'a' abbreviation, leading '+' sign, bare 'date'). NaN/Inf/null/undefined render the null token (default '—'); an empty formatStr renders the raw value. |
filterPivotColumnDefsPivot | (columnDefs: ColumnDef[], keep: Set<string>, opts?: { totalHeader?: string; keepTotal?: boolean }) => ColumnDef[] | Prune a pivot's column_defs to only the selected top-level column groups — a client-side DISPLAY filter (hides column groups, does NOT re-aggregate). Row-dim leaf columns always kept; the grand-total group kept when keepTotal (default true); an EMPTY keep set means 'no column filter'. Feed the result to layoutPivotHeader. |
layoutPivotHeaderPivot | (columnDefs: ColumnDef[]) => PivotHeaderLayout | Lay out a pivot's column_defs into header rows + leaves (skipping the row-dim leaf defs — the auto-group column shows the row hierarchy). Returns { rows: HeaderCell[][], leaves: ColumnDef[], depth }. Framework adapters (the React pivot) consume this directly. |
PIVOT_TOTAL_HEADERPivot | const PIVOT_TOTAL_HEADER = 'Total' | Default header of the grand-total column group emitted by pivotGrid (grandTotal: true). |
pivotColumnGroupsPivot | (columnDefs: ColumnDef[], opts?: { totalHeader?: string }) => string[] | The top-level pivoted column-group headers (each a distinct outer column-dimension value, e.g. '2024','2025') — the choices for a column-group filter control. The grand-total group is EXCLUDED. Sourced from column_defs directly so the strings match exactly (the same strings filterPivotColumnDefs prunes on). |
pivotGridPivot | (rows: Row[], rowDims: string[], colDims: string[], aggs: Record<string,string>, opts?: PivotOptions) => PivotResult | Build a full cross-tab: rowDims on the row hierarchy, colDims pivoted into nested column groups, measure cells at every intersection. Returns { row_data, column_defs }. Opts: colSubtotals, grandTotal, rowGrandTotal, formats, headers, rowColTypes, calculated, context. Byte-identical to the Polars oracle. |
GridViewStateSaved-views | { expanded?; sortKeys?: SortKey[]; search?; hiddenColumns?: string[]; density?; columnWidths?; selected?: string[]; keptColumnGroups?: string[]; columnOrder?: string[] } | A JSON-serializable snapshot of a grid's VIEW state, shared by every adapter so getState()/applyState() round-trip the same shape across vanilla / React / Vue. Presentation state only (never DATA); every field optional so a partial preset touches only the axes it names. The setFilter predicate is intentionally NOT part of this snapshot. |
drillThroughSelection | (rows: Row[], groupBy: string[], pathValues: unknown[], opts?: { columns?: string[]; limit?: number }) => Row[] | Return the source rows that rolled up into a node identified by pathValues (the raw dimension values from root to the node; may be shorter than groupBy to drill a parent). Mirrors drill_through. |
isSyntheticNodeIdSelection | (id: unknown) => boolean | Whether a node id belongs to an engine SYNTHETIC node — the grand-total ('Total') row or a top-N 'Others' roll-up. Such ids resolve to ZERO source rows, so selection affordances should skip them. Matches the node's own key (last path element), so a nested Others node is detected too. |
matchesPathSelection | (row: Record<string, unknown>, groupBy: string[], path: unknown[]) => boolean | True when a row matches a group-key path prefix (zip(group_by, path), min length). |
rowsForSelectionSelection | (rows: Row[], groupBy: string[], selectedRows: { id?: string }[], opts?: DrillOptions) => Row[] | Return the deduplicated source rows underlying a component selection. Each entry's id is a JSON-encoded group-key path (makeNodeId); selecting a group also selects its descendants, so only TOP-MOST paths are kept, each filtered, and the union order-preservingly deduplicated. Mirrors rows_for_selection. |
selectionRangeSelection | (orderedIds: string[], anchorId: string, targetId: string) => string[] | The ids from anchorId to targetId INCLUSIVE, in orderedIds order, regardless of which endpoint comes first — the pure math behind a range / shift-click selection. Both endpoints located by first occurrence; if EITHER is absent the range is empty; anchor === target yields the single id. |
summarizeRowsSelection | (rows: Record<string, unknown>[], columns: string[]) => Record<string, ColumnSummary> | Per-column { count, sum, avg, min, max } over the FINITE numeric values in rows (non-numeric / null / NaN / Inf skipped; an all-non-numeric column reports count:0 with null stats). Backs the selection status bar; adapters compose summarizeRows(rowsForSelection(...), measures). |
coerceNumberSerialization | (v: unknown) => number | null | Coerce a wire value to a finite number for aggregation, else null. Mirrors _coerce_number: bool is EXCLUDED (a bool is not a measure); a finite number passes; everything else (strings, bigint, null, objects, non-finite) is rejected. |
jsonSafeSerialization | (value: unknown) => WireValue | Port of the Python engine's json_safe: turn a computed JS value (number, bigint, boolean, string, null, Date, arrays, plain objects) into its on-the-wire form so @tensorgrid/core output is byte-identical to the Python engine. A whole-valued number above 2^53 is stringified; -0.0 serializes as 0 (float64 provenance limitation). |
makeNodeIdSerialization | (pathValues: unknown[]) => string | Deterministic, injective node id from a path of key values. Matches Python _make_node_id = json.dumps([json_safe(v) for v], ensure_ascii=True) EXACTLY (comma-space separators, \uXXXX escaping). int 2025 vs str '2025' encode differently. CAVEAT: a float dimension value may render differently than Python — use int/string/date-string dimensions. |
MAX_SAFE_INTSerialization | const MAX_SAFE_INT: number | The 2^53 integer-safety boundary used by jsonSafe (mirrors the Python engine's _MAX_SAFE_INT). |
cacheFromTreeServer/Lazy | (nodes: TreeNode[], map: Map<string, TreeNode[]>) => Map<string, TreeNode[]> | Seed/accumulate a node cache from a tree's inline subRows: every node carrying loaded children is recorded (id -> children), recursing. The passed map is the accumulator (mutated and returned). Re-exported from @tensorgrid/react and @tensorgrid/vue. |
getRowsWindowServer/Lazy | (rows: Row[], start: number, end: number, opts?: RowsWindowOptions) => RowsWindowResult | Serve one [start, end) block for the infinite/server row model. rows is the full materialized frame; opts.filters / opts.sort applied to the whole frame first. Returns { rows (each json-safed with an absolute _index), row_count } (the filtered count). |
htmlEscapeServer/Lazy | const htmlEscape: (v: unknown) => string | HTML-escape a value for text/attribute contexts (shared by the reference renderers). Use it on interpolated host data inside a vanilla/HTML cellRenderers function. |
idDepthServer/Lazy | (id: string) => number | Depth of a node id — the length of its group-key path (id is the JSON-encoded path from makeNodeId). Returns 0 for a non-array/unparseable id. |
makeSkeletonServer/Lazy | (id: string, count: number) => TreeNode[] | Synthesize count client-only loading-skeleton children for node id: placeholder rows marked _loading (rendered by renderGridHtml as tg-row-skeleton rows) at the child level, with no measure values. Spliced under an expanding node DURING an in-flight fetch and replaced on resolve. Re-exported from @tensorgrid/react and @tensorgrid/vue. |
mergeChildrenServer/Lazy | (roots: TreeNode[], id: string, children: TreeNode[]) => TreeNode[] | Immutably splice children in as the subRows of the node whose id === id, cloning ONLY the ancestor spine down to that node (siblings/subtrees shared by reference), and return the new roots. When id is not found, or the target already has exactly this children reference, the SAME roots reference is returned (a cheap identity-checkable no-op). Backs the lazy Mode-B display tree. |
nodeChildrenStateServer/Lazy | (node: TreeNode, cache?: { has(id: string): boolean }) => 'leaf' | 'unloaded' | 'loaded' | Classify a node's child-load state so an adapter can decide fetch-vs-instant: 'leaf' (no children), 'loaded' (inline subRows or id in cache), 'unloaded' (children exist on the server but not sent — triggers a Mode-B round-trip + skeleton). |
renderGridHtmlServer/Lazy | (tree: TreeNode[], groupBy: string[], measures: ColumnDef[], opts?: RenderGridOptions) => string | Framework-neutral reference renderer: composes flattenTree + formatValue into a semantic HTML <table> string — an auto-group first column (dimension value indented by _level with a ▸/▾ expander) + one column per measure def (formatted via each def's formatStr). Opts cover expanded, groupHeader, selected, cellStyles, pinFirstColumn, noRowsMessage, resizable, columnWidths, footer/footerLabel, colorScales, dataBars, iconSets, sparklines, cellRenderers. No DOM/framework (SSR-friendly). |
renderPivotHtmlServer/Lazy | (pivot: PivotResult, rowDims: string[], opts?: RenderPivotOptions) => string | Framework-neutral reference renderer for the PIVOT / cross-tab: composes pivotGrid's { row_data, column_defs } into an HTML <table> string with a multi-row header (nested groups colspan their leaves; leaf measure cells rowspan to the bottom row). Opts: expanded, groupHeader, cellStyles/colorScales/dataBars/iconSets/cellRenderers (keyed by MEASURE NAME), noRowsMessage, pinFirstColumn, sort. |
RowNodeServer/Lazy | type RowNode = TreeNode | A tree node with the engine-added lazy markers (id, _level, _hasChildren, _loading, measures) — the same shape as core TreeNode; no distinct type. |
useLazyTreeServer/Lazy | (options: UseLazyTreeOptions) => UseLazyTreeResult | React/Vue hook implementing the lazy Mode-B node-cache: the FIRST expand of a node fetches its children (fetchChildren(id) => Promise<RowNode[]>), a re-expand of an already-fetched node is INSTANT with zero network, an in-flight fetch shows a loading skeleton, and invalidate() clears the cache. Transport- and DOM-neutral; reuses core mergeChildren; effect-free (fetching driven by toggle/expand). |
UseLazyTreeOptionsServer/Lazy | { initialRoots: RowNode[]; fetchChildren: (id: string) => Promise<RowNode[]>; skeletonCount?: number; expanded?: Record<string, boolean>; onExpandedChange?: (next) => void } | useLazyTree input: initialRoots (pristine level-0 nodes from an initial Mode-B payload), fetchChildren (transport/DOM-neutral fetch of ONE node's children by id), skeletonCount (placeholder rows during a first-expand fetch, default 4), and optional CONTROLLED expanded state + onExpandedChange. |
UseLazyTreeResultServer/Lazy | { expanded; tree: RowNode[]; childrenCache: ReadonlyMap<string,RowNode[]>; pendingIds: string[]; isPending(id): boolean; fetchCount: number; toggle(id): Promise<void>; expand(id): Promise<void>; collapse(id): void; invalidate(freshRoots): void } | useLazyTree result: the DISPLAY tree (roots + folded cached children + in-flight skeletons), the node cache, pending ids, a resolved-fetch counter (the honesty proof), and toggle/expand/collapse/invalidate operations. invalidate clears the cache, replaces the roots, and KEEPS the expanded state. |
SortKeySorting | interface SortKey { by: string; desc?: boolean } | One key of a multi-column sort (primary first, later keys break ties). desc default false = ascending. Consumed by sortTreeMulti and the adapters' click-to-sort headers. |
sortTreeSorting | (nodes: TreeNode[], by: string, opts?: { desc?: boolean }) => TreeNode[] | Return a new tree with the siblings at EVERY level ordered by `by`. Nulls sort LAST both directions; grand-total rows (_isGrandTotal) pinned first; leaves returned by reference, parents shallow-copied with sorted subRows. Pure — never mutates. |
sortTreeMultiSorting | (nodes: TreeNode[], sortKeys: SortKey[]) => TreeNode[] | Multi-column sort: order siblings at every level by the FIRST key, breaking ties with each subsequent key. Same null/type/grand-total semantics as sortTree. An empty sortKeys is a no-op. |
expandToDepthVirtualization | (tree: TreeNode[], depth: number) => Record<string, boolean> | Build the expanded-state ({ id: true }) revealing every node down to `depth` levels (each node at level < depth that has children marked expanded). depth<=0 collapses to roots ({}); a depth past the deepest fully expands. Backs 'expand all / collapse all / expand to level N'. |
flattenTreeVirtualization | (nodes: TreeNode[], expanded: ExpandedState) => TreeNode[] | Flatten the tree into the ordered list of VISIBLE rows: every node in order, followed by its subRows only when the node's id is expanded (recursively). Node objects returned by reference (each carries its _level for indentation). |
flattenTreeWindowVirtualization | (nodes: TreeNode[], expanded: ExpandedState, start: number, end: number) => TreeWindow | The ordered visible rows in the half-open window [start, end) plus the total visible count ({ rows, total }). One depth-first pass: O(visible) time, O(window) memory. Out-of-range windows yield rows: []; a negative/reversed range is clamped. Sizes a virtual scroller from total. |
isNodeExpandedVirtualization | (expanded: ExpandedState, id: unknown) => boolean | Whether a node id is expanded (a non-string id is never expandable). Shared by the flatteners, the virtualization window, and the reference renderers. |
visibleIndexOfVirtualization | (nodes: TreeNode[], expanded: ExpandedState, id: string) => number | The VISIBLE index of a node id under the given expanded-state, or -1 when the node is hidden inside a collapsed subtree or absent. Early-exits on the first match (supports scroll-to-node). |
visibleRowCountVirtualization | (nodes: TreeNode[], expanded: ExpandedState) => number | The number of visible rows for the given expanded-state (sizes a virtual scroller). |
movingAverageWindow | (tree: TreeNode[], measure: string, window: number, opts?: { into?: string }) => TreeNode[] | Add a trailing simple moving average of measure over the last `window` siblings (inclusive) at each level. Partial at the start (min_periods=1). A null/non-numeric current yields null (still occupies a slot); a grand-total node is skipped (no slot). into default '<measure>_ma<window>'. Mirrors moving_average. |
pctOfParentWindow | (tree: TreeNode[], measure: string, into?: string) => TreeNode[] | Add each node's share of its PARENT's measure (a [0,1] fraction) under key into (default '<measure>_pct_parent'). Top-level nodes divide by the top-level total. A null/non-numeric measure or zero parent yields null. |
pctOfTotalWindow | (tree: TreeNode[], measure: string, into?: string) => TreeNode[] | Add each node's share of the GRAND TOTAL of measure (a [0,1] fraction; format with %) under key into (default '<measure>_pct'). Denominator = the sum of the top-level nodes (grand-total node excluded, resolves to 1). A null/non-numeric measure or zero total yields null. |
rankChildrenWindow | (tree: TreeNode[], by: string, opts?: { descending?: boolean; into?: string; dense?: boolean }) => TreeNode[] | Add a 1-based rank of each node among its siblings by `by`. dense = ties share a rank, no gaps; else standard competition ranking. None-valued nodes get null; a grand-total node is excluded (null). Does NOT reorder. Mirrors rank_children. |
runningTotalWindow | (tree: TreeNode[], measure: string, into?: string) => TreeNode[] | Add a cumulative running total of measure across siblings at each level, under key into (default '<measure>_cumulative'). A grand-total node (_isGrandTotal) is skipped (null). Mirrors running_total. Mutates in place and returns the tree. |
siblingDeltaWindow | (tree: TreeNode[], measure: string, opts?: { into?: string; percent?: boolean }) => TreeNode[] | Add the change in measure from the PREVIOUS sibling at each level (period-over-period). The first sibling gets null; each later gets current-previous (absolute) or, with percent, (current-previous)/previous as a [0,1] fraction. A null/non-numeric current/previous (or zero previous for percent) yields null and breaks the chain. A grand-total node is skipped. into default '<measure>_delta' (or '_delta_pct'). Mirrors sibling_delta. |
WindowColumnSpecWindow | { kind: 'runningTotal'|'rank'|'pctOfTotal'|'pctOfParent'|'delta'|'movingAverage'; by: string; as: string; header?: string; format?: string; descending?: boolean; dense?: boolean; percent?: boolean; window?: number } | One derived window column. runningTotal = cumulative sum of `by` across siblings; rank = 1-based sibling rank (descending default true, dense optional); pctOfTotal = share of grand total; pctOfParent = share of parent (both percent kinds store a [0,1] fraction, format with %); delta = change from the previous sibling (absolute, or [0,1] fraction when percent); movingAverage = trailing SMA over the last `window` siblings (default 3). |