sygnal 5.4.0 → 6.0.0

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 (316) hide show
  1. package/CHANGELOG.md +646 -0
  2. package/README.md +24 -9
  3. package/dist/astro/client.cjs.js +16 -9
  4. package/dist/astro/client.cjs.js.map +1 -1
  5. package/dist/astro/client.mjs +16 -9
  6. package/dist/astro/client.mjs.map +1 -1
  7. package/dist/astro/index.cjs.js +362 -91
  8. package/dist/astro/index.cjs.js.map +1 -1
  9. package/dist/astro/index.mjs +362 -92
  10. package/dist/astro/index.mjs.map +1 -1
  11. package/dist/astro/server.cjs.js +3396 -165
  12. package/dist/astro/server.cjs.js.map +1 -1
  13. package/dist/astro/server.mjs +3396 -165
  14. package/dist/astro/server.mjs.map +1 -1
  15. package/dist/devtools.cjs.js +1431 -0
  16. package/dist/devtools.cjs.js.map +1 -0
  17. package/dist/devtools.esm.js +1419 -0
  18. package/dist/devtools.esm.js.map +1 -0
  19. package/dist/diagnostics.cjs.js +3032 -296
  20. package/dist/diagnostics.cjs.js.map +1 -1
  21. package/dist/diagnostics.esm.js +3032 -296
  22. package/dist/diagnostics.esm.js.map +1 -1
  23. package/dist/element.cjs.js +230 -0
  24. package/dist/element.cjs.js.map +1 -0
  25. package/dist/element.esm.js +228 -0
  26. package/dist/element.esm.js.map +1 -0
  27. package/dist/guide/accessibility.md +257 -0
  28. package/dist/guide/adapters.md +221 -0
  29. package/dist/guide/behaviors.md +312 -0
  30. package/dist/guide/browser-sources.md +203 -0
  31. package/dist/guide/drag-and-drop.md +342 -0
  32. package/dist/guide/element-commands.md +306 -0
  33. package/dist/guide/error-boundaries.md +169 -0
  34. package/dist/guide/forms-reference.md +381 -0
  35. package/dist/guide/forms.md +250 -0
  36. package/dist/guide/http.md +299 -0
  37. package/dist/guide/inputs.md +173 -0
  38. package/dist/guide/persistence.md +245 -0
  39. package/dist/guide/recipes/carousel.md +155 -0
  40. package/dist/guide/recipes/charts.md +177 -0
  41. package/dist/guide/recipes/code-editor.md +135 -0
  42. package/dist/guide/recipes/data-grid.md +155 -0
  43. package/dist/guide/recipes/data-table.md +196 -0
  44. package/dist/guide/recipes/i18n.md +222 -0
  45. package/dist/guide/recipes/icons.md +115 -0
  46. package/dist/guide/recipes/overview.md +33 -0
  47. package/dist/guide/recipes/rich-text.md +154 -0
  48. package/dist/guide/resources.md +471 -0
  49. package/dist/guide/ssr.md +255 -0
  50. package/dist/guide/timers.md +178 -0
  51. package/dist/guide/ui/accordion.md +93 -0
  52. package/dist/guide/ui/combobox.md +144 -0
  53. package/dist/guide/ui/dialog.md +124 -0
  54. package/dist/guide/ui/disclosure.md +60 -0
  55. package/dist/guide/ui/menu.md +125 -0
  56. package/dist/guide/ui/overview.md +166 -0
  57. package/dist/guide/ui/popover.md +101 -0
  58. package/dist/guide/ui/select.md +114 -0
  59. package/dist/guide/ui/tabs.md +161 -0
  60. package/dist/guide/ui/toaster.md +152 -0
  61. package/dist/guide/ui/tooltip.md +103 -0
  62. package/dist/guide/undo.md +178 -0
  63. package/dist/guide/virtual-collections.md +183 -0
  64. package/dist/guide/web-components.md +179 -0
  65. package/dist/guide/widgets.md +217 -0
  66. package/dist/index.cjs.js +13178 -5769
  67. package/dist/index.cjs.js.map +1 -1
  68. package/dist/index.d.ts +2908 -276
  69. package/dist/index.esm.js +13149 -5779
  70. package/dist/index.esm.js.map +1 -1
  71. package/dist/jsx-dev-runtime.cjs.js +26 -334
  72. package/dist/jsx-dev-runtime.cjs.js.map +1 -1
  73. package/dist/jsx-dev-runtime.esm.js +19 -327
  74. package/dist/jsx-dev-runtime.esm.js.map +1 -1
  75. package/dist/jsx-runtime.cjs.js +26 -334
  76. package/dist/jsx-runtime.cjs.js.map +1 -1
  77. package/dist/jsx-runtime.esm.js +19 -327
  78. package/dist/jsx-runtime.esm.js.map +1 -1
  79. package/dist/jsx.cjs.js +10 -314
  80. package/dist/jsx.cjs.js.map +1 -1
  81. package/dist/jsx.esm.js +8 -315
  82. package/dist/jsx.esm.js.map +1 -1
  83. package/dist/react.cjs.js +117 -0
  84. package/dist/react.cjs.js.map +1 -0
  85. package/dist/react.esm.js +115 -0
  86. package/dist/react.esm.js.map +1 -0
  87. package/dist/shims/globalthis.cjs +20 -0
  88. package/dist/sygnal.min.js +1 -1
  89. package/dist/sygnal.min.js.map +1 -1
  90. package/dist/ui-combobox.cjs.js +169 -0
  91. package/dist/ui-combobox.cjs.js.map +1 -0
  92. package/dist/ui-combobox.esm.js +148 -0
  93. package/dist/ui-combobox.esm.js.map +1 -0
  94. package/dist/ui-menu.cjs.js +87 -0
  95. package/dist/ui-menu.cjs.js.map +1 -0
  96. package/dist/ui-menu.esm.js +66 -0
  97. package/dist/ui-menu.esm.js.map +1 -0
  98. package/dist/ui-select.cjs.js +104 -0
  99. package/dist/ui-select.cjs.js.map +1 -0
  100. package/dist/ui-select.esm.js +83 -0
  101. package/dist/ui-select.esm.js.map +1 -0
  102. package/dist/ui.cjs.js +738 -0
  103. package/dist/ui.cjs.js.map +1 -0
  104. package/dist/ui.esm.js +727 -0
  105. package/dist/ui.esm.js.map +1 -0
  106. package/dist/vike/ClientOnly.cjs.js +4 -14
  107. package/dist/vike/ClientOnly.cjs.js.map +1 -1
  108. package/dist/vike/ClientOnly.mjs +4 -14
  109. package/dist/vike/ClientOnly.mjs.map +1 -1
  110. package/dist/vike/{+config.js → config/+config.js} +9 -1
  111. package/dist/vike/config/+config.js.map +1 -0
  112. package/dist/vike/config/package.json +6 -0
  113. package/dist/vike/onRenderClient.cjs.js +165 -95
  114. package/dist/vike/onRenderClient.cjs.js.map +1 -1
  115. package/dist/vike/onRenderClient.mjs +165 -95
  116. package/dist/vike/onRenderClient.mjs.map +1 -1
  117. package/dist/vike/onRenderHtml.cjs.js +59 -24
  118. package/dist/vike/onRenderHtml.cjs.js.map +1 -1
  119. package/dist/vike/onRenderHtml.mjs +60 -25
  120. package/dist/vike/onRenderHtml.mjs.map +1 -1
  121. package/dist/vite/plugin.cjs.js +323 -88
  122. package/dist/vite/plugin.cjs.js.map +1 -1
  123. package/dist/vite/plugin.mjs +323 -89
  124. package/dist/vite/plugin.mjs.map +1 -1
  125. package/dist/zag.cjs.js +408 -0
  126. package/dist/zag.cjs.js.map +1 -0
  127. package/dist/zag.esm.js +405 -0
  128. package/dist/zag.esm.js.map +1 -0
  129. package/llms.txt +166 -103
  130. package/package.json +98 -14
  131. package/src/astro/client.ts +27 -16
  132. package/src/astro/index.d.ts +24 -0
  133. package/src/astro/index.ts +69 -3
  134. package/src/astro/server.ts +8 -2
  135. package/src/collection.ts +6 -93
  136. package/src/core/actions.ts +134 -0
  137. package/src/core/cell.ts +202 -0
  138. package/src/core/debug.ts +23 -0
  139. package/src/core/define.ts +242 -0
  140. package/src/core/hooks.ts +314 -0
  141. package/src/core/hosts/collection.ts +325 -0
  142. package/src/core/hosts/switchable.ts +146 -0
  143. package/src/core/instance.ts +592 -0
  144. package/src/core/markers/clientonly.ts +13 -0
  145. package/src/core/markers/lazy.ts +40 -0
  146. package/src/core/markers/portal.ts +96 -0
  147. package/src/core/markers/suspense.ts +41 -0
  148. package/src/core/markers/transition.ts +70 -0
  149. package/src/core/registry.ts +25 -0
  150. package/src/core/runtime.ts +573 -0
  151. package/src/core/statics.ts +104 -0
  152. package/src/core/teardown.ts +60 -0
  153. package/src/core/view.ts +37 -0
  154. package/src/cycle/dom/DocumentDOMSource.ts +13 -8
  155. package/src/cycle/dom/ElementFinder.ts +7 -9
  156. package/src/cycle/dom/EventDelegator.ts +174 -223
  157. package/src/cycle/dom/IsolateModule.ts +65 -35
  158. package/src/cycle/dom/MainDOMSource.ts +9 -2
  159. package/src/cycle/dom/PriorityQueue.ts +4 -2
  160. package/src/cycle/dom/SymbolTree.ts +18 -47
  161. package/src/cycle/dom/classNameModule.ts +9 -7
  162. package/src/cycle/dom/controlledInputModule.ts +23 -6
  163. package/src/cycle/dom/enrichEventStream.ts +25 -47
  164. package/src/cycle/dom/fragment.ts +7 -0
  165. package/src/cycle/dom/isolate.ts +30 -27
  166. package/src/cycle/dom/makeDOMDriver.ts +115 -56
  167. package/src/cycle/dom/mockDOMSource.ts +21 -1
  168. package/src/cycle/dom/modules.ts +16 -3
  169. package/src/cycle/dom/propsModule.ts +65 -0
  170. package/src/cycle/dom/selectModule.ts +22 -17
  171. package/src/cycle/dom/snabbdom.ts +1 -6
  172. package/src/cycle/dom/thunk.ts +3 -0
  173. package/src/cycle/dom/utils.ts +98 -0
  174. package/src/cycle/dom/viewTransition.ts +43 -0
  175. package/src/cycle/state/StateSource.ts +19 -3
  176. package/src/cycle/state/objIsEqual.ts +50 -0
  177. package/src/cycle/state/types.ts +0 -10
  178. package/src/defineComponent.ts +34 -0
  179. package/src/devtools.d.ts +151 -0
  180. package/src/devtools.ts +34 -0
  181. package/src/element.d.ts +59 -0
  182. package/src/element.ts +235 -0
  183. package/src/extra/backoff.ts +9 -0
  184. package/src/extra/behaviors.ts +169 -0
  185. package/src/extra/browserSignals.ts +23 -0
  186. package/src/extra/browserSources.ts +326 -0
  187. package/src/extra/command.ts +3 -3
  188. package/src/extra/controls.ts +47 -0
  189. package/src/extra/copyAsTest.ts +286 -0
  190. package/src/extra/devtools.ts +101 -31
  191. package/src/extra/devtoolsActions.ts +379 -0
  192. package/src/extra/devtoolsHook.ts +9 -0
  193. package/src/extra/devtoolsNext.ts +83 -0
  194. package/src/extra/diagnostics/checks/actionLog.ts +108 -0
  195. package/src/extra/diagnostics/checks/behaviors.ts +49 -0
  196. package/src/extra/diagnostics/checks/browserSources.ts +96 -0
  197. package/src/extra/diagnostics/checks/collections.ts +1 -1
  198. package/src/extra/diagnostics/checks/controls.ts +148 -0
  199. package/src/extra/diagnostics/checks/dataset.ts +57 -0
  200. package/src/extra/diagnostics/checks/dom.ts +20 -11
  201. package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
  202. package/src/extra/diagnostics/checks/events.ts +17 -2
  203. package/src/extra/diagnostics/checks/fetch.ts +135 -0
  204. package/src/extra/diagnostics/checks/forms.ts +163 -0
  205. package/src/extra/diagnostics/checks/index.ts +97 -4
  206. package/src/extra/diagnostics/checks/inspect.ts +140 -32
  207. package/src/extra/diagnostics/checks/next.ts +417 -0
  208. package/src/extra/diagnostics/checks/persist.ts +54 -0
  209. package/src/extra/diagnostics/checks/props.ts +10 -5
  210. package/src/extra/diagnostics/checks/public.d.ts +98 -7
  211. package/src/extra/diagnostics/checks/replies.ts +128 -0
  212. package/src/extra/diagnostics/checks/router.ts +100 -0
  213. package/src/extra/diagnostics/checks/rxjsHints.ts +1 -1
  214. package/src/extra/diagnostics/checks/shared.ts +86 -2
  215. package/src/extra/diagnostics/checks/shorthand.ts +115 -0
  216. package/src/extra/diagnostics/checks/sortable.ts +129 -0
  217. package/src/extra/diagnostics/checks/state.ts +100 -7
  218. package/src/extra/diagnostics/checks/statics.ts +48 -0
  219. package/src/extra/diagnostics/checks/strict.ts +10 -67
  220. package/src/extra/diagnostics/checks/timers.ts +80 -0
  221. package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
  222. package/src/extra/diagnostics/checks/virtual.ts +73 -0
  223. package/src/extra/diagnostics/checks/widgets.ts +109 -0
  224. package/src/extra/diagnostics/checks/wiring.ts +66 -10
  225. package/src/extra/diagnostics/codes.ts +268 -23
  226. package/src/extra/diagnostics/index.ts +34 -9
  227. package/src/extra/diagnostics/legacy.ts +17 -0
  228. package/src/extra/driverFactories.ts +83 -19
  229. package/src/extra/elementCommands.ts +53 -0
  230. package/src/extra/fetchDriver.ts +519 -0
  231. package/src/extra/focusWithin.ts +27 -0
  232. package/src/extra/form.ts +268 -0
  233. package/src/extra/formHelpers.ts +139 -0
  234. package/src/extra/head.ts +106 -0
  235. package/src/extra/hmr.ts +2 -3
  236. package/src/extra/owned.ts +24 -0
  237. package/src/extra/pager.ts +50 -0
  238. package/src/extra/persist.ts +133 -0
  239. package/src/extra/pwa.ts +1 -1
  240. package/src/extra/queryCache.ts +107 -0
  241. package/src/extra/reducers.ts +1 -1
  242. package/src/extra/reduxDevtools.ts +92 -0
  243. package/src/extra/replies.ts +54 -0
  244. package/src/extra/router.ts +323 -0
  245. package/src/extra/run.ts +90 -217
  246. package/src/extra/selection.ts +76 -0
  247. package/src/extra/socketDriver.ts +265 -0
  248. package/src/extra/sortable.ts +377 -0
  249. package/src/extra/ssr.ts +427 -160
  250. package/src/extra/standardSchema.ts +27 -0
  251. package/src/extra/testing.ts +2433 -175
  252. package/src/extra/timers.ts +95 -0
  253. package/src/extra/undo.ts +261 -0
  254. package/src/extra/viewTransitions.ts +38 -0
  255. package/src/extra/virtual.ts +513 -0
  256. package/src/extra/widget.ts +201 -0
  257. package/src/index.d.ts +2631 -117
  258. package/src/index.ts +25 -4
  259. package/src/jsx-runtime.ts +15 -1
  260. package/src/jsx.ts +2 -1
  261. package/src/lazy.ts +50 -7
  262. package/src/portal.ts +3 -1
  263. package/src/pragma/index.ts +256 -133
  264. package/src/react-peers.d.ts +5 -0
  265. package/src/react.d.ts +43 -0
  266. package/src/react.ts +110 -0
  267. package/src/shared.ts +48 -0
  268. package/src/slot.ts +1 -1
  269. package/src/suspense.ts +3 -1
  270. package/src/switchable.ts +6 -121
  271. package/src/transition.ts +3 -1
  272. package/src/ui/accordion.ts +64 -0
  273. package/src/ui/dialog.ts +129 -0
  274. package/src/ui/disclosure.ts +35 -0
  275. package/src/ui/popover.ts +45 -0
  276. package/src/ui/shared.ts +94 -0
  277. package/src/ui/tabs.ts +82 -0
  278. package/src/ui/toaster.ts +198 -0
  279. package/src/ui/tooltip.ts +70 -0
  280. package/src/ui/zag/combobox.ts +115 -0
  281. package/src/ui/zag/menu.ts +40 -0
  282. package/src/ui/zag/select.ts +54 -0
  283. package/src/ui/zag/shared.ts +43 -0
  284. package/src/ui-combobox.d.ts +20 -0
  285. package/src/ui-combobox.ts +6 -0
  286. package/src/ui-menu.d.ts +30 -0
  287. package/src/ui-menu.ts +6 -0
  288. package/src/ui-select.d.ts +17 -0
  289. package/src/ui-select.ts +6 -0
  290. package/src/ui-zag-types.d.ts +42 -0
  291. package/src/ui.d.ts +208 -0
  292. package/src/ui.ts +15 -0
  293. package/src/vike/+config.ts +9 -1
  294. package/src/vike/ClientOnly.ts +1 -1
  295. package/src/vike/onRenderClient.ts +144 -96
  296. package/src/vike/onRenderHtml.ts +69 -26
  297. package/src/vike/types.ts +7 -1
  298. package/src/vite/globalthis-shim.ts +18 -0
  299. package/src/vite/globalthis.ts +56 -0
  300. package/src/vite/plugin.d.ts +22 -3
  301. package/src/vite/plugin.ts +222 -24
  302. package/src/zag.d.ts +64 -0
  303. package/src/zag.ts +238 -0
  304. package/dist/vike/+config.cjs.js +0 -66
  305. package/dist/vike/+config.cjs.js.map +0 -1
  306. package/dist/vike/+config.js.map +0 -1
  307. package/src/component.ts +0 -2301
  308. package/src/cycle/isolate/index.ts +0 -196
  309. package/src/cycle/run/index.ts +0 -151
  310. package/src/cycle/run/internals.ts +0 -143
  311. package/src/cycle/state/Collection.ts +0 -184
  312. package/src/cycle/state/index.ts +0 -5
  313. package/src/cycle/state/pickCombine.ts +0 -201
  314. package/src/cycle/state/pickMerge.ts +0 -122
  315. package/src/cycle/state/withState.ts +0 -47
  316. package/src/pragma/fn.ts +0 -55
