@rljson/rljson 0.0.33 → 0.0.34

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.
@@ -23,6 +23,10 @@ export interface Buffet extends Json {
23
23
  */
24
24
  ref: Ref;
25
25
  }>;
26
+ /**
27
+ * An optional ID of the buffet.
28
+ */
29
+ id?: BuffetId;
26
30
  }
27
31
  /**
28
32
  * A table containing buffets
@@ -34,6 +34,10 @@ export interface Cake extends Json {
34
34
  layers: {
35
35
  [layerId: CakeLayerId]: LayerRef;
36
36
  };
37
+ /**
38
+ * An optional ID of the cake.
39
+ */
40
+ id?: string;
37
41
  }
38
42
  /**
39
43
  * A table containing cakes
@@ -1,7 +1,6 @@
1
- import { Json } from '@rljson/json';
2
1
  import { NutritionalValues } from '../example/bakery-example.ts';
3
2
  import { RljsonTable } from '../rljson.ts';
4
- import { Ref } from '../typedefs.ts';
3
+ import { JsonWithId, Ref } from '../typedefs.ts';
5
4
  /**
6
5
  * A reference to a ingredients row in a ingredients table
7
6
  */
@@ -9,7 +8,7 @@ export type IngredientsRef = Ref;
9
8
  /**
10
9
  * A table containing ingredients
11
10
  */
12
- export type IngredientsTable<T extends Json> = RljsonTable<T, 'ingredients'>;
11
+ export type IngredientsTable<T extends JsonWithId> = RljsonTable<T, 'ingredients'>;
13
12
  /**
14
13
  * Provides an example ingredients table for test purposes
15
14
  */
@@ -0,0 +1,37 @@
1
+ import { Json } from '@rljson/json';
2
+ import { RljsonTable } from '../rljson.ts';
3
+ import { Ref, TableKey } from '../typedefs.ts';
4
+ /**
5
+ * Describes a revision of a row in a table
6
+ */
7
+ export interface Revision extends Json {
8
+ /**
9
+ * The name of the table the revisione row belongs to
10
+ */
11
+ table: TableKey;
12
+ /**
13
+ * The predecessor of the revision
14
+ */
15
+ predecessor: Ref;
16
+ /**
17
+ * The successor of the revision
18
+ */
19
+ successor: Ref;
20
+ /**
21
+ * The UTC timestamp of the revision
22
+ */
23
+ timestamp: number;
24
+ /**
25
+ * The optional ID of the revisioned element.
26
+ * Can be used get all revisions of a specific ingredient.
27
+ */
28
+ id?: string;
29
+ }
30
+ /**
31
+ * A table containing revisions
32
+ */
33
+ export type RevisionsTable = RljsonTable<Revision, 'ingredients'>;
34
+ /**
35
+ * Example revision object for test purposes
36
+ */
37
+ export declare const exampleRevision: () => Revision;
@@ -9,10 +9,6 @@ export type TableCfgRef = Ref;
9
9
  * A column configuration
10
10
  */
