@plitzi/sdk-schema 0.32.5 → 0.32.6
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/CHANGELOG.md +9 -0
- package/dist/SchemaReducer.d.ts +4 -0
- package/dist/SchemaReducer.mjs +10 -3
- package/dist/helpers/FlatMap.d.ts +14 -0
- package/dist/helpers/FlatMap.mjs +144 -135
- package/dist/helpers/idRef.d.ts +34 -0
- package/dist/helpers/idRef.mjs +72 -0
- package/dist/helpers/schemaValidator.mjs +163 -129
- package/package.json +10 -6
package/CHANGELOG.md
CHANGED
package/dist/SchemaReducer.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare const SchemaActions: {
|
|
|
16
16
|
readonly SCHEMA_MOVE_ELEMENT: "SCHEMA_MOVE_ELEMENT";
|
|
17
17
|
readonly SCHEMA_CLONE_ELEMENT: "SCHEMA_CLONE_ELEMENT";
|
|
18
18
|
readonly SCHEMA_UPDATE_ELEMENT: "SCHEMA_UPDATE_ELEMENT";
|
|
19
|
+
readonly SCHEMA_UPDATE_ELEMENTS: "SCHEMA_UPDATE_ELEMENTS";
|
|
19
20
|
readonly SCHEMA_ADD_TEMPLATE: "SCHEMA_ADD_TEMPLATE";
|
|
20
21
|
readonly SCHEMA_UPDATE_SETTINGS: "SCHEMA_UPDATE_SETTINGS";
|
|
21
22
|
};
|
|
@@ -81,6 +82,9 @@ export type SchemaReducerActions = SchemaReducerActionsBase & ({
|
|
|
81
82
|
} | {
|
|
82
83
|
type: 'SCHEMA_UPDATE_ELEMENT';
|
|
83
84
|
element: Element;
|
|
85
|
+
} | {
|
|
86
|
+
type: 'SCHEMA_UPDATE_ELEMENTS';
|
|
87
|
+
elements: Element[];
|
|
84
88
|
} | {
|
|
85
89
|
type: 'SCHEMA_UPDATE_SETTINGS';
|
|
86
90
|
path: string;
|
package/dist/SchemaReducer.mjs
CHANGED
|
@@ -19,6 +19,7 @@ var a = {
|
|
|
19
19
|
SCHEMA_MOVE_ELEMENT: "SCHEMA_MOVE_ELEMENT",
|
|
20
20
|
SCHEMA_CLONE_ELEMENT: "SCHEMA_CLONE_ELEMENT",
|
|
21
21
|
SCHEMA_UPDATE_ELEMENT: "SCHEMA_UPDATE_ELEMENT",
|
|
22
|
+
SCHEMA_UPDATE_ELEMENTS: "SCHEMA_UPDATE_ELEMENTS",
|
|
22
23
|
SCHEMA_ADD_TEMPLATE: "SCHEMA_ADD_TEMPLATE",
|
|
23
24
|
SCHEMA_UPDATE_SETTINGS: "SCHEMA_UPDATE_SETTINGS"
|
|
24
25
|
}, o = (o, s) => {
|
|
@@ -127,9 +128,15 @@ var a = {
|
|
|
127
128
|
});
|
|
128
129
|
}
|
|
129
130
|
case a.SCHEMA_UPDATE_ELEMENT: {
|
|
130
|
-
let { element:
|
|
131
|
-
return i(o, (
|
|
132
|
-
|
|
131
|
+
let { element: t } = s;
|
|
132
|
+
return i(o, (n) => {
|
|
133
|
+
e.updateElement(n.flat, t);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
case a.SCHEMA_UPDATE_ELEMENTS: {
|
|
137
|
+
let { elements: t } = s;
|
|
138
|
+
return i(o, (n) => {
|
|
139
|
+
t.forEach((t) => e.updateElement(n.flat, t));
|
|
133
140
|
});
|
|
134
141
|
}
|
|
135
142
|
case a.SCHEMA_UPDATE_SETTINGS: {
|
|
@@ -9,9 +9,21 @@ declare class FlatMap {
|
|
|
9
9
|
variables: Schema['variables'];
|
|
10
10
|
constructor(props?: FlatMapProps);
|
|
11
11
|
addElement: (data: Element, to: Element["id"], dropPosition?: DropPosition, initialItems?: Record<Element["id"], Element>) => boolean;
|
|
12
|
+
/** Refuses a rename onto an unusable idRef: two elements answering to the same name make every binding and
|
|
13
|
+
* interaction written against it resolve to whichever one is found first. Only a change is checked, so an
|
|
14
|
+
* element already stored with a bad ref stays editable.
|
|
15
|
+
*
|
|
16
|
+
* A rename that IS accepted carries its wiring with it: the idRef is the key bindings and interactions target,
|
|
17
|
+
* so every reference to the old name across the space is repointed here. Doing it at the single point every
|
|
18
|
+
* writer goes through is what keeps a rename from silently unwiring the element. */
|
|
12
19
|
updateElement: (element?: Element) => boolean;
|
|
13
20
|
moveElement: (from: Element["id"], to: Element["id"], elementId: Element["id"], dropPosition?: DropPosition) => boolean;
|
|
14
21
|
getElement: (elementId: Element["id"]) => Element<Record<string, unknown>>;
|
|
22
|
+
/** Every idRef currently in use, so a newly minted one stays unique across the space. */
|
|
23
|
+
takenIdRefs: () => Set<string>;
|
|
24
|
+
/** Why an idRef cannot be used here (charset or a clash), or null when it is free. `ignoreElementId` exempts the
|
|
25
|
+
* element being edited, so re-saving an element its own ref is not a conflict. */
|
|
26
|
+
idRefConflict: (idRef: string, ignoreElementId?: Element["id"]) => string | null;
|
|
15
27
|
cloneElements: (elementId: Element["id"], parentId?: Element["id"], rootId?: Element["id"], excludeRoot?: boolean) => {
|
|
16
28
|
acum: Record<Element["id"], Element>;
|
|
17
29
|
item?: Element;
|
|
@@ -47,6 +59,8 @@ declare class FlatMap {
|
|
|
47
59
|
item?: Element;
|
|
48
60
|
};
|
|
49
61
|
static removeElement: (flat: Schema["flat"], elementId: Element["id"], removePage?: boolean) => boolean;
|
|
62
|
+
static takenIdRefs: (flat: Schema["flat"]) => Set<string>;
|
|
63
|
+
static idRefConflict: (flat: Schema["flat"], idRef: string, ignoreElementId?: Element["id"]) => string | null;
|
|
50
64
|
static addVariables: (schemaVariables: Schema["variables"], variables: Schema["variables"]) => boolean;
|
|
51
65
|
static addVariable: (schemaVariables: Schema["variables"], variable: SchemaVariable) => boolean;
|
|
52
66
|
static updateVariable: (schemaVariables: Schema["variables"], variable: SchemaVariable) => boolean;
|
package/dist/helpers/FlatMap.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
1
|
+
import { idRefConflict as e, idRefsUsable as t, remapClonedRefs as n, repointIdRefs as r, takenIdRefs as i } from "./idRef.mjs";
|
|
2
|
+
import { validateSchema as a } from "./schemaValidator.mjs";
|
|
3
|
+
import { get as o, set as s } from "@plitzi/plitzi-ui/helpers";
|
|
4
|
+
import { generateID as c } from "@plitzi/sdk-shared/helpers/utils";
|
|
5
|
+
import { EMPTY_SCHEMA as l, VARIABLE_REGEX as u } from "@plitzi/sdk-shared/schema/schemaConstants";
|
|
6
|
+
import { EMPTY_STYLE_SCHEMA as d } from "@plitzi/sdk-shared/style/styleConstants";
|
|
7
|
+
import f from "@plitzi/sdk-style/helpers/calculateInheriting";
|
|
7
8
|
//#region src/helpers/FlatMap.ts
|
|
8
|
-
var
|
|
9
|
+
var p = class {
|
|
9
10
|
flat;
|
|
10
11
|
variables;
|
|
11
12
|
constructor(e = {}) {
|
|
@@ -13,95 +14,101 @@ var c = class {
|
|
|
13
14
|
if (!t) throw Error("Flat is required");
|
|
14
15
|
this.flat = t, this.variables = n ?? [];
|
|
15
16
|
}
|
|
16
|
-
addElement = (e,
|
|
17
|
-
let
|
|
18
|
-
if (
|
|
19
|
-
if (
|
|
20
|
-
let e = this.flat[
|
|
17
|
+
addElement = (e, n, r = "inside", i = {}) => {
|
|
18
|
+
let a;
|
|
19
|
+
if (r !== "custom") {
|
|
20
|
+
if (r !== "inside") {
|
|
21
|
+
let e = this.flat[n];
|
|
21
22
|
if (!e) return !1;
|
|
22
|
-
e.definition.parentId && (
|
|
23
|
-
} else
|
|
24
|
-
if (!
|
|
23
|
+
e.definition.parentId && (a = this.flat[e.definition.parentId]);
|
|
24
|
+
} else a = this.flat[n];
|
|
25
|
+
if (!a) return !1;
|
|
25
26
|
}
|
|
26
|
-
if (
|
|
27
|
-
switch (
|
|
27
|
+
if (r !== "custom" && (this.flat[e.id] || !Array.isArray(o(a, "definition.items"))) || !this.isValidElement(e) || !t(this.flat, [e, ...Object.values(i)])) return !1;
|
|
28
|
+
switch (s(this.flat, e.id, e), r) {
|
|
28
29
|
case "left":
|
|
29
30
|
case "top": {
|
|
30
|
-
let
|
|
31
|
-
if (
|
|
32
|
-
|
|
31
|
+
let t = o(a, "definition.items", []);
|
|
32
|
+
if (t.splice(t.findIndex((e) => e === n), 0, e.id), !a) return !1;
|
|
33
|
+
s(this.flat, `${a.id}.definition.items`, t), s(this.flat, `${e.id}.definition.parentId`, a.id), s(this.flat, `${e.id}.definition.rootId`, a.definition.rootId);
|
|
33
34
|
break;
|
|
34
35
|
}
|
|
35
36
|
case "right":
|
|
36
37
|
case "bottom": {
|
|
37
|
-
let
|
|
38
|
-
if (
|
|
39
|
-
|
|
38
|
+
let t = o(a, "definition.items", []);
|
|
39
|
+
if (t.splice(t.findIndex((e) => e === n) + 1, 0, e.id), !a) return !1;
|
|
40
|
+
s(this.flat, `${a.id}.definition.items`, t), s(this.flat, `${e.id}.definition.parentId`, a.id), s(this.flat, `${e.id}.definition.rootId`, a.definition.rootId);
|
|
40
41
|
break;
|
|
41
42
|
}
|
|
42
43
|
case "inside": {
|
|
43
|
-
let
|
|
44
|
-
if (!
|
|
45
|
-
|
|
44
|
+
let t = o(a, "definition.items", []);
|
|
45
|
+
if (!a) return !1;
|
|
46
|
+
s(this.flat, `${n}.definition.items`, [...t, e.id]), s(this.flat, `${e.id}.definition.parentId`, n), s(this.flat, `${e.id}.definition.rootId`, a.definition.rootId);
|
|
46
47
|
break;
|
|
47
48
|
}
|
|
48
49
|
case "custom": break;
|
|
49
50
|
default: return !1;
|
|
50
51
|
}
|
|
51
|
-
return Object.keys(
|
|
52
|
-
this.flat[e] =
|
|
52
|
+
return Object.keys(i).length > 0 && Object.keys(i).forEach((e) => {
|
|
53
|
+
this.flat[e] = i[e];
|
|
53
54
|
}), !0;
|
|
54
55
|
};
|
|
55
|
-
updateElement = (e) =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
updateElement = (e) => {
|
|
57
|
+
if (!e || !this.flat[e.id]) return !1;
|
|
58
|
+
let n = this.flat[e.id].idRef, i = e.idRef !== n;
|
|
59
|
+
return i && !t(this.flat, [e]) ? !1 : i && n && e.idRef ? (this.flat[e.id] = structuredClone(e), r(this.flat, { [n]: e.idRef }), !0) : (this.flat[e.id] = e, !0);
|
|
60
|
+
};
|
|
61
|
+
moveElement = (e, t, n, r = "inside") => {
|
|
62
|
+
if (n === t || !this.flat[e]) return !1;
|
|
63
|
+
let i = this.flat[t];
|
|
64
|
+
if (!i) return !1;
|
|
65
|
+
let a = this.flat[t];
|
|
66
|
+
for (; a;) {
|
|
67
|
+
let e = o(a, "definition.parentId");
|
|
63
68
|
if (!e) break;
|
|
64
|
-
if (
|
|
65
|
-
|
|
69
|
+
if (a.id === n) return !1;
|
|
70
|
+
a = this.flat[e];
|
|
66
71
|
}
|
|
67
|
-
if (!
|
|
68
|
-
let c =
|
|
72
|
+
if (!a) return !1;
|
|
73
|
+
let c = o(this.flat, `${e}.definition.items`, []).filter((e) => e !== n);
|
|
69
74
|
if ([
|
|
70
75
|
"left",
|
|
71
76
|
"top",
|
|
72
77
|
"right",
|
|
73
78
|
"bottom"
|
|
74
|
-
].includes(
|
|
75
|
-
if (!
|
|
76
|
-
let
|
|
77
|
-
if (!
|
|
78
|
-
let l =
|
|
79
|
-
|
|
80
|
-
let u = l.findIndex((e) => e ===
|
|
81
|
-
["right", "bottom"].includes(
|
|
82
|
-
} else if (
|
|
83
|
-
if (!this.flat[
|
|
84
|
-
let
|
|
85
|
-
e ===
|
|
79
|
+
].includes(r)) {
|
|
80
|
+
if (!i.definition.parentId) return !1;
|
|
81
|
+
let a = this.flat[i.definition.parentId];
|
|
82
|
+
if (!a) return !1;
|
|
83
|
+
let l = o(a, "definition.items", []);
|
|
84
|
+
a.id === e && (l = c);
|
|
85
|
+
let u = l.findIndex((e) => e === t);
|
|
86
|
+
["right", "bottom"].includes(r) && u++, l.splice(u, 0, n), s(this.flat, `${e}.definition.items`, c), s(this.flat, `${a.id}.definition.items`, l), s(this.flat, `${n}.definition.parentId`, a.id);
|
|
87
|
+
} else if (r === "inside") {
|
|
88
|
+
if (!this.flat[t]) return !1;
|
|
89
|
+
let r = o(this.flat, `${t}.definition.items`, []);
|
|
90
|
+
e === t && (r = c), r = [...r, n], s(this.flat, `${e}.definition.items`, c), s(this.flat, `${t}.definition.items`, r), s(this.flat, `${n}.definition.parentId`, t);
|
|
86
91
|
}
|
|
87
92
|
return !0;
|
|
88
93
|
};
|
|
89
|
-
getElement = (e) =>
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
getElement = (e) => o(this.flat, e);
|
|
95
|
+
takenIdRefs = () => i(this.flat);
|
|
96
|
+
idRefConflict = (t, n) => e(this.flat, t, n);
|
|
97
|
+
cloneElements = (e, t = "", r = "", i = !1) => {
|
|
98
|
+
let a = {
|
|
92
99
|
acum: {},
|
|
93
100
|
item: void 0
|
|
94
|
-
},
|
|
95
|
-
if (!
|
|
96
|
-
let
|
|
101
|
+
}, l = {}, u = this.flat[e];
|
|
102
|
+
if (!u) return a;
|
|
103
|
+
let d = this.takenIdRefs(), f = [e, ...this.childTree(e)].reduce((e, t) => {
|
|
97
104
|
let n = this.flat[t];
|
|
98
|
-
return n ? (
|
|
105
|
+
return n ? (l[n.id] = c(n.id), r ? {
|
|
99
106
|
...e,
|
|
100
107
|
[n.id]: {
|
|
101
108
|
...n,
|
|
102
109
|
definition: {
|
|
103
110
|
...n.definition,
|
|
104
|
-
rootId:
|
|
111
|
+
rootId: r
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
} : {
|
|
@@ -110,27 +117,27 @@ var c = class {
|
|
|
110
117
|
}) : e;
|
|
111
118
|
}, {});
|
|
112
119
|
try {
|
|
113
|
-
let t = JSON.stringify(
|
|
114
|
-
t = Object.keys(
|
|
120
|
+
let t = JSON.stringify(f);
|
|
121
|
+
t = Object.keys(l).reduce((e, t) => e.replace(new RegExp(t, "g"), l[t]), t), a.acum = JSON.parse(t), a.item = a.acum[l[e]], n(a.acum, (e) => d.has(e));
|
|
115
122
|
} catch (e) {
|
|
116
123
|
return console.error("Error parsing elements", e), {
|
|
117
124
|
acum: {},
|
|
118
125
|
item: void 0
|
|
119
126
|
};
|
|
120
127
|
}
|
|
121
|
-
|
|
122
|
-
let
|
|
123
|
-
return (!
|
|
128
|
+
i && delete a.acum[l[e]];
|
|
129
|
+
let p = this.flat[t];
|
|
130
|
+
return (!p || !Array.isArray(o(p, "definition.items"))) && (t = o(p, "definition.parentId", o(u, "definition.parentId"))), t && s(a, "item.definition.parentId", t), a;
|
|
124
131
|
};
|
|
125
|
-
removeElement = (e,
|
|
126
|
-
let
|
|
127
|
-
if (!
|
|
128
|
-
let
|
|
129
|
-
|
|
130
|
-
let
|
|
131
|
-
if (
|
|
132
|
-
let { definition: { items: t = [] } } =
|
|
133
|
-
|
|
132
|
+
removeElement = (e, t = !1) => {
|
|
133
|
+
let n = this.flat[e];
|
|
134
|
+
if (!n || n.definition.type === "page" && !t || t && o(n, "attributes.default", !1)) return !1;
|
|
135
|
+
let r = o(n, "definition.items");
|
|
136
|
+
r && r.length > 0 && r.forEach((e) => this.removeElement(e));
|
|
137
|
+
let i = o(n, "definition.parentId"), a = i ? this.flat[i] : void 0;
|
|
138
|
+
if (i && a) {
|
|
139
|
+
let { definition: { items: t = [] } } = a;
|
|
140
|
+
s(a, "definition.items", t.filter((t) => t !== e)), this.flat[i] = a;
|
|
134
141
|
}
|
|
135
142
|
return delete this.flat[e], !0;
|
|
136
143
|
};
|
|
@@ -154,22 +161,22 @@ var c = class {
|
|
|
154
161
|
};
|
|
155
162
|
removeVariable = (e) => this.removeVariables([e]);
|
|
156
163
|
parentTree = (e) => {
|
|
157
|
-
let
|
|
158
|
-
if (!
|
|
164
|
+
let t = this.flat[e], n = [];
|
|
165
|
+
if (!t) return n;
|
|
159
166
|
do {
|
|
160
|
-
if (t
|
|
161
|
-
let e = t
|
|
162
|
-
e &&
|
|
167
|
+
if (o(t, "definition.type") === "page") {
|
|
168
|
+
let e = o(t, "attributes.layout"), r = o(t, "attributes.layoutContainer");
|
|
169
|
+
e && r && n.push(r, ...this.parentTree(r));
|
|
163
170
|
}
|
|
164
|
-
e !==
|
|
165
|
-
} while (
|
|
166
|
-
return
|
|
171
|
+
e !== t.id && n.push(t.id), t = o(this.flat, o(t, "definition.parentId"), void 0);
|
|
172
|
+
} while (t);
|
|
173
|
+
return n;
|
|
167
174
|
};
|
|
168
175
|
childTree = (e) => {
|
|
169
|
-
let
|
|
170
|
-
if (!
|
|
171
|
-
let
|
|
172
|
-
return
|
|
176
|
+
let t = this.flat[e];
|
|
177
|
+
if (!t) return [];
|
|
178
|
+
let n = [], r = o(t, "definition.items");
|
|
179
|
+
return r && r.forEach((e) => n.push(e, ...this.childTree(e))), n;
|
|
173
180
|
};
|
|
174
181
|
isValidElement = (e) => {
|
|
175
182
|
if (!e) return !1;
|
|
@@ -178,85 +185,85 @@ var c = class {
|
|
|
178
185
|
let { type: i, label: a, styleSelectors: o, rootId: s } = r;
|
|
179
186
|
return !(!i || a === void 0 || typeof o != "object" || s === void 0);
|
|
180
187
|
};
|
|
181
|
-
flatAsTemplate = (e,
|
|
182
|
-
let
|
|
183
|
-
...
|
|
188
|
+
flatAsTemplate = (e, t, n = !1) => {
|
|
189
|
+
let r = {
|
|
190
|
+
...d,
|
|
184
191
|
platform: {
|
|
185
192
|
desktop: {},
|
|
186
193
|
tablet: {},
|
|
187
194
|
mobile: {}
|
|
188
195
|
}
|
|
189
|
-
},
|
|
190
|
-
if (!
|
|
196
|
+
}, i = [];
|
|
197
|
+
if (!t) return {
|
|
191
198
|
elements: {
|
|
192
199
|
acum: {},
|
|
193
200
|
item: void 0
|
|
194
201
|
},
|
|
195
|
-
elementsStyle:
|
|
196
|
-
variables:
|
|
202
|
+
elementsStyle: r,
|
|
203
|
+
variables: i
|
|
197
204
|
};
|
|
198
|
-
let
|
|
199
|
-
if (!
|
|
205
|
+
let a = o(this.flat, t);
|
|
206
|
+
if (!a) return {
|
|
200
207
|
elements: {
|
|
201
208
|
acum: {},
|
|
202
209
|
item: void 0
|
|
203
210
|
},
|
|
204
|
-
elementsStyle:
|
|
205
|
-
variables:
|
|
211
|
+
elementsStyle: r,
|
|
212
|
+
variables: i
|
|
206
213
|
};
|
|
207
|
-
let
|
|
208
|
-
return
|
|
209
|
-
let { id:
|
|
210
|
-
if (
|
|
211
|
-
let { displayMode: n, name:
|
|
212
|
-
!(
|
|
214
|
+
let c = this.cloneElements(t, a.definition.parentId);
|
|
215
|
+
return c.item ? (Object.values(c.acum).forEach((t) => {
|
|
216
|
+
let { id: n } = t;
|
|
217
|
+
if (s(c.acum, `${n}.definition.rootId`, c.item?.id), f(t, t.definition.type, this.flat, e.platform, {}, { includeSelf: !0 }).tree.forEach((t) => {
|
|
218
|
+
let { displayMode: n, name: i } = t;
|
|
219
|
+
!(i in r.platform[n]) && i in e.platform[n] && (r.platform[n][i] = e.platform[n][i]);
|
|
213
220
|
}), this.variables.length > 0) {
|
|
214
|
-
let t = this.getElementVariables(e,
|
|
215
|
-
|
|
221
|
+
let t = this.getElementVariables(e, n, c.acum);
|
|
222
|
+
i = [...i, ...t];
|
|
216
223
|
}
|
|
217
|
-
}),
|
|
218
|
-
elements:
|
|
219
|
-
elementsStyle:
|
|
220
|
-
variables:
|
|
224
|
+
}), s(c.acum, `${c.item.id}.definition.parentId`, null), n && delete c.acum[c.item.id], i.length > 1 && (i = [...new Set(i)]), {
|
|
225
|
+
elements: c,
|
|
226
|
+
elementsStyle: r,
|
|
227
|
+
variables: i
|
|
221
228
|
}) : {
|
|
222
229
|
elements: {
|
|
223
230
|
acum: {},
|
|
224
231
|
item: void 0
|
|
225
232
|
},
|
|
226
|
-
elementsStyle:
|
|
227
|
-
variables:
|
|
233
|
+
elementsStyle: r,
|
|
234
|
+
variables: i
|
|
228
235
|
};
|
|
229
236
|
};
|
|
230
|
-
validate = () =>
|
|
231
|
-
...
|
|
237
|
+
validate = () => a({
|
|
238
|
+
...l.schema,
|
|
232
239
|
flat: this.flat,
|
|
233
240
|
variables: this.variables
|
|
234
241
|
});
|
|
235
242
|
isValid = () => this.validate().valid;
|
|
236
|
-
assertValid = (
|
|
237
|
-
let
|
|
238
|
-
...
|
|
243
|
+
assertValid = (e) => {
|
|
244
|
+
let t = a({
|
|
245
|
+
...l.schema,
|
|
239
246
|
flat: this.flat,
|
|
240
247
|
variables: this.variables
|
|
241
248
|
});
|
|
242
|
-
if (!
|
|
243
|
-
let
|
|
244
|
-
throw Error(
|
|
249
|
+
if (!t.valid) {
|
|
250
|
+
let n = `Invalid schema${e ? ` (${e})` : ""}: ${t.errors.map((e) => e.message).join("; ")}`;
|
|
251
|
+
throw Error(n);
|
|
245
252
|
}
|
|
246
253
|
};
|
|
247
|
-
getElementVariables = (e,
|
|
248
|
-
let
|
|
249
|
-
if (!
|
|
250
|
-
let
|
|
251
|
-
return Object.values(
|
|
254
|
+
getElementVariables = (e, t, n = this.flat, r = this.variables) => {
|
|
255
|
+
let i = [], a = o(n, `${t}.definition.styleSelectors`);
|
|
256
|
+
if (!a) return i;
|
|
257
|
+
let s = new RegExp(u, "g");
|
|
258
|
+
return Object.values(a).filter(Boolean).forEach((t) => {
|
|
252
259
|
Object.values(e.platform).forEach((e) => {
|
|
253
260
|
let n = e[t];
|
|
254
|
-
n && [...JSON.stringify(n.attributes).matchAll(
|
|
255
|
-
let t =
|
|
256
|
-
t && !
|
|
261
|
+
n && [...JSON.stringify(n.attributes).matchAll(s)].forEach((e) => {
|
|
262
|
+
let t = r.find((t) => t.name === e[1] || t.name === e[2]);
|
|
263
|
+
t && !i.find((e) => e.name === t.name) && i.push(t);
|
|
257
264
|
});
|
|
258
265
|
});
|
|
259
|
-
}),
|
|
266
|
+
}), i;
|
|
260
267
|
};
|
|
261
268
|
static getInstance = (e) => new this(e);
|
|
262
269
|
static addElement = (e, t, n, r = "inside", i = {}) => this.getInstance({ flat: e }).addElement(t, n, r, i);
|
|
@@ -265,6 +272,8 @@ var c = class {
|
|
|
265
272
|
static getElement = (e, t) => this.getInstance({ flat: e }).getElement(t);
|
|
266
273
|
static cloneElements = (e, t, n = "", r = "", i = !1) => this.getInstance({ flat: e }).cloneElements(t, n, r, i);
|
|
267
274
|
static removeElement = (e, t, n = !1) => this.getInstance({ flat: e }).removeElement(t, n);
|
|
275
|
+
static takenIdRefs = (e) => this.getInstance({ flat: e }).takenIdRefs();
|
|
276
|
+
static idRefConflict = (e, t, n) => this.getInstance({ flat: e }).idRefConflict(t, n);
|
|
268
277
|
static addVariables = (e, t) => this.getInstance({ variables: e }).addVariables(t);
|
|
269
278
|
static addVariable = (e, t) => this.getInstance({ variables: e }).addVariable(t);
|
|
270
279
|
static updateVariable = (e, t) => this.getInstance({ variables: e }).updateVariable(t);
|
|
@@ -287,15 +296,15 @@ var c = class {
|
|
|
287
296
|
variables: i
|
|
288
297
|
}).getElementVariables(t, n);
|
|
289
298
|
};
|
|
290
|
-
static validate = (
|
|
291
|
-
static isValid = (
|
|
292
|
-
static assertValid = (
|
|
293
|
-
let
|
|
294
|
-
if (!
|
|
295
|
-
let e = `Invalid schema${
|
|
299
|
+
static validate = (e) => a(e);
|
|
300
|
+
static isValid = (e) => a(e).valid;
|
|
301
|
+
static assertValid = (e, t) => {
|
|
302
|
+
let n = a(e);
|
|
303
|
+
if (!n.valid) {
|
|
304
|
+
let e = `Invalid schema${t ? ` (${t})` : ""}: ${n.errors.map((e) => e.message).join("; ")}`;
|
|
296
305
|
throw Error(e);
|
|
297
306
|
}
|
|
298
307
|
};
|
|
299
308
|
};
|
|
300
309
|
//#endregion
|
|
301
|
-
export {
|
|
310
|
+
export { p as default };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Element } from '@plitzi/sdk-shared';
|
|
2
|
+
/** True when an idRef is well formed: it starts with a letter and then carries letters, numbers, hyphens and
|
|
3
|
+
* underscores. Leading letter keeps a source `<type>_<idRef>` a valid twig identifier. A '.' would split the
|
|
4
|
+
* `<type>_<idRef>.<field>` source path and an interaction target lookup — so it is not allowed. A source name
|
|
5
|
+
* uses the first '_' as separator between `<type>` and `<idRef>` (element types are camelCase with no underscore),
|
|
6
|
+
* so underscores inside the idRef are unambiguous. A hyphen is allowed too: a source doubles as a twig token, and
|
|
7
|
+
* `processTwig` resolves a hyphenated `<type>_<idRef>` through `_context` subscript access. */
|
|
8
|
+
export declare const isValidIdRef: (idRef: string) => boolean;
|
|
9
|
+
/** Every idRef currently in use, so a new one can be checked or minted against it. */
|
|
10
|
+
export declare const takenIdRefs: (flat: Record<Element["id"], Element>) => Set<string>;
|
|
11
|
+
/** Why `idRef` cannot be used in this schema, phrased for a person, or null when it is free and well formed.
|
|
12
|
+
* `ignoreElementId` exempts the element being edited, so re-saving an element its own ref is not a conflict. */
|
|
13
|
+
export declare const idRefConflict: (flat: Record<Element["id"], Element>, idRef: string, ignoreElementId?: Element["id"]) => string | null;
|
|
14
|
+
/** Whether every idRef a write brings into a schema is usable: well formed, free — an element already stored never
|
|
15
|
+
* clashes with itself — and not repeated inside the incoming set, which `idRefConflict` cannot see on its own
|
|
16
|
+
* because those elements are not in `flat` yet. */
|
|
17
|
+
export declare const idRefsUsable: (flat: Record<Element["id"], Element>, elements: Element[]) => boolean;
|
|
18
|
+
/** A unique, charset-safe idRef for a new element: `<type>-<n>`, incrementing until `isTaken` says it is free.
|
|
19
|
+
* The hyphen sits between two alphanumeric runs, so it is valid (never leading or trailing) and readable. */
|
|
20
|
+
export declare const makeIdRef: (type: string, isTaken: (candidate: string) => boolean) => string;
|
|
21
|
+
/** Apply an idRef renaming (old → new) across a set of elements: the idRef itself plus every reference written
|
|
22
|
+
* against it — a binding's data `source`, its transformer params and `when`, and an interaction's target
|
|
23
|
+
* `elementId`, params and `when`. A ref absent from the map is left alone, so references leaving this set keep
|
|
24
|
+
* pointing outward, which is what callers want.
|
|
25
|
+
*
|
|
26
|
+
* Ids are remapped by a blind string replace over the serialized tree (see `FlatMap.cloneElements`); that is safe
|
|
27
|
+
* for a 24-char hex id but not for an idRef, which is short and human-readable — replacing "card-1" everywhere
|
|
28
|
+
* would corrupt any label containing it. Hence this field-by-field pass: a plain `source` goes through
|
|
29
|
+
* `remapSource`, embedded tokens (twig, transformer params, query-builder operands) through `remapTokensDeep`,
|
|
30
|
+
* which only ever rewrites a full `<type>_<idRef>` token. */
|
|
31
|
+
export declare const repointIdRefs: (elements: Record<Element["id"], Element>, mapRefs: Record<string, string>) => void;
|
|
32
|
+
/** Give every element in a freshly cloned subtree a new idRef, so the copy wires to itself instead of to the
|
|
33
|
+
* original it was cloned from. An element that had no idRef stays without one — a clone copies what is there. */
|
|
34
|
+
export declare const remapClonedRefs: (elements: Record<Element["id"], Element>, isTaken: (ref: string) => boolean) => void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/helpers/idRef.ts
|
|
2
|
+
var e = /^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9_])?$/, t = (t) => e.test(t), n = (e) => {
|
|
3
|
+
let t = /* @__PURE__ */ new Set();
|
|
4
|
+
for (let n of Object.values(e)) n.idRef && t.add(n.idRef);
|
|
5
|
+
return t;
|
|
6
|
+
}, r = (e, n, r) => t(n) ? Object.values(e).find((e) => e.idRef === n && e.id !== r) ? `"${n}" is already used by another element in this space` : null : `"${n}" is not a valid reference: start with a letter, then letters, numbers, hyphens and underscores`, i = (e, t) => {
|
|
7
|
+
let n = /* @__PURE__ */ new Set();
|
|
8
|
+
for (let i of t) if (i.idRef) {
|
|
9
|
+
if (n.has(i.idRef) || r(e, i.idRef, i.id)) return !1;
|
|
10
|
+
n.add(i.idRef);
|
|
11
|
+
}
|
|
12
|
+
return !0;
|
|
13
|
+
}, a = (e, t) => {
|
|
14
|
+
let n = e.replace(/[^A-Za-z0-9]/g, "") || "element", r = 1;
|
|
15
|
+
for (; t(`${n}-${r}`);) r += 1;
|
|
16
|
+
return `${n}-${r}`;
|
|
17
|
+
}, o = (e, t) => {
|
|
18
|
+
let n = e.indexOf("."), r = n === -1 ? e : e.slice(0, n), i = r.indexOf("_");
|
|
19
|
+
if (i === -1) return e;
|
|
20
|
+
let a = t[r.slice(i + 1)];
|
|
21
|
+
return a ? `${r.slice(0, i + 1)}${a}${n === -1 ? "" : e.slice(n)}` : e;
|
|
22
|
+
}, s = /([A-Za-z][A-Za-z0-9]*)_([A-Za-z][A-Za-z0-9_-]*)/g, c = (e, t) => e.replace(s, (e, n, r) => {
|
|
23
|
+
let i = t[r];
|
|
24
|
+
return i ? `${n}_${i}` : e;
|
|
25
|
+
}), l = (e, t) => {
|
|
26
|
+
if (Array.isArray(e)) {
|
|
27
|
+
e.forEach((n, r) => {
|
|
28
|
+
if (typeof n == "string") {
|
|
29
|
+
let i = c(n, t);
|
|
30
|
+
i !== n && (e[r] = i);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
l(n, t);
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!e || typeof e != "object") return;
|
|
38
|
+
let n = e;
|
|
39
|
+
for (let [e, r] of Object.entries(n)) {
|
|
40
|
+
if (typeof r == "string") {
|
|
41
|
+
let i = c(r, t);
|
|
42
|
+
i !== r && (n[e] = i);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
l(r, t);
|
|
46
|
+
}
|
|
47
|
+
}, u = (e, t) => {
|
|
48
|
+
for (let n of Object.values(e)) {
|
|
49
|
+
n.idRef && t[n.idRef] && (n.idRef = t[n.idRef]);
|
|
50
|
+
for (let e of Object.values(n.definition.bindings ?? {})) for (let n of e) {
|
|
51
|
+
let e = o(n.source, t);
|
|
52
|
+
e !== n.source && (n.source = e), n.transformers && l(n.transformers, t), n.when && l(n.when, t);
|
|
53
|
+
}
|
|
54
|
+
for (let e of Object.values(n.definition.interactions ?? {})) {
|
|
55
|
+
if (e.elementId) {
|
|
56
|
+
let n = t[e.elementId];
|
|
57
|
+
n && (e.elementId = n);
|
|
58
|
+
}
|
|
59
|
+
l(e.params, t), e.when && l(e.when, t);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}, d = (e, t) => {
|
|
63
|
+
let n = {}, r = /* @__PURE__ */ new Set();
|
|
64
|
+
for (let i of Object.values(e)) {
|
|
65
|
+
if (!i.idRef) continue;
|
|
66
|
+
let e = a(i.definition.type, (e) => t(e) || r.has(e));
|
|
67
|
+
r.add(e), n[i.idRef] = e;
|
|
68
|
+
}
|
|
69
|
+
u(e, n);
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { r as idRefConflict, i as idRefsUsable, t as isValidIdRef, a as makeIdRef, d as remapClonedRefs, u as repointIdRefs, n as takenIdRefs };
|
|
@@ -1,111 +1,112 @@
|
|
|
1
|
+
import { isValidIdRef as e } from "./idRef.mjs";
|
|
1
2
|
//#region src/helpers/schemaValidator.ts
|
|
2
|
-
var
|
|
3
|
-
let
|
|
3
|
+
var t = (t) => {
|
|
4
|
+
let n = [], r = [], { flat: i, pages: a, pageFolders: o, variables: s } = t, c = (e) => !!i[e], l = (e) => i[e], u = () => !i || typeof i != "object" ? (n.push({
|
|
4
5
|
code: "INVALID_FLAT",
|
|
5
6
|
message: "Schema.flat must be a valid Record<string, Element>"
|
|
6
|
-
}), !1) : Array.isArray(
|
|
7
|
+
}), !1) : Array.isArray(a) ? Array.isArray(o) ? Array.isArray(s) ? !0 : (n.push({
|
|
7
8
|
code: "INVALID_VARIABLES",
|
|
8
9
|
message: "Schema.variables must be an array"
|
|
9
|
-
}), !1) : (
|
|
10
|
+
}), !1) : (n.push({
|
|
10
11
|
code: "INVALID_PAGE_FOLDERS",
|
|
11
12
|
message: "Schema.pageFolders must be an array"
|
|
12
|
-
}), !1) : (
|
|
13
|
+
}), !1) : (n.push({
|
|
13
14
|
code: "INVALID_PAGES",
|
|
14
15
|
message: "Schema.pages must be an array of element IDs"
|
|
15
|
-
}), !1),
|
|
16
|
-
Object.entries(
|
|
17
|
-
if (!
|
|
18
|
-
|
|
16
|
+
}), !1), d = () => {
|
|
17
|
+
Object.entries(i).forEach(([e, t]) => {
|
|
18
|
+
if (!t) {
|
|
19
|
+
n.push({
|
|
19
20
|
code: "NULL_ELEMENT",
|
|
20
21
|
message: `Element with id "${e}" is null or undefined`,
|
|
21
22
|
elementId: e
|
|
22
23
|
});
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
|
-
if (!
|
|
26
|
-
|
|
26
|
+
if (!t.id) {
|
|
27
|
+
n.push({
|
|
27
28
|
code: "MISSING_ID",
|
|
28
29
|
message: `Element at key "${e}" has no id property`
|
|
29
30
|
});
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
|
-
if (
|
|
33
|
+
if (t.id !== e && n.push({
|
|
33
34
|
code: "ID_MISMATCH",
|
|
34
|
-
message: `Element id "${
|
|
35
|
+
message: `Element id "${t.id}" doesn't match flat key "${e}"`,
|
|
35
36
|
elementId: e
|
|
36
|
-
}), !
|
|
37
|
-
|
|
37
|
+
}), !t.definition) {
|
|
38
|
+
n.push({
|
|
38
39
|
code: "MISSING_DEFINITION",
|
|
39
40
|
message: "Element missing definition",
|
|
40
41
|
elementId: e
|
|
41
42
|
});
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
|
-
let { definition: i, attributes: a } =
|
|
45
|
-
i.type ||
|
|
45
|
+
let { definition: i, attributes: a } = t;
|
|
46
|
+
i.type || n.push({
|
|
46
47
|
code: "MISSING_TYPE",
|
|
47
48
|
message: "Element missing definition.type",
|
|
48
49
|
elementId: e
|
|
49
|
-
}), i.label === void 0 &&
|
|
50
|
+
}), i.label === void 0 && n.push({
|
|
50
51
|
code: "MISSING_LABEL",
|
|
51
52
|
message: "Element missing definition.label",
|
|
52
53
|
elementId: e
|
|
53
|
-
}), i.rootId ||
|
|
54
|
+
}), i.rootId || n.push({
|
|
54
55
|
code: "MISSING_ROOT_ID",
|
|
55
56
|
message: "Element missing definition.rootId",
|
|
56
57
|
elementId: e
|
|
57
|
-
}), (!i.styleSelectors || typeof i.styleSelectors != "object") &&
|
|
58
|
+
}), (!i.styleSelectors || typeof i.styleSelectors != "object") && n.push({
|
|
58
59
|
code: "MISSING_STYLE_SELECTORS",
|
|
59
60
|
message: "Element missing or invalid definition.styleSelectors",
|
|
60
61
|
elementId: e
|
|
61
|
-
}), a ||
|
|
62
|
+
}), a || r.push({
|
|
62
63
|
code: "MISSING_ATTRIBUTES",
|
|
63
64
|
message: "Element has no attributes",
|
|
64
65
|
elementId: e
|
|
65
|
-
}), i.items && (Array.isArray(i.items) ? i.items.forEach((
|
|
66
|
-
|
|
66
|
+
}), i.items && (Array.isArray(i.items) ? i.items.forEach((t, r) => {
|
|
67
|
+
c(t) || n.push({
|
|
67
68
|
code: "ORPHANED_ITEM_REFERENCE",
|
|
68
|
-
message: `Element "${e}" references non-existent child "${
|
|
69
|
+
message: `Element "${e}" references non-existent child "${t}" at items[${r}]`,
|
|
69
70
|
elementId: e,
|
|
70
71
|
details: {
|
|
71
|
-
childId:
|
|
72
|
+
childId: t,
|
|
72
73
|
index: r
|
|
73
74
|
}
|
|
74
75
|
});
|
|
75
|
-
}) :
|
|
76
|
+
}) : n.push({
|
|
76
77
|
code: "INVALID_ITEMS",
|
|
77
78
|
message: "Element.definition.items must be an array",
|
|
78
79
|
elementId: e
|
|
79
|
-
})), i.parentId && !
|
|
80
|
+
})), i.parentId && !c(i.parentId) && n.push({
|
|
80
81
|
code: "ORPHANED_PARENT_REFERENCE",
|
|
81
82
|
message: `Element "${e}" has parentId "${i.parentId}" but parent doesn't exist in flat`,
|
|
82
83
|
elementId: e,
|
|
83
84
|
details: { parentId: i.parentId }
|
|
84
85
|
});
|
|
85
86
|
});
|
|
86
|
-
},
|
|
87
|
-
Object.values(
|
|
87
|
+
}, f = () => {
|
|
88
|
+
Object.values(i).forEach((e) => {
|
|
88
89
|
if (!e?.definition) return;
|
|
89
|
-
let { id:
|
|
90
|
+
let { id: t, definition: r } = e;
|
|
90
91
|
if (r.items && r.items.forEach((e) => {
|
|
91
|
-
let r =
|
|
92
|
-
r?.definition && r.definition.parentId !==
|
|
92
|
+
let r = l(e);
|
|
93
|
+
r?.definition && r.definition.parentId !== t && n.push({
|
|
93
94
|
code: "PARENT_CHILD_MISMATCH",
|
|
94
|
-
message: `Element "${e}" is in "${
|
|
95
|
+
message: `Element "${e}" is in "${t}".items but has parentId "${r.definition.parentId}"`,
|
|
95
96
|
elementId: e,
|
|
96
97
|
details: {
|
|
97
|
-
expectedParent:
|
|
98
|
+
expectedParent: t,
|
|
98
99
|
actualParent: r.definition.parentId
|
|
99
100
|
}
|
|
100
101
|
});
|
|
101
102
|
}), r.parentId) {
|
|
102
|
-
let e =
|
|
103
|
+
let e = l(r.parentId);
|
|
103
104
|
if (!e?.definition) return;
|
|
104
105
|
let i = e.definition.items || [];
|
|
105
|
-
i.includes(
|
|
106
|
+
i.includes(t) || n.push({
|
|
106
107
|
code: "PARENT_CHILD_MISMATCH",
|
|
107
|
-
message: `Element "${
|
|
108
|
-
elementId:
|
|
108
|
+
message: `Element "${t}" has parentId "${r.parentId}" but parent doesn't have it in items`,
|
|
109
|
+
elementId: t,
|
|
109
110
|
details: {
|
|
110
111
|
parentId: r.parentId,
|
|
111
112
|
parentItems: i
|
|
@@ -113,169 +114,202 @@ var e = (e) => {
|
|
|
113
114
|
});
|
|
114
115
|
}
|
|
115
116
|
});
|
|
116
|
-
},
|
|
117
|
-
let e = /* @__PURE__ */ new Set(),
|
|
118
|
-
if (
|
|
117
|
+
}, p = () => {
|
|
118
|
+
let e = /* @__PURE__ */ new Set(), t = /* @__PURE__ */ new Set(), r = (i) => {
|
|
119
|
+
if (t.has(i)) return n.push({
|
|
119
120
|
code: "CIRCULAR_REFERENCE",
|
|
120
|
-
message: `Circular reference detected involving element "${
|
|
121
|
-
elementId:
|
|
121
|
+
message: `Circular reference detected involving element "${i}"`,
|
|
122
|
+
elementId: i
|
|
122
123
|
}), !0;
|
|
123
|
-
if (e.has(
|
|
124
|
-
e.add(
|
|
125
|
-
let a =
|
|
124
|
+
if (e.has(i)) return !1;
|
|
125
|
+
e.add(i), t.add(i);
|
|
126
|
+
let a = l(i);
|
|
126
127
|
if (a?.definition?.items) {
|
|
127
|
-
for (let e of a.definition.items) if (
|
|
128
|
+
for (let e of a.definition.items) if (r(e)) return t.delete(i), !0;
|
|
128
129
|
}
|
|
129
130
|
let o = /* @__PURE__ */ new Set(), s = a;
|
|
130
131
|
for (; s?.definition?.parentId;) {
|
|
131
|
-
if (o.has(s.id)) return
|
|
132
|
+
if (o.has(s.id)) return n.push({
|
|
132
133
|
code: "CIRCULAR_PARENT_REFERENCE",
|
|
133
134
|
message: `Circular parent reference detected involving element "${s.id}"`,
|
|
134
135
|
elementId: s.id
|
|
135
136
|
}), !0;
|
|
136
|
-
o.add(s.id), s =
|
|
137
|
+
o.add(s.id), s = l(s.definition.parentId);
|
|
137
138
|
}
|
|
138
|
-
return
|
|
139
|
+
return t.delete(i), !1;
|
|
139
140
|
};
|
|
140
|
-
Object.keys(
|
|
141
|
-
e.has(t) ||
|
|
141
|
+
Object.keys(i).forEach((t) => {
|
|
142
|
+
e.has(t) || r(t);
|
|
142
143
|
});
|
|
143
|
-
},
|
|
144
|
-
let e = /* @__PURE__ */ new Set(),
|
|
145
|
-
|
|
146
|
-
e.has(
|
|
144
|
+
}, m = () => {
|
|
145
|
+
let e = /* @__PURE__ */ new Set(), t = 0;
|
|
146
|
+
a.forEach((r, i) => {
|
|
147
|
+
e.has(r) && n.push({
|
|
147
148
|
code: "DUPLICATE_PAGE",
|
|
148
|
-
message: `Duplicate page ID "${
|
|
149
|
-
elementId:
|
|
150
|
-
}), e.add(
|
|
151
|
-
let a =
|
|
149
|
+
message: `Duplicate page ID "${r}" in pages array at index ${i}`,
|
|
150
|
+
elementId: r
|
|
151
|
+
}), e.add(r);
|
|
152
|
+
let a = l(r);
|
|
152
153
|
if (!a) {
|
|
153
|
-
|
|
154
|
+
n.push({
|
|
154
155
|
code: "INVALID_PAGE_REFERENCE",
|
|
155
|
-
message: `Page ID "${
|
|
156
|
-
elementId:
|
|
156
|
+
message: `Page ID "${r}" in pages array doesn't exist in flat`,
|
|
157
|
+
elementId: r
|
|
157
158
|
});
|
|
158
159
|
return;
|
|
159
160
|
}
|
|
160
|
-
a.definition.type !== "page" &&
|
|
161
|
+
a.definition.type !== "page" && n.push({
|
|
161
162
|
code: "INVALID_PAGE_TYPE",
|
|
162
|
-
message: `Element "${
|
|
163
|
-
elementId:
|
|
164
|
-
}), a.definition.rootId !==
|
|
163
|
+
message: `Element "${r}" in pages array has type "${a.definition.type}" instead of "page"`,
|
|
164
|
+
elementId: r
|
|
165
|
+
}), a.definition.rootId !== r && n.push({
|
|
165
166
|
code: "PAGE_ROOT_ID_MISMATCH",
|
|
166
|
-
message: `Page "${
|
|
167
|
-
elementId:
|
|
168
|
-
}), a.attributes?.default &&
|
|
169
|
-
}),
|
|
167
|
+
message: `Page "${r}" has rootId "${a.definition.rootId}" instead of its own ID`,
|
|
168
|
+
elementId: r
|
|
169
|
+
}), a.attributes?.default && t++;
|
|
170
|
+
}), t === 0 && a.length > 0 ? r.push({
|
|
170
171
|
code: "NO_DEFAULT_PAGE",
|
|
171
172
|
message: "No default page found in schema"
|
|
172
|
-
}) :
|
|
173
|
+
}) : t > 1 && r.push({
|
|
173
174
|
code: "MULTIPLE_DEFAULT_PAGES",
|
|
174
|
-
message: `Found ${
|
|
175
|
+
message: `Found ${t} default pages, expected 1`
|
|
175
176
|
});
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
let
|
|
179
|
-
if (!
|
|
180
|
-
let r = (
|
|
181
|
-
let i =
|
|
182
|
-
i?.definition && (i.definition.rootId !== e &&
|
|
177
|
+
}, h = () => {
|
|
178
|
+
a.forEach((e) => {
|
|
179
|
+
let t = l(e);
|
|
180
|
+
if (!t) return;
|
|
181
|
+
let r = (t) => {
|
|
182
|
+
let i = l(t);
|
|
183
|
+
i?.definition && (i.definition.rootId !== e && n.push({
|
|
183
184
|
code: "ROOT_ID_MISMATCH",
|
|
184
|
-
message: `Element "${
|
|
185
|
-
elementId:
|
|
185
|
+
message: `Element "${t}" has rootId "${i.definition.rootId}" but should be "${e}" (page's ID)`,
|
|
186
|
+
elementId: t,
|
|
186
187
|
details: {
|
|
187
188
|
expectedRootId: e,
|
|
188
189
|
actualRootId: i.definition.rootId
|
|
189
190
|
}
|
|
190
191
|
}), i.definition.items && i.definition.items.forEach((e) => r(e)));
|
|
191
192
|
};
|
|
192
|
-
|
|
193
|
+
t.definition.items && t.definition.items.forEach((e) => r(e));
|
|
193
194
|
});
|
|
194
|
-
},
|
|
195
|
+
}, g = () => {
|
|
195
196
|
let e = /* @__PURE__ */ new Set();
|
|
196
|
-
|
|
197
|
-
if (!
|
|
198
|
-
|
|
197
|
+
o.forEach((t, r) => {
|
|
198
|
+
if (!t.id) {
|
|
199
|
+
n.push({
|
|
199
200
|
code: "INVALID_FOLDER",
|
|
200
201
|
message: `Page folder at index ${r} has no id`
|
|
201
202
|
});
|
|
202
203
|
return;
|
|
203
204
|
}
|
|
204
|
-
e.has(
|
|
205
|
+
e.has(t.id) && n.push({
|
|
205
206
|
code: "DUPLICATE_FOLDER",
|
|
206
|
-
message: `Duplicate folder ID "${
|
|
207
|
-
elementId:
|
|
208
|
-
}), e.add(
|
|
207
|
+
message: `Duplicate folder ID "${t.id}"`,
|
|
208
|
+
elementId: t.id
|
|
209
|
+
}), e.add(t.id), t.parentId && (e.has(t.parentId) || n.push({
|
|
209
210
|
code: "ORPHANED_FOLDER_PARENT",
|
|
210
|
-
message: `Folder "${
|
|
211
|
-
elementId:
|
|
212
|
-
details: { parentId:
|
|
211
|
+
message: `Folder "${t.id}" has non-existent parent "${t.parentId}"`,
|
|
212
|
+
elementId: t.id,
|
|
213
|
+
details: { parentId: t.parentId }
|
|
213
214
|
}));
|
|
214
215
|
});
|
|
215
|
-
},
|
|
216
|
-
let t = /* @__PURE__ */ new Set(),
|
|
216
|
+
}, _ = (e) => {
|
|
217
|
+
let t = /* @__PURE__ */ new Set(), n = (e) => {
|
|
217
218
|
if (t.has(e)) return;
|
|
218
219
|
t.add(e);
|
|
219
|
-
let
|
|
220
|
-
|
|
220
|
+
let r = l(e);
|
|
221
|
+
r?.definition?.items && r.definition.items.forEach((e) => n(e));
|
|
221
222
|
};
|
|
222
|
-
if (!e)
|
|
223
|
-
|
|
224
|
-
let t =
|
|
225
|
-
t?.attributes?.layoutContainer &&
|
|
223
|
+
if (!e) a.forEach((e) => {
|
|
224
|
+
n(e);
|
|
225
|
+
let t = l(e);
|
|
226
|
+
t?.attributes?.layoutContainer && n(t.attributes.layoutContainer);
|
|
226
227
|
});
|
|
227
228
|
else if (e) {
|
|
228
|
-
|
|
229
|
-
let t =
|
|
230
|
-
t?.attributes?.layoutContainer &&
|
|
229
|
+
n(e);
|
|
230
|
+
let t = l(e);
|
|
231
|
+
t?.attributes?.layoutContainer && n(t.attributes.layoutContainer);
|
|
231
232
|
}
|
|
232
|
-
Object.keys(
|
|
233
|
-
let
|
|
234
|
-
|
|
233
|
+
Object.keys(i).forEach((e) => {
|
|
234
|
+
let n = l(e);
|
|
235
|
+
n && !t.has(e) && n.definition.type !== "page" && r.push({
|
|
235
236
|
code: "ORPHANED_ELEMENT",
|
|
236
237
|
message: `Element "${e}" is not reachable from any page`,
|
|
237
238
|
elementId: e
|
|
238
239
|
});
|
|
239
240
|
});
|
|
240
|
-
},
|
|
241
|
+
}, v = () => {
|
|
241
242
|
let e = /* @__PURE__ */ new Set();
|
|
242
|
-
|
|
243
|
-
if (!
|
|
244
|
-
|
|
243
|
+
s.forEach((t, i) => {
|
|
244
|
+
if (!t.name) {
|
|
245
|
+
n.push({
|
|
245
246
|
code: "INVALID_VARIABLE",
|
|
246
247
|
message: `Variable at index ${i} has no name`
|
|
247
248
|
});
|
|
248
249
|
return;
|
|
249
250
|
}
|
|
250
|
-
e.has(
|
|
251
|
+
e.has(t.name) && n.push({
|
|
251
252
|
code: "DUPLICATE_VARIABLE",
|
|
252
|
-
message: `Duplicate variable name "${
|
|
253
|
-
details: { variableName:
|
|
254
|
-
}), e.add(
|
|
253
|
+
message: `Duplicate variable name "${t.name}"`,
|
|
254
|
+
details: { variableName: t.name }
|
|
255
|
+
}), e.add(t.name), t.type || r.push({
|
|
255
256
|
code: "MISSING_VARIABLE_TYPE",
|
|
256
|
-
message: `Variable "${
|
|
257
|
-
details: { variableName:
|
|
257
|
+
message: `Variable "${t.name}" has no type`,
|
|
258
|
+
details: { variableName: t.name }
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}, y = () => {
|
|
262
|
+
let t = /* @__PURE__ */ new Map();
|
|
263
|
+
Object.values(i).forEach((r) => {
|
|
264
|
+
if (!r) return;
|
|
265
|
+
let { idRef: i } = r;
|
|
266
|
+
if (!i) {
|
|
267
|
+
r.definition.interactions && Object.keys(r.definition.interactions).length > 0 && n.push({
|
|
268
|
+
code: "INTERACTIONS_WITHOUT_ID_REF",
|
|
269
|
+
message: `Element "${r.id}" has interactions but no idRef, so none of them can fire`,
|
|
270
|
+
elementId: r.id
|
|
271
|
+
});
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
e(i) || n.push({
|
|
275
|
+
code: "INVALID_ID_REF",
|
|
276
|
+
message: `Element "${r.id}" has idRef "${i}", which must start with a letter, then letters, numbers, hyphens and underscores (no hyphen or underscore at the start, and no hyphen at the end)`,
|
|
277
|
+
elementId: r.id
|
|
258
278
|
});
|
|
279
|
+
let a = t.get(i);
|
|
280
|
+
if (a) {
|
|
281
|
+
n.push({
|
|
282
|
+
code: "DUPLICATE_ID_REF",
|
|
283
|
+
message: `Elements "${a}" and "${r.id}" share the idRef "${i}"`,
|
|
284
|
+
elementId: r.id,
|
|
285
|
+
details: {
|
|
286
|
+
idRef: i,
|
|
287
|
+
otherElementId: a
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
t.set(i, r.id);
|
|
259
293
|
});
|
|
260
294
|
};
|
|
261
295
|
return { validate: (e) => {
|
|
262
|
-
let { baseElementId:
|
|
263
|
-
return
|
|
264
|
-
valid:
|
|
265
|
-
errors:
|
|
266
|
-
warnings:
|
|
296
|
+
let { baseElementId: t } = e ?? {};
|
|
297
|
+
return u() ? (d(), f(), p(), m(), h(), g(), _(t), v(), y(), {
|
|
298
|
+
valid: n.length === 0,
|
|
299
|
+
errors: n,
|
|
300
|
+
warnings: r
|
|
267
301
|
}) : {
|
|
268
302
|
valid: !1,
|
|
269
|
-
errors:
|
|
270
|
-
warnings:
|
|
303
|
+
errors: n,
|
|
304
|
+
warnings: r
|
|
271
305
|
};
|
|
272
306
|
} };
|
|
273
|
-
},
|
|
274
|
-
let i =
|
|
307
|
+
}, n = (e, n) => t(e).validate(n), r = (e, t, r) => {
|
|
308
|
+
let i = n(e, t);
|
|
275
309
|
if (!i.valid) {
|
|
276
310
|
let e = `Invalid schema${r ? ` (${r})` : ""}: ${i.errors.map((e) => e.message).join("; ")}`;
|
|
277
311
|
throw Error(e);
|
|
278
312
|
}
|
|
279
|
-
},
|
|
313
|
+
}, i = (e, t) => n(e, t).valid;
|
|
280
314
|
//#endregion
|
|
281
|
-
export {
|
|
315
|
+
export { r as assertSchemaValid, i as isSchemaValid, n as validateSchema };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plitzi/sdk-schema",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.6",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"types": "./dist/helpers/FlatMap.d.ts",
|
|
19
19
|
"import": "./dist/helpers/FlatMap.mjs"
|
|
20
20
|
},
|
|
21
|
+
"./helpers/idRef": {
|
|
22
|
+
"types": "./dist/helpers/idRef.d.ts",
|
|
23
|
+
"import": "./dist/helpers/idRef.mjs"
|
|
24
|
+
},
|
|
21
25
|
"./helpers/schemaValidator": {
|
|
22
26
|
"types": "./dist/helpers/schemaValidator.d.ts",
|
|
23
27
|
"import": "./dist/helpers/schemaValidator.mjs"
|
|
@@ -40,15 +44,15 @@
|
|
|
40
44
|
"build:prod": "vite build && node ../sdk-shared/scripts/generate-exports.mjs"
|
|
41
45
|
},
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@plitzi/plitzi-ui": "^1.6.
|
|
44
|
-
"@plitzi/sdk-shared": "0.32.
|
|
45
|
-
"@plitzi/sdk-style": "0.32.
|
|
47
|
+
"@plitzi/plitzi-ui": "^1.6.17",
|
|
48
|
+
"@plitzi/sdk-shared": "0.32.6",
|
|
49
|
+
"@plitzi/sdk-style": "0.32.6",
|
|
46
50
|
"prop-types": "^15.8.1"
|
|
47
51
|
},
|
|
48
52
|
"devDependencies": {
|
|
49
|
-
"eslint": "^9.39.
|
|
53
|
+
"eslint": "^9.39.5",
|
|
50
54
|
"typescript": "^6.0.3",
|
|
51
|
-
"vite": "^8.1.
|
|
55
|
+
"vite": "^8.1.5",
|
|
52
56
|
"vitest": "^4.1.10"
|
|
53
57
|
}
|
|
54
58
|
}
|