@@ -0,0 +1,417 @@
1
+ /**
2
+ * PLAN-4.6 R4: the dev entry's checks on the next component core (src/core/).
3
+ *
4
+ * The core has no instance to patch and no diagnostics calls of its own: it reads this
5
+ * entry's hooks once per app (`__SYGNAL_DIAGNOSTICS__.nextHooks(api)`, 04-hooks-contract §2.2)
6
+ * and calls them with read-only InstanceViews. This module maps them onto the existing checks:
7
+ *
8
+ * - each instance gets a facade with the fields the checks read from today's instances (name,
9
+ * view, model, sources, currentState, ...), so the DiagnosticCheck hooks (onIntent, onModel,
10
+ * onRender, onReducer, onDispose, sources) run unchanged through the core's dispatchers;
11
+ * - what the checks did by patching an instance becomes a hook: SYG222's reducer wrapping
12
+ * (wrapHandler), the reply / fetch / EVENTS taps of a sink (onSink), the ELEMENT check
13
+ * (onElementCommand), the Collection check (onHostProps), the action log (actionLog.ts);
14
+ * - the core's own dev codes: SYG423 (D168: a view context tracking skipped would have
15
+ * rendered differently), SYG424 (D169/D177: duplicate Collection ids), SYG425 (D174: an
16
+ * isolatedState child kept a slice that lacks its initialState keys), SYG148 / SYG149 (G-419:
17
+ * a Collection's viewTransitionName that isn't an identifier, the same name twice on the
18
+ * page after a patch, G-460: on rendered elements), SYG612 (D173: a form
19
+ * 6.0 removed, met at runtime; once per form and component, with a link to the migration
20
+ * guide).
21
+ *
22
+ * Only while diagnostics are on (the checks' own rule); production builds never load this.
23
+ */
24
+ import {bridge, devReport, reportSafely, once, onReset, nameOf, isPlainObject} from './shared'
25
+ import {DEV_CODE_SEVERITY} from '../codes'
26
+ import {watchMutation} from './state'
27
+ import {checkRequest} from './replies'
28
+ import {check as checkFetch} from './fetch'
29
+ import {checkSentCommand} from './elementCommands'
30
+ import {checkCollection} from './collections'
31
+ import {eventEmitted, actionListener as recentActions} from './inspect'
32
+ import {actionHooks} from './actionLog'
33
+
34
+ const MIGRATE = 'https://sygnal.js.org/guide/migrating-to-6'
35
+
36
+ /** the removed forms (D162-D164) by migration-guide anchor: what it was, how to write it now */
37
+ export const REMOVED: Record<string, [what: string, fix: string]> = {
38
+ 'string-tags': ['a component named by a string tag (<Name /> as a string, looked up in .components)', 'Import the component and use it as a JSX tag: <Badge />'],
39
+ 'components': ['the .components registry', 'Import each component and use it as a JSX tag; remove .components'],
40
+ 'collection-of-name': ['<Collection of="Name"> (a name)', 'Pass the component itself: <Collection of={Item} from="items" />'],
41
+ 'collection-wrapper': ["the Collection's wrapper element (className, style, class, attrs, data-*, on, ref or hook on <Collection>)", 'Collection renders its items directly into its parent: put them on your own wrapping element, <ul className="x"><Collection of={Item} from="items" /></ul>'],
42
+ 'child-select-name': ["CHILD.select('Name') (a name)", 'Pass the component itself: CHILD.select(Item)'],
43
+ 'pipe-keys': ["'ACTION | SINK' model keys", "Use the object form: ACTION: { SINK: (state, data) => ... }"],
44
+ 'peers': ['.peers', 'Render the peer as a sibling in the parent view'],
45
+ 'hmractions': ['hmrActions', 'Remove hmrActions; sygnal/vite keeps the state across a hot update'],
46
+ 'positional-views': ['a view with positional parameters (props, state, context, peers)', 'Destructure the one argument: function C({ state, context, ...props })'],
47
+ 'source-names': ['DOMSourceName / stateSourceName', "Remove them: the sources are always DOM and STATE"],
48
+ 'storecalculatedinstate': ['storeCalculatedInState', 'Remove it: calculated fields are always part of the state the view and reducers get'],
49
+ 'component-factory': ['the component({ ... }) factory (with sources / isolateOpts)', 'Write a function component with statics (C.model, C.intent, C.initialState), or use defineComponent({ ... })'],
50
+ }
51
+
52
+ /** 4-H: the marker's props / data buckets the removed Collection wrapper element took */
53
+ const WRAPPER = ['className', 'style', 'class', 'attrs', 'dataset', 'on', 'hook']
54
+
55
+ const STATICS: Array<[string, string]> = [['components', 'components'], ['peers', 'peers'], ['hmrActions', 'hmractions'], ['DOMSourceName', 'source-names'], ['stateSourceName', 'source-names'], ['storeCalculatedInState', 'storecalculatedinstate']]
56
+
57
+ function removed(component: any, name: string, anchor: string, detail?: string): void {
58
+ if (!once(`SYG612:${name}:${anchor}`)) return
59
+ const [what, fix] = REMOVED[anchor]
60
+ devReport('SYG612', {
61
+ component: name,
62
+ message: `${name} uses ${what}${detail ? ` (${detail})` : ''}, which Sygnal 6.0 removed, so it is ignored or fails`,
63
+ fix: `${fix}. See ${MIGRATE}#${anchor}`,
64
+ data: {form: anchor, guide: `${MIGRATE}#${anchor}`, ...(detail ? {detail} : {})},
65
+ })
66
+ }
67
+
68
+ /** the removed forms a definition shows (statics, view arity, model keys), once per function */
69
+ let seenDefs = new WeakSet<object>()
70
+ // G-332: resetChecks() forgets them (as the once() dedupe)
71
+ onReset(() => { seenDefs = new WeakSet<object>() })
72
+ function removedStatics(f: any): void {
73
+ const view = f.view
74
+ if (!view || seenDefs.has(view)) return
75
+ seenDefs.add(view)
76
+ const name = f.name
77
+ if (view.isSygnalComponent) removed(f, name, 'component-factory')
78
+ for (const [k, anchor] of STATICS) if (view[k] !== undefined && !(k == 'components' && isPlainObject(view[k]) && !Object.keys(view[k]).length)) removed(f, name, anchor, k)
79
+ // G-343: a defineComponent() wrapper's own arity is 1; the view it calls is __sygnalView
80
+ const arity = typeof view == 'function' ? (view.__sygnalView || view).length : 0
81
+ if (arity > 1 && !view.__sygnalLazy && !view.isSygnalComponent) removed(f, name, 'positional-views', `${arity} parameters`)
82
+ const model = view.model
83
+ if (isPlainObject(model)) for (const k of Object.keys(model)) if (k.includes('|')) removed(f, name, 'pipe-keys', `'${k}'`)
84
+ }
85
+
86
+ /** string tags left in a rendered vnode (the core renders them as elements) */
87
+ function removedTags(f: any, v: any, depth = 0): void {
88
+ if (!v || typeof v != 'object' || depth > 300) return
89
+ const sel = v.sel
90
+ // G-329: a component name is PascalCase; an all-caps tag (h('SPAN'), h(el.tagName)) is an element
91
+ const tag = typeof sel == 'string' ? sel.split(/[.#]/)[0] : ''
92
+ if (/^[A-Z]/.test(tag) && /[a-z]/.test(tag) && !(v.data && v.data.c)) removed(f, f.name, 'string-tags', `<${tag}>`)
93
+ const kids = v.children
94
+ if (Array.isArray(kids)) for (const k of kids) removedTags(f, k, depth + 1)
95
+ }
96
+
97
+ /** the instance fields the checks read from today's Component instances */
98
+ class Facade {
99
+ _so: any
100
+ constructor(public __next: any) {}
101
+ get name() { return this.__next.name }
102
+ get view() { return this.__next.def.view }
103
+ get model() {
104
+ const m: Record<string, any> = {}
105
+ this.__next.def.handlers.forEach((hs: any[], a: string) => { const e: any = m[a] = {}; for (const [s, fn] of hs) e[s] = fn })
106
+ return m
107
+ }
108
+ get modelMap(): Record<string, string[]> {
109
+ const m: Record<string, string[]> = {}
110
+ this.__next.def.handlers.forEach((hs: any[], a: string) => { m[a] = hs.map(h => h[0]) })
111
+ // the built-in INITIALIZE (today's model map ends with it for every component)
112
+ if (!m.INITIALIZE) m.INITIALIZE = ['STATE']
113
+ return m
114
+ }
115
+ get sources() { return this._so || this.__next.sources }
116
+ get sourceNames() { return Object.keys(this.__next.sources) }
117
+ get stateSourceName() { return 'STATE' }
118
+ get DOMSourceName() { return 'DOM' }
119
+ get isSubComponent() { return !this.__next.isRoot }
120
+ get initialState() { return this.__next.def.initialState }
121
+ get currentState() { return this.__next.state }
122
+ get currentProps() { return this.__next.props }
123
+ get currentContext() { return this.__next.context }
124
+ get _componentNumber() { return this.__next.id }
125
+ get calculated() { return this.__next.def.view.calculated }
126
+ get _calculatedFieldNames() { return this.__next.def.calcNames }
127
+ get context() { return this.__next.def.view.context }
128
+ get _uses() { return Object.entries(this.__next.def.view.uses || {}) }
129
+ get _behaviorActions() { return this.__next.def.behaviorActions }
130
+ get intent$() { return {__sygnalTestActions: this.__next.def.testActions || []} }
131
+ get _disposed() { return this.__next.disposed }
132
+ /** the state already has its calculated fields */
133
+ addCalculated(s: any) { return s }
134
+ }
135
+
136
+ const facades = new WeakMap<object, Facade>()
137
+ const fac = (iv: any): Facade => {
138
+ let f = facades.get(iv)
139
+ if (!f) facades.set(iv, f = new Facade(iv))
140
+ return f
141
+ }
142
+
143
+ /** structural vnode equality (functions equal: a view may make new closures every call) */
144
+ function same(a: any, b: any, d = 0): boolean {
145
+ if (a === b || (typeof a == 'function' && typeof b == 'function')) return true
146
+ if (!a || !b || typeof a != 'object' || typeof b != 'object') return a !== a && b !== b
147
+ if (d > 300) return true
148
+ if (Array.isArray(a) != Array.isArray(b)) return false
149
+ const ka = Object.keys(a).filter(k => k != 'elm' && a[k] !== undefined), kb = Object.keys(b).filter(k => k != 'elm' && b[k] !== undefined)
150
+ if (ka.length != kb.length) return false
151
+ for (const k of ka) if (!same(a[k], b[k], d + 1)) return false
152
+ return true
153
+ }
154
+
155
+ const SAMPLE = 16, CAP = 20
156
+
157
+ /** a CSS identifier's start, then identifier characters (`<prefix>-<id>` is one when the prefix starts one) */
158
+ const IDENT = /^(--|-?[A-Za-z_\u0080-\uffff])[\w\u0080-\uffff-]*$/
159
+
160
+ /** G-419 SYG148: a Collection's viewTransitionName that is not a CSS identifier (true: a valid one) */
161
+ function vtPrefix(name: string, p: any): boolean {
162
+ if (typeof p == 'string' && IDENT.test(p)) return true
163
+ const shown = typeof p == 'string' ? JSON.stringify(p) : `{${typeof p}}`
164
+ if (once(`SYG148:${name}:${String(p)}`)) devReport('SYG148', {
165
+ component: name,
166
+ message: `A Collection in ${name} has viewTransitionName=${shown}, which is not a CSS identifier, so every item's view-transition-name (${typeof p == 'string' ? p : '<prefix>'}-<id>) is invalid CSS: the browser ignores it and nothing animates`,
167
+ fix: 'Use a CSS identifier as the prefix: letters, digits, - and _, not starting with a digit (viewTransitionName="card")',
168
+ data: {value: p},
169
+ })
170
+ return false
171
+ }
172
+
173
+ /**
174
+ * G-460: an element the browser renders (a View Transition captures only those): not in a
175
+ * display: none subtree (a hidden tab panel, a list shown only at another width). checkVisibility()
176
+ * where there is one; else (jsdom) no display: none on it or an ancestor
177
+ */
178
+ function rendered(el: any): boolean {
179
+ if (!el?.isConnected) return false
180
+ if (typeof el.checkVisibility == 'function') return el.checkVisibility()
181
+ const cs = el.ownerDocument?.defaultView?.getComputedStyle
182
+ for (let n = el; n && n.nodeType == 1; n = n.parentNode) if (n.hidden || cs?.(n).display == 'none') return false
183
+ return true
184
+ }
185
+
186
+ /**
187
+ * G-419 SYG149: two elements of the patched page with the same view-transition-name from
188
+ * Collections with the same prefix (the same id shown in two of them): the browser skips the
189
+ * whole View Transition. Walks the vnode tree (dev only, while a named Collection is mounted);
190
+ * G-460: a name found twice is checked on the DOM after the patch (a microtask later; when a View
191
+ * Transition defers the patch, again a little later): only rendered elements count. Returns the
192
+ * groups of vnodes with one name (none: an empty list)
193
+ */
194
+ function vtDuplicates(root: any, prefixes: Set<string>): any[][] {
195
+ const seen = new Map<string, any[]>(), dup: any[][] = []
196
+ const stack = [root]
197
+ while (stack.length) {
198
+ const v = stack.pop()
199
+ if (!v || typeof v != 'object') continue
200
+ const st = v.data?.style, n = st?.viewTransitionName
201
+ if (typeof n == 'string' && prefixes.has(st.viewTransitionClass)) {
202
+ const g = seen.get(n)
203
+ if (!g) seen.set(n, [v])
204
+ else if (g.push(v) == 2) dup.push(g)
205
+ }
206
+ if (Array.isArray(v.children)) for (let i = v.children.length; i--;) stack.push(v.children[i])
207
+ }
208
+ return dup
209
+ }
210
+
211
+ // G-538: a fragment root never gets an element (the DOM driver flattens it into the container):
212
+ // it has run when each of its children has one (a kept child has its old one: a View Transition
213
+ // patch of a fragment root whose children are all kept is checked before it runs)
214
+ const patched = (v: any): any => v.elm || !v.sel && v.children?.every((c: any) => !c || patched(c))
215
+
216
+ /**
217
+ * G-527: the patches waiting for their SYG149 check ([root vnode, duplicate groups], newest last,
218
+ * at most 8) and one chain of checks over them: a microtask after the first, then every 50 ms
219
+ * while some wait. The patch of a root has run when it has its element (a View Transition patches
220
+ * in its update callback, and replaces a held vnode it hasn't patched yet; kept vnodes have their
221
+ * old elements before that): each check takes the newest patch that ran and drops it and the older
222
+ * ones. A newer patch joins the queue and doesn't restart the chain, so patches closer than 50 ms
223
+ * (View Transitions back to back) can't starve it. A patch without duplicates joins only a queue
224
+ * that waits (once it has run, the older ones are moot). G-501: the chain stops once the app (or
225
+ * every named Collection) is gone, and after 10 tries without a patched root (the mock DOM; a root
226
+ * that never gets its element isn't checked on its children's old elements)
227
+ */
228
+ function vtChecker(live: () => any) {
229
+ let q: any[][] = [], busy = false, tries = 0
230
+ const vtRendered = (): void => {
231
+ if (!live()) { q = []; busy = false; return }
232
+ let i = q.length
233
+ while (i-- && !patched(q[i][0]));
234
+ if (i >= 0) { vtReport(q[i][1]); q = q.slice(i + 1); tries = 0 }
235
+ else tries++
236
+ if (!q.length || tries > 10) { q = []; busy = false; return }
237
+ setTimeout(vtRendered, 50)
238
+ }
239
+ return (root: any, dup: any[][]) => {
240
+ if (!dup.length && !q.length) return
241
+ q.push([root, dup])
242
+ if (q.length > 8) q.shift()
243
+ if (!busy) { busy = true; tries = 0; queueMicrotask(vtRendered) }
244
+ }
245
+ }
246
+
247
+ function vtReport(dup: any[][]): void {
248
+ for (const g of dup) {
249
+ const v = g[0], st = v.data.style, n = st.viewTransitionName
250
+ if (g.filter(x => rendered(x.elm)).length < 2 || !once(`SYG149:${n}`)) continue
251
+ devReport('SYG149', {
252
+ component: 'Collection',
253
+ message: `Two elements on the page have view-transition-name '${n}': Collections with viewTransitionName="${st.viewTransitionClass}" show the item with that id at the same time. Names must be unique when a View Transition starts, so the browser skips every transition while both are shown`,
254
+ fix: `Give Collections that can show the same item at once different prefixes (viewTransitionName="${st.viewTransitionClass}" and another), or name the item yourself with its own style`,
255
+ data: {name: n, prefix: st.viewTransitionClass},
256
+ })
257
+ }
258
+ }
259
+
260
+ /** The hooks one app gets (installChecks publishes this on the bridge). */
261
+ export function nextHooks(_api: any): any {
262
+ const core = bridge(), H = core.hooks
263
+ const on = () => H.on()
264
+ const modelOf = (f: Facade) => f.modelMap
265
+ const wired = new WeakSet<object>()
266
+ const wire = (iv: any, names: string[]) => {
267
+ const f = fac(iv)
268
+ if (wired.has(f)) return
269
+ wired.add(f)
270
+ H.onIntent(f, names)
271
+ H.onModel(f, modelOf(f))
272
+ }
273
+ // D168: the views context tracking skipped, checked on a sample (each instance's first two
274
+ // skips, then 1 in 16; at most CAP per tick)
275
+ const skips = new WeakMap<object, number>()
276
+ let budget = 0
277
+ const log = actionHooks(recentActions, () => on())
278
+ // G-419: the viewTransitionName prefixes this app's Collections use; G-460: per instance that
279
+ // renders them, so the SYG149 walk stops once every one of them is disposed
280
+ const vtp = new Map<any, Set<string>>()
281
+ // G-527: one chain of SYG149 checks over the latest patches (G-501: it stops once every instance
282
+ // that renders a named Collection is disposed, the app's dispose included)
283
+ const vtCheck = vtChecker(() => vtp.size && on())
284
+ return {
285
+ onCreate(iv: any) {
286
+ if (!on()) return
287
+ log.onCreate(iv)
288
+ const f = fac(iv)
289
+ removedStatics(f)
290
+ if (!iv.def.intent) wire(iv, [])
291
+ },
292
+ wrapSources(iv: any, so: any) {
293
+ const f = fac(iv)
294
+ f._so = so
295
+ let out
296
+ try { out = H.sourcesFor(f) } finally { f._so = undefined }
297
+ if (!on() || typeof Proxy != 'function') return out
298
+ // D173: CHILD.select('Name')
299
+ const s = out || so
300
+ return new Proxy(s, {
301
+ get(t: any, k: any) {
302
+ const v = t[k]
303
+ if (k !== 'CHILD' || !v || typeof v.select != 'function') return v
304
+ return {...v, select: (x: any, ...r: any[]) => { if (typeof x == 'string') removed(f, f.name, 'child-select-name', `CHILD.select('${x}')`); return v.select(x, ...r) }}
305
+ },
306
+ })
307
+ },
308
+ onIntent(iv: any, names: string[]) {
309
+ wire(iv, names)
310
+ },
311
+ onRender(iv: any, vnode: any) {
312
+ const f = fac(iv)
313
+ H.onRender(f, vnode)
314
+ if (on()) removedTags(f, vnode)
315
+ },
316
+ onReducer(iv: any, type: string, prev: any, next: any) {
317
+ H.onReducer(fac(iv), type, prev, next, 'STATE')
318
+ },
319
+ onDispose(iv: any) {
320
+ vtp.delete(iv)
321
+ H.onDispose(fac(iv))
322
+ },
323
+ onAction(iv: any, a: any) { log.onAction(iv, a) },
324
+ wrapHandler(iv: any, type: string, sink: string, fn: any) {
325
+ let h = log.wrapHandler(iv, type, sink, fn) || fn
326
+ // SYG222: the STATE reducers, wrapped (today the check rewrote the instance's model)
327
+ if (on() && sink == 'STATE' && typeof fn == 'function') h = watchMutation(fac(iv), type, h)
328
+ return h === fn ? undefined : h
329
+ },
330
+ onSink(iv: any, type: string | null, sink: string, v: any) {
331
+ if (!on()) return
332
+ const f = fac(iv), src = iv.sources[sink]
333
+ try {
334
+ if (sink == 'EVENTS') eventEmitted(f, v)
335
+ if (src && src.__sygnalReplies === true) checkRequest(f, sink, v, Object.keys(f.modelMap))
336
+ if (src && src.__sygnalStatic === 'resources') checkFetch(f, sink, v)
337
+ } catch (_) { /* a check never breaks the app */ }
338
+ },
339
+ onElementCommand(iv: any, cmd: any) {
340
+ if (!on()) return
341
+ const f = fac(iv)
342
+ for (const c of ([] as any[]).concat(cmd)) checkSentCommand(f, c)
343
+ },
344
+ onHostProps(owner: any, sel: string, props: any, data?: any) {
345
+ if (!on() || (sel != 'collection' && sel != 'virtual-collection')) return
346
+ const f = fac(owner)
347
+ if (typeof props.of == 'string') removed(f, f.name, 'collection-of-name', `of="${props.of}"`)
348
+ // 4-H (D229): what went only to the removed wrapper div (VirtualCollection keeps its container)
349
+ if (sel == 'collection') {
350
+ const w = WRAPPER.filter(k => k == 'className' ? props.className != null : data?.[k] != null)
351
+ if (w.length) removed(f, f.name, 'collection-wrapper', w.map(k => k == 'dataset' ? 'data-*' : k == 'hook' ? 'ref / hook' : k).join(', '))
352
+ }
353
+ try { checkCollection(f, {data: {props}}) } catch (_) { /* ignore */ }
354
+ // G-419: SYG148 for a prefix that isn't an identifier; a valid one is checked for
355
+ // duplicate names after each patch (SYG149). G-460: a falsy one names nothing (as the host)
356
+ const p = props.viewTransitionName
357
+ if (p && vtPrefix(f.name, p)) {
358
+ let s = vtp.get(owner)
359
+ if (!s) vtp.set(owner, s = new Set())
360
+ s.add(p)
361
+ }
362
+ },
363
+ onPatch(vnode: any) {
364
+ if (!vtp.size || !on()) return
365
+ const all = new Set<string>()
366
+ for (const s of vtp.values()) for (const p of s) all.add(p)
367
+ try { vtCheck(vnode, vtDuplicates(vnode, all)) } catch (_) { /* a check never breaks the app */ }
368
+ },
369
+ onDuplicateKey(owner: any, key: any) {
370
+ if (!on()) return
371
+ const name = owner.name
372
+ if (!once(`SYG424:${name}:${String(key)}`)) return
373
+ devReport('SYG424', {
374
+ component: name,
375
+ message: `A Collection in ${name} has more than one item with the id ${JSON.stringify(key) ?? String(key)} (duplicate ids); only the first of them renders, and their writes go to it`,
376
+ fix: 'Give every item a unique id (or no id: an item without one is keyed by its index)',
377
+ data: {id: key},
378
+ })
379
+ },
380
+ onStateSeed(iv: any, slice: any, init: any) {
381
+ if (!on() || !isPlainObject(init) || !isPlainObject(slice)) return
382
+ // G-333: a key initialState sets to undefined is no data the slice lacks
383
+ const missing = Object.keys(init).filter(k => init[k] !== undefined && !(k in slice))
384
+ const name = iv.name
385
+ if (!missing.length || !once(`SYG425:${name}:${missing.join(',')}`)) return
386
+ const list = missing.map(k => `'${k}'`).join(', ')
387
+ devReport('SYG425', {
388
+ component: name,
389
+ message: `${name} has isolatedState and is bound to a slice of its parent's state that already exists, so it keeps that slice instead of its initialState; the slice has no ${list}, which ${name}.initialState defines`,
390
+ fix: `To start ${name} from its initialState instead, add resetState to the tag (<${name} state="..." resetState />). To keep the parent's data, initialize ${list} in the parent's state`,
391
+ data: {missing, slice: Object.keys(slice)},
392
+ })
393
+ },
394
+ onContextSkip(iv: any, render: (c: any) => any, prev: any, next: any, keys: string[]) {
395
+ if (!on() || !prev || !next) return
396
+ const n = (skips.get(iv) || 0) + 1
397
+ skips.set(iv, n)
398
+ if ((n > 2 && n % SAMPLE) || budget >= CAP) return
399
+ if (!budget++) queueMicrotask(() => { budget = 0 })
400
+ let a, b, c
401
+ try { a = render(prev); b = render(next); c = render(prev) } catch (_) { return }
402
+ // G-327: a control render: a view whose output differs between two calls with the same
403
+ // context (a render counter, Date.now(), Math.random(), generated ids) proves nothing
404
+ if (same(a, b) || !same(a, c)) return
405
+ const name = iv.name
406
+ const changed = Object.keys(next).filter(k => next[k] !== prev[k])
407
+ if (!once(`SYG423:${name}`)) return
408
+ reportSafely('SYG423', {
409
+ severity: DEV_CODE_SEVERITY.SYG423,
410
+ component: name,
411
+ message: `The context keys ${changed.map(k => `'${k}'`).join(', ')} changed and ${name}'s view was not re-rendered, because the view read none of them during its last call (it read: ${keys.length ? keys.map(k => `'${k}'`).join(', ') : 'nothing'}). Calling it with the new context renders something else, so the page shows a stale render`,
412
+ fix: `Read context entries in the view itself (context.theme), not through a value kept from an earlier render or a function that runs later; Object.getOwnPropertyDescriptor and similar reflection aren't tracked`,
413
+ data: {keysRead: keys, changed},
414
+ })
415
+ },
416
+ }
417
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * PLAN-4 GS-5: persist() checks (dev entry only; sygnal-check reports both statically).
3
+ *
4
+ * SYG224 (error) — a `persist` static on a component that isn't the root: the core only sets it
5
+ * up on the root (the one run() or renderComponent() is given), so nothing is saved
6
+ * or restored. Under Vike's Layout/Wrapper shell (the `__vike` source) the message says
7
+ * persist isn't supported on Vike pages, layouts or wrappers yet.
8
+ * SYG223 (warn) — a `pick` / `omit` key of persist() that isn't a key of the component's
9
+ * `initialState` static (a typo: that key is never saved, or never left out).
10
+ * Once per component name. Mechanism: onModel reads the static `view.persist` (the persist()
11
+ * value carries its options) and `view.initialState`.
12
+ */
13
+ import type {DiagnosticCheck} from '../index'
14
+ import {devReport, nameOf, once, didYouMean} from './shared'
15
+
16
+ export const persistCheck: DiagnosticCheck = {
17
+ id: 'persist',
18
+
19
+ onModel(component) {
20
+ const view = component?.view, p = view?.persist
21
+ if (!p) return
22
+ const name = nameOf(component)
23
+ if (component.isSubComponent) {
24
+ // 3-B2: under Vike's Layout/Wrapper shell (onRenderClient's `__vike` source) the Page,
25
+ // Layouts and Wrappers are all sub-components of the shell root
26
+ const vike = component.sources?.__vike
27
+ if (once('SYG224:' + name)) devReport('SYG224', {
28
+ component,
29
+ message: vike
30
+ ? `${name}.persist is set, but ${name} renders in Vike's Layout/Wrapper shell (the shell is the app's root), so its state is never saved or restored: persist() isn't supported on Vike pages, layouts or wrappers yet`
31
+ : `${name}.persist is set, but ${name} is not the root component, so its state is never saved or restored (persist() works on the root only)`,
32
+ fix: vike
33
+ ? `Remove persist from ${name}. Save the state yourself (STATE.watch writing to localStorage, read back in BOOTSTRAP), or use persist() on a component you run() yourself, or on a Vike page with no Layout or Wrapper (it is its own root)`
34
+ : `Move persist to the root component (the one passed to run()) and pick the keys it holds: persist({ key, pick: ['${name.toLowerCase()}'] })`,
35
+ data: {key: p.options?.key, ...(vike && {vike: true})},
36
+ })
37
+ return
38
+ }
39
+ const o = p.options, init = view.initialState
40
+ if (!o || !init || typeof init != 'object') return
41
+ const keys = Object.keys(init)
42
+ for (const opt of ['pick', 'omit']) {
43
+ for (const k of Array.isArray(o[opt]) ? o[opt] : []) {
44
+ if (keys.includes(k) || !once(`SYG223:${name}:${opt}:${k}`)) continue
45
+ devReport('SYG223', {
46
+ component,
47
+ message: `persist ${opt} names '${k}', which is not a key of ${name}.initialState, so it is ${opt == 'pick' ? 'never saved' : 'never left out'}${didYouMean(k, keys)}`,
48
+ fix: `Use top-level keys of initialState in ${opt} (${keys.join(', ')}), or add '${k}' to initialState`,
49
+ data: {option: opt, key: k, stateKeys: keys},
50
+ })
51
+ }
52
+ }
53
+ },
54
+ }
@@ -1,7 +1,8 @@
1
1
  /**
2
- * SYG106 — a prop passed by the parent is silently overwritten (warn).
2
+ * SYG106 — a prop passed by the parent is silently overwritten (warn; error in
3
+ * strict mode, G-007 part 2).
3
4
  *
4
- * The view is called with { ...props, state, children, slots, context, peers },
5
+ * The view is called with { ...props, state, children, slots, context, uid },
5
6
  * so a parent prop with one of those names never reaches the child. (Tracker
6
7
  * G-007 item 2.) `state` is special: Sygnal reads it as the child's state
7
8
  * lens (a state field name or a { get, set } object), so it is only reported
@@ -12,8 +13,11 @@
12
13
  */
13
14
  import type {DiagnosticCheck} from '../index'
14
15
  import {report, once, nameOf} from './shared'
16
+ import {isStrictEnabled} from './strict'
15
17
 
16
- const RESERVED = ['children', 'slots', 'context', 'peers']
18
+ // PLAN-4 GS-9: uid (the view's uid(name?) function)
19
+ // (R5: 6.0 passes no `peers`, D164: a prop of that name reaches the view)
20
+ const RESERVED = ['children', 'slots', 'context', 'uid']
17
21
 
18
22
  export const propsCheck: DiagnosticCheck = {
19
23
  id: 'props',
@@ -22,12 +26,13 @@ export const propsCheck: DiagnosticCheck = {
22
26
  const props = component && component.currentProps
23
27
  if (!props || typeof props !== 'object') return
24
28
  const name = nameOf(component)
29
+ const severity = isStrictEnabled() ? 'error' : 'warn'
25
30
 
26
31
  for (const key of RESERVED) {
27
32
  if (!(key in props) || !once(`SYG106:${name}:${key}`)) continue
28
33
  report('SYG106', {
29
34
  component,
30
- severity: 'warn',
35
+ severity,
31
36
  message: `The prop '${key}' passed to ${name} is overwritten: '${key}' is a reserved view argument, so the child never sees the parent's value`,
32
37
  fix: `Rename the prop (for example '${key}Value'), in the parent and in ${name}`,
33
38
  data: {prop: key},
@@ -40,7 +45,7 @@ export const propsCheck: DiagnosticCheck = {
40
45
  if (!isLens && value !== undefined && once(`SYG106:${name}:state`)) {
41
46
  report('SYG106', {
42
47
  component,
43
- severity: 'warn',
48
+ severity,
44
49
  message: `The prop 'state' passed to ${name} is not data: Sygnal reads it as the child's state lens (a state field name or a { get, set } object), and the view's 'state' argument is the child's own state`,
45
50
  fix: `To give ${name} a slice of the parent state use state="fieldName"; to pass data, use another prop name (for example 'item')`,
46
51
  data: {prop: 'state', valueType: typeof value},