@skygraph/core 0.0.0-placeholder.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +42 -6
- package/dist/calendar.cjs +404 -0
- package/dist/calendar.cjs.map +1 -0
- package/dist/calendar.d.cts +209 -0
- package/dist/calendar.d.ts +209 -0
- package/dist/calendar.js +12 -0
- package/dist/calendar.js.map +1 -0
- package/dist/chunk-5CCD5Q4B.js +36 -0
- package/dist/chunk-5CCD5Q4B.js.map +1 -0
- package/dist/chunk-7FA2TBSZ.js +1211 -0
- package/dist/chunk-7FA2TBSZ.js.map +1 -0
- package/dist/chunk-AB3RLBLW.js +357 -0
- package/dist/chunk-AB3RLBLW.js.map +1 -0
- package/dist/chunk-GEMALROQ.js +258 -0
- package/dist/chunk-GEMALROQ.js.map +1 -0
- package/dist/chunk-IY6LJU3L.js +256 -0
- package/dist/chunk-IY6LJU3L.js.map +1 -0
- package/dist/chunk-KMGRNPLG.js +453 -0
- package/dist/chunk-KMGRNPLG.js.map +1 -0
- package/dist/chunk-Y7FTBBYX.js +397 -0
- package/dist/chunk-Y7FTBBYX.js.map +1 -0
- package/dist/chunk-ZWB7JGAJ.js +488 -0
- package/dist/chunk-ZWB7JGAJ.js.map +1 -0
- package/dist/form.cjs +498 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.d.cts +130 -0
- package/dist/form.d.ts +130 -0
- package/dist/form.js +8 -0
- package/dist/form.js.map +1 -0
- package/dist/graph.cjs +1269 -0
- package/dist/graph.cjs.map +1 -0
- package/dist/graph.d.cts +671 -0
- package/dist/graph.d.ts +671 -0
- package/dist/graph.js +34 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.cjs +3860 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +144 -0
- package/dist/index.d.ts +144 -0
- package/dist/index.js +477 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime-internal.cjs +339 -0
- package/dist/runtime-internal.cjs.map +1 -0
- package/dist/runtime-internal.d.cts +130 -0
- package/dist/runtime-internal.d.ts +130 -0
- package/dist/runtime-internal.js +67 -0
- package/dist/runtime-internal.js.map +1 -0
- package/dist/table.cjs +537 -0
- package/dist/table.cjs.map +1 -0
- package/dist/table.d.cts +215 -0
- package/dist/table.d.ts +215 -0
- package/dist/table.js +16 -0
- package/dist/table.js.map +1 -0
- package/dist/tree.cjs +442 -0
- package/dist/tree.cjs.map +1 -0
- package/dist/tree.d.cts +76 -0
- package/dist/tree.d.ts +76 -0
- package/dist/tree.js +8 -0
- package/dist/tree.js.map +1 -0
- package/dist/types-B-rKQJ4R.d.cts +35 -0
- package/dist/types-B-rKQJ4R.d.ts +35 -0
- package/dist/virtual.cjs +283 -0
- package/dist/virtual.cjs.map +1 -0
- package/dist/virtual.d.cts +96 -0
- package/dist/virtual.d.ts +96 -0
- package/dist/virtual.js +9 -0
- package/dist/virtual.js.map +1 -0
- package/package.json +98 -18
- package/index.js +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/Scheduler.ts"],"sourcesContent":["export type Task = () => void\n\n/**\n * Scheduler manages different priority queues for updates.\n * - micro: synchronous, within current transaction\n * - macro: deferred async effects (validation, server sync)\n * - render: batched UI notifications (grouped per frame)\n */\nexport class Scheduler {\n private microQueue: Task[] = []\n private macroQueue: Task[] = []\n private renderQueue: Task[] = []\n private renderScheduled = false\n\n enqueueMicro(task: Task): void {\n this.microQueue.push(task)\n }\n\n enqueueMacro(task: Task): void {\n this.macroQueue.push(task)\n queueMicrotask(() => this.flushMacro())\n }\n\n enqueueRender(task: Task): void {\n this.renderQueue.push(task)\n if (!this.renderScheduled) {\n this.renderScheduled = true\n if (typeof requestAnimationFrame !== 'undefined') {\n requestAnimationFrame(() => this.flushRender())\n } else {\n queueMicrotask(() => this.flushRender())\n }\n }\n }\n\n flushMicro(): void {\n while (this.microQueue.length > 0) {\n const task = this.microQueue.shift()!\n task()\n }\n }\n\n private flushMacro(): void {\n const tasks = [...this.macroQueue]\n this.macroQueue = []\n for (const task of tasks) {\n task()\n }\n }\n\n private flushRender(): void {\n this.renderScheduled = false\n const tasks = [...this.renderQueue]\n this.renderQueue = []\n for (const task of tasks) {\n task()\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAQO,IAAM,YAAN,MAAgB;AAAA,EACb,aAAqB,CAAC;AAAA,EACtB,aAAqB,CAAC;AAAA,EACtB,cAAsB,CAAC;AAAA,EACvB,kBAAkB;AAAA,EAE1B,aAAa,MAAkB;AAC7B,SAAK,WAAW,KAAK,IAAI;AAAA,EAC3B;AAAA,EAEA,aAAa,MAAkB;AAC7B,SAAK,WAAW,KAAK,IAAI;AACzB,mBAAe,MAAM,KAAK,WAAW,CAAC;AAAA,EACxC;AAAA,EAEA,cAAc,MAAkB;AAC9B,SAAK,YAAY,KAAK,IAAI;AAC1B,QAAI,CAAC,KAAK,iBAAiB;AACzB,WAAK,kBAAkB;AACvB,UAAI,OAAO,0BAA0B,aAAa;AAChD,8BAAsB,MAAM,KAAK,YAAY,CAAC;AAAA,MAChD,OAAO;AACL,uBAAe,MAAM,KAAK,YAAY,CAAC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAmB;AACjB,WAAO,KAAK,WAAW,SAAS,GAAG;AACjC,YAAM,OAAO,KAAK,WAAW,MAAM;AACnC,WAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,UAAM,QAAQ,CAAC,GAAG,KAAK,UAAU;AACjC,SAAK,aAAa,CAAC;AACnB,eAAW,QAAQ,OAAO;AACxB,WAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEQ,cAAoB;AAC1B,SAAK,kBAAkB;AACvB,UAAM,QAAQ,CAAC,GAAG,KAAK,WAAW;AAClC,SAAK,cAAc,CAAC;AACpB,eAAW,QAAQ,OAAO;AACxB,WAAK;AAAA,IACP;AAAA,EACF;AACF;","names":[]}
|
package/dist/table.cjs
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/engines/table/index.ts
|
|
21
|
+
var table_exports = {};
|
|
22
|
+
__export(table_exports, {
|
|
23
|
+
computeAggregate: () => computeAggregate,
|
|
24
|
+
createTable: () => createTable,
|
|
25
|
+
matchesColumnFilter: () => matchesColumnFilter,
|
|
26
|
+
matchesOperator: () => matchesOperator,
|
|
27
|
+
resolveOperator: () => resolveOperator
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(table_exports);
|
|
30
|
+
|
|
31
|
+
// src/engines/namespaces.ts
|
|
32
|
+
var reserved = /* @__PURE__ */ new Map();
|
|
33
|
+
function reservePrefix(engine, prefix) {
|
|
34
|
+
if (!prefix.startsWith("$") || !prefix.endsWith(".")) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`[skygraph] engine "${engine}" tried to reserve invalid prefix "${prefix}". Engine prefixes must start with "$" and end with ".".`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
const existing = reserved.get(prefix);
|
|
40
|
+
if (existing !== void 0 && existing !== engine) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`[skygraph] prefix "${prefix}" is already owned by engine "${existing}", cannot reserve it for "${engine}". Pick a different prefix or update the registry.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
reserved.set(prefix, engine);
|
|
46
|
+
return prefix;
|
|
47
|
+
}
|
|
48
|
+
var FORM_META_PREFIX = reservePrefix("form", "$meta.");
|
|
49
|
+
var TABLE_PREFIX = reservePrefix("table", "$table.");
|
|
50
|
+
var TREE_PREFIX = reservePrefix("tree", "$tree.");
|
|
51
|
+
var GRAPH_PREFIX = reservePrefix("graph", "$graph.");
|
|
52
|
+
var CALENDAR_PREFIX = reservePrefix("calendar", "$calendar.");
|
|
53
|
+
|
|
54
|
+
// src/engines/table/filter.ts
|
|
55
|
+
function resolveOperator(filter) {
|
|
56
|
+
const adv = filter;
|
|
57
|
+
if (adv.op != null) return adv.op;
|
|
58
|
+
const col = filter;
|
|
59
|
+
if (col.operator != null) return col.operator;
|
|
60
|
+
return Array.isArray(filter.value) ? "in" : "eq";
|
|
61
|
+
}
|
|
62
|
+
function isEmptyValue(val) {
|
|
63
|
+
return val == null || val === "";
|
|
64
|
+
}
|
|
65
|
+
function asNumberPair(a, b) {
|
|
66
|
+
const na = typeof a === "number" ? a : Number(a);
|
|
67
|
+
const nb = typeof b === "number" ? b : Number(b);
|
|
68
|
+
if (Number.isNaN(na) || Number.isNaN(nb)) return null;
|
|
69
|
+
return [na, nb];
|
|
70
|
+
}
|
|
71
|
+
function matchesOperator(val, op, filterValue) {
|
|
72
|
+
switch (op) {
|
|
73
|
+
case "eq":
|
|
74
|
+
return val === filterValue;
|
|
75
|
+
case "neq":
|
|
76
|
+
return val !== filterValue;
|
|
77
|
+
case "lt":
|
|
78
|
+
case "lte":
|
|
79
|
+
case "gt":
|
|
80
|
+
case "gte": {
|
|
81
|
+
const pair = asNumberPair(val, filterValue);
|
|
82
|
+
if (!pair) return false;
|
|
83
|
+
const [a, b] = pair;
|
|
84
|
+
if (op === "lt") return a < b;
|
|
85
|
+
if (op === "lte") return a <= b;
|
|
86
|
+
if (op === "gt") return a > b;
|
|
87
|
+
return a >= b;
|
|
88
|
+
}
|
|
89
|
+
case "between": {
|
|
90
|
+
if (!Array.isArray(filterValue) || filterValue.length !== 2) return false;
|
|
91
|
+
const minPair = asNumberPair(val, filterValue[0]);
|
|
92
|
+
const maxPair = asNumberPair(val, filterValue[1]);
|
|
93
|
+
if (!minPair || !maxPair) return false;
|
|
94
|
+
return minPair[0] >= minPair[1] && maxPair[0] <= maxPair[1];
|
|
95
|
+
}
|
|
96
|
+
case "in":
|
|
97
|
+
return Array.isArray(filterValue) && filterValue.includes(val);
|
|
98
|
+
case "notIn":
|
|
99
|
+
return Array.isArray(filterValue) && !filterValue.includes(val);
|
|
100
|
+
case "contains":
|
|
101
|
+
if (typeof val !== "string") return false;
|
|
102
|
+
return val.toLowerCase().includes(String(filterValue ?? "").toLowerCase());
|
|
103
|
+
case "startsWith":
|
|
104
|
+
if (typeof val !== "string") return false;
|
|
105
|
+
return val.toLowerCase().startsWith(String(filterValue ?? "").toLowerCase());
|
|
106
|
+
case "endsWith":
|
|
107
|
+
if (typeof val !== "string") return false;
|
|
108
|
+
return val.toLowerCase().endsWith(String(filterValue ?? "").toLowerCase());
|
|
109
|
+
case "isEmpty":
|
|
110
|
+
return isEmptyValue(val);
|
|
111
|
+
case "isNotEmpty":
|
|
112
|
+
return !isEmptyValue(val);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function matchesColumnFilter(row, filter) {
|
|
116
|
+
const op = resolveOperator(filter);
|
|
117
|
+
return matchesOperator(row[filter.column], op, filter.value);
|
|
118
|
+
}
|
|
119
|
+
function computeAggregate(values, type) {
|
|
120
|
+
if (typeof type === "function") return type(values);
|
|
121
|
+
if (type === "count") return values.length;
|
|
122
|
+
const nums = [];
|
|
123
|
+
for (const v of values) {
|
|
124
|
+
if (v == null || v === "") continue;
|
|
125
|
+
const n = typeof v === "number" ? v : Number(v);
|
|
126
|
+
if (!Number.isNaN(n)) nums.push(n);
|
|
127
|
+
}
|
|
128
|
+
if (nums.length === 0) return null;
|
|
129
|
+
switch (type) {
|
|
130
|
+
case "sum":
|
|
131
|
+
return nums.reduce((a, b) => a + b, 0);
|
|
132
|
+
case "avg":
|
|
133
|
+
return nums.reduce((a, b) => a + b, 0) / nums.length;
|
|
134
|
+
case "min":
|
|
135
|
+
return Math.min(...nums);
|
|
136
|
+
case "max":
|
|
137
|
+
return Math.max(...nums);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/engines/table/TableEngine.ts
|
|
142
|
+
function statePath(tableId, key) {
|
|
143
|
+
return `${TABLE_PREFIX}${tableId}.state.${key}`;
|
|
144
|
+
}
|
|
145
|
+
var tableCounter = 0;
|
|
146
|
+
function createTable(core, options) {
|
|
147
|
+
const tableId = `t${tableCounter++}`;
|
|
148
|
+
let currentPageSize = options?.pageSize ?? 50;
|
|
149
|
+
let order = [];
|
|
150
|
+
let filteredOrder = [];
|
|
151
|
+
let sorts = [];
|
|
152
|
+
let filters = [];
|
|
153
|
+
let customFilterFn = null;
|
|
154
|
+
let page = 1;
|
|
155
|
+
let pinnedLeft = [];
|
|
156
|
+
let pinnedRight = [];
|
|
157
|
+
let columnWidths = {};
|
|
158
|
+
let groupByField = null;
|
|
159
|
+
let columnAggregates = [];
|
|
160
|
+
let groups = [];
|
|
161
|
+
const dataById = /* @__PURE__ */ new Map();
|
|
162
|
+
const keysById = /* @__PURE__ */ new Map();
|
|
163
|
+
function getRowData(id) {
|
|
164
|
+
const stored = dataById.get(id);
|
|
165
|
+
if (!stored) return void 0;
|
|
166
|
+
if (options?.columns) {
|
|
167
|
+
const filtered = {};
|
|
168
|
+
for (const col of options.columns) {
|
|
169
|
+
filtered[col] = stored[col];
|
|
170
|
+
}
|
|
171
|
+
return filtered;
|
|
172
|
+
}
|
|
173
|
+
return stored;
|
|
174
|
+
}
|
|
175
|
+
function matchesFilters(rowData) {
|
|
176
|
+
if (customFilterFn && !customFilterFn(rowData)) return false;
|
|
177
|
+
for (const f of filters) {
|
|
178
|
+
if (!matchesColumnFilter(rowData, f)) return false;
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
function compareBySort(a, b) {
|
|
183
|
+
const aData = getRowData(a);
|
|
184
|
+
const bData = getRowData(b);
|
|
185
|
+
for (const s of sorts) {
|
|
186
|
+
const aVal = aData?.[s.column];
|
|
187
|
+
const bVal = bData?.[s.column];
|
|
188
|
+
if (aVal === bVal) continue;
|
|
189
|
+
if (aVal === void 0 || aVal === null) return 1;
|
|
190
|
+
if (bVal === void 0 || bVal === null) return -1;
|
|
191
|
+
const cmp = aVal < bVal ? -1 : 1;
|
|
192
|
+
return s.direction === "asc" ? cmp : -cmp;
|
|
193
|
+
}
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
function recomputeFiltered() {
|
|
197
|
+
if (filters.length === 0 && !customFilterFn) {
|
|
198
|
+
filteredOrder = [...order];
|
|
199
|
+
} else {
|
|
200
|
+
filteredOrder = order.filter((id) => {
|
|
201
|
+
const data = getRowData(id);
|
|
202
|
+
return data ? matchesFilters(data) : false;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (sorts.length > 0) {
|
|
206
|
+
filteredOrder.sort(compareBySort);
|
|
207
|
+
}
|
|
208
|
+
const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize));
|
|
209
|
+
if (page > totalPages) page = totalPages;
|
|
210
|
+
recomputeGroups();
|
|
211
|
+
publishState();
|
|
212
|
+
}
|
|
213
|
+
function recomputeGroups() {
|
|
214
|
+
if (!groupByField) {
|
|
215
|
+
groups = [];
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const map = /* @__PURE__ */ new Map();
|
|
219
|
+
const orderKeys = [];
|
|
220
|
+
for (const id of filteredOrder) {
|
|
221
|
+
const data = getRowData(id);
|
|
222
|
+
if (!data) continue;
|
|
223
|
+
const raw = data[groupByField];
|
|
224
|
+
const key = raw == null ? "__null__" : String(raw);
|
|
225
|
+
if (!map.has(key)) {
|
|
226
|
+
map.set(key, { value: raw, rows: [] });
|
|
227
|
+
orderKeys.push(key);
|
|
228
|
+
}
|
|
229
|
+
map.get(key).rows.push(id);
|
|
230
|
+
}
|
|
231
|
+
groups = orderKeys.map((key) => {
|
|
232
|
+
const { value, rows } = map.get(key);
|
|
233
|
+
const aggregates = {};
|
|
234
|
+
for (const agg of columnAggregates) {
|
|
235
|
+
const values = rows.map((id) => dataById.get(id)?.[agg.column]);
|
|
236
|
+
aggregates[agg.column] = computeAggregate(values, agg.type);
|
|
237
|
+
}
|
|
238
|
+
return { key, value, rows, aggregates };
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function publishState() {
|
|
242
|
+
const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize));
|
|
243
|
+
core.set(statePath(tableId, "totalRows"), order.length);
|
|
244
|
+
core.set(statePath(tableId, "filteredRows"), filteredOrder.length);
|
|
245
|
+
core.set(statePath(tableId, "page"), page);
|
|
246
|
+
core.set(statePath(tableId, "pageSize"), currentPageSize);
|
|
247
|
+
core.set(statePath(tableId, "totalPages"), totalPages);
|
|
248
|
+
core.set(statePath(tableId, "groupBy"), groupByField);
|
|
249
|
+
core.set(statePath(tableId, "groupCount"), groups.length);
|
|
250
|
+
}
|
|
251
|
+
function getColumnKeys() {
|
|
252
|
+
if (options?.columns) return options.columns;
|
|
253
|
+
if (order.length === 0) return [];
|
|
254
|
+
const firstId = order[0];
|
|
255
|
+
return keysById.get(firstId) ?? [];
|
|
256
|
+
}
|
|
257
|
+
function toColumnFilter(column, filter) {
|
|
258
|
+
const adv = filter;
|
|
259
|
+
if (adv.op != null) {
|
|
260
|
+
return { column, operator: adv.op, value: adv.value };
|
|
261
|
+
}
|
|
262
|
+
const cf = filter;
|
|
263
|
+
return { column, operator: cf.operator, value: cf.value };
|
|
264
|
+
}
|
|
265
|
+
const table = {
|
|
266
|
+
addRow(id, data) {
|
|
267
|
+
dataById.set(id, data);
|
|
268
|
+
keysById.set(id, Object.keys(data));
|
|
269
|
+
order.push(id);
|
|
270
|
+
recomputeFiltered();
|
|
271
|
+
},
|
|
272
|
+
addRows(rows) {
|
|
273
|
+
for (const row of rows) {
|
|
274
|
+
dataById.set(row.id, row.data);
|
|
275
|
+
keysById.set(row.id, Object.keys(row.data));
|
|
276
|
+
order.push(row.id);
|
|
277
|
+
}
|
|
278
|
+
recomputeFiltered();
|
|
279
|
+
},
|
|
280
|
+
removeRow(id) {
|
|
281
|
+
const idx = order.indexOf(id);
|
|
282
|
+
if (idx === -1) return;
|
|
283
|
+
order.splice(idx, 1);
|
|
284
|
+
dataById.delete(id);
|
|
285
|
+
keysById.delete(id);
|
|
286
|
+
recomputeFiltered();
|
|
287
|
+
},
|
|
288
|
+
updateCell(id, column, value) {
|
|
289
|
+
const row = dataById.get(id);
|
|
290
|
+
if (!row) return;
|
|
291
|
+
row[column] = value;
|
|
292
|
+
const keys = keysById.get(id);
|
|
293
|
+
if (keys && !keys.includes(column)) {
|
|
294
|
+
keys.push(column);
|
|
295
|
+
}
|
|
296
|
+
recomputeFiltered();
|
|
297
|
+
},
|
|
298
|
+
getRow(id) {
|
|
299
|
+
return getRowData(id);
|
|
300
|
+
},
|
|
301
|
+
getCell(id, column) {
|
|
302
|
+
return dataById.get(id)?.[column];
|
|
303
|
+
},
|
|
304
|
+
getVisibleRows() {
|
|
305
|
+
const start = (page - 1) * currentPageSize;
|
|
306
|
+
const end = start + currentPageSize;
|
|
307
|
+
const slice = filteredOrder.slice(start, end);
|
|
308
|
+
const out = new Array(slice.length);
|
|
309
|
+
for (let i = 0; i < slice.length; i++) {
|
|
310
|
+
const id = slice[i];
|
|
311
|
+
out[i] = { id, data: getRowData(id) ?? {} };
|
|
312
|
+
}
|
|
313
|
+
return out;
|
|
314
|
+
},
|
|
315
|
+
getAllRowIds() {
|
|
316
|
+
return [...order];
|
|
317
|
+
},
|
|
318
|
+
getAllRows() {
|
|
319
|
+
const out = new Array(filteredOrder.length);
|
|
320
|
+
for (let i = 0; i < filteredOrder.length; i++) {
|
|
321
|
+
const id = filteredOrder[i];
|
|
322
|
+
out[i] = { id, data: getRowData(id) ?? {} };
|
|
323
|
+
}
|
|
324
|
+
return out;
|
|
325
|
+
},
|
|
326
|
+
setSort(column, direction, append) {
|
|
327
|
+
if (append) {
|
|
328
|
+
sorts = sorts.filter((s) => s.column !== column);
|
|
329
|
+
sorts.push({ column, direction });
|
|
330
|
+
} else {
|
|
331
|
+
sorts = [{ column, direction }];
|
|
332
|
+
}
|
|
333
|
+
recomputeFiltered();
|
|
334
|
+
},
|
|
335
|
+
setSorts(newSorts) {
|
|
336
|
+
sorts = [...newSorts];
|
|
337
|
+
recomputeFiltered();
|
|
338
|
+
},
|
|
339
|
+
clearSort() {
|
|
340
|
+
sorts = [];
|
|
341
|
+
recomputeFiltered();
|
|
342
|
+
},
|
|
343
|
+
addFilter(filter) {
|
|
344
|
+
filters = filters.filter((f) => f.column !== filter.column);
|
|
345
|
+
filters.push(filter);
|
|
346
|
+
page = 1;
|
|
347
|
+
recomputeFiltered();
|
|
348
|
+
},
|
|
349
|
+
removeFilter(column) {
|
|
350
|
+
filters = filters.filter((f) => f.column !== column);
|
|
351
|
+
recomputeFiltered();
|
|
352
|
+
},
|
|
353
|
+
clearFilters() {
|
|
354
|
+
filters = [];
|
|
355
|
+
customFilterFn = null;
|
|
356
|
+
recomputeFiltered();
|
|
357
|
+
},
|
|
358
|
+
setFilterFn(fn) {
|
|
359
|
+
customFilterFn = fn;
|
|
360
|
+
recomputeFiltered();
|
|
361
|
+
},
|
|
362
|
+
setColumnFilter(column, filter) {
|
|
363
|
+
filters = filters.filter((f) => f.column !== column);
|
|
364
|
+
if (filter !== null) {
|
|
365
|
+
filters.push(toColumnFilter(column, filter));
|
|
366
|
+
}
|
|
367
|
+
page = 1;
|
|
368
|
+
recomputeFiltered();
|
|
369
|
+
},
|
|
370
|
+
setPage(p) {
|
|
371
|
+
const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize));
|
|
372
|
+
page = Math.max(1, Math.min(p, totalPages));
|
|
373
|
+
publishState();
|
|
374
|
+
},
|
|
375
|
+
setPageSize(size) {
|
|
376
|
+
currentPageSize = size;
|
|
377
|
+
page = 1;
|
|
378
|
+
recomputeFiltered();
|
|
379
|
+
},
|
|
380
|
+
nextPage() {
|
|
381
|
+
table.setPage(page + 1);
|
|
382
|
+
},
|
|
383
|
+
prevPage() {
|
|
384
|
+
table.setPage(page - 1);
|
|
385
|
+
},
|
|
386
|
+
moveRow(fromIndex, toIndex) {
|
|
387
|
+
if (fromIndex < 0 || fromIndex >= order.length) return;
|
|
388
|
+
if (toIndex < 0 || toIndex >= order.length) return;
|
|
389
|
+
if (fromIndex === toIndex) return;
|
|
390
|
+
const [item] = order.splice(fromIndex, 1);
|
|
391
|
+
order.splice(toIndex, 0, item);
|
|
392
|
+
recomputeFiltered();
|
|
393
|
+
},
|
|
394
|
+
pinColumn(column, side) {
|
|
395
|
+
pinnedLeft = pinnedLeft.filter((c) => c !== column);
|
|
396
|
+
pinnedRight = pinnedRight.filter((c) => c !== column);
|
|
397
|
+
if (side === "left") pinnedLeft.push(column);
|
|
398
|
+
else if (side === "right") pinnedRight.push(column);
|
|
399
|
+
core.set(statePath(tableId, "pinnedLeft"), [...pinnedLeft]);
|
|
400
|
+
core.set(statePath(tableId, "pinnedRight"), [...pinnedRight]);
|
|
401
|
+
},
|
|
402
|
+
getPinnedColumns() {
|
|
403
|
+
return { left: [...pinnedLeft], right: [...pinnedRight] };
|
|
404
|
+
},
|
|
405
|
+
clearPinned() {
|
|
406
|
+
pinnedLeft = [];
|
|
407
|
+
pinnedRight = [];
|
|
408
|
+
core.set(statePath(tableId, "pinnedLeft"), []);
|
|
409
|
+
core.set(statePath(tableId, "pinnedRight"), []);
|
|
410
|
+
},
|
|
411
|
+
setColumnWidth(column, width) {
|
|
412
|
+
columnWidths = { ...columnWidths, [column]: width };
|
|
413
|
+
core.set(statePath(tableId, "columnWidths"), { ...columnWidths });
|
|
414
|
+
},
|
|
415
|
+
getColumnWidth(column) {
|
|
416
|
+
return columnWidths[column];
|
|
417
|
+
},
|
|
418
|
+
getColumnWidths() {
|
|
419
|
+
return { ...columnWidths };
|
|
420
|
+
},
|
|
421
|
+
clearColumnWidths() {
|
|
422
|
+
columnWidths = {};
|
|
423
|
+
core.set(statePath(tableId, "columnWidths"), {});
|
|
424
|
+
},
|
|
425
|
+
moveRows(ids, toIndex) {
|
|
426
|
+
const items = ids.map((id) => {
|
|
427
|
+
const idx = order.indexOf(id);
|
|
428
|
+
return { id, idx };
|
|
429
|
+
}).filter((x) => x.idx !== -1);
|
|
430
|
+
if (items.length === 0) return;
|
|
431
|
+
const idsSet = new Set(ids);
|
|
432
|
+
const remaining = order.filter((id) => !idsSet.has(id));
|
|
433
|
+
const clamped = Math.max(0, Math.min(toIndex, remaining.length));
|
|
434
|
+
remaining.splice(clamped, 0, ...items.map((x) => x.id));
|
|
435
|
+
order = remaining;
|
|
436
|
+
recomputeFiltered();
|
|
437
|
+
},
|
|
438
|
+
getExportData(exportOptions) {
|
|
439
|
+
const cols = exportOptions?.columns ?? getColumnKeys();
|
|
440
|
+
const result = [];
|
|
441
|
+
if (exportOptions?.headers !== false) {
|
|
442
|
+
result.push(cols);
|
|
443
|
+
}
|
|
444
|
+
const sourceIds = exportOptions?.allRows ? filteredOrder : filteredOrder.slice(
|
|
445
|
+
(page - 1) * currentPageSize,
|
|
446
|
+
(page - 1) * currentPageSize + currentPageSize
|
|
447
|
+
);
|
|
448
|
+
for (const id of sourceIds) {
|
|
449
|
+
const data = getRowData(id);
|
|
450
|
+
if (!data) continue;
|
|
451
|
+
result.push(
|
|
452
|
+
cols.map((col) => {
|
|
453
|
+
const v = data[col];
|
|
454
|
+
return v == null ? "" : String(v);
|
|
455
|
+
})
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
return result;
|
|
459
|
+
},
|
|
460
|
+
getTableState() {
|
|
461
|
+
const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize));
|
|
462
|
+
return {
|
|
463
|
+
totalRows: order.length,
|
|
464
|
+
filteredRows: filteredOrder.length,
|
|
465
|
+
page,
|
|
466
|
+
pageSize: currentPageSize,
|
|
467
|
+
totalPages,
|
|
468
|
+
sorts: [...sorts],
|
|
469
|
+
sort: sorts.length > 0 ? sorts[0] : null,
|
|
470
|
+
filters: [...filters],
|
|
471
|
+
groupBy: groupByField,
|
|
472
|
+
groupCount: groups.length
|
|
473
|
+
};
|
|
474
|
+
},
|
|
475
|
+
groupBy(field, aggregates) {
|
|
476
|
+
groupByField = field ?? null;
|
|
477
|
+
columnAggregates = aggregates ? [...aggregates] : [];
|
|
478
|
+
recomputeGroups();
|
|
479
|
+
publishState();
|
|
480
|
+
},
|
|
481
|
+
clearGroupBy() {
|
|
482
|
+
groupByField = null;
|
|
483
|
+
columnAggregates = [];
|
|
484
|
+
groups = [];
|
|
485
|
+
publishState();
|
|
486
|
+
},
|
|
487
|
+
getGroupBy() {
|
|
488
|
+
return groupByField;
|
|
489
|
+
},
|
|
490
|
+
getGroups() {
|
|
491
|
+
return groups.map((g) => ({
|
|
492
|
+
key: g.key,
|
|
493
|
+
value: g.value,
|
|
494
|
+
rows: [...g.rows],
|
|
495
|
+
aggregates: { ...g.aggregates }
|
|
496
|
+
}));
|
|
497
|
+
},
|
|
498
|
+
getEstimatedRowHeight(id) {
|
|
499
|
+
const fn = options?.estimateRowHeight;
|
|
500
|
+
if (!fn) return null;
|
|
501
|
+
const data = getRowData(id);
|
|
502
|
+
if (!data) return null;
|
|
503
|
+
const v = fn(data, id);
|
|
504
|
+
return Number.isFinite(v) ? v : null;
|
|
505
|
+
},
|
|
506
|
+
reset() {
|
|
507
|
+
order = [];
|
|
508
|
+
filteredOrder = [];
|
|
509
|
+
sorts = [];
|
|
510
|
+
filters = [];
|
|
511
|
+
customFilterFn = null;
|
|
512
|
+
page = 1;
|
|
513
|
+
pinnedLeft = [];
|
|
514
|
+
pinnedRight = [];
|
|
515
|
+
columnWidths = {};
|
|
516
|
+
groupByField = null;
|
|
517
|
+
columnAggregates = [];
|
|
518
|
+
groups = [];
|
|
519
|
+
dataById.clear();
|
|
520
|
+
keysById.clear();
|
|
521
|
+
core.set(statePath(tableId, "columnWidths"), {});
|
|
522
|
+
publishState();
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
core.set(statePath(tableId, "columnWidths"), {});
|
|
526
|
+
publishState();
|
|
527
|
+
return table;
|
|
528
|
+
}
|
|
529
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
530
|
+
0 && (module.exports = {
|
|
531
|
+
computeAggregate,
|
|
532
|
+
createTable,
|
|
533
|
+
matchesColumnFilter,
|
|
534
|
+
matchesOperator,
|
|
535
|
+
resolveOperator
|
|
536
|
+
});
|
|
537
|
+
//# sourceMappingURL=table.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/table/index.ts","../src/engines/namespaces.ts","../src/engines/table/filter.ts","../src/engines/table/TableEngine.ts"],"sourcesContent":["export { createTable } from './TableEngine'\nexport {\n matchesOperator,\n matchesColumnFilter,\n resolveOperator,\n computeAggregate,\n} from './filter'\nexport type {\n TableEngine,\n TableState,\n TableOptions,\n ExportOptions,\n RowId,\n SortConfig,\n SortDirection,\n ColumnFilter,\n FilterFn,\n FilterOperator,\n AdvancedFilter,\n AggregateType,\n AggregateFn,\n ColumnAggregate,\n TableGroup,\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 {\n AdvancedFilter,\n AggregateFn,\n AggregateType,\n ColumnFilter,\n FilterOperator,\n} from './types'\n\n/**\n * Возвращает финальный оператор фильтра. Соблюдаем backward-compat:\n * если оператор не задан, и `value` — массив, считаем фильтр `in`,\n * иначе — `eq`.\n */\nexport function resolveOperator(\n filter: AdvancedFilter | ColumnFilter,\n): FilterOperator {\n const adv = filter as AdvancedFilter\n if (adv.op != null) return adv.op\n const col = filter as ColumnFilter\n if (col.operator != null) return col.operator\n return Array.isArray(filter.value) ? 'in' : 'eq'\n}\n\n/** Проверка пустоты для `isEmpty` / `isNotEmpty`. */\nfunction isEmptyValue(val: unknown): boolean {\n return val == null || val === ''\n}\n\n/** Числовое сравнение с защитой от NaN. */\nfunction asNumberPair(a: unknown, b: unknown): [number, number] | null {\n const na = typeof a === 'number' ? a : Number(a)\n const nb = typeof b === 'number' ? b : Number(b)\n if (Number.isNaN(na) || Number.isNaN(nb)) return null\n return [na, nb]\n}\n\n/**\n * Проверяет, проходит ли значение `val` фильтр (`op` + `filterValue`).\n * Используется как для `ColumnFilter`, так и для `AdvancedFilter`.\n */\nexport function matchesOperator(\n val: unknown,\n op: FilterOperator,\n filterValue: unknown,\n): boolean {\n switch (op) {\n case 'eq':\n return val === filterValue\n case 'neq':\n return val !== filterValue\n\n case 'lt':\n case 'lte':\n case 'gt':\n case 'gte': {\n const pair = asNumberPair(val, filterValue)\n if (!pair) return false\n const [a, b] = pair\n if (op === 'lt') return a < b\n if (op === 'lte') return a <= b\n if (op === 'gt') return a > b\n return a >= b\n }\n\n case 'between': {\n if (!Array.isArray(filterValue) || filterValue.length !== 2) return false\n const minPair = asNumberPair(val, filterValue[0])\n const maxPair = asNumberPair(val, filterValue[1])\n if (!minPair || !maxPair) return false\n return minPair[0] >= minPair[1] && maxPair[0] <= maxPair[1]\n }\n\n case 'in':\n return Array.isArray(filterValue) && filterValue.includes(val)\n case 'notIn':\n return Array.isArray(filterValue) && !filterValue.includes(val)\n\n case 'contains':\n if (typeof val !== 'string') return false\n return val.toLowerCase().includes(String(filterValue ?? '').toLowerCase())\n case 'startsWith':\n if (typeof val !== 'string') return false\n return val.toLowerCase().startsWith(String(filterValue ?? '').toLowerCase())\n case 'endsWith':\n if (typeof val !== 'string') return false\n return val.toLowerCase().endsWith(String(filterValue ?? '').toLowerCase())\n\n case 'isEmpty':\n return isEmptyValue(val)\n case 'isNotEmpty':\n return !isEmptyValue(val)\n }\n}\n\n/**\n * Применяет `ColumnFilter` к строке (по `filter.column`).\n * Точка входа из движка таблицы.\n */\nexport function matchesColumnFilter(\n row: Record<string, unknown>,\n filter: ColumnFilter,\n): boolean {\n const op = resolveOperator(filter)\n return matchesOperator(row[filter.column], op, filter.value)\n}\n\n/** Считает встроенную агрегацию для массива значений. */\nexport function computeAggregate(\n values: unknown[],\n type: AggregateType | AggregateFn,\n): unknown {\n if (typeof type === 'function') return type(values)\n\n if (type === 'count') return values.length\n\n const nums: number[] = []\n for (const v of values) {\n if (v == null || v === '') continue\n const n = typeof v === 'number' ? v : Number(v)\n if (!Number.isNaN(n)) nums.push(n)\n }\n if (nums.length === 0) return null\n\n switch (type) {\n case 'sum':\n return nums.reduce((a, b) => a + b, 0)\n case 'avg':\n return nums.reduce((a, b) => a + b, 0) / nums.length\n case 'min':\n return Math.min(...nums)\n case 'max':\n return Math.max(...nums)\n }\n}\n","import type { Core } from '../../types'\nimport type {\n AdvancedFilter,\n ColumnAggregate,\n ColumnFilter,\n ExportOptions,\n FilterFn,\n RowId,\n SortConfig,\n SortDirection,\n TableEngine,\n TableGroup,\n TableOptions,\n TableState,\n} from './types'\n\nimport { TABLE_PREFIX } from '../namespaces'\nimport { computeAggregate, matchesColumnFilter } from './filter'\n\nfunction statePath(tableId: string, key: string): string {\n return `${TABLE_PREFIX}${tableId}.state.${key}`\n}\n\nlet tableCounter = 0\n\n/**\n * `createTable` строит TableEngine поверх Core. Пользовательские данные строк\n * хранятся в private замыкании (`dataById`/`keysById`), а в Core попадают\n * только пути `$table.<id>.state.*` (агрегированные счётчики, ширины колонок,\n * пин-конфиг). Это держит `addRows(100k)` на масштабе O(N) Map.set вместо\n * O(N × cols) `core.set` (исторический паттерн `byId.<rid>.<col>` создавал\n * сотни тысяч узлов в Store и аллокаций Set/Map в `Core.set` на каждую\n * cell-запись — см. `docs/_streams/findings/T-Table-Perf.md` H1).\n *\n * Семантика публичных методов `getRow`/`getCell`/`getVisibleRows` сохранена.\n * Внешние подписки на `$table.<id>.state.*` пути продолжают работать;\n * подписок на `byId.*` в монорепе нет (они никогда не были задокументированы).\n */\nexport function createTable(core: Core, options?: TableOptions): TableEngine {\n const tableId = `t${tableCounter++}`\n let currentPageSize = options?.pageSize ?? 50\n\n let order: RowId[] = []\n let filteredOrder: RowId[] = []\n let sorts: SortConfig[] = []\n let filters: ColumnFilter[] = []\n let customFilterFn: FilterFn | null = null\n let page = 1\n let pinnedLeft: string[] = []\n let pinnedRight: string[] = []\n let columnWidths: Record<string, number> = {}\n\n // Группировка\n let groupByField: string | null = null\n let columnAggregates: ColumnAggregate[] = []\n let groups: TableGroup[] = []\n\n // Private storage: данные строк живут в замыкании, не в Core store.\n // Это устраняет 800k `core.set` per-cell на 100k×7 датасете и убирает\n // основной источник аллокаций (Store-узлы + Set/Map в `Core.set`).\n const dataById = new Map<RowId, Record<string, unknown>>()\n const keysById = new Map<RowId, string[]>()\n\n function getRowData(id: RowId): Record<string, unknown> | undefined {\n const stored = dataById.get(id)\n if (!stored) return undefined\n\n // Если пользователь передал явный whitelist колонок через\n // `TableOptions.columns`, отдаём отфильтрованную копию (исторический\n // контракт). В типичном кейсе (опция не задана) — возвращаем хранимую\n // ссылку без копии: hot path `compareBySort`/`recomputeFiltered`/render\n // не должны платить за per-row allocation.\n if (options?.columns) {\n const filtered: Record<string, unknown> = {}\n for (const col of options.columns) {\n filtered[col] = stored[col]\n }\n return filtered\n }\n return stored\n }\n\n function matchesFilters(rowData: Record<string, unknown>): boolean {\n if (customFilterFn && !customFilterFn(rowData)) return false\n\n for (const f of filters) {\n if (!matchesColumnFilter(rowData, f)) return false\n }\n return true\n }\n\n function compareBySort(a: RowId, b: RowId): number {\n const aData = getRowData(a)\n const bData = getRowData(b)\n\n for (const s of sorts) {\n const aVal = aData?.[s.column]\n const bVal = bData?.[s.column]\n\n if (aVal === bVal) continue\n if (aVal === undefined || aVal === null) return 1\n if (bVal === undefined || bVal === null) return -1\n\n const cmp = aVal < bVal ? -1 : 1\n return s.direction === 'asc' ? cmp : -cmp\n }\n return 0\n }\n\n function recomputeFiltered(): void {\n if (filters.length === 0 && !customFilterFn) {\n filteredOrder = [...order]\n } else {\n filteredOrder = order.filter((id) => {\n const data = getRowData(id)\n return data ? matchesFilters(data) : false\n })\n }\n\n if (sorts.length > 0) {\n filteredOrder.sort(compareBySort)\n }\n\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\n if (page > totalPages) page = totalPages\n\n recomputeGroups()\n publishState()\n }\n\n function recomputeGroups(): void {\n if (!groupByField) {\n groups = []\n return\n }\n\n const map = new Map<string, { value: unknown; rows: RowId[] }>()\n const orderKeys: string[] = []\n\n for (const id of filteredOrder) {\n const data = getRowData(id)\n if (!data) continue\n const raw = data[groupByField]\n const key = raw == null ? '__null__' : String(raw)\n if (!map.has(key)) {\n map.set(key, { value: raw, rows: [] })\n orderKeys.push(key)\n }\n map.get(key)!.rows.push(id)\n }\n\n groups = orderKeys.map((key) => {\n const { value, rows } = map.get(key)!\n const aggregates: Record<string, unknown> = {}\n for (const agg of columnAggregates) {\n const values = rows.map((id) => dataById.get(id)?.[agg.column])\n aggregates[agg.column] = computeAggregate(values, agg.type)\n }\n return { key, value, rows, aggregates }\n })\n }\n\n function publishState(): void {\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\n core.set(statePath(tableId, 'totalRows'), order.length)\n core.set(statePath(tableId, 'filteredRows'), filteredOrder.length)\n core.set(statePath(tableId, 'page'), page)\n core.set(statePath(tableId, 'pageSize'), currentPageSize)\n core.set(statePath(tableId, 'totalPages'), totalPages)\n core.set(statePath(tableId, 'groupBy'), groupByField)\n core.set(statePath(tableId, 'groupCount'), groups.length)\n }\n\n function getColumnKeys(): string[] {\n if (options?.columns) return options.columns\n if (order.length === 0) return []\n const firstId = order[0]\n return keysById.get(firstId) ?? []\n }\n\n /** Привести `AdvancedFilter | ColumnFilter` к единому `ColumnFilter`. */\n function toColumnFilter(column: string, filter: AdvancedFilter | ColumnFilter): ColumnFilter {\n const adv = filter as AdvancedFilter\n if (adv.op != null) {\n return { column, operator: adv.op, value: adv.value }\n }\n const cf = filter as ColumnFilter\n return { column, operator: cf.operator, value: cf.value }\n }\n\n const table: TableEngine = {\n addRow(id: RowId, data: Record<string, unknown>): void {\n dataById.set(id, data)\n keysById.set(id, Object.keys(data))\n order.push(id)\n recomputeFiltered()\n },\n\n addRows(rows: Array<{ id: RowId; data: Record<string, unknown> }>): void {\n // Single Map.set per row instead of (cols + 1) `core.set` per row —\n // на 100k×7 это разница 800k vs 100k операций и убирает\n // основной источник аллокаций. См. `findings/T-Table-Perf.md` H1.\n for (const row of rows) {\n dataById.set(row.id, row.data)\n keysById.set(row.id, Object.keys(row.data))\n order.push(row.id)\n }\n recomputeFiltered()\n },\n\n removeRow(id: RowId): void {\n const idx = order.indexOf(id)\n if (idx === -1) return\n order.splice(idx, 1)\n dataById.delete(id)\n keysById.delete(id)\n recomputeFiltered()\n },\n\n updateCell(id: RowId, column: string, value: unknown): void {\n const row = dataById.get(id)\n if (!row) return\n // Мутация хранимого объекта. `getRow` отдаёт эту же ссылку (см. контракт\n // в JSDoc к `createTable`), `recomputeFiltered` снизу пересоберёт сорт/\n // группы как раньше.\n row[column] = value\n const keys = keysById.get(id)\n if (keys && !keys.includes(column)) {\n keys.push(column)\n }\n recomputeFiltered()\n },\n\n getRow(id: RowId): Record<string, unknown> | undefined {\n return getRowData(id)\n },\n\n getCell(id: RowId, column: string): unknown {\n return dataById.get(id)?.[column]\n },\n\n getVisibleRows(): Array<{ id: RowId; data: Record<string, unknown> }> {\n const start = (page - 1) * currentPageSize\n const end = start + currentPageSize\n const slice = filteredOrder.slice(start, end)\n const out = new Array(slice.length) as Array<{\n id: RowId\n data: Record<string, unknown>\n }>\n for (let i = 0; i < slice.length; i++) {\n const id = slice[i]\n out[i] = { id, data: getRowData(id) ?? {} }\n }\n return out\n },\n\n getAllRowIds(): RowId[] {\n return [...order]\n },\n\n getAllRows(): Array<{ id: RowId; data: Record<string, unknown> }> {\n const out = new Array(filteredOrder.length) as Array<{\n id: RowId\n data: Record<string, unknown>\n }>\n for (let i = 0; i < filteredOrder.length; i++) {\n const id = filteredOrder[i]\n out[i] = { id, data: getRowData(id) ?? {} }\n }\n return out\n },\n\n setSort(column: string, direction: SortDirection, append?: boolean): void {\n if (append) {\n sorts = sorts.filter((s) => s.column !== column)\n sorts.push({ column, direction })\n } else {\n sorts = [{ column, direction }]\n }\n recomputeFiltered()\n },\n\n setSorts(newSorts: SortConfig[]): void {\n sorts = [...newSorts]\n recomputeFiltered()\n },\n\n clearSort(): void {\n sorts = []\n recomputeFiltered()\n },\n\n addFilter(filter: ColumnFilter): void {\n filters = filters.filter((f) => f.column !== filter.column)\n filters.push(filter)\n page = 1\n recomputeFiltered()\n },\n\n removeFilter(column: string): void {\n filters = filters.filter((f) => f.column !== column)\n recomputeFiltered()\n },\n\n clearFilters(): void {\n filters = []\n customFilterFn = null\n recomputeFiltered()\n },\n\n setFilterFn(fn: FilterFn | null): void {\n customFilterFn = fn\n recomputeFiltered()\n },\n\n setColumnFilter(column, filter): void {\n filters = filters.filter((f) => f.column !== column)\n if (filter !== null) {\n filters.push(toColumnFilter(column, filter))\n }\n page = 1\n recomputeFiltered()\n },\n\n setPage(p: number): void {\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\n page = Math.max(1, Math.min(p, totalPages))\n publishState()\n },\n\n setPageSize(size: number): void {\n currentPageSize = size\n page = 1\n recomputeFiltered()\n },\n\n nextPage(): void {\n table.setPage(page + 1)\n },\n\n prevPage(): void {\n table.setPage(page - 1)\n },\n\n moveRow(fromIndex: number, toIndex: number): void {\n if (fromIndex < 0 || fromIndex >= order.length) return\n if (toIndex < 0 || toIndex >= order.length) return\n if (fromIndex === toIndex) return\n\n const [item] = order.splice(fromIndex, 1)\n order.splice(toIndex, 0, item)\n recomputeFiltered()\n },\n\n pinColumn(column: string, side: 'left' | 'right' | null): void {\n pinnedLeft = pinnedLeft.filter((c) => c !== column)\n pinnedRight = pinnedRight.filter((c) => c !== column)\n if (side === 'left') pinnedLeft.push(column)\n else if (side === 'right') pinnedRight.push(column)\n core.set(statePath(tableId, 'pinnedLeft'), [...pinnedLeft])\n core.set(statePath(tableId, 'pinnedRight'), [...pinnedRight])\n },\n\n getPinnedColumns(): { left: string[]; right: string[] } {\n return { left: [...pinnedLeft], right: [...pinnedRight] }\n },\n\n clearPinned(): void {\n pinnedLeft = []\n pinnedRight = []\n core.set(statePath(tableId, 'pinnedLeft'), [])\n core.set(statePath(tableId, 'pinnedRight'), [])\n },\n\n setColumnWidth(column: string, width: number): void {\n columnWidths = { ...columnWidths, [column]: width }\n core.set(statePath(tableId, 'columnWidths'), { ...columnWidths })\n },\n\n getColumnWidth(column: string): number | undefined {\n return columnWidths[column]\n },\n\n getColumnWidths(): Record<string, number> {\n return { ...columnWidths }\n },\n\n clearColumnWidths(): void {\n columnWidths = {}\n core.set(statePath(tableId, 'columnWidths'), {})\n },\n\n moveRows(ids: RowId[], toIndex: number): void {\n const items = ids\n .map((id) => {\n const idx = order.indexOf(id)\n return { id, idx }\n })\n .filter((x) => x.idx !== -1)\n\n if (items.length === 0) return\n\n const idsSet = new Set(ids)\n const remaining = order.filter((id) => !idsSet.has(id))\n const clamped = Math.max(0, Math.min(toIndex, remaining.length))\n remaining.splice(clamped, 0, ...items.map((x) => x.id))\n order = remaining\n recomputeFiltered()\n },\n\n getExportData(exportOptions?: ExportOptions): string[][] {\n const cols = exportOptions?.columns ?? getColumnKeys()\n const result: string[][] = []\n\n if (exportOptions?.headers !== false) {\n result.push(cols)\n }\n\n const sourceIds = exportOptions?.allRows\n ? filteredOrder\n : filteredOrder.slice(\n (page - 1) * currentPageSize,\n (page - 1) * currentPageSize + currentPageSize,\n )\n\n for (const id of sourceIds) {\n const data = getRowData(id)\n if (!data) continue\n result.push(\n cols.map((col) => {\n const v = data[col]\n return v == null ? '' : String(v)\n }),\n )\n }\n\n return result\n },\n\n getTableState(): TableState {\n const totalPages = Math.max(1, Math.ceil(filteredOrder.length / currentPageSize))\n return {\n totalRows: order.length,\n filteredRows: filteredOrder.length,\n page,\n pageSize: currentPageSize,\n totalPages,\n sorts: [...sorts],\n sort: sorts.length > 0 ? sorts[0] : null,\n filters: [...filters],\n groupBy: groupByField,\n groupCount: groups.length,\n }\n },\n\n groupBy(field, aggregates): void {\n groupByField = field ?? null\n columnAggregates = aggregates ? [...aggregates] : []\n recomputeGroups()\n publishState()\n },\n\n clearGroupBy(): void {\n groupByField = null\n columnAggregates = []\n groups = []\n publishState()\n },\n\n getGroupBy(): string | null {\n return groupByField\n },\n\n getGroups(): TableGroup[] {\n return groups.map((g) => ({\n key: g.key,\n value: g.value,\n rows: [...g.rows],\n aggregates: { ...g.aggregates },\n }))\n },\n\n getEstimatedRowHeight(id: RowId): number | null {\n const fn = options?.estimateRowHeight\n if (!fn) return null\n const data = getRowData(id)\n if (!data) return null\n const v = fn(data, id)\n return Number.isFinite(v) ? v : null\n },\n\n reset(): void {\n order = []\n filteredOrder = []\n sorts = []\n filters = []\n customFilterFn = null\n page = 1\n pinnedLeft = []\n pinnedRight = []\n columnWidths = {}\n groupByField = null\n columnAggregates = []\n groups = []\n dataById.clear()\n keysById.clear()\n core.set(statePath(tableId, 'columnWidths'), {})\n publishState()\n },\n }\n\n // Initial publish — emit empty `columnWidths` so subscribers can read a\n // stable shape from the store without needing to handle `undefined`.\n core.set(statePath(tableId, 'columnWidths'), {})\n publishState()\n return table\n}\n"],"mappings":"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","names":[]}
|