@rljson/rljson 0.0.66 → 0.0.68

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.
@@ -4,7 +4,7 @@ import { CakesTable } from '../content/cake.ts';
4
4
  import { ComponentsTable } from '../content/components.ts';
5
5
  import { LayersTable } from '../content/layer.ts';
6
6
  import { SliceIdsTable } from '../content/slice-ids.ts';
7
- import { History } from '../history/history.ts';
7
+ import { InsertHistory } from '../insertHistory/insertHistory.ts';
8
8
  import { Rljson } from '../rljson.ts';
9
9
  import { Ref } from '../typedefs.ts';
10
10
  export interface Ingredient extends Json {
@@ -32,6 +32,6 @@ export interface Bakery extends Rljson {
32
32
  recipeIngredients: ComponentsTable<RecipIngredient>;
33
33
  ingredients: ComponentsTable<Ingredient>;
34
34
  nutritionalValues: ComponentsTable<NutritionalValues>;
35
- ingredientsHistory: History<'Ingredients'>;
35
+ ingredientsInsertHistory: InsertHistory<'Ingredients'>;
36
36
  }
37
37
  export declare const bakeryExample: () => Bakery;
package/dist/index.d.ts CHANGED
@@ -7,9 +7,9 @@ export * from './content/slice-ids.ts';
7
7
  export * from './content/table-cfg.ts';
8
8
  export * from './example.ts';
9
9
  export * from './example/bakery-example.ts';
10
- export * from './history/history.ts';
11
10
  export * from './insert/insert-validator.ts';
12
11
  export * from './insert/insert.ts';
12
+ export * from './insertHistory/insertHistory.ts';
13
13
  export * from './rljson.ts';
14
14
  export * from './route/route.ts';
15
15
  export * from './tools/remove-duplicates.ts';
@@ -0,0 +1,24 @@
1
+ import { TableCfg } from '../content/table-cfg.ts';
2
+ import { RljsonTable } from '../rljson.ts';
3
+ import { RouteRef } from '../route/route.ts';
4
+ import { Ref } from '../typedefs.ts';
5
+ export type InsertHistoryTimeId = string;
6
+ export type InsertHistoryRow<Str extends string> = {
7
+ [key in Str as `${Uncapitalize<string & key>}Ref`]: string;
8
+ } & {
9
+ timeId: InsertHistoryTimeId;
10
+ route: RouteRef;
11
+ origin?: Ref;
12
+ previous?: InsertHistoryTimeId[];
13
+ };
14
+ export type InsertHistory<Str extends string> = RljsonTable<InsertHistoryRow<Str>, 'insertHistory'>;
15
+ /**
16
+ * Creates a TableCfg for a InsertHistory table for the given table configuration
17
+ * @param tableCfg - The table configuration to create the InsertHistory table for
18
+ * @returns The TableCfg for the InsertHistory table
19
+ */
20
+ export declare const createInsertHistoryTableCfg: (tableCfg: TableCfg) => TableCfg;
21
+ /**
22
+ * Provides an example insertHistory table for test purposes
23
+ */
24
+ export declare const exampleInsertHistoryTable: () => InsertHistory<any>;
package/dist/rljson.d.ts CHANGED
@@ -6,14 +6,14 @@ import { LayersTable } from './content/layer.ts';
6
6
  import { RevisionsTable } from './content/revision.ts';
7
7
  import { SliceIdsTable } from './content/slice-ids.ts';
8
8
  import { TableCfgRef, TablesCfgTable } from './content/table-cfg.ts';
9
- import { History } from './history/history.ts';
9
+ import { InsertHistory } from './insertHistory/insertHistory.ts';
10
10
  import { ContentType, Ref, TableKey } from './typedefs.ts';
11
11
  export declare const reservedFieldNames: string[];
12
12
  export declare const reservedTableKeys: string[];
13
13
  /**
14
14
  * One of the supported Rljson table types
15
15
  */
16
- export type TableType = BuffetsTable | ComponentsTable<any> | LayersTable | SliceIdsTable | CakesTable | RevisionsTable | TablesCfgTable | History<any>;
16
+ export type TableType = BuffetsTable | ComponentsTable<any> | LayersTable | SliceIdsTable | CakesTable | RevisionsTable | TablesCfgTable | InsertHistory<any>;
17
17
  /** The rljson data format */
18
18
  export interface Rljson extends Json {
19
19
  [tableId: TableKey]: TableType;
package/dist/rljson.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { hip, hsh } from "@rljson/hash";
2
2
  import { exampleJsonObject, jsonValueTypes, jsonValueMatchesType, jsonValueType } from "@rljson/json";
3
3
  import { nanoid } from "nanoid";
4
- // @license
5
4
  class Route {
6
5
  constructor(_segments) {
7
6
  this._segments = _segments;
8
7
  }
8
+ _propertyKey;
9
9
  // .............................................................................
10
10
  /**
11
11
  * Creates a Route from a flat string representation.
@@ -17,7 +17,7 @@ class Route {
17
17
  const segments = [];
18
18
  for (const segmentFlat of segmentsFlat) {
19
19
  const [tableKey, refFlat] = segmentFlat.split("@");
20
- const ref = !!refFlat ? refFlat.split(":").length == 2 ? { [tableKey + "HistoryRef"]: refFlat } : { [tableKey + "Ref"]: refFlat } : {};
20
+ const ref = !!refFlat ? refFlat.split(":").length == 2 ? { [tableKey + "InsertHistoryRef"]: refFlat } : { [tableKey + "Ref"]: refFlat } : {};
21
21
  const segment = {
22
22
  tableKey,
23
23
  ...ref
@@ -59,6 +59,78 @@ class Route {
59
59
  }
60
60
  }
61
61
  // .............................................................................
62
+ /**
63
+ * Returns a new Route that is one level higher than the current route.
64
+ * If steps is provided, it returns a new Route that is 'steps' levels higher.
65
+ * @param steps - The number of levels to go higher (optional)
66
+ * @returns A new Route that is one level higher or 'steps' levels higher
67
+ */
68
+ upper(steps) {
69
+ if (steps === void 0) {
70
+ return new Route(this._segments.slice(0, -1));
71
+ } else {
72
+ if (steps < 1) {
73
+ throw new Error("Steps must be greater than 0");
74
+ }
75
+ if (steps >= this._segments.length) {
76
+ throw new Error("Cannot go upper than the top level");
77
+ }
78
+ return new Route(this._segments.slice(0, -steps));
79
+ }
80
+ }
81
+ // .............................................................................
82
+ /**
83
+ * Returns a new Route with the property key set to the last segment's table key.
84
+ * If the property key is already set, it returns the current route.
85
+ * @returns A new Route with the property key set
86
+ */
87
+ toRouteWithProperty() {
88
+ if (this.hasPropertyKey) return this;
89
+ const route = this.upper();
90
+ route.propertyKey = this.segment().tableKey;
91
+ return route;
92
+ }
93
+ // .............................................................................
94
+ /**
95
+ * Returns a new Route without the property key.
96
+ * If the property key is not set, it returns the current route.
97
+ * @returns A new Route without the property key
98
+ */
99
+ toRouteWithoutProperty() {
100
+ if (!this.hasPropertyKey) return this;
101
+ const route = new Route(this._segments);
102
+ route.propertyKey = void 0;
103
+ return route;
104
+ }
105
+ // .............................................................................
106
+ /**
107
+ * Checks if the current route includes another route.
108
+ * A route includes another route if all segments of the other route
109
+ * are present in the current route in the same order.
110
+ * @param other - The other route to check
111
+ * @returns True if the current route includes the other route, false otherwise
112
+ */
113
+ includes(other) {
114
+ if (other._segments.length < this._segments.length) {
115
+ return false;
116
+ }
117
+ for (let i = 0; i < this._segments.length; i++) {
118
+ const thisSegment = this._segments[i];
119
+ const otherSegment = other._segments[i];
120
+ if (thisSegment.tableKey !== otherSegment.tableKey) {
121
+ return false;
122
+ }
123
+ if (Route.segmentHasRef(thisSegment) && Route.segmentHasRef(otherSegment)) {
124
+ const thisRef = Route.segmentRef(thisSegment);
125
+ const otherRef = Route.segmentRef(otherSegment);
126
+ if (thisRef !== otherRef) {
127
+ return false;
128
+ }
129
+ }
130
+ }
131
+ return true;
132
+ }
133
+ // .............................................................................
62
134
  /**
63
135
  * Checks if the current route is the root route.
64
136
  * @returns True if the current route is the root route, false otherwise
@@ -72,6 +144,18 @@ class Route {
72
144
  * @returns The flat string representation of the route (e.g. "/a/b/c")
73
145
  */
74
146
  get flat() {
147
+ let flat = this.flatWithoutPropertyKey;
148
+ if (this.hasPropertyKey) {
149
+ flat += `/${this.propertyKey}`;
150
+ }
151
+ return flat;
152
+ }
153
+ // .............................................................................
154
+ /**
155
+ * Returns the flat string representation of the route without the property key.
156
+ * @returns The flat string representation of the route without the property key
157
+ */
158
+ get flatWithoutPropertyKey() {
75
159
  let flat = "";
76
160
  for (const segment of this._segments) {
77
161
  const tableKey = segment.tableKey;
@@ -81,6 +165,22 @@ class Route {
81
165
  return flat;
82
166
  }
83
167
  // .............................................................................
168
+ /**
169
+ * Returns the flat string representation of the route without any references.
170
+ * @returns The flat string representation of the route without any references
171
+ */
172
+ get flatWithoutRefs() {
173
+ let flat = "";
174
+ for (const segment of this._segments) {
175
+ const tableKey = segment.tableKey;
176
+ flat += `/${tableKey}`;
177
+ }
178
+ if (this.hasPropertyKey) {
179
+ flat += `/${this.propertyKey}`;
180
+ }
181
+ return flat;
182
+ }
183
+ // .............................................................................
84
184
  /**
85
185
  * Returns the segments of the route as an array of strings.
86
186
  * @returns The segments of the route as an array of strings
@@ -121,6 +221,57 @@ class Route {
121
221
  return this._segments.length > 0 && this._segments.every((s) => s.tableKey.length > 0);
122
222
  }
123
223
  // .............................................................................
224
+ /**
225
+ * Checks if the route has a property key.
226
+ * @returns True if the route has a property key, false otherwise
227
+ */
228
+ get hasPropertyKey() {
229
+ return this._propertyKey !== void 0;
230
+ }
231
+ // .............................................................................
232
+ /**
233
+ * Returns the property key of the route if it exists.
234
+ * @returns The property key of the route or undefined if it doesn't exist
235
+ */
236
+ get propertyKey() {
237
+ return this._propertyKey;
238
+ }
239
+ // .............................................................................
240
+ /**
241
+ * Sets the property key of the route.
242
+ * @param key - The property key to set
243
+ */
244
+ set propertyKey(key) {
245
+ this._propertyKey = key;
246
+ }
247
+ // .............................................................................
248
+ /**
249
+ * Checks if two routes are equal.
250
+ * @param other - The other route to compare with
251
+ * @returns True if the routes are equal, false otherwise
252
+ */
253
+ equals(other) {
254
+ return this.flat === other.flat;
255
+ }
256
+ // .............................................................................
257
+ /**
258
+ * Checks if two routes are equal without considering the property key.
259
+ * @param other - The other route to compare with
260
+ * @returns True if the routes are equal without considering the property key, false otherwise
261
+ */
262
+ equalsWithoutPropertyKey(other) {
263
+ return this.flatWithoutPropertyKey === other.flatWithoutPropertyKey;
264
+ }
265
+ // .............................................................................
266
+ /**
267
+ * Checks if two routes are equal without considering the references.
268
+ * @param other - The other route to compare with
269
+ * @returns True if the routes are equal without considering the references, false otherwise
270
+ */
271
+ equalsWithoutRefs(other) {
272
+ return this.flatWithoutRefs === other.flatWithoutRefs;
273
+ }
274
+ // .............................................................................
124
275
  /**
125
276
  * Returns the reference of a segment if it exists.
126
277
  * @param segment - The segment to get the reference from
@@ -131,7 +282,6 @@ class Route {
131
282
  const refKey = Object.keys(segment).find(
132
283
  (k) => k.endsWith("Ref") && k !== "tableKey"
133
284
  );
134
- /* v8 ignore next -- @preserve */
135
285
  if (refKey) {
136
286
  return segment[refKey];
137
287
  }
@@ -140,7 +290,7 @@ class Route {
140
290
  }
141
291
  // .............................................................................
142
292
  /**
143
- * Checks if a segment has any reference (either default or history).
293
+ * Checks if a segment has any reference (either default or insertHistory).
144
294
  * @param segment - The segment to check
145
295
  * @returns True if the segment has any reference, false otherwise
146
296
  */
@@ -149,24 +299,23 @@ class Route {
149
299
  }
150
300
  // .............................................................................
151
301
  /**
152
- * Checks if a segment has a default reference (i.e. not a history reference).
302
+ * Checks if a segment has a default reference (i.e. not a insertHistory reference).
153
303
  * @param segment - The segment to check
154
304
  * @returns True if the segment has a default reference, false otherwise
155
305
  */
156
306
  static segmentHasDefaultRef(segment) {
157
- return this.segmentHasRef(segment) && !this.segmentHasHistoryRef(segment);
307
+ return this.segmentHasRef(segment) && !this.segmentHasInsertHistoryRef(segment);
158
308
  }
159
309
  // .............................................................................
160
310
  /**
161
- * Checks if a segment has a history reference (i.e. an HistoryRef).
311
+ * Checks if a segment has a insertHistory reference (i.e. an InsertHistoryRef).
162
312
  * @param segment - The segment to check
163
- * @returns True if the segment has a history reference, false otherwise
313
+ * @returns True if the segment has a insertHistory reference, false otherwise
164
314
  */
165
- static segmentHasHistoryRef(segment) {
166
- return this.segmentHasRef(segment) && Object.keys(segment).some((k) => k.endsWith("HistoryRef"));
315
+ static segmentHasInsertHistoryRef(segment) {
316
+ return this.segmentHasRef(segment) && Object.keys(segment).some((k) => k.endsWith("InsertHistoryRef"));
167
317
  }
168
318
  }
169
- // @license
170
319
  const bakeryExample = () => {
171
320
  const nutritionalValues = hip({
172
321
  _type: "components",
@@ -294,8 +443,8 @@ const bakeryExample = () => {
294
443
  }
295
444
  ]
296
445
  });
297
- const ingredientsHistory = hip({
298
- _type: "history",
446
+ const ingredientsInsertHistory = hip({
447
+ _type: "insertHistory",
299
448
  _data: [
300
449
  {
301
450
  timeId: "de72:1759123957292",
@@ -324,13 +473,11 @@ const bakeryExample = () => {
324
473
  recipeIngredients,
325
474
  ingredients,
326
475
  nutritionalValues,
327
- ingredientsHistory
476
+ ingredientsInsertHistory
328
477
  };
329
478
  return result;
330
479
  };
331
- // @license
332
480
  const exampleBuffetsTable = () => bakeryExample().buffets;
333
- // @license
334
481
  const createCakeTableCfg = (cakeKey) => ({
335
482
  key: cakeKey,
336
483
  type: "cakes",
@@ -356,9 +503,7 @@ const createCakeTableCfg = (cakeKey) => ({
356
503
  isShared: true
357
504
  });
358
505
  const exampleCakesTable = () => bakeryExample().cakes;
359
- // @license
360
506
  const exampleComponentsTable = () => bakeryExample().nutritionalValues;
361
- // @license
362
507
  const createLayerTableCfg = (layerKey) => ({
363
508
  key: layerKey,
364
509
  type: "layers",
@@ -391,7 +536,6 @@ const createLayerTableCfg = (layerKey) => ({
391
536
  isShared: true
392
537
  });
393
538
  const exampleLayersTable = () => bakeryExample().recipeLayers;
394
- // @license
395
539
  const exampleRevision = () => ({
396
540
  table: "nutritionalValues",
397
541
  id: "flour",
@@ -399,9 +543,7 @@ const exampleRevision = () => ({
399
543
  successor: "IqeoWJjZQNlr-NVk2QT15B",
400
544
  timestamp: 1743558427
401
545
  });
402
- // @license
403
546
  const exampleSliceIdsTable = () => bakeryExample().slices;
404
- // @license
405
547
  class Example {
406
548
  static ok = {
407
549
  bakery: () => bakeryExample(),
@@ -1188,7 +1330,6 @@ class Example {
1188
1330
  }
1189
1331
  };
1190
1332
  }
1191
- // @license
1192
1333
  const throwOnInvalidTableCfg = (tableCfg) => {
1193
1334
  if (tableCfg.columns.length < 2) {
1194
1335
  throw new Error(
@@ -1295,46 +1436,7 @@ const exampleTableCfg = (tableCfg = void 0) => {
1295
1436
  isShared: false
1296
1437
  };
1297
1438
  };
1298
- // @license
1299
- const createHistoryTableCfg = (tableCfg) => ({
1300
- key: `${tableCfg.key}History`,
1301
- type: "history",
1302
- columns: [
1303
- { key: "_hash", type: "string", titleLong: "Hash", titleShort: "Hash" },
1304
- {
1305
- key: "timeId",
1306
- type: "string",
1307
- titleLong: "Time ID",
1308
- titleShort: "Time ID"
1309
- },
1310
- {
1311
- key: `${tableCfg.key}Ref`,
1312
- type: "string",
1313
- titleLong: "Reference",
1314
- titleShort: "Ref"
1315
- },
1316
- { key: "route", type: "string", titleLong: "Route", titleShort: "Route" },
1317
- {
1318
- key: "origin",
1319
- type: "string",
1320
- titleLong: "Origin",
1321
- titleShort: "Origin"
1322
- },
1323
- {
1324
- key: "previous",
1325
- type: "jsonArray",
1326
- titleLong: "Previous",
1327
- titleShort: "Previous"
1328
- }
1329
- ],
1330
- isHead: false,
1331
- isRoot: false,
1332
- isShared: false
1333
- });
1334
- const exampleHistoryTable = () => bakeryExample().ingredientsHistory;
1335
- // @license
1336
1439
  const objectDepth = (o) => Object(o) === o ? 1 + Math.max(-1, ...Object.values(o).map(objectDepth)) : 0;
1337
- // @license
1338
1440
  class InsertValidator {
1339
1441
  constructor(_insert) {
1340
1442
  this._insert = _insert;
@@ -1388,9 +1490,9 @@ class InsertValidator {
1388
1490
  if (route.isValid) {
1389
1491
  const routeDepth = route.segments.length;
1390
1492
  const valueDepth = objectDepth(this._insert.value);
1391
- if (routeDepth !== valueDepth) {
1493
+ if (routeDepth > valueDepth) {
1392
1494
  this.errors.dataRouteMismatch = {
1393
- error: "Insert route depth does not match value depth. Route depth must match the depth of the value object.",
1495
+ error: "Insert route depth does not match value depth. Route depth must be lower than the depth of the value object.",
1394
1496
  route: this._insert.route,
1395
1497
  routeDepth,
1396
1498
  valueDepth
@@ -1440,13 +1542,47 @@ class InsertValidator {
1440
1542
  const validateInsert = (insert) => {
1441
1543
  return InsertValidator.create(insert).validate();
1442
1544
  };
1443
- // @license
1444
1545
  const exampleInsert = () => ({
1445
1546
  route: "a/b/c",
1446
1547
  command: "add",
1447
1548
  value: { x: { y: { z: true } } }
1448
1549
  });
1449
- // @license
1550
+ const createInsertHistoryTableCfg = (tableCfg) => ({
1551
+ key: `${tableCfg.key}InsertHistory`,
1552
+ type: "insertHistory",
1553
+ columns: [
1554
+ { key: "_hash", type: "string", titleLong: "Hash", titleShort: "Hash" },
1555
+ {
1556
+ key: "timeId",
1557
+ type: "string",
1558
+ titleLong: "Time ID",
1559
+ titleShort: "Time ID"
1560
+ },
1561
+ {
1562
+ key: `${tableCfg.key}Ref`,
1563
+ type: "string",
1564
+ titleLong: "Reference",
1565
+ titleShort: "Ref"
1566
+ },
1567
+ { key: "route", type: "string", titleLong: "Route", titleShort: "Route" },
1568
+ {
1569
+ key: "origin",
1570
+ type: "string",
1571
+ titleLong: "Origin",
1572
+ titleShort: "Origin"
1573
+ },
1574
+ {
1575
+ key: "previous",
1576
+ type: "jsonArray",
1577
+ titleLong: "Previous",
1578
+ titleShort: "Previous"
1579
+ }
1580
+ ],
1581
+ isHead: false,
1582
+ isRoot: false,
1583
+ isShared: false
1584
+ });
1585
+ const exampleInsertHistoryTable = () => bakeryExample().ingredientsInsertHistory;
1450
1586
  const reservedFieldNames = ["_data"];
1451
1587
  const reservedTableKeys = [
1452
1588
  "_hash",
@@ -1486,7 +1622,6 @@ const iterateTables = async (rljson, callback) => {
1486
1622
  throw errors;
1487
1623
  }
1488
1624
  };
1489
- // @license
1490
1625
  const removeDuplicates = (rljson) => {
1491
1626
  const result = {};
1492
1627
  for (const key in rljson) {
@@ -1500,17 +1635,25 @@ const removeDuplicates = (rljson) => {
1500
1635
  }
1501
1636
  return hip(result, { throwOnWrongHashes: false, updateExistingHashes: true });
1502
1637
  };
1503
- // @license
1504
1638
  const timeId = () => {
1505
- return nanoid(4) + ":" + Date.now();
1639
+ return Date.now() + ":" + nanoid(4);
1506
1640
  };
1507
1641
  const isTimeId = (id) => {
1508
1642
  const parts = id.split(":");
1509
1643
  if (parts.length !== 2) return false;
1510
- if (isNaN(Number(parts[1]))) return false;
1511
- return parts[0].length === 4;
1644
+ if (isNaN(Number(parts[0]))) return false;
1645
+ return parts[1].length === 4;
1646
+ };
1647
+ const getTimeIdTimestamp = (id) => {
1648
+ if (!isTimeId(id)) return null;
1649
+ const parts = id.split(":");
1650
+ return Number(parts[0]);
1651
+ };
1652
+ const getTimeIdUniquePart = (id) => {
1653
+ if (!isTimeId(id)) return null;
1654
+ const parts = id.split(":");
1655
+ return parts[1];
1512
1656
  };
1513
- // @license
1514
1657
  const contentTypes = [
1515
1658
  "buffets",
1516
1659
  "cakes",
@@ -1519,7 +1662,7 @@ const contentTypes = [
1519
1662
  "components",
1520
1663
  "revisions",
1521
1664
  "tableCfgs",
1522
- "history"
1665
+ "insertHistory"
1523
1666
  ];
1524
1667
  const exampleTypedefs = () => {
1525
1668
  return {
@@ -1529,7 +1672,6 @@ const exampleTypedefs = () => {
1529
1672
  contentType: "layers"
1530
1673
  };
1531
1674
  };
1532
- // @license
1533
1675
  const rljsonIndexed = (rljson) => {
1534
1676
  const result = {};
1535
1677
  for (const key in rljson) {
@@ -1552,7 +1694,6 @@ const rljsonIndexed = (rljson) => {
1552
1694
  }
1553
1695
  return result;
1554
1696
  };
1555
- // @license
1556
1697
  class BaseValidator {
1557
1698
  name = "base";
1558
1699
  async validate(rljson) {
@@ -1968,7 +2109,6 @@ class _BaseValidator {
1968
2109
  const tableCfgRef = table._tableCfg;
1969
2110
  if (!tableCfgRef) return;
1970
2111
  const tableCfg = this.rljsonIndexed.tableCfgs._data[tableCfgRef];
1971
- /* v8 ignore next -- @preserve */
1972
2112
  if (!tableCfg) return;
1973
2113
  const tableRows = table._data;
1974
2114
  for (const row of tableRows) {
@@ -1977,7 +2117,6 @@ class _BaseValidator {
1977
2117
  const columnCfg = tableCfg.columns.find(
1978
2118
  (col) => col.key === columnKey
1979
2119
  );
1980
- /* v8 ignore next -- @preserve */
1981
2120
  if (columnCfg === void 0) continue;
1982
2121
  if (columnCfg.ref && columnCfg.ref.tableKey) {
1983
2122
  const targetTableKey = columnCfg.ref.tableKey;
@@ -2331,7 +2470,6 @@ class _BaseValidator {
2331
2470
  }
2332
2471
  }
2333
2472
  const isValidFieldName = (fieldName) => BaseValidator.isValidFieldName(fieldName);
2334
- // @license
2335
2473
  class Validate {
2336
2474
  addValidator(validator) {
2337
2475
  this._validators.push(validator);
@@ -2376,13 +2514,13 @@ export {
2376
2514
  bakeryExample,
2377
2515
  contentTypes,
2378
2516
  createCakeTableCfg,
2379
- createHistoryTableCfg,
2517
+ createInsertHistoryTableCfg,
2380
2518
  createLayerTableCfg,
2381
2519
  exampleBuffetsTable,
2382
2520
  exampleCakesTable,
2383
2521
  exampleComponentsTable,
2384
- exampleHistoryTable,
2385
2522
  exampleInsert,
2523
+ exampleInsertHistoryTable,
2386
2524
  exampleLayersTable,
2387
2525
  exampleRevision,
2388
2526
  exampleRljson,
@@ -2390,6 +2528,8 @@ export {
2390
2528
  exampleTableCfg,
2391
2529
  exampleTableCfgTable,
2392
2530
  exampleTypedefs,
2531
+ getTimeIdTimestamp,
2532
+ getTimeIdUniquePart,
2393
2533
  isTimeId,
2394
2534
  isValidFieldName,
2395
2535
  iterateTables,
@@ -11,6 +11,7 @@ export type RouteSegmentFlat<N extends string> = `${N}` | `${N}@${string}` | `${
11
11
  */
12
12
  export declare class Route {
13
13
  private readonly _segments;
14
+ private _propertyKey?;
14
15
  constructor(_segments: RouteSegment<any>[]);
15
16
  /**
16
17
  * Creates a Route from a flat string representation.
@@ -31,6 +32,33 @@ export declare class Route {
31
32
  * @returns A new Route that is one level deeper or 'steps' levels deeper
32
33
  */
33
34
  deeper(steps?: number): Route;
35
+ /**
36
+ * Returns a new Route that is one level higher than the current route.
37
+ * If steps is provided, it returns a new Route that is 'steps' levels higher.
38
+ * @param steps - The number of levels to go higher (optional)
39
+ * @returns A new Route that is one level higher or 'steps' levels higher
40
+ */
41
+ upper(steps?: number): Route;
42
+ /**
43
+ * Returns a new Route with the property key set to the last segment's table key.
44
+ * If the property key is already set, it returns the current route.
45
+ * @returns A new Route with the property key set
46
+ */
47
+ toRouteWithProperty(): Route;
48
+ /**
49
+ * Returns a new Route without the property key.
50
+ * If the property key is not set, it returns the current route.
51
+ * @returns A new Route without the property key
52
+ */
53
+ toRouteWithoutProperty(): Route;
54
+ /**
55
+ * Checks if the current route includes another route.
56
+ * A route includes another route if all segments of the other route
57
+ * are present in the current route in the same order.
58
+ * @param other - The other route to check
59
+ * @returns True if the current route includes the other route, false otherwise
60
+ */
61
+ includes(other: Route): boolean;
34
62
  /**
35
63
  * Checks if the current route is the root route.
36
64
  * @returns True if the current route is the root route, false otherwise
@@ -41,6 +69,16 @@ export declare class Route {
41
69
  * @returns The flat string representation of the route (e.g. "/a/b/c")
42
70
  */
43
71
  get flat(): string;
72
+ /**
73
+ * Returns the flat string representation of the route without the property key.
74
+ * @returns The flat string representation of the route without the property key
75
+ */
76
+ get flatWithoutPropertyKey(): string;
77
+ /**
78
+ * Returns the flat string representation of the route without any references.
79
+ * @returns The flat string representation of the route without any references
80
+ */
81
+ get flatWithoutRefs(): string;
44
82
  /**
45
83
  * Returns the segments of the route as an array of strings.
46
84
  * @returns The segments of the route as an array of strings
@@ -66,6 +104,39 @@ export declare class Route {
66
104
  * @returns True if the route is valid, false otherwise
67
105
  */
68
106
  get isValid(): boolean;
107
+ /**
108
+ * Checks if the route has a property key.
109
+ * @returns True if the route has a property key, false otherwise
110
+ */
111
+ get hasPropertyKey(): boolean;
112
+ /**
113
+ * Returns the property key of the route if it exists.
114
+ * @returns The property key of the route or undefined if it doesn't exist
115
+ */
116
+ get propertyKey(): string | undefined;
117
+ /**
118
+ * Sets the property key of the route.
119
+ * @param key - The property key to set
120
+ */
121
+ set propertyKey(key: string | undefined);
122
+ /**
123
+ * Checks if two routes are equal.
124
+ * @param other - The other route to compare with
125
+ * @returns True if the routes are equal, false otherwise
126
+ */
127
+ equals(other: Route): boolean;
128
+ /**
129
+ * Checks if two routes are equal without considering the property key.
130
+ * @param other - The other route to compare with
131
+ * @returns True if the routes are equal without considering the property key, false otherwise
132
+ */
133
+ equalsWithoutPropertyKey(other: Route): boolean;
134
+ /**
135
+ * Checks if two routes are equal without considering the references.
136
+ * @param other - The other route to compare with
137
+ * @returns True if the routes are equal without considering the references, false otherwise
138
+ */
139
+ equalsWithoutRefs(other: Route): boolean;
69
140
  /**
70
141
  * Returns the reference of a segment if it exists.
71
142
  * @param segment - The segment to get the reference from
@@ -73,21 +144,21 @@ export declare class Route {
73
144
  */
74
145
  static segmentRef(segment: RouteSegment<any>): string | undefined;
75
146
  /**
76
- * Checks if a segment has any reference (either default or history).
147
+ * Checks if a segment has any reference (either default or insertHistory).
77
148
  * @param segment - The segment to check
78
149
  * @returns True if the segment has any reference, false otherwise
79
150
  */
80
151
  static segmentHasRef(segment: RouteSegment<any>): boolean;
81
152
  /**
82
- * Checks if a segment has a default reference (i.e. not a history reference).
153
+ * Checks if a segment has a default reference (i.e. not a insertHistory reference).
83
154
  * @param segment - The segment to check
84
155
  * @returns True if the segment has a default reference, false otherwise
85
156
  */
86
157
  static segmentHasDefaultRef(segment: RouteSegment<any>): boolean;
87
158
  /**
88
- * Checks if a segment has a history reference (i.e. an HistoryRef).
159
+ * Checks if a segment has a insertHistory reference (i.e. an InsertHistoryRef).
89
160
  * @param segment - The segment to check
90
- * @returns True if the segment has a history reference, false otherwise
161
+ * @returns True if the segment has a insertHistory reference, false otherwise
91
162
  */
92
- static segmentHasHistoryRef(segment: RouteSegment<any>): boolean;
163
+ static segmentHasInsertHistoryRef(segment: RouteSegment<any>): boolean;
93
164
  }
@@ -15,3 +15,15 @@ export declare const timeId: () => string;
15
15
  * @returns True if the id is a valid TimeId, false otherwise
16
16
  */
17
17
  export declare const isTimeId: (id: string) => boolean;
18
+ /**
19
+ * Extracts the timestamp from a TimeId.
20
+ * @param id - The TimeId string
21
+ * @returns The timestamp in milliseconds since epoch, or null if the id is not a valid TimeId
22
+ */
23
+ export declare const getTimeIdTimestamp: (id: string) => number | null;
24
+ /**
25
+ * Extracts the unique part from a TimeId.
26
+ * @param id - The TimeId string
27
+ * @returns The unique identifier part, or null if the id is not a valid TimeId
28
+ */
29
+ export declare const getTimeIdUniquePart: (id: string) => string | null;
@@ -26,7 +26,7 @@ export type ColumnKey = JsonKey;
26
26
  * - `ids` Tables containing slice ids
27
27
  * - `components` Tables containing slice components
28
28
  */
29
- export declare const contentTypes: readonly ["buffets", "cakes", "layers", "sliceIds", "components", "revisions", "tableCfgs", "history"];
29
+ export declare const contentTypes: readonly ["buffets", "cakes", "layers", "sliceIds", "components", "revisions", "tableCfgs", "insertHistory"];
30
30
  export type ContentType = (typeof contentTypes)[number];
31
31
  /**
32
32
  * An example object using the typedefs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/rljson",
3
- "version": "0.0.66",
3
+ "version": "0.0.68",
4
4
  "description": "The RLJSON data format specification",
5
5
  "homepage": "https://github.com/rljson/rljson",
6
6
  "bugs": "https://github.com/rljson/rljson/issues",
@@ -20,29 +20,29 @@
20
20
  ],
21
21
  "type": "module",
22
22
  "devDependencies": {
23
- "@types/node": "^24.9.1",
24
- "@typescript-eslint/eslint-plugin": "^8.46.2",
25
- "@typescript-eslint/parser": "^8.46.2",
26
- "@vitest/coverage-v8": "^4.0.1",
23
+ "@types/node": "^24.10.0",
24
+ "@typescript-eslint/eslint-plugin": "^8.46.3",
25
+ "@typescript-eslint/parser": "^8.46.3",
26
+ "@vitest/coverage-v8": "^4.0.7",
27
27
  "cross-env": "^10.1.0",
28
- "eslint": "^9.38.0",
29
- "eslint-plugin-jsdoc": "^61.1.5",
28
+ "eslint": "^9.39.1",
29
+ "eslint-plugin-jsdoc": "^61.1.12",
30
30
  "eslint-plugin-tsdoc": "^0.4.0",
31
- "globals": "^16.4.0",
31
+ "globals": "^16.5.0",
32
32
  "jsdoc": "^4.0.5",
33
33
  "read-pkg": "^9.0.1",
34
34
  "typescript": "~5.9.3",
35
- "typescript-eslint": "^8.46.2",
36
- "vite": "^7.1.12",
37
- "vite-node": "^3.2.4",
35
+ "typescript-eslint": "^8.46.3",
36
+ "vite": "^7.2.1",
37
+ "vite-node": "^5.0.0",
38
38
  "vite-plugin-dts": "^4.5.4",
39
39
  "vite-tsconfig-paths": "^5.1.4",
40
- "vitest": "^4.0.1",
40
+ "vitest": "^4.0.7",
41
41
  "vitest-dom": "^0.1.1"
42
42
  },
43
43
  "dependencies": {
44
44
  "@rljson/hash": "^0.0.17",
45
- "@rljson/json": "^0.0.22",
45
+ "@rljson/json": "^0.0.23",
46
46
  "nanoid": "^5.1.6"
47
47
  },
48
48
  "scripts": {
@@ -1,24 +0,0 @@
1
- import { TableCfg } from '../content/table-cfg.ts';
2
- import { RljsonTable } from '../rljson.ts';
3
- import { RouteRef } from '../route/route.ts';
4
- import { Ref } from '../typedefs.ts';
5
- export type HistoryTimeId = string;
6
- export type HistoryRow<Str extends string> = {
7
- [key in Str as `${Uncapitalize<string & key>}Ref`]: string;
8
- } & {
9
- timeId: HistoryTimeId;
10
- route: RouteRef;
11
- origin?: Ref;
12
- previous?: HistoryTimeId[];
13
- };
14
- export type History<Str extends string> = RljsonTable<HistoryRow<Str>, 'history'>;
15
- /**
16
- * Creates a TableCfg for a History table for the given table configuration
17
- * @param tableCfg - The table configuration to create the History table for
18
- * @returns The TableCfg for the History table
19
- */
20
- export declare const createHistoryTableCfg: (tableCfg: TableCfg) => TableCfg;
21
- /**
22
- * Provides an example history table for test purposes
23
- */
24
- export declare const exampleHistoryTable: () => History<any>;