@orkestrel/table 0.0.4 → 0.0.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.
@@ -1,4 +1,4 @@
1
- import { arrayOf, attempt, cloneJSONRecord, isArray, isBoolean, isBoundedJSONRecord, isContractError, isFiniteNumber, isRecord, isString, parseNumber, readArrayEntries, recordOf, unionOf } from "@orkestrel/contract";
1
+ import { arrayOf, attempt, cloneJSONRecord, isArray, isBoolean, isBoundedJSONRecord, isContractError, isFiniteNumber, isInstance, isRecord, isString, parseNumber, readArrayEntries, recordOf, unionOf } from "@orkestrel/contract";
2
2
  import { Emitter } from "@orkestrel/emitter";
3
3
  //#region src/core/constants.ts
4
4
  /** Lists every column cell, in the order declared by the public contract. */
@@ -8,21 +8,26 @@ var COLUMN_CELLS = Object.freeze([
8
8
  "flag",
9
9
  "choice"
10
10
  ]);
11
- /** Names the maximum number of columns one schema may declare. */
11
+ /** Names the maximum number of columns one schema may declare: 256. */
12
12
  var COLUMN_LIMIT = 256;
13
- /** Names the maximum number of choices one `choice` column may offer. */
13
+ /** Names the maximum number of choices one `choice` column may offer: 1024. */
14
14
  var CHOICE_LIMIT = 1024;
15
- /** Names the maximum length, in UTF-16 code units, of a schema name or column key. */
15
+ /** Names the maximum length of a schema name or column key: 128 UTF-16 code units. */
16
16
  var NAME_LIMIT = 128;
17
- /** Names the maximum length, in UTF-16 code units, of any single retained string. */
17
+ /** Names the maximum length of any single retained string: 65536 UTF-16 code units. */
18
18
  var STRING_LIMIT = 65536;
19
- /** Names the maximum total length, in UTF-16 code units, of every string one schema retains. */
19
+ /**
20
+ * Names the maximum total length of every string one schema retains: 1048576 UTF-16 code units.
21
+ */
20
22
  var TEXT_LIMIT = 1048576;
21
- /** Names the maximum total number of records, arrays, and leaves one schema retains. */
23
+ /** Names the maximum total number of records, arrays, and leaves one schema retains: 16384. */
22
24
  var NODE_LIMIT = 16384;
23
25
  //#endregion
24
26
  //#region src/core/errors.ts
25
- /** Represents an error raised by the table domain. */
27
+ /**
28
+ * Represents an error raised by the table domain — a machine-readable `code` and optional
29
+ * structured `context`.
30
+ */
26
31
  var TableError = class extends Error {
27
32
  /** Holds the machine-readable reason for this failure. */
28
33
  code;
@@ -43,18 +48,19 @@ var TableError = class extends Error {
43
48
  }
44
49
  };
45
50
  /**
46
- * Determines whether an unknown value is a table error.
51
+ * Determines whether a caught value is a table error, so a `catch` branches on `code` without an
52
+ * assertion.
47
53
  *
48
54
  * @param input - The value to inspect.
49
55
  * @returns True if the value is a {@link TableError} instance; false otherwise.
50
56
  */
51
57
  function isTableError(input) {
52
- return input instanceof TableError;
58
+ return isInstance(input, TableError);
53
59
  }
54
60
  //#endregion
55
61
  //#region src/core/helpers.ts
56
62
  /**
57
- * Finds one column by key.
63
+ * Finds one column by key; `undefined` when the schema declares no such column.
58
64
  *
59
65
  * @param schema - The schema whose columns to search.
60
66
  * @param key - The column key to find.
@@ -64,7 +70,8 @@ function extractColumn(schema, key) {
64
70
  return schema.columns.find((column) => column.key === key);
65
71
  }
66
72
  /**
67
- * Reads one row's declared identity.
73
+ * Reads one row's declared identity; `undefined` when its key cell is missing, empty, or not a
74
+ * string.
68
75
  *
69
76
  * @param schema - The schema that names the identity column.
70
77
  * @param row - The row whose identity to read.
@@ -76,7 +83,8 @@ function extractKey(schema, row) {
76
83
  return isString(key) && key.length > 0 ? key : void 0;
77
84
  }
78
85
  /**
79
- * Computes one atomic 0/1/N membership change over known keys.
86
+ * Computes one atomic 0/1/N membership change over the keys a caller may address — the engine
87
+ * selection and expansion share.
80
88
  *
81
89
  * @param known - Every key the caller may change.
82
90
  * @param current - The current key set.
@@ -86,7 +94,7 @@ function extractKey(schema, row) {
86
94
  * set when membership changes.
87
95
  */
