@revisium/schema-toolkit 0.21.5 → 0.22.1

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 CHANGED
@@ -49,7 +49,41 @@ row.getValue('name'); // string (typed!)
49
49
  row.setValue('price', 19.99); // OK
50
50
  row.setValue('price', 'wrong'); // TS Error!
51
51
  row.getPlainValue(); // { name: string, price: number }
52
- row.getPatches(); // JSON Patch operations
52
+ row.patches; // JSON Patch operations
53
+ row.root; // typed root node (InferNode<S>)
54
+ row.reset({ name: 'New', price: 0 }); // reset to new data, commit
55
+ row.reset(); // reset to schema defaults
56
+ ```
57
+
58
+ ### Array Search
59
+
60
+ Arrays expose `find` and `findIndex` for searching elements by node properties:
61
+
62
+ ```typescript
63
+ import { obj, str, arr, createRowModel } from '@revisium/schema-toolkit';
64
+
65
+ const schema = obj({
66
+ sorts: arr(obj({ field: str(), direction: str() })),
67
+ });
68
+
69
+ const row = createRowModel({
70
+ rowId: 'row-1',
71
+ schema,
72
+ data: { sorts: [
73
+ { field: 'name', direction: 'asc' },
74
+ { field: 'age', direction: 'desc' },
75
+ ]},
76
+ });
77
+
78
+ const sortsNode = row.get('sorts');
79
+ // find returns the typed node
80
+ const ageSort = sortsNode.find(
81
+ (node) => node.child('field').getPlainValue() === 'age',
82
+ );
83
+ // findIndex returns the index
84
+ const idx = sortsNode.findIndex(
85
+ (node) => node.child('field').getPlainValue() === 'age',
86
+ ); // 1
53
87
  ```
54
88
 
55
89
  ### TableModel
@@ -215,6 +249,33 @@ See [ForeignKeyResolver docs](src/model/foreign-key-resolver/README.md) for cach
215
249
  | `createRowModel(options)` | Create a row model (typed overload when schema is typed) |
216
250
  | `createTableModel(options)` | Create a table model (typed overload when schema is typed) |
217
251
 
252
+ #### RowModel
253
+
254
+ | Property / Method | Description |
255
+ |-------------------|-------------|
256
+ | `root` | Typed root node (`InferNode<S>` for typed, `ValueNode` for untyped) |
257
+ | `get(path)` | Get node at path |
258
+ | `getValue(path)` | Get plain value at path |
259
+ | `setValue(path, value)` | Set value at path |
260
+ | `getPlainValue()` | Get full plain value |
261
+ | `patches` | JSON Patch operations (`JsonValuePatch[]`) for current changes |
262
+ | `reset(data?)` | Reset to given data (or schema defaults) and commit |
263
+ | `commit()` | Commit current state as base |
264
+ | `revert()` | Revert to last committed state |
265
+
266
+ #### ArrayValueNode
267
+
268
+ | Method | Description |
269
+ |--------|-------------|
270
+ | `at(index)` | Get element at index (supports negative) |
271
+ | `find(predicate)` | Find first element matching predicate, or `undefined` |
272
+ | `findIndex(predicate)` | Find index of first matching element, or `-1` |
273
+ | `push(node)` | Append element |
274
+ | `pushValue(value?)` | Create and append element from value |
275
+ | `removeAt(index)` | Remove element at index |
276
+ | `move(from, to)` | Move element between positions |
277
+ | `clear()` | Remove all elements |
278
+
218
279
  ### Value Tree
219
280
 
220
281
  | Function | Description |
@@ -268,7 +329,7 @@ See [ForeignKeyResolver docs](src/model/foreign-key-resolver/README.md) for cach
268
329
  | `InferNode<S>` | Schema → typed ValueNode interface |
269
330
  | `SchemaFromValue<T>` | Plain TS type → virtual schema shape |
270
331
  | `SchemaPaths<S>` | Union of all valid dot-separated paths |
271
- | `TypedRowModel<S>` | RowModel with typed `getValue`, `setValue`, `getPlainValue` |
332
+ | `TypedRowModel<S>` | RowModel with typed `root`, `getValue`, `setValue`, `getPlainValue`, `reset` |
272
333
  | `TypedTableModel<S>` | TableModel with typed rows, `addRow`, `getRow` |
273
334
 
274
335
  See [Typed API documentation](src/types/TYPED-API.md) for the full reference.
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,2 @@
1
+ 'use strict';
2
+
@@ -317,25 +317,6 @@ var jsonPatchSchema = {
317
317
  type: "array"
318
318
  };
319
319
 
320
- // src/validation-schemas/history-patches-schema.ts
321
- var historyPatchesSchema = {
322
- $id: "history-patches-schema.json",
323
- type: "array",
324
- minItems: 1,
325
- items: {
326
- type: "object",
327
- properties: {
328
- patches: {
329
- $ref: "json-patch-schema.json"
330
- },
331
- hash: {
332
- type: "string"
333
- }
334
- },
335
- required: ["patches", "hash"]
336
- }
337
- };
338
-
339
320
  // src/validation-schemas/table-migrations-schema.ts
340
321
  var tableMigrationsSchema = {
341
322
  $id: "table-migrations-schema.json",
@@ -395,4 +376,147 @@ var tableMigrationsSchema = {
395
376
  title: "JSON Schema for a Single Migration"
396
377
  };
397
378
 
398
- export { arrayMetaSchema, baseStringFields, booleanMetaSchema, foreignKeyExcludesFormula, historyPatchesSchema, jsonPatchSchema, metaSchema, noForeignKeyStringMetaSchema, notForeignKeyMetaSchema, numberMetaSchema, objectMetaSchema, refMetaSchema, sharedFields, stringMetaSchema, tableMigrationsSchema, xFormulaRequiresReadOnly, xFormulaSchema };
379
+ // src/validation-schemas/history-patches-schema.ts
380
+ var historyPatchesSchema = {
381
+ $id: "history-patches-schema.json",
382
+ type: "array",
383
+ minItems: 1,
384
+ items: {
385
+ type: "object",
386
+ properties: {
387
+ patches: {
388
+ $ref: "json-patch-schema.json"
389
+ },
390
+ hash: {
391
+ type: "string"
392
+ }
393
+ },
394
+ required: ["patches", "hash"]
395
+ }
396
+ };
397
+
398
+ // src/validation-schemas/table-views-schema.ts
399
+ var tableViewsSchema = {
400
+ $id: "table-views-schema.json",
401
+ type: "object",
402
+ additionalProperties: false,
403
+ required: ["version", "views"],
404
+ properties: {
405
+ version: {
406
+ type: "integer",
407
+ minimum: 1,
408
+ default: 1
409
+ },
410
+ defaultViewId: {
411
+ type: "string",
412
+ default: "default"
413
+ },
414
+ views: {
415
+ type: "array",
416
+ items: { $ref: "#/$defs/View" },
417
+ default: []
418
+ }
419
+ },
420
+ $defs: {
421
+ View: {
422
+ type: "object",
423
+ additionalProperties: false,
424
+ required: ["id", "name"],
425
+ properties: {
426
+ id: { type: "string", minLength: 1 },
427
+ name: { type: "string", minLength: 1, maxLength: 100 },
428
+ description: { type: "string", maxLength: 500, default: "" },
429
+ columns: {
430
+ oneOf: [
431
+ { type: "null" },
432
+ { type: "array", items: { $ref: "#/$defs/Column" } }
433
+ ],
434
+ default: null
435
+ },
436
+ filters: { $ref: "#/$defs/FilterGroup" },
437
+ sorts: {
438
+ type: "array",
439
+ items: { $ref: "#/$defs/Sort" },
440
+ default: []
441
+ },
442
+ search: {
443
+ type: "string",
444
+ default: ""
445
+ }
446
+ }
447
+ },
448
+ Column: {
449
+ type: "object",
450
+ additionalProperties: false,
451
+ required: ["field"],
452
+ properties: {
453
+ field: { type: "string", minLength: 1 },
454
+ width: { type: "number", minimum: 40 },
455
+ pinned: { type: "string", enum: ["left", "right"] }
456
+ }
457
+ },
458
+ FilterGroup: {
459
+ type: "object",
460
+ additionalProperties: false,
461
+ properties: {
462
+ logic: {
463
+ type: "string",
464
+ enum: ["and", "or"],
465
+ default: "and"
466
+ },
467
+ conditions: {
468
+ type: "array",
469
+ items: { $ref: "#/$defs/FilterCondition" },
470
+ default: []
471
+ },
472
+ groups: {
473
+ type: "array",
474
+ items: { $ref: "#/$defs/FilterGroup" },
475
+ default: []
476
+ }
477
+ }
478
+ },
479
+ FilterCondition: {
480
+ type: "object",
481
+ additionalProperties: false,
482
+ required: ["field", "operator"],
483
+ properties: {
484
+ field: { type: "string", minLength: 1 },
485
+ operator: {
486
+ type: "string",
487
+ enum: [
488
+ "equals",
489
+ "not_equals",
490
+ "contains",
491
+ "not_contains",
492
+ "starts_with",
493
+ "ends_with",
494
+ "is_empty",
495
+ "is_not_empty",
496
+ "gt",
497
+ "gte",
498
+ "lt",
499
+ "lte",
500
+ "is_true",
501
+ "is_false"
502
+ ]
503
+ },
504
+ value: {}
505
+ }
506
+ },
507
+ Sort: {
508
+ type: "object",
509
+ additionalProperties: false,
510
+ required: ["field", "direction"],
511
+ properties: {
512
+ field: { type: "string", minLength: 1 },
513
+ direction: {
514
+ type: "string",
515
+ enum: ["asc", "desc"]
516
+ }
517
+ }
518
+ }
519
+ }
520
+ };
521
+
522
+ export { arrayMetaSchema, baseStringFields, booleanMetaSchema, foreignKeyExcludesFormula, historyPatchesSchema, jsonPatchSchema, metaSchema, noForeignKeyStringMetaSchema, notForeignKeyMetaSchema, numberMetaSchema, objectMetaSchema, refMetaSchema, sharedFields, stringMetaSchema, tableMigrationsSchema, tableViewsSchema, xFormulaRequiresReadOnly, xFormulaSchema };
@@ -1742,6 +1742,12 @@ var ArrayValueNode = class extends BaseValueNode {
1742
1742
  }
1743
1743
  return this._items[index];
1744
1744
  }
1745
+ find(predicate) {
1746
+ return this._items.find((node, index) => predicate(node, index));
1747
+ }
1748
+ findIndex(predicate) {
1749
+ return this._items.findIndex((node, index) => predicate(node, index));
1750
+ }
1745
1751
  push(node) {
1746
1752
  node.parent = this;
1747
1753
  this._items.push(node);
@@ -3137,12 +3143,16 @@ var ValueTree = class {
3137
3143
  // src/model/table/row/RowModelImpl.ts
3138
3144
  var UNSET_INDEX = -1;
3139
3145
  var RowModelImpl = class {
3140
- constructor(_rowId, _tree) {
3146
+ constructor(_rowId, _tree, _schema, _refSchemas) {
3141
3147
  this._rowId = _rowId;
3142
3148
  this._tree = _tree;
3149
+ this._schema = _schema;
3150
+ this._refSchemas = _refSchemas;
3143
3151
  makeAutoObservable(this, {
3144
3152
  _rowId: false,
3145
3153
  _tree: false,
3154
+ _schema: false,
3155
+ _refSchemas: false,
3146
3156
  _tableModel: "observable.ref"
3147
3157
  });
3148
3158
  }
@@ -3156,6 +3166,9 @@ var RowModelImpl = class {
3156
3166
  get tree() {
3157
3167
  return this._tree;
3158
3168
  }
3169
+ get root() {
3170
+ return this._tree.root;
3171
+ }
3159
3172
  get index() {
3160
3173
  if (!this._tableModel) {
3161
3174
  return UNSET_INDEX;
@@ -3215,6 +3228,11 @@ var RowModelImpl = class {
3215
3228
  revert() {
3216
3229
  this._tree.revert();
3217
3230
  }
3231
+ reset(data) {
3232
+ const value = data ?? generateDefaultValue(this._schema, { refSchemas: this._refSchemas });
3233
+ this._tree.setValue("", value);
3234
+ this._tree.commit();
3235
+ }
3218
3236
  dispose() {
3219
3237
  this._tree.dispose();
3220
3238
  }
@@ -3232,7 +3250,7 @@ function createRowModel(options) {
3232
3250
  const valueTree = new ValueTree(rootNode);
3233
3251
  const formulaEngine = new FormulaEngine(valueTree);
3234
3252
  valueTree.setFormulaEngine(formulaEngine);
3235
- return new RowModelImpl(options.rowId, valueTree);
3253
+ return new RowModelImpl(options.rowId, valueTree, options.schema, options.refSchemas);
3236
3254
  }
3237
3255
 
3238
3256
  // src/model/table/TableModelImpl.ts
@@ -319,25 +319,6 @@ var jsonPatchSchema = {
319
319
  type: "array"
320
320
  };
321
321
 
322
- // src/validation-schemas/history-patches-schema.ts
323
- var historyPatchesSchema = {
324
- $id: "history-patches-schema.json",
325
- type: "array",
326
- minItems: 1,
327
- items: {
328
- type: "object",
329
- properties: {
330
- patches: {
331
- $ref: "json-patch-schema.json"
332
- },
333
- hash: {
334
- type: "string"
335
- }
336
- },
337
- required: ["patches", "hash"]
338
- }
339
- };
340
-
341
322
  // src/validation-schemas/table-migrations-schema.ts
342
323
  var tableMigrationsSchema = {
343
324
  $id: "table-migrations-schema.json",
@@ -397,6 +378,149 @@ var tableMigrationsSchema = {
397
378
  title: "JSON Schema for a Single Migration"
398
379
  };
399
380
 
381
+ // src/validation-schemas/history-patches-schema.ts
382
+ var historyPatchesSchema = {
383
+ $id: "history-patches-schema.json",
384
+ type: "array",
385
+ minItems: 1,
386
+ items: {
387
+ type: "object",
388
+ properties: {
389
+ patches: {
390
+ $ref: "json-patch-schema.json"
391
+ },
392
+ hash: {
393
+ type: "string"
394
+ }
395
+ },
396
+ required: ["patches", "hash"]
397
+ }
398
+ };
399
+
400
+ // src/validation-schemas/table-views-schema.ts
401
+ var tableViewsSchema = {
402
+ $id: "table-views-schema.json",
403
+ type: "object",
404
+ additionalProperties: false,
405
+ required: ["version", "views"],
406
+ properties: {
407
+ version: {
408
+ type: "integer",
409
+ minimum: 1,
410
+ default: 1
411
+ },
412
+ defaultViewId: {
413
+ type: "string",
414
+ default: "default"
415
+ },
416
+ views: {
417
+ type: "array",
418
+ items: { $ref: "#/$defs/View" },
419
+ default: []
420
+ }
421
+ },
422
+ $defs: {
423
+ View: {
424
+ type: "object",
425
+ additionalProperties: false,
426
+ required: ["id", "name"],
427
+ properties: {
428
+ id: { type: "string", minLength: 1 },
429
+ name: { type: "string", minLength: 1, maxLength: 100 },
430
+ description: { type: "string", maxLength: 500, default: "" },
431
+ columns: {
432
+ oneOf: [
433
+ { type: "null" },
434
+ { type: "array", items: { $ref: "#/$defs/Column" } }
435
+ ],
436
+ default: null
437
+ },
438
+ filters: { $ref: "#/$defs/FilterGroup" },
439
+ sorts: {
440
+ type: "array",
441
+ items: { $ref: "#/$defs/Sort" },
442
+ default: []
443
+ },
444
+ search: {
445
+ type: "string",
446
+ default: ""
447
+ }
448
+ }
449
+ },
450
+ Column: {
451
+ type: "object",
452
+ additionalProperties: false,
453
+ required: ["field"],
454
+ properties: {
455
+ field: { type: "string", minLength: 1 },
456
+ width: { type: "number", minimum: 40 },
457
+ pinned: { type: "string", enum: ["left", "right"] }
458
+ }
459
+ },
460
+ FilterGroup: {
461
+ type: "object",
462
+ additionalProperties: false,
463
+ properties: {
464
+ logic: {
465
+ type: "string",
466
+ enum: ["and", "or"],
467
+ default: "and"
468
+ },
469
+ conditions: {
470
+ type: "array",
471
+ items: { $ref: "#/$defs/FilterCondition" },
472
+ default: []
473
+ },
474
+ groups: {
475
+ type: "array",
476
+ items: { $ref: "#/$defs/FilterGroup" },
477
+ default: []
478
+ }
479
+ }
480
+ },
481
+ FilterCondition: {
482
+ type: "object",
483
+ additionalProperties: false,
484
+ required: ["field", "operator"],
485
+ properties: {
486
+ field: { type: "string", minLength: 1 },
487
+ operator: {
488
+ type: "string",
489
+ enum: [
490
+ "equals",
491
+ "not_equals",
492
+ "contains",
493
+ "not_contains",
494
+ "starts_with",
495
+ "ends_with",
496
+ "is_empty",
497
+ "is_not_empty",
498
+ "gt",
499
+ "gte",
500
+ "lt",
501
+ "lte",
502
+ "is_true",
503
+ "is_false"
504
+ ]
505
+ },
506
+ value: {}
507
+ }
508
+ },
509
+ Sort: {
510
+ type: "object",
511
+ additionalProperties: false,
512
+ required: ["field", "direction"],
513
+ properties: {
514
+ field: { type: "string", minLength: 1 },
515
+ direction: {
516
+ type: "string",
517
+ enum: ["asc", "desc"]
518
+ }
519
+ }
520
+ }
521
+ }
522
+ };
523
+
400
524
  exports.arrayMetaSchema = arrayMetaSchema;
401
525
  exports.baseStringFields = baseStringFields;
402
526
  exports.booleanMetaSchema = booleanMetaSchema;
@@ -412,5 +536,6 @@ exports.refMetaSchema = refMetaSchema;
412
536
  exports.sharedFields = sharedFields;
413
537
  exports.stringMetaSchema = stringMetaSchema;
414
538
  exports.tableMigrationsSchema = tableMigrationsSchema;
539
+ exports.tableViewsSchema = tableViewsSchema;
415
540
  exports.xFormulaRequiresReadOnly = xFormulaRequiresReadOnly;
416
541
  exports.xFormulaSchema = xFormulaSchema;
@@ -1744,6 +1744,12 @@ var ArrayValueNode = class extends BaseValueNode {
1744
1744
  }
1745
1745
  return this._items[index];
1746
1746
  }
1747
+ find(predicate) {
1748
+ return this._items.find((node, index) => predicate(node, index));
1749
+ }
1750
+ findIndex(predicate) {
1751
+ return this._items.findIndex((node, index) => predicate(node, index));
1752
+ }
1747
1753
  push(node) {
1748
1754
  node.parent = this;
1749
1755
  this._items.push(node);
@@ -3139,12 +3145,16 @@ var ValueTree = class {
3139
3145
  // src/model/table/row/RowModelImpl.ts
3140
3146
  var UNSET_INDEX = -1;
3141
3147
  var RowModelImpl = class {
3142
- constructor(_rowId, _tree) {
3148
+ constructor(_rowId, _tree, _schema, _refSchemas) {
3143
3149
  this._rowId = _rowId;
3144
3150
  this._tree = _tree;
3151
+ this._schema = _schema;
3152
+ this._refSchemas = _refSchemas;
3145
3153
  chunkPJ5OFCLO_cjs.makeAutoObservable(this, {
3146
3154
  _rowId: false,
3147
3155
  _tree: false,
3156
+ _schema: false,
3157
+ _refSchemas: false,
3148
3158
  _tableModel: "observable.ref"
3149
3159
  });
3150
3160
  }
@@ -3158,6 +3168,9 @@ var RowModelImpl = class {
3158
3168
  get tree() {
3159
3169
  return this._tree;
3160
3170
  }
3171
+ get root() {
3172
+ return this._tree.root;
3173
+ }
3161
3174
  get index() {
3162
3175
  if (!this._tableModel) {
3163
3176
  return UNSET_INDEX;
@@ -3217,6 +3230,11 @@ var RowModelImpl = class {
3217
3230
  revert() {
3218
3231
  this._tree.revert();
3219
3232
  }
3233
+ reset(data) {
3234
+ const value = data ?? generateDefaultValue(this._schema, { refSchemas: this._refSchemas });
3235
+ this._tree.setValue("", value);
3236
+ this._tree.commit();
3237
+ }
3220
3238
  dispose() {
3221
3239
  this._tree.dispose();
3222
3240
  }
@@ -3234,7 +3252,7 @@ function createRowModel(options) {
3234
3252
  const valueTree = new ValueTree(rootNode);
3235
3253
  const formulaEngine = new FormulaEngine(valueTree);
3236
3254
  valueTree.setFormulaEngine(formulaEngine);
3237
- return new RowModelImpl(options.rowId, valueTree);
3255
+ return new RowModelImpl(options.rowId, valueTree, options.schema, options.refSchemas);
3238
3256
  }
3239
3257
 
3240
3258
  // src/model/table/TableModelImpl.ts