@rljson/rljson 0.0.61 → 0.0.62
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/edit/edit-validator.d.ts +24 -0
- package/dist/edit/edit.d.ts +17 -5
- package/dist/index.d.ts +2 -1
- package/dist/rljson.js +256 -13
- package/dist/route/route.d.ts +93 -0
- package/dist/tools/object-depth.d.ts +1 -0
- package/dist/tools/time-id.d.ts +16 -0
- package/package.json +9 -9
- package/dist/edit/route.d.ts +0 -13
package/dist/content/cake.d.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Json } from '@rljson/json';
|
|
2
|
+
import { Errors } from '../validate/validate.ts';
|
|
3
|
+
import { Edit } from './edit.ts';
|
|
4
|
+
export interface EditErrors 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 EditValidator<T extends Json> {
|
|
16
|
+
private _edit;
|
|
17
|
+
errors: EditErrors;
|
|
18
|
+
get hasErrors(): boolean;
|
|
19
|
+
constructor(_edit: Edit<T>);
|
|
20
|
+
validate(): EditErrors;
|
|
21
|
+
private _checkMatchingRefs;
|
|
22
|
+
static create(edit: Edit<any>): EditValidator<any>;
|
|
23
|
+
}
|
|
24
|
+
export declare const validateEdit: (edit: Edit<any>) => EditErrors;
|
package/dist/edit/edit.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import { Json
|
|
1
|
+
import { Json } from '@rljson/json';
|
|
2
2
|
import { Ref } from '../typedefs.ts';
|
|
3
|
-
import {
|
|
3
|
+
import { TableCfg } from '../content/table-cfg.ts';
|
|
4
4
|
import { RljsonTable } from '../rljson.ts';
|
|
5
|
+
import { RouteRef } from '../route/route.ts';
|
|
5
6
|
/**
|
|
6
7
|
* An Edit Object describing edits on data basically
|
|
7
8
|
*/
|
|
8
9
|
export type EditRef = Ref;
|
|
10
|
+
export type EditCommand = 'add' | 'remove';
|
|
11
|
+
/**
|
|
12
|
+
* An Edit describes a change to be applied to an Rljson object.
|
|
13
|
+
* @param T - The type of the value being edited, extending Json
|
|
14
|
+
*/
|
|
9
15
|
export type Edit<T extends Json> = {
|
|
10
|
-
|
|
16
|
+
command: EditCommand;
|
|
17
|
+
value: T;
|
|
11
18
|
route: RouteRef;
|
|
12
19
|
origin?: Ref;
|
|
13
|
-
previous?: EditProtocolTimeId[];
|
|
14
20
|
acknowledged?: boolean;
|
|
15
|
-
}
|
|
21
|
+
};
|
|
16
22
|
export type EditProtocolTimeId = string;
|
|
17
23
|
export type EditProtocolRow<Str extends string> = {
|
|
18
24
|
[key in Str as `${Uncapitalize<string & key>}Ref`]: string;
|
|
@@ -23,6 +29,12 @@ export type EditProtocolRow<Str extends string> = {
|
|
|
23
29
|
previous?: EditProtocolTimeId[];
|
|
24
30
|
};
|
|
25
31
|
export type EditProtocol<Str extends string> = RljsonTable<EditProtocolRow<Str>, 'edits'>;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a TableCfg for an Edit Protocol table for the given table configuration
|
|
34
|
+
* @param tableCfg - The table configuration to create the Edit Protocol table for
|
|
35
|
+
* @returns The TableCfg for the Edit Protocol table
|
|
36
|
+
*/
|
|
37
|
+
export declare const createEditProtocolTableCfg: (tableCfg: TableCfg) => TableCfg;
|
|
26
38
|
/**
|
|
27
39
|
* Provides an example Edits table for test purposes
|
|
28
40
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,12 @@ 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/edit-validator.ts';
|
|
8
9
|
export * from './edit/edit.ts';
|
|
9
|
-
export * from './edit/route.ts';
|
|
10
10
|
export * from './example.ts';
|
|
11
11
|
export * from './example/bakery-example.ts';
|
|
12
12
|
export * from './rljson.ts';
|
|
13
|
+
export * from './route/route.ts';
|
|
13
14
|
export * from './tools/remove-duplicates.ts';
|
|
14
15
|
export * from './tools/time-id.ts';
|
|
15
16
|
export * from './typedefs.ts';
|
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 + "EditsRef"]: 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 protocol).
|
|
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 protocol 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.segmentHasProtocolRef(segment);
|
|
157
|
+
}
|
|
158
|
+
// .............................................................................
|
|
159
|
+
/**
|
|
160
|
+
* Checks if a segment has a protocol reference (i.e. an EditsRef).
|
|
161
|
+
* @param segment - The segment to check
|
|
162
|
+
* @returns True if the segment has a protocol reference, false otherwise
|
|
163
|
+
*/
|
|
164
|
+
static segmentHasProtocolRef(segment) {
|
|
165
|
+
return this.segmentHasRef(segment) && Object.keys(segment).some((k) => k.endsWith("EditsRef"));
|
|
36
166
|
}
|
|
37
167
|
}
|
|
38
168
|
// @license
|
|
@@ -204,9 +334,10 @@ const createCakeTableCfg = (cakeKey) => ({
|
|
|
204
334
|
key: cakeKey,
|
|
205
335
|
type: "cakes",
|
|
206
336
|
columns: [
|
|
337
|
+
{ key: "_hash", type: "string" },
|
|
207
338
|
{ key: "sliceIdsTable", type: "string" },
|
|
208
339
|
{ key: "sliceIdsRow", type: "string" },
|
|
209
|
-
{ key: "layers", type: "
|
|
340
|
+
{ key: "layers", type: "json" },
|
|
210
341
|
{ key: "id", type: "string" }
|
|
211
342
|
],
|
|
212
343
|
isHead: false,
|
|
@@ -221,12 +352,13 @@ const createLayerTableCfg = (layerKey) => ({
|
|
|
221
352
|
key: layerKey,
|
|
222
353
|
type: "layers",
|
|
223
354
|
columns: [
|
|
355
|
+
{ key: "_hash", type: "string" },
|
|
224
356
|
{ key: "base", type: "string" },
|
|
225
357
|
{ key: "sliceIdsTable", type: "string" },
|
|
226
358
|
{ key: "sliceIdsTableRow", type: "string" },
|
|
227
359
|
{ key: "componentsTable", type: "string" },
|
|
228
|
-
{ key: "add", type: "
|
|
229
|
-
{ key: "remove", type: "
|
|
360
|
+
{ key: "add", type: "json" },
|
|
361
|
+
{ key: "remove", type: "json" }
|
|
230
362
|
],
|
|
231
363
|
isHead: false,
|
|
232
364
|
isRoot: false,
|
|
@@ -918,6 +1050,107 @@ const exampleTableCfg = (tableCfg = void 0) => {
|
|
|
918
1050
|
};
|
|
919
1051
|
};
|
|
920
1052
|
// @license
|
|
1053
|
+
const objectDepth = (o) => Object(o) === o ? 1 + Math.max(-1, ...Object.values(o).map(objectDepth)) : 0;
|
|
1054
|
+
// @license
|
|
1055
|
+
class EditValidator {
|
|
1056
|
+
constructor(_edit) {
|
|
1057
|
+
this._edit = _edit;
|
|
1058
|
+
}
|
|
1059
|
+
errors = { hasErrors: false };
|
|
1060
|
+
get hasErrors() {
|
|
1061
|
+
return Object.keys(this.errors).length > 1;
|
|
1062
|
+
}
|
|
1063
|
+
validate() {
|
|
1064
|
+
if (typeof this._edit.route !== "string" || this._edit.route.length === 0) {
|
|
1065
|
+
this.errors.parameterRouteInvalid = {
|
|
1066
|
+
error: "Edit route must be a non-empty string.",
|
|
1067
|
+
parameter: this._edit.route
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
if (!this._edit.command.startsWith("add") && !this._edit.command.startsWith("remove")) {
|
|
1071
|
+
this.errors.parameterCommandInvalid = {
|
|
1072
|
+
error: "Edit command must be starting with either 'add' or 'remove'.",
|
|
1073
|
+
parameter: this._edit.command
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof this._edit.value === "undefined" || typeof this._edit.value !== "object" || this._edit.value === null) {
|
|
1077
|
+
this.errors.parameterValueInvalid = {
|
|
1078
|
+
error: "Edit value must be a non-null object.",
|
|
1079
|
+
parameter: this._edit.value
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
if (typeof this._edit.origin !== "undefined" && typeof this._edit.origin !== "string") {
|
|
1083
|
+
this.errors.parameterOriginInvalid = {
|
|
1084
|
+
error: "Edit origin must be a string if defined.",
|
|
1085
|
+
parameter: this._edit.origin
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
const route = Route.fromFlat(this._edit.route);
|
|
1089
|
+
if (!route.isValid) {
|
|
1090
|
+
this.errors.routeInvalid = {
|
|
1091
|
+
error: "Edit route is not valid.",
|
|
1092
|
+
route: this._edit.route
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
if (route.isValid) {
|
|
1096
|
+
const routeDepth = route.segments.length;
|
|
1097
|
+
const valueDepth = objectDepth(this._edit.value);
|
|
1098
|
+
if (routeDepth !== valueDepth) {
|
|
1099
|
+
this.errors.dataRouteMismatch = {
|
|
1100
|
+
error: "Edit route depth does not match value depth. Route depth must match the depth of the value object.",
|
|
1101
|
+
route: this._edit.route,
|
|
1102
|
+
routeDepth,
|
|
1103
|
+
valueDepth
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
if (typeof this._edit.value === "object" && this._edit.value !== null) {
|
|
1108
|
+
this._checkMatchingRefs(route, this._edit.value);
|
|
1109
|
+
}
|
|
1110
|
+
this.errors.hasErrors = this.hasErrors;
|
|
1111
|
+
return this.errors;
|
|
1112
|
+
}
|
|
1113
|
+
_checkMatchingRefs(route, value) {
|
|
1114
|
+
const next = route.next;
|
|
1115
|
+
const keys = Object.keys(value);
|
|
1116
|
+
for (const key of keys) {
|
|
1117
|
+
if (key.endsWith("Ref") && value[key] !== null && value[key] !== void 0 && typeof value[key] !== "string") {
|
|
1118
|
+
const refObj = value[key];
|
|
1119
|
+
if (!next || next.tableKey !== key.slice(0, -3)) {
|
|
1120
|
+
this.errors.parameterInvalid = {
|
|
1121
|
+
error: `Edit value has a reference key "${key}" that does not match the next route segment.`,
|
|
1122
|
+
parameter: this._edit.value
|
|
1123
|
+
};
|
|
1124
|
+
break;
|
|
1125
|
+
}
|
|
1126
|
+
if (route.deeper().next)
|
|
1127
|
+
this._checkMatchingRefs(route.deeper(), refObj);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
static create(edit) {
|
|
1132
|
+
return new EditValidator(edit);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
const validateEdit = (edit) => {
|
|
1136
|
+
return EditValidator.create(edit).validate();
|
|
1137
|
+
};
|
|
1138
|
+
// @license
|
|
1139
|
+
const createEditProtocolTableCfg = (tableCfg) => ({
|
|
1140
|
+
key: `${tableCfg.key}Edits`,
|
|
1141
|
+
type: "edits",
|
|
1142
|
+
columns: [
|
|
1143
|
+
{ key: "_hash", type: "string" },
|
|
1144
|
+
{ key: "timeId", type: "string" },
|
|
1145
|
+
{ key: `${tableCfg.key}Ref`, type: "string" },
|
|
1146
|
+
{ key: "route", type: "string" },
|
|
1147
|
+
{ key: "origin", type: "string" },
|
|
1148
|
+
{ key: "previous", type: "jsonArray" }
|
|
1149
|
+
],
|
|
1150
|
+
isHead: false,
|
|
1151
|
+
isRoot: false,
|
|
1152
|
+
isShared: false
|
|
1153
|
+
});
|
|
921
1154
|
const exampleEditsTable = () => bakeryExample().ingredientsEdits;
|
|
922
1155
|
// @license
|
|
923
1156
|
const reservedFieldNames = ["_data"];
|
|
@@ -977,6 +1210,12 @@ const removeDuplicates = (rljson) => {
|
|
|
977
1210
|
const timeId = () => {
|
|
978
1211
|
return nanoid(4) + ":" + Date.now();
|
|
979
1212
|
};
|
|
1213
|
+
const isTimeId = (id) => {
|
|
1214
|
+
const parts = id.split(":");
|
|
1215
|
+
if (parts.length !== 2) return false;
|
|
1216
|
+
if (isNaN(Number(parts[1]))) return false;
|
|
1217
|
+
return parts[0].length === 4;
|
|
1218
|
+
};
|
|
980
1219
|
// @license
|
|
981
1220
|
const contentTypes = [
|
|
982
1221
|
"buffets",
|
|
@@ -1875,6 +2114,7 @@ class Validate {
|
|
|
1875
2114
|
}
|
|
1876
2115
|
export {
|
|
1877
2116
|
BaseValidator,
|
|
2117
|
+
EditValidator,
|
|
1878
2118
|
Example,
|
|
1879
2119
|
Route,
|
|
1880
2120
|
Validate,
|
|
@@ -1882,6 +2122,7 @@ export {
|
|
|
1882
2122
|
bakeryExample,
|
|
1883
2123
|
contentTypes,
|
|
1884
2124
|
createCakeTableCfg,
|
|
2125
|
+
createEditProtocolTableCfg,
|
|
1885
2126
|
createLayerTableCfg,
|
|
1886
2127
|
exampleBuffetsTable,
|
|
1887
2128
|
exampleCakesTable,
|
|
@@ -1894,6 +2135,7 @@ export {
|
|
|
1894
2135
|
exampleTableCfg,
|
|
1895
2136
|
exampleTableCfgTable,
|
|
1896
2137
|
exampleTypedefs,
|
|
2138
|
+
isTimeId,
|
|
1897
2139
|
isValidFieldName,
|
|
1898
2140
|
iterateTables,
|
|
1899
2141
|
iterateTablesSync,
|
|
@@ -1902,5 +2144,6 @@ export {
|
|
|
1902
2144
|
reservedTableKeys,
|
|
1903
2145
|
throwOnInvalidTableCfg,
|
|
1904
2146
|
timeId,
|
|
2147
|
+
validateEdit,
|
|
1905
2148
|
validateRljsonAgainstTableCfg
|
|
1906
2149
|
};
|
|
@@ -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 protocol).
|
|
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 protocol 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 protocol reference (i.e. an EditsRef).
|
|
89
|
+
* @param segment - The segment to check
|
|
90
|
+
* @returns True if the segment has a protocol reference, false otherwise
|
|
91
|
+
*/
|
|
92
|
+
static segmentHasProtocolRef(segment: RouteSegment<any>): boolean;
|
|
93
|
+
}
|
|
@@ -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rljson/rljson",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.62",
|
|
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.7.2",
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "^8.46.0",
|
|
25
|
+
"@typescript-eslint/parser": "^8.46.0",
|
|
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.37.0",
|
|
29
|
+
"eslint-plugin-jsdoc": "^61.1.1",
|
|
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.0",
|
|
36
|
+
"vite": "^7.1.9",
|
|
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/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
|
-
}
|