@plitzi/sdk-schema 0.37.1 → 0.37.3
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 +1296 -0
- package/dist/helpers/FlatMap.d.ts +13 -30
- package/dist/helpers/FlatMap.mjs +51 -159
- package/dist/helpers/elementTree.d.ts +44 -0
- package/dist/helpers/elementTree.mjs +41 -0
- package/dist/helpers/schemaValidator.d.ts +12 -0
- package/dist/helpers/schemaValidator.mjs +32 -22
- package/dist/helpers/styleWithoutTag.d.ts +5 -0
- package/dist/helpers/styleWithoutTag.mjs +7 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +5 -4
- package/package.json +9 -5
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { SchemaValidationResult } from './schemaValidator';
|
|
2
1
|
import { MintElementId } from './elementId';
|
|
3
2
|
import { Style, Element, Schema, DropPosition, SchemaVariable } from '@plitzi/sdk-shared';
|
|
4
3
|
/** An element on its way in. Its id is the name it will answer to, and leaving it out asks this map to mint one. */
|
|
@@ -31,6 +30,12 @@ declare class FlatMap {
|
|
|
31
30
|
/** Inserts an element, minting its id when the caller did not name it. Nothing else in the codebase mints an
|
|
32
31
|
* element id: every writer goes through here, so "every element has a name" is true by construction. */
|
|
33
32
|
addElement: (input: ElementInput, to: Element["id"], dropPosition?: DropPosition, initialItems?: Record<Element["id"], Element>) => boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Where `ids` go when dropped at `dropPosition` of `to`: the parent that takes them and its items with them in place.
|
|
35
|
+
* Null when there is nowhere to put them — no such element, a sibling of an element with no parent, a parent that
|
|
36
|
+
* holds no items, or an anchor its parent does not list. Computed without writing, so a refusal leaves no trace.
|
|
37
|
+
*/
|
|
38
|
+
private placement;
|
|
34
39
|
/** Replaces a stored element with an edited copy of itself. The id is its identity, not a field an update may
|
|
35
40
|
* carry a new value for — changing the name is `renameElement`, which is a document-wide operation. */
|
|
36
41
|
updateElement: (element?: Element) => boolean;
|
|
@@ -46,15 +51,14 @@ declare class FlatMap {
|
|
|
46
51
|
* change has to publish: the one element it renamed is almost never the whole of what moved.
|
|
47
52
|
*/
|
|
48
53
|
renameElement: (from: Element["id"], to: Element["id"]) => Element["id"][] | false;
|
|
49
|
-
/**
|
|
50
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Moves an element — and everything in it — next to or inside `to`. Refused when `to` is the element itself or one
|
|
56
|
+
* of its own descendants: the subtree would end up holding itself. Crossing into another page or layout takes the
|
|
57
|
+
* subtree's `rootId` along, so the tree agrees with itself about where everything lives.
|
|
58
|
+
*/
|
|
51
59
|
moveElement: (from: Element["id"], to: Element["id"], elementId: Element["id"], dropPosition?: DropPosition) => boolean;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
takenIds: () => Set<string>;
|
|
55
|
-
/** Why an id cannot be used here (charset or a clash), or null when it is free. `ignoreElementId` exempts the
|
|
56
|
-
* element being edited, so re-saving an element its own name is not a conflict. */
|
|
57
|
-
elementIdConflict: (id: string, ignoreElementId?: Element["id"]) => string | null;
|
|
60
|
+
/** Points a subtree at the root it now lives under, when a move took it into another page or layout. */
|
|
61
|
+
private carryRoot;
|
|
58
62
|
/**
|
|
59
63
|
* Copies a subtree onto fresh names.
|
|
60
64
|
*
|
|
@@ -74,13 +78,6 @@ declare class FlatMap {
|
|
|
74
78
|
updateVariable: (variable: SchemaVariable) => boolean;
|
|
75
79
|
removeVariables: (variables: string[]) => boolean;
|
|
76
80
|
removeVariable: (variable: string) => boolean;
|
|
77
|
-
/**
|
|
78
|
-
* Everything an element is rendered inside, nearest first — its ancestors, and past a root the shell that root is
|
|
79
|
-
* shown in. A layout names its own shell the way a page does, so the walk continues through as many as are nested;
|
|
80
|
-
* `visited` keeps a document whose shells name each other from walking forever.
|
|
81
|
-
*/
|
|
82
|
-
parentTree: (elementId: Element["id"], visited?: Set<Element["id"]>) => string[];
|
|
83
|
-
childTree: (elementId: Element["id"]) => string[];
|
|
84
81
|
isValidElement: (element?: Partial<Element>) => boolean;
|
|
85
82
|
flatAsTemplate: (style: Style, elementId: Element["id"], excludeRoot?: boolean) => {
|
|
86
83
|
elements: {
|
|
@@ -90,31 +87,21 @@ declare class FlatMap {
|
|
|
90
87
|
elementsStyle: Style;
|
|
91
88
|
variables: SchemaVariable[];
|
|
92
89
|
};
|
|
93
|
-
validate: () => SchemaValidationResult;
|
|
94
|
-
isValid: () => boolean;
|
|
95
|
-
assertValid: (context?: string) => void;
|
|
96
90
|
getElementVariables: (style: Style, elementId: Element["id"], flat?: Record<string, Element<Record<string, unknown>>>, variables?: SchemaVariable[]) => SchemaVariable[];
|
|
97
91
|
static getInstance: (props: FlatMapProps) => FlatMap;
|
|
98
92
|
static addElement: (flat: Schema["flat"], data: ElementInput, to: Element["id"], dropPosition?: DropPosition, initialItems?: Record<Element["id"], Element>) => boolean;
|
|
99
93
|
static updateElement: (flat: Schema["flat"], element: Element) => boolean;
|
|
100
94
|
static renameElement: (schema: Pick<Schema, "flat" | "pages">, from: Element["id"], to: Element["id"]) => false | string[];
|
|
101
95
|
static moveElement: (flat: Schema["flat"], from: Element["id"], to: Element["id"], elementId: Element["id"], dropPosition?: DropPosition) => boolean;
|
|
102
|
-
static getElement: (flat: Schema["flat"], elementId: Element["id"]) => Element<Record<string, unknown>>;
|
|
103
96
|
static cloneElements: (flat: Schema["flat"], elementId: Element["id"], parentId?: Element["id"], rootId?: Element["id"], excludeRoot?: boolean) => {
|
|
104
97
|
acum: Record<Element["id"], Element>;
|
|
105
98
|
item?: Element;
|
|
106
99
|
};
|
|
107
100
|
static removeElement: (flat: Schema["flat"], elementId: Element["id"], removePage?: boolean) => boolean;
|
|
108
|
-
static takenIds: (flat: Schema["flat"]) => Set<string>;
|
|
109
|
-
static elementIdConflict: (flat: Schema["flat"], id: string, ignoreElementId?: Element["id"]) => string | null;
|
|
110
101
|
static addVariables: (schemaVariables: Schema["variables"], variables: Schema["variables"]) => boolean;
|
|
111
102
|
static addVariable: (schemaVariables: Schema["variables"], variable: SchemaVariable) => boolean;
|
|
112
103
|
static updateVariable: (schemaVariables: Schema["variables"], variable: SchemaVariable) => boolean;
|
|
113
|
-
static removeVariables: (schemaVariables: Schema["variables"], variables: string[]) => boolean;
|
|
114
104
|
static removeVariable: (schemaVariables: Schema["variables"], variable: string) => boolean;
|
|
115
|
-
static parentTree: (flat: Schema["flat"], elementId: Element["id"]) => string[];
|
|
116
|
-
static childTree: (flat: Schema["flat"], elementId: Element["id"]) => string[];
|
|
117
|
-
static isValidElement: (flat: Schema["flat"], element: Element) => boolean;
|
|
118
105
|
static flatAsTemplate: (schema: Schema, style: Style, elementId: Element["id"], excludeRoot?: boolean) => {
|
|
119
106
|
elements: {
|
|
120
107
|
acum: Record<Element["id"], Element>;
|
|
@@ -123,9 +110,5 @@ declare class FlatMap {
|
|
|
123
110
|
elementsStyle: Style;
|
|
124
111
|
variables: SchemaVariable[];
|
|
125
112
|
};
|
|
126
|
-
static getElementVariables: (schema: Schema, style: Style, elementId: Element["id"]) => SchemaVariable[];
|
|
127
|
-
static validate: (schema: Schema) => SchemaValidationResult;
|
|
128
|
-
static isValid: (schema: Schema) => boolean;
|
|
129
|
-
static assertValid: (schema: Schema, context?: string) => void;
|
|
130
113
|
}
|
|
131
114
|
export default FlatMap;
|
package/dist/helpers/FlatMap.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { elementIdConflict as e, elementIdsFree as t, randomElementId as n, repointIds as r, takenIds as i, uniqueElementId as a } from "./elementId.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import f from "@plitzi/sdk-style/helpers/calculateInheriting";
|
|
2
|
+
import { descendants as o, parentChain as s } from "./elementTree.mjs";
|
|
3
|
+
import { VARIABLE_REGEX as c } from "@plitzi/sdk-shared/schema/schemaConstants";
|
|
4
|
+
import { EMPTY_STYLE_SCHEMA as l } from "@plitzi/sdk-shared/style/styleConstants";
|
|
5
|
+
import u from "@plitzi/sdk-style/helpers/calculateInheriting";
|
|
7
6
|
//#region src/helpers/FlatMap.ts
|
|
8
|
-
var
|
|
7
|
+
var d = class {
|
|
9
8
|
flat;
|
|
10
9
|
variables;
|
|
11
10
|
pages;
|
|
@@ -16,97 +15,55 @@ var p = class {
|
|
|
16
15
|
this.flat = t, this.variables = r ?? [], this.pages = i ?? [], this.mintId = a ?? n;
|
|
17
16
|
}
|
|
18
17
|
nextId = (e, t = () => !1) => {
|
|
19
|
-
let n = this.
|
|
18
|
+
let n = i(this.flat);
|
|
20
19
|
return this.mintId(e, (e) => n.has(e) || t(e));
|
|
21
20
|
};
|
|
22
21
|
addElement = (e, n, r = "inside", i = {}) => {
|
|
23
22
|
let a = e.id ? e : {
|
|
24
23
|
...e,
|
|
25
24
|
id: this.nextId(e.definition.type)
|
|
26
|
-
}
|
|
25
|
+
};
|
|
26
|
+
if (!this.isValidElement(a) || !t(this.flat, [a, ...Object.values(i)])) return !1;
|
|
27
27
|
if (r !== "custom") {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
e.definition.parentId && (o = this.flat[e.definition.parentId]);
|
|
32
|
-
} else o = this.flat[n];
|
|
33
|
-
if (!o) return !1;
|
|
34
|
-
}
|
|
35
|
-
if (r !== "custom" && !Array.isArray(s(o, "definition.items")) || !this.isValidElement(a) || !t(this.flat, [a, ...Object.values(i)])) return !1;
|
|
36
|
-
switch (c(this.flat, a.id, a), r) {
|
|
37
|
-
case "left":
|
|
38
|
-
case "top": {
|
|
39
|
-
let e = s(o, "definition.items", []);
|
|
40
|
-
if (e.splice(e.findIndex((e) => e === n), 0, a.id), !o) return !1;
|
|
41
|
-
c(this.flat, `${o.id}.definition.items`, e), c(this.flat, `${a.id}.definition.parentId`, o.id), c(this.flat, `${a.id}.definition.rootId`, o.definition.rootId);
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
case "right":
|
|
45
|
-
case "bottom": {
|
|
46
|
-
let e = s(o, "definition.items", []);
|
|
47
|
-
if (e.splice(e.findIndex((e) => e === n) + 1, 0, a.id), !o) return !1;
|
|
48
|
-
c(this.flat, `${o.id}.definition.items`, e), c(this.flat, `${a.id}.definition.parentId`, o.id), c(this.flat, `${a.id}.definition.rootId`, o.definition.rootId);
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
case "inside": {
|
|
52
|
-
let e = s(o, "definition.items", []);
|
|
53
|
-
if (!o) return !1;
|
|
54
|
-
c(this.flat, `${n}.definition.items`, [...e, a.id]), c(this.flat, `${a.id}.definition.parentId`, n), c(this.flat, `${a.id}.definition.rootId`, o.definition.rootId);
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
case "custom": break;
|
|
58
|
-
default: return !1;
|
|
59
|
-
}
|
|
60
|
-
return Object.keys(i).length > 0 && Object.keys(i).forEach((e) => {
|
|
61
|
-
this.flat[e] = i[e];
|
|
62
|
-
}), !0;
|
|
63
|
-
};
|
|
64
|
-
updateElement = (e) => !e || !this.flat[e.id] ? !1 : (this.flat[e.id] = e, !0);
|
|
65
|
-
renameElement = (t, n) => this.flat[t] ? t === n ? [] : !e(this.flat, n) && r(this.flat, { [t]: n }, this.pages) : !1;
|
|
66
|
-
renameConflict = (t, n) => e(this.flat, n, t);
|
|
67
|
-
moveElement = (e, t, n, r = "inside") => {
|
|
68
|
-
if (n === t || !this.flat[e]) return !1;
|
|
69
|
-
let i = this.flat[t];
|
|
70
|
-
if (!i) return !1;
|
|
71
|
-
let a = this.flat[t];
|
|
72
|
-
for (; a;) {
|
|
73
|
-
let e = s(a, "definition.parentId");
|
|
74
|
-
if (!e) break;
|
|
75
|
-
if (a.id === n) return !1;
|
|
76
|
-
a = this.flat[e];
|
|
28
|
+
let e = this.placement(n, r, [a.id]);
|
|
29
|
+
if (!e) return !1;
|
|
30
|
+
e.parent.definition.items = e.items, a.definition.parentId = e.parent.id, a.definition.rootId = e.parent.definition.rootId;
|
|
77
31
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
32
|
+
return this.flat[a.id] = a, Object.assign(this.flat, i), !0;
|
|
33
|
+
};
|
|
34
|
+
placement = (e, t, n, r) => {
|
|
35
|
+
let i = this.flat[e], a = t === "inside" ? e : i?.definition.parentId, o = a ? this.flat[a] : void 0;
|
|
36
|
+
if (!i || !o?.definition.items) return null;
|
|
37
|
+
let s = o.definition.items.filter((e) => e !== r), c = t === "inside" ? s.length : s.indexOf(e);
|
|
38
|
+
return c < 0 || ![
|
|
39
|
+
"inside",
|
|
81
40
|
"left",
|
|
82
41
|
"top",
|
|
83
42
|
"right",
|
|
84
43
|
"bottom"
|
|
85
|
-
].includes(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
let l = s(a, "definition.items", []);
|
|
90
|
-
a.id === e && (l = o);
|
|
91
|
-
let u = l.findIndex((e) => e === t);
|
|
92
|
-
["right", "bottom"].includes(r) && u++, l.splice(u, 0, n), c(this.flat, `${e}.definition.items`, o), c(this.flat, `${a.id}.definition.items`, l), c(this.flat, `${n}.definition.parentId`, a.id);
|
|
93
|
-
} else if (r === "inside") {
|
|
94
|
-
if (!this.flat[t]) return !1;
|
|
95
|
-
let r = s(this.flat, `${t}.definition.items`, []);
|
|
96
|
-
e === t && (r = o), r = [...r, n], c(this.flat, `${e}.definition.items`, o), c(this.flat, `${t}.definition.items`, r), c(this.flat, `${n}.definition.parentId`, t);
|
|
97
|
-
}
|
|
98
|
-
return !0;
|
|
44
|
+
].includes(t) ? null : (s.splice(t === "right" || t === "bottom" ? c + 1 : c, 0, ...n), {
|
|
45
|
+
parent: o,
|
|
46
|
+
items: s
|
|
47
|
+
});
|
|
99
48
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
49
|
+
updateElement = (e) => !e || !this.flat[e.id] ? !1 : (this.flat[e.id] = e, !0);
|
|
50
|
+
renameElement = (t, n) => this.flat[t] ? t === n ? [] : !e(this.flat, n) && r(this.flat, { [t]: n }, this.pages) : !1;
|
|
51
|
+
moveElement = (e, t, n, r = "inside") => {
|
|
52
|
+
let i = this.flat[e], a = this.flat[n];
|
|
53
|
+
if (!i || !a || n === t || s(this.flat, t).includes(n)) return !1;
|
|
54
|
+
let o = this.placement(t, r, [n], n);
|
|
55
|
+
return o ? (i.definition.items = (i.definition.items ?? []).filter((e) => e !== n), o.parent.definition.items = o.items, a.definition.parentId = o.parent.id, this.carryRoot(n, o.parent.definition.rootId), !0) : !1;
|
|
56
|
+
};
|
|
57
|
+
carryRoot = (e, t) => {
|
|
58
|
+
if (this.flat[e].definition.rootId !== t) for (let n of [e, ...o(this.flat, e)]) this.flat[n].definition.rootId = t;
|
|
59
|
+
};
|
|
60
|
+
cloneElements = (e, t = "", n = "", s = !1) => {
|
|
61
|
+
let c = {
|
|
105
62
|
acum: {},
|
|
106
63
|
item: void 0
|
|
107
64
|
}, l = {}, u = this.flat[e];
|
|
108
|
-
if (!u) return
|
|
109
|
-
let d = [e, ...
|
|
65
|
+
if (!u) return c;
|
|
66
|
+
let d = [e, ...o(this.flat, e)], f = i(this.flat);
|
|
110
67
|
for (let e of d) {
|
|
111
68
|
let t = a(e, (e) => f.has(e));
|
|
112
69
|
f.add(t), l[e] = t;
|
|
@@ -116,21 +73,16 @@ var p = class {
|
|
|
116
73
|
let t = structuredClone(this.flat[e]);
|
|
117
74
|
n && (t.definition.rootId = n), p[e] = t;
|
|
118
75
|
}
|
|
119
|
-
r(p, l),
|
|
76
|
+
r(p, l), c.acum = p, c.item = p[l[e]], s && delete c.acum[l[e]];
|
|
120
77
|
let m = this.flat[t];
|
|
121
|
-
return
|
|
78
|
+
return m?.definition.items || (t = m?.definition.parentId ?? u.definition.parentId ?? ""), t && (c.item.definition.parentId = t), c;
|
|
122
79
|
};
|
|
123
80
|
removeElement = (e, t = !1) => {
|
|
124
81
|
let n = this.flat[e];
|
|
125
|
-
if (!n || n.definition.type === "page" && !t || t &&
|
|
126
|
-
let
|
|
127
|
-
r
|
|
128
|
-
|
|
129
|
-
if (i && a) {
|
|
130
|
-
let { definition: { items: t = [] } } = a;
|
|
131
|
-
c(a, "definition.items", t.filter((t) => t !== e)), this.flat[i] = a;
|
|
132
|
-
}
|
|
133
|
-
return delete this.flat[e], !0;
|
|
82
|
+
if (!n || n.definition.type === "page" && !t || t && n.attributes.default) return !1;
|
|
83
|
+
for (let t of o(this.flat, e)) delete this.flat[t];
|
|
84
|
+
let r = n.definition.parentId ? this.flat[n.definition.parentId] : void 0;
|
|
85
|
+
return r?.definition.items && (r.definition.items = r.definition.items.filter((t) => t !== e)), delete this.flat[e], !0;
|
|
134
86
|
};
|
|
135
87
|
addVariables = (e) => {
|
|
136
88
|
if (e && e.length > 0) {
|
|
@@ -151,26 +103,6 @@ var p = class {
|
|
|
151
103
|
return this.variables = this.variables.filter((t) => e.includes(t.name)), t !== this.variables.length;
|
|
152
104
|
};
|
|
153
105
|
removeVariable = (e) => this.removeVariables([e]);
|
|
154
|
-
parentTree = (e, t = /* @__PURE__ */ new Set()) => {
|
|
155
|
-
let n = this.flat[e], r = [];
|
|
156
|
-
if (!n) return r;
|
|
157
|
-
do {
|
|
158
|
-
let i = s(n, "definition.type");
|
|
159
|
-
if ((i === "page" || i === "layoutContainer") && !t.has(n.id)) {
|
|
160
|
-
t.add(n.id);
|
|
161
|
-
let e = s(n, "attributes.layout"), i = s(n, "attributes.layoutContainer");
|
|
162
|
-
e && i && r.push(i, ...this.parentTree(i, t));
|
|
163
|
-
}
|
|
164
|
-
e !== n.id && r.push(n.id), n = s(this.flat, s(n, "definition.parentId"), void 0);
|
|
165
|
-
} while (n);
|
|
166
|
-
return r;
|
|
167
|
-
};
|
|
168
|
-
childTree = (e) => {
|
|
169
|
-
let t = this.flat[e];
|
|
170
|
-
if (!t) return [];
|
|
171
|
-
let n = [], r = s(t, "definition.items");
|
|
172
|
-
return r && r.forEach((e) => n.push(e, ...this.childTree(e))), n;
|
|
173
|
-
};
|
|
174
106
|
isValidElement = (e) => {
|
|
175
107
|
if (!e) return !1;
|
|
176
108
|
let { id: t, attributes: n, definition: r } = e;
|
|
@@ -180,7 +112,7 @@ var p = class {
|
|
|
180
112
|
};
|
|
181
113
|
flatAsTemplate = (e, t, n = !1) => {
|
|
182
114
|
let r = {
|
|
183
|
-
...
|
|
115
|
+
...l,
|
|
184
116
|
platform: {
|
|
185
117
|
desktop: {},
|
|
186
118
|
tablet: {},
|
|
@@ -195,7 +127,7 @@ var p = class {
|
|
|
195
127
|
elementsStyle: r,
|
|
196
128
|
variables: i
|
|
197
129
|
};
|
|
198
|
-
let a =
|
|
130
|
+
let a = this.flat[t];
|
|
199
131
|
if (!a) return {
|
|
200
132
|
elements: {
|
|
201
133
|
acum: {},
|
|
@@ -207,14 +139,14 @@ var p = class {
|
|
|
207
139
|
let o = this.cloneElements(t, a.definition.parentId);
|
|
208
140
|
return o.item ? (Object.values(o.acum).forEach((t) => {
|
|
209
141
|
let { id: n } = t;
|
|
210
|
-
if (
|
|
142
|
+
if (o.item && (t.definition.rootId = o.item.id), u(t, t.definition.type, this.flat, e.platform, {}, { includeSelf: !0 }).tree.forEach((t) => {
|
|
211
143
|
let { displayMode: n, name: i } = t;
|
|
212
144
|
!(i in r.platform[n]) && i in e.platform[n] && (r.platform[n][i] = e.platform[n][i]);
|
|
213
145
|
}), this.variables.length > 0) {
|
|
214
146
|
let t = this.getElementVariables(e, n, o.acum);
|
|
215
147
|
i = [...i, ...t];
|
|
216
148
|
}
|
|
217
|
-
}),
|
|
149
|
+
}), delete o.acum[o.item.id].definition.parentId, n && delete o.acum[o.item.id], i.length > 1 && (i = [...new Set(i)]), {
|
|
218
150
|
elements: o,
|
|
219
151
|
elementsStyle: r,
|
|
220
152
|
variables: i
|
|
@@ -227,27 +159,10 @@ var p = class {
|
|
|
227
159
|
variables: i
|
|
228
160
|
};
|
|
229
161
|
};
|
|
230
|
-
validate = () => o({
|
|
231
|
-
...l.schema,
|
|
232
|
-
flat: this.flat,
|
|
233
|
-
variables: this.variables
|
|
234
|
-
});
|
|
235
|
-
isValid = () => this.validate().valid;
|
|
236
|
-
assertValid = (e) => {
|
|
237
|
-
let t = o({
|
|
238
|
-
...l.schema,
|
|
239
|
-
flat: this.flat,
|
|
240
|
-
variables: this.variables
|
|
241
|
-
});
|
|
242
|
-
if (!t.valid) {
|
|
243
|
-
let n = `Invalid schema${e ? ` (${e})` : ""}: ${t.errors.map((e) => e.message).join("; ")}`;
|
|
244
|
-
throw Error(n);
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
162
|
getElementVariables = (e, t, n = this.flat, r = this.variables) => {
|
|
248
|
-
let i = [], a =
|
|
163
|
+
let i = [], a = n[t]?.definition.styleSelectors;
|
|
249
164
|
if (!a) return i;
|
|
250
|
-
let o = new RegExp(
|
|
165
|
+
let o = new RegExp(c, "g");
|
|
251
166
|
return Object.values(a).filter(Boolean).forEach((t) => {
|
|
252
167
|
Object.values(e.platform).forEach((e) => {
|
|
253
168
|
let n = e[t];
|
|
@@ -266,19 +181,12 @@ var p = class {
|
|
|
266
181
|
pages: e.pages
|
|
267
182
|
}).renameElement(t, n);
|
|
268
183
|
static moveElement = (e, t, n, r, i = "inside") => this.getInstance({ flat: e }).moveElement(t, n, r, i);
|
|
269
|
-
static getElement = (e, t) => this.getInstance({ flat: e }).getElement(t);
|
|
270
184
|
static cloneElements = (e, t, n = "", r = "", i = !1) => this.getInstance({ flat: e }).cloneElements(t, n, r, i);
|
|
271
185
|
static removeElement = (e, t, n = !1) => this.getInstance({ flat: e }).removeElement(t, n);
|
|
272
|
-
static takenIds = (e) => this.getInstance({ flat: e }).takenIds();
|
|
273
|
-
static elementIdConflict = (e, t, n) => this.getInstance({ flat: e }).elementIdConflict(t, n);
|
|
274
186
|
static addVariables = (e, t) => this.getInstance({ variables: e }).addVariables(t);
|
|
275
187
|
static addVariable = (e, t) => this.getInstance({ variables: e }).addVariable(t);
|
|
276
188
|
static updateVariable = (e, t) => this.getInstance({ variables: e }).updateVariable(t);
|
|
277
|
-
static removeVariables = (e, t) => this.getInstance({ variables: e }).removeVariables(t);
|
|
278
189
|
static removeVariable = (e, t) => this.getInstance({ variables: e }).removeVariable(t);
|
|
279
|
-
static parentTree = (e, t) => this.getInstance({ flat: e }).parentTree(t);
|
|
280
|
-
static childTree = (e, t) => this.getInstance({ flat: e }).childTree(t);
|
|
281
|
-
static isValidElement = (e, t) => this.getInstance({ flat: e }).isValidElement(t);
|
|
282
190
|
static flatAsTemplate = (e, t, n, r = !1) => {
|
|
283
191
|
let { flat: i, variables: a } = e;
|
|
284
192
|
return this.getInstance({
|
|
@@ -286,22 +194,6 @@ var p = class {
|
|
|
286
194
|
variables: a
|
|
287
195
|
}).flatAsTemplate(t, n, r);
|
|
288
196
|
};
|
|
289
|
-
static getElementVariables = (e, t, n) => {
|
|
290
|
-
let { flat: r, variables: i } = e;
|
|
291
|
-
return this.getInstance({
|
|
292
|
-
flat: r,
|
|
293
|
-
variables: i
|
|
294
|
-
}).getElementVariables(t, n);
|
|
295
|
-
};
|
|
296
|
-
static validate = (e) => o(e);
|
|
297
|
-
static isValid = (e) => o(e).valid;
|
|
298
|
-
static assertValid = (e, t) => {
|
|
299
|
-
let n = o(e);
|
|
300
|
-
if (!n.valid) {
|
|
301
|
-
let e = `Invalid schema${t ? ` (${t})` : ""}: ${n.errors.map((e) => e.message).join("; ")}`;
|
|
302
|
-
throw Error(e);
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
197
|
};
|
|
306
198
|
//#endregion
|
|
307
|
-
export {
|
|
199
|
+
export { d as default };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Element, Schema } from '@plitzi/sdk-shared';
|
|
2
|
+
/**
|
|
3
|
+
* The flat schema, typed as it actually behaves: a `parentId` or an item can name an element the document no longer
|
|
4
|
+
* has, and every walk here has to survive that. `Record<string, Element>` would call those checks dead code.
|
|
5
|
+
*/
|
|
6
|
+
type Flat = Schema['flat'] | Record<string, Element | undefined>;
|
|
7
|
+
/**
|
|
8
|
+
* The elements `id` is nested in, nearest first, up to its page or layout root.
|
|
9
|
+
*
|
|
10
|
+
* The tree as it is stored — no layout crossed. What the builder opens to reveal an element, and what "inside a list"
|
|
11
|
+
* means for an author. A schema edited by two people at once can briefly describe a cycle, so every id is visited once.
|
|
12
|
+
*/
|
|
13
|
+
export declare const parentChain: (flat: Flat, id: string) => string[];
|
|
14
|
+
/**
|
|
15
|
+
* Everything an element renders inside, nearest first: its ancestors and, past a page or a layout that is shown in a
|
|
16
|
+
* layout, the container that shell renders it in and that container's own ancestors — through as many layouts as are
|
|
17
|
+
* nested.
|
|
18
|
+
*
|
|
19
|
+
* What the runtime walks to decide which data sources an element sees, so it is what any check of that — the linter's
|
|
20
|
+
* scope rules — has to walk too. A provider elsewhere in the layout, beside the slot rather than around it, is not in
|
|
21
|
+
* it.
|
|
22
|
+
*/
|
|
23
|
+
export declare const renderContext: (flat: Flat, id: string) => string[];
|
|
24
|
+
/** Every element under `id`, depth first in document order. Items that name nothing are skipped; a cycle is walked once. */
|
|
25
|
+
export declare const descendants: (flat: Flat, id: string) => string[];
|
|
26
|
+
/** What the author calls a page or layout: its `name`, else its label, else the id when the root is not in `flat`. */
|
|
27
|
+
export declare const rootName: (flat: Flat, rootId: string) => string;
|
|
28
|
+
/** One root of a schema — a page, or a layout several pages render inside — and how many elements it holds. */
|
|
29
|
+
export type RootElements = {
|
|
30
|
+
/** What the author called it (`rootName`). */
|
|
31
|
+
page: string;
|
|
32
|
+
elements: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The element count, grouped by the root each element names (`definition.rootId`), heaviest first. `only` narrows it
|
|
36
|
+
* to the elements it accepts — where a plugin is used, say — still named after the page or layout that holds them.
|
|
37
|
+
*
|
|
38
|
+
* Unnarrowed it is a grouping, not a second measurement: it always adds up to the number of elements in `flat`, so the
|
|
39
|
+
* builder's live meter and the API's usage panel agree with the count the element ceilings are judged on. Layouts are
|
|
40
|
+
* roots too and are listed as themselves rather than shared out over the pages that render inside them — their
|
|
41
|
+
* elements are authored once, and splitting them between pages would report a total that no page has.
|
|
42
|
+
*/
|
|
43
|
+
export declare const elementsByRoot: (flat: Flat, only?: (element: Element) => boolean) => RootElements[];
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/helpers/elementTree.ts
|
|
2
|
+
var e = (e, t) => t && Object.hasOwn(e, t) ? e[t] : void 0, t = (t, n) => {
|
|
3
|
+
let r = [], i = /* @__PURE__ */ new Set([n]);
|
|
4
|
+
for (let a = e(t, e(t, n)?.definition.parentId); a && !i.has(a.id);) i.add(a.id), r.push(a.id), a = e(t, a.definition.parentId);
|
|
5
|
+
return r;
|
|
6
|
+
}, n = (n, r) => {
|
|
7
|
+
let i = [], a = /* @__PURE__ */ new Set([r]), o = (s) => {
|
|
8
|
+
for (let c of [s, ...t(n, s)]) {
|
|
9
|
+
let t = e(n, c);
|
|
10
|
+
if (c !== s || s !== r) {
|
|
11
|
+
if (a.has(c)) continue;
|
|
12
|
+
a.add(c), i.push(c);
|
|
13
|
+
}
|
|
14
|
+
let l = t?.definition.type, { layout: u, layoutContainer: d } = t?.attributes ?? {};
|
|
15
|
+
(l === "page" || l === "layoutContainer") && u && typeof d == "string" && !a.has(d) && o(d);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
return o(r), i;
|
|
19
|
+
}, r = (t, n) => {
|
|
20
|
+
let r = [], i = /* @__PURE__ */ new Set([n]), a = (n) => {
|
|
21
|
+
for (let o of e(t, n)?.definition.items ?? []) !i.has(o) && e(t, o) && (i.add(o), r.push(o), a(o));
|
|
22
|
+
};
|
|
23
|
+
return a(n), r;
|
|
24
|
+
}, i = (t, n) => {
|
|
25
|
+
let r = e(t, n);
|
|
26
|
+
if (!r) return n;
|
|
27
|
+
let { name: i } = r.attributes;
|
|
28
|
+
return typeof i == "string" && i ? i : r.definition.label;
|
|
29
|
+
}, a = (e, t = () => !0) => {
|
|
30
|
+
let n = /* @__PURE__ */ new Map();
|
|
31
|
+
for (let r of Object.values(e)) if (r && t(r)) {
|
|
32
|
+
let e = r.definition.rootId;
|
|
33
|
+
n.set(e, (n.get(e) ?? 0) + 1);
|
|
34
|
+
}
|
|
35
|
+
return [...n.entries()].map(([t, n]) => ({
|
|
36
|
+
page: i(e, t),
|
|
37
|
+
elements: n
|
|
38
|
+
})).sort((e, t) => t.elements - e.elements);
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
export { r as descendants, a as elementsByRoot, t as parentChain, n as renderContext, i as rootName };
|
|
@@ -21,6 +21,18 @@ export type SchemaValidationResult = {
|
|
|
21
21
|
errors: SchemaValidationError[];
|
|
22
22
|
warnings: SchemaValidationError[];
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* The errors that are a reference to something no longer there, rather than the document being broken.
|
|
26
|
+
*
|
|
27
|
+
* An editor produces them in the ordinary course of editing: delete a provider and the binding that read it names
|
|
28
|
+
* nothing, delete an element and the step aimed at it has no target. The next edit is what settles them — rebind, or
|
|
29
|
+
* drop the step — so a writer that edits one change at a time reports them and refuses them only when the space is
|
|
30
|
+
* about to be served. Every other error is the tree itself broken — an orphan, a cycle, two ids for one element — and
|
|
31
|
+
* no sequence of edits should ever leave one behind.
|
|
32
|
+
*/
|
|
33
|
+
export declare const REFERENCE_ERROR_CODES: ReadonlySet<string>;
|
|
34
|
+
/** Whether an error is the document itself being broken, as opposed to a reference an edit left dangling. */
|
|
35
|
+
export declare const isIntegrityError: (error: SchemaValidationError) => boolean;
|
|
24
36
|
export declare const validateSchema: (schema: Schema, options?: SchemaValidationOptions) => SchemaValidationResult;
|
|
25
37
|
export declare const assertSchemaValid: (schema: Schema, options?: SchemaValidationOptions, context?: string) => void;
|
|
26
38
|
export declare const isSchemaValid: (schema: Schema, options?: SchemaValidationOptions) => boolean;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { isValidElementId as e } from "./elementId.mjs";
|
|
2
2
|
import { findLayoutCycle as t } from "@plitzi/sdk-shared/schema/layoutChain";
|
|
3
3
|
//#region src/helpers/schemaValidator.ts
|
|
4
|
-
var n =
|
|
4
|
+
var n = /* @__PURE__ */ new Set([
|
|
5
|
+
"UNRESOLVED_BINDING_SOURCE",
|
|
6
|
+
"MISMATCHED_BINDING_SOURCE",
|
|
7
|
+
"UNRESOLVED_INTERACTION_TARGET"
|
|
8
|
+
]), r = (e) => !n.has(e.code), i = (n) => {
|
|
5
9
|
let r = [], i = [], { flat: a, pages: o, pageFolders: s, variables: c } = n, l = (e) => !!a[e], u = (e) => a[e], d = () => Object.values(a).filter((e) => e?.definition?.type === "layoutContainer" && !e.definition.parentId).map((e) => e.id), f = () => [...o, ...d()], p = () => !a || typeof a != "object" ? (r.push({
|
|
6
10
|
code: "INVALID_FLAT",
|
|
7
11
|
message: "Schema.flat must be a valid Record<string, Element>"
|
|
@@ -317,34 +321,40 @@ var n = (n) => {
|
|
|
317
321
|
}, T = () => {
|
|
318
322
|
let t = new Set(Object.keys(a));
|
|
319
323
|
Object.values(a).forEach((n) => {
|
|
320
|
-
let
|
|
321
|
-
if (!
|
|
322
|
-
let
|
|
323
|
-
Object.entries(
|
|
324
|
-
e(
|
|
324
|
+
let a = n?.definition.interactions;
|
|
325
|
+
if (!a) return;
|
|
326
|
+
let o = Object.keys(a);
|
|
327
|
+
Object.entries(a).forEach(([a, s]) => {
|
|
328
|
+
e(a) || r.push({
|
|
325
329
|
code: "INVALID_INTERACTION_ID",
|
|
326
|
-
message: `Interaction "${
|
|
330
|
+
message: `Interaction "${a}" on element "${n.id}" has a name that must start with a letter, then letters, numbers, hyphens and underscores — a later step reads it as {{ ${a}.field }}`,
|
|
327
331
|
elementId: n.id
|
|
328
|
-
}),
|
|
332
|
+
}), s.id !== a && r.push({
|
|
329
333
|
code: "INTERACTION_ID_MISMATCH",
|
|
330
|
-
message: `Interaction id "${
|
|
334
|
+
message: `Interaction id "${s.id}" on element "${n.id}" doesn't match its key "${a}"`,
|
|
331
335
|
elementId: n.id
|
|
332
336
|
}), ["beforeNode", "afterNode"].forEach((e) => {
|
|
333
|
-
let t =
|
|
334
|
-
t && !
|
|
337
|
+
let t = s[e];
|
|
338
|
+
t && !o.includes(t) && r.push({
|
|
335
339
|
code: "BROKEN_FLOW_LINK",
|
|
336
|
-
message: `Interaction "${
|
|
340
|
+
message: `Interaction "${s.id}" on element "${n.id}" names ${e} "${t}", which is not a node of this flow`,
|
|
337
341
|
elementId: n.id
|
|
338
342
|
});
|
|
339
|
-
}),
|
|
343
|
+
}), s.flowId && !o.includes(s.flowId) && r.push({
|
|
340
344
|
code: "BROKEN_FLOW_ID",
|
|
341
|
-
message: `Interaction "${
|
|
345
|
+
message: `Interaction "${s.id}" on element "${n.id}" belongs to flow "${s.flowId}", which is not a node of this flow`,
|
|
342
346
|
elementId: n.id
|
|
343
|
-
}),
|
|
347
|
+
}), s.type === "callback" && s.elementId && !t.has(s.elementId) && r.push({
|
|
344
348
|
code: "UNRESOLVED_INTERACTION_TARGET",
|
|
345
|
-
message: `Interaction "${
|
|
349
|
+
message: `Interaction "${s.id}" on element "${n.id}" runs against "${s.elementId}", but no element answers to that name`,
|
|
346
350
|
elementId: n.id
|
|
347
351
|
});
|
|
352
|
+
let c = s.type === "trigger" && s.action === "onSubmit" && s.enabled ? u(s.elementId ?? n.id) : void 0;
|
|
353
|
+
c?.definition.type === "form" && c.attributes.managedByInteractions !== !0 && i.push({
|
|
354
|
+
code: "FORM_SUBMIT_UNMANAGED",
|
|
355
|
+
message: `Form "${c.id}" has an onSubmit flow but is not managedByInteractions, so the browser submits it natively and the flow never runs — set managedByInteractions: true`,
|
|
356
|
+
elementId: c.id
|
|
357
|
+
});
|
|
348
358
|
});
|
|
349
359
|
});
|
|
350
360
|
}, E = () => {
|
|
@@ -383,12 +393,12 @@ var n = (n) => {
|
|
|
383
393
|
warnings: i
|
|
384
394
|
};
|
|
385
395
|
} };
|
|
386
|
-
},
|
|
387
|
-
let
|
|
388
|
-
if (!
|
|
389
|
-
let e = `Invalid schema${n ? ` (${n})` : ""}: ${
|
|
396
|
+
}, a = (e, t) => i(e).validate(t), o = (e, t, n) => {
|
|
397
|
+
let r = a(e, t);
|
|
398
|
+
if (!r.valid) {
|
|
399
|
+
let e = `Invalid schema${n ? ` (${n})` : ""}: ${r.errors.map((e) => e.message).join("; ")}`;
|
|
390
400
|
throw Error(e);
|
|
391
401
|
}
|
|
392
|
-
},
|
|
402
|
+
}, s = (e, t) => a(e, t).valid;
|
|
393
403
|
//#endregion
|
|
394
|
-
export {
|
|
404
|
+
export { n as REFERENCE_ERROR_CODES, o as assertSchemaValid, r as isIntegrityError, s as isSchemaValid, a as validateSchema };
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { Element, Style } from '@plitzi/sdk-shared';
|
|
2
|
+
/**
|
|
3
|
+
* Whether an element renders no element of its own — an `apiContainer` with no `subType`, the builder's "Container
|
|
4
|
+
* Tag: None". Its children sit straight in its parent, so it has no box: nothing to style, and nothing a test can see.
|
|
5
|
+
*/
|
|
6
|
+
export declare const rendersNoTag: (element: Pick<Element, "attributes" | "definition">) => boolean;
|
|
2
7
|
/**
|
|
3
8
|
* Why an element's style applies to nothing, if it does not.
|
|
4
9
|
*
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
//#region src/helpers/styleWithoutTag.ts
|
|
2
|
-
var e = (e) => Object.keys(e ?? {}).length > 0, t = (t) => Object.values(t ?? {}).some(e), n = (n) => e(n.default) || t(n.states) || Object.values(n.variants ?? {}).some((n) => e(n.default) || t(n.states)), r = (e, t) => Object.values(e.platform).some((e) => Object.hasOwn(e, t) && Object.values(e[t].attributes).some(n)), i = (e
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
var e = (e) => Object.keys(e ?? {}).length > 0, t = (t) => Object.values(t ?? {}).some(e), n = (n) => e(n.default) || t(n.states) || Object.values(n.variants ?? {}).some((n) => e(n.default) || t(n.states)), r = (e, t) => Object.values(e.platform).some((e) => Object.hasOwn(e, t) && Object.values(e[t].attributes).some(n)), i = (e) => {
|
|
3
|
+
let t = e.attributes.subType;
|
|
4
|
+
return e.definition.type === "apiContainer" && (typeof t != "string" || t === "");
|
|
5
|
+
}, a = (e, t) => {
|
|
6
|
+
if (!i(e)) return;
|
|
7
|
+
let { styleSelectors: n, initialState: a, bindings: o } = e.definition, s = Object.values(n).some((e) => e.split(" ").some((e) => e && r(t, e))), c = Object.keys(a?.styleVariant ?? {}).length > 0, l = (o?.style?.length ?? 0) > 0;
|
|
7
8
|
if (s || c || l) return "has style but no `subType` (container tag), so it renders no element of its own and the style applies to nothing — its children lay out in its parent. Give it a tag (a `subType` of `div`, `section`, …) or move the style onto its parent or a child.";
|
|
8
9
|
};
|
|
9
10
|
//#endregion
|
|
10
|
-
export { i as styleWithoutTag };
|
|
11
|
+
export { i as rendersNoTag, a as styleWithoutTag };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import { default as FlatMap } from './helpers/FlatMap';
|
|
|
2
2
|
import { default as SchemaReducer } from './SchemaReducer';
|
|
3
3
|
export * from './SchemaReducer';
|
|
4
4
|
export * from './helpers/FlatMap';
|
|
5
|
+
export * from './helpers/elementTree';
|
|
5
6
|
export * from './helpers/schemaValidator';
|
|
6
7
|
export { FlatMap, SchemaReducer };
|