nodality 1.3.9 → 1.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animator.cjs.js +1 -1
- package/dist/animator.cjs.js.LICENSE.txt +1 -1
- package/dist/animator.esm.js +1 -1
- package/dist/animator.esm.js.LICENSE.txt +1 -1
- package/dist/audionew.cjs.js +1 -1
- package/dist/audionew.cjs.js.LICENSE.txt +1 -1
- package/dist/audionew.esm.js +1 -1
- package/dist/audionew.esm.js.LICENSE.txt +1 -1
- package/dist/base.cjs.js +1 -1
- package/dist/base.cjs.js.LICENSE.txt +1 -1
- package/dist/base.esm.js +1 -1
- package/dist/base.esm.js.LICENSE.txt +1 -1
- package/dist/beta-desktop-bar.cjs.js +1 -1
- package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/beta-desktop-bar.esm.js +1 -1
- package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
- package/dist/beta-mobile-bar.cjs.js +1 -1
- package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/beta-mobile-bar.esm.js +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 +1 -1
- package/dist/button.cjs.js.LICENSE.txt +1 -1
- package/dist/button.esm.js +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 +1 -1
- package/dist/center.cjs.js.LICENSE.txt +1 -1
- package/dist/center.esm.js +1 -1
- package/dist/center.esm.js.LICENSE.txt +1 -1
- package/dist/checkbox.cjs.js +1 -1
- package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
- package/dist/checkbox.esm.js +1 -1
- package/dist/checkbox.esm.js.LICENSE.txt +1 -1
- package/dist/code.cjs.js +1 -1
- package/dist/code.cjs.js.LICENSE.txt +1 -1
- package/dist/code.esm.js +1 -1
- package/dist/code.esm.js.LICENSE.txt +1 -1
- package/dist/container.cjs.js +1 -1
- package/dist/container.cjs.js.LICENSE.txt +1 -1
- package/dist/container.esm.js +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 +1 -1
- package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
- package/dist/element-mapper.esm.js +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 +1 -1
- package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-card.esm.js +1 -1
- package/dist/flex-card.esm.js.LICENSE.txt +1 -1
- package/dist/flex-grid.cjs.js +1 -1
- package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-grid.esm.js +1 -1
- package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
- package/dist/flex-row.cjs.js +1 -1
- package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
- package/dist/flex-row.esm.js +1 -1
- package/dist/flex-row.esm.js.LICENSE.txt +1 -1
- package/dist/floating-input.cjs.js +1 -1
- package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
- package/dist/floating-input.esm.js +1 -1
- package/dist/floating-input.esm.js.LICENSE.txt +1 -1
- package/dist/free.cjs.js +1 -1
- package/dist/free.cjs.js.LICENSE.txt +1 -1
- package/dist/free.esm.js +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 +1 -1
- package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
- package/dist/image-picker.esm.js +1 -1
- package/dist/image-picker.esm.js.LICENSE.txt +1 -1
- package/dist/image.cjs.js +1 -1
- package/dist/image.cjs.js.LICENSE.txt +1 -1
- package/dist/image.esm.js +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 +1 -1
- package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
- package/dist/link-getter.esm.js +1 -1
- package/dist/link-getter.esm.js.LICENSE.txt +1 -1
- package/dist/link.cjs.js +1 -1
- package/dist/link.cjs.js.LICENSE.txt +1 -1
- package/dist/link.esm.js +1 -1
- package/dist/link.esm.js.LICENSE.txt +1 -1
- package/dist/meta-adder.cjs.js +1 -1
- package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
- package/dist/meta-adder.esm.js +1 -1
- package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
- package/dist/modal-2025.cjs.js +1 -1
- package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
- package/dist/modal-2025.esm.js +1 -1
- package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
- package/dist/multiswitcher.cjs.js +1 -1
- package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
- package/dist/multiswitcher.esm.js +1 -1
- package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
- package/dist/new-nav-bar.cjs.js +1 -1
- package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/new-nav-bar.esm.js +1 -1
- package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
- package/dist/picker.cjs.js +1 -1
- package/dist/picker.cjs.js.LICENSE.txt +1 -1
- package/dist/picker.esm.js +1 -1
- package/dist/picker.esm.js.LICENSE.txt +1 -1
- package/dist/progress.cjs.js +1 -1
- package/dist/progress.cjs.js.LICENSE.txt +1 -1
- package/dist/progress.esm.js +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 +1 -1
- package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/side-bar.esm.js +1 -1
- package/dist/side-bar.esm.js.LICENSE.txt +1 -1
- package/dist/side-nav-bar.cjs.js +1 -1
- package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/side-nav-bar.esm.js +1 -1
- package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
- package/dist/simple-bar.cjs.js +1 -1
- package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
- package/dist/simple-bar.esm.js +1 -1
- package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
- package/dist/slider-2025.cjs.js +1 -1
- package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
- package/dist/slider-2025.esm.js +1 -1
- package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
- package/dist/spacer.cjs.js +1 -1
- package/dist/spacer.cjs.js.LICENSE.txt +1 -1
- package/dist/spacer.esm.js +1 -1
- package/dist/spacer.esm.js.LICENSE.txt +1 -1
- package/dist/stack.cjs.js +1 -1
- package/dist/stack.cjs.js.LICENSE.txt +1 -1
- package/dist/stack.esm.js +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 +1 -1
- package/dist/table.cjs.js.LICENSE.txt +1 -1
- package/dist/table.esm.js +1 -1
- package/dist/table.esm.js.LICENSE.txt +1 -1
- package/dist/text-field.cjs.js +1 -1
- package/dist/text-field.cjs.js.LICENSE.txt +1 -1
- package/dist/text-field.esm.js +1 -1
- package/dist/text-field.esm.js.LICENSE.txt +1 -1
- package/dist/text.cjs.js +1 -1
- package/dist/text.cjs.js.LICENSE.txt +1 -1
- package/dist/text.esm.js +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 +1 -1
- package/dist/ulist.cjs.js.LICENSE.txt +1 -1
- package/dist/ulist.esm.js +1 -1
- package/dist/ulist.esm.js.LICENSE.txt +1 -1
- package/dist/video.cjs.js +1 -1
- package/dist/video.cjs.js.LICENSE.txt +1 -1
- package/dist/video.esm.js +1 -1
- package/dist/video.esm.js.LICENSE.txt +1 -1
- package/dist/wrap.cjs.js +1 -1
- package/dist/wrap.cjs.js.LICENSE.txt +1 -1
- package/dist/wrap.esm.js +1 -1
- package/dist/wrap.esm.js.LICENSE.txt +1 -1
- package/dist/zoom-card.cjs.js +1 -1
- package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
- package/dist/zoom-card.esm.js +1 -1
- package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
- package/layout/animator.js +44 -21
- 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-overlay.js +19 -19
- 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 +24 -21
- package/layout/wrap.js +1 -1
- package/layout/zoom-card.js +1 -1
- package/lib/agent-surface.js +1 -1
- package/lib/card-getter.js +1 -1
- package/lib/check-page.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 +83 -13
- package/lib/element-params.generated.js +13 -2
- package/lib/grid-geometry.js +1 -1
- package/lib/keyframe-animation.js +1 -1
- package/lib/link-getter.js +1 -1
- package/lib/morph-node.js +1 -1
- package/lib/normalize-spec.js +1 -1
- package/lib/parse-html.js +1 -1
- package/lib/raster-inspect.js +1 -1
- package/lib/raster-ops.js +1 -1
- package/lib/raster-presets.js +1 -1
- package/lib/resolve-refs.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 +146 -4
- package/lib/webmcp-adapter.js +1 -1
- package/package.json +1 -1
- package/schema.json +1391 -2263
- package/scripts/generate-schema.mjs +135 -15
- package/skills/nodality/SKILL.md +15 -0
package/lib/validate-nodes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* nodality v1.3.
|
|
2
|
+
* nodality v1.3.11
|
|
3
3
|
* (c) 2026 Filip Vabrousek
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -33,7 +33,114 @@ import { presetNames, presetInfo } from "./raster-presets.js";
|
|
|
33
33
|
import { collectRefs, isRef, resolveRefs } from "./resolve-refs.js";
|
|
34
34
|
import { normalizeSpec, aliasConflicts, ALIASES } from "./normalize-spec.js";
|
|
35
35
|
import { ELEMENT_TYPES } from "./element-mapper.js";
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
ELEMENT_PARAM_NAMES, ELEMENT_PARAMS_BY_TYPE, ELEMENT_PARAM_UNITS,
|
|
38
|
+
} from "./element-params.generated.js";
|
|
39
|
+
|
|
40
|
+
// ── Value shapes ─────────────────────────────────────────────────────
|
|
41
|
+
//
|
|
42
|
+
// Until now this file checked NAMES and never values, so `{width: 7}`,
|
|
43
|
+
// `{mar: 7}` and `{columns: "four"}` all validated clean and all rendered
|
|
44
|
+
// nothing — the same silent no-op the name checking exists to remove, one
|
|
45
|
+
// level down.
|
|
46
|
+
//
|
|
47
|
+
// A violation is an ERROR only where the value is provably inert: a CSS
|
|
48
|
+
// length written as a bare number is dropped by the CSSOM, and a value
|
|
49
|
+
// outside an enum falls through to a default. Everything else is a WARNING,
|
|
50
|
+
// because several components accept looser input than they document and an
|
|
51
|
+
// error would stop `preview` rendering a page that works — the costlier
|
|
52
|
+
// direction to be wrong in, as 1.2.7 established.
|
|
53
|
+
const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
54
|
+
|
|
55
|
+
const SHAPES = {
|
|
56
|
+
"css-length": {
|
|
57
|
+
want: 'a CSS length with a unit, e.g. "320px", "100%" or "2rem"',
|
|
58
|
+
bad: (v) => typeof v === "number" && v !== 0,
|
|
59
|
+
level: "error",
|
|
60
|
+
fix: (v) => [`"${v}px"`],
|
|
61
|
+
},
|
|
62
|
+
"px-or-length": {
|
|
63
|
+
want: "a number of pixels, or a CSS length string",
|
|
64
|
+
bad: (v) => typeof v !== "number" && typeof v !== "string",
|
|
65
|
+
level: "warning",
|
|
66
|
+
fix: () => ["12", '"12px"'],
|
|
67
|
+
},
|
|
68
|
+
"css-aspect-ratio": {
|
|
69
|
+
want: 'a CSS aspect ratio, e.g. "16 / 9"',
|
|
70
|
+
bad: (v) => typeof v !== "string" || !/\d\s*\/\s*\d/.test(v),
|
|
71
|
+
level: "warning",
|
|
72
|
+
fix: () => ['"16 / 9"'],
|
|
73
|
+
},
|
|
74
|
+
"px-number": {
|
|
75
|
+
want: "a bare number of pixels, e.g. 12",
|
|
76
|
+
bad: (v) => typeof v === "string" && /[a-z%]/i.test(v) && !/^\d+(\.\d+)?px$/.test(v),
|
|
77
|
+
level: "warning",
|
|
78
|
+
fix: (v) => [String(parseFloat(v) || 0)],
|
|
79
|
+
},
|
|
80
|
+
ratio: {
|
|
81
|
+
want: "a number from 0 to 1",
|
|
82
|
+
bad: (v) => typeof v !== "number" || v < 0 || v > 1,
|
|
83
|
+
level: "warning",
|
|
84
|
+
fix: () => ["0.5"],
|
|
85
|
+
},
|
|
86
|
+
count: {
|
|
87
|
+
want: "a whole number",
|
|
88
|
+
bad: (v) => typeof v !== "number" || !Number.isFinite(v) || Math.floor(v) !== v,
|
|
89
|
+
level: "warning",
|
|
90
|
+
fix: (v) => (typeof v === "string" && /^\d+$/.test(v) ? [v] : ["4"]),
|
|
91
|
+
},
|
|
92
|
+
bool: { want: "true or false", bad: (v) => typeof v !== "boolean", level: "warning", fix: () => ["true"] },
|
|
93
|
+
color: { want: "a CSS colour", bad: (v) => typeof v !== "string", level: "warning", fix: () => ['"#0B1B2B"'] },
|
|
94
|
+
url: { want: "a URL string", bad: (v) => typeof v !== "string", level: "warning", fix: () => ['"/path/to/file"'] },
|
|
95
|
+
text: { want: "a string", bad: (v) => typeof v !== "string", level: "warning", fix: () => ['"…"'] },
|
|
96
|
+
"css-cursor": { want: 'a CSS cursor keyword, e.g. "pointer"', bad: (v) => typeof v !== "string", level: "warning", fix: () => ['"pointer"'] },
|
|
97
|
+
"css-transform": { want: 'a CSS transform, e.g. "rotate(3deg)"', bad: (v) => typeof v !== "string" && !isPlainObject(v), level: "warning", fix: () => ['"rotate(3deg)"'] },
|
|
98
|
+
"css-track-list": { want: 'a CSS track list, e.g. "repeat(4, 1fr)"', bad: (v) => typeof v !== "string", level: "warning", fix: () => ['"repeat(4, 1fr)"'] },
|
|
99
|
+
"css-areas": { want: 'CSS grid-template-areas, e.g. \'"nav main"\'', bad: (v) => typeof v !== "string", level: "warning", fix: () => ['\'"nav main"\''] },
|
|
100
|
+
array: { want: "an array", bad: (v) => !Array.isArray(v), level: "warning", fix: () => ["[…]"] },
|
|
101
|
+
nodes: { want: "an array of op nodes", bad: (v) => !Array.isArray(v), level: "warning", fix: () => ['[{ op: "dither" }]'] },
|
|
102
|
+
breakpoints: {
|
|
103
|
+
want: "an array of per-breakpoint overrides, [{breakpoint, ...css}]",
|
|
104
|
+
bad: (v) => !Array.isArray(v),
|
|
105
|
+
level: "warning",
|
|
106
|
+
fix: () => ['[{ breakpoint: 768, gridTemplateColumns: "1fr" }]'],
|
|
107
|
+
},
|
|
108
|
+
object: { want: "an object", bad: (v) => !isPlainObject(v), level: "warning", fix: () => ["{ … }"] },
|
|
109
|
+
keyset: {
|
|
110
|
+
want: "{key, value}, or an array of them",
|
|
111
|
+
bad: (v) => !isPlainObject(v) && !Array.isArray(v),
|
|
112
|
+
level: "warning",
|
|
113
|
+
fix: () => ['[{ key: "display", value: "grid" }]'],
|
|
114
|
+
},
|
|
115
|
+
sides: {
|
|
116
|
+
want: 'an array of side objects, e.g. [{a: 40}] — or "center" for `mar`',
|
|
117
|
+
bad: (v) => !Array.isArray(v) && !isPlainObject(v) && v !== "center",
|
|
118
|
+
level: "warning",
|
|
119
|
+
fix: (v) => (typeof v === "number" ? [`[{ a: ${v} }]`] : ["[{ a: 40 }]"]),
|
|
120
|
+
},
|
|
121
|
+
"scale-step": {
|
|
122
|
+
want: "a fluid type step, S1 through S6",
|
|
123
|
+
bad: (v) => typeof v !== "string" || !/^S[1-6]$/.test(v),
|
|
124
|
+
level: "error",
|
|
125
|
+
fix: () => ['"S3"'],
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/** `enum(a|b|c)` is declared inline rather than listed here. */
|
|
130
|
+
function shapeFor(unit) {
|
|
131
|
+
if (!unit) return null;
|
|
132
|
+
const m = /^enum\(([^)]*)\)$/.exec(unit);
|
|
133
|
+
if (m) {
|
|
134
|
+
const allowed = m[1].split("|").map((x) => x.trim()).filter(Boolean);
|
|
135
|
+
return {
|
|
136
|
+
want: `one of ${allowed.map((a) => `"${a}"`).join(", ")}`,
|
|
137
|
+
bad: (v) => !allowed.includes(v),
|
|
138
|
+
level: "error",
|
|
139
|
+
fix: () => allowed.slice(0, 3).map((a) => `"${a}"`),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return SHAPES[unit] || null;
|
|
143
|
+
}
|
|
37
144
|
import { didYouMean, suggest, levenshtein } from "./suggest.js";
|
|
38
145
|
|
|
39
146
|
/**
|
|
@@ -218,6 +325,10 @@ export const ITEM_SHAPE = {
|
|
|
218
325
|
|
|
219
326
|
export function validateNodes(nodes, elements, defs) {
|
|
220
327
|
const errors = [];
|
|
328
|
+
// Findings that describe a page which will render, but not as written.
|
|
329
|
+
// They are kept apart from `errors` so `ok` keeps meaning "this will
|
|
330
|
+
// render", and a caller that only knows about errors is unaffected.
|
|
331
|
+
const warnings = [];
|
|
221
332
|
const push = (code, path, got, suggestions, valid) => {
|
|
222
333
|
errors.push({
|
|
223
334
|
code, path, got,
|
|
@@ -225,10 +336,18 @@ export function validateNodes(nodes, elements, defs) {
|
|
|
225
336
|
valid: valid || [],
|
|
226
337
|
});
|
|
227
338
|
};
|
|
339
|
+
const warn = (code, path, got, suggestions, valid, detail) => {
|
|
340
|
+
warnings.push({
|
|
341
|
+
code, path, got,
|
|
342
|
+
suggestions: suggestions || [],
|
|
343
|
+
valid: valid || [],
|
|
344
|
+
...(detail ? { detail } : {}),
|
|
345
|
+
});
|
|
346
|
+
};
|
|
228
347
|
|
|
229
348
|
if (!Array.isArray(nodes)) {
|
|
230
349
|
push("BAD_NODES", "nodes", nodes, [], ["an array of node objects"]);
|
|
231
|
-
return { ok: false, errors };
|
|
350
|
+
return { ok: false, errors, warnings };
|
|
232
351
|
}
|
|
233
352
|
|
|
234
353
|
// Ids declared by E, including children, since `target` may name any
|
|
@@ -391,7 +510,30 @@ export function validateNodes(nodes, elements, defs) {
|
|
|
391
510
|
// rendering a page that works. Detection here, full per-type
|
|
392
511
|
// vocabulary from `npx nodality schema <type>`.
|
|
393
512
|
if (typeof el.type === "string") {
|
|
513
|
+
const vocab = ELEMENT_PARAMS_BY_TYPE[el.type];
|
|
394
514
|
for (const key in el) {
|
|
515
|
+
// Known library-wide, but not something THIS type
|
|
516
|
+
// reads. It is not a typo, so the near-miss check
|
|
517
|
+
// below never fires; it simply does nothing, which is
|
|
518
|
+
// how `keySet` on a `table` silently failed to place
|
|
519
|
+
// it in a grid. A warning, not an error: the page
|
|
520
|
+
// renders, just not as written.
|
|
521
|
+
if (vocab && ELEMENT_PARAM_NAMES.includes(key) && !vocab.includes(key)) {
|
|
522
|
+
warn("PARAM_NOT_ON_TYPE", `${p}.${key}`, key, [],
|
|
523
|
+
[`run \`npx nodality schema ${el.type}\` for what this type reads`],
|
|
524
|
+
`"${el.type}" does not read "${key}" — it is accepted and ignored`);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// A value the parameter cannot use. Checked only where
|
|
528
|
+
// the source declares a shape, so this grows with the
|
|
529
|
+
// annotations and never guesses.
|
|
530
|
+
const shape = shapeFor(ELEMENT_PARAM_UNITS[`${el.type}.${key}`]);
|
|
531
|
+
if (shape && el[key] !== undefined && shape.bad(el[key])) {
|
|
532
|
+
const report = shape.level === "error" ? push : warn;
|
|
533
|
+
report("BAD_PARAM_VALUE", `${p}.${key}`, el[key],
|
|
534
|
+
shape.fix(el[key]), [shape.want]);
|
|
535
|
+
}
|
|
536
|
+
|
|
395
537
|
if (ELEMENT_PARAM_NAMES.includes(key)) continue;
|
|
396
538
|
// Ranked, closest first, capped at three. `suggest`
|
|
397
539
|
// returns everything within distance 2 in list order,
|
|
@@ -833,7 +975,7 @@ export function validateNodes(nodes, elements, defs) {
|
|
|
833
975
|
}
|
|
834
976
|
});
|
|
835
977
|
|
|
836
|
-
return { ok: errors.length === 0, errors };
|
|
978
|
+
return { ok: errors.length === 0, errors, warnings };
|
|
837
979
|
}
|
|
838
980
|
|
|
839
981
|
/**
|
package/lib/webmcp-adapter.js
CHANGED