@rljson/rljson 0.0.61 → 0.0.64
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/dist/content/cake.d.ts +1 -1
- package/dist/content/table-cfg.d.ts +17 -0
- package/dist/edit/history.d.ts +24 -0
- package/dist/edit/insert-validator.d.ts +47 -0
- package/dist/edit/insert.d.ts +19 -0
- package/dist/example/bakery-example.d.ts +2 -2
- package/dist/index.d.ts +4 -2
- package/dist/rljson.d.ts +2 -2
- package/dist/rljson.js +369 -35
- package/dist/route/route.d.ts +93 -0
- package/dist/src/example.ts +19 -0
- package/dist/tools/object-depth.d.ts +1 -0
- package/dist/tools/time-id.d.ts +16 -0
- package/dist/typedefs.d.ts +1 -1
- package/package.json +9 -9
- package/dist/edit/edit.d.ts +0 -29
- package/dist/edit/route.d.ts +0 -13
package/dist/content/cake.d.ts
CHANGED
|
@@ -17,6 +17,23 @@ export interface ColumnCfg extends Json {
|
|
|
17
17
|
* The type of the column
|
|
18
18
|
*/
|
|
19
19
|
type: JsonValueType;
|
|
20
|
+
/**
|
|
21
|
+
* An optional long title of the column
|
|
22
|
+
*/
|
|
23
|
+
titleLong: string;
|
|
24
|
+
/**
|
|
25
|
+
* An optional short title of the column
|
|
26
|
+
*/
|
|
27
|
+
titleShort: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A column configuration with route
|
|
31
|
+
*/
|
|
32
|
+
export interface ColumnCfgWithRoute extends ColumnCfg {
|
|
33
|
+
/**
|
|
34
|
+
* An optional route for reference columns
|
|
35
|
+
*/
|
|
36
|
+
route: string;
|
|
20
37
|
}
|
|
21
38
|
/**
|
|
22
39
|
* Describes the configuration of a table, i.e. table metadata and columns
|
|
@@ -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 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>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Json } from '@rljson/json';
|
|
2
|
+
import { Errors } from '../validate/validate.ts';
|
|
3
|
+
import { Insert } from './insert.ts';
|
|
4
|
+
export interface InsertErrors extends Errors {
|
|
5
|
+
invalidObject?: Json;
|
|
6
|
+
parameterInvalid?: Json;
|
|
7
|
+
parameterRouteInvalid?: Json;
|
|
8
|
+
parameterCommandInvalid?: Json;
|
|
9
|
+
parameterValueInvalid?: Json;
|
|
10
|
+
parameterOriginInvalid?: Json;
|
|
11
|
+
parameterPreviousInvalid?: Json;
|
|
12
|
+
routeInvalid?: Json;
|
|
13
|
+
dataRouteMismatch?: Json;
|
|
14
|
+
}
|
|
15
|
+
export declare class InsertValidator<T extends Json> {
|
|
16
|
+
private _insert;
|
|
17
|
+
errors: InsertErrors;
|
|
18
|
+
/**
|
|
19
|
+
* Indicates whether there are any errors
|
|
20
|
+
* @returns boolean - True if there are errors, false otherwise
|
|
21
|
+
*/
|
|
22
|
+
get hasErrors(): boolean;
|
|
23
|
+
constructor(_insert: Insert<T>);
|
|
24
|
+
/**
|
|
25
|
+
* Validates the Insert object
|
|
26
|
+
* @returns InsertErrors - The errors found during validation
|
|
27
|
+
*/
|
|
28
|
+
validate(): InsertErrors;
|
|
29
|
+
/**
|
|
30
|
+
* Recursively checks that all reference keys in the value match the route segments
|
|
31
|
+
* @param route - The current route segment
|
|
32
|
+
* @param value - The current value object
|
|
33
|
+
*/
|
|
34
|
+
private _checkMatchingRefs;
|
|
35
|
+
/**
|
|
36
|
+
* Creates an InsertValidator for the given Insert object
|
|
37
|
+
* @param insert - The Insert object to validate
|
|
38
|
+
* @returns InsertValidator - The InsertValidator instance
|
|
39
|
+
*/
|
|
40
|
+
static create(insert: Insert<any>): InsertValidator<any>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Validates the given Insert object
|
|
44
|
+
* @param insert - The Insert object to validate
|
|
45
|
+
* @returns InsertErrors - The errors found during validation
|
|
46
|
+
*/
|
|
47
|
+
export declare const validateInsert: (insert: Insert<any>) => InsertErrors;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Json } from '@rljson/json';
|
|
2
|
+
import { RouteRef } from '../route/route.ts';
|
|
3
|
+
import { Ref } from '../typedefs.ts';
|
|
4
|
+
/**
|
|
5
|
+
* An Insert Object describing inserts on data basically
|
|
6
|
+
*/
|
|
7
|
+
export type InsertRef = Ref;
|
|
8
|
+
export type InsertCommand = 'add' | 'remove';
|
|
9
|
+
/**
|
|
10
|
+
* An Insert describes a change to be applied to an Rljson object.
|
|
11
|
+
* @param T - The type of the value being edited, extending Json
|
|
12
|
+
*/
|
|
13
|
+
export type Insert<T extends Json> = {
|
|
14
|
+
command: InsertCommand;
|
|
15
|
+
value: T;
|
|
16
|
+
route: RouteRef;
|
|
17
|
+
origin?: Ref;
|
|
18
|
+
acknowledged?: boolean;
|
|
19
|
+
};
|
|
@@ -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 {
|
|
7
|
+
import { History } from '../edit/history.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
|
-
|
|
35
|
+
ingredientsHistory: History<'Ingredients'>;
|
|
36
36
|
}
|
|
37
37
|
export declare const bakeryExample: () => Bakery;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,13 @@ export * from './content/layer.ts';
|
|
|
5
5
|
export * from './content/revision.ts';
|
|
6
6
|
export * from './content/slice-ids.ts';
|
|
7
7
|
export * from './content/table-cfg.ts';
|
|
8
|
-
export * from './edit/
|
|
9
|
-
export * from './edit/
|
|
8
|
+
export * from './edit/history.ts';
|
|
9
|
+
export * from './edit/insert-validator.ts';
|
|
10
|
+
export * from './edit/insert.ts';
|
|
10
11
|
export * from './example.ts';
|
|
11
12
|
export * from './example/bakery-example.ts';
|
|
12
13
|
export * from './rljson.ts';
|
|
14
|
+
export * from './route/route.ts';
|
|
13
15
|
export * from './tools/remove-duplicates.ts';
|
|
14
16
|
export * from './tools/time-id.ts';
|
|
15
17
|
export * from './typedefs.ts';
|
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 {
|
|
9
|
+
import { History } from './edit/history.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 |
|
|
16
|
+
export type TableType = BuffetsTable | ComponentsTable<any> | LayersTable | SliceIdsTable | CakesTable | RevisionsTable | TablesCfgTable | History<any>;
|
|
17
17
|
/** The rljson data format */
|
|
18
18
|
export interface Rljson extends Json {
|
|
19
19
|
[tableId: TableKey]: TableType;
|
package/dist/rljson.js
CHANGED
|
@@ -3,36 +3,166 @@ import { exampleJsonObject, jsonValueTypes, jsonValueMatchesType, jsonValueType
|
|
|
3
3
|
import { nanoid } from "nanoid";
|
|
4
4
|
// @license
|
|
5
5
|
class Route {
|
|
6
|
-
constructor(
|
|
7
|
-
this.
|
|
6
|
+
constructor(_segments) {
|
|
7
|
+
this._segments = _segments;
|
|
8
8
|
}
|
|
9
|
+
// .............................................................................
|
|
10
|
+
/**
|
|
11
|
+
* Creates a Route from a flat string representation.
|
|
12
|
+
* @param route - The flat string representation of the route (e.g. "/a/b/c")
|
|
13
|
+
* @returns A Route object
|
|
14
|
+
*/
|
|
9
15
|
static fromFlat(route) {
|
|
10
|
-
|
|
16
|
+
const segmentsFlat = route.split("/").filter((s) => s.length > 0);
|
|
17
|
+
const segments = [];
|
|
18
|
+
for (const segmentFlat of segmentsFlat) {
|
|
19
|
+
const [tableKey, refFlat] = segmentFlat.split("@");
|
|
20
|
+
const ref = !!refFlat ? refFlat.split(":").length == 2 ? { [tableKey + "HistoryRef"]: refFlat } : { [tableKey + "Ref"]: refFlat } : {};
|
|
21
|
+
const segment = {
|
|
22
|
+
tableKey,
|
|
23
|
+
...ref
|
|
24
|
+
};
|
|
25
|
+
segments.push(segment);
|
|
26
|
+
}
|
|
27
|
+
return new Route(segments);
|
|
11
28
|
}
|
|
29
|
+
// .............................................................................
|
|
30
|
+
/**
|
|
31
|
+
* Returns the segment at the given index or the last segment if no index is provided.
|
|
32
|
+
* @param index - The index of the segment to return (optional)
|
|
33
|
+
* @returns The segment at the given index or the last segment
|
|
34
|
+
*/
|
|
12
35
|
segment(index) {
|
|
13
36
|
if (index === void 0) {
|
|
14
|
-
return this.
|
|
37
|
+
return this._segments[this._segments.length - 1];
|
|
15
38
|
}
|
|
16
|
-
return this.
|
|
39
|
+
return this._segments[index];
|
|
17
40
|
}
|
|
41
|
+
// .............................................................................
|
|
42
|
+
/**
|
|
43
|
+
* Returns a new Route that is one level deeper than the current route.
|
|
44
|
+
* If steps is provided, it returns a new Route that is 'steps' levels deeper.
|
|
45
|
+
* @param steps - The number of levels to go deeper (optional)
|
|
46
|
+
* @returns A new Route that is one level deeper or 'steps' levels deeper
|
|
47
|
+
*/
|
|
18
48
|
deeper(steps) {
|
|
19
49
|
if (steps === void 0) {
|
|
20
|
-
return new Route(this.
|
|
50
|
+
return new Route(this._segments.slice(1, this._segments.length));
|
|
21
51
|
} else {
|
|
22
52
|
if (steps < 1) {
|
|
23
53
|
throw new Error("Steps must be greater than 0");
|
|
24
54
|
}
|
|
25
|
-
if (steps >= this.
|
|
55
|
+
if (steps >= this._segments.length) {
|
|
26
56
|
throw new Error("Cannot go deeper than the root");
|
|
27
57
|
}
|
|
28
|
-
return new Route(this.
|
|
58
|
+
return new Route(this._segments.slice(steps, this._segments.length));
|
|
29
59
|
}
|
|
30
60
|
}
|
|
61
|
+
// .............................................................................
|
|
62
|
+
/**
|
|
63
|
+
* Checks if the current route is the root route.
|
|
64
|
+
* @returns True if the current route is the root route, false otherwise
|
|
65
|
+
*/
|
|
31
66
|
get isRoot() {
|
|
32
|
-
return this.
|
|
67
|
+
return this._segments.length === 1;
|
|
33
68
|
}
|
|
69
|
+
// .............................................................................
|
|
70
|
+
/**
|
|
71
|
+
* Returns the flat string representation of the route.
|
|
72
|
+
* @returns The flat string representation of the route (e.g. "/a/b/c")
|
|
73
|
+
*/
|
|
34
74
|
get flat() {
|
|
35
|
-
|
|
75
|
+
let flat = "";
|
|
76
|
+
for (const segment of this._segments) {
|
|
77
|
+
const tableKey = segment.tableKey;
|
|
78
|
+
const ref = Object.keys(segment).filter((k) => k !== "tableKey")[0];
|
|
79
|
+
flat += `/${tableKey}${ref ? `@${segment[ref]}` : ""}`;
|
|
80
|
+
}
|
|
81
|
+
return flat;
|
|
82
|
+
}
|
|
83
|
+
// .............................................................................
|
|
84
|
+
/**
|
|
85
|
+
* Returns the segments of the route as an array of strings.
|
|
86
|
+
* @returns The segments of the route as an array of strings
|
|
87
|
+
*/
|
|
88
|
+
get segments() {
|
|
89
|
+
return this._segments;
|
|
90
|
+
}
|
|
91
|
+
// .............................................................................
|
|
92
|
+
/**
|
|
93
|
+
* Returns the root segment of the route.
|
|
94
|
+
* @returns The root segment of the route
|
|
95
|
+
*/
|
|
96
|
+
get root() {
|
|
97
|
+
return this.segment();
|
|
98
|
+
}
|
|
99
|
+
// .............................................................................
|
|
100
|
+
/**
|
|
101
|
+
* Returns the top level segment of the route.
|
|
102
|
+
* @returns The top level segment of the route
|
|
103
|
+
*/
|
|
104
|
+
get top() {
|
|
105
|
+
return this.segment(0);
|
|
106
|
+
}
|
|
107
|
+
// .............................................................................
|
|
108
|
+
/**
|
|
109
|
+
* Returns the next segment of the route if it exists.
|
|
110
|
+
* @returns The next segment of the route or undefined if it doesn't exist
|
|
111
|
+
*/
|
|
112
|
+
get next() {
|
|
113
|
+
return this._segments.length > 1 ? this._segments[1] : void 0;
|
|
114
|
+
}
|
|
115
|
+
// .............................................................................
|
|
116
|
+
/**
|
|
117
|
+
* Checks if the route is valid (i.e. has at least one segment and no empty segments).
|
|
118
|
+
* @returns True if the route is valid, false otherwise
|
|
119
|
+
*/
|
|
120
|
+
get isValid() {
|
|
121
|
+
return this._segments.length > 0 && this._segments.every((s) => s.tableKey.length > 0);
|
|
122
|
+
}
|
|
123
|
+
// .............................................................................
|
|
124
|
+
/**
|
|
125
|
+
* Returns the reference of a segment if it exists.
|
|
126
|
+
* @param segment - The segment to get the reference from
|
|
127
|
+
* @returns The reference of the segment or undefined if it doesn't exist
|
|
128
|
+
*/
|
|
129
|
+
static segmentRef(segment) {
|
|
130
|
+
if (this.segmentHasRef(segment)) {
|
|
131
|
+
const refKey = Object.keys(segment).find(
|
|
132
|
+
(k) => k.endsWith("Ref") && k !== "tableKey"
|
|
133
|
+
);
|
|
134
|
+
if (refKey) {
|
|
135
|
+
return segment[refKey];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return void 0;
|
|
139
|
+
}
|
|
140
|
+
// .............................................................................
|
|
141
|
+
/**
|
|
142
|
+
* Checks if a segment has any reference (either default or history).
|
|
143
|
+
* @param segment - The segment to check
|
|
144
|
+
* @returns True if the segment has any reference, false otherwise
|
|
145
|
+
*/
|
|
146
|
+
static segmentHasRef(segment) {
|
|
147
|
+
return Object.keys(segment).some((k) => k.endsWith("Ref"));
|
|
148
|
+
}
|
|
149
|
+
// .............................................................................
|
|
150
|
+
/**
|
|
151
|
+
* Checks if a segment has a default reference (i.e. not a history reference).
|
|
152
|
+
* @param segment - The segment to check
|
|
153
|
+
* @returns True if the segment has a default reference, false otherwise
|
|
154
|
+
*/
|
|
155
|
+
static segmentHasDefaultRef(segment) {
|
|
156
|
+
return this.segmentHasRef(segment) && !this.segmentHasHistoryRef(segment);
|
|
157
|
+
}
|
|
158
|
+
// .............................................................................
|
|
159
|
+
/**
|
|
160
|
+
* Checks if a segment has a history reference (i.e. an HistoryRef).
|
|
161
|
+
* @param segment - The segment to check
|
|
162
|
+
* @returns True if the segment has a history reference, false otherwise
|
|
163
|
+
*/
|
|
164
|
+
static segmentHasHistoryRef(segment) {
|
|
165
|
+
return this.segmentHasRef(segment) && Object.keys(segment).some((k) => k.endsWith("HistoryRef"));
|
|
36
166
|
}
|
|
37
167
|
}
|
|
38
168
|
// @license
|
|
@@ -163,8 +293,8 @@ const bakeryExample = () => {
|
|
|
163
293
|
}
|
|
164
294
|
]
|
|
165
295
|
});
|
|
166
|
-
const
|
|
167
|
-
_type: "
|
|
296
|
+
const ingredientsHistory = hip({
|
|
297
|
+
_type: "history",
|
|
168
298
|
_data: [
|
|
169
299
|
{
|
|
170
300
|
timeId: "de72:1759123957292",
|
|
@@ -193,7 +323,7 @@ const bakeryExample = () => {
|
|
|
193
323
|
recipeIngredients,
|
|
194
324
|
ingredients,
|
|
195
325
|
nutritionalValues,
|
|
196
|
-
|
|
326
|
+
ingredientsHistory
|
|
197
327
|
};
|
|
198
328
|
return result;
|
|
199
329
|
};
|
|
@@ -204,10 +334,21 @@ const createCakeTableCfg = (cakeKey) => ({
|
|
|
204
334
|
key: cakeKey,
|
|
205
335
|
type: "cakes",
|
|
206
336
|
columns: [
|
|
207
|
-
{ key: "
|
|
208
|
-
{
|
|
209
|
-
|
|
210
|
-
|
|
337
|
+
{ key: "_hash", type: "string", titleLong: "Hash", titleShort: "Hash" },
|
|
338
|
+
{
|
|
339
|
+
key: "sliceIdsTable",
|
|
340
|
+
type: "string",
|
|
341
|
+
titleLong: "Slice Ids Table",
|
|
342
|
+
titleShort: "Slice Ids Table"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
key: "sliceIdsRow",
|
|
346
|
+
type: "string",
|
|
347
|
+
titleLong: "Slice Ids Row",
|
|
348
|
+
titleShort: "Slice Ids Row"
|
|
349
|
+
},
|
|
350
|
+
{ key: "layers", type: "json", titleLong: "Layers", titleShort: "Layers" },
|
|
351
|
+
{ key: "id", type: "string", titleLong: "ID", titleShort: "ID" }
|
|
211
352
|
],
|
|
212
353
|
isHead: false,
|
|
213
354
|
isRoot: false,
|
|
@@ -221,12 +362,28 @@ const createLayerTableCfg = (layerKey) => ({
|
|
|
221
362
|
key: layerKey,
|
|
222
363
|
type: "layers",
|
|
223
364
|
columns: [
|
|
224
|
-
{ key: "
|
|
225
|
-
{ key: "
|
|
226
|
-
{
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
365
|
+
{ key: "_hash", type: "string", titleLong: "Hash", titleShort: "Hash" },
|
|
366
|
+
{ key: "base", type: "string", titleLong: "Base", titleShort: "Base" },
|
|
367
|
+
{
|
|
368
|
+
key: "sliceIdsTable",
|
|
369
|
+
type: "string",
|
|
370
|
+
titleLong: "Slice Ids Table",
|
|
371
|
+
titleShort: "Slice Ids Table"
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
key: "sliceIdsTableRow",
|
|
375
|
+
type: "string",
|
|
376
|
+
titleLong: "Slice Ids Table Row",
|
|
377
|
+
titleShort: "Slice Ids Table Row"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
key: "componentsTable",
|
|
381
|
+
type: "string",
|
|
382
|
+
titleLong: "Components Table",
|
|
383
|
+
titleShort: "Components Table"
|
|
384
|
+
},
|
|
385
|
+
{ key: "add", type: "json", titleLong: "Add", titleShort: "Add" },
|
|
386
|
+
{ key: "remove", type: "json", titleLong: "Remove", titleShort: "Remove" }
|
|
230
387
|
],
|
|
231
388
|
isHead: false,
|
|
232
389
|
isRoot: false,
|
|
@@ -279,39 +436,57 @@ class Example {
|
|
|
279
436
|
columns: [
|
|
280
437
|
{
|
|
281
438
|
key: "_hash",
|
|
282
|
-
type: "string"
|
|
439
|
+
type: "string",
|
|
440
|
+
titleLong: "Hash",
|
|
441
|
+
titleShort: "Hash"
|
|
283
442
|
},
|
|
284
443
|
{
|
|
285
444
|
key: "int",
|
|
286
|
-
type: "number"
|
|
445
|
+
type: "number",
|
|
446
|
+
titleLong: "Integer",
|
|
447
|
+
titleShort: "Int"
|
|
287
448
|
},
|
|
288
449
|
{
|
|
289
450
|
key: "double",
|
|
290
|
-
type: "number"
|
|
451
|
+
type: "number",
|
|
452
|
+
titleLong: "Double",
|
|
453
|
+
titleShort: "Double"
|
|
291
454
|
},
|
|
292
455
|
{
|
|
293
456
|
key: "string",
|
|
294
|
-
type: "string"
|
|
457
|
+
type: "string",
|
|
458
|
+
titleLong: "String",
|
|
459
|
+
titleShort: "String"
|
|
295
460
|
},
|
|
296
461
|
{
|
|
297
462
|
key: "boolean",
|
|
298
|
-
type: "boolean"
|
|
463
|
+
type: "boolean",
|
|
464
|
+
titleLong: "Boolean",
|
|
465
|
+
titleShort: "Boolean"
|
|
299
466
|
},
|
|
300
467
|
{
|
|
301
468
|
key: "null",
|
|
302
|
-
type: "string"
|
|
469
|
+
type: "string",
|
|
470
|
+
titleLong: "Null",
|
|
471
|
+
titleShort: "Null"
|
|
303
472
|
},
|
|
304
473
|
{
|
|
305
474
|
key: "jsonArray",
|
|
306
|
-
type: "jsonArray"
|
|
475
|
+
type: "jsonArray",
|
|
476
|
+
titleLong: "JSON Array",
|
|
477
|
+
titleShort: "JSONArray"
|
|
307
478
|
},
|
|
308
479
|
{
|
|
309
480
|
key: "json",
|
|
310
|
-
type: "json"
|
|
481
|
+
type: "json",
|
|
482
|
+
titleLong: "JSON Object",
|
|
483
|
+
titleShort: "JSONObject"
|
|
311
484
|
},
|
|
312
485
|
{
|
|
313
486
|
key: "jsonValue",
|
|
314
|
-
type: "jsonValue"
|
|
487
|
+
type: "jsonValue",
|
|
488
|
+
titleLong: "JSON Value",
|
|
489
|
+
titleShort: "JSONValue"
|
|
315
490
|
}
|
|
316
491
|
]
|
|
317
492
|
}
|
|
@@ -900,14 +1075,20 @@ const exampleTableCfg = (tableCfg = void 0) => {
|
|
|
900
1075
|
columns: tableCfg?.columns ?? [
|
|
901
1076
|
{
|
|
902
1077
|
key: "_hash",
|
|
1078
|
+
titleLong: "Hash",
|
|
1079
|
+
titleShort: "Hash",
|
|
903
1080
|
type: "string"
|
|
904
1081
|
},
|
|
905
1082
|
{
|
|
906
1083
|
key: "a",
|
|
1084
|
+
titleLong: "Column A",
|
|
1085
|
+
titleShort: "A",
|
|
907
1086
|
type: "string"
|
|
908
1087
|
},
|
|
909
1088
|
{
|
|
910
1089
|
key: "b",
|
|
1090
|
+
titleLong: "Column B",
|
|
1091
|
+
titleShort: "B",
|
|
911
1092
|
type: "number"
|
|
912
1093
|
}
|
|
913
1094
|
],
|
|
@@ -918,7 +1099,150 @@ const exampleTableCfg = (tableCfg = void 0) => {
|
|
|
918
1099
|
};
|
|
919
1100
|
};
|
|
920
1101
|
// @license
|
|
921
|
-
const
|
|
1102
|
+
const createHistoryTableCfg = (tableCfg) => ({
|
|
1103
|
+
key: `${tableCfg.key}History`,
|
|
1104
|
+
type: "history",
|
|
1105
|
+
columns: [
|
|
1106
|
+
{ key: "_hash", type: "string", titleLong: "Hash", titleShort: "Hash" },
|
|
1107
|
+
{
|
|
1108
|
+
key: "timeId",
|
|
1109
|
+
type: "string",
|
|
1110
|
+
titleLong: "Time ID",
|
|
1111
|
+
titleShort: "Time ID"
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
key: `${tableCfg.key}Ref`,
|
|
1115
|
+
type: "string",
|
|
1116
|
+
titleLong: "Reference",
|
|
1117
|
+
titleShort: "Ref"
|
|
1118
|
+
},
|
|
1119
|
+
{ key: "route", type: "string", titleLong: "Route", titleShort: "Route" },
|
|
1120
|
+
{
|
|
1121
|
+
key: "origin",
|
|
1122
|
+
type: "string",
|
|
1123
|
+
titleLong: "Origin",
|
|
1124
|
+
titleShort: "Origin"
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
key: "previous",
|
|
1128
|
+
type: "jsonArray",
|
|
1129
|
+
titleLong: "Previous",
|
|
1130
|
+
titleShort: "Previous"
|
|
1131
|
+
}
|
|
1132
|
+
],
|
|
1133
|
+
isHead: false,
|
|
1134
|
+
isRoot: false,
|
|
1135
|
+
isShared: false
|
|
1136
|
+
});
|
|
1137
|
+
const exampleHistoryTable = () => bakeryExample().ingredientsHistory;
|
|
1138
|
+
// @license
|
|
1139
|
+
const objectDepth = (o) => Object(o) === o ? 1 + Math.max(-1, ...Object.values(o).map(objectDepth)) : 0;
|
|
1140
|
+
// @license
|
|
1141
|
+
class InsertValidator {
|
|
1142
|
+
constructor(_insert) {
|
|
1143
|
+
this._insert = _insert;
|
|
1144
|
+
}
|
|
1145
|
+
errors = { hasErrors: false };
|
|
1146
|
+
// ............................................................................
|
|
1147
|
+
/**
|
|
1148
|
+
* Indicates whether there are any errors
|
|
1149
|
+
* @returns boolean - True if there are errors, false otherwise
|
|
1150
|
+
*/
|
|
1151
|
+
get hasErrors() {
|
|
1152
|
+
return Object.keys(this.errors).length > 1;
|
|
1153
|
+
}
|
|
1154
|
+
// ............................................................................
|
|
1155
|
+
/**
|
|
1156
|
+
* Validates the Insert object
|
|
1157
|
+
* @returns InsertErrors - The errors found during validation
|
|
1158
|
+
*/
|
|
1159
|
+
validate() {
|
|
1160
|
+
if (typeof this._insert.route !== "string" || this._insert.route.length === 0) {
|
|
1161
|
+
this.errors.parameterRouteInvalid = {
|
|
1162
|
+
error: "Insert route must be a non-empty string.",
|
|
1163
|
+
parameter: this._insert.route
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
if (!this._insert.command.startsWith("add") && !this._insert.command.startsWith("remove")) {
|
|
1167
|
+
this.errors.parameterCommandInvalid = {
|
|
1168
|
+
error: "Insert command must be starting with either 'add' or 'remove'.",
|
|
1169
|
+
parameter: this._insert.command
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
if (typeof this._insert.value === "undefined" || typeof this._insert.value !== "object" || this._insert.value === null) {
|
|
1173
|
+
this.errors.parameterValueInvalid = {
|
|
1174
|
+
error: "Insert value must be a non-null object.",
|
|
1175
|
+
parameter: this._insert.value
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
if (typeof this._insert.origin !== "undefined" && typeof this._insert.origin !== "string") {
|
|
1179
|
+
this.errors.parameterOriginInvalid = {
|
|
1180
|
+
error: "Insert origin must be a string if defined.",
|
|
1181
|
+
parameter: this._insert.origin
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
const route = Route.fromFlat(this._insert.route);
|
|
1185
|
+
if (!route.isValid) {
|
|
1186
|
+
this.errors.routeInvalid = {
|
|
1187
|
+
error: "Insert route is not valid.",
|
|
1188
|
+
route: this._insert.route
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
if (route.isValid) {
|
|
1192
|
+
const routeDepth = route.segments.length;
|
|
1193
|
+
const valueDepth = objectDepth(this._insert.value);
|
|
1194
|
+
if (routeDepth !== valueDepth) {
|
|
1195
|
+
this.errors.dataRouteMismatch = {
|
|
1196
|
+
error: "Insert route depth does not match value depth. Route depth must match the depth of the value object.",
|
|
1197
|
+
route: this._insert.route,
|
|
1198
|
+
routeDepth,
|
|
1199
|
+
valueDepth
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if (typeof this._insert.value === "object" && this._insert.value !== null) {
|
|
1204
|
+
this._checkMatchingRefs(route, this._insert.value);
|
|
1205
|
+
}
|
|
1206
|
+
this.errors.hasErrors = this.hasErrors;
|
|
1207
|
+
return this.errors;
|
|
1208
|
+
}
|
|
1209
|
+
// ............................................................................
|
|
1210
|
+
/**
|
|
1211
|
+
* Recursively checks that all reference keys in the value match the route segments
|
|
1212
|
+
* @param route - The current route segment
|
|
1213
|
+
* @param value - The current value object
|
|
1214
|
+
*/
|
|
1215
|
+
_checkMatchingRefs(route, value) {
|
|
1216
|
+
const next = route.next;
|
|
1217
|
+
const keys = Object.keys(value);
|
|
1218
|
+
for (const key of keys) {
|
|
1219
|
+
if (key.endsWith("Ref") && value[key] !== null && value[key] !== void 0 && typeof value[key] !== "string") {
|
|
1220
|
+
const refObj = value[key];
|
|
1221
|
+
if (!next || next.tableKey !== key.slice(0, -3)) {
|
|
1222
|
+
this.errors.parameterInvalid = {
|
|
1223
|
+
error: `Insert value has a reference key "${key}" that does not match the next route segment.`,
|
|
1224
|
+
parameter: this._insert.value
|
|
1225
|
+
};
|
|
1226
|
+
break;
|
|
1227
|
+
}
|
|
1228
|
+
if (route.deeper().next)
|
|
1229
|
+
this._checkMatchingRefs(route.deeper(), refObj);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
// ............................................................................
|
|
1234
|
+
/**
|
|
1235
|
+
* Creates an InsertValidator for the given Insert object
|
|
1236
|
+
* @param insert - The Insert object to validate
|
|
1237
|
+
* @returns InsertValidator - The InsertValidator instance
|
|
1238
|
+
*/
|
|
1239
|
+
static create(insert) {
|
|
1240
|
+
return new InsertValidator(insert);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
const validateInsert = (insert) => {
|
|
1244
|
+
return InsertValidator.create(insert).validate();
|
|
1245
|
+
};
|
|
922
1246
|
// @license
|
|
923
1247
|
const reservedFieldNames = ["_data"];
|
|
924
1248
|
const reservedTableKeys = [
|
|
@@ -977,6 +1301,12 @@ const removeDuplicates = (rljson) => {
|
|
|
977
1301
|
const timeId = () => {
|
|
978
1302
|
return nanoid(4) + ":" + Date.now();
|
|
979
1303
|
};
|
|
1304
|
+
const isTimeId = (id) => {
|
|
1305
|
+
const parts = id.split(":");
|
|
1306
|
+
if (parts.length !== 2) return false;
|
|
1307
|
+
if (isNaN(Number(parts[1]))) return false;
|
|
1308
|
+
return parts[0].length === 4;
|
|
1309
|
+
};
|
|
980
1310
|
// @license
|
|
981
1311
|
const contentTypes = [
|
|
982
1312
|
"buffets",
|
|
@@ -986,7 +1316,7 @@ const contentTypes = [
|
|
|
986
1316
|
"components",
|
|
987
1317
|
"revisions",
|
|
988
1318
|
"tableCfgs",
|
|
989
|
-
"
|
|
1319
|
+
"history"
|
|
990
1320
|
];
|
|
991
1321
|
const exampleTypedefs = () => {
|
|
992
1322
|
return {
|
|
@@ -1876,17 +2206,19 @@ class Validate {
|
|
|
1876
2206
|
export {
|
|
1877
2207
|
BaseValidator,
|
|
1878
2208
|
Example,
|
|
2209
|
+
InsertValidator,
|
|
1879
2210
|
Route,
|
|
1880
2211
|
Validate,
|
|
1881
2212
|
addColumnsToTableCfg,
|
|
1882
2213
|
bakeryExample,
|
|
1883
2214
|
contentTypes,
|
|
1884
2215
|
createCakeTableCfg,
|
|
2216
|
+
createHistoryTableCfg,
|
|
1885
2217
|
createLayerTableCfg,
|
|
1886
2218
|
exampleBuffetsTable,
|
|
1887
2219
|
exampleCakesTable,
|
|
1888
2220
|
exampleComponentsTable,
|
|
1889
|
-
|
|
2221
|
+
exampleHistoryTable,
|
|
1890
2222
|
exampleLayersTable,
|
|
1891
2223
|
exampleRevision,
|
|
1892
2224
|
exampleRljson,
|
|
@@ -1894,6 +2226,7 @@ export {
|
|
|
1894
2226
|
exampleTableCfg,
|
|
1895
2227
|
exampleTableCfgTable,
|
|
1896
2228
|
exampleTypedefs,
|
|
2229
|
+
isTimeId,
|
|
1897
2230
|
isValidFieldName,
|
|
1898
2231
|
iterateTables,
|
|
1899
2232
|
iterateTablesSync,
|
|
@@ -1902,5 +2235,6 @@ export {
|
|
|
1902
2235
|
reservedTableKeys,
|
|
1903
2236
|
throwOnInvalidTableCfg,
|
|
1904
2237
|
timeId,
|
|
2238
|
+
validateInsert,
|
|
1905
2239
|
validateRljsonAgainstTableCfg
|
|
1906
2240
|
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { TableKey } from '../typedefs.ts';
|
|
2
|
+
export type RouteRef = string;
|
|
3
|
+
export type RouteSegment<Str extends string> = {
|
|
4
|
+
[key in Str as `${Uncapitalize<string & key>}Ref`]: string;
|
|
5
|
+
} & {
|
|
6
|
+
tableKey: TableKey;
|
|
7
|
+
};
|
|
8
|
+
export type RouteSegmentFlat<N extends string> = `${N}` | `${N}@${string}` | `${N}@${string}:${string}`;
|
|
9
|
+
/**
|
|
10
|
+
* A class to handle routes in an Rljson object.
|
|
11
|
+
*/
|
|
12
|
+
export declare class Route {
|
|
13
|
+
private readonly _segments;
|
|
14
|
+
constructor(_segments: RouteSegment<any>[]);
|
|
15
|
+
/**
|
|
16
|
+
* Creates a Route from a flat string representation.
|
|
17
|
+
* @param route - The flat string representation of the route (e.g. "/a/b/c")
|
|
18
|
+
* @returns A Route object
|
|
19
|
+
*/
|
|
20
|
+
static fromFlat(route: string): Route;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the segment at the given index or the last segment if no index is provided.
|
|
23
|
+
* @param index - The index of the segment to return (optional)
|
|
24
|
+
* @returns The segment at the given index or the last segment
|
|
25
|
+
*/
|
|
26
|
+
segment(index?: number): RouteSegment<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a new Route that is one level deeper than the current route.
|
|
29
|
+
* If steps is provided, it returns a new Route that is 'steps' levels deeper.
|
|
30
|
+
* @param steps - The number of levels to go deeper (optional)
|
|
31
|
+
* @returns A new Route that is one level deeper or 'steps' levels deeper
|
|
32
|
+
*/
|
|
33
|
+
deeper(steps?: number): Route;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the current route is the root route.
|
|
36
|
+
* @returns True if the current route is the root route, false otherwise
|
|
37
|
+
*/
|
|
38
|
+
get isRoot(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Returns the flat string representation of the route.
|
|
41
|
+
* @returns The flat string representation of the route (e.g. "/a/b/c")
|
|
42
|
+
*/
|
|
43
|
+
get flat(): string;
|
|
44
|
+
/**
|
|
45
|
+
* Returns the segments of the route as an array of strings.
|
|
46
|
+
* @returns The segments of the route as an array of strings
|
|
47
|
+
*/
|
|
48
|
+
get segments(): RouteSegment<any>[];
|
|
49
|
+
/**
|
|
50
|
+
* Returns the root segment of the route.
|
|
51
|
+
* @returns The root segment of the route
|
|
52
|
+
*/
|
|
53
|
+
get root(): RouteSegment<any>;
|
|
54
|
+
/**
|
|
55
|
+
* Returns the top level segment of the route.
|
|
56
|
+
* @returns The top level segment of the route
|
|
57
|
+
*/
|
|
58
|
+
get top(): RouteSegment<any>;
|
|
59
|
+
/**
|
|
60
|
+
* Returns the next segment of the route if it exists.
|
|
61
|
+
* @returns The next segment of the route or undefined if it doesn't exist
|
|
62
|
+
*/
|
|
63
|
+
get next(): RouteSegment<any> | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Checks if the route is valid (i.e. has at least one segment and no empty segments).
|
|
66
|
+
* @returns True if the route is valid, false otherwise
|
|
67
|
+
*/
|
|
68
|
+
get isValid(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Returns the reference of a segment if it exists.
|
|
71
|
+
* @param segment - The segment to get the reference from
|
|
72
|
+
* @returns The reference of the segment or undefined if it doesn't exist
|
|
73
|
+
*/
|
|
74
|
+
static segmentRef(segment: RouteSegment<any>): string | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a segment has any reference (either default or history).
|
|
77
|
+
* @param segment - The segment to check
|
|
78
|
+
* @returns True if the segment has any reference, false otherwise
|
|
79
|
+
*/
|
|
80
|
+
static segmentHasRef(segment: RouteSegment<any>): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Checks if a segment has a default reference (i.e. not a history reference).
|
|
83
|
+
* @param segment - The segment to check
|
|
84
|
+
* @returns True if the segment has a default reference, false otherwise
|
|
85
|
+
*/
|
|
86
|
+
static segmentHasDefaultRef(segment: RouteSegment<any>): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Checks if a segment has a history reference (i.e. an HistoryRef).
|
|
89
|
+
* @param segment - The segment to check
|
|
90
|
+
* @returns True if the segment has a history reference, false otherwise
|
|
91
|
+
*/
|
|
92
|
+
static segmentHasHistoryRef(segment: RouteSegment<any>): boolean;
|
|
93
|
+
}
|
package/dist/src/example.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { ColumnCfg, TablesCfgTable } from './content/table-cfg.ts';
|
|
|
16
16
|
import { bakeryExample } from './example/bakery-example.ts';
|
|
17
17
|
import { Rljson } from './rljson.ts';
|
|
18
18
|
|
|
19
|
+
|
|
19
20
|
export class Example {
|
|
20
21
|
static readonly ok = {
|
|
21
22
|
bakery: (): Rljson => bakeryExample(),
|
|
@@ -55,38 +56,56 @@ export class Example {
|
|
|
55
56
|
{
|
|
56
57
|
key: '_hash',
|
|
57
58
|
type: 'string',
|
|
59
|
+
titleLong: 'Hash',
|
|
60
|
+
titleShort: 'Hash',
|
|
58
61
|
},
|
|
59
62
|
{
|
|
60
63
|
key: 'int',
|
|
61
64
|
type: 'number',
|
|
65
|
+
titleLong: 'Integer',
|
|
66
|
+
titleShort: 'Int',
|
|
62
67
|
},
|
|
63
68
|
{
|
|
64
69
|
key: 'double',
|
|
65
70
|
type: 'number',
|
|
71
|
+
titleLong: 'Double',
|
|
72
|
+
titleShort: 'Double',
|
|
66
73
|
},
|
|
67
74
|
{
|
|
68
75
|
key: 'string',
|
|
69
76
|
type: 'string',
|
|
77
|
+
titleLong: 'String',
|
|
78
|
+
titleShort: 'String',
|
|
70
79
|
},
|
|
71
80
|
{
|
|
72
81
|
key: 'boolean',
|
|
73
82
|
type: 'boolean',
|
|
83
|
+
titleLong: 'Boolean',
|
|
84
|
+
titleShort: 'Boolean',
|
|
74
85
|
},
|
|
75
86
|
{
|
|
76
87
|
key: 'null',
|
|
77
88
|
type: 'string',
|
|
89
|
+
titleLong: 'Null',
|
|
90
|
+
titleShort: 'Null',
|
|
78
91
|
},
|
|
79
92
|
{
|
|
80
93
|
key: 'jsonArray',
|
|
81
94
|
type: 'jsonArray',
|
|
95
|
+
titleLong: 'JSON Array',
|
|
96
|
+
titleShort: 'JSONArray',
|
|
82
97
|
},
|
|
83
98
|
{
|
|
84
99
|
key: 'json',
|
|
85
100
|
type: 'json',
|
|
101
|
+
titleLong: 'JSON Object',
|
|
102
|
+
titleShort: 'JSONObject',
|
|
86
103
|
},
|
|
87
104
|
{
|
|
88
105
|
key: 'jsonValue',
|
|
89
106
|
type: 'jsonValue',
|
|
107
|
+
titleLong: 'JSON Value',
|
|
108
|
+
titleShort: 'JSONValue',
|
|
90
109
|
},
|
|
91
110
|
],
|
|
92
111
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const objectDepth: (o: object) => number;
|
package/dist/tools/time-id.d.ts
CHANGED
|
@@ -1 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a new TimeId.
|
|
3
|
+
* A TimeId is a string in the format "xxxx:timestamp" where:
|
|
4
|
+
* - "xxxx" is a 4-character unique identifier
|
|
5
|
+
* - "timestamp" is the current time in milliseconds since epoch
|
|
6
|
+
* @returns A new TimeId string
|
|
7
|
+
*/
|
|
1
8
|
export declare const timeId: () => string;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if a given id is a valid TimeId.
|
|
11
|
+
* A valid TimeId has the format "xxxx:timestamp" where:
|
|
12
|
+
* - "xxxx" is a 4-character string
|
|
13
|
+
* - "timestamp" is a valid number representing milliseconds since epoch
|
|
14
|
+
* @param id - The id to check
|
|
15
|
+
* @returns True if the id is a valid TimeId, false otherwise
|
|
16
|
+
*/
|
|
17
|
+
export declare const isTimeId: (id: string) => boolean;
|
package/dist/typedefs.d.ts
CHANGED
|
@@ -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", "
|
|
29
|
+
export declare const contentTypes: readonly ["buffets", "cakes", "layers", "sliceIds", "components", "revisions", "tableCfgs", "history"];
|
|
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.
|
|
3
|
+
"version": "0.0.64",
|
|
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,20 +20,20 @@
|
|
|
20
20
|
],
|
|
21
21
|
"type": "module",
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@types/node": "^24.
|
|
24
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
25
|
-
"@typescript-eslint/parser": "^8.
|
|
23
|
+
"@types/node": "^24.9.1",
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
|
25
|
+
"@typescript-eslint/parser": "^8.46.2",
|
|
26
26
|
"@vitest/coverage-v8": "^3.2.4",
|
|
27
27
|
"cross-env": "^10.1.0",
|
|
28
|
-
"eslint": "^9.
|
|
29
|
-
"eslint-plugin-jsdoc": "^
|
|
28
|
+
"eslint": "^9.38.0",
|
|
29
|
+
"eslint-plugin-jsdoc": "^61.1.5",
|
|
30
30
|
"eslint-plugin-tsdoc": "^0.4.0",
|
|
31
31
|
"globals": "^16.4.0",
|
|
32
|
-
"jsdoc": "^4.0.
|
|
32
|
+
"jsdoc": "^4.0.5",
|
|
33
33
|
"read-pkg": "^9.0.1",
|
|
34
34
|
"typescript": "~5.9.3",
|
|
35
|
-
"typescript-eslint": "^8.
|
|
36
|
-
"vite": "^7.1.
|
|
35
|
+
"typescript-eslint": "^8.46.2",
|
|
36
|
+
"vite": "^7.1.11",
|
|
37
37
|
"vite-node": "^3.2.4",
|
|
38
38
|
"vite-plugin-dts": "^4.5.4",
|
|
39
39
|
"vite-tsconfig-paths": "^5.1.4",
|
package/dist/edit/edit.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Json, JsonH, JsonValueH } from '@rljson/json';
|
|
2
|
-
import { Ref } from '../typedefs.ts';
|
|
3
|
-
import { RouteRef } from './route.ts';
|
|
4
|
-
import { RljsonTable } from '../rljson.ts';
|
|
5
|
-
/**
|
|
6
|
-
* An Edit Object describing edits on data basically
|
|
7
|
-
*/
|
|
8
|
-
export type EditRef = Ref;
|
|
9
|
-
export type Edit<T extends Json> = {
|
|
10
|
-
value: T & JsonValueH;
|
|
11
|
-
route: RouteRef;
|
|
12
|
-
origin?: Ref;
|
|
13
|
-
previous?: EditProtocolTimeId[];
|
|
14
|
-
acknowledged?: boolean;
|
|
15
|
-
} & JsonH;
|
|
16
|
-
export type EditProtocolTimeId = string;
|
|
17
|
-
export type EditProtocolRow<Str extends string> = {
|
|
18
|
-
[key in Str as `${Uncapitalize<string & key>}Ref`]: string;
|
|
19
|
-
} & {
|
|
20
|
-
timeId: EditProtocolTimeId;
|
|
21
|
-
route: RouteRef;
|
|
22
|
-
origin?: Ref;
|
|
23
|
-
previous?: EditProtocolTimeId[];
|
|
24
|
-
};
|
|
25
|
-
export type EditProtocol<Str extends string> = RljsonTable<EditProtocolRow<Str>, 'edits'>;
|
|
26
|
-
/**
|
|
27
|
-
* Provides an example Edits table for test purposes
|
|
28
|
-
*/
|
|
29
|
-
export declare const exampleEditsTable: () => EditProtocol<any>;
|
package/dist/edit/route.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type RouteRef = string;
|
|
2
|
-
/**
|
|
3
|
-
* A class to handle routes in an Rljson object.
|
|
4
|
-
*/
|
|
5
|
-
export declare class Route {
|
|
6
|
-
private segments;
|
|
7
|
-
constructor(segments: string[]);
|
|
8
|
-
static fromFlat(route: string): Route;
|
|
9
|
-
segment(index?: number): string;
|
|
10
|
-
deeper(steps?: number): Route;
|
|
11
|
-
get isRoot(): boolean;
|
|
12
|
-
get flat(): string;
|
|
13
|
-
}
|