@skygraph/core 0.5.3 → 0.6.6
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/README.md +48 -48
- package/dist/calendar.cjs.map +1 -1
- package/dist/calendar.js +1 -1
- package/dist/{chunk-7FA2TBSZ.js → chunk-3DDKJILC.js} +1 -1
- package/dist/chunk-3DDKJILC.js.map +1 -0
- package/dist/{chunk-GEMALROQ.js → chunk-75BQUWZC.js} +1 -1
- package/dist/chunk-75BQUWZC.js.map +1 -0
- package/dist/{chunk-ZWB7JGAJ.js → chunk-CEX4ZVZF.js} +1 -1
- package/dist/chunk-CEX4ZVZF.js.map +1 -0
- package/dist/{chunk-AB3RLBLW.js → chunk-MEZUJRC7.js} +1 -1
- package/dist/chunk-MEZUJRC7.js.map +1 -0
- package/dist/{chunk-Y7FTBBYX.js → chunk-QYUKEEBL.js} +1 -1
- package/dist/chunk-QYUKEEBL.js.map +1 -0
- package/dist/{chunk-IY6LJU3L.js → chunk-SUGXXNZK.js} +1 -1
- package/dist/chunk-SUGXXNZK.js.map +1 -0
- package/dist/form.cjs.map +1 -1
- package/dist/graph.cjs.map +1 -1
- package/dist/graph.js +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/runtime-internal.cjs.map +1 -1
- package/dist/runtime-internal.js +1 -1
- package/dist/runtime-internal.js.map +1 -1
- package/dist/table.cjs.map +1 -1
- package/dist/table.js +1 -1
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/virtual.cjs.map +1 -1
- package/dist/virtual.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-7FA2TBSZ.js.map +0 -1
- package/dist/chunk-AB3RLBLW.js.map +0 -1
- package/dist/chunk-GEMALROQ.js.map +0 -1
- package/dist/chunk-IY6LJU3L.js.map +0 -1
- package/dist/chunk-Y7FTBBYX.js.map +0 -1
- package/dist/chunk-ZWB7JGAJ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/table/filter.ts","../src/engines/table/TableEngine.ts"],"sourcesContent":["import type {\r\n AdvancedFilter,\r\n AggregateFn,\r\n AggregateType,\r\n ColumnFilter,\r\n FilterOperator,\r\n} from './types'\r\n\r\n/**\r\n * Возвращает финальный оператор фильтра. Соблюдаем backward-compat:\r\n * если оператор не задан, и `value` — массив, считаем фильтр `in`,\r\n * иначе — `eq`.\r\n */\r\nexport function resolveOperator(\r\n filter: AdvancedFilter | ColumnFilter,\r\n): FilterOperator {\r\n const adv = filter as AdvancedFilter\r\n if (adv.op != null) return adv.op\r\n const col = filter as ColumnFilter\r\n if (col.operator != null) return col.operator\r\n return Array.isArray(filter.value) ? 'in' : 'eq'\r\n}\r\n\r\n/** Проверка пустоты для `isEmpty` / `isNotEmpty`. */\r\nfunction isEmptyValue(val: unknown): boolean {\r\n return val == null || val === ''\r\n}\r\n\r\n/** Числовое сравнение с защитой от NaN. */\r\nfunction asNumberPair(a: unknown, b: unknown): [number, number] | null {\r\n const na = typeof a === 'number' ? a : Number(a)\r\n const nb = typeof b === 'number' ? b : Number(b)\r\n if (Number.isNaN(na) || Number.isNaN(nb)) return null\r\n return [na, nb]\r\n}\r\n\r\n/**\r\n * Проверяет, проходит ли значение `val` фильтр (`op` + `filterValue`).\r\n * Используется как для `ColumnFilter`, так и для `AdvancedFilter`.\r\n */\r\nexport function matchesOperator(\r\n val: unknown,\r\n op: FilterOperator,\r\n filterValue: unknown,\r\n): boolean {\r\n switch (op) {\r\n case 'eq':\r\n return val === filterValue\r\n case 'neq':\r\n return val !== filterValue\r\n\r\n case 'lt':\r\n case 'lte':\r\n case 'gt':\r\n case 'gte': {\r\n const pair = asNumberPair(val, filterValue)\r\n if (!pair) return false\r\n const [a, b] = pair\r\n if (op === 'lt') return a < b\r\n if (op === 'lte') return a <= b\r\n if (op === 'gt') return a > b\r\n return a >= b\r\n }\r\n\r\n case 'between': {\r\n if (!Array.isArray(filterValue) || filterValue.length !== 2) return false\r\n const minPair = asNumberPair(val, filterValue[0])\r\n const maxPair = asNumberPair(val, filterValue[1])\r\n if (!minPair || !maxPair) return false\r\n return minPair[0] >= minPair[1] && maxPair[0] <= maxPair[1]\r\n }\r\n\r\n case 'in':\r\n return Array.isArray(filterValue) && filterValue.includes(val)\r\n case 'notIn':\r\n return Array.isArray(filterValue) && !filterValue.includes(val)\r\n\r\n case 'contains':\r\n if (typeof val !== 'string') return false\r\n return val.toLowerCase().includes(String(filterValue ?? '').toLowerCase())\r\n case 'startsWith':\r\n if (typeof val !== 'string') return false\r\n return val.toLowerCase().startsWith(String(filterValue ?? '').toLowerCase())\r\n case 'endsWith':\r\n if (typeof val !== 'string') return false\r\n return val.toLowerCase().endsWith(String(filterValue ?? '').toLowerCase())\r\n\r\n case 'isEmpty':\r\n return isEmptyValue(val)\r\n case 'isNotEmpty':\r\n return !isEmptyValue(val)\r\n }\r\n}\r\n\r\n/**\r\n * Применяет `ColumnFilter` к строке (по `filter.column`).\r\n * Точка входа из движка таблицы.\r\n */\r\nexport function matchesColumnFilter(\r\n row: Record<string, unknown>,\r\n filter: ColumnFilter,\r\n): boolean {\r\n const op = resolveOperator(filter)\r\n return matchesOperator(row[filter.column], op, filter.value)\r\n}\r\n\r\n/** Считает встроенную агрегацию для массива значений. */\r\nexport function computeAggregate(\r\n values: unknown[],\r\n type: AggregateType | AggregateFn,\r\n): unknown {\r\n if (typeof type === 'function') return type(values)\r\n\r\n if (type === 'count') return values.length\r\n\r\n const nums: number[] = []\r\n for (const v of values) {\r\n if (v == null || v === '') continue\r\n const n = typeof v === 'number' ? v : Number(v)\r\n if (!Number.isNaN(n)) nums.push(n)\r\n }\r\n if (nums.length === 0) return null\r\n\r\n switch (type) {\r\n case 'sum':\r\n return nums.reduce((a, b) => a + b, 0)\r\n case 'avg':\r\n return nums.reduce((a, b) => a + b, 0) / nums.length\r\n case 'min':\r\n return Math.min(...nums)\r\n case 'max':\r\n return Math.max(...nums)\r\n }\r\n}\r\n","import type { Core } from '../../types'\r\nimport type {\r\n AdvancedFilter,\r\n ColumnAggregate,\r\n ColumnFilter,\r\n ExportOptions,\r\n FilterFn,\r\n RowId,\r\n SortConfig,\r\n SortDirection,\r\n TableEngine,\r\n TableGroup,\r\n TableOptions,\r\n TableState,\r\n} from './types'\r\n\r\nimport { TABLE_PREFIX } from '../namespaces'\r\nimport { computeAggregate, matchesColumnFilter } from './filter'\r\n\r\nfunction statePath(tableId: string, key: string): string {\r\n return `${TABLE_PREFIX}${tableId}.state.${key}`\r\n}\r\n\r\nlet tableCounter = 0\r\n\r\n/**\r\n * `createTable` строит TableEngine поверх Core. Пользовательские данные строк\r\n * хранятся в private замыкании (`dataById`/`keysById`), а в Core попадают\r\n * только пути `$table.<id>.state.*` (агрегированные счётчики, ширины колонок,\r\n * пин-конфиг). Это держит `addRows(100k)` на масштабе O(N) Map.set вместо\r\n * O(N × cols) `core.set` (исторический паттерн `byId.<rid>.<col>` создавал\r\n * сотни тысяч узлов в Store и аллокаций Set/Map в `Core.set` на каждую\r\n * cell-запись — см. `docs/_streams/findings/T-Table-Perf.md` H1).\r\n *\r\n * Семантика публичных методов `getRow`/`getCell`/`getVisibleRows` сохранена.\r\n * Внешние подписки на `$table.<id>.state.*` пути продолжают работать;\r\n * подписок на `byId.*` в монорепе нет (они никогда не были задокументированы).\r\n */\r\nexport function createTable(core: Core, options?: TableOptions): TableEngine {\r\n const tableId = `t${tableCounter++}`\r\n let currentPageSize = options?.pageSize ?? 50\r\n\r\n let order: RowId[] = []\r\n let filteredOrder: RowId[] = []\r\n let sorts: SortConfig[] = []\r\n let filters: ColumnFilter[] = []\r\n let customFilterFn: FilterFn | null = null\r\n let page = 1\r\n let pinnedLeft: string[] = []\r\n let pinnedRight: string[] = []\r\n let columnWidths: Record<string, number> = {}\r\n\r\n // Группировка\r\n let groupByField: string | null = null\r\n let columnAggregates: ColumnAggregate[] = []\r\n let groups: TableGroup[] = []\r\n\r\n // Private storage: данные строк живут в замыкании, не в Core store.\r\n // Это устраняет 800k `core.set` per-cell на 100k×7 датасете и убирает\r\n // основной источник аллокаций (Store-узлы + Set/Map в `Core.set`).\r\n const dataById = new Map<RowId, Record<string, unknown>>()\r\n const keysById = new Map<RowId, string[]>()\r\n\r\n function getRowData(id: RowId): Record<string, unknown> | undefined {\r\n const stored = dataById.get(id)\r\n if (!stored) return undefined\r\n\r\n // Если пользователь передал явный whitelist колонок через\r\n // `TableOptions.columns`, отдаём отфильтрованную копию (исторический\r\n // контракт). В типичном кейсе (опция не задана) — возвращаем хранимую\r\n // ссылку без копии: hot path `compareBySort`/`recomputeFiltered`/render\r\n // не должны платить за per-row allocation.\r\n if (options?.columns) {\r\n const filtered: Record<string, unknown> = {}\r\n for (const col of options.columns) {\r\n filtered[col] = stored[col]\r\n }\r\n return filtered\r\n }\r\n return stored\r\n }\r\n\r\n function matchesFilters(rowData: Record<string, unknown>): boolean {\r\n if (customFilterFn && !customFilterFn(rowData)) return false\r\n\r\n for (const f of filters) {\r\n if (!matchesColumnFilter(rowData, f)) return false\r\n }\r\n return true\r\n }\r\n\r\n function compareBySort(a: RowId, b: RowId): number {\r\n const aData = getRowData(a)\r\n const bData = getRowData(b)\r\n\r\n for (const s of sorts) {\r\n const aVal = aData?.[s.column]\r\n const bVal = bData?.[s.column]\r\n\r\n if (aVal === bVal) continue\r\n if (aVal === undefined || aVal === null) return 1\r\n if (bVal === undefined || bVal === null) return -1\r\n\r\n const cmp = aVal < bVal ? -1 : 1\r\n return s.direction === 'asc' ? cmp : -cmp\r\n }\r\n return 0\r\n }\r\n\r\n function recomputeFiltered(): void {\r\n if (filters.length === 0 && !customFilterFn) {\r\n filteredOrder = [...order]\r\n } else {\r\n filteredOrder = order.filter((id) => {\r\n const data = getRowData(id)\r\n return data ? matchesFilters(data) : false\r\n })\r\n }\r\n\r\n if (sorts.length > 0) {\r\n filteredOrder.sort(compareBySort)\r\n }\r\n\r\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\r\n if (page > totalPages) page = totalPages\r\n\r\n recomputeGroups()\r\n publishState()\r\n }\r\n\r\n function recomputeGroups(): void {\r\n if (!groupByField) {\r\n groups = []\r\n return\r\n }\r\n\r\n const map = new Map<string, { value: unknown; rows: RowId[] }>()\r\n const orderKeys: string[] = []\r\n\r\n for (const id of filteredOrder) {\r\n const data = getRowData(id)\r\n if (!data) continue\r\n const raw = data[groupByField]\r\n const key = raw == null ? '__null__' : String(raw)\r\n if (!map.has(key)) {\r\n map.set(key, { value: raw, rows: [] })\r\n orderKeys.push(key)\r\n }\r\n map.get(key)!.rows.push(id)\r\n }\r\n\r\n groups = orderKeys.map((key) => {\r\n const { value, rows } = map.get(key)!\r\n const aggregates: Record<string, unknown> = {}\r\n for (const agg of columnAggregates) {\r\n const values = rows.map((id) => dataById.get(id)?.[agg.column])\r\n aggregates[agg.column] = computeAggregate(values, agg.type)\r\n }\r\n return { key, value, rows, aggregates }\r\n })\r\n }\r\n\r\n function publishState(): void {\r\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\r\n core.set(statePath(tableId, 'totalRows'), order.length)\r\n core.set(statePath(tableId, 'filteredRows'), filteredOrder.length)\r\n core.set(statePath(tableId, 'page'), page)\r\n core.set(statePath(tableId, 'pageSize'), currentPageSize)\r\n core.set(statePath(tableId, 'totalPages'), totalPages)\r\n core.set(statePath(tableId, 'groupBy'), groupByField)\r\n core.set(statePath(tableId, 'groupCount'), groups.length)\r\n }\r\n\r\n function getColumnKeys(): string[] {\r\n if (options?.columns) return options.columns\r\n if (order.length === 0) return []\r\n const firstId = order[0]\r\n return keysById.get(firstId) ?? []\r\n }\r\n\r\n /** Привести `AdvancedFilter | ColumnFilter` к единому `ColumnFilter`. */\r\n function toColumnFilter(column: string, filter: AdvancedFilter | ColumnFilter): ColumnFilter {\r\n const adv = filter as AdvancedFilter\r\n if (adv.op != null) {\r\n return { column, operator: adv.op, value: adv.value }\r\n }\r\n const cf = filter as ColumnFilter\r\n return { column, operator: cf.operator, value: cf.value }\r\n }\r\n\r\n const table: TableEngine = {\r\n addRow(id: RowId, data: Record<string, unknown>): void {\r\n dataById.set(id, data)\r\n keysById.set(id, Object.keys(data))\r\n order.push(id)\r\n recomputeFiltered()\r\n },\r\n\r\n addRows(rows: Array<{ id: RowId; data: Record<string, unknown> }>): void {\r\n // Single Map.set per row instead of (cols + 1) `core.set` per row —\r\n // на 100k×7 это разница 800k vs 100k операций и убирает\r\n // основной источник аллокаций. См. `findings/T-Table-Perf.md` H1.\r\n for (const row of rows) {\r\n dataById.set(row.id, row.data)\r\n keysById.set(row.id, Object.keys(row.data))\r\n order.push(row.id)\r\n }\r\n recomputeFiltered()\r\n },\r\n\r\n removeRow(id: RowId): void {\r\n const idx = order.indexOf(id)\r\n if (idx === -1) return\r\n order.splice(idx, 1)\r\n dataById.delete(id)\r\n keysById.delete(id)\r\n recomputeFiltered()\r\n },\r\n\r\n updateCell(id: RowId, column: string, value: unknown): void {\r\n const row = dataById.get(id)\r\n if (!row) return\r\n // Мутация хранимого объекта. `getRow` отдаёт эту же ссылку (см. контракт\r\n // в JSDoc к `createTable`), `recomputeFiltered` снизу пересоберёт сорт/\r\n // группы как раньше.\r\n row[column] = value\r\n const keys = keysById.get(id)\r\n if (keys && !keys.includes(column)) {\r\n keys.push(column)\r\n }\r\n recomputeFiltered()\r\n },\r\n\r\n getRow(id: RowId): Record<string, unknown> | undefined {\r\n return getRowData(id)\r\n },\r\n\r\n getCell(id: RowId, column: string): unknown {\r\n return dataById.get(id)?.[column]\r\n },\r\n\r\n getVisibleRows(): Array<{ id: RowId; data: Record<string, unknown> }> {\r\n const start = (page - 1) * currentPageSize\r\n const end = start + currentPageSize\r\n const slice = filteredOrder.slice(start, end)\r\n const out = new Array(slice.length) as Array<{\r\n id: RowId\r\n data: Record<string, unknown>\r\n }>\r\n for (let i = 0; i < slice.length; i++) {\r\n const id = slice[i]\r\n out[i] = { id, data: getRowData(id) ?? {} }\r\n }\r\n return out\r\n },\r\n\r\n getAllRowIds(): RowId[] {\r\n return [...order]\r\n },\r\n\r\n getAllRows(): Array<{ id: RowId; data: Record<string, unknown> }> {\r\n const out = new Array(filteredOrder.length) as Array<{\r\n id: RowId\r\n data: Record<string, unknown>\r\n }>\r\n for (let i = 0; i < filteredOrder.length; i++) {\r\n const id = filteredOrder[i]\r\n out[i] = { id, data: getRowData(id) ?? {} }\r\n }\r\n return out\r\n },\r\n\r\n setSort(column: string, direction: SortDirection, append?: boolean): void {\r\n if (append) {\r\n sorts = sorts.filter((s) => s.column !== column)\r\n sorts.push({ column, direction })\r\n } else {\r\n sorts = [{ column, direction }]\r\n }\r\n recomputeFiltered()\r\n },\r\n\r\n setSorts(newSorts: SortConfig[]): void {\r\n sorts = [...newSorts]\r\n recomputeFiltered()\r\n },\r\n\r\n clearSort(): void {\r\n sorts = []\r\n recomputeFiltered()\r\n },\r\n\r\n addFilter(filter: ColumnFilter): void {\r\n filters = filters.filter((f) => f.column !== filter.column)\r\n filters.push(filter)\r\n page = 1\r\n recomputeFiltered()\r\n },\r\n\r\n removeFilter(column: string): void {\r\n filters = filters.filter((f) => f.column !== column)\r\n recomputeFiltered()\r\n },\r\n\r\n clearFilters(): void {\r\n filters = []\r\n customFilterFn = null\r\n recomputeFiltered()\r\n },\r\n\r\n setFilterFn(fn: FilterFn | null): void {\r\n customFilterFn = fn\r\n recomputeFiltered()\r\n },\r\n\r\n setColumnFilter(column, filter): void {\r\n filters = filters.filter((f) => f.column !== column)\r\n if (filter !== null) {\r\n filters.push(toColumnFilter(column, filter))\r\n }\r\n page = 1\r\n recomputeFiltered()\r\n },\r\n\r\n setPage(p: number): void {\r\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\r\n page = Math.max(1, Math.min(p, totalPages))\r\n publishState()\r\n },\r\n\r\n setPageSize(size: number): void {\r\n currentPageSize = size\r\n page = 1\r\n recomputeFiltered()\r\n },\r\n\r\n nextPage(): void {\r\n table.setPage(page + 1)\r\n },\r\n\r\n prevPage(): void {\r\n table.setPage(page - 1)\r\n },\r\n\r\n moveRow(fromIndex: number, toIndex: number): void {\r\n if (fromIndex < 0 || fromIndex >= order.length) return\r\n if (toIndex < 0 || toIndex >= order.length) return\r\n if (fromIndex === toIndex) return\r\n\r\n const [item] = order.splice(fromIndex, 1)\r\n order.splice(toIndex, 0, item)\r\n recomputeFiltered()\r\n },\r\n\r\n pinColumn(column: string, side: 'left' | 'right' | null): void {\r\n pinnedLeft = pinnedLeft.filter((c) => c !== column)\r\n pinnedRight = pinnedRight.filter((c) => c !== column)\r\n if (side === 'left') pinnedLeft.push(column)\r\n else if (side === 'right') pinnedRight.push(column)\r\n core.set(statePath(tableId, 'pinnedLeft'), [...pinnedLeft])\r\n core.set(statePath(tableId, 'pinnedRight'), [...pinnedRight])\r\n },\r\n\r\n getPinnedColumns(): { left: string[]; right: string[] } {\r\n return { left: [...pinnedLeft], right: [...pinnedRight] }\r\n },\r\n\r\n clearPinned(): void {\r\n pinnedLeft = []\r\n pinnedRight = []\r\n core.set(statePath(tableId, 'pinnedLeft'), [])\r\n core.set(statePath(tableId, 'pinnedRight'), [])\r\n },\r\n\r\n setColumnWidth(column: string, width: number): void {\r\n columnWidths = { ...columnWidths, [column]: width }\r\n core.set(statePath(tableId, 'columnWidths'), { ...columnWidths })\r\n },\r\n\r\n getColumnWidth(column: string): number | undefined {\r\n return columnWidths[column]\r\n },\r\n\r\n getColumnWidths(): Record<string, number> {\r\n return { ...columnWidths }\r\n },\r\n\r\n clearColumnWidths(): void {\r\n columnWidths = {}\r\n core.set(statePath(tableId, 'columnWidths'), {})\r\n },\r\n\r\n moveRows(ids: RowId[], toIndex: number): void {\r\n const items = ids\r\n .map((id) => {\r\n const idx = order.indexOf(id)\r\n return { id, idx }\r\n })\r\n .filter((x) => x.idx !== -1)\r\n\r\n if (items.length === 0) return\r\n\r\n const idsSet = new Set(ids)\r\n const remaining = order.filter((id) => !idsSet.has(id))\r\n const clamped = Math.max(0, Math.min(toIndex, remaining.length))\r\n remaining.splice(clamped, 0, ...items.map((x) => x.id))\r\n order = remaining\r\n recomputeFiltered()\r\n },\r\n\r\n getExportData(exportOptions?: ExportOptions): string[][] {\r\n const cols = exportOptions?.columns ?? getColumnKeys()\r\n const result: string[][] = []\r\n\r\n if (exportOptions?.headers !== false) {\r\n result.push(cols)\r\n }\r\n\r\n const sourceIds = exportOptions?.allRows\r\n ? filteredOrder\r\n : filteredOrder.slice(\r\n (page - 1) * currentPageSize,\r\n (page - 1) * currentPageSize + currentPageSize,\r\n )\r\n\r\n for (const id of sourceIds) {\r\n const data = getRowData(id)\r\n if (!data) continue\r\n result.push(\r\n cols.map((col) => {\r\n const v = data[col]\r\n return v == null ? '' : String(v)\r\n }),\r\n )\r\n }\r\n\r\n return result\r\n },\r\n\r\n getTableState(): TableState {\r\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\r\n return {\r\n totalRows: order.length,\r\n filteredRows: filteredOrder.length,\r\n page,\r\n pageSize: currentPageSize,\r\n totalPages,\r\n sorts: [...sorts],\r\n sort: sorts.length > 0 ? sorts[0] : null,\r\n filters: [...filters],\r\n groupBy: groupByField,\r\n groupCount: groups.length,\r\n }\r\n },\r\n\r\n groupBy(field, aggregates): void {\r\n groupByField = field ?? null\r\n columnAggregates = aggregates ? [...aggregates] : []\r\n recomputeGroups()\r\n publishState()\r\n },\r\n\r\n clearGroupBy(): void {\r\n groupByField = null\r\n columnAggregates = []\r\n groups = []\r\n publishState()\r\n },\r\n\r\n getGroupBy(): string | null {\r\n return groupByField\r\n },\r\n\r\n getGroups(): TableGroup[] {\r\n return groups.map((g) => ({\r\n key: g.key,\r\n value: g.value,\r\n rows: [...g.rows],\r\n aggregates: { ...g.aggregates },\r\n }))\r\n },\r\n\r\n getEstimatedRowHeight(id: RowId): number | null {\r\n const fn = options?.estimateRowHeight\r\n if (!fn) return null\r\n const data = getRowData(id)\r\n if (!data) return null\r\n const v = fn(data, id)\r\n return Number.isFinite(v) ? v : null\r\n },\r\n\r\n reset(): void {\r\n order = []\r\n filteredOrder = []\r\n sorts = []\r\n filters = []\r\n customFilterFn = null\r\n page = 1\r\n pinnedLeft = []\r\n pinnedRight = []\r\n columnWidths = {}\r\n groupByField = null\r\n columnAggregates = []\r\n groups = []\r\n dataById.clear()\r\n keysById.clear()\r\n core.set(statePath(tableId, 'columnWidths'), {})\r\n publishState()\r\n },\r\n }\r\n\r\n // Initial publish — emit empty `columnWidths` so subscribers can read a\r\n // stable shape from the store without needing to handle `undefined`.\r\n core.set(statePath(tableId, 'columnWidths'), {})\r\n publishState()\r\n return table\r\n}\r\n"],"mappings":";;;;;AAaO,SAAS,gBACd,QACgB;AAChB,QAAM,MAAM;AACZ,MAAI,IAAI,MAAM,KAAM,QAAO,IAAI;AAC/B,QAAM,MAAM;AACZ,MAAI,IAAI,YAAY,KAAM,QAAO,IAAI;AACrC,SAAO,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO;AAC9C;AAGA,SAAS,aAAa,KAAuB;AAC3C,SAAO,OAAO,QAAQ,QAAQ;AAChC;AAGA,SAAS,aAAa,GAAY,GAAqC;AACrE,QAAM,KAAK,OAAO,MAAM,WAAW,IAAI,OAAO,CAAC;AAC/C,QAAM,KAAK,OAAO,MAAM,WAAW,IAAI,OAAO,CAAC;AAC/C,MAAI,OAAO,MAAM,EAAE,KAAK,OAAO,MAAM,EAAE,EAAG,QAAO;AACjD,SAAO,CAAC,IAAI,EAAE;AAChB;AAMO,SAAS,gBACd,KACA,IACA,aACS;AACT,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ;AAAA,IAEjB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,OAAO;AACV,YAAM,OAAO,aAAa,KAAK,WAAW;AAC1C,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,CAAC,GAAG,CAAC,IAAI;AACf,UAAI,OAAO,KAAM,QAAO,IAAI;AAC5B,UAAI,OAAO,MAAO,QAAO,KAAK;AAC9B,UAAI,OAAO,KAAM,QAAO,IAAI;AAC5B,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,KAAK,WAAW;AACd,UAAI,CAAC,MAAM,QAAQ,WAAW,KAAK,YAAY,WAAW,EAAG,QAAO;AACpE,YAAM,UAAU,aAAa,KAAK,YAAY,CAAC,CAAC;AAChD,YAAM,UAAU,aAAa,KAAK,YAAY,CAAC,CAAC;AAChD,UAAI,CAAC,WAAW,CAAC,QAAS,QAAO;AACjC,aAAO,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC;AAAA,IAC5D;AAAA,IAEA,KAAK;AACH,aAAO,MAAM,QAAQ,WAAW,KAAK,YAAY,SAAS,GAAG;AAAA,IAC/D,KAAK;AACH,aAAO,MAAM,QAAQ,WAAW,KAAK,CAAC,YAAY,SAAS,GAAG;AAAA,IAEhE,KAAK;AACH,UAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,aAAO,IAAI,YAAY,EAAE,SAAS,OAAO,eAAe,EAAE,EAAE,YAAY,CAAC;AAAA,IAC3E,KAAK;AACH,UAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,aAAO,IAAI,YAAY,EAAE,WAAW,OAAO,eAAe,EAAE,EAAE,YAAY,CAAC;AAAA,IAC7E,KAAK;AACH,UAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,aAAO,IAAI,YAAY,EAAE,SAAS,OAAO,eAAe,EAAE,EAAE,YAAY,CAAC;AAAA,IAE3E,KAAK;AACH,aAAO,aAAa,GAAG;AAAA,IACzB,KAAK;AACH,aAAO,CAAC,aAAa,GAAG;AAAA,EAC5B;AACF;AAMO,SAAS,oBACd,KACA,QACS;AACT,QAAM,KAAK,gBAAgB,MAAM;AACjC,SAAO,gBAAgB,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,KAAK;AAC7D;AAGO,SAAS,iBACd,QACA,MACS;AACT,MAAI,OAAO,SAAS,WAAY,QAAO,KAAK,MAAM;AAElD,MAAI,SAAS,QAAS,QAAO,OAAO;AAEpC,QAAM,OAAiB,CAAC;AACxB,aAAW,KAAK,QAAQ;AACtB,QAAI,KAAK,QAAQ,MAAM,GAAI;AAC3B,UAAM,IAAI,OAAO,MAAM,WAAW,IAAI,OAAO,CAAC;AAC9C,QAAI,CAAC,OAAO,MAAM,CAAC,EAAG,MAAK,KAAK,CAAC;AAAA,EACnC;AACA,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,KAAK,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,IACvC,KAAK;AACH,aAAO,KAAK,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK;AAAA,IAChD,KAAK;AACH,aAAO,KAAK,IAAI,GAAG,IAAI;AAAA,IACzB,KAAK;AACH,aAAO,KAAK,IAAI,GAAG,IAAI;AAAA,EAC3B;AACF;;;AClHA,SAAS,UAAU,SAAiB,KAAqB;AACvD,SAAO,GAAG,YAAY,GAAG,OAAO,UAAU,GAAG;AAC/C;AAEA,IAAI,eAAe;AAeZ,SAAS,YAAY,MAAY,SAAqC;AAC3E,QAAM,UAAU,IAAI,cAAc;AAClC,MAAI,kBAAkB,SAAS,YAAY;AAE3C,MAAI,QAAiB,CAAC;AACtB,MAAI,gBAAyB,CAAC;AAC9B,MAAI,QAAsB,CAAC;AAC3B,MAAI,UAA0B,CAAC;AAC/B,MAAI,iBAAkC;AACtC,MAAI,OAAO;AACX,MAAI,aAAuB,CAAC;AAC5B,MAAI,cAAwB,CAAC;AAC7B,MAAI,eAAuC,CAAC;AAG5C,MAAI,eAA8B;AAClC,MAAI,mBAAsC,CAAC;AAC3C,MAAI,SAAuB,CAAC;AAK5B,QAAM,WAAW,oBAAI,IAAoC;AACzD,QAAM,WAAW,oBAAI,IAAqB;AAE1C,WAAS,WAAW,IAAgD;AAClE,UAAM,SAAS,SAAS,IAAI,EAAE;AAC9B,QAAI,CAAC,OAAQ,QAAO;AAOpB,QAAI,SAAS,SAAS;AACpB,YAAM,WAAoC,CAAC;AAC3C,iBAAW,OAAO,QAAQ,SAAS;AACjC,iBAAS,GAAG,IAAI,OAAO,GAAG;AAAA,MAC5B;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,WAAS,eAAe,SAA2C;AACjE,QAAI,kBAAkB,CAAC,eAAe,OAAO,EAAG,QAAO;AAEvD,eAAW,KAAK,SAAS;AACvB,UAAI,CAAC,oBAAoB,SAAS,CAAC,EAAG,QAAO;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,GAAU,GAAkB;AACjD,UAAM,QAAQ,WAAW,CAAC;AAC1B,UAAM,QAAQ,WAAW,CAAC;AAE1B,eAAW,KAAK,OAAO;AACrB,YAAM,OAAO,QAAQ,EAAE,MAAM;AAC7B,YAAM,OAAO,QAAQ,EAAE,MAAM;AAE7B,UAAI,SAAS,KAAM;AACnB,UAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAChD,UAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAEhD,YAAM,MAAM,OAAO,OAAO,KAAK;AAC/B,aAAO,EAAE,cAAc,QAAQ,MAAM,CAAC;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAEA,WAAS,oBAA0B;AACjC,QAAI,QAAQ,WAAW,KAAK,CAAC,gBAAgB;AAC3C,sBAAgB,CAAC,GAAG,KAAK;AAAA,IAC3B,OAAO;AACL,sBAAgB,MAAM,OAAO,CAAC,OAAO;AACnC,cAAM,OAAO,WAAW,EAAE;AAC1B,eAAO,OAAO,eAAe,IAAI,IAAI;AAAA,MACvC,CAAC;AAAA,IACH;AAEA,QAAI,MAAM,SAAS,GAAG;AACpB,oBAAc,KAAK,aAAa;AAAA,IAClC;AAEA,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,cAAc,SAAS,eAAe,CAAC;AAChF,QAAI,OAAO,WAAY,QAAO;AAE9B,oBAAgB;AAChB,iBAAa;AAAA,EACf;AAEA,WAAS,kBAAwB;AAC/B,QAAI,CAAC,cAAc;AACjB,eAAS,CAAC;AACV;AAAA,IACF;AAEA,UAAM,MAAM,oBAAI,IAA+C;AAC/D,UAAM,YAAsB,CAAC;AAE7B,eAAW,MAAM,eAAe;AAC9B,YAAM,OAAO,WAAW,EAAE;AAC1B,UAAI,CAAC,KAAM;AACX,YAAM,MAAM,KAAK,YAAY;AAC7B,YAAM,MAAM,OAAO,OAAO,aAAa,OAAO,GAAG;AACjD,UAAI,CAAC,IAAI,IAAI,GAAG,GAAG;AACjB,YAAI,IAAI,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,EAAE,CAAC;AACrC,kBAAU,KAAK,GAAG;AAAA,MACpB;AACA,UAAI,IAAI,GAAG,EAAG,KAAK,KAAK,EAAE;AAAA,IAC5B;AAEA,aAAS,UAAU,IAAI,CAAC,QAAQ;AAC9B,YAAM,EAAE,OAAO,KAAK,IAAI,IAAI,IAAI,GAAG;AACnC,YAAM,aAAsC,CAAC;AAC7C,iBAAW,OAAO,kBAAkB;AAClC,cAAM,SAAS,KAAK,IAAI,CAAC,OAAO,SAAS,IAAI,EAAE,IAAI,IAAI,MAAM,CAAC;AAC9D,mBAAW,IAAI,MAAM,IAAI,iBAAiB,QAAQ,IAAI,IAAI;AAAA,MAC5D;AACA,aAAO,EAAE,KAAK,OAAO,MAAM,WAAW;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,WAAS,eAAqB;AAC5B,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,cAAc,SAAS,eAAe,CAAC;AAChF,SAAK,IAAI,UAAU,SAAS,WAAW,GAAG,MAAM,MAAM;AACtD,SAAK,IAAI,UAAU,SAAS,cAAc,GAAG,cAAc,MAAM;AACjE,SAAK,IAAI,UAAU,SAAS,MAAM,GAAG,IAAI;AACzC,SAAK,IAAI,UAAU,SAAS,UAAU,GAAG,eAAe;AACxD,SAAK,IAAI,UAAU,SAAS,YAAY,GAAG,UAAU;AACrD,SAAK,IAAI,UAAU,SAAS,SAAS,GAAG,YAAY;AACpD,SAAK,IAAI,UAAU,SAAS,YAAY,GAAG,OAAO,MAAM;AAAA,EAC1D;AAEA,WAAS,gBAA0B;AACjC,QAAI,SAAS,QAAS,QAAO,QAAQ;AACrC,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAChC,UAAM,UAAU,MAAM,CAAC;AACvB,WAAO,SAAS,IAAI,OAAO,KAAK,CAAC;AAAA,EACnC;AAGA,WAAS,eAAe,QAAgB,QAAqD;AAC3F,UAAM,MAAM;AACZ,QAAI,IAAI,MAAM,MAAM;AAClB,aAAO,EAAE,QAAQ,UAAU,IAAI,IAAI,OAAO,IAAI,MAAM;AAAA,IACtD;AACA,UAAM,KAAK;AACX,WAAO,EAAE,QAAQ,UAAU,GAAG,UAAU,OAAO,GAAG,MAAM;AAAA,EAC1D;AAEA,QAAM,QAAqB;AAAA,IACzB,OAAO,IAAW,MAAqC;AACrD,eAAS,IAAI,IAAI,IAAI;AACrB,eAAS,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;AAClC,YAAM,KAAK,EAAE;AACb,wBAAkB;AAAA,IACpB;AAAA,IAEA,QAAQ,MAAiE;AAIvE,iBAAW,OAAO,MAAM;AACtB,iBAAS,IAAI,IAAI,IAAI,IAAI,IAAI;AAC7B,iBAAS,IAAI,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC;AAC1C,cAAM,KAAK,IAAI,EAAE;AAAA,MACnB;AACA,wBAAkB;AAAA,IACpB;AAAA,IAEA,UAAU,IAAiB;AACzB,YAAM,MAAM,MAAM,QAAQ,EAAE;AAC5B,UAAI,QAAQ,GAAI;AAChB,YAAM,OAAO,KAAK,CAAC;AACnB,eAAS,OAAO,EAAE;AAClB,eAAS,OAAO,EAAE;AAClB,wBAAkB;AAAA,IACpB;AAAA,IAEA,WAAW,IAAW,QAAgB,OAAsB;AAC1D,YAAM,MAAM,SAAS,IAAI,EAAE;AAC3B,UAAI,CAAC,IAAK;AAIV,UAAI,MAAM,IAAI;AACd,YAAM,OAAO,SAAS,IAAI,EAAE;AAC5B,UAAI,QAAQ,CAAC,KAAK,SAAS,MAAM,GAAG;AAClC,aAAK,KAAK,MAAM;AAAA,MAClB;AACA,wBAAkB;AAAA,IACpB;AAAA,IAEA,OAAO,IAAgD;AACrD,aAAO,WAAW,EAAE;AAAA,IACtB;AAAA,IAEA,QAAQ,IAAW,QAAyB;AAC1C,aAAO,SAAS,IAAI,EAAE,IAAI,MAAM;AAAA,IAClC;AAAA,IAEA,iBAAsE;AACpE,YAAM,SAAS,OAAO,KAAK;AAC3B,YAAM,MAAM,QAAQ;AACpB,YAAM,QAAQ,cAAc,MAAM,OAAO,GAAG;AAC5C,YAAM,MAAM,IAAI,MAAM,MAAM,MAAM;AAIlC,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAM,KAAK,MAAM,CAAC;AAClB,YAAI,CAAC,IAAI,EAAE,IAAI,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE;AAAA,MAC5C;AACA,aAAO;AAAA,IACT;AAAA,IAEA,eAAwB;AACtB,aAAO,CAAC,GAAG,KAAK;AAAA,IAClB;AAAA,IAEA,aAAkE;AAChE,YAAM,MAAM,IAAI,MAAM,cAAc,MAAM;AAI1C,eAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,cAAM,KAAK,cAAc,CAAC;AAC1B,YAAI,CAAC,IAAI,EAAE,IAAI,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE;AAAA,MAC5C;AACA,aAAO;AAAA,IACT;AAAA,IAEA,QAAQ,QAAgB,WAA0B,QAAwB;AACxE,UAAI,QAAQ;AACV,gBAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAC/C,cAAM,KAAK,EAAE,QAAQ,UAAU,CAAC;AAAA,MAClC,OAAO;AACL,gBAAQ,CAAC,EAAE,QAAQ,UAAU,CAAC;AAAA,MAChC;AACA,wBAAkB;AAAA,IACpB;AAAA,IAEA,SAAS,UAA8B;AACrC,cAAQ,CAAC,GAAG,QAAQ;AACpB,wBAAkB;AAAA,IACpB;AAAA,IAEA,YAAkB;AAChB,cAAQ,CAAC;AACT,wBAAkB;AAAA,IACpB;AAAA,IAEA,UAAU,QAA4B;AACpC,gBAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,MAAM;AAC1D,cAAQ,KAAK,MAAM;AACnB,aAAO;AACP,wBAAkB;AAAA,IACpB;AAAA,IAEA,aAAa,QAAsB;AACjC,gBAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACnD,wBAAkB;AAAA,IACpB;AAAA,IAEA,eAAqB;AACnB,gBAAU,CAAC;AACX,uBAAiB;AACjB,wBAAkB;AAAA,IACpB;AAAA,IAEA,YAAY,IAA2B;AACrC,uBAAiB;AACjB,wBAAkB;AAAA,IACpB;AAAA,IAEA,gBAAgB,QAAQ,QAAc;AACpC,gBAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACnD,UAAI,WAAW,MAAM;AACnB,gBAAQ,KAAK,eAAe,QAAQ,MAAM,CAAC;AAAA,MAC7C;AACA,aAAO;AACP,wBAAkB;AAAA,IACpB;AAAA,IAEA,QAAQ,GAAiB;AACvB,YAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,cAAc,SAAS,eAAe,CAAC;AAChF,aAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,UAAU,CAAC;AAC1C,mBAAa;AAAA,IACf;AAAA,IAEA,YAAY,MAAoB;AAC9B,wBAAkB;AAClB,aAAO;AACP,wBAAkB;AAAA,IACpB;AAAA,IAEA,WAAiB;AACf,YAAM,QAAQ,OAAO,CAAC;AAAA,IACxB;AAAA,IAEA,WAAiB;AACf,YAAM,QAAQ,OAAO,CAAC;AAAA,IACxB;AAAA,IAEA,QAAQ,WAAmB,SAAuB;AAChD,UAAI,YAAY,KAAK,aAAa,MAAM,OAAQ;AAChD,UAAI,UAAU,KAAK,WAAW,MAAM,OAAQ;AAC5C,UAAI,cAAc,QAAS;AAE3B,YAAM,CAAC,IAAI,IAAI,MAAM,OAAO,WAAW,CAAC;AACxC,YAAM,OAAO,SAAS,GAAG,IAAI;AAC7B,wBAAkB;AAAA,IACpB;AAAA,IAEA,UAAU,QAAgB,MAAqC;AAC7D,mBAAa,WAAW,OAAO,CAAC,MAAM,MAAM,MAAM;AAClD,oBAAc,YAAY,OAAO,CAAC,MAAM,MAAM,MAAM;AACpD,UAAI,SAAS,OAAQ,YAAW,KAAK,MAAM;AAAA,eAClC,SAAS,QAAS,aAAY,KAAK,MAAM;AAClD,WAAK,IAAI,UAAU,SAAS,YAAY,GAAG,CAAC,GAAG,UAAU,CAAC;AAC1D,WAAK,IAAI,UAAU,SAAS,aAAa,GAAG,CAAC,GAAG,WAAW,CAAC;AAAA,IAC9D;AAAA,IAEA,mBAAwD;AACtD,aAAO,EAAE,MAAM,CAAC,GAAG,UAAU,GAAG,OAAO,CAAC,GAAG,WAAW,EAAE;AAAA,IAC1D;AAAA,IAEA,cAAoB;AAClB,mBAAa,CAAC;AACd,oBAAc,CAAC;AACf,WAAK,IAAI,UAAU,SAAS,YAAY,GAAG,CAAC,CAAC;AAC7C,WAAK,IAAI,UAAU,SAAS,aAAa,GAAG,CAAC,CAAC;AAAA,IAChD;AAAA,IAEA,eAAe,QAAgB,OAAqB;AAClD,qBAAe,EAAE,GAAG,cAAc,CAAC,MAAM,GAAG,MAAM;AAClD,WAAK,IAAI,UAAU,SAAS,cAAc,GAAG,EAAE,GAAG,aAAa,CAAC;AAAA,IAClE;AAAA,IAEA,eAAe,QAAoC;AACjD,aAAO,aAAa,MAAM;AAAA,IAC5B;AAAA,IAEA,kBAA0C;AACxC,aAAO,EAAE,GAAG,aAAa;AAAA,IAC3B;AAAA,IAEA,oBAA0B;AACxB,qBAAe,CAAC;AAChB,WAAK,IAAI,UAAU,SAAS,cAAc,GAAG,CAAC,CAAC;AAAA,IACjD;AAAA,IAEA,SAAS,KAAc,SAAuB;AAC5C,YAAM,QAAQ,IACX,IAAI,CAAC,OAAO;AACX,cAAM,MAAM,MAAM,QAAQ,EAAE;AAC5B,eAAO,EAAE,IAAI,IAAI;AAAA,MACnB,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE;AAE7B,UAAI,MAAM,WAAW,EAAG;AAExB,YAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,YAAM,YAAY,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;AACtD,YAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,UAAU,MAAM,CAAC;AAC/D,gBAAU,OAAO,SAAS,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACtD,cAAQ;AACR,wBAAkB;AAAA,IACpB;AAAA,IAEA,cAAc,eAA2C;AACvD,YAAM,OAAO,eAAe,WAAW,cAAc;AACrD,YAAM,SAAqB,CAAC;AAE5B,UAAI,eAAe,YAAY,OAAO;AACpC,eAAO,KAAK,IAAI;AAAA,MAClB;AAEA,YAAM,YAAY,eAAe,UAC7B,gBACA,cAAc;AAAA,SACX,OAAO,KAAK;AAAA,SACZ,OAAO,KAAK,kBAAkB;AAAA,MACjC;AAEJ,iBAAW,MAAM,WAAW;AAC1B,cAAM,OAAO,WAAW,EAAE;AAC1B,YAAI,CAAC,KAAM;AACX,eAAO;AAAA,UACL,KAAK,IAAI,CAAC,QAAQ;AAChB,kBAAM,IAAI,KAAK,GAAG;AAClB,mBAAO,KAAK,OAAO,KAAK,OAAO,CAAC;AAAA,UAClC,CAAC;AAAA,QACH;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,gBAA4B;AAC1B,YAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,cAAc,SAAS,eAAe,CAAC;AAChF,aAAO;AAAA,QACL,WAAW,MAAM;AAAA,QACjB,cAAc,cAAc;AAAA,QAC5B;AAAA,QACA,UAAU;AAAA,QACV;AAAA,QACA,OAAO,CAAC,GAAG,KAAK;AAAA,QAChB,MAAM,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI;AAAA,QACpC,SAAS,CAAC,GAAG,OAAO;AAAA,QACpB,SAAS;AAAA,QACT,YAAY,OAAO;AAAA,MACrB;AAAA,IACF;AAAA,IAEA,QAAQ,OAAO,YAAkB;AAC/B,qBAAe,SAAS;AACxB,yBAAmB,aAAa,CAAC,GAAG,UAAU,IAAI,CAAC;AACnD,sBAAgB;AAChB,mBAAa;AAAA,IACf;AAAA,IAEA,eAAqB;AACnB,qBAAe;AACf,yBAAmB,CAAC;AACpB,eAAS,CAAC;AACV,mBAAa;AAAA,IACf;AAAA,IAEA,aAA4B;AAC1B,aAAO;AAAA,IACT;AAAA,IAEA,YAA0B;AACxB,aAAO,OAAO,IAAI,CAAC,OAAO;AAAA,QACxB,KAAK,EAAE;AAAA,QACP,OAAO,EAAE;AAAA,QACT,MAAM,CAAC,GAAG,EAAE,IAAI;AAAA,QAChB,YAAY,EAAE,GAAG,EAAE,WAAW;AAAA,MAChC,EAAE;AAAA,IACJ;AAAA,IAEA,sBAAsB,IAA0B;AAC9C,YAAM,KAAK,SAAS;AACpB,UAAI,CAAC,GAAI,QAAO;AAChB,YAAM,OAAO,WAAW,EAAE;AAC1B,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,IAAI,GAAG,MAAM,EAAE;AACrB,aAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,IAClC;AAAA,IAEA,QAAc;AACZ,cAAQ,CAAC;AACT,sBAAgB,CAAC;AACjB,cAAQ,CAAC;AACT,gBAAU,CAAC;AACX,uBAAiB;AACjB,aAAO;AACP,mBAAa,CAAC;AACd,oBAAc,CAAC;AACf,qBAAe,CAAC;AAChB,qBAAe;AACf,yBAAmB,CAAC;AACpB,eAAS,CAAC;AACV,eAAS,MAAM;AACf,eAAS,MAAM;AACf,WAAK,IAAI,UAAU,SAAS,cAAc,GAAG,CAAC,CAAC;AAC/C,mBAAa;AAAA,IACf;AAAA,EACF;AAIA,OAAK,IAAI,UAAU,SAAS,cAAc,GAAG,CAAC,CAAC;AAC/C,eAAa;AACb,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/calendar/availability.ts","../src/engines/calendar/conflicts.ts","../src/engines/calendar/CalendarEngine.ts"],"sourcesContent":["import type { AvailabilityRule, DayOfWeek, Resource } from './types'\r\n\r\nconst DAY_MS = 86_400_000\r\n\r\n/**\r\n * Parse `HH:MM` into milliseconds-from-midnight.\r\n *\r\n * Returns `null` for malformed input — callers treat that as \"rule has no\r\n * window on this side\" (i.e. the canonical 00:00 / 24:00 fallback).\r\n */\r\nfunction parseHHMM(s: string | undefined, fallback: number): number {\r\n if (s === undefined) return fallback\r\n const m = /^(\\d{1,2}):(\\d{2})$/.exec(s)\r\n if (!m) return fallback\r\n const h = Number(m[1])\r\n const mm = Number(m[2])\r\n if (!Number.isFinite(h) || !Number.isFinite(mm)) return fallback\r\n if (h < 0 || h > 24 || mm < 0 || mm >= 60) return fallback\r\n return h * 3_600_000 + mm * 60_000\r\n}\r\n\r\n/** Rules attached to one resource. Cheap to compute, cached per call. */\r\nfunction rulesFor(\r\n resourceId: string,\r\n rules: readonly AvailabilityRule[],\r\n): AvailabilityRule[] {\r\n return rules.filter((r) => r.resourceId === resourceId)\r\n}\r\n\r\nfunction dayBucket(t: number): { dayStart: number; dayOfWeek: DayOfWeek } {\r\n // Floor to UTC day boundary; getUTCDay returns 0..6 (Sun..Sat).\r\n const d = new Date(t)\r\n const dayStart =\r\n Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())\r\n const dayOfWeek = new Date(dayStart).getUTCDay() as DayOfWeek\r\n return { dayStart, dayOfWeek }\r\n}\r\n\r\n/**\r\n * `true` ⇔ the entire `[start, end)` interval falls inside at least one\r\n * availability window for `resource`. A resource without any matching\r\n * rule (or without any rules at all) is considered always available —\r\n * unconfigured calendars stay friendly.\r\n *\r\n * Implementation: walk one UTC day at a time and check that the slice of\r\n * `[start, end)` intersected with that day is fully covered by the union\r\n * of windows attached to that day. The union is built by sorting rule\r\n * windows by `from` and merging overlaps in O(k log k) where k = rules\r\n * for that day (typically 1–3).\r\n */\r\nexport function isAvailable(\r\n resource: Resource,\r\n range: { start: number; end: number },\r\n rules: readonly AvailabilityRule[],\r\n): boolean {\r\n if (range.end <= range.start) return true\r\n\r\n const own = rulesFor(resource.id, rules)\r\n if (own.length === 0) return true\r\n\r\n let cursor = range.start\r\n while (cursor < range.end) {\r\n const { dayStart, dayOfWeek } = dayBucket(cursor)\r\n const dayEnd = dayStart + DAY_MS\r\n const sliceEnd = Math.min(range.end, dayEnd)\r\n\r\n const dayRules = own.filter(\r\n (r) => r.dayOfWeek === undefined || r.dayOfWeek === dayOfWeek,\r\n )\r\n if (dayRules.length === 0) return false\r\n\r\n // Build union of windows for this day, in absolute ms.\r\n const intervals = dayRules\r\n .map((r) => {\r\n const fromMs = parseHHMM(r.from, 0)\r\n const toMs = parseHHMM(r.to, DAY_MS)\r\n return { from: dayStart + fromMs, to: dayStart + toMs }\r\n })\r\n .filter((w) => w.to > w.from)\r\n .sort((a, b) => a.from - b.from)\r\n\r\n if (intervals.length === 0) return false\r\n\r\n const merged: Array<{ from: number; to: number }> = []\r\n for (const w of intervals) {\r\n const last = merged[merged.length - 1]\r\n if (last && w.from <= last.to) {\r\n last.to = Math.max(last.to, w.to)\r\n } else {\r\n merged.push({ ...w })\r\n }\r\n }\r\n\r\n // The required slice for this day is [cursor, sliceEnd). It must be\r\n // fully contained in the union. We sweep the merged windows.\r\n let needed = cursor\r\n for (const w of merged) {\r\n if (w.from > needed) return false\r\n if (w.to >= sliceEnd) {\r\n needed = sliceEnd\r\n break\r\n }\r\n needed = Math.max(needed, w.to)\r\n }\r\n if (needed < sliceEnd) return false\r\n\r\n cursor = sliceEnd\r\n }\r\n\r\n return true\r\n}\r\n","import { isAvailable } from './availability'\r\nimport type {\r\n Assignment,\r\n AvailabilityRule,\r\n CalendarScale,\r\n CalendarState,\r\n Conflict,\r\n Resource,\r\n} from './types'\r\n\r\nconst DAY_MS = 86_400_000\r\nconst STEP_MS: Record<CalendarScale, number> = {\r\n day: DAY_MS,\r\n week: 7 * DAY_MS,\r\n month: 30 * DAY_MS,\r\n}\r\n\r\nexport interface DetectConflictsArgs {\r\n scale?: CalendarScale\r\n rules?: readonly AvailabilityRule[]\r\n}\r\n\r\nfunction makeId(reason: Conflict['reason'], ids: readonly string[]): string {\r\n return `${reason}:${[...ids].sort().join(',')}`\r\n}\r\n\r\nfunction pushConflict(\r\n out: Map<string, Conflict>,\r\n reason: Conflict['reason'],\r\n ids: string[],\r\n): void {\r\n if (ids.length === 0) return\r\n const sorted = [...ids].sort()\r\n const id = makeId(reason, sorted)\r\n if (out.has(id)) return\r\n out.set(id, { id, reason, assignmentIds: sorted })\r\n}\r\n\r\n/**\r\n * Find all conflicts in `state`.\r\n *\r\n * Algorithm — three independent passes, results de-duplicated by\r\n * `(reason, sorted-ids)` so the same overlapping pair is never reported\r\n * twice as `overlap`:\r\n *\r\n * 1. **overlap** (per resource): sort assignments by `start` and sweep.\r\n * Keep an active set ordered by `end` ASC; whenever a new\r\n * assignment opens, every still-active assignment forms a pairwise\r\n * `overlap` conflict with it. O(n log n + k) where k = total\r\n * overlapping pairs.\r\n *\r\n * 2. **over-capacity** (per resource with `capacityPerSlot`): bucket\r\n * every assignment into the slots it touches (1 slot = 1 scale\r\n * step). For each slot whose concurrent count exceeds capacity,\r\n * emit one `over-capacity` conflict naming exactly the assignments\r\n * that touch that slot. This is the simple counter approach (no\r\n * interval tree) — fine up to ~10⁵ assignments per resource.\r\n *\r\n * 3. **outside-availability**: per-assignment check via\r\n * `isAvailable`. Each violation becomes its own one-element\r\n * conflict.\r\n */\r\nexport function detectConflicts(\r\n state: Pick<CalendarState, 'resources' | 'assignments'>,\r\n opts: DetectConflictsArgs = {},\r\n): Conflict[] {\r\n const scale = opts.scale ?? 'day'\r\n const step = STEP_MS[scale]\r\n const rules = opts.rules ?? []\r\n const conflicts = new Map<string, Conflict>()\r\n\r\n const byResource = new Map<string, Assignment[]>()\r\n for (const a of state.assignments) {\r\n let bucket = byResource.get(a.resourceId)\r\n if (!bucket) {\r\n bucket = []\r\n byResource.set(a.resourceId, bucket)\r\n }\r\n bucket.push(a)\r\n }\r\n\r\n // ── 1. Pairwise overlap (per resource) ─────────────────────────────\r\n for (const list of byResource.values()) {\r\n const sorted = [...list].sort((x, y) => x.start - y.start)\r\n for (let i = 0; i < sorted.length; i++) {\r\n const a = sorted[i]!\r\n for (let j = i + 1; j < sorted.length; j++) {\r\n const b = sorted[j]!\r\n if (b.start >= a.end) break\r\n // Touching boundaries (b.start === a.end) is NOT a conflict —\r\n // assignment ranges are half-open [start, end).\r\n pushConflict(conflicts, 'overlap', [a.id, b.id])\r\n }\r\n }\r\n }\r\n\r\n // ── 2. Over-capacity per slot (per resource with capacityPerSlot) ──\r\n const resourceById = new Map<string, Resource>()\r\n for (const r of state.resources) resourceById.set(r.id, r)\r\n\r\n for (const [rid, list] of byResource) {\r\n const resource = resourceById.get(rid)\r\n if (!resource || resource.capacityPerSlot === undefined) continue\r\n const cap = Math.max(0, Math.floor(resource.capacityPerSlot))\r\n\r\n const slotMap = new Map<number, string[]>()\r\n for (const a of list) {\r\n // Every slot the assignment touches.\r\n const lo = Math.floor(a.start / step) * step\r\n const hi = Math.ceil(a.end / step) * step\r\n for (let s = lo; s < hi; s += step) {\r\n let bucket = slotMap.get(s)\r\n if (!bucket) {\r\n bucket = []\r\n slotMap.set(s, bucket)\r\n }\r\n bucket.push(a.id)\r\n }\r\n }\r\n\r\n for (const ids of slotMap.values()) {\r\n if (ids.length > cap) {\r\n pushConflict(conflicts, 'over-capacity', ids)\r\n }\r\n }\r\n }\r\n\r\n // ── 3. Outside availability (per assignment) ───────────────────────\r\n if (rules.length > 0) {\r\n for (const a of state.assignments) {\r\n const r = resourceById.get(a.resourceId)\r\n if (!r) continue\r\n if (!isAvailable(r, { start: a.start, end: a.end }, rules)) {\r\n pushConflict(conflicts, 'outside-availability', [a.id])\r\n }\r\n }\r\n }\r\n\r\n return [...conflicts.values()]\r\n}\r\n","import type { Core } from '../../types'\r\nimport { CALENDAR_PREFIX } from '../namespaces'\r\nimport { detectConflicts } from './conflicts'\r\nimport type {\r\n Assignment,\r\n AvailabilityRule,\r\n CalendarEngine,\r\n CalendarEngineOptions,\r\n CalendarScale,\r\n CalendarState,\r\n Conflict,\r\n Resource,\r\n} from './types'\r\n\r\nlet calendarCounter = 0\r\n\r\n/**\r\n * Resource Calendar engine — the sixth member of the\r\n * form / table / tree / virtual / graph / **calendar** family.\r\n *\r\n * The in-memory maps are the source of truth and the public read API;\r\n * snapshots are mirrored to the Core store under\r\n * `$calendar.<id>.{resources,assignments,conflicts,view}` so other\r\n * engines / external observers can react via `core.subscribe(...)`.\r\n *\r\n * v0 scope:\r\n * - addResource / removeResource / updateResource\r\n * - addAssignment / updateAssignment / removeAssignment\r\n * - moveAssignment(id, deltaMs) — shifts both ends together\r\n * - resizeAssignment(id, side, deltaMs) — clamps so width >= 1ms\r\n * - setRules / setScale — re-compute conflicts on change\r\n * - detectConflicts under the hood; status of involved assignments\r\n * is auto-promoted to `'conflict'` so the React adapter can render\r\n * without re-running the algorithm.\r\n *\r\n * NOT in v0 (deferred to round-10):\r\n * - exception dates on `AvailabilityRule`\r\n * - full per-engine undo/redo (use `core.snapshot/restore` instead)\r\n * - aggregate read APIs over a sub-range\r\n */\r\nexport function createCalendar(\r\n core: Core,\r\n options?: CalendarEngineOptions,\r\n): CalendarEngine {\r\n const engineId = `c${calendarCounter++}${options?.name ? `-${options.name}` : ''}`\r\n const prefix = CALENDAR_PREFIX\r\n\r\n const resources = new Map<string, Resource>()\r\n const assignments = new Map<string, Assignment>()\r\n let rules: AvailabilityRule[] = options?.rules ? [...options.rules] : []\r\n let scale: CalendarScale = options?.scale ?? 'day'\r\n let conflicts: Conflict[] = []\r\n\r\n const localSubscribers = new Set<() => void>()\r\n\r\n function publish(): void {\r\n const resList = [...resources.values()]\r\n const assignList = [...assignments.values()]\r\n core.batch(() => {\r\n core.set(`${prefix}${engineId}.resources`, resList)\r\n core.set(`${prefix}${engineId}.assignments`, assignList)\r\n core.set(`${prefix}${engineId}.conflicts`, conflicts)\r\n core.set(`${prefix}${engineId}.view`, { scale })\r\n })\r\n for (const cb of localSubscribers) cb()\r\n }\r\n\r\n function recompute(): void {\r\n conflicts = detectConflicts(\r\n { resources: [...resources.values()], assignments: [...assignments.values()] },\r\n { scale, rules },\r\n )\r\n // Promote involved assignments to status: 'conflict'. Assignments\r\n // that aren't in any conflict get their original (or default)\r\n // status restored. We don't lose the underlying intent: the\r\n // promotion is reversible and recomputed on every mutation.\r\n const involved = new Set<string>()\r\n for (const c of conflicts) for (const id of c.assignmentIds) involved.add(id)\r\n for (const [id, a] of assignments) {\r\n const isConflicting = involved.has(id)\r\n if (isConflicting && a.status !== 'conflict') {\r\n assignments.set(id, { ...a, status: 'conflict' })\r\n } else if (!isConflicting && a.status === 'conflict') {\r\n // Drop the auto-`conflict` flag — the original intent (tentative\r\n // / confirmed / undefined) was lost when we promoted, and the\r\n // adapter only needs to know \"no longer conflicting\", so we\r\n // default back to `'tentative'` which is the safest fallback.\r\n assignments.set(id, { ...a, status: 'tentative' })\r\n }\r\n }\r\n }\r\n\r\n function commitAndPublish(): void {\r\n recompute()\r\n publish()\r\n }\r\n\r\n function subscribe(cb: () => void): () => void {\r\n localSubscribers.add(cb)\r\n return () => {\r\n localSubscribers.delete(cb)\r\n }\r\n }\r\n\r\n function addResource(resource: Resource): void {\r\n if (resources.has(resource.id)) {\r\n throw new Error(\r\n `[skygraph/calendar] resource id \"${resource.id}\" already exists`,\r\n )\r\n }\r\n resources.set(resource.id, { ...resource })\r\n commitAndPublish()\r\n }\r\n\r\n function removeResource(id: string): void {\r\n if (!resources.has(id)) return\r\n resources.delete(id)\r\n // Cascade: drop assignments tied to this resource.\r\n for (const [aid, a] of assignments) {\r\n if (a.resourceId === id) assignments.delete(aid)\r\n }\r\n commitAndPublish()\r\n }\r\n\r\n function updateResource(id: string, patch: Partial<Resource>): void {\r\n const r = resources.get(id)\r\n if (!r) throw new Error(`[skygraph/calendar] resource \"${id}\" not found`)\r\n resources.set(id, { ...r, ...patch, id })\r\n commitAndPublish()\r\n }\r\n\r\n function getResource(id: string): Resource | undefined {\r\n return resources.get(id)\r\n }\r\n\r\n function getResources(): Resource[] {\r\n return [...resources.values()]\r\n }\r\n\r\n function addAssignment(assignment: Assignment): void {\r\n if (assignments.has(assignment.id)) {\r\n throw new Error(\r\n `[skygraph/calendar] assignment id \"${assignment.id}\" already exists`,\r\n )\r\n }\r\n if (!resources.has(assignment.resourceId)) {\r\n throw new Error(\r\n `[skygraph/calendar] addAssignment: resource \"${assignment.resourceId}\" not found`,\r\n )\r\n }\r\n if (assignment.end <= assignment.start) {\r\n throw new Error(\r\n `[skygraph/calendar] addAssignment: end (${assignment.end}) must be greater than start (${assignment.start})`,\r\n )\r\n }\r\n assignments.set(assignment.id, { ...assignment })\r\n commitAndPublish()\r\n }\r\n\r\n function updateAssignment(id: string, patch: Partial<Assignment>): void {\r\n const a = assignments.get(id)\r\n if (!a) throw new Error(`[skygraph/calendar] assignment \"${id}\" not found`)\r\n const next: Assignment = { ...a, ...patch, id }\r\n if (next.end <= next.start) {\r\n throw new Error(\r\n `[skygraph/calendar] updateAssignment: end (${next.end}) must be greater than start (${next.start})`,\r\n )\r\n }\r\n if (!resources.has(next.resourceId)) {\r\n throw new Error(\r\n `[skygraph/calendar] updateAssignment: resource \"${next.resourceId}\" not found`,\r\n )\r\n }\r\n assignments.set(id, next)\r\n commitAndPublish()\r\n }\r\n\r\n function removeAssignment(id: string): void {\r\n if (!assignments.has(id)) return\r\n assignments.delete(id)\r\n commitAndPublish()\r\n }\r\n\r\n function moveAssignment(id: string, deltaMs: number): void {\r\n const a = assignments.get(id)\r\n if (!a) throw new Error(`[skygraph/calendar] assignment \"${id}\" not found`)\r\n if (deltaMs === 0) return\r\n assignments.set(id, { ...a, start: a.start + deltaMs, end: a.end + deltaMs })\r\n commitAndPublish()\r\n }\r\n\r\n function resizeAssignment(\r\n id: string,\r\n side: 'start' | 'end',\r\n deltaMs: number,\r\n ): void {\r\n const a = assignments.get(id)\r\n if (!a) throw new Error(`[skygraph/calendar] assignment \"${id}\" not found`)\r\n if (deltaMs === 0) return\r\n let next: Assignment\r\n if (side === 'end') {\r\n const nextEnd = Math.max(a.start + 1, a.end + deltaMs)\r\n next = { ...a, end: nextEnd }\r\n } else {\r\n const nextStart = Math.min(a.end - 1, a.start + deltaMs)\r\n next = { ...a, start: nextStart }\r\n }\r\n assignments.set(id, next)\r\n commitAndPublish()\r\n }\r\n\r\n function getAssignment(id: string): Assignment | undefined {\r\n return assignments.get(id)\r\n }\r\n\r\n function getAssignments(): Assignment[] {\r\n return [...assignments.values()]\r\n }\r\n\r\n function setRules(next: readonly AvailabilityRule[]): void {\r\n rules = [...next]\r\n commitAndPublish()\r\n }\r\n\r\n function getRules(): AvailabilityRule[] {\r\n return [...rules]\r\n }\r\n\r\n function getConflicts(): Conflict[] {\r\n return [...conflicts]\r\n }\r\n\r\n function setScale(next: CalendarScale): void {\r\n if (next === scale) return\r\n scale = next\r\n commitAndPublish()\r\n }\r\n\r\n function getScale(): CalendarScale {\r\n return scale\r\n }\r\n\r\n function getState(): CalendarState {\r\n return {\r\n resources: [...resources.values()],\r\n assignments: [...assignments.values()],\r\n conflicts: [...conflicts],\r\n }\r\n }\r\n\r\n function clear(): void {\r\n resources.clear()\r\n assignments.clear()\r\n rules = []\r\n conflicts = []\r\n publish()\r\n }\r\n\r\n publish() // initial empty publish so subscribers see a stable shape\r\n\r\n return {\r\n id: engineId,\r\n addResource,\r\n removeResource,\r\n updateResource,\r\n getResource,\r\n getResources,\r\n addAssignment,\r\n updateAssignment,\r\n removeAssignment,\r\n moveAssignment,\r\n resizeAssignment,\r\n getAssignment,\r\n getAssignments,\r\n setRules,\r\n getRules,\r\n getConflicts,\r\n setScale,\r\n getScale,\r\n getState,\r\n subscribe,\r\n clear,\r\n }\r\n}\r\n"],"mappings":"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","names":["DAY_MS"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/tree/TreeEngine.ts"],"sourcesContent":["import type { Core } from '../../types'\r\nimport type {\r\n TreeKey,\r\n TreeNodeData,\r\n TreeFieldNames,\r\n TreeEngine,\r\n TreeEngineOptions,\r\n TreeState,\r\n} from './types'\r\n\r\nimport { TREE_PREFIX } from '../namespaces'\r\n\r\nlet treeCounter = 0\r\n\r\ninterface InternalNode {\r\n node: TreeNodeData\r\n key: TreeKey\r\n depth: number\r\n parentKey: TreeKey | null\r\n childKeys: TreeKey[]\r\n isLeaf: boolean\r\n}\r\n\r\nexport function createTree(core: Core, options?: TreeEngineOptions): TreeEngine {\r\n const treeId = `tr${treeCounter++}`\r\n const fn: Required<TreeFieldNames> = {\r\n key: options?.fieldNames?.key ?? 'key',\r\n title: options?.fieldNames?.title ?? 'title',\r\n children: options?.fieldNames?.children ?? 'children',\r\n }\r\n const checkStrictly = options?.checkStrictly ?? false\r\n\r\n let nodes: TreeNodeData[] = []\r\n let nodeMap = new Map<TreeKey, InternalNode>()\r\n\r\n let expandedKeys = new Set<TreeKey>(options?.defaultExpandedKeys ?? [])\r\n let checkedKeys = new Set<TreeKey>(options?.defaultCheckedKeys ?? [])\r\n let halfCheckedKeys = new Set<TreeKey>()\r\n let selectedKeys = new Set<TreeKey>(options?.defaultSelectedKeys ?? [])\r\n let loadedKeys = new Set<TreeKey>()\r\n let loadingKeys = new Set<TreeKey>()\r\n let filteredKeys: Set<TreeKey> | null = null\r\n\r\n function getKey(node: TreeNodeData): TreeKey {\r\n return (node as Record<string, unknown>)[fn.key] as TreeKey\r\n }\r\n\r\n function getChildren(node: TreeNodeData): TreeNodeData[] | undefined {\r\n return (node as Record<string, unknown>)[fn.children] as TreeNodeData[] | undefined\r\n }\r\n\r\n function buildMap(data: TreeNodeData[]): void {\r\n nodeMap = new Map()\r\n function walk(list: TreeNodeData[], parentKey: TreeKey | null, depth: number) {\r\n for (const n of list) {\r\n const k = getKey(n)\r\n const children = getChildren(n)\r\n const childKeys: TreeKey[] = []\r\n const isLeaf = n.isLeaf === true || (!children || children.length === 0)\r\n\r\n if (children && children.length > 0) {\r\n for (const ch of children) childKeys.push(getKey(ch))\r\n }\r\n\r\n nodeMap.set(k, { node: n, key: k, depth, parentKey, childKeys, isLeaf })\r\n\r\n if (children && children.length > 0) {\r\n walk(children, k, depth + 1)\r\n }\r\n }\r\n }\r\n walk(data, null, 0)\r\n }\r\n\r\n function getAllDescendantKeys(key: TreeKey): TreeKey[] {\r\n const result: TreeKey[] = []\r\n const internal = nodeMap.get(key)\r\n if (!internal) return result\r\n for (const ck of internal.childKeys) {\r\n result.push(ck)\r\n result.push(...getAllDescendantKeys(ck))\r\n }\r\n return result\r\n }\r\n\r\n function getAllAncestorKeys(key: TreeKey): TreeKey[] {\r\n const result: TreeKey[] = []\r\n let current = nodeMap.get(key)\r\n while (current && current.parentKey !== null) {\r\n result.push(current.parentKey)\r\n current = nodeMap.get(current.parentKey)\r\n }\r\n return result\r\n }\r\n\r\n function recomputeHalfChecked(): void {\r\n if (checkStrictly) {\r\n halfCheckedKeys = new Set()\r\n return\r\n }\r\n const half = new Set<TreeKey>()\r\n for (const [key, internal] of nodeMap) {\r\n if (internal.childKeys.length === 0) continue\r\n if (checkedKeys.has(key)) continue\r\n const allDescendants = getAllDescendantKeys(key)\r\n const someChecked = allDescendants.some((dk) => checkedKeys.has(dk))\r\n if (someChecked) half.add(key)\r\n }\r\n halfCheckedKeys = half\r\n }\r\n\r\n function cascadeCheck(key: TreeKey, checked: boolean): void {\r\n if (checkStrictly) {\r\n if (checked) checkedKeys.add(key)\r\n else checkedKeys.delete(key)\r\n return\r\n }\r\n\r\n const internal = nodeMap.get(key)\r\n if (!internal) return\r\n\r\n if (checked) {\r\n checkedKeys.add(key)\r\n const descendants = getAllDescendantKeys(key)\r\n for (const dk of descendants) {\r\n const dn = nodeMap.get(dk)\r\n if (dn && !dn.node.disabled && !dn.node.disableCheckbox) {\r\n checkedKeys.add(dk)\r\n }\r\n }\r\n } else {\r\n checkedKeys.delete(key)\r\n const descendants = getAllDescendantKeys(key)\r\n for (const dk of descendants) {\r\n checkedKeys.delete(dk)\r\n }\r\n }\r\n\r\n // Propagate up\r\n const ancestors = getAllAncestorKeys(key)\r\n for (const ak of ancestors) {\r\n const an = nodeMap.get(ak)\r\n if (!an) continue\r\n const allChildren = getAllDescendantKeys(ak)\r\n const enabledChildren = allChildren.filter((ck) => {\r\n const cn = nodeMap.get(ck)\r\n return cn && !cn.node.disabled && !cn.node.disableCheckbox\r\n })\r\n const allChecked = enabledChildren.length > 0 && enabledChildren.every((ck) => checkedKeys.has(ck))\r\n if (allChecked) {\r\n checkedKeys.add(ak)\r\n } else {\r\n checkedKeys.delete(ak)\r\n }\r\n }\r\n\r\n recomputeHalfChecked()\r\n }\r\n\r\n function removeFromTree(data: TreeNodeData[], targetKey: TreeKey): { remaining: TreeNodeData[]; removed: TreeNodeData | null } {\r\n let removed: TreeNodeData | null = null\r\n const remaining = data.filter((n) => {\r\n if (getKey(n) === targetKey) {\r\n removed = n\r\n return false\r\n }\r\n return true\r\n })\r\n if (!removed) {\r\n for (const n of remaining) {\r\n const children = getChildren(n)\r\n if (children && children.length > 0) {\r\n const result = removeFromTree(children, targetKey)\r\n if (result.removed) {\r\n ;(n as Record<string, unknown>)[fn.children] = result.remaining\r\n return { remaining, removed: result.removed }\r\n }\r\n }\r\n }\r\n }\r\n return { remaining, removed }\r\n }\r\n\r\n function insertIntoTree(\r\n data: TreeNodeData[],\r\n targetKey: TreeKey,\r\n node: TreeNodeData,\r\n position: -1 | 0 | 1,\r\n ): TreeNodeData[] {\r\n if (position === 0) {\r\n return data.map((n) => {\r\n if (getKey(n) === targetKey) {\r\n const children = getChildren(n) ?? []\r\n ;(n as Record<string, unknown>)[fn.children] = [...children, node]\r\n return n\r\n }\r\n const children = getChildren(n)\r\n if (children && children.length > 0) {\r\n ;(n as Record<string, unknown>)[fn.children] = insertIntoTree(children, targetKey, node, position)\r\n }\r\n return n\r\n })\r\n }\r\n\r\n const result: TreeNodeData[] = []\r\n for (const n of data) {\r\n if (getKey(n) === targetKey) {\r\n if (position === -1) {\r\n result.push(node, n)\r\n } else {\r\n result.push(n, node)\r\n }\r\n } else {\r\n const children = getChildren(n)\r\n if (children && children.length > 0) {\r\n ;(n as Record<string, unknown>)[fn.children] = insertIntoTree(children, targetKey, node, position)\r\n }\r\n result.push(n)\r\n }\r\n }\r\n return result\r\n }\r\n\r\n function publishState(): void {\r\n const path = (k: string) => `${TREE_PREFIX}${treeId}.${k}`\r\n core.batch(() => {\r\n core.set(path('expandedKeys'), [...expandedKeys])\r\n core.set(path('checkedKeys'), [...checkedKeys])\r\n core.set(path('halfCheckedKeys'), [...halfCheckedKeys])\r\n core.set(path('selectedKeys'), [...selectedKeys])\r\n core.set(path('loadedKeys'), [...loadedKeys])\r\n core.set(path('loadingKeys'), [...loadingKeys])\r\n })\r\n }\r\n\r\n function initDefaults(): void {\r\n if (options?.defaultExpandAll) {\r\n for (const [key, internal] of nodeMap) {\r\n if (!internal.isLeaf) expandedKeys.add(key)\r\n }\r\n }\r\n\r\n if (options?.defaultCheckedKeys && !checkStrictly) {\r\n for (const key of options.defaultCheckedKeys) {\r\n cascadeCheck(key, true)\r\n }\r\n }\r\n\r\n recomputeHalfChecked()\r\n publishState()\r\n }\r\n\r\n const engine: TreeEngine = {\r\n setData(data: TreeNodeData[]): void {\r\n nodes = data\r\n buildMap(data)\r\n initDefaults()\r\n },\r\n\r\n getData(): TreeNodeData[] {\r\n return nodes\r\n },\r\n\r\n // Expand\r\n expand(key: TreeKey): void {\r\n expandedKeys.add(key)\r\n publishState()\r\n },\r\n\r\n collapse(key: TreeKey): void {\r\n expandedKeys.delete(key)\r\n publishState()\r\n },\r\n\r\n toggleExpand(key: TreeKey): void {\r\n if (expandedKeys.has(key)) expandedKeys.delete(key)\r\n else expandedKeys.add(key)\r\n publishState()\r\n },\r\n\r\n setExpandedKeys(keys: TreeKey[]): void {\r\n expandedKeys = new Set(keys)\r\n publishState()\r\n },\r\n\r\n expandAll(): void {\r\n for (const [key, internal] of nodeMap) {\r\n if (!internal.isLeaf) expandedKeys.add(key)\r\n }\r\n publishState()\r\n },\r\n\r\n collapseAll(): void {\r\n expandedKeys = new Set()\r\n publishState()\r\n },\r\n\r\n // Check\r\n check(key: TreeKey): void {\r\n cascadeCheck(key, true)\r\n publishState()\r\n },\r\n\r\n uncheck(key: TreeKey): void {\r\n cascadeCheck(key, false)\r\n publishState()\r\n },\r\n\r\n toggleCheck(key: TreeKey): void {\r\n const checked = !checkedKeys.has(key)\r\n cascadeCheck(key, checked)\r\n publishState()\r\n },\r\n\r\n setCheckedKeys(keys: TreeKey[]): void {\r\n checkedKeys = new Set(keys)\r\n recomputeHalfChecked()\r\n publishState()\r\n },\r\n\r\n // Select\r\n select(key: TreeKey, multiple?: boolean): void {\r\n if (multiple) {\r\n if (selectedKeys.has(key)) selectedKeys.delete(key)\r\n else selectedKeys.add(key)\r\n } else {\r\n selectedKeys = new Set([key])\r\n }\r\n publishState()\r\n },\r\n\r\n deselect(key: TreeKey): void {\r\n selectedKeys.delete(key)\r\n publishState()\r\n },\r\n\r\n setSelectedKeys(keys: TreeKey[]): void {\r\n selectedKeys = new Set(keys)\r\n publishState()\r\n },\r\n\r\n // Async loading\r\n markLoading(key: TreeKey): void {\r\n loadingKeys.add(key)\r\n publishState()\r\n },\r\n\r\n markLoaded(key: TreeKey): void {\r\n loadingKeys.delete(key)\r\n loadedKeys.add(key)\r\n publishState()\r\n },\r\n\r\n addChildren(parentKey: TreeKey, children: TreeNodeData[]): void {\r\n const internal = nodeMap.get(parentKey)\r\n if (!internal) return\r\n ;(internal.node as Record<string, unknown>)[fn.children] = children\r\n buildMap(nodes)\r\n publishState()\r\n },\r\n\r\n // Drag & drop\r\n moveNode(dragKey: TreeKey, dropKey: TreeKey, position: -1 | 0 | 1): TreeNodeData[] | null {\r\n if (dragKey === dropKey) return null\r\n const ancestors = getAllAncestorKeys(dropKey)\r\n if (ancestors.includes(dragKey)) return null\r\n\r\n const { remaining, removed } = removeFromTree(nodes, dragKey)\r\n if (!removed) return null\r\n\r\n nodes = insertIntoTree(remaining, dropKey, removed, position)\r\n buildMap(nodes)\r\n publishState()\r\n return nodes\r\n },\r\n\r\n // Filter\r\n filterNodes(predicate: ((node: TreeNodeData) => boolean) | null): void {\r\n if (!predicate) {\r\n filteredKeys = null\r\n return\r\n }\r\n const matched = new Set<TreeKey>()\r\n for (const [key, internal] of nodeMap) {\r\n if (predicate(internal.node)) {\r\n matched.add(key)\r\n const ancestors = getAllAncestorKeys(key)\r\n for (const ak of ancestors) matched.add(ak)\r\n }\r\n }\r\n filteredKeys = matched\r\n },\r\n\r\n getFilteredKeys(): TreeKey[] | null {\r\n return filteredKeys ? [...filteredKeys] : null\r\n },\r\n\r\n // Query\r\n getNode(key: TreeKey): TreeNodeData | undefined {\r\n return nodeMap.get(key)?.node\r\n },\r\n\r\n getParentKey(key: TreeKey): TreeKey | null {\r\n return nodeMap.get(key)?.parentKey ?? null\r\n },\r\n\r\n getChildKeys(key: TreeKey): TreeKey[] {\r\n return nodeMap.get(key)?.childKeys ?? []\r\n },\r\n\r\n getAllKeys(): TreeKey[] {\r\n return [...nodeMap.keys()]\r\n },\r\n\r\n getLeafKeys(): TreeKey[] {\r\n const result: TreeKey[] = []\r\n for (const [key, internal] of nodeMap) {\r\n if (internal.isLeaf) result.push(key)\r\n }\r\n return result\r\n },\r\n\r\n getState(): TreeState {\r\n return {\r\n expandedKeys: [...expandedKeys],\r\n checkedKeys: [...checkedKeys],\r\n halfCheckedKeys: [...halfCheckedKeys],\r\n selectedKeys: [...selectedKeys],\r\n loadedKeys: [...loadedKeys],\r\n loadingKeys: [...loadingKeys],\r\n }\r\n },\r\n\r\n getFlatNodes() {\r\n const result: Array<{ node: TreeNodeData; key: TreeKey; depth: number; isLeaf: boolean; parentKey: TreeKey | null }> = []\r\n\r\n function walk(list: TreeNodeData[], parentKey: TreeKey | null, depth: number) {\r\n for (const n of list) {\r\n const k = getKey(n)\r\n if (filteredKeys && !filteredKeys.has(k)) continue\r\n\r\n const children = getChildren(n)\r\n const isLeaf = n.isLeaf === true || (!children || children.length === 0)\r\n\r\n result.push({ node: n, key: k, depth, isLeaf, parentKey })\r\n\r\n if (!isLeaf && expandedKeys.has(k) && children && children.length > 0) {\r\n walk(children, k, depth + 1)\r\n }\r\n }\r\n }\r\n\r\n walk(nodes, null, 0)\r\n return result\r\n },\r\n\r\n reset(): void {\r\n nodes = []\r\n nodeMap = new Map()\r\n expandedKeys = new Set()\r\n checkedKeys = new Set()\r\n halfCheckedKeys = new Set()\r\n selectedKeys = new Set()\r\n loadedKeys = new Set()\r\n loadingKeys = new Set()\r\n filteredKeys = null\r\n publishState()\r\n },\r\n }\r\n\r\n return engine\r\n}\r\n"],"mappings":"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","names":["children"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/virtual/measure.ts","../src/engines/virtual/index.ts"],"sourcesContent":["/**\r\n * Кэш измерений высоты для VirtualEngine с динамической высотой строк.\r\n *\r\n * Хранит реальные измеренные высоты `Map<index, number>` поверх эстимейта.\r\n * Префикс-сумма (offsets) пересобирается лениво при первом запросе после\r\n * любой инвалидации (resize / measure / reset). Подписки нужны React-адаптеру,\r\n * чтобы перерисоваться, когда измерение строки изменилось.\r\n */\r\n\r\nexport type MeasureCacheEvent = 'measure' | 'reset' | 'resize'\r\nexport type MeasureCacheListener = (event: MeasureCacheEvent) => void\r\n\r\nexport interface MeasureCacheOptions {\r\n itemCount: number\r\n estimate: number | ((index: number) => number)\r\n}\r\n\r\nexport interface MeasureCache {\r\n readonly itemCount: number\r\n /** Сколько строк уже было измерено. */\r\n readonly measuredCount: number\r\n\r\n setItemCount(count: number): void\r\n setEstimate(estimate: number | ((index: number) => number)): void\r\n\r\n /** Записать измеренную высоту. Возвращает `true`, если значение изменилось. */\r\n setMeasuredHeight(index: number, height: number): boolean\r\n /** Сбросить измерение для одной строки. */\r\n clearMeasured(index: number): boolean\r\n /** Сбросить все измерения. */\r\n reset(): void\r\n\r\n hasMeasured(index: number): boolean\r\n getMeasuredHeight(index: number): number | undefined\r\n\r\n /** Эстимейт высоты — без учёта измерений. */\r\n getEstimatedSize(index: number): number\r\n /** Эффективная высота строки (измерение или эстимейт). */\r\n getItemSize(index: number): number\r\n\r\n getItemOffset(index: number): number\r\n getItemAtOffset(offset: number): number\r\n getTotalHeight(): number\r\n\r\n subscribe(listener: MeasureCacheListener): () => void\r\n}\r\n\r\nexport function createMeasureCache(options: MeasureCacheOptions): MeasureCache {\r\n let itemCount = options.itemCount\r\n let estimate = options.estimate\r\n const measured = new Map<number, number>()\r\n let offsets: number[] | null = null\r\n let cachedTotal = 0\r\n const listeners = new Set<MeasureCacheListener>()\r\n\r\n const getEstimate = (index: number): number =>\r\n typeof estimate === 'number' ? estimate : estimate(index)\r\n\r\n const getItemSize = (index: number): number => {\r\n const m = measured.get(index)\r\n return m !== undefined ? m : getEstimate(index)\r\n }\r\n\r\n const rebuildOffsets = () => {\r\n if (offsets && offsets.length === itemCount) return\r\n const arr = new Array<number>(itemCount)\r\n let acc = 0\r\n for (let i = 0; i < itemCount; i++) {\r\n arr[i] = acc\r\n acc += getItemSize(i)\r\n }\r\n offsets = arr\r\n cachedTotal = acc\r\n }\r\n\r\n const getTotalHeight = (): number => {\r\n rebuildOffsets()\r\n return cachedTotal\r\n }\r\n\r\n const getItemOffset = (index: number): number => {\r\n if (index <= 0) return 0\r\n if (index >= itemCount) return getTotalHeight()\r\n rebuildOffsets()\r\n return offsets![index]!\r\n }\r\n\r\n const getItemAtOffset = (offset: number): number => {\r\n if (itemCount === 0) return 0\r\n rebuildOffsets()\r\n let lo = 0\r\n let hi = itemCount - 1\r\n while (lo < hi) {\r\n const mid = (lo + hi + 1) >>> 1\r\n if (offsets![mid]! <= offset) lo = mid\r\n else hi = mid - 1\r\n }\r\n return lo\r\n }\r\n\r\n const invalidate = (event: MeasureCacheEvent) => {\r\n offsets = null\r\n for (const l of listeners) l(event)\r\n }\r\n\r\n return {\r\n get itemCount() {\r\n return itemCount\r\n },\r\n get measuredCount() {\r\n return measured.size\r\n },\r\n\r\n setItemCount(count: number) {\r\n if (count === itemCount) return\r\n if (count < itemCount && measured.size > 0) {\r\n for (const k of [...measured.keys()]) {\r\n if (k >= count) measured.delete(k)\r\n }\r\n }\r\n itemCount = count\r\n invalidate('resize')\r\n },\r\n\r\n setEstimate(e: number | ((index: number) => number)) {\r\n estimate = e\r\n invalidate('reset')\r\n },\r\n\r\n setMeasuredHeight(index: number, height: number): boolean {\r\n if (index < 0 || index >= itemCount) return false\r\n if (!Number.isFinite(height) || height < 0) return false\r\n const prev = measured.get(index)\r\n if (prev === height) return false\r\n measured.set(index, height)\r\n invalidate('measure')\r\n return true\r\n },\r\n\r\n clearMeasured(index: number): boolean {\r\n const had = measured.delete(index)\r\n if (had) invalidate('measure')\r\n return had\r\n },\r\n\r\n reset() {\r\n if (measured.size === 0) return\r\n measured.clear()\r\n invalidate('reset')\r\n },\r\n\r\n hasMeasured(index: number) {\r\n return measured.has(index)\r\n },\r\n getMeasuredHeight(index: number) {\r\n return measured.get(index)\r\n },\r\n\r\n getEstimatedSize: getEstimate,\r\n getItemSize,\r\n getItemOffset,\r\n getItemAtOffset,\r\n getTotalHeight,\r\n\r\n subscribe(listener: MeasureCacheListener) {\r\n listeners.add(listener)\r\n return () => {\r\n listeners.delete(listener)\r\n }\r\n },\r\n }\r\n}\r\n","import { createMeasureCache, type MeasureCache } from './measure'\r\n\r\nexport type {\r\n MeasureCache,\r\n MeasureCacheEvent,\r\n MeasureCacheListener,\r\n MeasureCacheOptions,\r\n} from './measure'\r\nexport { createMeasureCache } from './measure'\r\n\r\nexport interface VirtualRange {\r\n startIndex: number\r\n endIndex: number\r\n offsetTop: number\r\n totalHeight: number\r\n visibleItems: VirtualItem[]\r\n}\r\n\r\nexport interface VirtualItem {\r\n index: number\r\n offsetTop: number\r\n height: number\r\n}\r\n\r\n/** Событие инвалидации, эмитимое VirtualEngine подписчикам. */\r\nexport type VirtualEngineEvent = 'measure' | 'reset' | 'resize'\r\nexport type VirtualEngineListener = (event: VirtualEngineEvent) => void\r\n\r\nexport interface VirtualEngineOptions {\r\n itemCount: number\r\n itemHeight: number | ((index: number) => number)\r\n overscan?: number\r\n}\r\n\r\nexport interface VirtualEngine {\r\n readonly itemCount: number\r\n readonly totalHeight: number\r\n /** Сколько строк прошли через `setMeasuredHeight`. */\r\n readonly measuredCount: number\r\n\r\n setItemCount(count: number): void\r\n setItemHeight(height: number | ((index: number) => number)): void\r\n\r\n /**\r\n * Записать реально измеренную (через ResizeObserver) высоту строки.\r\n * Возвращает `true`, если значение изменилось — полезно для контроля\r\n * количества `setState` в адаптере.\r\n */\r\n setMeasuredHeight(index: number, height: number): boolean\r\n /** Сбросить измерение для одной строки (высота вернётся к эстимейту). */\r\n clearMeasuredHeight(index: number): boolean\r\n /** Сбросить все измерения (например, при resize контейнера / смене темы). */\r\n resetMeasurements(): void\r\n /** Был ли индекс уже измерён. */\r\n hasMeasured(index: number): boolean\r\n /** Эстимейт высоты строки без учёта измерений. */\r\n getEstimatedSize(index: number): number\r\n /** Эффективная высота строки — измерение, если есть, иначе эстимейт. */\r\n getItemSize(index: number): number\r\n\r\n getRange(scrollTop: number, viewportHeight: number): VirtualRange\r\n getItemOffset(index: number): number\r\n getItemAtOffset(offset: number): number\r\n scrollToIndex(\r\n index: number,\r\n viewportHeight: number,\r\n align?: 'start' | 'center' | 'end',\r\n ): number\r\n\r\n /**\r\n * Подписаться на инвалидации (resize / measure / reset). Вызывается\r\n * только после реального изменения — повторные `setMeasuredHeight`\r\n * с тем же значением событие не эмитят.\r\n */\r\n subscribe(listener: VirtualEngineListener): () => void\r\n}\r\n\r\nexport function createVirtual(options: VirtualEngineOptions): VirtualEngine {\r\n let itemCount = options.itemCount\r\n let itemHeight = options.itemHeight\r\n const overscan = options.overscan ?? 5\r\n\r\n // Кэш создаётся лениво — для чисто фиксированной высоты без измерений\r\n // нам он не нужен, и мы сохраняем O(1) арифметику для миллионов строк.\r\n let cache: MeasureCache | null = null\r\n const listeners = new Set<VirtualEngineListener>()\r\n\r\n const ensureCache = (): MeasureCache => {\r\n if (cache) return cache\r\n cache = createMeasureCache({ itemCount, estimate: itemHeight })\r\n cache.subscribe((event) => {\r\n for (const l of listeners) l(event)\r\n })\r\n return cache\r\n }\r\n\r\n const isFastPath = (): boolean =>\r\n typeof itemHeight === 'number' && (cache === null || cache.measuredCount === 0)\r\n\r\n const getEstimate = (index: number): number =>\r\n typeof itemHeight === 'number' ? itemHeight : itemHeight(index)\r\n\r\n const getItemSize = (index: number): number => {\r\n if (cache) return cache.getItemSize(index)\r\n return getEstimate(index)\r\n }\r\n\r\n const getTotalHeight = (): number => {\r\n if (isFastPath()) return itemCount * (itemHeight as number)\r\n return ensureCache().getTotalHeight()\r\n }\r\n\r\n const getItemOffset = (index: number): number => {\r\n if (index <= 0) return 0\r\n if (index >= itemCount) return getTotalHeight()\r\n if (isFastPath()) return index * (itemHeight as number)\r\n return ensureCache().getItemOffset(index)\r\n }\r\n\r\n const getItemAtOffset = (offset: number): number => {\r\n if (itemCount === 0) return 0\r\n if (isFastPath()) {\r\n const h = itemHeight as number\r\n return Math.min(Math.floor(offset / h), itemCount - 1)\r\n }\r\n return ensureCache().getItemAtOffset(offset)\r\n }\r\n\r\n const getRange = (scrollTop: number, viewportHeight: number): VirtualRange => {\r\n if (itemCount === 0) {\r\n return { startIndex: 0, endIndex: 0, offsetTop: 0, totalHeight: 0, visibleItems: [] }\r\n }\r\n\r\n const total = getTotalHeight()\r\n const rawStart = getItemAtOffset(scrollTop)\r\n const startIndex = Math.max(0, rawStart - overscan)\r\n\r\n let endIndex = rawStart\r\n let accHeight = getItemOffset(rawStart) + getItemSize(rawStart)\r\n const bottomEdge = scrollTop + viewportHeight\r\n\r\n while (endIndex < itemCount - 1 && accHeight < bottomEdge) {\r\n endIndex++\r\n accHeight += getItemSize(endIndex)\r\n }\r\n endIndex = Math.min(itemCount - 1, endIndex + overscan)\r\n\r\n const visibleItems: VirtualItem[] = []\r\n for (let i = startIndex; i <= endIndex; i++) {\r\n visibleItems.push({\r\n index: i,\r\n offsetTop: getItemOffset(i),\r\n height: getItemSize(i),\r\n })\r\n }\r\n\r\n return {\r\n startIndex,\r\n endIndex,\r\n offsetTop: getItemOffset(startIndex),\r\n totalHeight: total,\r\n visibleItems,\r\n }\r\n }\r\n\r\n const scrollToIndex = (\r\n index: number,\r\n viewportHeight: number,\r\n align: 'start' | 'center' | 'end' = 'start',\r\n ): number => {\r\n const clamped = Math.max(0, Math.min(index, itemCount - 1))\r\n const offset = getItemOffset(clamped)\r\n const h = getItemSize(clamped)\r\n\r\n switch (align) {\r\n case 'center':\r\n return Math.max(0, offset - viewportHeight / 2 + h / 2)\r\n case 'end':\r\n return Math.max(0, offset - viewportHeight + h)\r\n default:\r\n return offset\r\n }\r\n }\r\n\r\n const emit = (event: VirtualEngineEvent) => {\r\n for (const l of listeners) l(event)\r\n }\r\n\r\n return {\r\n get itemCount() {\r\n return itemCount\r\n },\r\n get totalHeight() {\r\n return getTotalHeight()\r\n },\r\n get measuredCount() {\r\n return cache?.measuredCount ?? 0\r\n },\r\n\r\n setItemCount(count: number) {\r\n if (count === itemCount) return\r\n itemCount = count\r\n if (cache) {\r\n cache.setItemCount(count)\r\n } else {\r\n emit('resize')\r\n }\r\n },\r\n\r\n setItemHeight(height: number | ((index: number) => number)) {\r\n itemHeight = height\r\n if (cache) {\r\n cache.setEstimate(height)\r\n } else {\r\n emit('reset')\r\n }\r\n },\r\n\r\n setMeasuredHeight(index: number, height: number) {\r\n return ensureCache().setMeasuredHeight(index, height)\r\n },\r\n\r\n clearMeasuredHeight(index: number) {\r\n if (!cache) return false\r\n return cache.clearMeasured(index)\r\n },\r\n\r\n resetMeasurements() {\r\n if (cache) cache.reset()\r\n },\r\n\r\n hasMeasured(index: number) {\r\n return cache ? cache.hasMeasured(index) : false\r\n },\r\n\r\n getEstimatedSize: getEstimate,\r\n getItemSize,\r\n\r\n getRange,\r\n getItemOffset,\r\n getItemAtOffset,\r\n scrollToIndex,\r\n\r\n subscribe(listener: VirtualEngineListener) {\r\n listeners.add(listener)\r\n return () => {\r\n listeners.delete(listener)\r\n }\r\n },\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/form.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engines/form/index.ts","../src/engines/namespaces.ts","../src/engines/form/FormEngine.ts"],"sourcesContent":["export { createForm } from './FormEngine'\nexport type {\n FormEngine,\n FieldMeta,\n FieldMetaExtensions,\n FieldStatus,\n FormState,\n GetFieldValue,\n Rule,\n RuleFn,\n RuleObject,\n ValidationResult,\n FieldOptions,\n FormOptions,\n ValidationMode,\n FormListOperation,\n} from './types'\n","/**\n * Engine path namespace registry\n *\n * Every engine that stores state in the Core store under a `$`-prefixed\n * namespace MUST register its prefix here. This prevents two engines from\n * silently colliding on the same root path (e.g. two engines both writing\n * under `$meta.`).\n *\n * Rules:\n * 1. Prefixes MUST start with `$` and end with `.`.\n * 2. Prefixes MUST be unique across all engines.\n * 3. An engine MUST use `reservedPrefix(name)` at module load so\n * collisions surface at import time during dev/test.\n * 4. User data MUST NOT live under `$` prefixes — reserve them for engines.\n */\n\nconst reserved = new Map<string, string>()\n\n/**\n * Reserve (or look up) a prefix for an engine. Throws synchronously if the\n * same prefix is already owned by a different engine.\n */\nexport function reservePrefix(engine: string, prefix: string): string {\n if (!prefix.startsWith('$') || !prefix.endsWith('.')) {\n throw new Error(\n `[skygraph] engine \"${engine}\" tried to reserve invalid prefix \"${prefix}\". ` +\n `Engine prefixes must start with \"$\" and end with \".\".`,\n )\n }\n\n const existing = reserved.get(prefix)\n if (existing !== undefined && existing !== engine) {\n throw new Error(\n `[skygraph] prefix \"${prefix}\" is already owned by engine \"${existing}\", ` +\n `cannot reserve it for \"${engine}\". ` +\n `Pick a different prefix or update the registry.`,\n )\n }\n\n reserved.set(prefix, engine)\n return prefix\n}\n\n/** Snapshot of registered engine prefixes (debug / introspection). */\nexport function listReservedPrefixes(): ReadonlyMap<string, string> {\n return new Map(reserved)\n}\n\n/** Test-only helper. DO NOT call from engine code. */\nexport function __resetPrefixes(): void {\n reserved.clear()\n}\n\n// ── Canonical in-tree reservations ─────────────────────────────────────────\n//\n// Listed here so they are reserved even if the engine module is not loaded.\n// New engines must add their entry here and reference it from their\n// implementation via `reservePrefix(...)`.\n\nexport const FORM_META_PREFIX = reservePrefix('form', '$meta.')\nexport const TABLE_PREFIX = reservePrefix('table', '$table.')\nexport const TREE_PREFIX = reservePrefix('tree', '$tree.')\nexport const GRAPH_PREFIX = reservePrefix('graph', '$graph.')\nexport const CALENDAR_PREFIX = reservePrefix('calendar', '$calendar.')\n","import type { Core } from '../../types'\r\nimport type {\r\n FieldMeta,\r\n FieldOptions,\r\n FieldStatus,\r\n FormEngine,\r\n FormOptions,\r\n FormState,\r\n GetFieldValue,\r\n Rule,\r\n RuleFn,\r\n RuleObject,\r\n ValidationResult,\r\n} from './types'\r\n\r\nimport { FORM_META_PREFIX as META_PREFIX } from '../namespaces'\r\n\r\nfunction metaPath(name: string, field: string): string {\r\n return `${META_PREFIX}${name}.${field}`\r\n}\r\n\r\nfunction interpolateMessage(template: string, vars: Record<string, unknown>): string {\r\n return template.replace(/\\$\\{(\\w+)\\}/g, (_, key) => {\r\n return vars[key] != null ? String(vars[key]) : ''\r\n })\r\n}\r\n\r\nfunction compileRule(rule: Rule, templates?: Record<string, string>, fieldLabel?: string): RuleFn {\r\n if (typeof rule === 'function') return rule\r\n\r\n const obj = rule as RuleObject\r\n const vars: Record<string, unknown> = { label: fieldLabel ?? 'Field' }\r\n\r\n return (value: unknown, getFieldValue: GetFieldValue): string | null | Promise<string | null> => {\r\n if (obj.required) {\r\n if (value === undefined || value === null || value === '') {\r\n const tpl = templates?.required ?? obj.message\r\n return tpl ? interpolateMessage(tpl, vars) : (obj.message ?? 'This field is required')\r\n }\r\n }\r\n\r\n if (value === undefined || value === null || value === '') return null\r\n\r\n if (obj.type) {\r\n switch (obj.type) {\r\n case 'string':\r\n if (typeof value !== 'string') return obj.message ?? 'Must be a string'\r\n break\r\n case 'number':\r\n if (typeof value !== 'number' || isNaN(value)) return obj.message ?? 'Must be a number'\r\n break\r\n case 'email':\r\n if (typeof value !== 'string' || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value))\r\n return obj.message ?? 'Invalid email'\r\n break\r\n case 'url':\r\n try {\r\n new URL(value as string)\r\n } catch {\r\n return obj.message ?? 'Invalid URL'\r\n }\r\n break\r\n case 'boolean':\r\n if (typeof value !== 'boolean') return obj.message ?? 'Must be a boolean'\r\n break\r\n }\r\n }\r\n\r\n if (obj.min !== undefined) {\r\n vars.min = obj.min\r\n if (typeof value === 'string' && value.length < obj.min) {\r\n const tpl = templates?.min ?? obj.message\r\n return tpl ? interpolateMessage(tpl, vars) : (obj.message ?? `Minimum ${obj.min} characters`)\r\n }\r\n if (typeof value === 'number' && value < obj.min)\r\n return obj.message ?? `Minimum value is ${obj.min}`\r\n }\r\n\r\n if (obj.max !== undefined) {\r\n vars.max = obj.max\r\n if (typeof value === 'string' && value.length > obj.max) {\r\n const tpl = templates?.max ?? obj.message\r\n return tpl ? interpolateMessage(tpl, vars) : (obj.message ?? `Maximum ${obj.max} characters`)\r\n }\r\n if (typeof value === 'number' && value > obj.max)\r\n return obj.message ?? `Maximum value is ${obj.max}`\r\n }\r\n\r\n if (obj.pattern) {\r\n if (typeof value === 'string' && !obj.pattern.test(value))\r\n return obj.message ?? 'Invalid format'\r\n }\r\n\r\n if (obj.validator) {\r\n return obj.validator(value, getFieldValue)\r\n }\r\n\r\n return null\r\n }\r\n}\r\n\r\nfunction computeStatus(meta: { errors: string[]; warnings: string[]; validating: boolean }): FieldStatus {\r\n if (meta.validating) return 'validating'\r\n if (meta.errors.length > 0) return 'error'\r\n if (meta.warnings.length > 0) return 'warning'\r\n return undefined\r\n}\r\n\r\ninterface CompiledRule {\r\n original: Rule\r\n fn: RuleFn\r\n}\r\n\r\ninterface FieldRecord {\r\n rules: CompiledRule[]\r\n warningRules: CompiledRule[]\r\n options: FieldOptions\r\n abortController: AbortController | null\r\n}\r\n\r\nexport function createForm(core: Core, options?: FormOptions): FormEngine {\r\n const fields = new Map<string, FieldRecord>()\r\n const depMap = new Map<string, string[]>()\r\n const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>()\r\n const preservedValues = new Map<string, unknown>()\r\n let isSubmitting = false\r\n\r\n if (options?.defaultValues) {\r\n for (const [key, value] of Object.entries(options.defaultValues)) {\r\n core.set(key, value)\r\n }\r\n }\r\n\r\n function setMeta(name: string, meta: Partial<Record<string, unknown>>): void {\r\n for (const [key, value] of Object.entries(meta)) {\r\n core.set(metaPath(name, key), value)\r\n }\r\n }\r\n\r\n function getMeta(name: string): FieldMeta {\r\n const errors = (core.get(metaPath(name, 'errors')) as string[]) ?? []\r\n const warnings = (core.get(metaPath(name, 'warnings')) as string[]) ?? []\r\n const validating = (core.get(metaPath(name, 'validating')) as boolean) ?? false\r\n const touched = (core.get(metaPath(name, 'touched')) as boolean) ?? false\r\n const dirty = (core.get(metaPath(name, 'dirty')) as boolean) ?? false\r\n\r\n return {\r\n touched,\r\n dirty,\r\n errors,\r\n warnings,\r\n validating,\r\n status: computeStatus({ errors, warnings, validating }),\r\n error: errors[0] ?? null,\r\n }\r\n }\r\n\r\n function initMeta(name: string): void {\r\n setMeta(name, {\r\n touched: false,\r\n dirty: false,\r\n errors: [],\r\n warnings: [],\r\n validating: false,\r\n })\r\n }\r\n\r\n const getFieldValue: GetFieldValue = (fieldName: string) => core.get(fieldName)\r\n\r\n function fireValuesChange(changedName: string): void {\r\n if (!options?.onValuesChange) return\r\n const changed: Record<string, unknown> = { [changedName]: core.get(changedName) }\r\n const all: Record<string, unknown> = {}\r\n for (const n of fields.keys()) all[n] = core.get(n)\r\n options.onValuesChange(changed, all)\r\n }\r\n\r\n function fireFieldsChange(changedName: string): void {\r\n if (!options?.onFieldsChange) return\r\n const meta = getMeta(changedName)\r\n options.onFieldsChange([{\r\n name: changedName,\r\n value: core.get(changedName),\r\n errors: meta.errors,\r\n }])\r\n }\r\n\r\n async function runValidation(name: string): Promise<string[]> {\r\n const record = fields.get(name)\r\n if (!record) return []\r\n\r\n const value = core.get(name)\r\n const validateFirst = record.options.validateFirst ?? options?.validateFirst ?? false\r\n\r\n record.abortController?.abort()\r\n const controller = new AbortController()\r\n record.abortController = controller\r\n\r\n const errors: string[] = []\r\n\r\n for (const rule of record.rules) {\r\n if (controller.signal.aborted) return []\r\n\r\n const result = rule.fn(value, getFieldValue)\r\n\r\n if (result instanceof Promise) {\r\n setMeta(name, { validating: true })\r\n try {\r\n const asyncResult = await result\r\n if (controller.signal.aborted) return []\r\n if (asyncResult) {\r\n errors.push(asyncResult)\r\n if (validateFirst) break\r\n }\r\n } catch {\r\n if (controller.signal.aborted) return []\r\n errors.push('Validation failed')\r\n if (validateFirst) break\r\n }\r\n } else if (result) {\r\n errors.push(result)\r\n if (validateFirst) break\r\n }\r\n }\r\n\r\n const warnings: string[] = []\r\n for (const rule of record.warningRules) {\r\n if (controller.signal.aborted) return []\r\n const result = rule.fn(value, getFieldValue)\r\n if (result instanceof Promise) {\r\n try {\r\n const asyncResult = await result\r\n if (controller.signal.aborted) return []\r\n if (asyncResult) warnings.push(asyncResult)\r\n } catch {\r\n // skip\r\n }\r\n } else if (result) {\r\n warnings.push(result)\r\n }\r\n }\r\n\r\n if (!controller.signal.aborted) {\r\n setMeta(name, { errors, warnings, validating: false })\r\n fireFieldsChange(name)\r\n }\r\n\r\n return errors\r\n }\r\n\r\n async function validateDependents(name: string): Promise<void> {\r\n for (const [target, deps] of depMap) {\r\n if (deps.includes(name)) {\r\n await runValidation(target)\r\n }\r\n }\r\n }\r\n\r\n const form: FormEngine = {\r\n register(name: string, fieldOptions?: FieldOptions): void {\r\n const opts = fieldOptions ?? {}\r\n const templates = options?.validateMessages\r\n const label = opts.label\r\n\r\n fields.set(name, {\r\n rules: opts.rules\r\n ? opts.rules.map((r) => ({ original: r, fn: compileRule(r, templates, label) }))\r\n : [],\r\n warningRules: opts.warningRules\r\n ? opts.warningRules.map((r) => ({ original: r, fn: compileRule(r, templates, label) }))\r\n : [],\r\n options: opts,\r\n abortController: null,\r\n })\r\n\r\n if (preservedValues.has(name)) {\r\n core.set(name, preservedValues.get(name))\r\n preservedValues.delete(name)\r\n } else if (opts.defaultValue !== undefined && core.get(name) === undefined) {\r\n core.set(name, opts.defaultValue)\r\n }\r\n\r\n if (opts.dependencies) {\r\n depMap.set(name, [...opts.dependencies])\r\n }\r\n\r\n core.batch(() => {\r\n initMeta(name)\r\n })\r\n },\r\n\r\n unregister(name: string): void {\r\n const record = fields.get(name)\r\n if (!record) return\r\n record.abortController?.abort()\r\n\r\n const timer = debounceTimers.get(name)\r\n if (timer) {\r\n clearTimeout(timer)\r\n debounceTimers.delete(name)\r\n }\r\n\r\n if (record.options.preserve) {\r\n preservedValues.set(name, core.get(name))\r\n }\r\n\r\n fields.delete(name)\r\n depMap.delete(name)\r\n },\r\n\r\n setValue(name: string, value: unknown): void {\r\n core.transaction(() => {\r\n core.set(name, value)\r\n setMeta(name, { dirty: true, touched: true })\r\n })\r\n\r\n fireValuesChange(name)\r\n\r\n const mode = fields.get(name)?.options.validateOn ?? options?.validateOn ?? 'change'\r\n if (mode === 'change') {\r\n const debounceMs = options?.asyncDebounceMs\r\n if (debounceMs && debounceMs > 0) {\r\n const existing = debounceTimers.get(name)\r\n if (existing) clearTimeout(existing)\r\n debounceTimers.set(\r\n name,\r\n setTimeout(() => {\r\n debounceTimers.delete(name)\r\n runValidation(name).then(() => validateDependents(name))\r\n }, debounceMs),\r\n )\r\n } else {\r\n runValidation(name).then(() => validateDependents(name))\r\n }\r\n }\r\n },\r\n\r\n getValue(name: string): unknown {\r\n return core.get(name)\r\n },\r\n\r\n onFieldBlur(name: string): void {\r\n setMeta(name, { touched: true })\r\n const mode = fields.get(name)?.options.validateOn ?? options?.validateOn ?? 'change'\r\n if (mode === 'blur') {\r\n runValidation(name).then(() => validateDependents(name))\r\n }\r\n },\r\n\r\n setFieldsValue(values: Record<string, unknown>): void {\r\n core.batch(() => {\r\n for (const [name, value] of Object.entries(values)) {\r\n core.set(name, value)\r\n if (fields.has(name)) {\r\n setMeta(name, { dirty: true, touched: true })\r\n }\r\n }\r\n })\r\n\r\n for (const name of Object.keys(values)) {\r\n fireValuesChange(name)\r\n }\r\n },\r\n\r\n getFieldsValue(): Record<string, unknown> {\r\n const values: Record<string, unknown> = {}\r\n for (const name of fields.keys()) {\r\n values[name] = core.get(name)\r\n }\r\n return values\r\n },\r\n\r\n getFieldState(name: string): FieldMeta {\r\n return getMeta(name)\r\n },\r\n\r\n getFormState(): FormState {\r\n let isDirty = false\r\n let isValid = true\r\n let isValidating = false\r\n\r\n for (const name of fields.keys()) {\r\n const meta = getMeta(name)\r\n if (meta.dirty) isDirty = true\r\n if (meta.errors.length > 0) isValid = false\r\n if (meta.validating) isValidating = true\r\n }\r\n\r\n return { isDirty, isValid, isSubmitting, isValidating }\r\n },\r\n\r\n addRule(name: string, rule: Rule): void {\r\n const record = fields.get(name)\r\n if (!record) return\r\n record.rules.push({\r\n original: rule,\r\n fn: compileRule(rule, options?.validateMessages, record.options.label),\r\n })\r\n },\r\n\r\n removeRule(name: string, rule: Rule): void {\r\n const record = fields.get(name)\r\n if (!record) return\r\n const idx = record.rules.findIndex((r) => r.original === rule)\r\n if (idx !== -1) record.rules.splice(idx, 1)\r\n },\r\n\r\n depends(target: string, deps: string[]): void {\r\n depMap.set(target, [...deps])\r\n },\r\n\r\n async validate(name?: string): Promise<ValidationResult> {\r\n const errors: Record<string, string[]> = {}\r\n const warnings: Record<string, string[]> = {}\r\n\r\n if (name) {\r\n const errs = await runValidation(name)\r\n if (errs.length > 0) errors[name] = errs\r\n const meta = getMeta(name)\r\n if (meta.warnings.length > 0) warnings[name] = meta.warnings\r\n } else {\r\n const promises: Promise<void>[] = []\r\n for (const fieldName of fields.keys()) {\r\n promises.push(\r\n runValidation(fieldName).then((errs) => {\r\n if (errs.length > 0) errors[fieldName] = errs\r\n const meta = getMeta(fieldName)\r\n if (meta.warnings.length > 0) warnings[fieldName] = meta.warnings\r\n }),\r\n )\r\n }\r\n await Promise.all(promises)\r\n }\r\n\r\n return { valid: Object.keys(errors).length === 0, errors, warnings }\r\n },\r\n\r\n async submit(handler: (values: Record<string, unknown>) => Promise<void>): Promise<void> {\r\n isSubmitting = true\r\n\r\n core.batch(() => {\r\n for (const name of fields.keys()) {\r\n setMeta(name, { touched: true })\r\n }\r\n })\r\n\r\n const result = await form.validate()\r\n\r\n if (!result.valid) {\r\n isSubmitting = false\r\n return\r\n }\r\n\r\n const values: Record<string, unknown> = {}\r\n for (const name of fields.keys()) {\r\n values[name] = core.get(name)\r\n }\r\n\r\n try {\r\n await handler(values)\r\n } finally {\r\n isSubmitting = false\r\n }\r\n },\r\n\r\n reset(values?: Record<string, unknown>): void {\r\n core.batch(() => {\r\n for (const [name, record] of fields) {\r\n record.abortController?.abort()\r\n record.abortController = null\r\n\r\n const resetValue =\r\n values?.[name] ??\r\n options?.defaultValues?.[name] ??\r\n record.options.defaultValue ??\r\n undefined\r\n core.set(name, resetValue)\r\n initMeta(name)\r\n }\r\n })\r\n preservedValues.clear()\r\n },\r\n\r\n getFieldNames(): string[] {\r\n return [...fields.keys()]\r\n },\r\n\r\n // Manual error/warning control\r\n setFieldError(name: string, errs: string | string[]): void {\r\n const arr = typeof errs === 'string' ? [errs] : errs\r\n setMeta(name, { errors: arr })\r\n fireFieldsChange(name)\r\n },\r\n\r\n setFieldWarning(name: string, warns: string | string[]): void {\r\n const arr = typeof warns === 'string' ? [warns] : warns\r\n setMeta(name, { warnings: arr })\r\n },\r\n\r\n clearFieldErrors(name: string): void {\r\n setMeta(name, { errors: [], warnings: [] })\r\n fireFieldsChange(name)\r\n },\r\n\r\n getFieldErrors(name: string): string[] {\r\n return getMeta(name).errors\r\n },\r\n\r\n getFieldWarnings(name: string): string[] {\r\n return getMeta(name).warnings\r\n },\r\n\r\n isFieldTouched(name: string): boolean {\r\n return getMeta(name).touched\r\n },\r\n\r\n isFieldValidating(name: string): boolean {\r\n return getMeta(name).validating\r\n },\r\n\r\n // List operations\r\n getListValue(name: string): unknown[] {\r\n const val = core.get(name)\r\n return Array.isArray(val) ? val : []\r\n },\r\n\r\n listAdd(name: string, defaultValue?: unknown, insertIndex?: number): void {\r\n const current = form.getListValue(name)\r\n if (insertIndex !== undefined && insertIndex >= 0 && insertIndex <= current.length) {\r\n const next = [...current]\r\n next.splice(insertIndex, 0, defaultValue ?? null)\r\n core.set(name, next)\r\n } else {\r\n core.set(name, [...current, defaultValue ?? null])\r\n }\r\n },\r\n\r\n listRemove(name: string, index: number | number[]): void {\r\n const current = form.getListValue(name)\r\n if (Array.isArray(index)) {\r\n const indices = new Set(index)\r\n core.set(name, current.filter((_, i) => !indices.has(i)))\r\n } else {\r\n core.set(name, current.filter((_, i) => i !== index))\r\n }\r\n },\r\n\r\n listMove(name: string, from: number, to: number): void {\r\n const current = [...form.getListValue(name)]\r\n if (from < 0 || from >= current.length || to < 0 || to >= current.length) return\r\n const [item] = current.splice(from, 1)\r\n current.splice(to, 0, item)\r\n core.set(name, current)\r\n },\r\n\r\n listReplace(name: string, values: unknown[]): void {\r\n core.set(name, [...values])\r\n },\r\n }\r\n\r\n return form\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/engines/form/index.ts","../src/engines/namespaces.ts","../src/engines/form/FormEngine.ts"],"sourcesContent":["export { createForm } from './FormEngine'\r\nexport type {\r\n FormEngine,\r\n FieldMeta,\r\n FieldMetaExtensions,\r\n FieldStatus,\r\n FormState,\r\n GetFieldValue,\r\n Rule,\r\n RuleFn,\r\n RuleObject,\r\n ValidationResult,\r\n FieldOptions,\r\n FormOptions,\r\n ValidationMode,\r\n FormListOperation,\r\n} from './types'\r\n","/**\n * Engine path namespace registry\n *\n * Every engine that stores state in the Core store under a `$`-prefixed\n * namespace MUST register its prefix here. This prevents two engines from\n * silently colliding on the same root path (e.g. two engines both writing\n * under `$meta.`).\n *\n * Rules:\n * 1. Prefixes MUST start with `$` and end with `.`.\n * 2. Prefixes MUST be unique across all engines.\n * 3. An engine MUST use `reservedPrefix(name)` at module load so\n * collisions surface at import time during dev/test.\n * 4. User data MUST NOT live under `$` prefixes — reserve them for engines.\n */\n\nconst reserved = new Map<string, string>()\n\n/**\n * Reserve (or look up) a prefix for an engine. Throws synchronously if the\n * same prefix is already owned by a different engine.\n */\nexport function reservePrefix(engine: string, prefix: string): string {\n if (!prefix.startsWith('$') || !prefix.endsWith('.')) {\n throw new Error(\n `[skygraph] engine \"${engine}\" tried to reserve invalid prefix \"${prefix}\". ` +\n `Engine prefixes must start with \"$\" and end with \".\".`,\n )\n }\n\n const existing = reserved.get(prefix)\n if (existing !== undefined && existing !== engine) {\n throw new Error(\n `[skygraph] prefix \"${prefix}\" is already owned by engine \"${existing}\", ` +\n `cannot reserve it for \"${engine}\". ` +\n `Pick a different prefix or update the registry.`,\n )\n }\n\n reserved.set(prefix, engine)\n return prefix\n}\n\n/** Snapshot of registered engine prefixes (debug / introspection). */\nexport function listReservedPrefixes(): ReadonlyMap<string, string> {\n return new Map(reserved)\n}\n\n/** Test-only helper. DO NOT call from engine code. */\nexport function __resetPrefixes(): void {\n reserved.clear()\n}\n\n// ── Canonical in-tree reservations ─────────────────────────────────────────\n//\n// Listed here so they are reserved even if the engine module is not loaded.\n// New engines must add their entry here and reference it from their\n// implementation via `reservePrefix(...)`.\n\nexport const FORM_META_PREFIX = reservePrefix('form', '$meta.')\nexport const TABLE_PREFIX = reservePrefix('table', '$table.')\nexport const TREE_PREFIX = reservePrefix('tree', '$tree.')\nexport const GRAPH_PREFIX = reservePrefix('graph', '$graph.')\nexport const CALENDAR_PREFIX = reservePrefix('calendar', '$calendar.')\n","import type { Core } from '../../types'\r\nimport type {\r\n FieldMeta,\r\n FieldOptions,\r\n FieldStatus,\r\n FormEngine,\r\n FormOptions,\r\n FormState,\r\n GetFieldValue,\r\n Rule,\r\n RuleFn,\r\n RuleObject,\r\n ValidationResult,\r\n} from './types'\r\n\r\nimport { FORM_META_PREFIX as META_PREFIX } from '../namespaces'\r\n\r\nfunction metaPath(name: string, field: string): string {\r\n return `${META_PREFIX}${name}.${field}`\r\n}\r\n\r\nfunction interpolateMessage(template: string, vars: Record<string, unknown>): string {\r\n return template.replace(/\\$\\{(\\w+)\\}/g, (_, key) => {\r\n return vars[key] != null ? String(vars[key]) : ''\r\n })\r\n}\r\n\r\nfunction compileRule(rule: Rule, templates?: Record<string, string>, fieldLabel?: string): RuleFn {\r\n if (typeof rule === 'function') return rule\r\n\r\n const obj = rule as RuleObject\r\n const vars: Record<string, unknown> = { label: fieldLabel ?? 'Field' }\r\n\r\n return (value: unknown, getFieldValue: GetFieldValue): string | null | Promise<string | null> => {\r\n if (obj.required) {\r\n if (value === undefined || value === null || value === '') {\r\n const tpl = templates?.required ?? obj.message\r\n return tpl ? interpolateMessage(tpl, vars) : (obj.message ?? 'This field is required')\r\n }\r\n }\r\n\r\n if (value === undefined || value === null || value === '') return null\r\n\r\n if (obj.type) {\r\n switch (obj.type) {\r\n case 'string':\r\n if (typeof value !== 'string') return obj.message ?? 'Must be a string'\r\n break\r\n case 'number':\r\n if (typeof value !== 'number' || isNaN(value)) return obj.message ?? 'Must be a number'\r\n break\r\n case 'email':\r\n if (typeof value !== 'string' || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value))\r\n return obj.message ?? 'Invalid email'\r\n break\r\n case 'url':\r\n try {\r\n new URL(value as string)\r\n } catch {\r\n return obj.message ?? 'Invalid URL'\r\n }\r\n break\r\n case 'boolean':\r\n if (typeof value !== 'boolean') return obj.message ?? 'Must be a boolean'\r\n break\r\n }\r\n }\r\n\r\n if (obj.min !== undefined) {\r\n vars.min = obj.min\r\n if (typeof value === 'string' && value.length < obj.min) {\r\n const tpl = templates?.min ?? obj.message\r\n return tpl ? interpolateMessage(tpl, vars) : (obj.message ?? `Minimum ${obj.min} characters`)\r\n }\r\n if (typeof value === 'number' && value < obj.min)\r\n return obj.message ?? `Minimum value is ${obj.min}`\r\n }\r\n\r\n if (obj.max !== undefined) {\r\n vars.max = obj.max\r\n if (typeof value === 'string' && value.length > obj.max) {\r\n const tpl = templates?.max ?? obj.message\r\n return tpl ? interpolateMessage(tpl, vars) : (obj.message ?? `Maximum ${obj.max} characters`)\r\n }\r\n if (typeof value === 'number' && value > obj.max)\r\n return obj.message ?? `Maximum value is ${obj.max}`\r\n }\r\n\r\n if (obj.pattern) {\r\n if (typeof value === 'string' && !obj.pattern.test(value))\r\n return obj.message ?? 'Invalid format'\r\n }\r\n\r\n if (obj.validator) {\r\n return obj.validator(value, getFieldValue)\r\n }\r\n\r\n return null\r\n }\r\n}\r\n\r\nfunction computeStatus(meta: { errors: string[]; warnings: string[]; validating: boolean }): FieldStatus {\r\n if (meta.validating) return 'validating'\r\n if (meta.errors.length > 0) return 'error'\r\n if (meta.warnings.length > 0) return 'warning'\r\n return undefined\r\n}\r\n\r\ninterface CompiledRule {\r\n original: Rule\r\n fn: RuleFn\r\n}\r\n\r\ninterface FieldRecord {\r\n rules: CompiledRule[]\r\n warningRules: CompiledRule[]\r\n options: FieldOptions\r\n abortController: AbortController | null\r\n}\r\n\r\nexport function createForm(core: Core, options?: FormOptions): FormEngine {\r\n const fields = new Map<string, FieldRecord>()\r\n const depMap = new Map<string, string[]>()\r\n const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>()\r\n const preservedValues = new Map<string, unknown>()\r\n let isSubmitting = false\r\n\r\n if (options?.defaultValues) {\r\n for (const [key, value] of Object.entries(options.defaultValues)) {\r\n core.set(key, value)\r\n }\r\n }\r\n\r\n function setMeta(name: string, meta: Partial<Record<string, unknown>>): void {\r\n for (const [key, value] of Object.entries(meta)) {\r\n core.set(metaPath(name, key), value)\r\n }\r\n }\r\n\r\n function getMeta(name: string): FieldMeta {\r\n const errors = (core.get(metaPath(name, 'errors')) as string[]) ?? []\r\n const warnings = (core.get(metaPath(name, 'warnings')) as string[]) ?? []\r\n const validating = (core.get(metaPath(name, 'validating')) as boolean) ?? false\r\n const touched = (core.get(metaPath(name, 'touched')) as boolean) ?? false\r\n const dirty = (core.get(metaPath(name, 'dirty')) as boolean) ?? false\r\n\r\n return {\r\n touched,\r\n dirty,\r\n errors,\r\n warnings,\r\n validating,\r\n status: computeStatus({ errors, warnings, validating }),\r\n error: errors[0] ?? null,\r\n }\r\n }\r\n\r\n function initMeta(name: string): void {\r\n setMeta(name, {\r\n touched: false,\r\n dirty: false,\r\n errors: [],\r\n warnings: [],\r\n validating: false,\r\n })\r\n }\r\n\r\n const getFieldValue: GetFieldValue = (fieldName: string) => core.get(fieldName)\r\n\r\n function fireValuesChange(changedName: string): void {\r\n if (!options?.onValuesChange) return\r\n const changed: Record<string, unknown> = { [changedName]: core.get(changedName) }\r\n const all: Record<string, unknown> = {}\r\n for (const n of fields.keys()) all[n] = core.get(n)\r\n options.onValuesChange(changed, all)\r\n }\r\n\r\n function fireFieldsChange(changedName: string): void {\r\n if (!options?.onFieldsChange) return\r\n const meta = getMeta(changedName)\r\n options.onFieldsChange([{\r\n name: changedName,\r\n value: core.get(changedName),\r\n errors: meta.errors,\r\n }])\r\n }\r\n\r\n async function runValidation(name: string): Promise<string[]> {\r\n const record = fields.get(name)\r\n if (!record) return []\r\n\r\n const value = core.get(name)\r\n const validateFirst = record.options.validateFirst ?? options?.validateFirst ?? false\r\n\r\n record.abortController?.abort()\r\n const controller = new AbortController()\r\n record.abortController = controller\r\n\r\n const errors: string[] = []\r\n\r\n for (const rule of record.rules) {\r\n if (controller.signal.aborted) return []\r\n\r\n const result = rule.fn(value, getFieldValue)\r\n\r\n if (result instanceof Promise) {\r\n setMeta(name, { validating: true })\r\n try {\r\n const asyncResult = await result\r\n if (controller.signal.aborted) return []\r\n if (asyncResult) {\r\n errors.push(asyncResult)\r\n if (validateFirst) break\r\n }\r\n } catch {\r\n if (controller.signal.aborted) return []\r\n errors.push('Validation failed')\r\n if (validateFirst) break\r\n }\r\n } else if (result) {\r\n errors.push(result)\r\n if (validateFirst) break\r\n }\r\n }\r\n\r\n const warnings: string[] = []\r\n for (const rule of record.warningRules) {\r\n if (controller.signal.aborted) return []\r\n const result = rule.fn(value, getFieldValue)\r\n if (result instanceof Promise) {\r\n try {\r\n const asyncResult = await result\r\n if (controller.signal.aborted) return []\r\n if (asyncResult) warnings.push(asyncResult)\r\n } catch {\r\n // skip\r\n }\r\n } else if (result) {\r\n warnings.push(result)\r\n }\r\n }\r\n\r\n if (!controller.signal.aborted) {\r\n setMeta(name, { errors, warnings, validating: false })\r\n fireFieldsChange(name)\r\n }\r\n\r\n return errors\r\n }\r\n\r\n async function validateDependents(name: string): Promise<void> {\r\n for (const [target, deps] of depMap) {\r\n if (deps.includes(name)) {\r\n await runValidation(target)\r\n }\r\n }\r\n }\r\n\r\n const form: FormEngine = {\r\n register(name: string, fieldOptions?: FieldOptions): void {\r\n const opts = fieldOptions ?? {}\r\n const templates = options?.validateMessages\r\n const label = opts.label\r\n\r\n fields.set(name, {\r\n rules: opts.rules\r\n ? opts.rules.map((r) => ({ original: r, fn: compileRule(r, templates, label) }))\r\n : [],\r\n warningRules: opts.warningRules\r\n ? opts.warningRules.map((r) => ({ original: r, fn: compileRule(r, templates, label) }))\r\n : [],\r\n options: opts,\r\n abortController: null,\r\n })\r\n\r\n if (preservedValues.has(name)) {\r\n core.set(name, preservedValues.get(name))\r\n preservedValues.delete(name)\r\n } else if (opts.defaultValue !== undefined && core.get(name) === undefined) {\r\n core.set(name, opts.defaultValue)\r\n }\r\n\r\n if (opts.dependencies) {\r\n depMap.set(name, [...opts.dependencies])\r\n }\r\n\r\n core.batch(() => {\r\n initMeta(name)\r\n })\r\n },\r\n\r\n unregister(name: string): void {\r\n const record = fields.get(name)\r\n if (!record) return\r\n record.abortController?.abort()\r\n\r\n const timer = debounceTimers.get(name)\r\n if (timer) {\r\n clearTimeout(timer)\r\n debounceTimers.delete(name)\r\n }\r\n\r\n if (record.options.preserve) {\r\n preservedValues.set(name, core.get(name))\r\n }\r\n\r\n fields.delete(name)\r\n depMap.delete(name)\r\n },\r\n\r\n setValue(name: string, value: unknown): void {\r\n core.transaction(() => {\r\n core.set(name, value)\r\n setMeta(name, { dirty: true, touched: true })\r\n })\r\n\r\n fireValuesChange(name)\r\n\r\n const mode = fields.get(name)?.options.validateOn ?? options?.validateOn ?? 'change'\r\n if (mode === 'change') {\r\n const debounceMs = options?.asyncDebounceMs\r\n if (debounceMs && debounceMs > 0) {\r\n const existing = debounceTimers.get(name)\r\n if (existing) clearTimeout(existing)\r\n debounceTimers.set(\r\n name,\r\n setTimeout(() => {\r\n debounceTimers.delete(name)\r\n runValidation(name).then(() => validateDependents(name))\r\n }, debounceMs),\r\n )\r\n } else {\r\n runValidation(name).then(() => validateDependents(name))\r\n }\r\n }\r\n },\r\n\r\n getValue(name: string): unknown {\r\n return core.get(name)\r\n },\r\n\r\n onFieldBlur(name: string): void {\r\n setMeta(name, { touched: true })\r\n const mode = fields.get(name)?.options.validateOn ?? options?.validateOn ?? 'change'\r\n if (mode === 'blur') {\r\n runValidation(name).then(() => validateDependents(name))\r\n }\r\n },\r\n\r\n setFieldsValue(values: Record<string, unknown>): void {\r\n core.batch(() => {\r\n for (const [name, value] of Object.entries(values)) {\r\n core.set(name, value)\r\n if (fields.has(name)) {\r\n setMeta(name, { dirty: true, touched: true })\r\n }\r\n }\r\n })\r\n\r\n for (const name of Object.keys(values)) {\r\n fireValuesChange(name)\r\n }\r\n },\r\n\r\n getFieldsValue(): Record<string, unknown> {\r\n const values: Record<string, unknown> = {}\r\n for (const name of fields.keys()) {\r\n values[name] = core.get(name)\r\n }\r\n return values\r\n },\r\n\r\n getFieldState(name: string): FieldMeta {\r\n return getMeta(name)\r\n },\r\n\r\n getFormState(): FormState {\r\n let isDirty = false\r\n let isValid = true\r\n let isValidating = false\r\n\r\n for (const name of fields.keys()) {\r\n const meta = getMeta(name)\r\n if (meta.dirty) isDirty = true\r\n if (meta.errors.length > 0) isValid = false\r\n if (meta.validating) isValidating = true\r\n }\r\n\r\n return { isDirty, isValid, isSubmitting, isValidating }\r\n },\r\n\r\n addRule(name: string, rule: Rule): void {\r\n const record = fields.get(name)\r\n if (!record) return\r\n record.rules.push({\r\n original: rule,\r\n fn: compileRule(rule, options?.validateMessages, record.options.label),\r\n })\r\n },\r\n\r\n removeRule(name: string, rule: Rule): void {\r\n const record = fields.get(name)\r\n if (!record) return\r\n const idx = record.rules.findIndex((r) => r.original === rule)\r\n if (idx !== -1) record.rules.splice(idx, 1)\r\n },\r\n\r\n depends(target: string, deps: string[]): void {\r\n depMap.set(target, [...deps])\r\n },\r\n\r\n async validate(name?: string): Promise<ValidationResult> {\r\n const errors: Record<string, string[]> = {}\r\n const warnings: Record<string, string[]> = {}\r\n\r\n if (name) {\r\n const errs = await runValidation(name)\r\n if (errs.length > 0) errors[name] = errs\r\n const meta = getMeta(name)\r\n if (meta.warnings.length > 0) warnings[name] = meta.warnings\r\n } else {\r\n const promises: Promise<void>[] = []\r\n for (const fieldName of fields.keys()) {\r\n promises.push(\r\n runValidation(fieldName).then((errs) => {\r\n if (errs.length > 0) errors[fieldName] = errs\r\n const meta = getMeta(fieldName)\r\n if (meta.warnings.length > 0) warnings[fieldName] = meta.warnings\r\n }),\r\n )\r\n }\r\n await Promise.all(promises)\r\n }\r\n\r\n return { valid: Object.keys(errors).length === 0, errors, warnings }\r\n },\r\n\r\n async submit(handler: (values: Record<string, unknown>) => Promise<void>): Promise<void> {\r\n isSubmitting = true\r\n\r\n core.batch(() => {\r\n for (const name of fields.keys()) {\r\n setMeta(name, { touched: true })\r\n }\r\n })\r\n\r\n const result = await form.validate()\r\n\r\n if (!result.valid) {\r\n isSubmitting = false\r\n return\r\n }\r\n\r\n const values: Record<string, unknown> = {}\r\n for (const name of fields.keys()) {\r\n values[name] = core.get(name)\r\n }\r\n\r\n try {\r\n await handler(values)\r\n } finally {\r\n isSubmitting = false\r\n }\r\n },\r\n\r\n reset(values?: Record<string, unknown>): void {\r\n core.batch(() => {\r\n for (const [name, record] of fields) {\r\n record.abortController?.abort()\r\n record.abortController = null\r\n\r\n const resetValue =\r\n values?.[name] ??\r\n options?.defaultValues?.[name] ??\r\n record.options.defaultValue ??\r\n undefined\r\n core.set(name, resetValue)\r\n initMeta(name)\r\n }\r\n })\r\n preservedValues.clear()\r\n },\r\n\r\n getFieldNames(): string[] {\r\n return [...fields.keys()]\r\n },\r\n\r\n // Manual error/warning control\r\n setFieldError(name: string, errs: string | string[]): void {\r\n const arr = typeof errs === 'string' ? [errs] : errs\r\n setMeta(name, { errors: arr })\r\n fireFieldsChange(name)\r\n },\r\n\r\n setFieldWarning(name: string, warns: string | string[]): void {\r\n const arr = typeof warns === 'string' ? [warns] : warns\r\n setMeta(name, { warnings: arr })\r\n },\r\n\r\n clearFieldErrors(name: string): void {\r\n setMeta(name, { errors: [], warnings: [] })\r\n fireFieldsChange(name)\r\n },\r\n\r\n getFieldErrors(name: string): string[] {\r\n return getMeta(name).errors\r\n },\r\n\r\n getFieldWarnings(name: string): string[] {\r\n return getMeta(name).warnings\r\n },\r\n\r\n isFieldTouched(name: string): boolean {\r\n return getMeta(name).touched\r\n },\r\n\r\n isFieldValidating(name: string): boolean {\r\n return getMeta(name).validating\r\n },\r\n\r\n // List operations\r\n getListValue(name: string): unknown[] {\r\n const val = core.get(name)\r\n return Array.isArray(val) ? val : []\r\n },\r\n\r\n listAdd(name: string, defaultValue?: unknown, insertIndex?: number): void {\r\n const current = form.getListValue(name)\r\n if (insertIndex !== undefined && insertIndex >= 0 && insertIndex <= current.length) {\r\n const next = [...current]\r\n next.splice(insertIndex, 0, defaultValue ?? null)\r\n core.set(name, next)\r\n } else {\r\n core.set(name, [...current, defaultValue ?? null])\r\n }\r\n },\r\n\r\n listRemove(name: string, index: number | number[]): void {\r\n const current = form.getListValue(name)\r\n if (Array.isArray(index)) {\r\n const indices = new Set(index)\r\n core.set(name, current.filter((_, i) => !indices.has(i)))\r\n } else {\r\n core.set(name, current.filter((_, i) => i !== index))\r\n }\r\n },\r\n\r\n listMove(name: string, from: number, to: number): void {\r\n const current = [...form.getListValue(name)]\r\n if (from < 0 || from >= current.length || to < 0 || to >= current.length) return\r\n const [item] = current.splice(from, 1)\r\n current.splice(to, 0, item)\r\n core.set(name, current)\r\n },\r\n\r\n listReplace(name: string, values: unknown[]): void {\r\n core.set(name, [...values])\r\n },\r\n }\r\n\r\n return form\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgBA,IAAM,WAAW,oBAAI,IAAoB;AAMlC,SAAS,cAAc,QAAgB,QAAwB;AACpE,MAAI,CAAC,OAAO,WAAW,GAAG,KAAK,CAAC,OAAO,SAAS,GAAG,GAAG;AACpD,UAAM,IAAI;AAAA,MACR,sBAAsB,MAAM,sCAAsC,MAAM;AAAA,IAE1E;AAAA,EACF;AAEA,QAAM,WAAW,SAAS,IAAI,MAAM;AACpC,MAAI,aAAa,UAAa,aAAa,QAAQ;AACjD,UAAM,IAAI;AAAA,MACR,sBAAsB,MAAM,iCAAiC,QAAQ,6BACzC,MAAM;AAAA,IAEpC;AAAA,EACF;AAEA,WAAS,IAAI,QAAQ,MAAM;AAC3B,SAAO;AACT;AAkBO,IAAM,mBAAmB,cAAc,QAAQ,QAAQ;AACvD,IAAM,eAAe,cAAc,SAAS,SAAS;AACrD,IAAM,cAAc,cAAc,QAAQ,QAAQ;AAClD,IAAM,eAAe,cAAc,SAAS,SAAS;AACrD,IAAM,kBAAkB,cAAc,YAAY,YAAY;;;AC9CrE,SAAS,SAAS,MAAc,OAAuB;AACrD,SAAO,GAAG,gBAAW,GAAG,IAAI,IAAI,KAAK;AACvC;AAEA,SAAS,mBAAmB,UAAkB,MAAuC;AACnF,SAAO,SAAS,QAAQ,gBAAgB,CAAC,GAAG,QAAQ;AAClD,WAAO,KAAK,GAAG,KAAK,OAAO,OAAO,KAAK,GAAG,CAAC,IAAI;AAAA,EACjD,CAAC;AACH;AAEA,SAAS,YAAY,MAAY,WAAoC,YAA6B;AAChG,MAAI,OAAO,SAAS,WAAY,QAAO;AAEvC,QAAM,MAAM;AACZ,QAAM,OAAgC,EAAE,OAAO,cAAc,QAAQ;AAErE,SAAO,CAAC,OAAgB,kBAAyE;AAC/F,QAAI,IAAI,UAAU;AAChB,UAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD,cAAM,MAAM,WAAW,YAAY,IAAI;AACvC,eAAO,MAAM,mBAAmB,KAAK,IAAI,IAAK,IAAI,WAAW;AAAA,MAC/D;AAAA,IACF;AAEA,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,GAAI,QAAO;AAElE,QAAI,IAAI,MAAM;AACZ,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,cAAI,OAAO,UAAU,SAAU,QAAO,IAAI,WAAW;AACrD;AAAA,QACF,KAAK;AACH,cAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAG,QAAO,IAAI,WAAW;AACrE;AAAA,QACF,KAAK;AACH,cAAI,OAAO,UAAU,YAAY,CAAC,6BAA6B,KAAK,KAAK;AACvE,mBAAO,IAAI,WAAW;AACxB;AAAA,QACF,KAAK;AACH,cAAI;AACF,gBAAI,IAAI,KAAe;AAAA,UACzB,QAAQ;AACN,mBAAO,IAAI,WAAW;AAAA,UACxB;AACA;AAAA,QACF,KAAK;AACH,cAAI,OAAO,UAAU,UAAW,QAAO,IAAI,WAAW;AACtD;AAAA,MACJ;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ,QAAW;AACzB,WAAK,MAAM,IAAI;AACf,UAAI,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,KAAK;AACvD,cAAM,MAAM,WAAW,OAAO,IAAI;AAClC,eAAO,MAAM,mBAAmB,KAAK,IAAI,IAAK,IAAI,WAAW,WAAW,IAAI,GAAG;AAAA,MACjF;AACA,UAAI,OAAO,UAAU,YAAY,QAAQ,IAAI;AAC3C,eAAO,IAAI,WAAW,oBAAoB,IAAI,GAAG;AAAA,IACrD;AAEA,QAAI,IAAI,QAAQ,QAAW;AACzB,WAAK,MAAM,IAAI;AACf,UAAI,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,KAAK;AACvD,cAAM,MAAM,WAAW,OAAO,IAAI;AAClC,eAAO,MAAM,mBAAmB,KAAK,IAAI,IAAK,IAAI,WAAW,WAAW,IAAI,GAAG;AAAA,MACjF;AACA,UAAI,OAAO,UAAU,YAAY,QAAQ,IAAI;AAC3C,eAAO,IAAI,WAAW,oBAAoB,IAAI,GAAG;AAAA,IACrD;AAEA,QAAI,IAAI,SAAS;AACf,UAAI,OAAO,UAAU,YAAY,CAAC,IAAI,QAAQ,KAAK,KAAK;AACtD,eAAO,IAAI,WAAW;AAAA,IAC1B;AAEA,QAAI,IAAI,WAAW;AACjB,aAAO,IAAI,UAAU,OAAO,aAAa;AAAA,IAC3C;AAEA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,MAAkF;AACvG,MAAI,KAAK,WAAY,QAAO;AAC5B,MAAI,KAAK,OAAO,SAAS,EAAG,QAAO;AACnC,MAAI,KAAK,SAAS,SAAS,EAAG,QAAO;AACrC,SAAO;AACT;AAcO,SAAS,WAAW,MAAY,SAAmC;AACxE,QAAM,SAAS,oBAAI,IAAyB;AAC5C,QAAM,SAAS,oBAAI,IAAsB;AACzC,QAAM,iBAAiB,oBAAI,IAA2C;AACtE,QAAM,kBAAkB,oBAAI,IAAqB;AACjD,MAAI,eAAe;AAEnB,MAAI,SAAS,eAAe;AAC1B,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,aAAa,GAAG;AAChE,WAAK,IAAI,KAAK,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,WAAS,QAAQ,MAAc,MAA8C;AAC3E,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,WAAK,IAAI,SAAS,MAAM,GAAG,GAAG,KAAK;AAAA,IACrC;AAAA,EACF;AAEA,WAAS,QAAQ,MAAyB;AACxC,UAAM,SAAU,KAAK,IAAI,SAAS,MAAM,QAAQ,CAAC,KAAkB,CAAC;AACpE,UAAM,WAAY,KAAK,IAAI,SAAS,MAAM,UAAU,CAAC,KAAkB,CAAC;AACxE,UAAM,aAAc,KAAK,IAAI,SAAS,MAAM,YAAY,CAAC,KAAiB;AAC1E,UAAM,UAAW,KAAK,IAAI,SAAS,MAAM,SAAS,CAAC,KAAiB;AACpE,UAAM,QAAS,KAAK,IAAI,SAAS,MAAM,OAAO,CAAC,KAAiB;AAEhE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,cAAc,EAAE,QAAQ,UAAU,WAAW,CAAC;AAAA,MACtD,OAAO,OAAO,CAAC,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,WAAS,SAAS,MAAoB;AACpC,YAAQ,MAAM;AAAA,MACZ,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,MACT,UAAU,CAAC;AAAA,MACX,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,QAAM,gBAA+B,CAAC,cAAsB,KAAK,IAAI,SAAS;AAE9E,WAAS,iBAAiB,aAA2B;AACnD,QAAI,CAAC,SAAS,eAAgB;AAC9B,UAAM,UAAmC,EAAE,CAAC,WAAW,GAAG,KAAK,IAAI,WAAW,EAAE;AAChF,UAAM,MAA+B,CAAC;AACtC,eAAW,KAAK,OAAO,KAAK,EAAG,KAAI,CAAC,IAAI,KAAK,IAAI,CAAC;AAClD,YAAQ,eAAe,SAAS,GAAG;AAAA,EACrC;AAEA,WAAS,iBAAiB,aAA2B;AACnD,QAAI,CAAC,SAAS,eAAgB;AAC9B,UAAM,OAAO,QAAQ,WAAW;AAChC,YAAQ,eAAe,CAAC;AAAA,MACtB,MAAM;AAAA,MACN,OAAO,KAAK,IAAI,WAAW;AAAA,MAC3B,QAAQ,KAAK;AAAA,IACf,CAAC,CAAC;AAAA,EACJ;AAEA,iBAAe,cAAc,MAAiC;AAC5D,UAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,UAAM,QAAQ,KAAK,IAAI,IAAI;AAC3B,UAAM,gBAAgB,OAAO,QAAQ,iBAAiB,SAAS,iBAAiB;AAEhF,WAAO,iBAAiB,MAAM;AAC9B,UAAM,aAAa,IAAI,gBAAgB;AACvC,WAAO,kBAAkB;AAEzB,UAAM,SAAmB,CAAC;AAE1B,eAAW,QAAQ,OAAO,OAAO;AAC/B,UAAI,WAAW,OAAO,QAAS,QAAO,CAAC;AAEvC,YAAM,SAAS,KAAK,GAAG,OAAO,aAAa;AAE3C,UAAI,kBAAkB,SAAS;AAC7B,gBAAQ,MAAM,EAAE,YAAY,KAAK,CAAC;AAClC,YAAI;AACF,gBAAM,cAAc,MAAM;AAC1B,cAAI,WAAW,OAAO,QAAS,QAAO,CAAC;AACvC,cAAI,aAAa;AACf,mBAAO,KAAK,WAAW;AACvB,gBAAI,cAAe;AAAA,UACrB;AAAA,QACF,QAAQ;AACN,cAAI,WAAW,OAAO,QAAS,QAAO,CAAC;AACvC,iBAAO,KAAK,mBAAmB;AAC/B,cAAI,cAAe;AAAA,QACrB;AAAA,MACF,WAAW,QAAQ;AACjB,eAAO,KAAK,MAAM;AAClB,YAAI,cAAe;AAAA,MACrB;AAAA,IACF;AAEA,UAAM,WAAqB,CAAC;AAC5B,eAAW,QAAQ,OAAO,cAAc;AACtC,UAAI,WAAW,OAAO,QAAS,QAAO,CAAC;AACvC,YAAM,SAAS,KAAK,GAAG,OAAO,aAAa;AAC3C,UAAI,kBAAkB,SAAS;AAC7B,YAAI;AACF,gBAAM,cAAc,MAAM;AAC1B,cAAI,WAAW,OAAO,QAAS,QAAO,CAAC;AACvC,cAAI,YAAa,UAAS,KAAK,WAAW;AAAA,QAC5C,QAAQ;AAAA,QAER;AAAA,MACF,WAAW,QAAQ;AACjB,iBAAS,KAAK,MAAM;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,OAAO,SAAS;AAC9B,cAAQ,MAAM,EAAE,QAAQ,UAAU,YAAY,MAAM,CAAC;AACrD,uBAAiB,IAAI;AAAA,IACvB;AAEA,WAAO;AAAA,EACT;AAEA,iBAAe,mBAAmB,MAA6B;AAC7D,eAAW,CAAC,QAAQ,IAAI,KAAK,QAAQ;AACnC,UAAI,KAAK,SAAS,IAAI,GAAG;AACvB,cAAM,cAAc,MAAM;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAmB;AAAA,IACvB,SAAS,MAAc,cAAmC;AACxD,YAAM,OAAO,gBAAgB,CAAC;AAC9B,YAAM,YAAY,SAAS;AAC3B,YAAM,QAAQ,KAAK;AAEnB,aAAO,IAAI,MAAM;AAAA,QACf,OAAO,KAAK,QACR,KAAK,MAAM,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,YAAY,GAAG,WAAW,KAAK,EAAE,EAAE,IAC7E,CAAC;AAAA,QACL,cAAc,KAAK,eACf,KAAK,aAAa,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,YAAY,GAAG,WAAW,KAAK,EAAE,EAAE,IACpF,CAAC;AAAA,QACL,SAAS;AAAA,QACT,iBAAiB;AAAA,MACnB,CAAC;AAED,UAAI,gBAAgB,IAAI,IAAI,GAAG;AAC7B,aAAK,IAAI,MAAM,gBAAgB,IAAI,IAAI,CAAC;AACxC,wBAAgB,OAAO,IAAI;AAAA,MAC7B,WAAW,KAAK,iBAAiB,UAAa,KAAK,IAAI,IAAI,MAAM,QAAW;AAC1E,aAAK,IAAI,MAAM,KAAK,YAAY;AAAA,MAClC;AAEA,UAAI,KAAK,cAAc;AACrB,eAAO,IAAI,MAAM,CAAC,GAAG,KAAK,YAAY,CAAC;AAAA,MACzC;AAEA,WAAK,MAAM,MAAM;AACf,iBAAS,IAAI;AAAA,MACf,CAAC;AAAA,IACH;AAAA,IAEA,WAAW,MAAoB;AAC7B,YAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,UAAI,CAAC,OAAQ;AACb,aAAO,iBAAiB,MAAM;AAE9B,YAAM,QAAQ,eAAe,IAAI,IAAI;AACrC,UAAI,OAAO;AACT,qBAAa,KAAK;AAClB,uBAAe,OAAO,IAAI;AAAA,MAC5B;AAEA,UAAI,OAAO,QAAQ,UAAU;AAC3B,wBAAgB,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC;AAAA,MAC1C;AAEA,aAAO,OAAO,IAAI;AAClB,aAAO,OAAO,IAAI;AAAA,IACpB;AAAA,IAEA,SAAS,MAAc,OAAsB;AAC3C,WAAK,YAAY,MAAM;AACrB,aAAK,IAAI,MAAM,KAAK;AACpB,gBAAQ,MAAM,EAAE,OAAO,MAAM,SAAS,KAAK,CAAC;AAAA,MAC9C,CAAC;AAED,uBAAiB,IAAI;AAErB,YAAM,OAAO,OAAO,IAAI,IAAI,GAAG,QAAQ,cAAc,SAAS,cAAc;AAC5E,UAAI,SAAS,UAAU;AACrB,cAAM,aAAa,SAAS;AAC5B,YAAI,cAAc,aAAa,GAAG;AAChC,gBAAM,WAAW,eAAe,IAAI,IAAI;AACxC,cAAI,SAAU,cAAa,QAAQ;AACnC,yBAAe;AAAA,YACb;AAAA,YACA,WAAW,MAAM;AACf,6BAAe,OAAO,IAAI;AAC1B,4BAAc,IAAI,EAAE,KAAK,MAAM,mBAAmB,IAAI,CAAC;AAAA,YACzD,GAAG,UAAU;AAAA,UACf;AAAA,QACF,OAAO;AACL,wBAAc,IAAI,EAAE,KAAK,MAAM,mBAAmB,IAAI,CAAC;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,SAAS,MAAuB;AAC9B,aAAO,KAAK,IAAI,IAAI;AAAA,IACtB;AAAA,IAEA,YAAY,MAAoB;AAC9B,cAAQ,MAAM,EAAE,SAAS,KAAK,CAAC;AAC/B,YAAM,OAAO,OAAO,IAAI,IAAI,GAAG,QAAQ,cAAc,SAAS,cAAc;AAC5E,UAAI,SAAS,QAAQ;AACnB,sBAAc,IAAI,EAAE,KAAK,MAAM,mBAAmB,IAAI,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,IAEA,eAAe,QAAuC;AACpD,WAAK,MAAM,MAAM;AACf,mBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,eAAK,IAAI,MAAM,KAAK;AACpB,cAAI,OAAO,IAAI,IAAI,GAAG;AACpB,oBAAQ,MAAM,EAAE,OAAO,MAAM,SAAS,KAAK,CAAC;AAAA,UAC9C;AAAA,QACF;AAAA,MACF,CAAC;AAED,iBAAW,QAAQ,OAAO,KAAK,MAAM,GAAG;AACtC,yBAAiB,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,IAEA,iBAA0C;AACxC,YAAM,SAAkC,CAAC;AACzC,iBAAW,QAAQ,OAAO,KAAK,GAAG;AAChC,eAAO,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,MAC9B;AACA,aAAO;AAAA,IACT;AAAA,IAEA,cAAc,MAAyB;AACrC,aAAO,QAAQ,IAAI;AAAA,IACrB;AAAA,IAEA,eAA0B;AACxB,UAAI,UAAU;AACd,UAAI,UAAU;AACd,UAAI,eAAe;AAEnB,iBAAW,QAAQ,OAAO,KAAK,GAAG;AAChC,cAAM,OAAO,QAAQ,IAAI;AACzB,YAAI,KAAK,MAAO,WAAU;AAC1B,YAAI,KAAK,OAAO,SAAS,EAAG,WAAU;AACtC,YAAI,KAAK,WAAY,gBAAe;AAAA,MACtC;AAEA,aAAO,EAAE,SAAS,SAAS,cAAc,aAAa;AAAA,IACxD;AAAA,IAEA,QAAQ,MAAc,MAAkB;AACtC,YAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,UAAI,CAAC,OAAQ;AACb,aAAO,MAAM,KAAK;AAAA,QAChB,UAAU;AAAA,QACV,IAAI,YAAY,MAAM,SAAS,kBAAkB,OAAO,QAAQ,KAAK;AAAA,MACvE,CAAC;AAAA,IACH;AAAA,IAEA,WAAW,MAAc,MAAkB;AACzC,YAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,UAAI,CAAC,OAAQ;AACb,YAAM,MAAM,OAAO,MAAM,UAAU,CAAC,MAAM,EAAE,aAAa,IAAI;AAC7D,UAAI,QAAQ,GAAI,QAAO,MAAM,OAAO,KAAK,CAAC;AAAA,IAC5C;AAAA,IAEA,QAAQ,QAAgB,MAAsB;AAC5C,aAAO,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,SAAS,MAA0C;AACvD,YAAM,SAAmC,CAAC;AAC1C,YAAM,WAAqC,CAAC;AAE5C,UAAI,MAAM;AACR,cAAM,OAAO,MAAM,cAAc,IAAI;AACrC,YAAI,KAAK,SAAS,EAAG,QAAO,IAAI,IAAI;AACpC,cAAM,OAAO,QAAQ,IAAI;AACzB,YAAI,KAAK,SAAS,SAAS,EAAG,UAAS,IAAI,IAAI,KAAK;AAAA,MACtD,OAAO;AACL,cAAM,WAA4B,CAAC;AACnC,mBAAW,aAAa,OAAO,KAAK,GAAG;AACrC,mBAAS;AAAA,YACP,cAAc,SAAS,EAAE,KAAK,CAAC,SAAS;AACtC,kBAAI,KAAK,SAAS,EAAG,QAAO,SAAS,IAAI;AACzC,oBAAM,OAAO,QAAQ,SAAS;AAC9B,kBAAI,KAAK,SAAS,SAAS,EAAG,UAAS,SAAS,IAAI,KAAK;AAAA,YAC3D,CAAC;AAAA,UACH;AAAA,QACF;AACA,cAAM,QAAQ,IAAI,QAAQ;AAAA,MAC5B;AAEA,aAAO,EAAE,OAAO,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG,QAAQ,SAAS;AAAA,IACrE;AAAA,IAEA,MAAM,OAAO,SAA4E;AACvF,qBAAe;AAEf,WAAK,MAAM,MAAM;AACf,mBAAW,QAAQ,OAAO,KAAK,GAAG;AAChC,kBAAQ,MAAM,EAAE,SAAS,KAAK,CAAC;AAAA,QACjC;AAAA,MACF,CAAC;AAED,YAAM,SAAS,MAAM,KAAK,SAAS;AAEnC,UAAI,CAAC,OAAO,OAAO;AACjB,uBAAe;AACf;AAAA,MACF;AAEA,YAAM,SAAkC,CAAC;AACzC,iBAAW,QAAQ,OAAO,KAAK,GAAG;AAChC,eAAO,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,MAC9B;AAEA,UAAI;AACF,cAAM,QAAQ,MAAM;AAAA,MACtB,UAAE;AACA,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,IAEA,MAAM,QAAwC;AAC5C,WAAK,MAAM,MAAM;AACf,mBAAW,CAAC,MAAM,MAAM,KAAK,QAAQ;AACnC,iBAAO,iBAAiB,MAAM;AAC9B,iBAAO,kBAAkB;AAEzB,gBAAM,aACJ,SAAS,IAAI,KACb,SAAS,gBAAgB,IAAI,KAC7B,OAAO,QAAQ,gBACf;AACF,eAAK,IAAI,MAAM,UAAU;AACzB,mBAAS,IAAI;AAAA,QACf;AAAA,MACF,CAAC;AACD,sBAAgB,MAAM;AAAA,IACxB;AAAA,IAEA,gBAA0B;AACxB,aAAO,CAAC,GAAG,OAAO,KAAK,CAAC;AAAA,IAC1B;AAAA;AAAA,IAGA,cAAc,MAAc,MAA+B;AACzD,YAAM,MAAM,OAAO,SAAS,WAAW,CAAC,IAAI,IAAI;AAChD,cAAQ,MAAM,EAAE,QAAQ,IAAI,CAAC;AAC7B,uBAAiB,IAAI;AAAA,IACvB;AAAA,IAEA,gBAAgB,MAAc,OAAgC;AAC5D,YAAM,MAAM,OAAO,UAAU,WAAW,CAAC,KAAK,IAAI;AAClD,cAAQ,MAAM,EAAE,UAAU,IAAI,CAAC;AAAA,IACjC;AAAA,IAEA,iBAAiB,MAAoB;AACnC,cAAQ,MAAM,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC;AAC1C,uBAAiB,IAAI;AAAA,IACvB;AAAA,IAEA,eAAe,MAAwB;AACrC,aAAO,QAAQ,IAAI,EAAE;AAAA,IACvB;AAAA,IAEA,iBAAiB,MAAwB;AACvC,aAAO,QAAQ,IAAI,EAAE;AAAA,IACvB;AAAA,IAEA,eAAe,MAAuB;AACpC,aAAO,QAAQ,IAAI,EAAE;AAAA,IACvB;AAAA,IAEA,kBAAkB,MAAuB;AACvC,aAAO,QAAQ,IAAI,EAAE;AAAA,IACvB;AAAA;AAAA,IAGA,aAAa,MAAyB;AACpC,YAAM,MAAM,KAAK,IAAI,IAAI;AACzB,aAAO,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC;AAAA,IACrC;AAAA,IAEA,QAAQ,MAAc,cAAwB,aAA4B;AACxE,YAAM,UAAU,KAAK,aAAa,IAAI;AACtC,UAAI,gBAAgB,UAAa,eAAe,KAAK,eAAe,QAAQ,QAAQ;AAClF,cAAM,OAAO,CAAC,GAAG,OAAO;AACxB,aAAK,OAAO,aAAa,GAAG,gBAAgB,IAAI;AAChD,aAAK,IAAI,MAAM,IAAI;AAAA,MACrB,OAAO;AACL,aAAK,IAAI,MAAM,CAAC,GAAG,SAAS,gBAAgB,IAAI,CAAC;AAAA,MACnD;AAAA,IACF;AAAA,IAEA,WAAW,MAAc,OAAgC;AACvD,YAAM,UAAU,KAAK,aAAa,IAAI;AACtC,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,cAAM,UAAU,IAAI,IAAI,KAAK;AAC7B,aAAK,IAAI,MAAM,QAAQ,OAAO,CAAC,GAAG,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;AAAA,MAC1D,OAAO;AACL,aAAK,IAAI,MAAM,QAAQ,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK,CAAC;AAAA,MACtD;AAAA,IACF;AAAA,IAEA,SAAS,MAAc,MAAc,IAAkB;AACrD,YAAM,UAAU,CAAC,GAAG,KAAK,aAAa,IAAI,CAAC;AAC3C,UAAI,OAAO,KAAK,QAAQ,QAAQ,UAAU,KAAK,KAAK,MAAM,QAAQ,OAAQ;AAC1E,YAAM,CAAC,IAAI,IAAI,QAAQ,OAAO,MAAM,CAAC;AACrC,cAAQ,OAAO,IAAI,GAAG,IAAI;AAC1B,WAAK,IAAI,MAAM,OAAO;AAAA,IACxB;AAAA,IAEA,YAAY,MAAc,QAAyB;AACjD,WAAK,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|