nodality 1.1.13 → 1.1.15
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/bin/mcp-server.mjs +13 -3
- package/dist/animator.cjs.js.LICENSE.txt +1 -1
- package/dist/animator.esm.js.LICENSE.txt +1 -1
- package/dist/audionew.cjs.js.LICENSE.txt +1 -1
- package/dist/audionew.esm.js.LICENSE.txt +1 -1
- package/dist/base.cjs.js.LICENSE.txt +1 -1
- package/dist/base.esm.js.LICENSE.txt +1 -1
- package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
- package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
- package/dist/bundle.umd.js +1 -1
- package/dist/bundle.umd.js.LICENSE.txt +1 -1
- package/dist/button.cjs.js.LICENSE.txt +1 -1
- package/dist/button.esm.js.LICENSE.txt +1 -1
- package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
- package/dist/card-getter.esm.js.LICENSE.txt +1 -1
- package/dist/center.cjs.js.LICENSE.txt +1 -1
- package/dist/center.esm.js.LICENSE.txt +1 -1
- package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
- package/dist/checkbox.esm.js.LICENSE.txt +1 -1
- package/dist/code.cjs.js.LICENSE.txt +1 -1
- package/dist/code.esm.js.LICENSE.txt +1 -1
- package/dist/container.cjs.js.LICENSE.txt +1 -1
- package/dist/container.esm.js.LICENSE.txt +1 -1
- package/dist/data-list.cjs.js.LICENSE.txt +1 -1
- package/dist/data-list.esm.js.LICENSE.txt +1 -1
- package/dist/designer.cjs.js +1 -1
- package/dist/designer.cjs.js.LICENSE.txt +1 -1
- package/dist/designer.esm.js +1 -1
- package/dist/designer.esm.js.LICENSE.txt +1 -1
- package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
- package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
- package/dist/finalresult.esm.js +1 -1
- package/dist/finalresult.esm.js.LICENSE.txt +1 -1
- package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-card.esm.js.LICENSE.txt +1 -1
- package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
- package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-row.esm.js.LICENSE.txt +1 -1
- package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
- package/dist/floating-input.esm.js.LICENSE.txt +1 -1
- package/dist/free.cjs.js.LICENSE.txt +1 -1
- package/dist/free.esm.js.LICENSE.txt +1 -1
- package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
- package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
- package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
- package/dist/image-picker.esm.js.LICENSE.txt +1 -1
- package/dist/image.cjs.js.LICENSE.txt +1 -1
- package/dist/image.esm.js.LICENSE.txt +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.LICENSE.txt +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.LICENSE.txt +1 -1
- package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
- package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
- package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
- package/dist/link-getter.esm.js.LICENSE.txt +1 -1
- package/dist/link.cjs.js.LICENSE.txt +1 -1
- package/dist/link.esm.js.LICENSE.txt +1 -1
- package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
- package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
- package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
- package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
- package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
- package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
- package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
- package/dist/picker.cjs.js.LICENSE.txt +1 -1
- package/dist/picker.esm.js.LICENSE.txt +1 -1
- package/dist/progress.cjs.js.LICENSE.txt +1 -1
- package/dist/progress.esm.js.LICENSE.txt +1 -1
- package/dist/radio.cjs.js.LICENSE.txt +1 -1
- package/dist/radio.esm.js.LICENSE.txt +1 -1
- package/dist/range.cjs.js.LICENSE.txt +1 -1
- package/dist/range.esm.js.LICENSE.txt +1 -1
- package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
- package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
- package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/side-bar.esm.js.LICENSE.txt +1 -1
- package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
- package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
- package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
- package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
- package/dist/spacer.cjs.js.LICENSE.txt +1 -1
- package/dist/spacer.esm.js.LICENSE.txt +1 -1
- package/dist/stack.cjs.js.LICENSE.txt +1 -1
- package/dist/stack.esm.js.LICENSE.txt +1 -1
- package/dist/stacker.cjs.js.LICENSE.txt +1 -1
- package/dist/stacker.esm.js.LICENSE.txt +1 -1
- package/dist/table.cjs.js.LICENSE.txt +1 -1
- package/dist/table.esm.js.LICENSE.txt +1 -1
- package/dist/text-field.cjs.js.LICENSE.txt +1 -1
- package/dist/text-field.esm.js.LICENSE.txt +1 -1
- package/dist/text.cjs.js.LICENSE.txt +1 -1
- package/dist/text.esm.js.LICENSE.txt +1 -1
- package/dist/theme.cjs.js.LICENSE.txt +1 -1
- package/dist/theme.esm.js.LICENSE.txt +1 -1
- package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
- package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
- package/dist/ulist.cjs.js.LICENSE.txt +1 -1
- package/dist/ulist.esm.js.LICENSE.txt +1 -1
- package/dist/video.cjs.js.LICENSE.txt +1 -1
- package/dist/video.esm.js.LICENSE.txt +1 -1
- package/dist/wrap.cjs.js.LICENSE.txt +1 -1
- package/dist/wrap.esm.js.LICENSE.txt +1 -1
- package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
- package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
- package/layout/animator.js +1 -1
- package/layout/audio.js +1 -1
- package/layout/audionew.js +1 -1
- package/layout/base.js +1 -1
- package/layout/beta-desktop-bar.js +1 -1
- package/layout/beta-mobile-bar.js +1 -1
- package/layout/button.js +1 -1
- package/layout/center.js +1 -1
- package/layout/checkbox.js +1 -1
- package/layout/circle.js +1 -1
- package/layout/code.js +1 -1
- package/layout/container.js +1 -1
- package/layout/dropdown-2025.js +1 -1
- package/layout/flex-card.js +1 -1
- package/layout/flex-grid.js +1 -1
- package/layout/flex-row.js +1 -1
- package/layout/form-components/custom.js +1 -1
- package/layout/form-components/data-list.js +1 -1
- package/layout/form-components/floating-input.js +1 -1
- package/layout/form-components/form-all.js +1 -1
- package/layout/form-components/form.js +1 -1
- package/layout/form-components/image-picker.js +1 -1
- package/layout/form-components/picker.js +1 -1
- package/layout/form-components/radio.js +1 -1
- package/layout/form-components/radiogroup.js +1 -1
- package/layout/form-components/range.js +1 -1
- package/layout/free.js +1 -1
- package/layout/grid-switcher.js +1 -1
- package/layout/grid.js +1 -1
- package/layout/horizontal-scroller.js +1 -1
- package/layout/image.js +1 -1
- package/layout/index.js +1 -1
- package/layout/link.js +1 -1
- package/layout/list.js +1 -1
- package/layout/meta-adder.js +1 -1
- package/layout/modal-2025.js +1 -1
- package/layout/morph.js +1 -1
- package/layout/multiswitcher.js +1 -1
- package/layout/nav-bar.js +1 -1
- package/layout/nav-factor/custom-div.js +1 -1
- package/layout/new-nav-bar.js +1 -1
- package/layout/polygon.js +1 -1
- package/layout/prerender-site.js +1 -1
- package/layout/prerender.js +1 -1
- package/layout/progress.js +1 -1
- package/layout/row.js +1 -1
- package/layout/scroll-video.js +1 -1
- package/layout/side-bar.js +1 -1
- package/layout/side-nav-bar.js +1 -1
- package/layout/simple-bar.js +1 -1
- package/layout/slider-2025.js +1 -1
- package/layout/spacer.js +1 -1
- package/layout/stack.js +1 -1
- package/layout/svg.js +1 -1
- package/layout/switcher.js +1 -1
- package/layout/table.js +1 -1
- package/layout/text-field.js +1 -1
- package/layout/text.js +1 -1
- package/layout/ulist.js +1 -1
- package/layout/video.js +1 -1
- package/layout/wrap.js +1 -1
- package/layout/zoom-card.js +1 -1
- package/lib/card-getter.js +1 -1
- package/lib/codegen.js +1 -1
- package/lib/data.js +1 -1
- package/lib/designer.js +1 -1
- package/lib/element-mapper.js +1 -1
- package/lib/keyframe-animation.js +1 -1
- package/lib/link-getter.js +1 -1
- package/lib/morph-node.js +53 -7
- package/lib/raster-inspect.js +1 -1
- package/lib/raster-ops.js +1 -1
- package/lib/raster-presets.js +1 -1
- package/lib/scroll-video.js +1 -1
- package/lib/seo.js +1 -1
- package/lib/stacker.js +1 -1
- package/lib/suggest.js +1 -1
- package/lib/theme.js +1 -1
- package/lib/transform-anim.js +1 -1
- package/lib/transition.js +1 -1
- package/lib/validate-nodes.js +118 -31
- package/package.json +1 -1
package/lib/validate-nodes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* nodality v1.1.
|
|
2
|
+
* nodality v1.1.15
|
|
3
3
|
* (c) 2026 Filip Vabrousek
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -36,10 +36,20 @@ import { didYouMean, suggest } from "./suggest.js";
|
|
|
36
36
|
* the runtime, which is why it has to be reported here.
|
|
37
37
|
*/
|
|
38
38
|
const MORPH_FIELDS = [
|
|
39
|
-
"op", "target", "from", "to",
|
|
39
|
+
"op", "target", "from", "to", "chain",
|
|
40
40
|
"effect", "duration", "back", "live", "fade",
|
|
41
41
|
];
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Every key an entry in `chain` reads. `from` and `to` make the edge; the
|
|
45
|
+
* rest are the node's own settings, overridable per edge — which is why
|
|
46
|
+
* this list is MORPH_FIELDS without `op`, `target` or `chain`, an edge
|
|
47
|
+
* being able to carry neither an op nor a nested chain of its own.
|
|
48
|
+
*/
|
|
49
|
+
const EDGE_FIELDS = [
|
|
50
|
+
"from", "to", "effect", "duration", "back", "live", "fade",
|
|
51
|
+
];
|
|
52
|
+
|
|
43
53
|
/** Node families, told apart exactly the way the runtime tells them apart. */
|
|
44
54
|
const familyOf = (node) => {
|
|
45
55
|
if (!node || typeof node !== "object") return "invalid";
|
|
@@ -96,8 +106,13 @@ export function validateNodes(nodes, elements) {
|
|
|
96
106
|
push("BAD_TARGET", at, t, [], ["an element id"]);
|
|
97
107
|
return;
|
|
98
108
|
}
|
|
99
|
-
//
|
|
100
|
-
// "#"
|
|
109
|
+
// An id may be written bare ("home") or in selector form
|
|
110
|
+
// ("#home"). Both are accepted here because both are accepted
|
|
111
|
+
// by the runtime — `bareId` in morph-node.js reduces them to
|
|
112
|
+
// one key before anything is resolved. The two must agree: for
|
|
113
|
+
// a while this check tolerated "#home" while the runtime did
|
|
114
|
+
// not, so the validator passed a node that silently never
|
|
115
|
+
// morphed, which is the exact failure it exists to prevent.
|
|
101
116
|
const bare = t.startsWith("#") ? t.slice(1) : t;
|
|
102
117
|
if (idsKnown && !ids.includes(bare)) {
|
|
103
118
|
push("UNKNOWN_TARGET", at, t, suggest(bare, ids), ids);
|
|
@@ -121,37 +136,109 @@ export function validateNodes(nodes, elements) {
|
|
|
121
136
|
if (family === "design") return; // design nodes carry their own vocabulary
|
|
122
137
|
|
|
123
138
|
if (family === "morph") {
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
// `from` and `to` are what make a hop; without them it is
|
|
140
|
+
// inert. Factored out because a chain edge has exactly the
|
|
141
|
+
// same two ends as a single-hop node, and the diagnostics
|
|
142
|
+
// should not differ by where the edge was written.
|
|
143
|
+
const checkEnds = (o, at) => {
|
|
144
|
+
if (typeof o.from !== "string") {
|
|
145
|
+
push("MISSING_FIELD", `${at}.from`, o.from, [],
|
|
146
|
+
["the id of the element that morphs"]);
|
|
147
|
+
} else {
|
|
148
|
+
checkTargets(o.from, `${at}.from`);
|
|
149
|
+
}
|
|
150
|
+
if (o.to === undefined) {
|
|
151
|
+
push("MISSING_FIELD", `${at}.to`, undefined, [],
|
|
152
|
+
["[\"id\", ...]", "{ \"Link label\": \"id\" }"]);
|
|
153
|
+
} else if (Array.isArray(o.to)) {
|
|
154
|
+
checkTargets(o.to, `${at}.to`);
|
|
155
|
+
} else if (o.to && typeof o.to === "object") {
|
|
156
|
+
for (const label in o.to) {
|
|
157
|
+
checkTargets(o.to[label], `${at}.to.${label}`);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
push("BAD_FIELD", `${at}.to`, o.to, [],
|
|
161
|
+
["an array of ids, or a map of link label to id"]);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// The settings, which are hoisted defaults on the node and
|
|
166
|
+
// overrides on an edge, so both are checked the same way.
|
|
167
|
+
// `back` and `live` are compared against `false`/`true` by
|
|
168
|
+
// identity in the runtime, which makes a STRING the dangerous
|
|
169
|
+
// mistake: `live: "true"` is not `=== true`, so the live
|
|
170
|
+
// backend silently stays off and the page still works, on the
|
|
171
|
+
// other backend, looking as though the flag took.
|
|
172
|
+
const checkOpts = (o, at) => {
|
|
173
|
+
if (o.duration !== undefined &&
|
|
174
|
+
(typeof o.duration !== "number" || !(o.duration > 0))) {
|
|
175
|
+
push("BAD_VALUE", `${at}.duration`, o.duration, [],
|
|
176
|
+
["a positive number of milliseconds"]);
|
|
177
|
+
}
|
|
178
|
+
if (o.effect !== undefined &&
|
|
179
|
+
typeof o.effect !== "string" && !Array.isArray(o.effect)) {
|
|
180
|
+
push("BAD_FIELD", `${at}.effect`, o.effect, [],
|
|
181
|
+
["a preset name, or an inline array of raster nodes"]);
|
|
182
|
+
}
|
|
183
|
+
for (const flag of ["back", "live"]) {
|
|
184
|
+
if (o[flag] !== undefined && typeof o[flag] !== "boolean") {
|
|
185
|
+
push("BAD_VALUE", `${at}.${flag}`, o[flag], [],
|
|
186
|
+
["true", "false"]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (o.fade !== undefined && typeof o.fade !== "string") {
|
|
190
|
+
push("BAD_FIELD", `${at}.fade`, o.fade, [],
|
|
191
|
+
["a fade mode, as a string"]);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// A node is either one hop or a chain, and the runtime decides
|
|
196
|
+
// by looking at `chain` FIRST: `normalizeEdges` takes a
|
|
197
|
+
// non-empty chain and never reads node-level `from`/`to`. The
|
|
198
|
+
// check mirrors that order, so what passes here is what runs.
|
|
199
|
+
const chained = Array.isArray(node.chain) && node.chain.length > 0;
|
|
200
|
+
|
|
201
|
+
if (node.chain !== undefined && !Array.isArray(node.chain)) {
|
|
202
|
+
push("BAD_FIELD", `${path}.chain`, node.chain, [],
|
|
203
|
+
["an array of edges: [{ from, to }, ...]"]);
|
|
204
|
+
} else if (Array.isArray(node.chain) && !node.chain.length) {
|
|
205
|
+
// The runtime does not reject this — it falls back to the
|
|
206
|
+
// single-hop fields — but it is never what was meant.
|
|
207
|
+
push("BAD_VALUE", `${path}.chain`, node.chain, [],
|
|
208
|
+
["at least one edge, or no `chain` key at all"]);
|
|
131
209
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
210
|
+
|
|
211
|
+
checkOpts(node, path);
|
|
212
|
+
|
|
213
|
+
if (chained) {
|
|
214
|
+
// `from`/`to` written BESIDE a chain are dead, not merged.
|
|
215
|
+
// Worth reporting precisely because the page still works,
|
|
216
|
+
// using the chain, so the ignored pair looks as though it
|
|
217
|
+
// took effect.
|
|
218
|
+
for (const key of ["from", "to"]) {
|
|
219
|
+
if (node[key] !== undefined) {
|
|
220
|
+
push("IGNORED_FIELD", `${path}.${key}`, node[key], [],
|
|
221
|
+
["remove it, or drop `chain` and keep the single hop"]);
|
|
222
|
+
}
|
|
140
223
|
}
|
|
224
|
+
node.chain.forEach((edge, j) => {
|
|
225
|
+
const at = `${path}.chain[${j}]`;
|
|
226
|
+
if (!edge || typeof edge !== "object" || Array.isArray(edge)) {
|
|
227
|
+
push("BAD_FIELD", at, edge, [], ["{ from, to }"]);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
checkEnds(edge, at);
|
|
231
|
+
checkOpts(edge, at);
|
|
232
|
+
for (const key in edge) {
|
|
233
|
+
if (EDGE_FIELDS.includes(key)) continue;
|
|
234
|
+
push("UNKNOWN_PARAM", `${at}.${key}`, key,
|
|
235
|
+
suggest(key, EDGE_FIELDS), EDGE_FIELDS);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
141
238
|
} else {
|
|
142
|
-
|
|
143
|
-
["an array of ids, or a map of link label to id"]);
|
|
144
|
-
}
|
|
145
|
-
if (node.duration !== undefined &&
|
|
146
|
-
(typeof node.duration !== "number" || !(node.duration > 0))) {
|
|
147
|
-
push("BAD_VALUE", `${path}.duration`, node.duration, [],
|
|
148
|
-
["a positive number of milliseconds"]);
|
|
149
|
-
}
|
|
150
|
-
if (node.effect !== undefined &&
|
|
151
|
-
typeof node.effect !== "string" && !Array.isArray(node.effect)) {
|
|
152
|
-
push("BAD_FIELD", `${path}.effect`, node.effect, [],
|
|
153
|
-
["a preset name, or an inline array of raster nodes"]);
|
|
239
|
+
checkEnds(node, path);
|
|
154
240
|
}
|
|
241
|
+
|
|
155
242
|
// Unknown keys, checked here for the same reason they are
|
|
156
243
|
// checked on a raster node: a morph silently ignores what it
|
|
157
244
|
// does not recognise, so `duraton: 900` produces a transition
|