11
11
  export interface ColumnCfg extends Json {
12
- /**
13
- * The key of the column used in data
14
- */
15
- key: ColumnKey;
16
12
  /**
17
13
  * The type of the column
18
14
  */
@@ -43,6 +39,30 @@ export interface TableCfg extends Json {
43
39
  * Needs to be increased when new columns are added.
44
40
  */
45
41
  version: number;
42
+ /**
43
+ * Head tables serve as versioning entry points.
44
+ *
45
+ * - Head tables must contain an id column
46
+ * - Rows in an head table must contain a non-null id
47
+ * - Same row ids must refer to the same physical object
48
+ * - Head tables have no or only one parent table
49
+ */
50
+ isHead: boolean;
51
+ /**
52
+ * Root tables are tables that have no parent table.
53
+ *
54
+ * - Root tables are also head tables
55
+ */
56
+ isRoot: boolean;
57
+ /**
58
+ * Shared tables are tables that are used by multiple parents.
59
+ *
60
+ * - The don't need an id column
61
+ * - Same id can refer to different physical objects
62
+ * - Shared tables can have multiple parents
63
+ * - Shared tables can not be head or root tables
64
+ */
65
+ isShared: boolean;
46
66
  }
47
67
  /**
48
68
  * A table containing columns
package/dist/example.d.ts CHANGED
@@ -23,7 +23,7 @@ export declare class Example {
23
23
  missingReferencedTable: () => Rljson;
24
24
  };
25
25
  tableCfg: {
26
- wrongType: () => import('@rljson/hash').Hashed<Rljson>;
26
+ wrongType: () => Rljson;
27
27
  };
28
28
  layers: {
29
29
  missingBase: () => Rljson;
package/dist/rljson.d.ts CHANGED
@@ -3,6 +3,7 @@ import { BuffetsTable } from './content/buffet.ts';
3
3
  import { CakesTable } from './content/cake.ts';
4
4
  import { IngredientsTable } from './content/ingredients.ts';
5
5
  import { LayersTable } from './content/layer.ts';
6
+ import { RevisionsTable } from './content/revision.ts';
6
7
  import { SliceIdsTable } from './content/slice-ids.ts';
7
8
  import { TableCfgRef, TablesCfgTable } from './content/table-cfg.ts';
8
9
  import { ContentType, Ref, TableKey } from './typedefs.ts';
@@ -11,7 +12,7 @@ export declare const reservedTableKeys: string[];
11
12
  /**
12
13
  * One of the supported Rljson table types
13
14
  */
14
- export type TableType = BuffetsTable | IngredientsTable<any> | LayersTable | SliceIdsTable | CakesTable;
15
+ export type TableType = BuffetsTable | IngredientsTable<any> | LayersTable | SliceIdsTable | CakesTable | RevisionsTable;
15
16
  /** The rljson data format */
16
17
  export interface Rljson extends Json {
17
18
  [tableId: TableKey]: TableType;
package/dist/rljson.js CHANGED
@@ -9,11 +9,20 @@ const bakeryExample = () => {
9
9
  _type: "ingredients",
10
10
  _data: [
11
11
  {
12
+ id: "flour",
12
13
  energy: 364,
13
14
  fat: 0.98,
14
15
  protein: 10.33,
15
16
  carbohydrates: 76.31,
16
17
  _hash: ""
18
+ },
19
+ {
20
+ id: "flour",
21
+ energy: 364.1,
22
+ fat: 0.981,
23
+ protein: 10.331,
24
+ carbohydrates: 76.311,
25
+ _hash: ""
17
26
  }
18
27
  ],
19
28
  _hash: ""
@@ -22,7 +31,7 @@ const bakeryExample = () => {
22
31
  _type: "ingredients",
23
32
  _data: [
24
33
  {
25
- name: "flour",
34
+ id: "flour",
26
35
  amountUnit: "g",
27
36
  nutritionalValuesRef: nutritionalValues._data[0]._hash,
28
37
  _hash: ""
@@ -34,6 +43,7 @@ const bakeryExample = () => {
34
43
  _type: "ingredients",
35
44
  _data: [
36
45
  {
46
+ id: "flour",
37
47
  ingredientsRef: ingredients._data[0]._hash,
38
48
  quantity: 500,
39
49
  _hash: ""
@@ -45,6 +55,7 @@ const bakeryExample = () => {
45
55
  _type: "layers",
46
56
  _data: [
47
57
  {
58
+ id: "tastyCake",
48
59
  ingredientsTable: "recipeIngredients",
49
60
  assign: {
50
61
  flour: recipeIngredients._data[0]._hash
@@ -70,23 +81,21 @@ const bakeryExample = () => {
70
81
  _data: [
71
82
  {
72
83
  add: ["slice0", "slice1"],
73
- remove: [],
74
- _hash: ""
84
+ remove: []
75
85
  }
76
- ],
77
- _hash: ""
86
+ ]
78
87
  });
79
88
  const cakes = hip({
80
89
  _type: "cakes",
81
90
  _data: [
82
91
  {
92
+ id: "cake1",
83
93
  sliceIdsTable: "slices",
84
94
  sliceIds: slices._data[0]._hash,
85
95
  layersTable: "layers",
86
96
  layers: {
87
97
  flour: layers._data[0]._hash
88
- },
89
- _hash: ""
98
+ }
90
99
  }
91
100
  ]
92
101
  });
@@ -94,6 +103,7 @@ const bakeryExample = () => {
94
103
  _type: "buffets",
95
104
  _data: [
96
105
  {
106
+ id: "salesCounter",
97
107
  items: [
98
108
  {
99
109
  table: "cakes",
@@ -156,37 +166,32 @@ __publicField(_Example, "ok", {
156
166
  _hash: "",
157
167
  key: "table",
158
168
  type: "ingredients",
169
+ isHead: false,
170
+ isRoot: false,
171
+ isShared: true,
159
172
  columns: {
160
173
  int: {
161
- key: "int",
162
174
  type: "number"
163
175
  },
164
176
  double: {
165
- key: "double",
166
177
  type: "number"
167
178
  },
168
179
  string: {
169
- key: "string",
170
180
  type: "string"
171
181
  },
172
182
  boolean: {
173
- key: "boolean",
174
183
  type: "boolean"
175
184
  },
176
185
  null: {
177
- key: "null",
178
186
  type: "null"
179
187
  },
180
188
  jsonArray: {
181
- key: "jsonArray",
182
189
  type: "jsonArray"
183
190
  },
184
191
  json: {
185
- key: "json",
186
192
  type: "json"
187
193
  },
188
194
  jsonValue: {
189
- key: "jsonValue",
190
195
  type: "jsonValue"
191
196
  }
192
197
  }
@@ -399,7 +404,10 @@ __publicField(_Example, "broken", {
399
404
  const result = _Example.ok.singleRow();
400
405
  const tableCfg = result.tableCfgs._data[0];
401
406
  tableCfg.columns["int"].type = "numberBroken";
402
- return hip(result, true, false);
407
+ return hip(result, {
408
+ updateExistingHashes: true,
409
+ throwOnWrongHashes: false
410
+ });
403
411
  }
404
412
  },
405
413
  layers: {
@@ -407,13 +415,19 @@ __publicField(_Example, "broken", {
407
415
  const result = _Example.ok.complete();
408
416
  const layer1 = result.layers._data[1];
409
417
  layer1.base = "MISSING";
410
- return hip(result, true, false);
418
+ return hip(result, {
419
+ updateExistingHashes: true,
420
+ throwOnWrongHashes: false
421
+ });
411
422
  },
412
423
  missingSliceIdSet: () => {
413
424
  const result = _Example.ok.complete();
414
425
  const layer1 = result.layers._data[1];
415
426
  layer1.sliceIds = "MISSING1";
416
- return hip(result, true, false);
427
+ return hip(result, {
428
+ updateExistingHashes: true,
429
+ throwOnWrongHashes: false
430
+ });
417
431
  },
418
432
  missingAssignedIngredientTable: () => {
419
433
  const result = _Example.ok.complete();
@@ -423,27 +437,39 @@ __publicField(_Example, "broken", {
423
437
  missingAssignedIngredient: () => {
424
438
  const result = _Example.ok.complete();
425
439
  result.ingredients._data.splice(1, 2);
426
- return hip(result, true, false);
440
+ return hip(result, {
441
+ updateExistingHashes: true,
442
+ throwOnWrongHashes: false
443
+ });
427
444
  }
428
445
  },
429
446
  cakes: {
430
447
  missingSliceIdSet: () => {
431
448
  const result = _Example.ok.complete();
432
449
  result.cakes._data[0].sliceIds = "MISSING";
433
- hip(result.cakes, true, false);
450
+ hip(result.cakes, {
451
+ updateExistingHashes: true,
452
+ throwOnWrongHashes: false
453
+ });
434
454
  return result;
435
455
  },
436
456
  missingLayersTable: () => {
437
457
  const result = _Example.ok.complete();
438
458
  result.cakes._data[0].layersTable = "MISSING";
439
- hip(result.cakes, true, false);
459
+ hip(result.cakes, {
460
+ updateExistingHashes: true,
461
+ throwOnWrongHashes: false
462
+ });
440
463
  return result;
441
464
  },
442
465
  missingCakeLayer: () => {
443
466
  const result = _Example.ok.complete();
444
467
  result.cakes._data[0].layers["layer0"] = "MISSING0";
445
468
  result.cakes._data[0].layers["layer1"] = "MISSING1";
446
- hip(result.cakes, true, false);
469
+ hip(result.cakes, {
470
+ updateExistingHashes: true,
471
+ throwOnWrongHashes: false
472
+ });
447
473
  return result;
448
474
  }
449
475
  },
@@ -453,7 +479,7 @@ __publicField(_Example, "broken", {
453
479
  const buffet = result.buffets._data[0];
454
480
  buffet.items[0].table = "MISSING0";
455
481
  buffet.items[1].table = "MISSING1";
456
- hip(result, true, false);
482
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
457
483
  return result;
458
484
  },
459
485
  missingItems: () => {
@@ -461,7 +487,7 @@ __publicField(_Example, "broken", {
461
487
  const buffet = result.buffets._data[0];
462
488
  buffet.items[0].ref = "MISSING0";
463
489
  buffet.items[1].ref = "MISSING1";
464
- hip(result, true, false);
490
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
465
491
  return result;
466
492
  }
467
493
  }
@@ -475,15 +501,16 @@ const exampleTableCfg = (tableCfg = void 0) => {
475
501
  version: 1,
476
502
  columns: (tableCfg == null ? void 0 : tableCfg.columns) ?? {
477
503
  a: {
478
- key: "a",
479
504
  type: "string"
480
505
  },
481
506
  b: {
482
- key: "b",
483
507
  type: "number"
484
508
  }
485
509
  },
486
- type: (tableCfg == null ? void 0 : tableCfg.type) ?? "ingredients"
510
+ type: (tableCfg == null ? void 0 : tableCfg.type) ?? "ingredients",
511
+ isHead: true,
512
+ isRoot: true,
513
+ isShared: false
487
514
  };
488
515
  };
489
516
  // @license
@@ -511,7 +538,13 @@ const rljsonIndexed = (rljson) => {
511
538
  };
512
539
  // @license
513
540
  const reservedFieldNames = ["_type", "_data"];
514
- const reservedTableKeys = ["_hash", "sliceIds", "tableCfgs"];
541
+ const reservedTableKeys = [
542
+ "_hash",
543
+ "sliceIds",
544
+ "tableCfgs",
545
+ "reverseRefs",
546
+ "revisions"
547
+ ];
515
548
  const exampleRljson = () => Example.ok.singleRow();
516
549
  const iterateTables = (rljson, callback) => {
517
550
  for (const tableKey in rljson) {
@@ -587,6 +620,8 @@ class _BaseValidator {
587
620
  () => this._missingColumnConfigs(),
588
621
  () => this._dataDoesNotMatchColumnConfig(),
589
622
  () => this._tableTypesDoNotMatch(),
623
+ () => this._tableCfgHasRootHeadSharedError(),
624
+ () => this._rootOrHeadTableHasNoIdColumn(),
590
625
  // Check references
591
626
  () => this._refsNotFound(),
592
627
  // Check layers
@@ -893,6 +928,76 @@ class _BaseValidator {
893
928
  }
894
929
  }
895
930
  // ...........................................................................
931
+ _tableCfgHasRootHeadSharedError() {
932
+ const rljson = this.rljson;
933
+ const inconsistentTableCfgs = [];
934
+ for (const tableKey of this.tableKeys) {
935
+ const table = rljson[tableKey];
936
+ const cfgRef = table._tableCfg;
937
+ if (!cfgRef) {
938
+ continue;
939
+ }
940
+ const cfg = this.rljsonIndexed.tableCfgs._data[cfgRef];
941
+ const { isRoot, isHead, isShared } = cfg;
942
+ if (isShared && (isRoot || isHead)) {
943
+ inconsistentTableCfgs.push({
944
+ error: "Tables with isShared = true must have isRoot = false and isHead = false",
945
+ table: tableKey,
946
+ tableCfg: cfgRef
947
+ });
948
+ } else if (isRoot && !isHead) {
949
+ inconsistentTableCfgs.push({
950
+ error: "Tables with isRoot = true must also have isHead = true",
951
+ table: tableKey,
952
+ tableCfg: cfgRef
953
+ });
954
+ } else if (!isRoot && !isHead && !isShared) {
955
+ inconsistentTableCfgs.push({
956
+ error: "Tables must be either root, root+head or shared",
957
+ table: tableKey,
958
+ tableCfg: cfgRef
959
+ });
960
+ }
961
+ }
962
+ if (inconsistentTableCfgs.length > 0) {
963
+ this.errors.tableCfgHasRootHeadSharedError = {
964
+ error: "Table configs have inconsistent root/head/shared settings",
965
+ tables: inconsistentTableCfgs
966
+ };
967
+ }
968
+ }
969
+ // ...........................................................................
970
+ _rootOrHeadTableHasNoIdColumn() {
971
+ const rljson = this.rljson;
972
+ const rootOrHeadTablesWithoutIdColumns = [];
973
+ for (const tableKey of this.tableKeys) {
974
+ const table = rljson[tableKey];
975
+ const cfgRef = table._tableCfg;
976
+ if (!cfgRef) {
977
+ continue;
978
+ }
979
+ const cfg = this.rljsonIndexed.tableCfgs._data[cfgRef];
980
+ const isRootOrHeadTable = cfg.isRoot || cfg.isHead;
981
+ if (!isRootOrHeadTable) {
982
+ continue;
983
+ }
984
+ const columns = cfg.columns;
985
+ const idField = columns["id"];
986
+ if (!idField) {
987
+ rootOrHeadTablesWithoutIdColumns.push({
988
+ table: tableKey,
989
+ tableCfg: cfgRef
990
+ });
991
+ }
992
+ }
993
+ if (rootOrHeadTablesWithoutIdColumns.length > 0) {
994
+ this.errors.rootOrHeadTableHasNoIdColumn = {
995
+ error: "Root or head tables must have an id column",
996
+ tables: rootOrHeadTablesWithoutIdColumns
997
+ };
998
+ }
999
+ }
1000
+ // ...........................................................................
896
1001
  _dataHasWrongType() {
897
1002
  const rljson = this.rljson;
898
1003
  const tablesWithWrongType = [];
@@ -49,37 +49,32 @@ export class Example {
49
49
  _hash: '',
50
50
  key: 'table',
51
51
  type: 'ingredients',
52
+ isHead: false,
53
+ isRoot: false,
54
+ isShared: true,
52
55
  columns: {
53
56
  int: {
54
- key: 'int',
55
57
  type: 'number',
56
58
  },
57
59
  double: {
58
- key: 'double',
59
60
  type: 'number',
60
61
  },
61
62
  string: {
62
- key: 'string',
63
63
  type: 'string',
64
64
  },
65
65
  boolean: {
66
- key: 'boolean',
67
66
  type: 'boolean',
68
67
  },
69
68
  null: {
70
- key: 'null',
71
69
  type: 'null',
72
70
  },
73
71
  jsonArray: {
74
- key: 'jsonArray',
75
72
  type: 'jsonArray',
76
73
  },
77
74
  json: {
78
- key: 'json',
79
75
  type: 'json',
80
76
  },
81
77
  jsonValue: {
82
- key: 'jsonValue',
83
78
  type: 'jsonValue',
84
79
  },
85
80
  },
@@ -309,7 +304,10 @@ export class Example {
309
304
  const result = Example.ok.singleRow();
310
305
  const tableCfg = result.tableCfgs._data[0];
311
306
  tableCfg.columns['int'].type = 'numberBroken'; // Break one of the types
312
- return hip(result, true, false);
307
+ return hip(result, {
308
+ updateExistingHashes: true,
309
+ throwOnWrongHashes: false,
310
+ });
313
311
  },
314
312
  },
315
313
 
@@ -320,7 +318,10 @@ export class Example {
320
318
  layer1.base = 'MISSING'; // Missing base
321
319
 
322
320
  // Recalculate hashes
323
- return hip(result, true, false);
321
+ return hip(result, {
322
+ updateExistingHashes: true,
323
+ throwOnWrongHashes: false,
324
+ });
324
325
  },
325
326
 
326
327
  missingSliceIdSet: (): Rljson => {
@@ -330,7 +331,10 @@ export class Example {
330
331
  layer1.sliceIds = 'MISSING1';
331
332
 
332
333
  // Recalculate hashes
333
- return hip(result, true, false);
334
+ return hip(result, {
335
+ updateExistingHashes: true,
336
+ throwOnWrongHashes: false,
337
+ });
334
338
  },
335
339
 
336
340
  missingAssignedIngredientTable: (): Rljson => {
@@ -342,7 +346,10 @@ export class Example {
342
346
  missingAssignedIngredient: (): Rljson => {
343
347
  const result = Example.ok.complete();
344
348
  result.ingredients._data.splice(1, 2); // Remove an ingredient that is assigned
345
- return hip(result, true, false);
349
+ return hip(result, {
350
+ updateExistingHashes: true,
351
+ throwOnWrongHashes: false,
352
+ });
346
353
  },
347
354
  },
348
355
 
@@ -350,14 +357,20 @@ export class Example {
350
357
  missingSliceIdSet: (): Rljson => {
351
358
  const result = Example.ok.complete();
352
359
  result.cakes._data[0].sliceIds = 'MISSING'; // Missing ID set
353
- hip(result.cakes, true, false);
360
+ hip(result.cakes, {
361
+ updateExistingHashes: true,
362
+ throwOnWrongHashes: false,
363
+ });
354
364
  return result;
355
365
  },
356
366
 
357
367
  missingLayersTable: (): Rljson => {
358
368
  const result = Example.ok.complete();
359
369
  result.cakes._data[0].layersTable = 'MISSING'; // Missing layers table
360
- hip(result.cakes, true, false);
370
+ hip(result.cakes, {
371
+ updateExistingHashes: true,
372
+ throwOnWrongHashes: false,
373
+ });
361
374
  return result;
362
375
  },
363
376
 
@@ -365,7 +378,10 @@ export class Example {
365
378
  const result = Example.ok.complete();
366
379
  result.cakes._data[0].layers['layer0'] = 'MISSING0';
367
380
  result.cakes._data[0].layers['layer1'] = 'MISSING1';
368
- hip(result.cakes, true, false);
381
+ hip(result.cakes, {
382
+ updateExistingHashes: true,
383
+ throwOnWrongHashes: false,
384
+ });
369
385
  return result;
370
386
  },
371
387
  },
@@ -376,7 +392,7 @@ export class Example {
376
392
  const buffet = result.buffets._data[0];
377
393
  buffet.items[0].table = 'MISSING0';
378
394
  buffet.items[1].table = 'MISSING1';
379
- hip(result, true, false);
395
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
380
396
  return result;
381
397
  },
382
398
 
@@ -385,7 +401,7 @@ export class Example {
385
401
  const buffet = result.buffets._data[0];
386
402
  buffet.items[0].ref = 'MISSING0';
387
403
  buffet.items[1].ref = 'MISSING1';
388
- hip(result, true, false);
404
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
389
405
  return result;
390
406
  },
391
407
  },
@@ -1,4 +1,4 @@
1
- import { JsonKey } from '@rljson/json';
1
+ import { Json, JsonKey } from '@rljson/json';
2
2
  /**
3
3
  * A ref is a hash that references to another element
4
4
  */
@@ -37,3 +37,9 @@ export declare const exampleTypedefs: () => {
37
37
  tableKey: TableKey;
38
38
  contentType: ContentType;
39
39
  };
40
+ /**
41
+ * A json object with an optional id
42
+ */
43
+ export type JsonWithId = Json & {
44
+ id?: string;
45
+ };
@@ -16,6 +16,8 @@ export interface BaseErrors extends Errors {
16
16
  columnConfigNotFound?: Json;
17
17
  dataDoesNotMatchColumnConfig?: Json;
18
18
  tableTypesDoNotMatch?: Json;
19
+ rootOrHeadTableHasNoIdColumn?: Json;
20
+ tableCfgHasRootHeadSharedError?: Json;
19
21
  refsNotFound?: Json;
20
22
  layerBasesNotFound?: Json;
21
23
  layerSliceIdsTableNotFound?: Json;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/rljson",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "packageManager": "pnpm@10.6.3",
5
5
  "description": "The RLJSON data format specification",
6
6
  "homepage": "https://github.com/rljson/rljson",
@@ -29,10 +29,10 @@
29
29
  "updateGoldens": "cross-env UPDATE_GOLDENS=true npm test"
30
30
  },
31
31
  "devDependencies": {
32
- "@types/node": "^22.13.14",
33
- "@typescript-eslint/eslint-plugin": "^8.28.0",
34
- "@typescript-eslint/parser": "^8.28.0",
35
- "@vitest/coverage-v8": "^3.0.9",
32
+ "@types/node": "^22.13.17",
33
+ "@typescript-eslint/eslint-plugin": "^8.29.0",
34
+ "@typescript-eslint/parser": "^8.29.0",
35
+ "@vitest/coverage-v8": "^3.1.1",
36
36
  "cross-env": "^7.0.3",
37
37
  "eslint": "^9.23.0",
38
38
  "eslint-plugin-jsdoc": "^50.6.9",
@@ -41,16 +41,16 @@
41
41
  "jsdoc": "^4.0.4",
42
42
  "read-pkg": "^9.0.1",
43
43
  "typescript": "~5.8.2",
44
- "typescript-eslint": "^8.28.0",
45
- "vite": "^6.2.3",
46
- "vite-node": "^3.0.9",
44
+ "typescript-eslint": "^8.29.0",
45
+ "vite": "^6.2.4",
46
+ "vite-node": "^3.1.1",
47
47
  "vite-plugin-dts": "^4.5.3",
48
48
  "vite-tsconfig-paths": "^5.1.4",
49
- "vitest": "^3.0.9",
49
+ "vitest": "^3.1.1",
50
50
  "vitest-dom": "^0.1.1"
51
51
  },
52
52
  "dependencies": {
53
- "@rljson/hash": "^0.0.12",
53
+ "@rljson/hash": "^0.0.13",
54
54
  "@rljson/json": "^0.0.18"
55
55
  },
56
56
  "pnpm": {