@opencorestack/opengridx 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/dist/ai.cjs +3 -3
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.es.js +3 -3
- package/dist/ai.es.js.map +1 -1
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +4982 -4853
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +15 -15
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/features/filtering.md +2 -0
- package/lib/components/DataGrid/DataGrid.css +0 -3
- package/lib/components/DataGrid/DataGrid.tsx +2 -4
- package/lib/components/DataGrid/GridListView.tsx +1 -1
- package/lib/components/DataGrid/GridPinnedRows.tsx +1 -1
- package/lib/components/DataGrid/GridVirtualRows.tsx +1 -1
- package/lib/components/ListView/ListView.css +4 -4
- package/lib/hooks/core/useDataGrid.ts +40 -35
- package/lib/hooks/core/useGridAggregationApi.ts +1 -1
- package/lib/hooks/core/useGridCellSelection.ts +3 -4
- package/lib/hooks/core/useGridClipboardPaste.ts +1 -1
- package/lib/hooks/core/useGridDetailPanel.ts +1 -1
- package/lib/hooks/core/useGridFillHandle.ts +1 -1
- package/lib/hooks/core/useGridHierarchy.ts +2 -2
- package/lib/hooks/core/useGridKeyboardNavigation.ts +1 -1
- package/lib/hooks/core/useGridLiveRowSelection.ts +9 -2
- package/lib/hooks/core/useGridRangeEditing.ts +1 -1
- package/lib/hooks/core/useGridRowInteractions.ts +3 -2
- package/lib/hooks/core/useLayout.ts +34 -24
- package/lib/hooks/features/useGridSpanning.ts +3 -3
- package/lib/hooks/useRowGrouping.ts +19 -10
- package/lib/hooks/useRowReorder.ts +9 -3
- package/lib/styles/base/reset.css +5 -3
- package/lib/types/state.ts +9 -0
- package/lib/utils/editing/targets.ts +2 -3
- package/lib/utils/export/exportShared.ts +22 -4
- package/lib/utils/export/index.ts +8 -4
- package/lib/utils/filtering/index.ts +8 -2
- package/lib/utils/gridApiRows.ts +1 -1
- package/lib/utils/grouping/groupedExportRows.ts +1 -1
- package/lib/utils/grouping/layeredMap.ts +52 -0
- package/lib/utils/parsing.ts +24 -1
- package/lib/utils/rowIndex.ts +67 -0
- package/lib/utils/values.ts +31 -0
- package/package.json +1 -1
package/dist/ai.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.es.js","sources":["../lib/utils/values.ts","../lib/utils/filtering/index.ts","../lib/ai/columns.ts","../lib/ai/schema.ts","../lib/utils/aiBrand.ts","../lib/utils/parsing.ts","../lib/ai/coerce.ts","../lib/ai/validate.ts","../lib/ai/promptHandler.ts","../lib/ai/agentTools.ts"],"sourcesContent":["import type { GridColDef, GridRowModel } from '../types';\n\nconst warnedCallbacks = new Set<string>();\n\n/**\n * Warn once per key (callback kind and column), in development only, that a consumer callback\n * threw and the grid fell back to a default instead of crashing.\n */\nexport function warnCallbackFailure(key: string, message: string, error: unknown): void {\n if (process.env.NODE_ENV === 'production' || warnedCallbacks.has(key)) return;\n warnedCallbacks.add(key);\n console.warn(`[OpenGridX] ${message}.`, error);\n}\n\n/**\n * Call a consumer callback; when it throws, warn once per `key` (dev only) and return `fallback`.\n * Used for callbacks whose failure has an obvious default (a detail-panel height, a group label).\n */\nexport function callSafely<T>(fn: () => T, fallback: T, key: string, message: string): T {\n try {\n return fn();\n } catch (error) {\n warnCallbackFailure(key, message, error);\n return fallback;\n }\n}\n\ntype ValueGetterColumn<R extends GridRowModel> = Pick<GridColDef<R>, 'valueGetter'>;\n\n/**\n * Read a cell through the column's `valueGetter` (or `row[field]`), returning a throw as `error`\n * instead of swallowing it. The row renderer uses this to show the error in that one cell.\n */\nexport function tryGetCellValue<R extends GridRowModel>(\n row: R,\n field: string,\n colDef?: ValueGetterColumn<R>\n): { value: unknown; error?: unknown } {\n const raw = row[field];\n if (!colDef?.valueGetter) return { value: raw };\n try {\n return { value: colDef.valueGetter({ row, field, value: raw }) };\n } catch (error) {\n return { value: undefined, error: error ?? new Error('valueGetter failed') };\n }\n}\n\n/**\n * The value a cell holds before formatting: the column's `valueGetter` result when it has one,\n * otherwise `row[field]`. Filtering, sorting, the quick filter, aggregation, row grouping, pivot,\n * list view, clipboard and editing all read cells through this, so a computed column behaves the\n * same everywhere. A `valueGetter` that throws reads as `undefined` (with a one-time dev warning\n * per column), so one bad record cannot take the whole grid down.\n */\nexport function getCellValue<R extends GridRowModel>(row: R, field: string, colDef?: ValueGetterColumn<R>): unknown {\n // Plain columns read the field directly: this runs once per row and column in every\n // whole-dataset pass (sort, filter, grouping, aggregation), so it must not allocate.\n if (!colDef?.valueGetter) return row[field];\n const { value, error } = tryGetCellValue(row, field, colDef);\n if (error !== undefined) {\n warnCallbackFailure(`valueGetter:${field}`, `valueGetter for column \"${field}\" threw; the value is read as undefined`, error);\n }\n return value;\n}\n\n/**\n * The column's `valueFormatter` text for `value`, or undefined when the column has no formatter\n * or the formatter throws (with a one-time dev warning per column).\n */\nexport function getFormattedValue<R extends GridRowModel>(\n row: R,\n field: string,\n value: unknown,\n colDef?: Pick<GridColDef<R>, 'valueFormatter'>\n): string | undefined {\n const formatter = colDef?.valueFormatter;\n if (!formatter) return undefined;\n // callSafely inlined: this runs for every cell of the quick filter's first search.\n try {\n return formatter({ value, row, field });\n } catch (error) {\n warnCallbackFailure(`valueFormatter:${field}`, `valueFormatter for column \"${field}\" threw; the value is shown unformatted`, error);\n return undefined;\n }\n}\n\n/**\n * Coerce a cell or filter value to a number. Returns null for null/undefined, blank strings,\n * NaN and anything that does not parse, so an empty cell is never read as 0.\n */\nexport function toNumber(value: unknown): number | null {\n if (value == null) return null;\n if (typeof value === 'number') return Number.isNaN(value) ? null : value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n const n = Number(trimmed);\n return Number.isNaN(n) ? null : n;\n }\n if (typeof value === 'boolean') return null;\n if (value instanceof Date) {\n const t = value.getTime();\n return Number.isNaN(t) ? null : t;\n }\n if (typeof value === 'bigint') return Number(value);\n return null;\n}\n\nconst DATE_ONLY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Parse a Date object, epoch milliseconds or a date string. A plain `YYYY-MM-DD` string is read\n * as a local calendar date: `new Date('2024-01-10')` is UTC midnight, which is the previous day\n * west of UTC. Returns null for empty, unparsable or invalid values.\n */\nexport function toDate(value: unknown): Date | null {\n if (value == null) return null;\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'number') {\n date = new Date(value);\n } else if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n const match = DATE_ONLY.exec(trimmed);\n if (match) {\n const year = Number(match[1]);\n const month = Number(match[2]) - 1;\n const day = Number(match[3]);\n date = new Date(year, month, day);\n // Reject roll-overs such as 2024-02-31.\n if (date.getMonth() !== month || date.getDate() !== day) return null;\n } else {\n date = new Date(trimmed);\n }\n } else {\n return null;\n }\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\n/** A sortable integer for the local calendar day of a date (YYYYMMDD), or null when unparsable. */\nexport function toLocalDayKey(value: unknown): number | null {\n const date = toDate(value);\n if (!date) return null;\n return date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate();\n}\n\n/** The local calendar day of a date as `YYYY-MM-DD`, or '' when unparsable. */\nexport function toLocalDateString(value: unknown): string {\n const date = toDate(value);\n if (!date) return '';\n const y = String(date.getFullYear()).padStart(4, '0');\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\nlet localDateFormat: Intl.DateTimeFormat | null = null;\n\n/**\n * `date.toLocaleDateString()` (the default locale's numeric date), with the formatter created\n * once: building a new one per call is several times slower on large grids.\n */\nexport function formatLocalDate(date: Date): string {\n localDateFormat ??= new Intl.DateTimeFormat();\n return localDateFormat.format(date);\n}\n\ntype ValueOption = string | number | { value: unknown; label: string };\n\n/** The label of the `valueOptions` entry for `value`, or undefined when no option matches. */\nexport function getValueOptionLabel(options: readonly ValueOption[] | undefined, value: unknown): string | undefined {\n if (!options) return undefined;\n const optionValue = (option: ValueOption): unknown => (typeof option === 'object' ? option.value : option);\n const optionLabel = (option: ValueOption): string => (typeof option === 'object' ? option.label : String(option));\n // Exact match first; then by text, so a numeric option still labels a value read back as a string.\n const match = options.find(option => Object.is(optionValue(option), value))\n ?? options.find(option => String(optionValue(option)) === String(value));\n return match === undefined ? undefined : optionLabel(match);\n}\n\n/**\n * Default display text for a cell whose column has no `valueFormatter`, by column `type`:\n * - `date`: the local calendar date (`toLocaleDateString()`) of a Date, timestamp or date string;\n * text that does not parse as a date is shown as is.\n * - `boolean`: `Yes` / `No` for `true` / `false`.\n * - `singleSelect`: the matching `valueOptions` label; a value with no option is shown as is.\n * - anything else (and `image`, whose cell renders an image of this URL): `String(value)`.\n * null and undefined are ''. The grid cells and the text exporters (CSV, print, PDF) use this, so\n * a file shows what the grid shows.\n */\nexport function formatValueByType(value: unknown, colDef: Pick<GridColDef, 'type' | 'valueOptions'> | undefined): string {\n if (value === null || value === undefined) return '';\n switch (colDef?.type) {\n case 'date': {\n const date = toDate(value);\n return date ? formatLocalDate(date) : String(value);\n }\n case 'boolean':\n if (value === true) return 'Yes';\n if (value === false) return 'No';\n return String(value);\n case 'singleSelect':\n return getValueOptionLabel(colDef.valueOptions, value) ?? String(value);\n default:\n return String(value);\n }\n}\n","\nimport type { GridRowModel, GridFilterItem, GridFilterModel, GridFilterGroup, GridFilterOperator, GridColDef } from '../../types';\nimport type { GridColumnLookup } from '../columnLookup';\nimport { getCellValue, getFormattedValue, toLocalDateString, toLocalDayKey, toNumber } from '../values';\n\n/** Compares a cell value with the filter item's value. */\nexport type GridFilterOperatorFn = (value: unknown, filterValue?: unknown) => boolean;\n\ntype RowPredicate = (row: GridRowModel) => boolean;\n\n/** Operators that take no value. Every other operator ignores an item whose value is empty. */\nexport const NO_VALUE_OPERATORS: ReadonlySet<string> = new Set<GridFilterOperator>(['isEmpty', 'isNotEmpty']);\n\n/**\n * True for a filter value that means \"nothing entered yet\": undefined, null, a blank string or an\n * empty array. Items with such a value (other than isEmpty / isNotEmpty) do not filter.\n */\nexport function isEmptyFilterValue(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n return false;\n}\n\nfunction isBlankCell(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'number') return Number.isNaN(value);\n return typeof value === 'string' && value.trim() === '';\n}\n\nconst numeric = (compare: (a: number, b: number) => boolean): GridFilterOperatorFn => (value, filterValue) => {\n const a = toNumber(value);\n const b = toNumber(filterValue);\n if (a === null || b === null) return false;\n return compare(a, b);\n};\n\nconst byDay = (compare: (a: number, b: number) => boolean): GridFilterOperatorFn => (value, filterValue) => {\n const a = toLocalDayKey(value);\n const b = toLocalDayKey(filterValue);\n if (a === null || b === null) return false;\n return compare(a, b);\n};\n\n/** Same local calendar day. Accepts Date objects, epoch milliseconds and date strings on both sides. */\nconst dateIs: GridFilterOperatorFn = byDay((a, b) => a === b);\n\n/** A different local calendar day. Empty or unparsable cells count as \"not that day\". */\nconst dateNot: GridFilterOperatorFn = (value, filterValue) => {\n const a = toLocalDayKey(value);\n const b = toLocalDayKey(filterValue);\n if (a === null || b === null) return true;\n return a !== b;\n};\n\nexport const FILTER_OPERATORS: Record<GridFilterOperator, GridFilterOperatorFn> = {\n contains: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().includes(String(filterValue).toLowerCase());\n },\n\n equals: (value, filterValue) => {\n if (value == null && filterValue == null) return true;\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase() === String(filterValue).toLowerCase();\n },\n\n startsWith: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().startsWith(String(filterValue).toLowerCase());\n },\n\n endsWith: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().endsWith(String(filterValue).toLowerCase());\n },\n\n isEmpty: (value) => {\n return value == null || String(value).trim() === '';\n },\n\n isNotEmpty: (value) => {\n return value != null && String(value).trim() !== '';\n },\n\n // Numeric operators: blank cells and non-numeric values never match (a blank cell is not 0).\n '=': numeric((a, b) => a === b),\n '>': numeric((a, b) => a > b),\n '>=': numeric((a, b) => a >= b),\n '<': numeric((a, b) => a < b),\n '<=': numeric((a, b) => a <= b),\n\n '!=': (value, filterValue) => {\n if (isEmptyFilterValue(filterValue)) return true;\n const a = toNumber(value);\n const b = toNumber(filterValue);\n if (a !== null && b !== null) return a !== b;\n // An empty cell is \"not equal\" to every value, whatever that value is.\n if (isBlankCell(value)) return true;\n return String(value).toLowerCase() !== String(filterValue).toLowerCase();\n },\n\n // A scalar value is treated as a one-element list, so a typed \"Active\" works like [\"Active\"].\n isAnyOf: (value, filterValue) => {\n if (value == null) return false;\n const options = Array.isArray(filterValue) ? filterValue : [filterValue];\n const cell = String(value).toLowerCase();\n return options.some(option => option != null && String(option).toLowerCase() === cell);\n },\n\n // Used by boolean and singleSelect (case-insensitive string comparison), and by dates.\n not: (value, filterValue) => {\n if (value instanceof Date) return dateNot(value, filterValue);\n if (value == null && filterValue == null) return false;\n if (value == null || filterValue == null) return true;\n return String(value).toLowerCase() !== String(filterValue).toLowerCase();\n },\n\n is: (value, filterValue) => {\n if (filterValue == null || filterValue === '') return true;\n if (value instanceof Date) return dateIs(value, filterValue);\n return String(value).toLowerCase() === String(filterValue).toLowerCase();\n },\n\n // Date operators compare local calendar days.\n after: byDay((a, b) => a > b),\n onOrAfter: byDay((a, b) => a >= b),\n before: byDay((a, b) => a < b),\n onOrBefore: byDay((a, b) => a <= b),\n};\n\n/** Date columns compare `is` / `not` by calendar day, so ISO strings and Date objects match the typed day. */\nconst DATE_COLUMN_OPERATORS: Partial<Record<GridFilterOperator, GridFilterOperatorFn>> = {\n is: dateIs,\n not: dateNot,\n};\n\nfunction resolveOperator(operator: string, colDef: GridColDef | undefined): GridFilterOperatorFn | undefined {\n if (!Object.prototype.hasOwnProperty.call(FILTER_OPERATORS, operator)) return undefined;\n const op = operator as GridFilterOperator;\n if (colDef?.type === 'date') {\n const dateFn = DATE_COLUMN_OPERATORS[op];\n if (dateFn) return dateFn;\n }\n return FILTER_OPERATORS[op];\n}\n\nfunction isFilterGroup(item: GridFilterItem | GridFilterGroup): item is GridFilterGroup {\n return 'items' in item && Array.isArray(item.items);\n}\n\ninterface CompileContext {\n columns?: GridColumnLookup;\n /** Unknown operators already reported in this pass, so the warning fires once per pass, not per row. */\n warned: Set<string>;\n}\n\nfunction compileItem(item: GridFilterItem, ctx: CompileContext): RowPredicate | null {\n const { field, operator, value } = item;\n // An item whose value has not been entered yet (or was cleared) does not filter.\n if (!NO_VALUE_OPERATORS.has(operator) && isEmptyFilterValue(value)) return null;\n\n const colDef = ctx.columns?.byField.get(field);\n const operatorFn = resolveOperator(operator, colDef);\n if (!operatorFn) {\n if (!ctx.warned.has(operator)) {\n ctx.warned.add(operator);\n console.warn(`Unknown filter operator: ${operator}`);\n }\n return null;\n }\n return (row) => operatorFn(getCellValue(row, field, colDef), value);\n}\n\nfunction compileGroup(\n items: (GridFilterItem | GridFilterGroup)[],\n logicOperator: 'and' | 'or',\n ctx: CompileContext\n): RowPredicate | null {\n const predicates: RowPredicate[] = [];\n for (const item of items) {\n const predicate = isFilterGroup(item)\n ? compileGroup(item.items, item.logicOperator, ctx)\n : compileItem(item, ctx);\n if (predicate) predicates.push(predicate);\n }\n if (predicates.length === 0) return null;\n if (predicates.length === 1) return predicates[0];\n return logicOperator === 'or'\n ? (row) => predicates.some(p => p(row))\n : (row) => predicates.every(p => p(row));\n}\n\nfunction pushSearchText(out: string[], value: unknown): void {\n if (value == null) return;\n switch (typeof value) {\n case 'string':\n out.push(value.toLowerCase());\n return;\n case 'number':\n if (!Number.isNaN(value)) out.push(String(value));\n return;\n case 'boolean':\n case 'bigint':\n out.push(String(value));\n return;\n default:\n break;\n }\n if (value instanceof Date) {\n // Search the calendar day, not Date.toString()'s \"Wed Jan 10 2024 ... GMT+0000\".\n const day = toLocalDateString(value);\n if (day) out.push(day);\n return;\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (entry == null || typeof entry !== 'object') pushSearchText(out, entry);\n }\n }\n // Other objects have no meaningful text (\"[object Object]\") and are skipped.\n}\n\nfunction getQuickFilterTexts(row: GridRowModel, columns: GridColumnLookup | undefined): string[] {\n const texts: string[] = [];\n if (!columns) {\n for (const value of Object.values(row)) pushSearchText(texts, value);\n return texts;\n }\n for (const col of columns.quickFilterColumns) {\n const value = getCellValue(row, col.field, col);\n const formatted = getFormattedValue(row, col.field, value, col);\n if (formatted != null && formatted !== '') texts.push(String(formatted).toLowerCase());\n pushSearchText(texts, value);\n }\n return texts;\n}\n\n// Search texts per column lookup and row object. The grid keeps one lookup while the columns and\n// hidden columns stay the same, so typing in the quick filter reads every cell once, not per keystroke.\nconst quickFilterTextCache = new WeakMap<GridColumnLookup, WeakMap<GridRowModel, string[]>>();\n\nfunction getCachedQuickFilterTexts(row: GridRowModel, columns: GridColumnLookup | undefined): string[] {\n if (!columns) return getQuickFilterTexts(row, columns);\n let byRow = quickFilterTextCache.get(columns);\n if (!byRow) {\n byRow = new WeakMap();\n quickFilterTextCache.set(columns, byRow);\n }\n let texts = byRow.get(row);\n if (!texts) {\n texts = getQuickFilterTexts(row, columns);\n byRow.set(row, texts);\n }\n return texts;\n}\n\nfunction quickFilterTerms(values: readonly string[] | undefined): string[] {\n return (values ?? [])\n .map(value => String(value ?? '').trim().toLowerCase())\n .filter(term => term !== '');\n}\n\nfunction textsMatchTerms(texts: readonly string[], terms: readonly string[]): boolean {\n // Plain loops: this runs once per row on every keystroke.\n for (let t = 0; t < terms.length; t++) {\n const term = terms[t];\n let found = false;\n for (let i = 0; i < texts.length; i++) {\n if (texts[i].includes(term)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n return true;\n}\n\nfunction compileQuickFilter(values: readonly string[] | undefined, columns: GridColumnLookup | undefined): RowPredicate | null {\n const terms = quickFilterTerms(values);\n if (terms.length === 0) return null;\n return (row) => textsMatchTerms(getCachedQuickFilterTexts(row, columns), terms);\n}\n\n// filterRows also keeps the texts of the last rows array it searched, by position, per column\n// lookup. Looking a text up by index is much cheaper than one WeakMap entry per row, and after an\n// edit (a new array with mostly the same row objects at the same positions) only the rows whose\n// object changed are read again.\ninterface QuickFilterArrayTexts {\n rows: readonly GridRowModel[];\n texts: string[][];\n}\nconst quickFilterArrayCache = new WeakMap<GridColumnLookup, QuickFilterArrayTexts>();\n\nfunction getQuickFilterTextsByIndex(rows: readonly GridRowModel[], columns: GridColumnLookup): string[][] {\n const previous = quickFilterArrayCache.get(columns);\n if (previous && previous.rows === rows) return previous.texts;\n const texts = new Array<string[]>(rows.length);\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n texts[i] = previous && i < previous.rows.length && previous.rows[i] === row\n ? previous.texts[i]\n : getQuickFilterTexts(row, columns);\n }\n quickFilterArrayCache.set(columns, { rows, texts });\n return texts;\n}\n\n/**\n * Compile a filter model into a row predicate. Returns null when the model filters nothing\n * (no items with a value and no quick-filter terms), so callers can skip the pass entirely.\n *\n * Pass `columns` so that cells are read through `valueGetter`, date columns use calendar-day\n * comparison and the quick filter searches only visible, filterable columns (including their\n * `valueFormatter` text). Without it, `row[field]` is read and the quick filter searches every\n * primitive value in the row.\n */\nexport function createRowFilter(\n filterModel: GridFilterModel | GridFilterGroup | null | undefined,\n columns?: GridColumnLookup\n): RowPredicate | null {\n if (!filterModel) return null;\n const ctx: CompileContext = { columns, warned: new Set() };\n const quickFilterValues = 'quickFilterValues' in filterModel ? filterModel.quickFilterValues : undefined;\n const quick = compileQuickFilter(quickFilterValues, columns);\n const itemsPredicate = compileGroup(filterModel.items ?? [], filterModel.logicOperator ?? 'and', ctx);\n if (quick && itemsPredicate) return (row) => quick(row) && itemsPredicate(row);\n return quick ?? itemsPredicate;\n}\n\n/**\n * Apply a single filter item to a row\n */\nexport function applyFilterItem<R extends GridRowModel>(\n row: R,\n filterItem: GridFilterItem,\n colDef?: GridColDef\n): boolean {\n const columns: GridColumnLookup | undefined = colDef\n ? { byField: new Map([[filterItem.field, colDef]]), quickFilterColumns: [] }\n : undefined;\n const predicate = compileItem(filterItem, { columns, warned: new Set() });\n return predicate ? predicate(row) : true;\n}\n\n/**\n * Apply the quick filter (global search). Every term must be found in at least one searched value.\n */\nexport function applyQuickFilter<R extends GridRowModel>(\n row: R,\n quickFilterValues: string[],\n columns?: GridColumnLookup\n): boolean {\n const predicate = compileQuickFilter(quickFilterValues, columns);\n return predicate ? predicate(row) : true;\n}\n\n/**\n * Check if a row matches the filter model. Compiles the model on every call: to test many rows,\n * build a predicate once with createRowFilter.\n */\nexport function isRowMatchingFilter<R extends GridRowModel>(\n row: R,\n filterModel: GridFilterModel | GridFilterGroup,\n columns?: GridColumnLookup\n): boolean {\n const predicate = createRowFilter(filterModel, columns);\n return predicate ? predicate(row) : true;\n}\n\nexport function filterRows<R extends GridRowModel>(\n rows: R[],\n filterModel: GridFilterModel,\n columns?: GridColumnLookup\n): R[] {\n const terms = columns && filterModel ? quickFilterTerms(filterModel.quickFilterValues) : [];\n if (columns && terms.length > 0) {\n // The same result as createRowFilter's predicate: the quick filter and then the items.\n const itemsPredicate = compileGroup(filterModel.items ?? [], filterModel.logicOperator ?? 'and', { columns, warned: new Set() });\n const texts = getQuickFilterTextsByIndex(rows, columns);\n const result: R[] = [];\n for (let i = 0; i < rows.length; i++) {\n if (textsMatchTerms(texts[i], terms) && (!itemsPredicate || itemsPredicate(rows[i]))) result.push(rows[i]);\n }\n return result;\n }\n const predicate = createRowFilter(filterModel, columns);\n if (!predicate) return rows;\n return rows.filter(row => predicate(row));\n}\n\nexport function getDefaultOperator(type?: string): GridFilterOperator {\n switch (type) {\n case 'number':\n return '=';\n case 'date':\n return 'is';\n case 'boolean':\n return 'is';\n case 'singleSelect':\n return 'isAnyOf';\n default:\n return 'contains';\n }\n}\n\nexport function getOperatorsForType(type?: string): GridFilterOperator[] {\n switch (type) {\n case 'number':\n return ['=', '!=', '>', '>=', '<', '<=', 'isEmpty', 'isNotEmpty'];\n case 'date':\n return ['is', 'not', 'after', 'onOrAfter', 'before', 'onOrBefore', 'isEmpty', 'isNotEmpty'];\n case 'boolean':\n return ['is'];\n case 'singleSelect':\n return ['isAnyOf', 'is', 'not'];\n default:\n return ['contains', 'equals', 'startsWith', 'endsWith', 'isEmpty', 'isNotEmpty'];\n }\n}\n\n/**\n * The text an input shows for a committed filter value: dates as `YYYY-MM-DD`, lists joined with\n * commas. Never used to emit anything (the filter panel and the header filter row).\n */\nexport function filterValueToInputText(value: unknown, colType?: string): string {\n if (value == null) return '';\n if (colType === 'date' || value instanceof Date) {\n const day = toLocalDateString(value);\n return day || (typeof value === 'string' ? value : '');\n }\n if (Array.isArray(value)) return value.map(v => String(v)).join(', ');\n return String(value);\n}\n","// Which columns may take part in each part of the state. The schema and the validator both read\n// these, so the model is never offered a field the validator would drop.\nimport { getOperatorsForType } from '../utils/filtering';\nimport type { GridFilterOperator, GridPivotAggFn } from '../types';\nimport type { GridAiColumn, GridAiPart, GridAiPartOptions } from './types';\n\n/** The built-in aggregation functions (`AGGREGATION_FUNCTIONS` in lib/utils/aggregation). */\nexport const AGGREGATION_FNS: readonly string[] = ['sum', 'avg', 'count', 'min', 'max', 'unique'];\n/** The functions a pivot value field takes (`GridPivotAggFn`). */\nexport const PIVOT_FNS: readonly GridPivotAggFn[] = ['sum', 'avg', 'count', 'min', 'max'];\n/** Operators without a value. */\nexport const NO_VALUE_OPS: readonly string[] = ['isEmpty', 'isNotEmpty'];\n/** Deepest nesting of filter groups. */\nexport const MAX_FILTER_DEPTH = 3;\n\nexport const ALL_PARTS: readonly GridAiPart[] = ['filter', 'sort', 'grouping', 'aggregation', 'pivot', 'columnVisibility'];\n\n/** State key of each part, in output order. */\nexport const PART_KEYS: Record<GridAiPart, string> = {\n filter: 'filterModel',\n sort: 'sortModel',\n grouping: 'rowGroupingModel',\n aggregation: 'aggregationModel',\n pivot: 'pivotModel',\n columnVisibility: 'columnVisibilityModel',\n};\n\nexport function hasOwn(obj: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function selectedParts(options: GridAiPartOptions | undefined): GridAiPart[] {\n const include = Array.isArray(options?.include) ? options.include : ALL_PARTS;\n const exclude = Array.isArray(options?.exclude) ? options.exclude : [];\n return ALL_PARTS.filter((part) => include.includes(part) && !exclude.includes(part));\n}\n\n/**\n * The usable columns, first one per field. System columns (`__check__`, `__group__`, …), spacers\n * and fields that are not plain strings are skipped.\n */\nexport function usableColumns(columns: readonly GridAiColumn[] | unknown): GridAiColumn[] {\n if (!Array.isArray(columns)) return [];\n const seen = new Set<string>();\n const out: GridAiColumn[] = [];\n for (const col of columns as unknown[]) {\n if (!isPlainObject(col)) continue;\n const field = col.field;\n if (typeof field !== 'string' || field === '' || field.startsWith('__') || col.isSpacer === true || seen.has(field)) continue;\n seen.add(field);\n out.push(col as unknown as GridAiColumn);\n }\n return out;\n}\n\nexport function operatorsOf(col: GridAiColumn): GridFilterOperator[] {\n return getOperatorsForType(col.type);\n}\n\nexport const isFilterable = (col: GridAiColumn): boolean => col.filterable !== false;\nexport const isSortable = (col: GridAiColumn): boolean => col.sortable !== false;\nexport const isGroupable = (col: GridAiColumn): boolean => col.groupable !== false;\nexport const isHideable = (col: GridAiColumn): boolean => col.hideable !== false;\n\n/**\n * Aggregation functions for a column, as the Summaries panel offers them: every built-in function\n * for number columns (or `aggregable: true`), `count` for the others, never with `aggregable: false`,\n * and limited by `availableAggregationFunctions`.\n */\nexport function aggregationFnsOf(col: GridAiColumn, fns: readonly string[] = AGGREGATION_FNS): string[] {\n if (col.aggregable === false) return [];\n const base = col.type === 'number' || col.aggregable === true ? fns : fns.filter((fn) => fn === 'count');\n const allowed = col.availableAggregationFunctions;\n return Array.isArray(allowed) ? base.filter((fn) => allowed.includes(fn)) : [...base];\n}\n\n/** JSON-safe option values of a singleSelect column, in order, without duplicates. */\nexport function optionValues(col: GridAiColumn): (string | number)[] {\n const out: (string | number)[] = [];\n if (!Array.isArray(col.valueOptions)) return out;\n for (const option of col.valueOptions) {\n const value: unknown = option !== null && typeof option === 'object' ? option.value : option;\n if ((typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value))) && !out.includes(value)) out.push(value);\n }\n return out;\n}\n","// getGridAiSchema: a JSON Schema (draft 2020-12) of the grid state a model may produce. Built from\n// the column definitions only; no row data is read. Same columns and options, same schema.\nimport {\n MAX_FILTER_DEPTH,\n NO_VALUE_OPS,\n PART_KEYS,\n PIVOT_FNS,\n aggregationFnsOf,\n isFilterable,\n isGroupable,\n isHideable,\n isSortable,\n operatorsOf,\n optionValues,\n selectedParts,\n usableColumns,\n} from './columns';\nimport type { GridAiColumn, GridAiJsonSchema, GridAiPart, GridAiSchema, GridAiSchemaOptions } from './types';\n\n/** Title of every schema. Also the marker `check-bundle` uses to keep this code out of the core bundle. */\nexport const GRID_AI_SCHEMA_TITLE = 'OpenGridX grid state';\n\nconst MAX_EXAMPLES = 10;\n\ninterface Ctx {\n descriptions: boolean;\n examples: boolean;\n}\n\nfunction label(col: GridAiColumn): string {\n const header = typeof col.headerName === 'string' && col.headerName !== '' ? col.headerName : col.field;\n const desc = typeof col.description === 'string' && col.description !== '' ? ` (${col.description})` : '';\n return `${header}${desc}`;\n}\n\nfunction describe(node: GridAiJsonSchema, text: string, ctx: Ctx): GridAiJsonSchema {\n return ctx.descriptions ? { ...node, description: text } : node;\n}\n\nfunction examplesOf(col: GridAiColumn, ctx: Ctx): unknown[] {\n if (!ctx.examples || !Array.isArray(col.aiExamples)) return [];\n return col.aiExamples\n .filter((v) => typeof v === 'string' || typeof v === 'boolean' || (typeof v === 'number' && Number.isFinite(v)))\n .slice(0, MAX_EXAMPLES);\n}\n\n/** Schema of one filter value for the column's type. */\nfunction valueSchema(col: GridAiColumn, ctx: Ctx): GridAiJsonSchema {\n let node: GridAiJsonSchema;\n switch (col.type) {\n case 'number':\n node = { type: 'number' };\n break;\n case 'date':\n node = { type: 'string', format: 'date' };\n break;\n case 'boolean':\n node = { type: 'boolean' };\n break;\n case 'singleSelect': {\n const values = optionValues(col);\n const one: GridAiJsonSchema = values.length > 0 ? { enum: values } : { type: 'string' };\n node = { anyOf: [one, { type: 'array', items: one }] };\n break;\n }\n default:\n node = { type: 'string' };\n }\n const examples = examplesOf(col, ctx);\n return examples.length > 0 ? { ...node, examples } : node;\n}\n\nfunction filterItemSchema(col: GridAiColumn, ctx: Ctx): GridAiJsonSchema {\n const operators = operatorsOf(col);\n const noValue = operators.filter((op) => NO_VALUE_OPS.includes(op));\n const hint = col.type === 'singleSelect' ? '; isAnyOf takes an array' : '';\n const ops = noValue.length > 0 ? `${noValue.join(' and ')} take no value${hint}` : hint.slice(2);\n return describe(\n {\n type: 'object',\n properties: {\n field: { const: col.field },\n operator: { enum: operators },\n value: valueSchema(col, ctx),\n },\n required: ['field', 'operator'],\n additionalProperties: false,\n },\n ops ? `${label(col)}: ${ops}` : label(col),\n ctx,\n );\n}\n\nfunction filterSchema(cols: GridAiColumn[], ctx: Ctx, defs: Record<string, GridAiJsonSchema>): GridAiJsonSchema | null {\n const filterable = cols.filter(isFilterable);\n const properties: Record<string, GridAiJsonSchema> = {};\n const logic = { enum: ['and', 'or'] };\n if (filterable.length > 0) {\n defs.filterItem = { oneOf: filterable.map((col) => filterItemSchema(col, ctx)) };\n // Groups are unrolled to MAX_FILTER_DEPTH levels: the deepest one holds items only.\n for (let depth = MAX_FILTER_DEPTH; depth >= 1; depth--) {\n const child = depth === MAX_FILTER_DEPTH ? { $ref: '#/$defs/filterItem' } : { anyOf: [{ $ref: '#/$defs/filterItem' }, { $ref: `#/$defs/filterGroup${depth + 1}` }] };\n defs[`filterGroup${depth}`] = {\n type: 'object',\n properties: { logicOperator: logic, items: { type: 'array', items: child } },\n required: ['logicOperator', 'items'],\n additionalProperties: false,\n };\n }\n properties.items = { type: 'array', items: { anyOf: [{ $ref: '#/$defs/filterItem' }, { $ref: '#/$defs/filterGroup1' }] } };\n properties.logicOperator = logic;\n }\n properties.quickFilterValues = describe({ type: 'array', items: { type: 'string' } }, 'Words a row must contain, in any column', ctx);\n return { type: 'object', properties, additionalProperties: false };\n}\n\nfunction fieldEnum(cols: GridAiColumn[]): GridAiJsonSchema {\n return { enum: cols.map((c) => c.field) };\n}\n\nfunction partSchema(part: GridAiPart, cols: GridAiColumn[], ctx: Ctx, defs: Record<string, GridAiJsonSchema>): GridAiJsonSchema | null {\n switch (part) {\n case 'filter':\n return filterSchema(cols, ctx, defs);\n case 'sort': {\n const sortable = cols.filter(isSortable);\n if (sortable.length === 0) return null;\n return describe(\n {\n type: 'array',\n items: {\n type: 'object',\n properties: { field: fieldEnum(sortable), sort: { enum: ['asc', 'desc'] } },\n required: ['field', 'sort'],\n additionalProperties: false,\n },\n },\n 'Most significant first',\n ctx,\n );\n }\n case 'grouping': {\n const groupable = cols.filter(isGroupable);\n if (groupable.length === 0) return null;\n return describe({ type: 'array', items: fieldEnum(groupable), uniqueItems: true }, 'Outermost first', ctx);\n }\n case 'aggregation': {\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const col of cols) {\n const fns = aggregationFnsOf(col);\n if (fns.length > 0) properties[col.field] = describe({ enum: fns }, label(col), ctx);\n }\n if (Object.keys(properties).length === 0) return null;\n return { type: 'object', properties, additionalProperties: false };\n }\n case 'pivot': {\n const dims = cols.filter(isGroupable);\n const values = cols\n .map((col) => ({ col, fns: aggregationFnsOf(col, PIVOT_FNS) }))\n .filter((v) => v.fns.length > 0)\n .map(({ col, fns }) => describe({\n type: 'object',\n properties: { field: { const: col.field }, aggFn: { enum: fns } },\n required: ['field', 'aggFn'],\n additionalProperties: false,\n }, label(col), ctx));\n if (dims.length === 0 || values.length === 0) return null;\n const dimArray = { type: 'array', items: fieldEnum(dims), uniqueItems: true };\n return {\n type: 'object',\n properties: { rowFields: dimArray, columnFields: dimArray, valueFields: { type: 'array', items: { oneOf: values } } },\n required: ['rowFields', 'columnFields', 'valueFields'],\n additionalProperties: false,\n };\n }\n case 'columnVisibility': {\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const col of cols.filter(isHideable)) properties[col.field] = describe({ type: 'boolean' }, label(col), ctx);\n if (Object.keys(properties).length === 0) return null;\n return describe({ type: 'object', properties, additionalProperties: false }, 'false hides a column', ctx);\n }\n }\n}\n\n/**\n * A JSON Schema (draft 2020-12) of the grid state a model may return for these columns: filter,\n * sort, grouping, aggregation, pivot and column visibility, each limited to the fields, operators\n * and functions the columns allow. Send it with the user's prompt to a model with structured\n * output, then pass the reply to `validateGridAiState`. Reads column definitions only, never rows.\n * @since v3.4\n */\nexport function getGridAiSchema<C extends GridAiColumn>(columns: readonly C[], options: GridAiSchemaOptions = {}): GridAiSchema {\n const ctx: Ctx = { descriptions: options.descriptions !== false, examples: options.examples !== false };\n const cols = usableColumns(columns);\n const defs: Record<string, GridAiJsonSchema> = {};\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const part of selectedParts(options)) {\n const node = partSchema(part, cols, ctx, defs);\n if (node) properties[PART_KEYS[part]] = node;\n }\n const schema: GridAiSchema = {\n $schema: 'https://json-schema.org/draft/2020-12/schema',\n schemaVersion: 1,\n title: GRID_AI_SCHEMA_TITLE,\n type: 'object',\n properties,\n additionalProperties: false,\n };\n if (ctx.descriptions) {\n schema.description = 'Grid state to apply. Include only the parts the user asked to change.';\n }\n if (Object.keys(defs).length > 0) schema.$defs = defs;\n return schema;\n}\n","// The \"validated\" brand of the AI toolkit. `validateGridAiState` (in the `/ai` entry point) puts it on\n// its result and on the result's `state`; the grid's `aiAssistant` applies a state only when it carries\n// it. Shared by both bundles, so it holds no AI code: just the registered symbol and two helpers.\n\n/** `Symbol.for('opengridx.ai.validated')`: the same symbol in every bundle and realm. */\nexport const GRID_AI_VALIDATED_BRAND: symbol = Symbol.for('opengridx.ai.validated');\n\n/** Brands `value` (non-enumerable, so it does not change equality, spreading or JSON) and returns it. */\nexport function brandGridAiValidated<T extends object>(value: T): T {\n Object.defineProperty(value, GRID_AI_VALIDATED_BRAND, { value: true, enumerable: false });\n return value;\n}\n\n/** Whether `value` carries the brand. */\nexport function isGridAiValidated(value: unknown): boolean {\n return typeof value === 'object' && value !== null && (value as Record<symbol, unknown>)[GRID_AI_VALIDATED_BRAND] === true;\n}\n","import type { GridColDef, GridValidRowModel } from '../types';\nimport { toDate } from './values';\n\n/**\n * Text → typed values: the TSV reader clipboard paste uses, and the per-column-type parsers paste,\n * `GridColDef.valueParser` defaults and the `/ai` validator share. Pure and React-free.\n *\n * Every pattern here is linear (CodeQL scans every push): no adjacent quantifiers that can match the\n * same characters.\n */\n\n/** A parsed value, or `{ ok: false }` when the text does not fit the column type. */\nexport type GridParsedValue = { ok: true; value: unknown } | { ok: false };\n\nconst INVALID: GridParsedValue = { ok: false };\nconst valid = (value: unknown): GridParsedValue => ({ ok: true, value });\n\n/**\n * Splits tab-separated text the way Excel, Google Sheets and LibreOffice write it: tabs between\n * columns, `\\r\\n`, `\\n` or `\\r` between rows. A field that starts with a double quote is quoted: it\n * may hold tabs, line breaks and doubled quotes (`\"\"` → `\"`), the reverse of `escapeTsvField`. A\n * quote inside an unquoted field is kept as is. A trailing empty line is ignored, so `\"a\\tb\\n\"` is one\n * row. Empty text gives no rows.\n */\nexport function parseTsv(text: string): string[][] {\n const rows: string[][] = [];\n if (text === '') return rows;\n let row: string[] = [];\n let field = '';\n let i = 0;\n const n = text.length;\n let fieldStart = true;\n while (i < n) {\n const ch = text[i];\n if (fieldStart && ch === '\"') {\n // A quoted field: read to the closing quote, `\"\"` being one quote.\n let j = i + 1;\n let value = '';\n let closed = false;\n while (j < n) {\n const q = text[j];\n if (q === '\"') {\n if (text[j + 1] === '\"') {\n value += '\"';\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n value += q;\n j += 1;\n }\n if (!closed) {\n // No closing quote: not a quoted field after all, read the quote as text.\n field += ch;\n i += 1;\n fieldStart = false;\n continue;\n }\n field += value;\n i = j;\n fieldStart = false;\n continue;\n }\n fieldStart = false;\n if (ch === '\\t') {\n row.push(field);\n field = '';\n fieldStart = true;\n i += 1;\n } else if (ch === '\\n' || ch === '\\r') {\n row.push(field);\n rows.push(row);\n row = [];\n field = '';\n fieldStart = true;\n i += ch === '\\r' && text[i + 1] === '\\n' ? 2 : 1;\n } else {\n field += ch;\n i += 1;\n }\n }\n // The last line, unless the text ended with a line break (Excel always adds one).\n if (!fieldStart || row.length > 0 || field !== '') {\n row.push(field);\n rows.push(row);\n }\n return rows;\n}\n\nconst PLAIN_NUMBER = /^\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?$/i;\nconst LEADING_DOT_NUMBER = /^\\.\\d+(?:e[+-]?\\d+)?$/i;\nconst GROUPED_NUMBER = /^\\d{1,3}(?:,\\d{3})+(?:\\.\\d*)?$/;\n// Currency symbols (Unicode Sc) and every kind of space, including the no-break spaces Excel uses\n// as a thousands separator.\nconst STRIPPED_CHARS = /[\\p{Sc}\\s]/gu;\n\n/**\n * A number as spreadsheets copy it: `1234.5`, `1,234.5` (comma thousands groups only), `-12`,\n * `(12)` (accounting negative), `12%` (→ 0.12), `1e3`, with currency symbols and spaces stripped.\n * Empty text is `null`. `1,5` is not accepted (it is ambiguous): use a `valueParser` for\n * decimal-comma locales.\n */\nexport function parseNumberText(text: string): GridParsedValue {\n let s = text.replace(STRIPPED_CHARS, '');\n if (s === '') return text.trim() === '' ? valid(null) : INVALID;\n let negative = false;\n if (s.startsWith('(') && s.endsWith(')')) {\n negative = true;\n s = s.slice(1, -1);\n }\n if (s.startsWith('-') || s.startsWith('+') || s.startsWith('−')) {\n if (s[0] !== '+') negative = !negative;\n s = s.slice(1);\n }\n let percent = false;\n if (s.endsWith('%')) {\n percent = true;\n s = s.slice(0, -1);\n }\n if (GROUPED_NUMBER.test(s)) s = s.split(',').join('');\n else if (!PLAIN_NUMBER.test(s) && !LEADING_DOT_NUMBER.test(s)) return INVALID;\n let value = Number(s);\n if (!Number.isFinite(value)) return INVALID;\n if (percent) value /= 100;\n if (negative) value = -value;\n return valid(value);\n}\n\nconst ISO_DATE_PREFIX = /^(\\d{4}-\\d{2}-\\d{2})/;\nconst pad2 = (n: number) => String(n).padStart(2, '0');\nconst localDay = (date: Date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;\n\n/**\n * A date: ISO `2026-10-07` (read as that local calendar day) or anything `Date.parse` accepts. Empty\n * text is `null`. The result takes the kind of `current` (the value the cell holds now), as the date\n * editor does: a timestamp stays a timestamp, a date string stays a `YYYY-MM-DD` string (an ISO\n * date-time string keeps its time part); otherwise it is a `Date`.\n */\nexport function parseDateText(text: string, current?: unknown): GridParsedValue {\n const trimmed = text.trim();\n if (trimmed === '') return valid(null);\n const date = toDate(trimmed);\n if (!date) return INVALID;\n if (typeof current === 'number') return valid(date.getTime());\n if (typeof current === 'string') {\n const day = localDay(date);\n return valid(ISO_DATE_PREFIX.test(current) && current.length > 10 ? day + current.slice(10) : day);\n }\n return valid(date);\n}\n\n/** Text read as `true` / `false`, besides the grid's own `Yes` / `No` cell labels. Lower case. */\nconst TRUE_WORDS = new Set(['true', 'yes', '1']);\nconst FALSE_WORDS = new Set(['false', 'no', '0']);\n\nexport interface GridBooleanLabels {\n /** Text shown for `true` (the grid shows `Yes`). */\n trueLabel?: string;\n /** Text shown for `false` (the grid shows `No`). */\n falseLabel?: string;\n}\n\n/**\n * A boolean: `true`/`false`, `yes`/`no` (the grid's own `Yes` / `No` cell labels), `1`/`0` and any\n * `labels` given, case-insensitive. Empty text is `null`.\n */\nexport function parseBooleanText(text: string, labels?: GridBooleanLabels): GridParsedValue {\n const s = text.trim().toLowerCase();\n if (s === '') return valid(null);\n if (labels?.trueLabel !== undefined && s === labels.trueLabel.trim().toLowerCase()) return valid(true);\n if (labels?.falseLabel !== undefined && s === labels.falseLabel.trim().toLowerCase()) return valid(false);\n if (TRUE_WORDS.has(s)) return valid(true);\n if (FALSE_WORDS.has(s)) return valid(false);\n return INVALID;\n}\n\ntype ValueOption = NonNullable<GridColDef['valueOptions']>[number];\n\n/**\n * A `singleSelect` value: the option whose value or label matches the text, case-insensitive (values\n * first). Returns the option's own value, so a numeric option stays a number. Empty text is `null`.\n */\nexport function parseSingleSelectText(text: string, options: readonly ValueOption[] | undefined): GridParsedValue {\n const s = text.trim();\n if (s === '') return valid(null);\n if (!options || options.length === 0) return INVALID;\n const lower = s.toLowerCase();\n for (const option of options) {\n const value = typeof option === 'object' ? option.value : option;\n if (String(value).toLowerCase() === lower) return valid(value);\n }\n for (const option of options) {\n if (typeof option === 'object' && option.label.toLowerCase() === lower) return valid(option.value);\n }\n return INVALID;\n}\n\ntype ParserColumn = Pick<GridColDef, 'type' | 'valueOptions'>;\n\nexport interface GridParseTextOptions {\n /** The value the cell holds now: a parsed date takes its kind (see `parseDateText`). */\n current?: unknown;\n /** Extra boolean labels, besides `Yes` / `No`. */\n booleanLabels?: GridBooleanLabels;\n}\n\n/**\n * Parses cell text by the column `type`, without `valueParser`:\n *\n * | type | accepted |\n * | :--- | :--- |\n * | `string` (default), `image` | the text as is (an empty cell is `''`) |\n * | `number` | `parseNumberText` |\n * | `date` | `parseDateText` |\n * | `boolean` | `parseBooleanText` |\n * | `singleSelect` | `parseSingleSelectText` |\n *\n * An empty cell is `null` for every type but `string` / `image`.\n */\nexport function parseValueByType(text: string, colDef: ParserColumn | undefined, options?: GridParseTextOptions): GridParsedValue {\n switch (colDef?.type) {\n case 'number': return parseNumberText(text);\n case 'date': return parseDateText(text, options?.current);\n case 'boolean': return parseBooleanText(text, options?.booleanLabels);\n case 'singleSelect': return parseSingleSelectText(text, colDef.valueOptions);\n default: return valid(text);\n }\n}\n\n/**\n * Parses the text pasted into one cell: the column's `valueParser` when it has one (a throw, or a\n * returned `undefined`, rejects the text), otherwise `parseValueByType`.\n */\nexport function parseCellText<R extends GridValidRowModel>(\n text: string,\n colDef: GridColDef<R>,\n row: R,\n options?: GridParseTextOptions,\n): GridParsedValue {\n const { valueParser } = colDef;\n if (!valueParser) return parseValueByType(text, colDef as unknown as ParserColumn, options);\n let value: unknown;\n try {\n value = valueParser(text, { row, field: colDef.field, colDef });\n } catch {\n return INVALID;\n }\n return value === undefined ? INVALID : valid(value);\n}\n","// Value coercion for the AI validator. Text goes through the same parsers as clipboard paste\n// (`lib/utils/parsing.ts`), so a value the grid accepts from Excel is accepted from a model and the\n// other way round. Model output is JSON, so typed values (a number, a boolean, a Date) are taken as\n// they are. Empty input is valid: null, or '' for text columns.\nimport {\n parseBooleanText,\n parseDateText,\n parseNumberText,\n parseSingleSelectText,\n type GridParsedValue,\n} from '../utils/parsing';\n\nexport type CoerceResult<T = unknown> = { ok: true; value: T } | { ok: false; reason: 'invalidValue' };\n\n/** The column properties coercion reads. */\nexport interface CoerceColumn {\n type?: string;\n valueOptions?: readonly (string | number | { value: unknown; label: string })[];\n}\n\nconst ok = <T>(value: T): CoerceResult<T> => ({ ok: true, value });\nconst INVALID: CoerceResult<never> = { ok: false, reason: 'invalidValue' };\n\nconst fromParsed = <T>(parsed: GridParsedValue): CoerceResult<T> =>\n parsed.ok ? ok(parsed.value as T) : INVALID;\n\nfunction isBlank(text: unknown): boolean {\n return text == null || (typeof text === 'string' && text.trim() === '');\n}\n\n/** `string` and `image` columns: text as is. Numbers and booleans become their text. */\nexport function coerceString(text: unknown): CoerceResult<string> {\n if (text == null) return ok('');\n if (typeof text === 'string') return ok(text);\n if (typeof text === 'number' || typeof text === 'boolean') return ok(String(text));\n return INVALID;\n}\n\n/** `number` columns: a finite number, or text in the paste format (`1,234.5`, `12%`, `$40`). */\nexport function coerceNumber(text: unknown): CoerceResult<number | null> {\n if (isBlank(text)) return ok(null);\n if (typeof text === 'number') return Number.isFinite(text) ? ok(text) : INVALID;\n if (typeof text !== 'string') return INVALID;\n return fromParsed(parseNumberText(text));\n}\n\n/** `date` columns: a Date, epoch milliseconds, or text in the paste format (ISO `2026-10-07` …). */\nexport function coerceDate(text: unknown): CoerceResult<Date | null> {\n if (isBlank(text)) return ok(null);\n if (text instanceof Date) return Number.isNaN(text.getTime()) ? INVALID : ok(text);\n if (typeof text === 'number') return Number.isFinite(text) ? ok(new Date(text)) : INVALID;\n if (typeof text !== 'string') return INVALID;\n return fromParsed(parseDateText(text));\n}\n\n/** `boolean` columns: a boolean, or `true`/`false`, `yes`/`no`, `1`/`0` (case-insensitive). */\nexport function coerceBoolean(text: unknown): CoerceResult<boolean | null> {\n if (isBlank(text)) return ok(null);\n if (typeof text === 'boolean') return ok(text);\n if (typeof text !== 'string' && typeof text !== 'number') return INVALID;\n return fromParsed(parseBooleanText(String(text)));\n}\n\n/**\n * `singleSelect` columns: an option value or label, case-insensitive; returns the option's value.\n * Without `valueOptions` the model has nothing to choose from, so any scalar is kept as it is.\n */\nexport function coerceSingleSelect(text: unknown, colDef: CoerceColumn): CoerceResult<unknown> {\n if (isBlank(text)) return ok(null);\n if (typeof text !== 'string' && typeof text !== 'number' && typeof text !== 'boolean') return INVALID;\n const options = colDef.valueOptions;\n if (!options || options.length === 0) return ok(text);\n return fromParsed(parseSingleSelectText(String(text), options));\n}\n\n/** Coerces `text` for the column's `type`. */\nexport function coerceValue(text: unknown, colDef: CoerceColumn): CoerceResult<unknown> {\n switch (colDef.type) {\n case 'number':\n return coerceNumber(text);\n case 'date':\n return coerceDate(text);\n case 'boolean':\n return coerceBoolean(text);\n case 'singleSelect':\n return coerceSingleSelect(text, colDef);\n default:\n return coerceString(text);\n }\n}\n","// validateGridAiState: the safety layer between a model's reply and the grid. Anything the columns\n// do not allow is dropped with an error; values are coerced to the column type. Never throws.\n// Only own keys of the input are read (never `__proto__`), and every key written to the output is a\n// column field, so nothing in the reply can reach Object.prototype or the output's prototype.\nimport type {\n GridAggregationModel,\n GridColumnVisibilityModel,\n GridFilterGroup,\n GridFilterItem,\n GridFilterModel,\n GridFilterOperator,\n GridPivotModel,\n GridPivotValueField,\n GridSortItem,\n} from '../types';\nimport { toLocalDateString } from '../utils/values';\nimport { brandGridAiValidated } from '../utils/aiBrand';\nimport { coerceBoolean, coerceValue } from './coerce';\nimport {\n ALL_PARTS,\n MAX_FILTER_DEPTH,\n NO_VALUE_OPS,\n PART_KEYS,\n PIVOT_FNS,\n aggregationFnsOf,\n hasOwn,\n isFilterable,\n isGroupable,\n isHideable,\n isPlainObject,\n isSortable,\n operatorsOf,\n selectedParts,\n usableColumns,\n} from './columns';\nimport type { GridAiColumn, GridAiPart, GridAiState, GridAiValidateOptions, GridAiValidationError, GridAiValidationResult } from './types';\n\n/** Longest list read from the model output; the rest is dropped with one error. */\nconst MAX_LIST = 200;\n/** Errors past this many are not listed, so a reply full of junk still gives a readable list. */\nconst MAX_ERRORS = 100;\n\ntype Allowed = (col: GridAiColumn) => boolean;\ntype FilterNode = GridFilterItem | GridFilterGroup;\n\ninterface Ctx {\n errors: GridAiValidationError[];\n byField: Map<string, GridAiColumn>;\n}\n\nfunction fail(ctx: Ctx, path: string, message: string): null {\n if (ctx.errors.length < MAX_ERRORS) ctx.errors.push({ path, message });\n return null;\n}\n\n/** A short, safe rendering of a value for an error message. */\nfunction show(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.slice(0, 60));\n return value === null || typeof value !== 'object' ? String(value) : Array.isArray(value) ? 'a list' : 'an object';\n}\n\nfunction lower(value: unknown): string | null {\n return typeof value === 'string' ? value.trim().toLowerCase() : null;\n}\n\n/** Own enumerable keys of the input, without `__proto__`. */\nfunction keysOf(obj: Record<string, unknown>): string[] {\n return Object.keys(obj).filter((key) => key !== '__proto__');\n}\n\nfunction column(ctx: Ctx, value: unknown, path: string, allowed: Allowed, what: string): GridAiColumn | null {\n const col = typeof value === 'string' ? ctx.byField.get(value) : undefined;\n if (!col) return fail(ctx, path, `Unknown field ${show(value)}`);\n return allowed(col) ? col : fail(ctx, path, `Field ${show(value)} cannot be ${what}`);\n}\n\n/** The first MAX_LIST entries of an array; a single value is read as a one-entry list. */\nfunction list(ctx: Ctx, value: unknown, path: string): unknown[] {\n if (value == null) return [];\n const items = Array.isArray(value) ? value : [value];\n if (items.length > MAX_LIST) fail(ctx, path, `Only the first ${MAX_LIST} entries are read`);\n return items.slice(0, MAX_LIST);\n}\n\n/** The choice `value` names, case-insensitively, in the choice's own spelling. */\nfunction oneOf(ctx: Ctx, value: unknown, path: string, choices: readonly string[]): string | null {\n const v = lower(value);\n return choices.find((c) => c.toLowerCase() === v) ?? fail(ctx, path, `${show(value)} is not one of ${choices.join(', ')}`);\n}\n\n/** One filter value, coerced; dates become `YYYY-MM-DD` as the filter panel writes them. */\nfunction filterValue(ctx: Ctx, raw: unknown, col: GridAiColumn, path: string): { v: unknown } | null {\n const result = coerceValue(raw, col);\n if (!result.ok) return fail(ctx, path, `${show(raw)} is not a valid ${col.type ?? 'string'} value`);\n const v = result.value instanceof Date ? toLocalDateString(result.value) : result.value;\n return v == null || v === '' ? fail(ctx, path, 'Missing value') : { v };\n}\n\nfunction filterItem(ctx: Ctx, raw: Record<string, unknown>, path: string): GridFilterItem | null {\n const col = column(ctx, raw.field, `${path}.field`, isFilterable, 'filtered');\n if (!col) return null;\n const operator = oneOf(ctx, raw.operator, `${path}.operator`, operatorsOf(col));\n if (operator === null) return null;\n const item: GridFilterItem = { field: col.field, operator: operator as GridFilterOperator };\n if (NO_VALUE_OPS.includes(item.operator)) return item;\n const rawValue = hasOwn(raw, 'value') ? raw.value : undefined;\n if (item.operator === 'isAnyOf') {\n const values: unknown[] = [];\n list(ctx, rawValue, `${path}.value`).forEach((entry, i) => {\n const r = filterValue(ctx, entry, col, `${path}.value[${i}]`);\n if (r && !values.includes(r.v)) values.push(r.v);\n });\n if (values.length === 0) return fail(ctx, `${path}.value`, 'No valid values');\n item.value = values;\n return item;\n }\n if (Array.isArray(rawValue)) return fail(ctx, `${path}.value`, 'Expected one value, not a list');\n const r = filterValue(ctx, rawValue, col, `${path}.value`);\n if (!r) return null;\n item.value = r.v;\n return item;\n}\n\nfunction logic(ctx: Ctx, raw: unknown, path: string): 'and' | 'or' | null {\n return raw === undefined ? null : (oneOf(ctx, raw, path, ['and', 'or']) as 'and' | 'or' | null);\n}\n\nfunction filterItems(ctx: Ctx, raw: unknown, path: string, depth: number): FilterNode[] {\n const out: FilterNode[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const at = `${path}[${i}]`;\n if (!isPlainObject(entry)) {\n fail(ctx, at, `Expected a filter, got ${show(entry)}`);\n } else if (hasOwn(entry, 'items') || hasOwn(entry, 'logicOperator')) {\n if (depth >= MAX_FILTER_DEPTH) {\n fail(ctx, at, `Groups nest at most ${MAX_FILTER_DEPTH} levels`);\n return;\n }\n const items = filterItems(ctx, entry.items, `${at}.items`, depth + 1);\n if (items.length === 0) fail(ctx, at, 'Empty group removed');\n else out.push({ logicOperator: logic(ctx, entry.logicOperator, `${at}.logicOperator`) ?? 'and', items });\n } else {\n const item = filterItem(ctx, entry, at);\n if (item) out.push(item);\n }\n });\n return out;\n}\n\nfunction filterModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridFilterModel {\n const model: GridFilterModel = {};\n if (hasOwn(raw, 'items')) model.items = filterItems(ctx, raw.items, `${path}.items`, 0);\n const op = logic(ctx, raw.logicOperator, `${path}.logicOperator`);\n if (op) model.logicOperator = op;\n if (hasOwn(raw, 'quickFilterValues')) {\n model.quickFilterValues = [];\n list(ctx, raw.quickFilterValues, `${path}.quickFilterValues`).forEach((entry, i) => {\n const word = typeof entry === 'string' || typeof entry === 'number' ? String(entry).trim() : null;\n if (word === null) fail(ctx, `${path}.quickFilterValues[${i}]`, `Expected text, got ${show(entry)}`);\n else if (word !== '') model.quickFilterValues?.push(word);\n });\n }\n return model;\n}\n\nfunction sortModel(ctx: Ctx, raw: unknown, path: string): GridSortItem[] {\n const out: GridSortItem[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const at = `${path}[${i}]`;\n if (!isPlainObject(entry)) return fail(ctx, at, `Expected { field, sort }, got ${show(entry)}`);\n const col = column(ctx, entry.field, `${at}.field`, isSortable, 'sorted');\n const sort = col && oneOf(ctx, entry.sort, `${at}.sort`, ['asc', 'desc']);\n if (!col || !sort) return;\n if (out.some((s) => s.field === col.field)) fail(ctx, at, `${show(col.field)} is sorted twice`);\n else out.push({ field: col.field, sort: sort as 'asc' | 'desc' });\n });\n return out;\n}\n\nfunction fieldList(ctx: Ctx, raw: unknown, path: string, allowed: Allowed, what: string): string[] {\n const out: string[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const col = column(ctx, entry, `${path}[${i}]`, allowed, what);\n if (col && !out.includes(col.field)) out.push(col.field);\n });\n return out;\n}\n\nconst canAggregate: Allowed = (col) => aggregationFnsOf(col).length > 0;\nconst canPivot: Allowed = (col) => aggregationFnsOf(col, PIVOT_FNS).length > 0;\n\nfunction aggregationModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridAggregationModel {\n const model: GridAggregationModel = {};\n for (const key of keysOf(raw)) {\n // 'none' is how the grid spells \"no aggregation\": nothing to set.\n if (lower(raw[key]) === 'none') continue;\n const col = column(ctx, key, `${path}.${key}`, canAggregate, 'aggregated');\n const fn = col && oneOf(ctx, raw[key], `${path}.${key}`, aggregationFnsOf(col));\n if (col && fn) model[col.field] = fn;\n }\n return model;\n}\n\nfunction pivotModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridPivotModel {\n const valueFields: GridPivotValueField[] = [];\n list(ctx, raw.valueFields, `${path}.valueFields`).forEach((entry, i) => {\n const at = `${path}.valueFields[${i}]`;\n if (!isPlainObject(entry)) return fail(ctx, at, `Expected { field, aggFn }, got ${show(entry)}`);\n const col = column(ctx, entry.field, `${at}.field`, canPivot, 'a pivot value');\n const aggFn = col && (oneOf(ctx, entry.aggFn, `${at}.aggFn`, aggregationFnsOf(col, PIVOT_FNS)) as GridPivotValueField['aggFn'] | null);\n if (col && aggFn && !valueFields.some((v) => v.field === col.field && v.aggFn === aggFn)) valueFields.push({ field: col.field, aggFn });\n });\n return {\n rowFields: fieldList(ctx, raw.rowFields, `${path}.rowFields`, isGroupable, 'a pivot label'),\n columnFields: fieldList(ctx, raw.columnFields, `${path}.columnFields`, isGroupable, 'a pivot label'),\n valueFields,\n };\n}\n\nfunction visibilityModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridColumnVisibilityModel {\n const model: GridColumnVisibilityModel = {};\n for (const key of keysOf(raw)) {\n const col = column(ctx, key, `${path}.${key}`, isHideable, 'hidden');\n const visible = coerceBoolean(raw[key]);\n if (!col) continue;\n if (visible.ok && visible.value !== null) model[col.field] = visible.value;\n else fail(ctx, `${path}.${key}`, `Expected true or false, got ${show(raw[key])}`);\n }\n return model;\n}\n\nfunction readPart(ctx: Ctx, part: GridAiPart, raw: unknown, path: string, state: GridAiState): void {\n if (part === 'sort') state.sortModel = sortModel(ctx, raw, path);\n else if (part === 'grouping') state.rowGroupingModel = fieldList(ctx, raw, path, isGroupable, 'grouped');\n else if (!isPlainObject(raw)) fail(ctx, path, `Expected an object, got ${show(raw)}`);\n else if (part === 'filter') state.filterModel = filterModel(ctx, raw, path);\n else if (part === 'aggregation') state.aggregationModel = aggregationModel(ctx, raw, path);\n else if (part === 'pivot') state.pivotModel = pivotModel(ctx, raw, path);\n else state.columnVisibilityModel = visibilityModel(ctx, raw, path);\n}\n\n/**\n * Checks a model's reply against the columns and returns the state that is safe to apply.\n * `json` is an object or a JSON string (bad JSON gives one error and an empty state). A top-level\n * string `message` (the model's reply text) is skipped, not reported. Unknown parts, fields, operators and enum values are dropped, each with an error; values are coerced to\n * the column type (`\"1,200\"` → 1200, a date → `\"YYYY-MM-DD\"`); filter groups left empty are\n * removed. Never throws, and never returns a field the columns do not allow.\n *\n * The result and its `state` carry the brand `Symbol.for('opengridx.ai.validated')` (not enumerable):\n * the grid's `aiAssistant` applies only a branded state. Spreading the result keeps `state` branded.\n * @since v3.4\n */\nexport function validateGridAiState<C extends GridAiColumn>(\n json: unknown,\n columns: readonly C[],\n options: GridAiValidateOptions = {},\n): GridAiValidationResult {\n const result = validate(json, columns, options);\n brandGridAiValidated(result.state);\n return brandGridAiValidated(result);\n}\n\nfunction validate(json: unknown, columns: readonly GridAiColumn[], options: GridAiValidateOptions): GridAiValidationResult {\n const ctx: Ctx = { errors: [], byField: new Map() };\n const state: GridAiState = {};\n try {\n for (const col of usableColumns(columns)) ctx.byField.set(col.field, col);\n let input = json;\n if (typeof json === 'string') {\n try {\n input = JSON.parse(json) as unknown;\n } catch {\n fail(ctx, '', 'Not valid JSON');\n return { state, errors: ctx.errors };\n }\n }\n if (!isPlainObject(input)) {\n fail(ctx, '', `Expected an object, got ${show(input)}`);\n return { state, errors: ctx.errors };\n }\n const allowed = selectedParts(options);\n for (const key of keysOf(input)) {\n const part = ALL_PARTS.find((p) => PART_KEYS[p] === key);\n if (key === 'schemaVersion') {\n if (input[key] !== 1) fail(ctx, key, `Unsupported schemaVersion ${show(input[key])}`);\n } else if (key === 'message') {\n // The model's reply text next to the state (createGridAiPromptHandler shows it): not state.\n if (typeof input[key] !== 'string') fail(ctx, key, `Expected text, got ${show(input[key])}`);\n } else if (!part) fail(ctx, key, 'Unknown part');\n else if (!allowed.includes(part)) fail(ctx, key, 'Part not allowed');\n else readPart(ctx, part, input[key], key, state);\n }\n } catch {\n // Defensive only: a getter on a hand-built input object could throw.\n fail(ctx, '', 'Could not read the input');\n return { state: {}, errors: ctx.errors };\n }\n return { state, errors: ctx.errors };\n}\n","// createGridAiPromptHandler: the `aiAssistant.onPrompt` function for an app's own model. It builds the\n// schema once, calls the app's `callModel`, reads the reply (an object, JSON text, or text with a fenced\n// JSON block) and returns the validated, branded result. The grid never sees the raw reply.\nimport type { GridAiPromptContext, GridAiPromptResult } from '../types';\nimport { brandGridAiValidated } from '../utils/aiBrand';\nimport { hasOwn, isPlainObject } from './columns';\nimport { getGridAiSchema } from './schema';\nimport type { GridAiColumn, GridAiPartOptions, GridAiPromptHandlerOptions, GridAiValidationError } from './types';\nimport { validateGridAiState } from './validate';\n\nconst FENCE = '```';\n\n/** A DOMException named `AbortError`, as `fetch` rejects with. */\nexport function abortError(): Error {\n return typeof DOMException === 'function'\n ? new DOMException('The operation was aborted.', 'AbortError')\n : Object.assign(new Error('The operation was aborted.'), { name: 'AbortError' });\n}\n\n/**\n * Splits a text reply into the JSON it holds and the text around it: the whole text when it starts\n * with `{`, else the first fenced block (with no language or `json`). A plain loop, no regex.\n */\nexport function readModelText(text: string): { json: string | null; message: string } {\n const trimmed = text.trim();\n if (trimmed.startsWith('{')) return { json: trimmed, message: '' };\n const open = text.indexOf(FENCE);\n const lineEnd = open < 0 ? -1 : text.indexOf('\\n', open + FENCE.length);\n const close = lineEnd < 0 ? -1 : text.indexOf(FENCE, lineEnd + 1);\n const lang = close < 0 ? '' : text.slice(open + FENCE.length, lineEnd).trim().toLowerCase();\n if (close < 0 || (lang !== '' && lang !== 'json')) return { json: null, message: trimmed };\n return {\n json: text.slice(lineEnd + 1, close),\n message: `${text.slice(0, open)}${text.slice(close + FENCE.length)}`.trim(),\n };\n}\n\nfunction errorText(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n return typeof error === 'string' && error ? error : 'Unknown error';\n}\n\n/** A branded result with an empty state: nothing to apply, the errors explain why. */\nfunction emptyResult(errors: GridAiValidationError[], message?: string): GridAiPromptResult {\n const result: GridAiPromptResult = { state: brandGridAiValidated({}), errors };\n if (message) result.message = message;\n return brandGridAiValidated(result);\n}\n\n/** Validates a model reply into a branded result. Never throws. */\nexport function readModelReply(reply: unknown, columns: readonly GridAiColumn[], parts: GridAiPartOptions): GridAiPromptResult {\n let json: unknown = reply;\n let around = '';\n if (typeof reply === 'string') {\n const text = readModelText(reply);\n if (text.json === null) return emptyResult([], text.message || undefined);\n around = text.message;\n // Parsed here so a `message` key inside the JSON is read as for an object reply. Bad JSON is\n // passed on as text: validateGridAiState reports it.\n try {\n json = JSON.parse(text.json) as unknown;\n } catch {\n json = text.json;\n }\n }\n // A reply such as { filterModel, message: 'Showing paid orders' }: the validator skips the message.\n const inner = isPlainObject(json) && hasOwn(json, 'message') && typeof json.message === 'string' ? json.message.trim() : '';\n const message = [around, inner].filter(Boolean).join('\\n\\n');\n const result: GridAiPromptResult = validateGridAiState(json, columns, parts);\n if (message) result.message = message;\n return result;\n}\n\n/**\n * Builds `aiAssistant.onPrompt` for your own model. On each prompt it calls\n * `callModel({ prompt, schema, currentState, history }, { signal })`, reads the reply (a state object,\n * a JSON string, or a fenced JSON block inside text), validates it with `validateGridAiState` and\n * returns the branded result. A `callModel` throw or rejection becomes\n * `{ state: {}, errors: [{ path: '', message }] }`; an abort rejects with an `AbortError`.\n * @since v3.5\n */\nexport function createGridAiPromptHandler<C extends GridAiColumn>(\n options: GridAiPromptHandlerOptions<C>,\n): (prompt: string, context: GridAiPromptContext) => Promise<GridAiPromptResult> {\n const { columns, callModel, parts, schemaOptions = {} } = options;\n const partOptions: GridAiPartOptions = { include: parts ?? schemaOptions.include, exclude: schemaOptions.exclude };\n const schema = getGridAiSchema(columns, { ...schemaOptions, ...partOptions });\n\n return async (prompt, context) => {\n const signal = context?.signal ?? new AbortController().signal;\n if (signal.aborted) throw abortError();\n // Stop resolves the prompt at once, even when callModel ignores the signal.\n const aborted = new Promise<never>((_, reject) => {\n signal.addEventListener('abort', () => reject(abortError()), { once: true });\n });\n aborted.catch(() => undefined);\n let reply: unknown;\n try {\n const request = {\n prompt: String(prompt),\n schema,\n currentState: context?.currentState ?? {},\n history: Array.isArray(context?.history) ? context.history : [],\n };\n reply = await Promise.race([callModel(request, { signal }), aborted]);\n } catch (error) {\n if (signal.aborted) throw abortError();\n return emptyResult([{ path: '', message: `The model call failed: ${errorText(error)}` }]);\n }\n if (signal.aborted) throw abortError();\n return readModelReply(reply, columns, partOptions);\n };\n}\n","// createGridAgentTools: plain tool objects ({ name, description, inputSchema, execute }) that let an AI\n// agent read and change the grid through its apiRef. No SDK: they fit the Vercel AI SDK, CopilotKit,\n// OpenAI or Anthropic tool calling and WebMCP. Every input is validated; execute never throws.\nimport type { GridAiState, GridRowModel } from '../types';\nimport { getCellValue } from '../utils/values';\n\ntype CellColumn = Parameters<typeof getCellValue>[2];\nimport { hasOwn, isPlainObject, PART_KEYS, usableColumns } from './columns';\nimport { getGridAiSchema } from './schema';\nimport type {\n GridAgentApi,\n GridAgentTool,\n GridAgentToolResult,\n GridAgentToolsOptions,\n GridAiColumn,\n GridAiJsonSchema,\n GridAiPart,\n} from './types';\nimport { validateGridAiState } from './validate';\n\nconst DEFAULT_MAX_ROWS = 20;\nconst MAX_ROWS_LIMIT = 1000;\n\nconst SET_TOOLS: { name: string; part: GridAiPart; description: string }[] = [\n { name: 'set_filter', part: 'filter', description: 'Replace the filter model of the grid (filters and quick-filter words).' },\n { name: 'set_sort', part: 'sort', description: 'Replace the sort model of the grid, most significant field first. An empty list clears sorting.' },\n { name: 'set_grouping', part: 'grouping', description: 'Group the rows by these fields, outermost first. An empty list removes grouping.' },\n { name: 'set_aggregation', part: 'aggregation', description: 'Replace the summaries: field to aggregation function. An empty object removes them.' },\n { name: 'set_column_visibility', part: 'columnVisibility', description: 'Show (true) or hide (false) columns. Columns not listed keep their visibility.' },\n];\n\ntype ApiRef = { readonly current: GridAgentApi | null | undefined };\n\nfunction failure(message: string, path = ''): GridAgentToolResult {\n return { ok: false, errors: [{ path, message }] };\n}\n\n/** Runs a tool body; a throw becomes `{ ok: false }`. */\nasync function run(body: () => GridAgentToolResult): Promise<GridAgentToolResult> {\n try {\n return body();\n } catch (error) {\n return failure(error instanceof Error && error.message ? error.message : 'The tool failed');\n }\n}\n\nfunction apiOf(apiRef: ApiRef): GridAgentApi | null {\n const api = apiRef?.current;\n return api && typeof api.getGridAiState === 'function' ? api : null;\n}\n\n/** A JSON-safe cell value: primitives as they are, a Date as an ISO string, anything else null. */\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString();\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n return typeof value === 'string' || typeof value === 'boolean' ? value : null;\n}\n\nfunction setTool(apiRef: ApiRef, columns: readonly GridAiColumn[], name: string, part: GridAiPart, description: string): GridAgentTool | null {\n const key = PART_KEYS[part] as keyof GridAiState;\n const schema = getGridAiSchema(columns, { include: [part] });\n if (!hasOwn(schema.properties, key)) return null;\n const { $schema: _version, schemaVersion: _schemaVersion, title: _title, description: _description, ...inputSchema } = schema;\n return {\n name,\n description,\n inputSchema: { ...inputSchema, required: [key] },\n execute: (input) => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n if (!isPlainObject(input) || !hasOwn(input, key)) return failure(`Expected an object with \"${key}\"`, key);\n const { state, errors } = validateGridAiState({ [key]: input[key] }, columns, { include: [part] });\n // All or nothing: the agent gets the errors back and can correct its call.\n if (errors.length > 0) return { ok: false, errors };\n const applied: GridAiState = {};\n if (state.filterModel) api.setFilterModel(applied.filterModel = state.filterModel);\n if (state.sortModel) api.setSortModel(applied.sortModel = state.sortModel);\n if (state.rowGroupingModel) api.setRowGroupingModel(applied.rowGroupingModel = state.rowGroupingModel);\n if (state.aggregationModel) api.setAggregationModel(applied.aggregationModel = state.aggregationModel);\n if (state.columnVisibilityModel) {\n applied.columnVisibilityModel = { ...api.getGridAiState().columnVisibilityModel, ...state.columnVisibilityModel };\n api.setColumnVisibilityModel(applied.columnVisibilityModel);\n }\n return { ok: true, applied };\n }),\n };\n}\n\nconst NO_INPUT: GridAiJsonSchema = { type: 'object', properties: {}, additionalProperties: false };\n\n/**\n * Tools for an AI agent: `get_grid_state`, `set_filter`, `set_sort`, `set_grouping`, `set_aggregation`,\n * `set_column_visibility`, `clear_filters`, and `get_row_summary` only with `allowRowAccess: true` (the\n * one tool that sends row values). Each tool is `{ name, description, inputSchema, execute }`; inputs are\n * checked with `validateGridAiState` and applied through `apiRef` only when valid. `execute` never throws.\n * @since v3.5\n */\nexport function createGridAgentTools<C extends GridAiColumn>(\n apiRef: ApiRef,\n columns: readonly C[],\n options: GridAgentToolsOptions = {},\n): GridAgentTool[] {\n const cols = usableColumns(columns);\n const tools: GridAgentTool[] = [{\n name: 'get_grid_state',\n description: 'Read the current filter, sort, grouping, aggregation, pivot and column visibility of the grid, and its columns.',\n inputSchema: NO_INPUT,\n execute: () => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n return {\n ok: true,\n state: api.getGridAiState(),\n columns: cols.map((c) => ({ field: c.field, headerName: typeof c.headerName === 'string' ? c.headerName : c.field, type: typeof c.type === 'string' ? c.type : 'string' })),\n };\n }),\n }];\n for (const { name, part, description } of SET_TOOLS) {\n const tool = setTool(apiRef, cols, name, part, description);\n if (tool) tools.push(tool);\n }\n tools.push({\n name: 'clear_filters',\n description: 'Remove every filter and the quick-filter words.',\n inputSchema: NO_INPUT,\n execute: () => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n const filterModel = { items: [] };\n api.setFilterModel(filterModel);\n return { ok: true, applied: { filterModel } };\n }),\n });\n if (options.allowRowAccess === true) {\n const maxRows = typeof options.maxRows === 'number' && options.maxRows >= 1 ? Math.min(Math.floor(options.maxRows), MAX_ROWS_LIMIT) : DEFAULT_MAX_ROWS;\n const allowed = Array.isArray(options.fields) ? cols.filter((c) => options.fields?.includes(c.field)) : cols;\n tools.push({\n name: 'get_row_summary',\n description: `Count the rows that pass the current filter and read the first ones (at most ${maxRows}, fields: ${allowed.map((c) => c.field).join(', ')}).`,\n inputSchema: { type: 'object', properties: { limit: { type: 'integer', minimum: 1, maximum: maxRows } }, additionalProperties: false },\n execute: (input) => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n const raw = isPlainObject(input) && hasOwn(input, 'limit') ? input.limit : maxRows;\n const limit = typeof raw === 'number' && raw >= 1 ? Math.min(Math.floor(raw), maxRows) : maxRows;\n const all = api.getAllFilteredRows();\n const list = Array.isArray(all) ? all : [];\n const rows = list.slice(0, limit).map((row) => {\n const out: Record<string, unknown> = {};\n if (!isPlainObject(row)) return out;\n // Through the column's valueGetter, as the grid shows the cell.\n for (const col of allowed) out[col.field] = jsonValue(getCellValue(row as GridRowModel, col.field, col as CellColumn));\n return out;\n });\n return { ok: true, rowCount: list.length, rows };\n }),\n });\n }\n return tools;\n}\n"],"names":["warnedCallbacks","warnCallbackFailure","key","message","error","tryGetCellValue","row","field","colDef","raw","getCellValue","value","DATE_ONLY","toDate","date","trimmed","match","year","month","day","toLocalDateString","y","m","d","getOperatorsForType","type","AGGREGATION_FNS","PIVOT_FNS","NO_VALUE_OPS","MAX_FILTER_DEPTH","ALL_PARTS","PART_KEYS","hasOwn","obj","isPlainObject","selectedParts","options","include","exclude","part","usableColumns","columns","seen","out","col","operatorsOf","isFilterable","isSortable","isGroupable","isHideable","aggregationFnsOf","fns","base","fn","allowed","optionValues","option","GRID_AI_SCHEMA_TITLE","MAX_EXAMPLES","label","header","desc","describe","node","text","ctx","examplesOf","v","valueSchema","values","one","examples","filterItemSchema","operators","noValue","op","hint","ops","filterSchema","cols","defs","filterable","properties","logic","depth","child","fieldEnum","c","partSchema","sortable","groupable","dims","dimArray","getGridAiSchema","schema","GRID_AI_VALIDATED_BRAND","brandGridAiValidated","INVALID","valid","PLAIN_NUMBER","LEADING_DOT_NUMBER","GROUPED_NUMBER","STRIPPED_CHARS","parseNumberText","s","negative","percent","parseDateText","current","TRUE_WORDS","FALSE_WORDS","parseBooleanText","labels","parseSingleSelectText","lower","ok","fromParsed","parsed","isBlank","coerceString","coerceNumber","coerceDate","coerceBoolean","coerceSingleSelect","coerceValue","MAX_LIST","MAX_ERRORS","fail","path","show","keysOf","column","what","list","items","oneOf","choices","filterValue","result","filterItem","operator","item","rawValue","entry","i","r","filterItems","at","filterModel","model","word","sortModel","sort","fieldList","canAggregate","canPivot","aggregationModel","pivotModel","valueFields","aggFn","visibilityModel","visible","readPart","state","validateGridAiState","json","validate","input","p","FENCE","abortError","readModelText","open","lineEnd","close","lang","errorText","emptyResult","errors","readModelReply","reply","parts","around","inner","createGridAiPromptHandler","callModel","schemaOptions","partOptions","prompt","context","signal","aborted","_","reject","request","DEFAULT_MAX_ROWS","MAX_ROWS_LIMIT","SET_TOOLS","failure","run","body","apiOf","apiRef","api","jsonValue","setTool","name","description","_version","_schemaVersion","_title","_description","inputSchema","applied","NO_INPUT","createGridAgentTools","tools","tool","maxRows","limit","all","rows"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai.es.js","sources":["../lib/utils/values.ts","../lib/utils/filtering/index.ts","../lib/ai/columns.ts","../lib/ai/schema.ts","../lib/utils/aiBrand.ts","../lib/utils/parsing.ts","../lib/ai/coerce.ts","../lib/ai/validate.ts","../lib/ai/promptHandler.ts","../lib/ai/agentTools.ts"],"sourcesContent":["import type { GridColDef, GridRowModel } from '../types';\n\nconst warnedCallbacks = new Set<string>();\n\n/**\n * Warn once per key (callback kind and column), in development only, that a consumer callback\n * threw and the grid fell back to a default instead of crashing.\n */\nexport function warnCallbackFailure(key: string, message: string, error: unknown): void {\n if (process.env.NODE_ENV === 'production' || warnedCallbacks.has(key)) return;\n warnedCallbacks.add(key);\n console.warn(`[OpenGridX] ${message}.`, error);\n}\n\n/**\n * Call a consumer callback; when it throws, warn once per `key` (dev only) and return `fallback`.\n * Used for callbacks whose failure has an obvious default (a detail-panel height, a group label).\n */\nexport function callSafely<T>(fn: () => T, fallback: T, key: string, message: string): T {\n try {\n return fn();\n } catch (error) {\n warnCallbackFailure(key, message, error);\n return fallback;\n }\n}\n\ntype ValueGetterColumn<R extends GridRowModel> = Pick<GridColDef<R>, 'valueGetter'>;\n\n/**\n * Read a cell through the column's `valueGetter` (or `row[field]`), returning a throw as `error`\n * instead of swallowing it. The row renderer uses this to show the error in that one cell.\n */\nexport function tryGetCellValue<R extends GridRowModel>(\n row: R,\n field: string,\n colDef?: ValueGetterColumn<R>\n): { value: unknown; error?: unknown } {\n const raw = row[field];\n if (!colDef?.valueGetter) return { value: raw };\n try {\n return { value: colDef.valueGetter({ row, field, value: raw }) };\n } catch (error) {\n return { value: undefined, error: error ?? new Error('valueGetter failed') };\n }\n}\n\n/**\n * The value a cell holds before formatting: the column's `valueGetter` result when it has one,\n * otherwise `row[field]`. Filtering, sorting, the quick filter, aggregation, row grouping, pivot,\n * list view, clipboard and editing all read cells through this, so a computed column behaves the\n * same everywhere. A `valueGetter` that throws reads as `undefined` (with a one-time dev warning\n * per column), so one bad record cannot take the whole grid down.\n */\nexport function getCellValue<R extends GridRowModel>(row: R, field: string, colDef?: ValueGetterColumn<R>): unknown {\n // Plain columns read the field directly: this runs once per row and column in every\n // whole-dataset pass (sort, filter, grouping, aggregation), so it must not allocate.\n if (!colDef?.valueGetter) return row[field];\n const { value, error } = tryGetCellValue(row, field, colDef);\n if (error !== undefined) {\n warnCallbackFailure(`valueGetter:${field}`, `valueGetter for column \"${field}\" threw; the value is read as undefined`, error);\n }\n return value;\n}\n\n/**\n * The column's `valueFormatter` text for `value`, or undefined when the column has no formatter\n * or the formatter throws (with a one-time dev warning per column).\n */\nexport function getFormattedValue<R extends GridRowModel>(\n row: R,\n field: string,\n value: unknown,\n colDef?: Pick<GridColDef<R>, 'valueFormatter'>\n): string | undefined {\n const formatter = colDef?.valueFormatter;\n if (!formatter) return undefined;\n // callSafely inlined: this runs for every cell of the quick filter's first search.\n try {\n return formatter({ value, row, field });\n } catch (error) {\n warnCallbackFailure(`valueFormatter:${field}`, `valueFormatter for column \"${field}\" threw; the value is shown unformatted`, error);\n return undefined;\n }\n}\n\n/**\n * Coerce a cell or filter value to a number. Returns null for null/undefined, blank strings,\n * NaN and anything that does not parse, so an empty cell is never read as 0.\n */\nexport function toNumber(value: unknown): number | null {\n if (value == null) return null;\n if (typeof value === 'number') return Number.isNaN(value) ? null : value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n const n = Number(trimmed);\n return Number.isNaN(n) ? null : n;\n }\n if (typeof value === 'boolean') return null;\n if (value instanceof Date) {\n const t = value.getTime();\n return Number.isNaN(t) ? null : t;\n }\n if (typeof value === 'bigint') return Number(value);\n return null;\n}\n\nconst DATE_ONLY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Parse a Date object, epoch milliseconds or a date string. A plain `YYYY-MM-DD` string is read\n * as a local calendar date: `new Date('2024-01-10')` is UTC midnight, which is the previous day\n * west of UTC. Returns null for empty, unparsable or invalid values.\n */\nexport function toDate(value: unknown): Date | null {\n if (value == null) return null;\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'number') {\n date = new Date(value);\n } else if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n const match = DATE_ONLY.exec(trimmed);\n if (match) {\n const year = Number(match[1]);\n const month = Number(match[2]) - 1;\n const day = Number(match[3]);\n date = new Date(year, month, day);\n // Reject roll-overs such as 2024-02-31.\n if (date.getMonth() !== month || date.getDate() !== day) return null;\n } else {\n if (!hasOnlyDateWords(trimmed)) return null;\n date = new Date(trimmed);\n }\n } else {\n return null;\n }\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\nconst DATE_WORDS = [\n 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october',\n 'november', 'december', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',\n];\nconst DATE_TOKENS = new Set(['t', 'z', 'am', 'pm', 'gmt', 'utc', 'sept']);\n\nfunction isDateWord(word: string): boolean {\n if (DATE_TOKENS.has(word)) return true;\n return word.length >= 3 && DATE_WORDS.some(name => name.startsWith(word));\n}\n\n/**\n * Whether every run of letters in `text` is a month or weekday name (or abbreviation), or one of\n * T, Z, AM, PM, GMT, UTC. `Date.parse` accepts free text such as \"hello 5\" (as a 2001 date in V8),\n * which must not become a date. A loop, not a regex.\n */\nfunction hasOnlyDateWords(text: string): boolean {\n let word = '';\n for (let i = 0; i <= text.length; i++) {\n const ch = i < text.length ? text[i].toLowerCase() : '';\n if (ch >= 'a' && ch <= 'z') {\n word += ch;\n continue;\n }\n if (word !== '' && !isDateWord(word)) return false;\n word = '';\n }\n return true;\n}\n\n/** A sortable integer for the local calendar day of a date (YYYYMMDD), or null when unparsable. */\nexport function toLocalDayKey(value: unknown): number | null {\n const date = toDate(value);\n if (!date) return null;\n return date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate();\n}\n\n/** The local calendar day of a date as `YYYY-MM-DD`, or '' when unparsable. */\nexport function toLocalDateString(value: unknown): string {\n const date = toDate(value);\n if (!date) return '';\n const y = String(date.getFullYear()).padStart(4, '0');\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\nlet localDateFormat: Intl.DateTimeFormat | null = null;\n\n/**\n * `date.toLocaleDateString()` (the default locale's numeric date), with the formatter created\n * once: building a new one per call is several times slower on large grids.\n */\nexport function formatLocalDate(date: Date): string {\n localDateFormat ??= new Intl.DateTimeFormat();\n return localDateFormat.format(date);\n}\n\ntype ValueOption = string | number | { value: unknown; label: string };\n\n/** The label of the `valueOptions` entry for `value`, or undefined when no option matches. */\nexport function getValueOptionLabel(options: readonly ValueOption[] | undefined, value: unknown): string | undefined {\n if (!options) return undefined;\n const optionValue = (option: ValueOption): unknown => (typeof option === 'object' ? option.value : option);\n const optionLabel = (option: ValueOption): string => (typeof option === 'object' ? option.label : String(option));\n // Exact match first; then by text, so a numeric option still labels a value read back as a string.\n const match = options.find(option => Object.is(optionValue(option), value))\n ?? options.find(option => String(optionValue(option)) === String(value));\n return match === undefined ? undefined : optionLabel(match);\n}\n\n/**\n * Default display text for a cell whose column has no `valueFormatter`, by column `type`:\n * - `date`: the local calendar date (`toLocaleDateString()`) of a Date, timestamp or date string;\n * text that does not parse as a date is shown as is.\n * - `boolean`: `Yes` / `No` for `true` / `false`.\n * - `singleSelect`: the matching `valueOptions` label; a value with no option is shown as is.\n * - anything else (and `image`, whose cell renders an image of this URL): `String(value)`.\n * null and undefined are ''. The grid cells and the text exporters (CSV, print, PDF) use this, so\n * a file shows what the grid shows.\n */\nexport function formatValueByType(value: unknown, colDef: Pick<GridColDef, 'type' | 'valueOptions'> | undefined): string {\n if (value === null || value === undefined) return '';\n switch (colDef?.type) {\n case 'date': {\n const date = toDate(value);\n return date ? formatLocalDate(date) : String(value);\n }\n case 'boolean':\n if (value === true) return 'Yes';\n if (value === false) return 'No';\n return String(value);\n case 'singleSelect':\n return getValueOptionLabel(colDef.valueOptions, value) ?? String(value);\n default:\n return String(value);\n }\n}\n","\nimport type { GridRowModel, GridFilterItem, GridFilterModel, GridFilterGroup, GridFilterOperator, GridColDef } from '../../types';\nimport type { GridColumnLookup } from '../columnLookup';\nimport { getCellValue, formatValueByType, getFormattedValue, toLocalDateString, toLocalDayKey, toNumber } from '../values';\n\n/** Compares a cell value with the filter item's value. */\nexport type GridFilterOperatorFn = (value: unknown, filterValue?: unknown) => boolean;\n\ntype RowPredicate = (row: GridRowModel) => boolean;\n\n/** Operators that take no value. Every other operator ignores an item whose value is empty. */\nexport const NO_VALUE_OPERATORS: ReadonlySet<string> = new Set<GridFilterOperator>(['isEmpty', 'isNotEmpty']);\n\n/**\n * True for a filter value that means \"nothing entered yet\": undefined, null, a blank string or an\n * empty array. Items with such a value (other than isEmpty / isNotEmpty) do not filter.\n */\nexport function isEmptyFilterValue(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n return false;\n}\n\nfunction isBlankCell(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'number') return Number.isNaN(value);\n return typeof value === 'string' && value.trim() === '';\n}\n\nconst numeric = (compare: (a: number, b: number) => boolean): GridFilterOperatorFn => (value, filterValue) => {\n const a = toNumber(value);\n const b = toNumber(filterValue);\n if (a === null || b === null) return false;\n return compare(a, b);\n};\n\nconst byDay = (compare: (a: number, b: number) => boolean): GridFilterOperatorFn => (value, filterValue) => {\n const a = toLocalDayKey(value);\n const b = toLocalDayKey(filterValue);\n if (a === null || b === null) return false;\n return compare(a, b);\n};\n\n/** Same local calendar day. Accepts Date objects, epoch milliseconds and date strings on both sides. */\nconst dateIs: GridFilterOperatorFn = byDay((a, b) => a === b);\n\n/** A different local calendar day. Empty or unparsable cells count as \"not that day\". */\nconst dateNot: GridFilterOperatorFn = (value, filterValue) => {\n const a = toLocalDayKey(value);\n const b = toLocalDayKey(filterValue);\n if (a === null || b === null) return true;\n return a !== b;\n};\n\nexport const FILTER_OPERATORS: Record<GridFilterOperator, GridFilterOperatorFn> = {\n contains: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().includes(String(filterValue).toLowerCase());\n },\n\n equals: (value, filterValue) => {\n if (value == null && filterValue == null) return true;\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase() === String(filterValue).toLowerCase();\n },\n\n startsWith: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().startsWith(String(filterValue).toLowerCase());\n },\n\n endsWith: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().endsWith(String(filterValue).toLowerCase());\n },\n\n isEmpty: (value) => {\n return value == null || String(value).trim() === '';\n },\n\n isNotEmpty: (value) => {\n return value != null && String(value).trim() !== '';\n },\n\n // Numeric operators: blank cells and non-numeric values never match (a blank cell is not 0).\n '=': numeric((a, b) => a === b),\n '>': numeric((a, b) => a > b),\n '>=': numeric((a, b) => a >= b),\n '<': numeric((a, b) => a < b),\n '<=': numeric((a, b) => a <= b),\n\n '!=': (value, filterValue) => {\n if (isEmptyFilterValue(filterValue)) return true;\n const a = toNumber(value);\n const b = toNumber(filterValue);\n if (a !== null && b !== null) return a !== b;\n // An empty cell is \"not equal\" to every value, whatever that value is.\n if (isBlankCell(value)) return true;\n return String(value).toLowerCase() !== String(filterValue).toLowerCase();\n },\n\n // A scalar value is treated as a one-element list, so a typed \"Active\" works like [\"Active\"].\n isAnyOf: (value, filterValue) => {\n if (value == null) return false;\n const options = Array.isArray(filterValue) ? filterValue : [filterValue];\n const cell = String(value).toLowerCase();\n return options.some(option => option != null && String(option).toLowerCase() === cell);\n },\n\n // Used by boolean and singleSelect (case-insensitive string comparison), and by dates.\n not: (value, filterValue) => {\n if (value instanceof Date) return dateNot(value, filterValue);\n if (value == null && filterValue == null) return false;\n if (value == null || filterValue == null) return true;\n return String(value).toLowerCase() !== String(filterValue).toLowerCase();\n },\n\n is: (value, filterValue) => {\n if (filterValue == null || filterValue === '') return true;\n if (value instanceof Date) return dateIs(value, filterValue);\n return String(value).toLowerCase() === String(filterValue).toLowerCase();\n },\n\n // Date operators compare local calendar days.\n after: byDay((a, b) => a > b),\n onOrAfter: byDay((a, b) => a >= b),\n before: byDay((a, b) => a < b),\n onOrBefore: byDay((a, b) => a <= b),\n};\n\n/** Date columns compare `is` / `not` by calendar day, so ISO strings and Date objects match the typed day. */\nconst DATE_COLUMN_OPERATORS: Partial<Record<GridFilterOperator, GridFilterOperatorFn>> = {\n is: dateIs,\n not: dateNot,\n};\n\nfunction resolveOperator(operator: string, colDef: GridColDef | undefined): GridFilterOperatorFn | undefined {\n if (!Object.prototype.hasOwnProperty.call(FILTER_OPERATORS, operator)) return undefined;\n const op = operator as GridFilterOperator;\n if (colDef?.type === 'date') {\n const dateFn = DATE_COLUMN_OPERATORS[op];\n if (dateFn) return dateFn;\n }\n return FILTER_OPERATORS[op];\n}\n\nfunction isFilterGroup(item: GridFilterItem | GridFilterGroup): item is GridFilterGroup {\n return 'items' in item && Array.isArray(item.items);\n}\n\ninterface CompileContext {\n columns?: GridColumnLookup;\n /** Unknown operators already reported in this pass, so the warning fires once per pass, not per row. */\n warned: Set<string>;\n}\n\nfunction compileItem(item: GridFilterItem, ctx: CompileContext): RowPredicate | null {\n const { field, operator, value } = item;\n // An item whose value has not been entered yet (or was cleared) does not filter.\n if (!NO_VALUE_OPERATORS.has(operator) && isEmptyFilterValue(value)) return null;\n\n const colDef = ctx.columns?.byField.get(field);\n const operatorFn = resolveOperator(operator, colDef);\n if (!operatorFn) {\n if (!ctx.warned.has(operator)) {\n ctx.warned.add(operator);\n console.warn(`Unknown filter operator: ${operator}`);\n }\n return null;\n }\n return (row) => operatorFn(getCellValue(row, field, colDef), value);\n}\n\nfunction compileGroup(\n items: (GridFilterItem | GridFilterGroup)[],\n logicOperator: 'and' | 'or',\n ctx: CompileContext\n): RowPredicate | null {\n const predicates: RowPredicate[] = [];\n for (const item of items) {\n const predicate = isFilterGroup(item)\n ? compileGroup(item.items, item.logicOperator, ctx)\n : compileItem(item, ctx);\n if (predicate) predicates.push(predicate);\n }\n if (predicates.length === 0) return null;\n if (predicates.length === 1) return predicates[0];\n return logicOperator === 'or'\n ? (row) => predicates.some(p => p(row))\n : (row) => predicates.every(p => p(row));\n}\n\nfunction pushSearchText(out: string[], value: unknown): void {\n if (value == null) return;\n switch (typeof value) {\n case 'string':\n out.push(value.toLowerCase());\n return;\n case 'number':\n if (!Number.isNaN(value)) out.push(String(value));\n return;\n case 'boolean':\n case 'bigint':\n out.push(String(value));\n return;\n default:\n break;\n }\n if (value instanceof Date) {\n // Search the calendar day, not Date.toString()'s \"Wed Jan 10 2024 ... GMT+0000\".\n const day = toLocalDateString(value);\n if (day) out.push(day);\n return;\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (entry == null || typeof entry !== 'object') pushSearchText(out, entry);\n }\n }\n // Other objects have no meaningful text (\"[object Object]\") and are skipped.\n}\n\nfunction getQuickFilterTexts(row: GridRowModel, columns: GridColumnLookup | undefined): string[] {\n const texts: string[] = [];\n if (!columns) {\n for (const value of Object.values(row)) pushSearchText(texts, value);\n return texts;\n }\n for (const col of columns.quickFilterColumns) {\n const value = getCellValue(row, col.field, col);\n const formatted = getFormattedValue(row, col.field, value, col);\n if (formatted != null && formatted !== '') {\n texts.push(String(formatted).toLowerCase());\n } else if (col.type === 'date' || col.type === 'boolean' || col.type === 'singleSelect') {\n // Without a formatter the grid shows a locale date, Yes / No or the option label: search that too.\n const shown = formatValueByType(value, col);\n if (shown !== '') texts.push(shown.toLowerCase());\n }\n pushSearchText(texts, value);\n }\n return texts;\n}\n\n// Search texts per column lookup and row object. The grid keeps one lookup while the columns and\n// hidden columns stay the same, so typing in the quick filter reads every cell once, not per keystroke.\nconst quickFilterTextCache = new WeakMap<GridColumnLookup, WeakMap<GridRowModel, string[]>>();\n\nfunction getCachedQuickFilterTexts(row: GridRowModel, columns: GridColumnLookup | undefined): string[] {\n if (!columns) return getQuickFilterTexts(row, columns);\n let byRow = quickFilterTextCache.get(columns);\n if (!byRow) {\n byRow = new WeakMap();\n quickFilterTextCache.set(columns, byRow);\n }\n let texts = byRow.get(row);\n if (!texts) {\n texts = getQuickFilterTexts(row, columns);\n byRow.set(row, texts);\n }\n return texts;\n}\n\nfunction quickFilterTerms(values: readonly string[] | undefined): string[] {\n return (values ?? [])\n .map(value => String(value ?? '').trim().toLowerCase())\n .filter(term => term !== '');\n}\n\nfunction textsMatchTerms(texts: readonly string[], terms: readonly string[]): boolean {\n // Plain loops: this runs once per row on every keystroke.\n for (let t = 0; t < terms.length; t++) {\n const term = terms[t];\n let found = false;\n for (let i = 0; i < texts.length; i++) {\n if (texts[i].includes(term)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n return true;\n}\n\nfunction compileQuickFilter(values: readonly string[] | undefined, columns: GridColumnLookup | undefined): RowPredicate | null {\n const terms = quickFilterTerms(values);\n if (terms.length === 0) return null;\n return (row) => textsMatchTerms(getCachedQuickFilterTexts(row, columns), terms);\n}\n\n// filterRows also keeps the texts of the last rows array it searched, by position, per column\n// lookup. Looking a text up by index is much cheaper than one WeakMap entry per row, and after an\n// edit (a new array with mostly the same row objects at the same positions) only the rows whose\n// object changed are read again.\ninterface QuickFilterArrayTexts {\n rows: readonly GridRowModel[];\n texts: string[][];\n}\nconst quickFilterArrayCache = new WeakMap<GridColumnLookup, QuickFilterArrayTexts>();\n\nfunction getQuickFilterTextsByIndex(rows: readonly GridRowModel[], columns: GridColumnLookup): string[][] {\n const previous = quickFilterArrayCache.get(columns);\n if (previous && previous.rows === rows) return previous.texts;\n const texts = new Array<string[]>(rows.length);\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n texts[i] = previous && i < previous.rows.length && previous.rows[i] === row\n ? previous.texts[i]\n : getQuickFilterTexts(row, columns);\n }\n quickFilterArrayCache.set(columns, { rows, texts });\n return texts;\n}\n\n/**\n * Compile a filter model into a row predicate. Returns null when the model filters nothing\n * (no items with a value and no quick-filter terms), so callers can skip the pass entirely.\n *\n * Pass `columns` so that cells are read through `valueGetter`, date columns use calendar-day\n * comparison and the quick filter searches only visible, filterable columns (including their\n * `valueFormatter` text). Without it, `row[field]` is read and the quick filter searches every\n * primitive value in the row.\n */\nexport function createRowFilter(\n filterModel: GridFilterModel | GridFilterGroup | null | undefined,\n columns?: GridColumnLookup\n): RowPredicate | null {\n if (!filterModel) return null;\n const ctx: CompileContext = { columns, warned: new Set() };\n const quickFilterValues = 'quickFilterValues' in filterModel ? filterModel.quickFilterValues : undefined;\n const quick = compileQuickFilter(quickFilterValues, columns);\n const itemsPredicate = compileGroup(filterModel.items ?? [], filterModel.logicOperator ?? 'and', ctx);\n if (quick && itemsPredicate) return (row) => quick(row) && itemsPredicate(row);\n return quick ?? itemsPredicate;\n}\n\n/**\n * Apply a single filter item to a row\n */\nexport function applyFilterItem<R extends GridRowModel>(\n row: R,\n filterItem: GridFilterItem,\n colDef?: GridColDef\n): boolean {\n const columns: GridColumnLookup | undefined = colDef\n ? { byField: new Map([[filterItem.field, colDef]]), quickFilterColumns: [] }\n : undefined;\n const predicate = compileItem(filterItem, { columns, warned: new Set() });\n return predicate ? predicate(row) : true;\n}\n\n/**\n * Apply the quick filter (global search). Every term must be found in at least one searched value.\n */\nexport function applyQuickFilter<R extends GridRowModel>(\n row: R,\n quickFilterValues: string[],\n columns?: GridColumnLookup\n): boolean {\n const predicate = compileQuickFilter(quickFilterValues, columns);\n return predicate ? predicate(row) : true;\n}\n\n/**\n * Check if a row matches the filter model. Compiles the model on every call: to test many rows,\n * build a predicate once with createRowFilter.\n */\nexport function isRowMatchingFilter<R extends GridRowModel>(\n row: R,\n filterModel: GridFilterModel | GridFilterGroup,\n columns?: GridColumnLookup\n): boolean {\n const predicate = createRowFilter(filterModel, columns);\n return predicate ? predicate(row) : true;\n}\n\nexport function filterRows<R extends GridRowModel>(\n rows: R[],\n filterModel: GridFilterModel,\n columns?: GridColumnLookup\n): R[] {\n const terms = columns && filterModel ? quickFilterTerms(filterModel.quickFilterValues) : [];\n if (columns && terms.length > 0) {\n // The same result as createRowFilter's predicate: the quick filter and then the items.\n const itemsPredicate = compileGroup(filterModel.items ?? [], filterModel.logicOperator ?? 'and', { columns, warned: new Set() });\n const texts = getQuickFilterTextsByIndex(rows, columns);\n const result: R[] = [];\n for (let i = 0; i < rows.length; i++) {\n if (textsMatchTerms(texts[i], terms) && (!itemsPredicate || itemsPredicate(rows[i]))) result.push(rows[i]);\n }\n return result;\n }\n const predicate = createRowFilter(filterModel, columns);\n if (!predicate) return rows;\n return rows.filter(row => predicate(row));\n}\n\nexport function getDefaultOperator(type?: string): GridFilterOperator {\n switch (type) {\n case 'number':\n return '=';\n case 'date':\n return 'is';\n case 'boolean':\n return 'is';\n case 'singleSelect':\n return 'isAnyOf';\n default:\n return 'contains';\n }\n}\n\nexport function getOperatorsForType(type?: string): GridFilterOperator[] {\n switch (type) {\n case 'number':\n return ['=', '!=', '>', '>=', '<', '<=', 'isEmpty', 'isNotEmpty'];\n case 'date':\n return ['is', 'not', 'after', 'onOrAfter', 'before', 'onOrBefore', 'isEmpty', 'isNotEmpty'];\n case 'boolean':\n return ['is'];\n case 'singleSelect':\n return ['isAnyOf', 'is', 'not'];\n default:\n return ['contains', 'equals', 'startsWith', 'endsWith', 'isEmpty', 'isNotEmpty'];\n }\n}\n\n/**\n * The text an input shows for a committed filter value: dates as `YYYY-MM-DD`, lists joined with\n * commas. Never used to emit anything (the filter panel and the header filter row).\n */\nexport function filterValueToInputText(value: unknown, colType?: string): string {\n if (value == null) return '';\n if (colType === 'date' || value instanceof Date) {\n const day = toLocalDateString(value);\n return day || (typeof value === 'string' ? value : '');\n }\n if (Array.isArray(value)) return value.map(v => String(v)).join(', ');\n return String(value);\n}\n","// Which columns may take part in each part of the state. The schema and the validator both read\n// these, so the model is never offered a field the validator would drop.\nimport { getOperatorsForType } from '../utils/filtering';\nimport type { GridFilterOperator, GridPivotAggFn } from '../types';\nimport type { GridAiColumn, GridAiPart, GridAiPartOptions } from './types';\n\n/** The built-in aggregation functions (`AGGREGATION_FUNCTIONS` in lib/utils/aggregation). */\nexport const AGGREGATION_FNS: readonly string[] = ['sum', 'avg', 'count', 'min', 'max', 'unique'];\n/** The functions a pivot value field takes (`GridPivotAggFn`). */\nexport const PIVOT_FNS: readonly GridPivotAggFn[] = ['sum', 'avg', 'count', 'min', 'max'];\n/** Operators without a value. */\nexport const NO_VALUE_OPS: readonly string[] = ['isEmpty', 'isNotEmpty'];\n/** Deepest nesting of filter groups. */\nexport const MAX_FILTER_DEPTH = 3;\n\nexport const ALL_PARTS: readonly GridAiPart[] = ['filter', 'sort', 'grouping', 'aggregation', 'pivot', 'columnVisibility'];\n\n/** State key of each part, in output order. */\nexport const PART_KEYS: Record<GridAiPart, string> = {\n filter: 'filterModel',\n sort: 'sortModel',\n grouping: 'rowGroupingModel',\n aggregation: 'aggregationModel',\n pivot: 'pivotModel',\n columnVisibility: 'columnVisibilityModel',\n};\n\nexport function hasOwn(obj: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function selectedParts(options: GridAiPartOptions | undefined): GridAiPart[] {\n const include = Array.isArray(options?.include) ? options.include : ALL_PARTS;\n const exclude = Array.isArray(options?.exclude) ? options.exclude : [];\n return ALL_PARTS.filter((part) => include.includes(part) && !exclude.includes(part));\n}\n\n/**\n * The usable columns, first one per field. System columns (`__check__`, `__group__`, …), spacers\n * and fields that are not plain strings are skipped.\n */\nexport function usableColumns(columns: readonly GridAiColumn[] | unknown): GridAiColumn[] {\n if (!Array.isArray(columns)) return [];\n const seen = new Set<string>();\n const out: GridAiColumn[] = [];\n for (const col of columns as unknown[]) {\n if (!isPlainObject(col)) continue;\n const field = col.field;\n if (typeof field !== 'string' || field === '' || field.startsWith('__') || col.isSpacer === true || seen.has(field)) continue;\n seen.add(field);\n out.push(col as unknown as GridAiColumn);\n }\n return out;\n}\n\nexport function operatorsOf(col: GridAiColumn): GridFilterOperator[] {\n return getOperatorsForType(col.type);\n}\n\nexport const isFilterable = (col: GridAiColumn): boolean => col.filterable !== false;\nexport const isSortable = (col: GridAiColumn): boolean => col.sortable !== false;\nexport const isGroupable = (col: GridAiColumn): boolean => col.groupable !== false;\nexport const isHideable = (col: GridAiColumn): boolean => col.hideable !== false;\n\n/**\n * Aggregation functions for a column, as the Summaries panel offers them: every built-in function\n * for number columns (or `aggregable: true`), `count` for the others, never with `aggregable: false`,\n * and limited by `availableAggregationFunctions`.\n */\nexport function aggregationFnsOf(col: GridAiColumn, fns: readonly string[] = AGGREGATION_FNS): string[] {\n if (col.aggregable === false) return [];\n const base = col.type === 'number' || col.aggregable === true ? fns : fns.filter((fn) => fn === 'count');\n const allowed = col.availableAggregationFunctions;\n return Array.isArray(allowed) ? base.filter((fn) => allowed.includes(fn)) : [...base];\n}\n\n/** JSON-safe option values of a singleSelect column, in order, without duplicates. */\nexport function optionValues(col: GridAiColumn): (string | number)[] {\n const out: (string | number)[] = [];\n if (!Array.isArray(col.valueOptions)) return out;\n for (const option of col.valueOptions) {\n const value: unknown = option !== null && typeof option === 'object' ? option.value : option;\n if ((typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value))) && !out.includes(value)) out.push(value);\n }\n return out;\n}\n","// getGridAiSchema: a JSON Schema (draft 2020-12) of the grid state a model may produce. Built from\n// the column definitions only; no row data is read. Same columns and options, same schema.\nimport {\n MAX_FILTER_DEPTH,\n NO_VALUE_OPS,\n PART_KEYS,\n PIVOT_FNS,\n aggregationFnsOf,\n isFilterable,\n isGroupable,\n isHideable,\n isSortable,\n operatorsOf,\n optionValues,\n selectedParts,\n usableColumns,\n} from './columns';\nimport type { GridAiColumn, GridAiJsonSchema, GridAiPart, GridAiSchema, GridAiSchemaOptions } from './types';\n\n/** Title of every schema. Also the marker `check-bundle` uses to keep this code out of the core bundle. */\nexport const GRID_AI_SCHEMA_TITLE = 'OpenGridX grid state';\n\nconst MAX_EXAMPLES = 10;\n\ninterface Ctx {\n descriptions: boolean;\n examples: boolean;\n}\n\nfunction label(col: GridAiColumn): string {\n const header = typeof col.headerName === 'string' && col.headerName !== '' ? col.headerName : col.field;\n const desc = typeof col.description === 'string' && col.description !== '' ? ` (${col.description})` : '';\n return `${header}${desc}`;\n}\n\nfunction describe(node: GridAiJsonSchema, text: string, ctx: Ctx): GridAiJsonSchema {\n return ctx.descriptions ? { ...node, description: text } : node;\n}\n\nfunction examplesOf(col: GridAiColumn, ctx: Ctx): unknown[] {\n if (!ctx.examples || !Array.isArray(col.aiExamples)) return [];\n return col.aiExamples\n .filter((v) => typeof v === 'string' || typeof v === 'boolean' || (typeof v === 'number' && Number.isFinite(v)))\n .slice(0, MAX_EXAMPLES);\n}\n\n/** Schema of one filter value for the column's type. */\nfunction valueSchema(col: GridAiColumn, ctx: Ctx): GridAiJsonSchema {\n let node: GridAiJsonSchema;\n switch (col.type) {\n case 'number':\n node = { type: 'number' };\n break;\n case 'date':\n node = { type: 'string', format: 'date' };\n break;\n case 'boolean':\n node = { type: 'boolean' };\n break;\n case 'singleSelect': {\n const values = optionValues(col);\n const one: GridAiJsonSchema = values.length > 0 ? { enum: values } : { type: 'string' };\n node = { anyOf: [one, { type: 'array', items: one }] };\n break;\n }\n default:\n node = { type: 'string' };\n }\n const examples = examplesOf(col, ctx);\n return examples.length > 0 ? { ...node, examples } : node;\n}\n\nfunction filterItemSchema(col: GridAiColumn, ctx: Ctx): GridAiJsonSchema {\n const operators = operatorsOf(col);\n const noValue = operators.filter((op) => NO_VALUE_OPS.includes(op));\n const hint = col.type === 'singleSelect' ? '; isAnyOf takes an array' : '';\n const ops = noValue.length > 0 ? `${noValue.join(' and ')} take no value${hint}` : hint.slice(2);\n return describe(\n {\n type: 'object',\n properties: {\n field: { const: col.field },\n operator: { enum: operators },\n value: valueSchema(col, ctx),\n },\n required: ['field', 'operator'],\n additionalProperties: false,\n },\n ops ? `${label(col)}: ${ops}` : label(col),\n ctx,\n );\n}\n\nfunction filterSchema(cols: GridAiColumn[], ctx: Ctx, defs: Record<string, GridAiJsonSchema>): GridAiJsonSchema | null {\n const filterable = cols.filter(isFilterable);\n const properties: Record<string, GridAiJsonSchema> = {};\n const logic = { enum: ['and', 'or'] };\n if (filterable.length > 0) {\n defs.filterItem = { oneOf: filterable.map((col) => filterItemSchema(col, ctx)) };\n // Groups are unrolled to MAX_FILTER_DEPTH levels: the deepest one holds items only.\n for (let depth = MAX_FILTER_DEPTH; depth >= 1; depth--) {\n const child = depth === MAX_FILTER_DEPTH ? { $ref: '#/$defs/filterItem' } : { anyOf: [{ $ref: '#/$defs/filterItem' }, { $ref: `#/$defs/filterGroup${depth + 1}` }] };\n defs[`filterGroup${depth}`] = {\n type: 'object',\n properties: { logicOperator: logic, items: { type: 'array', items: child } },\n required: ['logicOperator', 'items'],\n additionalProperties: false,\n };\n }\n properties.items = { type: 'array', items: { anyOf: [{ $ref: '#/$defs/filterItem' }, { $ref: '#/$defs/filterGroup1' }] } };\n properties.logicOperator = logic;\n }\n properties.quickFilterValues = describe({ type: 'array', items: { type: 'string' } }, 'Words a row must contain, in any column', ctx);\n return { type: 'object', properties, additionalProperties: false };\n}\n\nfunction fieldEnum(cols: GridAiColumn[]): GridAiJsonSchema {\n return { enum: cols.map((c) => c.field) };\n}\n\nfunction partSchema(part: GridAiPart, cols: GridAiColumn[], ctx: Ctx, defs: Record<string, GridAiJsonSchema>): GridAiJsonSchema | null {\n switch (part) {\n case 'filter':\n return filterSchema(cols, ctx, defs);\n case 'sort': {\n const sortable = cols.filter(isSortable);\n if (sortable.length === 0) return null;\n return describe(\n {\n type: 'array',\n items: {\n type: 'object',\n properties: { field: fieldEnum(sortable), sort: { enum: ['asc', 'desc'] } },\n required: ['field', 'sort'],\n additionalProperties: false,\n },\n },\n 'Most significant first',\n ctx,\n );\n }\n case 'grouping': {\n const groupable = cols.filter(isGroupable);\n if (groupable.length === 0) return null;\n return describe({ type: 'array', items: fieldEnum(groupable), uniqueItems: true }, 'Outermost first', ctx);\n }\n case 'aggregation': {\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const col of cols) {\n const fns = aggregationFnsOf(col);\n if (fns.length > 0) properties[col.field] = describe({ enum: fns }, label(col), ctx);\n }\n if (Object.keys(properties).length === 0) return null;\n return { type: 'object', properties, additionalProperties: false };\n }\n case 'pivot': {\n const dims = cols.filter(isGroupable);\n const values = cols\n .map((col) => ({ col, fns: aggregationFnsOf(col, PIVOT_FNS) }))\n .filter((v) => v.fns.length > 0)\n .map(({ col, fns }) => describe({\n type: 'object',\n properties: { field: { const: col.field }, aggFn: { enum: fns } },\n required: ['field', 'aggFn'],\n additionalProperties: false,\n }, label(col), ctx));\n if (dims.length === 0 || values.length === 0) return null;\n const dimArray = { type: 'array', items: fieldEnum(dims), uniqueItems: true };\n return {\n type: 'object',\n properties: { rowFields: dimArray, columnFields: dimArray, valueFields: { type: 'array', items: { oneOf: values } } },\n required: ['rowFields', 'columnFields', 'valueFields'],\n additionalProperties: false,\n };\n }\n case 'columnVisibility': {\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const col of cols.filter(isHideable)) properties[col.field] = describe({ type: 'boolean' }, label(col), ctx);\n if (Object.keys(properties).length === 0) return null;\n return describe({ type: 'object', properties, additionalProperties: false }, 'false hides a column', ctx);\n }\n }\n}\n\n/**\n * A JSON Schema (draft 2020-12) of the grid state a model may return for these columns: filter,\n * sort, grouping, aggregation, pivot and column visibility, each limited to the fields, operators\n * and functions the columns allow. Send it with the user's prompt to a model with structured\n * output, then pass the reply to `validateGridAiState`. Reads column definitions only, never rows.\n * @since v3.4\n */\nexport function getGridAiSchema<C extends GridAiColumn>(columns: readonly C[], options: GridAiSchemaOptions = {}): GridAiSchema {\n const ctx: Ctx = { descriptions: options.descriptions !== false, examples: options.examples !== false };\n const cols = usableColumns(columns);\n const defs: Record<string, GridAiJsonSchema> = {};\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const part of selectedParts(options)) {\n const node = partSchema(part, cols, ctx, defs);\n if (node) properties[PART_KEYS[part]] = node;\n }\n const schema: GridAiSchema = {\n $schema: 'https://json-schema.org/draft/2020-12/schema',\n schemaVersion: 1,\n title: GRID_AI_SCHEMA_TITLE,\n type: 'object',\n properties,\n additionalProperties: false,\n };\n if (ctx.descriptions) {\n schema.description = 'Grid state to apply. Include only the parts the user asked to change.';\n }\n if (Object.keys(defs).length > 0) schema.$defs = defs;\n return schema;\n}\n","// The \"validated\" brand of the AI toolkit. `validateGridAiState` (in the `/ai` entry point) puts it on\n// its result and on the result's `state`; the grid's `aiAssistant` applies a state only when it carries\n// it. Shared by both bundles, so it holds no AI code: just the registered symbol and two helpers.\n\n/** `Symbol.for('opengridx.ai.validated')`: the same symbol in every bundle and realm. */\nexport const GRID_AI_VALIDATED_BRAND: symbol = Symbol.for('opengridx.ai.validated');\n\n/** Brands `value` (non-enumerable, so it does not change equality, spreading or JSON) and returns it. */\nexport function brandGridAiValidated<T extends object>(value: T): T {\n Object.defineProperty(value, GRID_AI_VALIDATED_BRAND, { value: true, enumerable: false });\n return value;\n}\n\n/** Whether `value` carries the brand. */\nexport function isGridAiValidated(value: unknown): boolean {\n return typeof value === 'object' && value !== null && (value as Record<symbol, unknown>)[GRID_AI_VALIDATED_BRAND] === true;\n}\n","import type { GridColDef, GridValidRowModel } from '../types';\nimport { toDate } from './values';\n\n/**\n * Text → typed values: the TSV reader clipboard paste uses, and the per-column-type parsers paste,\n * `GridColDef.valueParser` defaults and the `/ai` validator share. Pure and React-free.\n *\n * Every pattern here is linear (CodeQL scans every push): no adjacent quantifiers that can match the\n * same characters.\n */\n\n/** A parsed value, or `{ ok: false }` when the text does not fit the column type. */\nexport type GridParsedValue = { ok: true; value: unknown } | { ok: false };\n\nconst INVALID: GridParsedValue = { ok: false };\nconst valid = (value: unknown): GridParsedValue => ({ ok: true, value });\n\n/**\n * Splits tab-separated text the way Excel, Google Sheets and LibreOffice write it: tabs between\n * columns, `\\r\\n`, `\\n` or `\\r` between rows. A field that starts with a double quote is quoted: it\n * may hold tabs, line breaks and doubled quotes (`\"\"` → `\"`), the reverse of `escapeTsvField`. A\n * quote inside an unquoted field is kept as is. A trailing empty line is ignored, so `\"a\\tb\\n\"` is one\n * row. Empty text gives no rows.\n */\nexport function parseTsv(text: string): string[][] {\n const rows: string[][] = [];\n if (text === '') return rows;\n let row: string[] = [];\n let field = '';\n let i = 0;\n const n = text.length;\n let fieldStart = true;\n while (i < n) {\n const ch = text[i];\n if (fieldStart && ch === '\"') {\n // A quoted field: read to the closing quote, `\"\"` being one quote.\n let j = i + 1;\n let value = '';\n let closed = false;\n while (j < n) {\n const q = text[j];\n if (q === '\"') {\n if (text[j + 1] === '\"') {\n value += '\"';\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n value += q;\n j += 1;\n }\n if (!closed) {\n // No closing quote: not a quoted field after all, read the quote as text.\n field += ch;\n i += 1;\n fieldStart = false;\n continue;\n }\n field += value;\n i = j;\n fieldStart = false;\n continue;\n }\n fieldStart = false;\n if (ch === '\\t') {\n row.push(field);\n field = '';\n fieldStart = true;\n i += 1;\n } else if (ch === '\\n' || ch === '\\r') {\n row.push(field);\n rows.push(row);\n row = [];\n field = '';\n fieldStart = true;\n i += ch === '\\r' && text[i + 1] === '\\n' ? 2 : 1;\n } else {\n field += ch;\n i += 1;\n }\n }\n // The last line, unless the text ended with a line break (Excel always adds one).\n if (!fieldStart || row.length > 0 || field !== '') {\n row.push(field);\n rows.push(row);\n }\n return rows;\n}\n\nconst PLAIN_NUMBER = /^\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?$/i;\nconst LEADING_DOT_NUMBER = /^\\.\\d+(?:e[+-]?\\d+)?$/i;\nconst GROUPED_NUMBER = /^\\d{1,3}(?:,\\d{3})+(?:\\.\\d*)?$/;\n// Currency symbols (Unicode Sc) and every kind of space, including the no-break spaces Excel uses\n// as a thousands separator.\nconst STRIPPED_CHARS = /[\\p{Sc}\\s]/gu;\n\n/**\n * A number as spreadsheets copy it: `1234.5`, `1,234.5` (comma thousands groups only), `-12`,\n * `(12)` (accounting negative), `12%` (→ 0.12), `1e3`, with currency symbols and spaces stripped.\n * Empty text is `null`. `1,5` is not accepted (it is ambiguous): use a `valueParser` for\n * decimal-comma locales.\n */\nexport function parseNumberText(text: string): GridParsedValue {\n let s = text.replace(STRIPPED_CHARS, '');\n if (s === '') return text.trim() === '' ? valid(null) : INVALID;\n let negative = false;\n if (s.startsWith('(') && s.endsWith(')')) {\n negative = true;\n s = s.slice(1, -1);\n }\n if (s.startsWith('-') || s.startsWith('+') || s.startsWith('−')) {\n if (s[0] !== '+') negative = !negative;\n s = s.slice(1);\n }\n let percent = false;\n if (s.endsWith('%')) {\n percent = true;\n s = s.slice(0, -1);\n }\n if (GROUPED_NUMBER.test(s)) s = s.split(',').join('');\n else if (!PLAIN_NUMBER.test(s) && !LEADING_DOT_NUMBER.test(s)) return INVALID;\n let value = Number(s);\n if (!Number.isFinite(value)) return INVALID;\n if (percent) value /= 100;\n if (negative) value = -value;\n return valid(value);\n}\n\nconst ISO_DATE_PREFIX = /^(\\d{4}-\\d{2}-\\d{2})/;\nconst pad2 = (n: number) => String(n).padStart(2, '0');\n/** Whether an ISO date-time string ends with `Z` or a `±hh:mm` / `±hhmm` offset. A loop, not a regex. */\nfunction hasZone(text: string): boolean {\n const end = text.trimEnd();\n if (end.endsWith('Z') || end.endsWith('z')) return true;\n const tIndex = end.indexOf('T');\n if (tIndex < 0) return false;\n for (let i = end.length - 1; i > tIndex; i--) {\n const ch = end[i];\n if (ch === '+' || ch === '-') return true;\n if (!(ch >= '0' && ch <= '9') && ch !== ':') return false;\n }\n return false;\n}\nconst localDay = (date: Date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;\n\n/**\n * A date: ISO `2026-10-07` (read as that local calendar day) or anything `Date.parse` accepts. Empty\n * text is `null`. The result takes the kind of `current` (the value the cell holds now), as the date\n * editor does: a timestamp stays a timestamp, a date string stays a `YYYY-MM-DD` string (an ISO\n * date-time string keeps its time part); otherwise it is a `Date`.\n */\nexport function parseDateText(text: string, current?: unknown): GridParsedValue {\n const trimmed = text.trim();\n if (trimmed === '') return valid(null);\n const date = toDate(trimmed);\n if (!date) return INVALID;\n if (typeof current === 'number') return valid(date.getTime());\n if (typeof current === 'string') {\n const day = localDay(date);\n if (!ISO_DATE_PREFIX.test(current) || current.length <= 10) return valid(day);\n // A zoned date-time (\"…Z\", \"…+05:30\") is shown as a local day: keep its local time of day on\n // the pasted day and write UTC, or west of UTC the cell would show the day before.\n const held = hasZone(current) ? new Date(current) : null;\n if (held && !Number.isNaN(held.getTime())) {\n return valid(new Date(\n date.getFullYear(), date.getMonth(), date.getDate(),\n held.getHours(), held.getMinutes(), held.getSeconds(), held.getMilliseconds(),\n ).toISOString());\n }\n return valid(day + current.slice(10));\n }\n return valid(date);\n}\n\n/** Text read as `true` / `false`, besides the grid's own `Yes` / `No` cell labels. Lower case. */\nconst TRUE_WORDS = new Set(['true', 'yes', '1']);\nconst FALSE_WORDS = new Set(['false', 'no', '0']);\n\nexport interface GridBooleanLabels {\n /** Text shown for `true` (the grid shows `Yes`). */\n trueLabel?: string;\n /** Text shown for `false` (the grid shows `No`). */\n falseLabel?: string;\n}\n\n/**\n * A boolean: `true`/`false`, `yes`/`no` (the grid's own `Yes` / `No` cell labels), `1`/`0` and any\n * `labels` given, case-insensitive. Empty text is `null`.\n */\nexport function parseBooleanText(text: string, labels?: GridBooleanLabels): GridParsedValue {\n const s = text.trim().toLowerCase();\n if (s === '') return valid(null);\n if (labels?.trueLabel !== undefined && s === labels.trueLabel.trim().toLowerCase()) return valid(true);\n if (labels?.falseLabel !== undefined && s === labels.falseLabel.trim().toLowerCase()) return valid(false);\n if (TRUE_WORDS.has(s)) return valid(true);\n if (FALSE_WORDS.has(s)) return valid(false);\n return INVALID;\n}\n\ntype ValueOption = NonNullable<GridColDef['valueOptions']>[number];\n\n/**\n * A `singleSelect` value: the option whose value or label matches the text, case-insensitive (values\n * first). Returns the option's own value, so a numeric option stays a number. Empty text is `null`.\n */\nexport function parseSingleSelectText(text: string, options: readonly ValueOption[] | undefined): GridParsedValue {\n const s = text.trim();\n if (s === '') return valid(null);\n if (!options || options.length === 0) return INVALID;\n const lower = s.toLowerCase();\n for (const option of options) {\n const value = typeof option === 'object' ? option.value : option;\n if (String(value).toLowerCase() === lower) return valid(value);\n }\n for (const option of options) {\n if (typeof option === 'object' && option.label.toLowerCase() === lower) return valid(option.value);\n }\n return INVALID;\n}\n\ntype ParserColumn = Pick<GridColDef, 'type' | 'valueOptions'>;\n\nexport interface GridParseTextOptions {\n /** The value the cell holds now: a parsed date takes its kind (see `parseDateText`). */\n current?: unknown;\n /** Extra boolean labels, besides `Yes` / `No`. */\n booleanLabels?: GridBooleanLabels;\n}\n\n/**\n * Parses cell text by the column `type`, without `valueParser`:\n *\n * | type | accepted |\n * | :--- | :--- |\n * | `string` (default), `image` | the text as is (an empty cell is `''`) |\n * | `number` | `parseNumberText` |\n * | `date` | `parseDateText` |\n * | `boolean` | `parseBooleanText` |\n * | `singleSelect` | `parseSingleSelectText` |\n *\n * An empty cell is `null` for every type but `string` / `image`.\n */\nexport function parseValueByType(text: string, colDef: ParserColumn | undefined, options?: GridParseTextOptions): GridParsedValue {\n switch (colDef?.type) {\n case 'number': return parseNumberText(text);\n case 'date': return parseDateText(text, options?.current);\n case 'boolean': return parseBooleanText(text, options?.booleanLabels);\n case 'singleSelect': return parseSingleSelectText(text, colDef.valueOptions);\n default: return valid(text);\n }\n}\n\n/**\n * Parses the text pasted into one cell: the column's `valueParser` when it has one (a throw, or a\n * returned `undefined`, rejects the text), otherwise `parseValueByType`.\n */\nexport function parseCellText<R extends GridValidRowModel>(\n text: string,\n colDef: GridColDef<R>,\n row: R,\n options?: GridParseTextOptions,\n): GridParsedValue {\n const { valueParser } = colDef;\n if (!valueParser) return parseValueByType(text, colDef as unknown as ParserColumn, options);\n let value: unknown;\n try {\n value = valueParser(text, { row, field: colDef.field, colDef });\n } catch {\n return INVALID;\n }\n return value === undefined ? INVALID : valid(value);\n}\n","// Value coercion for the AI validator. Text goes through the same parsers as clipboard paste\n// (`lib/utils/parsing.ts`), so a value the grid accepts from Excel is accepted from a model and the\n// other way round. Model output is JSON, so typed values (a number, a boolean, a Date) are taken as\n// they are. Empty input is valid: null, or '' for text columns.\nimport {\n parseBooleanText,\n parseDateText,\n parseNumberText,\n parseSingleSelectText,\n type GridParsedValue,\n} from '../utils/parsing';\n\nexport type CoerceResult<T = unknown> = { ok: true; value: T } | { ok: false; reason: 'invalidValue' };\n\n/** The column properties coercion reads. */\nexport interface CoerceColumn {\n type?: string;\n valueOptions?: readonly (string | number | { value: unknown; label: string })[];\n}\n\nconst ok = <T>(value: T): CoerceResult<T> => ({ ok: true, value });\nconst INVALID: CoerceResult<never> = { ok: false, reason: 'invalidValue' };\n\nconst fromParsed = <T>(parsed: GridParsedValue): CoerceResult<T> =>\n parsed.ok ? ok(parsed.value as T) : INVALID;\n\nfunction isBlank(text: unknown): boolean {\n return text == null || (typeof text === 'string' && text.trim() === '');\n}\n\n/** `string` and `image` columns: text as is. Numbers and booleans become their text. */\nexport function coerceString(text: unknown): CoerceResult<string> {\n if (text == null) return ok('');\n if (typeof text === 'string') return ok(text);\n if (typeof text === 'number' || typeof text === 'boolean') return ok(String(text));\n return INVALID;\n}\n\n/** `number` columns: a finite number, or text in the paste format (`1,234.5`, `12%`, `$40`). */\nexport function coerceNumber(text: unknown): CoerceResult<number | null> {\n if (isBlank(text)) return ok(null);\n if (typeof text === 'number') return Number.isFinite(text) ? ok(text) : INVALID;\n if (typeof text !== 'string') return INVALID;\n return fromParsed(parseNumberText(text));\n}\n\n/** `date` columns: a Date, epoch milliseconds, or text in the paste format (ISO `2026-10-07` …). */\nexport function coerceDate(text: unknown): CoerceResult<Date | null> {\n if (isBlank(text)) return ok(null);\n if (text instanceof Date) return Number.isNaN(text.getTime()) ? INVALID : ok(text);\n if (typeof text === 'number') return Number.isFinite(text) ? ok(new Date(text)) : INVALID;\n if (typeof text !== 'string') return INVALID;\n return fromParsed(parseDateText(text));\n}\n\n/** `boolean` columns: a boolean, or `true`/`false`, `yes`/`no`, `1`/`0` (case-insensitive). */\nexport function coerceBoolean(text: unknown): CoerceResult<boolean | null> {\n if (isBlank(text)) return ok(null);\n if (typeof text === 'boolean') return ok(text);\n if (typeof text !== 'string' && typeof text !== 'number') return INVALID;\n return fromParsed(parseBooleanText(String(text)));\n}\n\n/**\n * `singleSelect` columns: an option value or label, case-insensitive; returns the option's value.\n * Without `valueOptions` the model has nothing to choose from, so any scalar is kept as it is.\n */\nexport function coerceSingleSelect(text: unknown, colDef: CoerceColumn): CoerceResult<unknown> {\n if (isBlank(text)) return ok(null);\n if (typeof text !== 'string' && typeof text !== 'number' && typeof text !== 'boolean') return INVALID;\n const options = colDef.valueOptions;\n if (!options || options.length === 0) return ok(text);\n return fromParsed(parseSingleSelectText(String(text), options));\n}\n\n/** Coerces `text` for the column's `type`. */\nexport function coerceValue(text: unknown, colDef: CoerceColumn): CoerceResult<unknown> {\n switch (colDef.type) {\n case 'number':\n return coerceNumber(text);\n case 'date':\n return coerceDate(text);\n case 'boolean':\n return coerceBoolean(text);\n case 'singleSelect':\n return coerceSingleSelect(text, colDef);\n default:\n return coerceString(text);\n }\n}\n","// validateGridAiState: the safety layer between a model's reply and the grid. Anything the columns\n// do not allow is dropped with an error; values are coerced to the column type. Never throws.\n// Only own keys of the input are read (never `__proto__`), and every key written to the output is a\n// column field, so nothing in the reply can reach Object.prototype or the output's prototype.\nimport type {\n GridAggregationModel,\n GridColumnVisibilityModel,\n GridFilterGroup,\n GridFilterItem,\n GridFilterModel,\n GridFilterOperator,\n GridPivotModel,\n GridPivotValueField,\n GridSortItem,\n} from '../types';\nimport { toLocalDateString } from '../utils/values';\nimport { brandGridAiValidated } from '../utils/aiBrand';\nimport { coerceBoolean, coerceValue } from './coerce';\nimport {\n ALL_PARTS,\n MAX_FILTER_DEPTH,\n NO_VALUE_OPS,\n PART_KEYS,\n PIVOT_FNS,\n aggregationFnsOf,\n hasOwn,\n isFilterable,\n isGroupable,\n isHideable,\n isPlainObject,\n isSortable,\n operatorsOf,\n selectedParts,\n usableColumns,\n} from './columns';\nimport type { GridAiColumn, GridAiPart, GridAiState, GridAiValidateOptions, GridAiValidationError, GridAiValidationResult } from './types';\n\n/** Longest list read from the model output; the rest is dropped with one error. */\nconst MAX_LIST = 200;\n/** Errors past this many are not listed, so a reply full of junk still gives a readable list. */\nconst MAX_ERRORS = 100;\n\ntype Allowed = (col: GridAiColumn) => boolean;\ntype FilterNode = GridFilterItem | GridFilterGroup;\n\ninterface Ctx {\n errors: GridAiValidationError[];\n byField: Map<string, GridAiColumn>;\n}\n\nfunction fail(ctx: Ctx, path: string, message: string): null {\n if (ctx.errors.length < MAX_ERRORS) ctx.errors.push({ path, message });\n return null;\n}\n\n/** A short, safe rendering of a value for an error message. */\nfunction show(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.slice(0, 60));\n return value === null || typeof value !== 'object' ? String(value) : Array.isArray(value) ? 'a list' : 'an object';\n}\n\nfunction lower(value: unknown): string | null {\n return typeof value === 'string' ? value.trim().toLowerCase() : null;\n}\n\n/** Own enumerable keys of the input, without `__proto__`. */\nfunction keysOf(obj: Record<string, unknown>): string[] {\n return Object.keys(obj).filter((key) => key !== '__proto__');\n}\n\nfunction column(ctx: Ctx, value: unknown, path: string, allowed: Allowed, what: string): GridAiColumn | null {\n const col = typeof value === 'string' ? ctx.byField.get(value) : undefined;\n if (!col) return fail(ctx, path, `Unknown field ${show(value)}`);\n return allowed(col) ? col : fail(ctx, path, `Field ${show(value)} cannot be ${what}`);\n}\n\n/** The first MAX_LIST entries of an array; a single value is read as a one-entry list. */\nfunction list(ctx: Ctx, value: unknown, path: string): unknown[] {\n if (value == null) return [];\n const items = Array.isArray(value) ? value : [value];\n if (items.length > MAX_LIST) fail(ctx, path, `Only the first ${MAX_LIST} entries are read`);\n return items.slice(0, MAX_LIST);\n}\n\n/** The choice `value` names, case-insensitively, in the choice's own spelling. */\nfunction oneOf(ctx: Ctx, value: unknown, path: string, choices: readonly string[]): string | null {\n const v = lower(value);\n return choices.find((c) => c.toLowerCase() === v) ?? fail(ctx, path, `${show(value)} is not one of ${choices.join(', ')}`);\n}\n\n/** One filter value, coerced; dates become `YYYY-MM-DD` as the filter panel writes them. */\nfunction filterValue(ctx: Ctx, raw: unknown, col: GridAiColumn, path: string): { v: unknown } | null {\n const result = coerceValue(raw, col);\n if (!result.ok) return fail(ctx, path, `${show(raw)} is not a valid ${col.type ?? 'string'} value`);\n const v = result.value instanceof Date ? toLocalDateString(result.value) : result.value;\n return v == null || v === '' ? fail(ctx, path, 'Missing value') : { v };\n}\n\nfunction filterItem(ctx: Ctx, raw: Record<string, unknown>, path: string): GridFilterItem | null {\n const col = column(ctx, raw.field, `${path}.field`, isFilterable, 'filtered');\n if (!col) return null;\n const operator = oneOf(ctx, raw.operator, `${path}.operator`, operatorsOf(col));\n if (operator === null) return null;\n const item: GridFilterItem = { field: col.field, operator: operator as GridFilterOperator };\n if (NO_VALUE_OPS.includes(item.operator)) return item;\n const rawValue = hasOwn(raw, 'value') ? raw.value : undefined;\n if (item.operator === 'isAnyOf') {\n const values: unknown[] = [];\n list(ctx, rawValue, `${path}.value`).forEach((entry, i) => {\n const r = filterValue(ctx, entry, col, `${path}.value[${i}]`);\n if (r && !values.includes(r.v)) values.push(r.v);\n });\n if (values.length === 0) return fail(ctx, `${path}.value`, 'No valid values');\n item.value = values;\n return item;\n }\n if (Array.isArray(rawValue)) return fail(ctx, `${path}.value`, 'Expected one value, not a list');\n const r = filterValue(ctx, rawValue, col, `${path}.value`);\n if (!r) return null;\n item.value = r.v;\n return item;\n}\n\nfunction logic(ctx: Ctx, raw: unknown, path: string): 'and' | 'or' | null {\n return raw === undefined ? null : (oneOf(ctx, raw, path, ['and', 'or']) as 'and' | 'or' | null);\n}\n\nfunction filterItems(ctx: Ctx, raw: unknown, path: string, depth: number): FilterNode[] {\n const out: FilterNode[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const at = `${path}[${i}]`;\n if (!isPlainObject(entry)) {\n fail(ctx, at, `Expected a filter, got ${show(entry)}`);\n } else if (hasOwn(entry, 'items') || hasOwn(entry, 'logicOperator')) {\n if (depth >= MAX_FILTER_DEPTH) {\n fail(ctx, at, `Groups nest at most ${MAX_FILTER_DEPTH} levels`);\n return;\n }\n const items = filterItems(ctx, entry.items, `${at}.items`, depth + 1);\n if (items.length === 0) fail(ctx, at, 'Empty group removed');\n else out.push({ logicOperator: logic(ctx, entry.logicOperator, `${at}.logicOperator`) ?? 'and', items });\n } else {\n const item = filterItem(ctx, entry, at);\n if (item) out.push(item);\n }\n });\n return out;\n}\n\nfunction filterModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridFilterModel {\n const model: GridFilterModel = {};\n if (hasOwn(raw, 'items')) model.items = filterItems(ctx, raw.items, `${path}.items`, 0);\n const op = logic(ctx, raw.logicOperator, `${path}.logicOperator`);\n if (op) model.logicOperator = op;\n if (hasOwn(raw, 'quickFilterValues')) {\n model.quickFilterValues = [];\n list(ctx, raw.quickFilterValues, `${path}.quickFilterValues`).forEach((entry, i) => {\n const word = typeof entry === 'string' || typeof entry === 'number' ? String(entry).trim() : null;\n if (word === null) fail(ctx, `${path}.quickFilterValues[${i}]`, `Expected text, got ${show(entry)}`);\n else if (word !== '') model.quickFilterValues?.push(word);\n });\n }\n return model;\n}\n\nfunction sortModel(ctx: Ctx, raw: unknown, path: string): GridSortItem[] {\n const out: GridSortItem[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const at = `${path}[${i}]`;\n if (!isPlainObject(entry)) return fail(ctx, at, `Expected { field, sort }, got ${show(entry)}`);\n const col = column(ctx, entry.field, `${at}.field`, isSortable, 'sorted');\n const sort = col && oneOf(ctx, entry.sort, `${at}.sort`, ['asc', 'desc']);\n if (!col || !sort) return;\n if (out.some((s) => s.field === col.field)) fail(ctx, at, `${show(col.field)} is sorted twice`);\n else out.push({ field: col.field, sort: sort as 'asc' | 'desc' });\n });\n return out;\n}\n\nfunction fieldList(ctx: Ctx, raw: unknown, path: string, allowed: Allowed, what: string): string[] {\n const out: string[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const col = column(ctx, entry, `${path}[${i}]`, allowed, what);\n if (col && !out.includes(col.field)) out.push(col.field);\n });\n return out;\n}\n\nconst canAggregate: Allowed = (col) => aggregationFnsOf(col).length > 0;\nconst canPivot: Allowed = (col) => aggregationFnsOf(col, PIVOT_FNS).length > 0;\n\nfunction aggregationModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridAggregationModel {\n const model: GridAggregationModel = {};\n for (const key of keysOf(raw)) {\n // 'none' is how the grid spells \"no aggregation\": nothing to set.\n if (lower(raw[key]) === 'none') continue;\n const col = column(ctx, key, `${path}.${key}`, canAggregate, 'aggregated');\n const fn = col && oneOf(ctx, raw[key], `${path}.${key}`, aggregationFnsOf(col));\n if (col && fn) model[col.field] = fn;\n }\n return model;\n}\n\nfunction pivotModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridPivotModel {\n const valueFields: GridPivotValueField[] = [];\n list(ctx, raw.valueFields, `${path}.valueFields`).forEach((entry, i) => {\n const at = `${path}.valueFields[${i}]`;\n if (!isPlainObject(entry)) return fail(ctx, at, `Expected { field, aggFn }, got ${show(entry)}`);\n const col = column(ctx, entry.field, `${at}.field`, canPivot, 'a pivot value');\n const aggFn = col && (oneOf(ctx, entry.aggFn, `${at}.aggFn`, aggregationFnsOf(col, PIVOT_FNS)) as GridPivotValueField['aggFn'] | null);\n if (col && aggFn && !valueFields.some((v) => v.field === col.field && v.aggFn === aggFn)) valueFields.push({ field: col.field, aggFn });\n });\n return {\n rowFields: fieldList(ctx, raw.rowFields, `${path}.rowFields`, isGroupable, 'a pivot label'),\n columnFields: fieldList(ctx, raw.columnFields, `${path}.columnFields`, isGroupable, 'a pivot label'),\n valueFields,\n };\n}\n\nfunction visibilityModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridColumnVisibilityModel {\n const model: GridColumnVisibilityModel = {};\n for (const key of keysOf(raw)) {\n const col = column(ctx, key, `${path}.${key}`, isHideable, 'hidden');\n const visible = coerceBoolean(raw[key]);\n if (!col) continue;\n if (visible.ok && visible.value !== null) model[col.field] = visible.value;\n else fail(ctx, `${path}.${key}`, `Expected true or false, got ${show(raw[key])}`);\n }\n return model;\n}\n\nfunction readPart(ctx: Ctx, part: GridAiPart, raw: unknown, path: string, state: GridAiState): void {\n if (part === 'sort') state.sortModel = sortModel(ctx, raw, path);\n else if (part === 'grouping') state.rowGroupingModel = fieldList(ctx, raw, path, isGroupable, 'grouped');\n else if (!isPlainObject(raw)) fail(ctx, path, `Expected an object, got ${show(raw)}`);\n else if (part === 'filter') state.filterModel = filterModel(ctx, raw, path);\n else if (part === 'aggregation') state.aggregationModel = aggregationModel(ctx, raw, path);\n else if (part === 'pivot') state.pivotModel = pivotModel(ctx, raw, path);\n else state.columnVisibilityModel = visibilityModel(ctx, raw, path);\n}\n\n/**\n * Checks a model's reply against the columns and returns the state that is safe to apply.\n * `json` is an object or a JSON string (bad JSON gives one error and an empty state). A top-level\n * string `message` (the model's reply text) is skipped, not reported. Unknown parts, fields, operators and enum values are dropped, each with an error; values are coerced to\n * the column type (`\"1,200\"` → 1200, a date → `\"YYYY-MM-DD\"`); filter groups left empty are\n * removed. Never throws, and never returns a field the columns do not allow.\n *\n * The result and its `state` carry the brand `Symbol.for('opengridx.ai.validated')` (not enumerable):\n * the grid's `aiAssistant` applies only a branded state. Spreading the result keeps `state` branded.\n * @since v3.4\n */\nexport function validateGridAiState<C extends GridAiColumn>(\n json: unknown,\n columns: readonly C[],\n options: GridAiValidateOptions = {},\n): GridAiValidationResult {\n const result = validate(json, columns, options);\n brandGridAiValidated(result.state);\n return brandGridAiValidated(result);\n}\n\nfunction validate(json: unknown, columns: readonly GridAiColumn[], options: GridAiValidateOptions): GridAiValidationResult {\n const ctx: Ctx = { errors: [], byField: new Map() };\n const state: GridAiState = {};\n try {\n for (const col of usableColumns(columns)) ctx.byField.set(col.field, col);\n let input = json;\n if (typeof json === 'string') {\n try {\n input = JSON.parse(json) as unknown;\n } catch {\n fail(ctx, '', 'Not valid JSON');\n return { state, errors: ctx.errors };\n }\n }\n if (!isPlainObject(input)) {\n fail(ctx, '', `Expected an object, got ${show(input)}`);\n return { state, errors: ctx.errors };\n }\n const allowed = selectedParts(options);\n for (const key of keysOf(input)) {\n const part = ALL_PARTS.find((p) => PART_KEYS[p] === key);\n if (key === 'schemaVersion') {\n if (input[key] !== 1) fail(ctx, key, `Unsupported schemaVersion ${show(input[key])}`);\n } else if (key === 'message') {\n // The model's reply text next to the state (createGridAiPromptHandler shows it): not state.\n if (typeof input[key] !== 'string') fail(ctx, key, `Expected text, got ${show(input[key])}`);\n } else if (!part) fail(ctx, key, 'Unknown part');\n else if (!allowed.includes(part)) fail(ctx, key, 'Part not allowed');\n else readPart(ctx, part, input[key], key, state);\n }\n } catch {\n // Defensive only: a getter on a hand-built input object could throw.\n fail(ctx, '', 'Could not read the input');\n return { state: {}, errors: ctx.errors };\n }\n return { state, errors: ctx.errors };\n}\n","// createGridAiPromptHandler: the `aiAssistant.onPrompt` function for an app's own model. It builds the\n// schema once, calls the app's `callModel`, reads the reply (an object, JSON text, or text with a fenced\n// JSON block) and returns the validated, branded result. The grid never sees the raw reply.\nimport type { GridAiPromptContext, GridAiPromptResult } from '../types';\nimport { brandGridAiValidated } from '../utils/aiBrand';\nimport { hasOwn, isPlainObject } from './columns';\nimport { getGridAiSchema } from './schema';\nimport type { GridAiColumn, GridAiPartOptions, GridAiPromptHandlerOptions, GridAiValidationError } from './types';\nimport { validateGridAiState } from './validate';\n\nconst FENCE = '```';\n\n/** A DOMException named `AbortError`, as `fetch` rejects with. */\nexport function abortError(): Error {\n return typeof DOMException === 'function'\n ? new DOMException('The operation was aborted.', 'AbortError')\n : Object.assign(new Error('The operation was aborted.'), { name: 'AbortError' });\n}\n\n/**\n * Splits a text reply into the JSON it holds and the text around it: the whole text when it starts\n * with `{`, else the first fenced block (with no language or `json`). A plain loop, no regex.\n */\nexport function readModelText(text: string): { json: string | null; message: string } {\n const trimmed = text.trim();\n if (trimmed.startsWith('{')) return { json: trimmed, message: '' };\n const open = text.indexOf(FENCE);\n const lineEnd = open < 0 ? -1 : text.indexOf('\\n', open + FENCE.length);\n const close = lineEnd < 0 ? -1 : text.indexOf(FENCE, lineEnd + 1);\n const lang = close < 0 ? '' : text.slice(open + FENCE.length, lineEnd).trim().toLowerCase();\n if (close < 0 || (lang !== '' && lang !== 'json')) return { json: null, message: trimmed };\n return {\n json: text.slice(lineEnd + 1, close),\n message: `${text.slice(0, open)}${text.slice(close + FENCE.length)}`.trim(),\n };\n}\n\nfunction errorText(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n return typeof error === 'string' && error ? error : 'Unknown error';\n}\n\n/** A branded result with an empty state: nothing to apply, the errors explain why. */\nfunction emptyResult(errors: GridAiValidationError[], message?: string): GridAiPromptResult {\n const result: GridAiPromptResult = { state: brandGridAiValidated({}), errors };\n if (message) result.message = message;\n return brandGridAiValidated(result);\n}\n\n/** Validates a model reply into a branded result. Never throws. */\nexport function readModelReply(reply: unknown, columns: readonly GridAiColumn[], parts: GridAiPartOptions): GridAiPromptResult {\n let json: unknown = reply;\n let around = '';\n if (typeof reply === 'string') {\n const text = readModelText(reply);\n if (text.json === null) return emptyResult([], text.message || undefined);\n around = text.message;\n // Parsed here so a `message` key inside the JSON is read as for an object reply. Bad JSON is\n // passed on as text: validateGridAiState reports it.\n try {\n json = JSON.parse(text.json) as unknown;\n } catch {\n json = text.json;\n }\n }\n // A reply such as { filterModel, message: 'Showing paid orders' }: the validator skips the message.\n const inner = isPlainObject(json) && hasOwn(json, 'message') && typeof json.message === 'string' ? json.message.trim() : '';\n const message = [around, inner].filter(Boolean).join('\\n\\n');\n const result: GridAiPromptResult = validateGridAiState(json, columns, parts);\n if (message) result.message = message;\n return result;\n}\n\n/**\n * Builds `aiAssistant.onPrompt` for your own model. On each prompt it calls\n * `callModel({ prompt, schema, currentState, history }, { signal })`, reads the reply (a state object,\n * a JSON string, or a fenced JSON block inside text), validates it with `validateGridAiState` and\n * returns the branded result. A `callModel` throw or rejection becomes\n * `{ state: {}, errors: [{ path: '', message }] }`; an abort rejects with an `AbortError`.\n * @since v3.5\n */\nexport function createGridAiPromptHandler<C extends GridAiColumn>(\n options: GridAiPromptHandlerOptions<C>,\n): (prompt: string, context: GridAiPromptContext) => Promise<GridAiPromptResult> {\n const { columns, callModel, parts, schemaOptions = {} } = options;\n const partOptions: GridAiPartOptions = { include: parts ?? schemaOptions.include, exclude: schemaOptions.exclude };\n const schema = getGridAiSchema(columns, { ...schemaOptions, ...partOptions });\n\n return async (prompt, context) => {\n const signal = context?.signal ?? new AbortController().signal;\n if (signal.aborted) throw abortError();\n // Stop resolves the prompt at once, even when callModel ignores the signal.\n const aborted = new Promise<never>((_, reject) => {\n signal.addEventListener('abort', () => reject(abortError()), { once: true });\n });\n aborted.catch(() => undefined);\n let reply: unknown;\n try {\n const request = {\n prompt: String(prompt),\n schema,\n currentState: context?.currentState ?? {},\n history: Array.isArray(context?.history) ? context.history : [],\n };\n reply = await Promise.race([callModel(request, { signal }), aborted]);\n } catch (error) {\n if (signal.aborted) throw abortError();\n return emptyResult([{ path: '', message: `The model call failed: ${errorText(error)}` }]);\n }\n if (signal.aborted) throw abortError();\n return readModelReply(reply, columns, partOptions);\n };\n}\n","// createGridAgentTools: plain tool objects ({ name, description, inputSchema, execute }) that let an AI\n// agent read and change the grid through its apiRef. No SDK: they fit the Vercel AI SDK, CopilotKit,\n// OpenAI or Anthropic tool calling and WebMCP. Every input is validated; execute never throws.\nimport type { GridAiState, GridRowModel } from '../types';\nimport { getCellValue } from '../utils/values';\n\ntype CellColumn = Parameters<typeof getCellValue>[2];\nimport { hasOwn, isPlainObject, PART_KEYS, usableColumns } from './columns';\nimport { getGridAiSchema } from './schema';\nimport type {\n GridAgentApi,\n GridAgentTool,\n GridAgentToolResult,\n GridAgentToolsOptions,\n GridAiColumn,\n GridAiJsonSchema,\n GridAiPart,\n} from './types';\nimport { validateGridAiState } from './validate';\n\nconst DEFAULT_MAX_ROWS = 20;\nconst MAX_ROWS_LIMIT = 1000;\n\nconst SET_TOOLS: { name: string; part: GridAiPart; description: string }[] = [\n { name: 'set_filter', part: 'filter', description: 'Replace the filter model of the grid (filters and quick-filter words).' },\n { name: 'set_sort', part: 'sort', description: 'Replace the sort model of the grid, most significant field first. An empty list clears sorting.' },\n { name: 'set_grouping', part: 'grouping', description: 'Group the rows by these fields, outermost first. An empty list removes grouping.' },\n { name: 'set_aggregation', part: 'aggregation', description: 'Replace the summaries: field to aggregation function. An empty object removes them.' },\n { name: 'set_column_visibility', part: 'columnVisibility', description: 'Show (true) or hide (false) columns. Columns not listed keep their visibility.' },\n];\n\ntype ApiRef = { readonly current: GridAgentApi | null | undefined };\n\nfunction failure(message: string, path = ''): GridAgentToolResult {\n return { ok: false, errors: [{ path, message }] };\n}\n\n/** Runs a tool body; a throw becomes `{ ok: false }`. */\nasync function run(body: () => GridAgentToolResult): Promise<GridAgentToolResult> {\n try {\n return body();\n } catch (error) {\n return failure(error instanceof Error && error.message ? error.message : 'The tool failed');\n }\n}\n\nfunction apiOf(apiRef: ApiRef): GridAgentApi | null {\n const api = apiRef?.current;\n return api && typeof api.getGridAiState === 'function' ? api : null;\n}\n\n/** A JSON-safe cell value: primitives as they are, a Date as an ISO string, anything else null. */\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString();\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n return typeof value === 'string' || typeof value === 'boolean' ? value : null;\n}\n\nfunction setTool(apiRef: ApiRef, columns: readonly GridAiColumn[], name: string, part: GridAiPart, description: string): GridAgentTool | null {\n const key = PART_KEYS[part] as keyof GridAiState;\n const schema = getGridAiSchema(columns, { include: [part] });\n if (!hasOwn(schema.properties, key)) return null;\n const { $schema: _version, schemaVersion: _schemaVersion, title: _title, description: _description, ...inputSchema } = schema;\n return {\n name,\n description,\n inputSchema: { ...inputSchema, required: [key] },\n execute: (input) => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n if (!isPlainObject(input) || !hasOwn(input, key)) return failure(`Expected an object with \"${key}\"`, key);\n const { state, errors } = validateGridAiState({ [key]: input[key] }, columns, { include: [part] });\n // All or nothing: the agent gets the errors back and can correct its call.\n if (errors.length > 0) return { ok: false, errors };\n const applied: GridAiState = {};\n if (state.filterModel) api.setFilterModel(applied.filterModel = state.filterModel);\n if (state.sortModel) api.setSortModel(applied.sortModel = state.sortModel);\n if (state.rowGroupingModel) api.setRowGroupingModel(applied.rowGroupingModel = state.rowGroupingModel);\n if (state.aggregationModel) api.setAggregationModel(applied.aggregationModel = state.aggregationModel);\n if (state.columnVisibilityModel) {\n applied.columnVisibilityModel = { ...api.getGridAiState().columnVisibilityModel, ...state.columnVisibilityModel };\n api.setColumnVisibilityModel(applied.columnVisibilityModel);\n }\n return { ok: true, applied };\n }),\n };\n}\n\nconst NO_INPUT: GridAiJsonSchema = { type: 'object', properties: {}, additionalProperties: false };\n\n/**\n * Tools for an AI agent: `get_grid_state`, `set_filter`, `set_sort`, `set_grouping`, `set_aggregation`,\n * `set_column_visibility`, `clear_filters`, and `get_row_summary` only with `allowRowAccess: true` (the\n * one tool that sends row values). Each tool is `{ name, description, inputSchema, execute }`; inputs are\n * checked with `validateGridAiState` and applied through `apiRef` only when valid. `execute` never throws.\n * @since v3.5\n */\nexport function createGridAgentTools<C extends GridAiColumn>(\n apiRef: ApiRef,\n columns: readonly C[],\n options: GridAgentToolsOptions = {},\n): GridAgentTool[] {\n const cols = usableColumns(columns);\n const tools: GridAgentTool[] = [{\n name: 'get_grid_state',\n description: 'Read the current filter, sort, grouping, aggregation, pivot and column visibility of the grid, and its columns.',\n inputSchema: NO_INPUT,\n execute: () => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n return {\n ok: true,\n state: api.getGridAiState(),\n columns: cols.map((c) => ({ field: c.field, headerName: typeof c.headerName === 'string' ? c.headerName : c.field, type: typeof c.type === 'string' ? c.type : 'string' })),\n };\n }),\n }];\n for (const { name, part, description } of SET_TOOLS) {\n const tool = setTool(apiRef, cols, name, part, description);\n if (tool) tools.push(tool);\n }\n tools.push({\n name: 'clear_filters',\n description: 'Remove every filter and the quick-filter words.',\n inputSchema: NO_INPUT,\n execute: () => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n const filterModel = { items: [] };\n api.setFilterModel(filterModel);\n return { ok: true, applied: { filterModel } };\n }),\n });\n if (options.allowRowAccess === true) {\n const maxRows = typeof options.maxRows === 'number' && options.maxRows >= 1 ? Math.min(Math.floor(options.maxRows), MAX_ROWS_LIMIT) : DEFAULT_MAX_ROWS;\n const allowed = Array.isArray(options.fields) ? cols.filter((c) => options.fields?.includes(c.field)) : cols;\n tools.push({\n name: 'get_row_summary',\n description: `Count the rows that pass the current filter and read the first ones (at most ${maxRows}, fields: ${allowed.map((c) => c.field).join(', ')}).`,\n inputSchema: { type: 'object', properties: { limit: { type: 'integer', minimum: 1, maximum: maxRows } }, additionalProperties: false },\n execute: (input) => run(() => {\n const api = apiOf(apiRef);\n if (!api) return failure('The grid is not ready');\n const raw = isPlainObject(input) && hasOwn(input, 'limit') ? input.limit : maxRows;\n const limit = typeof raw === 'number' && raw >= 1 ? Math.min(Math.floor(raw), maxRows) : maxRows;\n const all = api.getAllFilteredRows();\n const list = Array.isArray(all) ? all : [];\n const rows = list.slice(0, limit).map((row) => {\n const out: Record<string, unknown> = {};\n if (!isPlainObject(row)) return out;\n // Through the column's valueGetter, as the grid shows the cell.\n for (const col of allowed) out[col.field] = jsonValue(getCellValue(row as GridRowModel, col.field, col as CellColumn));\n return out;\n });\n return { ok: true, rowCount: list.length, rows };\n }),\n });\n }\n return tools;\n}\n"],"names":["warnedCallbacks","warnCallbackFailure","key","message","error","tryGetCellValue","row","field","colDef","raw","getCellValue","value","DATE_ONLY","toDate","date","trimmed","match","year","month","day","hasOnlyDateWords","DATE_WORDS","DATE_TOKENS","isDateWord","word","name","text","i","ch","toLocalDateString","y","m","d","getOperatorsForType","type","AGGREGATION_FNS","PIVOT_FNS","NO_VALUE_OPS","MAX_FILTER_DEPTH","ALL_PARTS","PART_KEYS","hasOwn","obj","isPlainObject","selectedParts","options","include","exclude","part","usableColumns","columns","seen","out","col","operatorsOf","isFilterable","isSortable","isGroupable","isHideable","aggregationFnsOf","fns","base","fn","allowed","optionValues","option","GRID_AI_SCHEMA_TITLE","MAX_EXAMPLES","label","header","desc","describe","node","ctx","examplesOf","v","valueSchema","values","one","examples","filterItemSchema","operators","noValue","op","hint","ops","filterSchema","cols","defs","filterable","properties","logic","depth","child","fieldEnum","c","partSchema","sortable","groupable","dims","dimArray","getGridAiSchema","schema","GRID_AI_VALIDATED_BRAND","brandGridAiValidated","INVALID","valid","PLAIN_NUMBER","LEADING_DOT_NUMBER","GROUPED_NUMBER","STRIPPED_CHARS","parseNumberText","s","negative","percent","parseDateText","current","TRUE_WORDS","FALSE_WORDS","parseBooleanText","labels","parseSingleSelectText","lower","ok","fromParsed","parsed","isBlank","coerceString","coerceNumber","coerceDate","coerceBoolean","coerceSingleSelect","coerceValue","MAX_LIST","MAX_ERRORS","fail","path","show","keysOf","column","what","list","items","oneOf","choices","filterValue","result","filterItem","operator","item","rawValue","entry","r","filterItems","at","filterModel","model","sortModel","sort","fieldList","canAggregate","canPivot","aggregationModel","pivotModel","valueFields","aggFn","visibilityModel","visible","readPart","state","validateGridAiState","json","validate","input","p","FENCE","abortError","readModelText","open","lineEnd","close","lang","errorText","emptyResult","errors","readModelReply","reply","parts","around","inner","createGridAiPromptHandler","callModel","schemaOptions","partOptions","prompt","context","signal","aborted","_","reject","request","DEFAULT_MAX_ROWS","MAX_ROWS_LIMIT","SET_TOOLS","failure","run","body","apiOf","apiRef","api","jsonValue","setTool","description","_version","_schemaVersion","_title","_description","inputSchema","applied","NO_INPUT","createGridAgentTools","tools","tool","maxRows","limit","all","rows"],"mappings":"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"}
|