88
96
  function computeKeys(known, current, input, include) {
89
- const requested = input === void 0 ? known : Array.isArray(input) ? input : [input];
97
+ const requested = input === void 0 ? known : isArray(input) ? input : [input];
90
98
  const population = new Set(known);
91
99
  if (requested.some((key) => !population.has(key))) return void 0;
92
100
  const next = new Set(current);
@@ -95,7 +103,8 @@ function computeKeys(known, current, input, include) {
95
103
  return next.size !== current.size || [...next].some((key) => !current.has(key)) ? next : current;
96
104
  }
97
105
  /**
98
- * Merges lens terms into a column-keyed list, replacing the entry that names the same column.
106
+ * Merges lens terms into a column-keyed list, replacing the entry that names the same column
107
+ * the `set` write.
99
108
  *
100
109
  * @param current - The list as it stands.
101
110
  * @param requested - The terms to write, in the order they are written.
@@ -113,7 +122,8 @@ function mergeTerms(current, requested) {
113
122
  return Object.freeze(next);
114
123
  }
115
124
  /**
116
- * Removes every lens term naming one of the given columns.
125
+ * Removes every lens term naming one of the given columns — the drop `sort.remove` and
126
+ * `filter.remove` share.
117
127
  *
118
128
  * @param current - The list as it stands.
119
129
  * @param columns - The column keys to drop.
@@ -124,7 +134,8 @@ function removeTerms(current, columns) {
124
134
  return Object.freeze(current.filter((term) => !removed.has(term.column)));
125
135
  }
126
136
  /**
127
- * Checks whether two lens lists hold the same terms in the same order.
137
+ * Checks whether two lens lists hold the same terms in the same order, with the supplied test
138
+ * deciding the operands.
128
139
  *
129
140
  * @param left - The first list.
130
141
  * @param right - The second list.
@@ -139,7 +150,8 @@ function matchesTerms(left, right, equal) {
139
150
  });
140
151
  }
141
152
  /**
142
- * Checks whether a value has the shape required by one column cell.
153
+ * Checks whether one column can hold a value the shape gate every write and every seed passes
154
+ * through.
143
155
  *
144
156
  * @param column - The column that owns the cell.
145
157
  * @param value - The unknown value to inspect.
@@ -155,7 +167,7 @@ function matchesCell(column, value) {
155
167
  }
156
168
  }
157
169
  /**
158
- * Compares two cells in ascending order according to one column.
170
+ * Compares two of one column's cells the way its `cell` fixes, describing ascending order.
159
171
  *
160
172
  * @param column - The column that fixes the comparison.
161
173
  * @param left - The first cell, or absence.
@@ -181,7 +193,8 @@ function compareCells(column, left, right) {
181
193
  }
182
194
  }
183
195
  /**
184
- * Checks whether one column admits a filter and all its operands.
196
+ * Checks whether one column admits a filter and every operand it carries — the gate `filter.set`
197
+ * and {@link matchesFilter} share.
185
198
  *
186
199
  * @param column - The column that fixes the accepted operators and cell shapes.
187
200
  * @param filter - The filter to inspect.
@@ -196,7 +209,7 @@ function admitsFilter(column, filter) {
196
209
  }
197
210
  }
198
211
  /**
199
- * Tests one cell against a filter according to its column.
212
+ * Tests one of a column's cells against one filter the way its `cell` fixes.
200
213
  *
201
214
  * @param column - The column that fixes the accepted operators.
202
215
  * @param cell - The cell to test, or absence.
@@ -212,7 +225,8 @@ function matchesFilter(column, cell, filter) {
212
225
  }
213
226
  }
214
227
  /**
215
- * Keeps the rows accepted by every filter.
228
+ * Keeps the rows every filter accepts, in the order given; a supplied {@link CellMatcher}
229
+ * replaces the default per column.
216
230
  *
217
231
  * @param schema - The schema that declares the filtered columns.
218
232
  * @param rows - The rows to filter.
@@ -230,7 +244,8 @@ function filterRows(schema, rows, filters, matchers) {
230
244
  })));
231
245
  }
232
246
  /**
233
- * Orders rows stably by a sequence of terms.
247
+ * Orders rows by the terms given, stably; a supplied {@link CellComparator} replaces the default
248
+ * per column.
234
249
  *
235
250
  * @param schema - The schema that declares the sorted columns.
236
251
  * @param rows - The rows to order.
@@ -258,7 +273,8 @@ function sortRows(schema, rows, orders, comparators) {
258
273
  return Object.freeze(indexed.map((entry) => entry.row));
259
274
  }
260
275
  /**
261
- * Audits a structurally valid schema for domain and budget faults.
276
+ * Audits a structurally valid schema for domain faults and budget breaches, returning human
277
+ * diagnostics.
262
278
  *
263
279
  * @param schema - The table schema to audit.
264
280
  * @returns Frozen human-readable diagnostics, or an empty list when the schema is sound.
@@ -357,7 +373,8 @@ function auditTable(schema) {
357
373
  return Object.freeze(faults);
358
374
  }
359
375
  /**
360
- * Projects a schema into declaration-ordered JSON.
376
+ * Projects a schema into JSON in declaration order, dropping every absent member; raises `SCHEMA`
377
+ * for a `meta` it cannot own.
361
378
  *
362
379
  * @param schema - The schema to project.
363
380
  * @returns A deeply owned JSON record with absent members omitted.
@@ -396,7 +413,8 @@ function serializeTable(schema) {
396
413
  }
397
414
  }
398
415
  /**
399
- * Projects rows into schema-column-ordered JSON.
416
+ * Projects rows into JSON with each row's cells in the schema's column order, dropping every
417
+ * absent cell.
400
418
  *
401
419
  * @param schema - The schema that fixes cell order.
402
420
  * @param rows - The rows to project.
@@ -424,7 +442,8 @@ function serializeRows(schema, rows) {
424
442
  //#endregion
425
443
  //#region src/core/validators.ts
426
444
  /**
427
- * Determines whether an unknown value has a table cell shape.
445
+ * Determines whether an unknown value has a table cell shape — a string, a finite number, or a
446
+ * boolean.
428
447
  *
429
448
  * @param input - The value to inspect.
430
449
  * @returns True if the value is a string, finite number, or boolean; false otherwise.
@@ -433,7 +452,8 @@ function isTableCell(input) {
433
452
  return unionOf(isString, isFiniteNumber, isBoolean)(input);
434
453
  }
435
454
  /**
436
- * Determines whether an unknown value is a record of table cells.
455
+ * Determines whether an unknown value is a record whose every own key is a string and every value
456
+ * a {@link TableCell}.
437
457
  *
438
458
  * @param input - The value to inspect.
439
459
  * @returns True if every own key is a string and every value is a table cell; false otherwise.
@@ -455,7 +475,8 @@ function isColumnCell(input) {
455
475
  return COLUMN_CELLS.some((cell) => cell === input);
456
476
  }
457
477
  /**
458
- * Determines whether an unknown value is one exact column choice record.
478
+ * Determines whether an unknown value is one exact {@link ColumnChoice} record; an unknown member
479
+ * refuses it.
459
480
  *
460
481
  * @param input - The value to inspect.
461
482
  * @returns True if the value is a column choice; false otherwise.
@@ -472,7 +493,8 @@ function isColumnChoice(input) {
472
493
  return outcome.success && outcome.value;
473
494
  }
474
495
  /**
475
- * Determines whether an unknown value is one exact discriminated table column.
496
+ * Determines whether an unknown value is one exact discriminated {@link TableColumn}, checked
497
+ * against its cell's own options.
476
498
  *
477
499
  * @param input - The value to inspect.
478
500
  * @returns True if the value is a structurally valid table column; false otherwise.
@@ -514,7 +536,8 @@ function isTableColumn(input) {
514
536
  return outcome.success && outcome.value;
515
537
  }
516
538
  /**
517
- * Determines whether an unknown value has one exact structural table-schema shape.
539
+ * Determines whether an unknown value has the exact shape of a {@link TableSchema} — the shape
540
+ * alone, with no domain check.
518
541
  *
519
542
  * @param input - The value to inspect.
520
543
  * @returns True if the value has the exact structure of a table schema; false otherwise.
@@ -537,7 +560,8 @@ function isStructuralTableSchema(input) {
537
560
  return outcome.success && outcome.value;
538
561
  }
539
562
  /**
540
- * Determines whether an unknown value is one semantically sound table schema.
563
+ * Determines whether an unknown value is a {@link TableSchema} a table can be opened against —
564
+ * the exact shape, and an audit that finds nothing.
541
565
  *
542
566
  * @param input - The value to inspect.
543
567
  * @returns True if the value has valid structure, domain relationships, and
@@ -559,7 +583,8 @@ function cloneRow(row) {
559
583
  return Object.freeze({ ...row });
560
584
  }
561
585
  /**
562
- * Clones a table schema into an owned frozen snapshot.
586
+ * Clones a whole schema into an owned frozen snapshot, freezing every nested column, choice list,
587
+ * choice, and `meta`; raises `SCHEMA` for a `meta` it cannot own.
563
588
  *
564
589
  * @param schema - The schema to own.
565
590
  * @returns A frozen schema with every nested column, choice, list, and metadata record owned.
@@ -590,7 +615,7 @@ function cloneSchema(schema) {
590
615
  //#endregion
591
616
  //#region src/core/parsers.ts
592
617
  /**
593
- * Parses unknown wire data into an owned, semantically sound table schema.
618
+ * Parses unknown wire data into an owned, structurally valid, semantically sound table schema.
594
619
  *
595
620
  * @param input - The unknown schema value to parse.
596
621
  * @returns An owned table schema, or `undefined` on refusal.
@@ -604,7 +629,8 @@ function parseTable(input) {
604
629
  return outcome.success ? outcome.value : void 0;
605
630
  }
606
631
  /**
607
- * Parses unknown wire rows against one table schema.
632
+ * Parses unknown wire data into owned rows against one table schema, coercing a numeric string
633
+ * and `'true'` / `'false'`.
608
634
  *
609
635
  * @param schema - The schema that declares the accepted keys and cell shapes.
610
636
  * @param input - The unknown row-list value to parse.
@@ -775,7 +801,7 @@ var FilterManager = class {
775
801
  /** Filters one column or several. */
776
802
  set(input) {
777
803
  this.#gate();
778
- const requested = Array.isArray(input) ? input : [input];
804
+ const requested = isArray(input) ? input : [input];
779
805
  for (const filter of requested) this.#validate(filter);
780
806
  const next = mergeTerms(this.#read(), requested);
781
807
  if (matchesTerms(next, this.#read(), (filter, other) => this.#operands(filter, other))) return;
@@ -787,7 +813,7 @@ var FilterManager = class {
787
813
  /** Stops filtering by one or more columns. */
788
814
  remove(input) {
789
815
  this.#gate();
790
- const columns = input === void 0 ? this.#schema.columns.map((column) => column.key) : Array.isArray(input) ? input : [input];
816
+ const columns = input === void 0 ? this.#schema.columns.map((column) => column.key) : isArray(input) ? input : [input];
791
817
  for (const column of columns) if (extractColumn(this.#schema, column) === void 0) return false;
792
818
  const next = removeTerms(this.#read(), columns);
793
819
  if (next.length !== this.#read().length) {
@@ -882,7 +908,7 @@ var PaginationManager = class {
882
908
  this.#emitter.emit("paginate", nextPage);
883
909
  }
884
910
  #normalize(value) {
885
- return Number.isFinite(value) ? Math.max(1, Math.trunc(value)) : 1;
911
+ return isFiniteNumber(value) ? Math.max(1, Math.trunc(value)) : 1;
886
912
  }
887
913
  };
888
914
  //#endregion
@@ -928,7 +954,7 @@ var RowManager = class {
928
954
  /** Appends one row or several. */
929
955
  add(input) {
930
956
  this.#gate();
931
- const rows = Array.isArray(input) ? input : [input];
957
+ const rows = isArray(input) ? input : [input];
932
958
  const keys = /* @__PURE__ */ new Set();
933
959
  for (const row of this.#read()) {
934
960
  const key = extractKey(this.#schema, row);
@@ -947,7 +973,7 @@ var RowManager = class {
947
973
  /** Merges one row or several into the rows their keys name. */
948
974
  update(input) {
949
975
  this.#gate();
950
- const updates = (Array.isArray(input) ? input : [input]).map((row) => cloneRow(row));
976
+ const updates = (isArray(input) ? input : [input]).map((row) => cloneRow(row));
951
977
  const current = this.#read();
952
978
  const locations = [];
953
979
  for (const update of updates) {
@@ -1007,7 +1033,7 @@ var RowManager = class {
1007
1033
  const requested = input === void 0 ? current.flatMap((row) => {
1008
1034
  const key = extractKey(this.#schema, row);
1009
1035
  return key === void 0 ? [] : [key];
1010
- }) : Array.isArray(input) ? input : [input];
1036
+ }) : isArray(input) ? input : [input];
1011
1037
  const keys = new Set(requested);
1012
1038
  const known = new Set(current.flatMap((row) => {
1013
1039
  const key = extractKey(this.#schema, row);
@@ -1130,7 +1156,7 @@ var SortManager = class {
1130
1156
  /** Sorts by one column or several. */
1131
1157
  set(input) {
1132
1158
  this.#gate();
1133
- const requested = Array.isArray(input) ? input : [input];
1159
+ const requested = isArray(input) ? input : [input];
1134
1160
  for (const order of requested) this.#require(order.column);
1135
1161
  const next = mergeTerms(this.#read(), requested);
1136
1162
  if (matchesTerms(next, this.#read(), (order, other) => order.direction === other.direction)) return;
@@ -1140,7 +1166,7 @@ var SortManager = class {
1140
1166
  /** Stops sorting by one or more columns. */
1141
1167
  remove(input) {
1142
1168
  this.#gate();
1143
- const columns = input === void 0 ? this.#schema.columns.map((column) => column.key) : Array.isArray(input) ? input : [input];
1169
+ const columns = input === void 0 ? this.#schema.columns.map((column) => column.key) : isArray(input) ? input : [input];
1144
1170
  for (const column of columns) if (extractColumn(this.#schema, column) === void 0) return false;
1145
1171
  const next = removeTerms(this.#read(), columns);
1146
1172
  if (next.length !== this.#read().length) {
@@ -1155,7 +1181,10 @@ var SortManager = class {
1155
1181
  };
1156
1182
  //#endregion
1157
1183
  //#region src/core/Table.ts
1158
- /** Holds a schema, its rows, and the lens through which they are read. */
1184
+ /**
1185
+ * Holds a schema, its rows, and the lens through which they are read, implementing
1186
+ * {@link TableInterface} exactly.
1187
+ */
1159
1188
  var Table = class {
1160
1189
  #emitter;
1161
1190
  #schema;
@@ -1323,17 +1352,43 @@ var Table = class {
1323
1352
  //#endregion
1324
1353
  //#region src/core/factories.ts
1325
1354
  /**
1326
- * Opens a table against a schema.
1355
+ * Opens a table against a schema. The schema is copied, and the copy is what the table declares.
1327
1356
  *
1328
1357
  * @param schema - The table declaration to own.
1329
1358
  * @param options - Initial rows, lens overrides, pagination, and emitter wiring.
1330
1359
  * @returns A live table interface.
1331
1360
  * @throws A {@link TableError} coded `SCHEMA` when the schema is unusable, `KEY` when a seeded
1332
1361
  * identity is unusable or repeated, and `CELL` when a seeded cell is invalid.
1333
- * @example
1362
+ * @example Open a table
1334
1363
  * ```ts
1335
- * const table = createTable({ key: 'id', columns: [{ cell: 'text', key: 'id' }] })
1336
- * table.rows.add({ id: '1' })
1364
+ * import { createTable } from '@orkestrel/table'
1365
+ *
1366
+ * const table = createTable(
1367
+ * {
1368
+ * label: 'People',
1369
+ * key: 'id',
1370
+ * columns: [
1371
+ * { cell: 'text', key: 'id', label: 'Reference' },
1372
+ * { cell: 'text', key: 'name', label: 'Name' },
1373
+ * { cell: 'number', key: 'age', label: 'Age' },
1374
+ * ],
1375
+ * },
1376
+ * {
1377
+ * rows: [
1378
+ * { id: '1', name: 'Ada', age: 36 },
1379
+ * { id: '2', name: 'Grace', age: 45 },
1380
+ * { id: '3', name: 'Alan', age: 41 },
1381
+ * ],
1382
+ * limit: 2,
1383
+ * },
1384
+ * )
1385
+ *
1386
+ * table.filter.set({ column: 'name', operator: 'contains', text: 'a' })
1387
+ * table.sort.set({ column: 'age', direction: 'descending' })
1388
+ *
1389
+ * table.count // 3 — every name holds a lowercase 'a'
1390
+ * table.pagination.count // 2 — two pages of two
1391
+ * table.view.map((row) => row.name) // ['Grace', 'Alan'] — page one, oldest first
1337
1392
  * ```
1338
1393
  */
1339
1394
  function createTable(schema, options) {