nodality 1.3.10 → 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.
Files changed (283) hide show
  1. package/dist/animator.cjs.js +1 -1
  2. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  3. package/dist/animator.esm.js +1 -1
  4. package/dist/animator.esm.js.LICENSE.txt +1 -1
  5. package/dist/audionew.cjs.js +1 -1
  6. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  7. package/dist/audionew.esm.js +1 -1
  8. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  9. package/dist/base.cjs.js +1 -1
  10. package/dist/base.cjs.js.LICENSE.txt +1 -1
  11. package/dist/base.esm.js +1 -1
  12. package/dist/base.esm.js.LICENSE.txt +1 -1
  13. package/dist/beta-desktop-bar.cjs.js +1 -1
  14. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  15. package/dist/beta-desktop-bar.esm.js +1 -1
  16. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  17. package/dist/beta-mobile-bar.cjs.js +1 -1
  18. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  19. package/dist/beta-mobile-bar.esm.js +1 -1
  20. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  21. package/dist/bundle.umd.js +1 -1
  22. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  23. package/dist/button.cjs.js +1 -1
  24. package/dist/button.cjs.js.LICENSE.txt +1 -1
  25. package/dist/button.esm.js +1 -1
  26. package/dist/button.esm.js.LICENSE.txt +1 -1
  27. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  28. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  29. package/dist/center.cjs.js +1 -1
  30. package/dist/center.cjs.js.LICENSE.txt +1 -1
  31. package/dist/center.esm.js +1 -1
  32. package/dist/center.esm.js.LICENSE.txt +1 -1
  33. package/dist/checkbox.cjs.js +1 -1
  34. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  35. package/dist/checkbox.esm.js +1 -1
  36. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  37. package/dist/code.cjs.js +1 -1
  38. package/dist/code.cjs.js.LICENSE.txt +1 -1
  39. package/dist/code.esm.js +1 -1
  40. package/dist/code.esm.js.LICENSE.txt +1 -1
  41. package/dist/container.cjs.js +1 -1
  42. package/dist/container.cjs.js.LICENSE.txt +1 -1
  43. package/dist/container.esm.js +1 -1
  44. package/dist/container.esm.js.LICENSE.txt +1 -1
  45. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  46. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  47. package/dist/designer.cjs.js +1 -1
  48. package/dist/designer.cjs.js.LICENSE.txt +1 -1
  49. package/dist/designer.esm.js +1 -1
  50. package/dist/designer.esm.js.LICENSE.txt +1 -1
  51. package/dist/element-mapper.cjs.js +1 -1
  52. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  53. package/dist/element-mapper.esm.js +1 -1
  54. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  55. package/dist/finalresult.esm.js +1 -1
  56. package/dist/finalresult.esm.js.LICENSE.txt +1 -1
  57. package/dist/flex-card.cjs.js +1 -1
  58. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  59. package/dist/flex-card.esm.js +1 -1
  60. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  61. package/dist/flex-grid.cjs.js +1 -1
  62. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  63. package/dist/flex-grid.esm.js +1 -1
  64. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  65. package/dist/flex-row.cjs.js +1 -1
  66. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  67. package/dist/flex-row.esm.js +1 -1
  68. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  69. package/dist/floating-input.cjs.js +1 -1
  70. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  71. package/dist/floating-input.esm.js +1 -1
  72. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  73. package/dist/free.cjs.js +1 -1
  74. package/dist/free.cjs.js.LICENSE.txt +1 -1
  75. package/dist/free.esm.js +1 -1
  76. package/dist/free.esm.js.LICENSE.txt +1 -1
  77. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  78. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  79. package/dist/image-picker.cjs.js +1 -1
  80. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  81. package/dist/image-picker.esm.js +1 -1
  82. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  83. package/dist/image.cjs.js +1 -1
  84. package/dist/image.cjs.js.LICENSE.txt +1 -1
  85. package/dist/image.esm.js +1 -1
  86. package/dist/image.esm.js.LICENSE.txt +1 -1
  87. package/dist/index.cjs.js +1 -1
  88. package/dist/index.cjs.js.LICENSE.txt +1 -1
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.esm.js +1 -1
  91. package/dist/index.esm.js.LICENSE.txt +1 -1
  92. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  93. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  94. package/dist/link-getter.cjs.js +1 -1
  95. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  96. package/dist/link-getter.esm.js +1 -1
  97. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  98. package/dist/link.cjs.js +1 -1
  99. package/dist/link.cjs.js.LICENSE.txt +1 -1
  100. package/dist/link.esm.js +1 -1
  101. package/dist/link.esm.js.LICENSE.txt +1 -1
  102. package/dist/meta-adder.cjs.js +1 -1
  103. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  104. package/dist/meta-adder.esm.js +1 -1
  105. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  106. package/dist/modal-2025.cjs.js +1 -1
  107. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  108. package/dist/modal-2025.esm.js +1 -1
  109. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  110. package/dist/multiswitcher.cjs.js +1 -1
  111. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  112. package/dist/multiswitcher.esm.js +1 -1
  113. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  114. package/dist/new-nav-bar.cjs.js +1 -1
  115. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  116. package/dist/new-nav-bar.esm.js +1 -1
  117. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  118. package/dist/picker.cjs.js +1 -1
  119. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  120. package/dist/picker.esm.js +1 -1
  121. package/dist/picker.esm.js.LICENSE.txt +1 -1
  122. package/dist/progress.cjs.js +1 -1
  123. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  124. package/dist/progress.esm.js +1 -1
  125. package/dist/progress.esm.js.LICENSE.txt +1 -1
  126. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  127. package/dist/radio.esm.js.LICENSE.txt +1 -1
  128. package/dist/range.cjs.js.LICENSE.txt +1 -1
  129. package/dist/range.esm.js.LICENSE.txt +1 -1
  130. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  131. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  132. package/dist/side-bar.cjs.js +1 -1
  133. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  134. package/dist/side-bar.esm.js +1 -1
  135. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  136. package/dist/side-nav-bar.cjs.js +1 -1
  137. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  138. package/dist/side-nav-bar.esm.js +1 -1
  139. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  140. package/dist/simple-bar.cjs.js +1 -1
  141. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  142. package/dist/simple-bar.esm.js +1 -1
  143. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  144. package/dist/slider-2025.cjs.js +1 -1
  145. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  146. package/dist/slider-2025.esm.js +1 -1
  147. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  148. package/dist/spacer.cjs.js +1 -1
  149. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  150. package/dist/spacer.esm.js +1 -1
  151. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  152. package/dist/stack.cjs.js +1 -1
  153. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  154. package/dist/stack.esm.js +1 -1
  155. package/dist/stack.esm.js.LICENSE.txt +1 -1
  156. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  157. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  158. package/dist/table.cjs.js +1 -1
  159. package/dist/table.cjs.js.LICENSE.txt +1 -1
  160. package/dist/table.esm.js +1 -1
  161. package/dist/table.esm.js.LICENSE.txt +1 -1
  162. package/dist/text-field.cjs.js +1 -1
  163. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  164. package/dist/text-field.esm.js +1 -1
  165. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  166. package/dist/text.cjs.js +1 -1
  167. package/dist/text.cjs.js.LICENSE.txt +1 -1
  168. package/dist/text.esm.js +1 -1
  169. package/dist/text.esm.js.LICENSE.txt +1 -1
  170. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  171. package/dist/theme.esm.js.LICENSE.txt +1 -1
  172. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  173. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  174. package/dist/ulist.cjs.js +1 -1
  175. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  176. package/dist/ulist.esm.js +1 -1
  177. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  178. package/dist/video.cjs.js +1 -1
  179. package/dist/video.cjs.js.LICENSE.txt +1 -1
  180. package/dist/video.esm.js +1 -1
  181. package/dist/video.esm.js.LICENSE.txt +1 -1
  182. package/dist/wrap.cjs.js +1 -1
  183. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  184. package/dist/wrap.esm.js +1 -1
  185. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  186. package/dist/zoom-card.cjs.js +1 -1
  187. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  188. package/dist/zoom-card.esm.js +1 -1
  189. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  190. package/layout/animator.js +44 -21
  191. package/layout/audio.js +1 -1
  192. package/layout/audionew.js +1 -1
  193. package/layout/base.js +1 -1
  194. package/layout/beta-desktop-bar.js +1 -1
  195. package/layout/beta-mobile-bar.js +1 -1
  196. package/layout/button.js +1 -1
  197. package/layout/center.js +1 -1
  198. package/layout/checkbox.js +1 -1
  199. package/layout/circle.js +1 -1
  200. package/layout/code.js +1 -1
  201. package/layout/container.js +1 -1
  202. package/layout/dropdown-2025.js +1 -1
  203. package/layout/flex-card.js +1 -1
  204. package/layout/flex-grid.js +1 -1
  205. package/layout/flex-row.js +1 -1
  206. package/layout/form-components/custom.js +1 -1
  207. package/layout/form-components/data-list.js +1 -1
  208. package/layout/form-components/floating-input.js +1 -1
  209. package/layout/form-components/form-all.js +1 -1
  210. package/layout/form-components/form.js +1 -1
  211. package/layout/form-components/image-picker.js +1 -1
  212. package/layout/form-components/picker.js +1 -1
  213. package/layout/form-components/radio.js +1 -1
  214. package/layout/form-components/radiogroup.js +1 -1
  215. package/layout/form-components/range.js +1 -1
  216. package/layout/free.js +1 -1
  217. package/layout/grid-overlay.js +19 -19
  218. package/layout/grid-switcher.js +1 -1
  219. package/layout/grid.js +1 -1
  220. package/layout/horizontal-scroller.js +1 -1
  221. package/layout/image.js +1 -1
  222. package/layout/index.js +1 -1
  223. package/layout/link.js +1 -1
  224. package/layout/list.js +1 -1
  225. package/layout/meta-adder.js +1 -1
  226. package/layout/modal-2025.js +1 -1
  227. package/layout/morph.js +1 -1
  228. package/layout/multiswitcher.js +1 -1
  229. package/layout/nav-bar.js +1 -1
  230. package/layout/nav-factor/custom-div.js +1 -1
  231. package/layout/new-nav-bar.js +1 -1
  232. package/layout/polygon.js +1 -1
  233. package/layout/prerender-site.js +1 -1
  234. package/layout/prerender.js +1 -1
  235. package/layout/progress.js +1 -1
  236. package/layout/row.js +1 -1
  237. package/layout/scroll-video.js +1 -1
  238. package/layout/side-bar.js +1 -1
  239. package/layout/side-nav-bar.js +1 -1
  240. package/layout/simple-bar.js +1 -1
  241. package/layout/slider-2025.js +1 -1
  242. package/layout/spacer.js +1 -1
  243. package/layout/stack.js +1 -1
  244. package/layout/svg.js +1 -1
  245. package/layout/switcher.js +1 -1
  246. package/layout/table.js +1 -1
  247. package/layout/text-field.js +1 -1
  248. package/layout/text.js +1 -1
  249. package/layout/ulist.js +1 -1
  250. package/layout/video.js +22 -22
  251. package/layout/wrap.js +1 -1
  252. package/layout/zoom-card.js +1 -1
  253. package/lib/agent-surface.js +1 -1
  254. package/lib/card-getter.js +1 -1
  255. package/lib/check-page.js +1 -1
  256. package/lib/codegen.js +1 -1
  257. package/lib/data.js +1 -1
  258. package/lib/designer.js +1 -1
  259. package/lib/element-mapper.js +83 -13
  260. package/lib/element-params.generated.js +13 -2
  261. package/lib/grid-geometry.js +1 -1
  262. package/lib/keyframe-animation.js +1 -1
  263. package/lib/link-getter.js +1 -1
  264. package/lib/morph-node.js +1 -1
  265. package/lib/normalize-spec.js +1 -1
  266. package/lib/parse-html.js +1 -1
  267. package/lib/raster-inspect.js +1 -1
  268. package/lib/raster-ops.js +1 -1
  269. package/lib/raster-presets.js +1 -1
  270. package/lib/resolve-refs.js +1 -1
  271. package/lib/scroll-video.js +1 -1
  272. package/lib/seo.js +1 -1
  273. package/lib/stacker.js +1 -1
  274. package/lib/suggest.js +1 -1
  275. package/lib/theme.js +1 -1
  276. package/lib/transform-anim.js +1 -1
  277. package/lib/transition.js +1 -1
  278. package/lib/validate-nodes.js +146 -4
  279. package/lib/webmcp-adapter.js +1 -1
  280. package/package.json +1 -1
  281. package/schema.json +1391 -2263
  282. package/scripts/generate-schema.mjs +135 -15
  283. package/skills/nodality/SKILL.md +15 -0
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.10
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 { ELEMENT_PARAM_NAMES } from "./element-params.generated.js";
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
  /**
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.10
2
+ * nodality v1.3.11
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodality",
3
- "version": "1.3.10",
3
+ "version": "1.3.11",
4
4
  "description": "A lightweight library for declarative UI elements.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",