@plitzi/sdk-schema 0.37.8 → 0.37.10
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 +825 -0
- package/dist/SchemaReducer.d.ts +34 -4
- package/dist/SchemaReducer.mjs +143 -96
- package/dist/helpers/FlatMap.d.ts +9 -3
- package/dist/helpers/FlatMap.mjs +11 -10
- package/dist/helpers/components.d.ts +68 -0
- package/dist/helpers/components.mjs +130 -0
- package/dist/helpers/elementId.d.ts +4 -4
- package/dist/helpers/elementId.mjs +2 -0
- package/dist/helpers/fitSnippet.d.ts +32 -0
- package/dist/helpers/fitSnippet.mjs +71 -0
- package/dist/helpers/schemaValidator.d.ts +3 -0
- package/dist/helpers/schemaValidator.mjs +289 -176
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +4 -3
- package/package.json +12 -4
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { isValidElementId as e, repointIds as t, uniqueElementId as n } from "./elementId.mjs";
|
|
2
|
+
import { descendants as r } from "./elementTree.mjs";
|
|
3
|
+
import i from "./FlatMap.mjs";
|
|
4
|
+
import { jsonCopy as a } from "@plitzi/sdk-shared/history";
|
|
5
|
+
//#region src/helpers/components.ts
|
|
6
|
+
var o = /* @__PURE__ */ new Set([
|
|
7
|
+
"referenceType",
|
|
8
|
+
"referenceId",
|
|
9
|
+
"slot",
|
|
10
|
+
"className",
|
|
11
|
+
"style",
|
|
12
|
+
"children",
|
|
13
|
+
"ref",
|
|
14
|
+
"id"
|
|
15
|
+
]), s = /^[A-Za-z][A-Za-z0-9_]*$/, c = (e) => s.test(e) ? o.has(e) ? `"${e}" is an attribute every instance already has` : null : `"${e}" is not a valid prop name: start with a letter, then letters, numbers and underscores — it is read as {{ props.${e} }}`, l = (e) => [{ flat: e.flat }, ...Object.values(e.components).map((e) => ({
|
|
16
|
+
flat: e.flat,
|
|
17
|
+
componentId: e.id
|
|
18
|
+
}))], u = (e, t) => l(e).find((e) => Object.hasOwn(e.flat, t)), d = (e) => new Set(l(e).flatMap((e) => Object.keys(e.flat))), f = (e, t, n) => {
|
|
19
|
+
let r = u(e, t);
|
|
20
|
+
if (!r) return;
|
|
21
|
+
let a = l(e).filter((e) => e.flat !== r.flat);
|
|
22
|
+
return new i({
|
|
23
|
+
flat: r.flat,
|
|
24
|
+
pages: r.componentId ? void 0 : e.pages,
|
|
25
|
+
mintId: n,
|
|
26
|
+
takenElsewhere: (e) => a.some((t) => Object.hasOwn(t.flat, e))
|
|
27
|
+
});
|
|
28
|
+
}, p = (e, t) => Object.hasOwn(e.components, t) ? e.components[t] : void 0, m = (e, t) => e.definition.type === "reference" && e.attributes.referenceType === "component" && (t === void 0 || e.attributes.referenceId === t), h = (e, t) => l(e).flatMap((e) => Object.values(e.flat).filter((e) => m(e, t))), g = (e, n, r) => {
|
|
29
|
+
let i = f(e, n);
|
|
30
|
+
if (!i) return !1;
|
|
31
|
+
let a = i.renameElement(n, r);
|
|
32
|
+
if (!a || n === r) return a;
|
|
33
|
+
for (let o of l(e)) o.flat !== i.flat && a.push(...t(o.flat, { [n]: r }));
|
|
34
|
+
for (let t of Object.values(e.components)) t.rootId === n && (t.rootId = r), t.slots?.includes(n) && (t.slots = t.slots.map((e) => e === n ? r : e));
|
|
35
|
+
return [...new Set(a)];
|
|
36
|
+
}, _ = (e, t) => {
|
|
37
|
+
for (let t of Object.keys(e.props ?? {})) {
|
|
38
|
+
let e = c(t);
|
|
39
|
+
if (e) return e;
|
|
40
|
+
}
|
|
41
|
+
let n = (e.slots ?? []).find((e) => !Object.hasOwn(t, e));
|
|
42
|
+
return n ? `slot "${n}" is not an element of the component` : null;
|
|
43
|
+
}, v = (e, t, n) => ({
|
|
44
|
+
id: t,
|
|
45
|
+
attributes: {
|
|
46
|
+
referenceType: "component",
|
|
47
|
+
referenceId: e.id
|
|
48
|
+
},
|
|
49
|
+
definition: {
|
|
50
|
+
label: e.label ?? e.id,
|
|
51
|
+
type: "reference",
|
|
52
|
+
items: [],
|
|
53
|
+
bindings: {},
|
|
54
|
+
parentId: n.definition.parentId,
|
|
55
|
+
rootId: n.definition.rootId,
|
|
56
|
+
styleSelectors: { base: "" },
|
|
57
|
+
initialState: { visibility: !0 }
|
|
58
|
+
}
|
|
59
|
+
}), y = (t, n, i) => {
|
|
60
|
+
if (!e(n.id) || Object.hasOwn(t.components, n.id)) return !1;
|
|
61
|
+
if (!i) {
|
|
62
|
+
let e = n.flat[n.rootId], r = d(t);
|
|
63
|
+
return !e || e.definition.parentId || Object.keys(n.flat).some((e) => r.has(e)) || _(n, n.flat) ? !1 : (t.components[n.id] = n, !0);
|
|
64
|
+
}
|
|
65
|
+
let { elementId: a, instanceId: o } = i, s = u(t, a), c = s?.flat[a], l = c?.definition.parentId ? s?.flat[c.definition.parentId] : void 0;
|
|
66
|
+
if (!s || !c || !l?.definition.items || !e(o) || d(t).has(o)) return !1;
|
|
67
|
+
let f = {};
|
|
68
|
+
for (let e of [a, ...r(s.flat, a)]) {
|
|
69
|
+
let { parentId: t, ...n } = s.flat[e].definition;
|
|
70
|
+
f[e] = {
|
|
71
|
+
...s.flat[e],
|
|
72
|
+
definition: {
|
|
73
|
+
...n,
|
|
74
|
+
...e === a ? {} : { parentId: t },
|
|
75
|
+
rootId: a
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
let p = {
|
|
80
|
+
...n,
|
|
81
|
+
rootId: a,
|
|
82
|
+
flat: f
|
|
83
|
+
};
|
|
84
|
+
if (_(p, f)) return !1;
|
|
85
|
+
for (let e of Object.keys(f)) delete s.flat[e];
|
|
86
|
+
return s.flat[o] = v(p, o, c), l.definition.items = l.definition.items.map((e) => e === a ? o : e), t.components[p.id] = p, !0;
|
|
87
|
+
}, b = (e, t, n) => {
|
|
88
|
+
let r = p(e, t);
|
|
89
|
+
return !r || _({
|
|
90
|
+
...r,
|
|
91
|
+
...n
|
|
92
|
+
}, r.flat) ? !1 : (e.components[t] = {
|
|
93
|
+
...r,
|
|
94
|
+
...n
|
|
95
|
+
}, !0);
|
|
96
|
+
}, x = (e, t) => !Object.hasOwn(e.components, t) || h(e, t).length > 0 ? !1 : (delete e.components[t], !0), S = (e, i) => {
|
|
97
|
+
let o = u(e, i), s = o?.flat[i], { referenceId: c } = s?.attributes ?? {}, l = s && m(s) && typeof c == "string" ? p(e, c) : void 0, f = s?.definition.parentId ? o?.flat[s.definition.parentId] : void 0;
|
|
98
|
+
if (!o || !s || !l || !f?.definition.items) return !1;
|
|
99
|
+
let h = s.definition.items ?? [], g = (e) => {
|
|
100
|
+
let { slot: t } = o.flat[e].attributes;
|
|
101
|
+
return typeof t == "string" ? t : l.slots?.[0];
|
|
102
|
+
};
|
|
103
|
+
if (h.some((e) => !l.slots?.includes(g(e) ?? ""))) return !1;
|
|
104
|
+
let _ = d(e);
|
|
105
|
+
_.delete(i);
|
|
106
|
+
let v = [l.rootId, ...r(l.flat, l.rootId)], y = {};
|
|
107
|
+
for (let e of v) y[e] = n(e, (e) => _.has(e)), _.add(y[e]);
|
|
108
|
+
let b = {};
|
|
109
|
+
for (let e of v) {
|
|
110
|
+
let t = a(l.flat[e]);
|
|
111
|
+
t.definition.rootId = s.definition.rootId, b[e] = t;
|
|
112
|
+
}
|
|
113
|
+
t(b, y);
|
|
114
|
+
let x = b[y[l.rootId]];
|
|
115
|
+
x.definition.parentId = s.definition.parentId;
|
|
116
|
+
for (let e of h) {
|
|
117
|
+
let t = b[y[g(e) ?? ""]], n = o.flat[e], { slot: r, ...i } = n.attributes;
|
|
118
|
+
o.flat[e] = {
|
|
119
|
+
...n,
|
|
120
|
+
attributes: i,
|
|
121
|
+
definition: {
|
|
122
|
+
...n.definition,
|
|
123
|
+
parentId: t.id
|
|
124
|
+
}
|
|
125
|
+
}, t.definition.items = [...t.definition.items ?? [], e];
|
|
126
|
+
}
|
|
127
|
+
return Object.assign(o.flat, b), delete o.flat[i], f.definition.items = f.definition.items.map((e) => e === i ? x.id : e), x.id;
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
export { o as RESERVED_PROP_NAMES, y as addComponent, p as componentNamed, S as detachInstance, d as documentIds, f as flatMapOf, h as instancesOf, m as isInstance, c as propNameProblem, x as removeComponent, g as renameElement, u as treeOf, l as treesOf, b as updateComponent };
|
|
@@ -11,9 +11,9 @@ export declare const isValidElementId: (id: string) => boolean;
|
|
|
11
11
|
* collapse, and a leading non-letter is dropped — so a name is editable as prose in the builder's tree and still
|
|
12
12
|
* lands as a valid key. Empty when nothing usable survives, which the caller reports rather than storing. */
|
|
13
13
|
export declare const slugifyElementId: (value: string) => string;
|
|
14
|
-
/** Every id
|
|
15
|
-
* space
|
|
16
|
-
* several
|
|
14
|
+
/** Every id in use in one tree, so a new one can be checked or minted against it. Uniqueness spans the DOCUMENT —
|
|
15
|
+
* the space's `flat` and every component's (`documentIds`) — which is what makes a lookup a `flat` key access. A
|
|
16
|
+
* component placed several times repeats its ids in the rendered tree; each instance's scope tells those apart. */
|
|
17
17
|
export declare const takenIds: (flat: Record<Element["id"], Element>) => Set<string>;
|
|
18
18
|
/** Why `id` cannot be used in this document, phrased for a person, or null when it is free and well formed.
|
|
19
19
|
* `ignoreElementId` exempts the element being edited, so re-saving an element its own id is not a conflict. */
|
|
@@ -66,7 +66,7 @@ export declare const repointIds: (flat: Record<Element["id"], Element>, map: Rec
|
|
|
66
66
|
* Renames only the elements of an incoming set whose names this document has already taken, and repoints the set's
|
|
67
67
|
* own references onto the new names.
|
|
68
68
|
*
|
|
69
|
-
* What a
|
|
69
|
+
* What a snippet drop and a cross-document paste both need. Renaming everything would be simpler and worse: the
|
|
70
70
|
* names an author gave the template are the reason it is readable, and a document that had no `hero` should get
|
|
71
71
|
* one called `hero`. Returns the renaming it applied, so a caller can report what it had to change.
|
|
72
72
|
*/
|
|
@@ -78,6 +78,8 @@ var e = /^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9_])?$/, t = (t) => e.test(t), n = (
|
|
|
78
78
|
let r = o[n];
|
|
79
79
|
typeof r == "string" && t[r] && (!i || i(o)) && (o[n] = t[r], e = !0);
|
|
80
80
|
}
|
|
81
|
+
let { slot: s } = o;
|
|
82
|
+
typeof s == "string" && t[s] && (o.slot = t[s], e = !0);
|
|
81
83
|
for (let n of Object.values(r.bindings ?? {})) for (let r of n) {
|
|
82
84
|
let n = p(r.source, t);
|
|
83
85
|
n !== r.source && (r.source = n, e = !0), r.transformers && g(r.transformers, t) && (e = !0), r.when && g(r.when, t) && (e = !0);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Element, Schema, SnippetStyle, Style } from '@plitzi/sdk-shared';
|
|
2
|
+
type Elements = Record<Element['id'], Element>;
|
|
3
|
+
/**
|
|
4
|
+
* A snippet, fitted to the space it is about to enter: its elements and its classes under names that are free there.
|
|
5
|
+
*
|
|
6
|
+
* A snippet arrives from a document nobody here has seen, and the names it brought may not be free — dropping the same
|
|
7
|
+
* snippet twice is enough. Only what collides changes, and everything that pointed at it is repointed with it: the
|
|
8
|
+
* names an author gave are why the snippet reads well, and a space with no `hero` should get one called `hero`.
|
|
9
|
+
*
|
|
10
|
+
* - An element whose id the space holds is renamed (`remapCollidingIds`).
|
|
11
|
+
* - A class the space uses for something else is renamed, in the snippet's style and on the elements that wear it, so
|
|
12
|
+
* the space's own `.card` is not restyled by the snippet's. One that says the same is shared.
|
|
13
|
+
* - Rules for an element type, and tokens, are left for the merge (`mergeSnippetStyle`), which adds what the space
|
|
14
|
+
* lacks and keeps what it has.
|
|
15
|
+
*
|
|
16
|
+
* Decided once, where somebody dropped it, and carried by the insert from there: the editor, the server it is saved to
|
|
17
|
+
* and every collaborator it is broadcast to then insert the same names, and one that stopped being free on the way is
|
|
18
|
+
* refused there rather than stored under another name. Copied first: the snippet belongs to whoever passed it.
|
|
19
|
+
*/
|
|
20
|
+
declare const fitSnippet: (space: {
|
|
21
|
+
schema: Pick<Schema, "flat" | "components">;
|
|
22
|
+
style: Pick<Style, "platform">;
|
|
23
|
+
}, snippet: {
|
|
24
|
+
data: Element;
|
|
25
|
+
initialItems?: Elements;
|
|
26
|
+
style?: SnippetStyle;
|
|
27
|
+
}) => {
|
|
28
|
+
data: Element;
|
|
29
|
+
initialItems: Elements;
|
|
30
|
+
style?: SnippetStyle;
|
|
31
|
+
};
|
|
32
|
+
export default fitSnippet;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { remapCollidingIds as e } from "./elementId.mjs";
|
|
2
|
+
import { documentIds as t } from "./components.mjs";
|
|
3
|
+
import { isDisplayMode as n } from "@plitzi/sdk-shared/style/displayModes";
|
|
4
|
+
import { sameSelector as r, selectorsOf as i } from "@plitzi/sdk-shared/style/snippetStyle";
|
|
5
|
+
import a from "@plitzi/sdk-style/helpers/processSelector";
|
|
6
|
+
//#region src/helpers/fitSnippet.ts
|
|
7
|
+
var o = (e, t) => {
|
|
8
|
+
let n = 2;
|
|
9
|
+
for (; t.has(`${e}-${n}`);) n += 1;
|
|
10
|
+
return `${e}-${n}`;
|
|
11
|
+
}, s = (e, t) => {
|
|
12
|
+
let n = /* @__PURE__ */ new Set([...i(e), ...i(t)]), a = /* @__PURE__ */ new Map();
|
|
13
|
+
return i(t).forEach((s) => {
|
|
14
|
+
if (Object.values(t).find((e) => Object.hasOwn(e, s))?.[s]?.type === "element" || !i(e).has(s) || r(s, e, t)) return;
|
|
15
|
+
let c = o(s, n);
|
|
16
|
+
n.add(c), a.set(s, c);
|
|
17
|
+
}), a;
|
|
18
|
+
}, c = (e, t, n) => {
|
|
19
|
+
let r = t !== e.name, i = Object.fromEntries(Object.entries(e.attributes).map(([e, t]) => {
|
|
20
|
+
if (!t.ancestors || !Object.keys(t.ancestors).some((e) => n.has(e))) return [e, t];
|
|
21
|
+
r = !0;
|
|
22
|
+
let i = Object.fromEntries(Object.entries(t.ancestors).map(([e, t]) => [n.get(e) ?? e, t]));
|
|
23
|
+
return [e, {
|
|
24
|
+
...t,
|
|
25
|
+
ancestors: i
|
|
26
|
+
}];
|
|
27
|
+
}));
|
|
28
|
+
if (!r) return e;
|
|
29
|
+
let o = {
|
|
30
|
+
...e,
|
|
31
|
+
name: t,
|
|
32
|
+
attributes: i
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
...o,
|
|
36
|
+
cache: a(o)
|
|
37
|
+
};
|
|
38
|
+
}, l = (e, t) => {
|
|
39
|
+
if (t.size === 0) return e;
|
|
40
|
+
let r = { ...e.platform };
|
|
41
|
+
return Object.keys(r).filter(n).forEach((e) => {
|
|
42
|
+
r[e] = Object.fromEntries(Object.entries(r[e]).map(([e, n]) => {
|
|
43
|
+
let r = t.get(e) ?? e;
|
|
44
|
+
return [r, c(n, r, t)];
|
|
45
|
+
}));
|
|
46
|
+
}), {
|
|
47
|
+
...e,
|
|
48
|
+
platform: r
|
|
49
|
+
};
|
|
50
|
+
}, u = (e, t) => {
|
|
51
|
+
Object.values(e).forEach((e) => {
|
|
52
|
+
let { styleSelectors: n } = e.definition;
|
|
53
|
+
Object.keys(n).forEach((e) => {
|
|
54
|
+
n[e] = n[e].split(/\s+/).map((e) => t.get(e) ?? e).join(" ");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}, d = (n, r) => {
|
|
58
|
+
let i = structuredClone({
|
|
59
|
+
...r.initialItems,
|
|
60
|
+
[r.data.id]: r.data
|
|
61
|
+
}), a = t(n.schema), o = e(i, (e) => a.has(e)), c = r.style ? s(n.style.platform, r.style.platform) : /* @__PURE__ */ new Map();
|
|
62
|
+
u(i, c);
|
|
63
|
+
let { [o[r.data.id] ?? r.data.id]: d, ...f } = i;
|
|
64
|
+
return {
|
|
65
|
+
data: d,
|
|
66
|
+
initialItems: f,
|
|
67
|
+
style: r.style && l(r.style, c)
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
export { d as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Schema } from '@plitzi/sdk-shared';
|
|
2
2
|
export type SchemaValidationOptions = {
|
|
3
|
+
/** Validates `flat` as a fragment hung off this element — a component's tree — instead of as the pages' tree. */
|
|
3
4
|
baseElementId?: string;
|
|
4
5
|
/**
|
|
5
6
|
* Element type → the source name it publishes under.
|
|
@@ -14,6 +15,8 @@ export type SchemaValidationError = {
|
|
|
14
15
|
code: string;
|
|
15
16
|
message: string;
|
|
16
17
|
elementId?: string;
|
|
18
|
+
/** The component whose tree the error is in; absent for the pages' tree. */
|
|
19
|
+
componentId?: string;
|
|
17
20
|
details?: unknown;
|
|
18
21
|
};
|
|
19
22
|
export type SchemaValidationResult = {
|