sygnal 5.3.7 → 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.
- package/CHANGELOG.md +646 -0
- package/README.md +77 -47
- package/dist/astro/client.cjs.js +33 -8114
- package/dist/astro/client.cjs.js.map +1 -0
- package/dist/astro/client.mjs +33 -8114
- package/dist/astro/client.mjs.map +1 -0
- package/dist/astro/index.cjs.js +1039 -9
- package/dist/astro/index.cjs.js.map +1 -0
- package/dist/astro/index.mjs +1038 -9
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/server.cjs.js +3400 -166
- package/dist/astro/server.cjs.js.map +1 -0
- package/dist/astro/server.mjs +3400 -166
- package/dist/astro/server.mjs.map +1 -0
- package/dist/devtools.cjs.js +1431 -0
- package/dist/devtools.cjs.js.map +1 -0
- package/dist/devtools.esm.js +1419 -0
- package/dist/devtools.esm.js.map +1 -0
- package/dist/diagnostics.cjs.js +4033 -0
- package/dist/diagnostics.cjs.js.map +1 -0
- package/dist/diagnostics.esm.js +4003 -0
- package/dist/diagnostics.esm.js.map +1 -0
- package/dist/element.cjs.js +230 -0
- package/dist/element.cjs.js.map +1 -0
- package/dist/element.esm.js +228 -0
- package/dist/element.esm.js.map +1 -0
- package/dist/guide/accessibility.md +257 -0
- package/dist/guide/adapters.md +221 -0
- package/dist/guide/behaviors.md +312 -0
- package/dist/guide/browser-sources.md +203 -0
- package/dist/guide/drag-and-drop.md +342 -0
- package/dist/guide/element-commands.md +306 -0
- package/dist/guide/error-boundaries.md +169 -0
- package/dist/guide/forms-reference.md +381 -0
- package/dist/guide/forms.md +250 -0
- package/dist/guide/http.md +299 -0
- package/dist/guide/inputs.md +173 -0
- package/dist/guide/persistence.md +245 -0
- package/dist/guide/recipes/carousel.md +155 -0
- package/dist/guide/recipes/charts.md +177 -0
- package/dist/guide/recipes/code-editor.md +135 -0
- package/dist/guide/recipes/data-grid.md +155 -0
- package/dist/guide/recipes/data-table.md +196 -0
- package/dist/guide/recipes/i18n.md +222 -0
- package/dist/guide/recipes/icons.md +115 -0
- package/dist/guide/recipes/overview.md +33 -0
- package/dist/guide/recipes/rich-text.md +154 -0
- package/dist/guide/resources.md +471 -0
- package/dist/guide/ssr.md +255 -0
- package/dist/guide/timers.md +178 -0
- package/dist/guide/ui/accordion.md +93 -0
- package/dist/guide/ui/combobox.md +144 -0
- package/dist/guide/ui/dialog.md +124 -0
- package/dist/guide/ui/disclosure.md +60 -0
- package/dist/guide/ui/menu.md +125 -0
- package/dist/guide/ui/overview.md +166 -0
- package/dist/guide/ui/popover.md +101 -0
- package/dist/guide/ui/select.md +114 -0
- package/dist/guide/ui/tabs.md +161 -0
- package/dist/guide/ui/toaster.md +152 -0
- package/dist/guide/ui/tooltip.md +103 -0
- package/dist/guide/undo.md +178 -0
- package/dist/guide/virtual-collections.md +183 -0
- package/dist/guide/web-components.md +179 -0
- package/dist/guide/widgets.md +217 -0
- package/dist/index.cjs.js +15283 -6279
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +3739 -370
- package/dist/index.esm.js +15230 -6274
- package/dist/index.esm.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs.js +27 -329
- package/dist/jsx-dev-runtime.cjs.js.map +1 -0
- package/dist/jsx-dev-runtime.esm.js +20 -322
- package/dist/jsx-dev-runtime.esm.js.map +1 -0
- package/dist/jsx-runtime.cjs.js +27 -329
- package/dist/jsx-runtime.cjs.js.map +1 -0
- package/dist/jsx-runtime.esm.js +20 -322
- package/dist/jsx-runtime.esm.js.map +1 -0
- package/dist/jsx.cjs.js +11 -309
- package/dist/jsx.cjs.js.map +1 -0
- package/dist/jsx.esm.js +9 -310
- package/dist/jsx.esm.js.map +1 -0
- package/dist/react.cjs.js +117 -0
- package/dist/react.cjs.js.map +1 -0
- package/dist/react.esm.js +115 -0
- package/dist/react.esm.js.map +1 -0
- package/dist/shims/globalthis.cjs +20 -0
- package/dist/sygnal.min.js +2 -1
- package/dist/sygnal.min.js.map +1 -0
- package/dist/ui-combobox.cjs.js +169 -0
- package/dist/ui-combobox.cjs.js.map +1 -0
- package/dist/ui-combobox.esm.js +148 -0
- package/dist/ui-combobox.esm.js.map +1 -0
- package/dist/ui-menu.cjs.js +87 -0
- package/dist/ui-menu.cjs.js.map +1 -0
- package/dist/ui-menu.esm.js +66 -0
- package/dist/ui-menu.esm.js.map +1 -0
- package/dist/ui-select.cjs.js +104 -0
- package/dist/ui-select.cjs.js.map +1 -0
- package/dist/ui-select.esm.js +83 -0
- package/dist/ui-select.esm.js.map +1 -0
- package/dist/ui.cjs.js +738 -0
- package/dist/ui.cjs.js.map +1 -0
- package/dist/ui.esm.js +727 -0
- package/dist/ui.esm.js.map +1 -0
- package/dist/vike/ClientOnly.cjs.js +5 -14
- package/dist/vike/ClientOnly.cjs.js.map +1 -0
- package/dist/vike/ClientOnly.mjs +5 -14
- package/dist/vike/ClientOnly.mjs.map +1 -0
- package/dist/vike/{+config.js → config/+config.js} +10 -1
- package/dist/vike/config/+config.js.map +1 -0
- package/dist/vike/config/package.json +6 -0
- package/dist/vike/onRenderClient.cjs.js +166 -95
- package/dist/vike/onRenderClient.cjs.js.map +1 -0
- package/dist/vike/onRenderClient.mjs +166 -95
- package/dist/vike/onRenderClient.mjs.map +1 -0
- package/dist/vike/onRenderHtml.cjs.js +60 -24
- package/dist/vike/onRenderHtml.cjs.js.map +1 -0
- package/dist/vike/onRenderHtml.mjs +61 -25
- package/dist/vike/onRenderHtml.mjs.map +1 -0
- package/dist/vite/plugin.cjs.js +926 -65
- package/dist/vite/plugin.cjs.js.map +1 -0
- package/dist/vite/plugin.mjs +925 -65
- package/dist/vite/plugin.mjs.map +1 -0
- package/dist/zag.cjs.js +408 -0
- package/dist/zag.cjs.js.map +1 -0
- package/dist/zag.esm.js +405 -0
- package/dist/zag.esm.js.map +1 -0
- package/llms.txt +313 -0
- package/package.json +109 -16
- package/src/astro/client.ts +40 -18
- package/src/astro/index.d.ts +48 -1
- package/src/astro/index.ts +106 -9
- package/src/astro/server.ts +11 -3
- package/src/collection.ts +6 -90
- package/src/core/actions.ts +134 -0
- package/src/core/cell.ts +202 -0
- package/src/core/debug.ts +23 -0
- package/src/core/define.ts +242 -0
- package/src/core/hooks.ts +314 -0
- package/src/core/hosts/collection.ts +325 -0
- package/src/core/hosts/switchable.ts +146 -0
- package/src/core/instance.ts +592 -0
- package/src/core/markers/clientonly.ts +13 -0
- package/src/core/markers/lazy.ts +40 -0
- package/src/core/markers/portal.ts +96 -0
- package/src/core/markers/suspense.ts +41 -0
- package/src/core/markers/transition.ts +70 -0
- package/src/core/registry.ts +25 -0
- package/src/core/runtime.ts +573 -0
- package/src/core/statics.ts +104 -0
- package/src/core/teardown.ts +60 -0
- package/src/core/view.ts +37 -0
- package/src/cycle/dom/DocumentDOMSource.ts +13 -8
- package/src/cycle/dom/ElementFinder.ts +7 -9
- package/src/cycle/dom/EventDelegator.ts +174 -223
- package/src/cycle/dom/IsolateModule.ts +65 -35
- package/src/cycle/dom/MainDOMSource.ts +13 -2
- package/src/cycle/dom/PriorityQueue.ts +4 -2
- package/src/cycle/dom/SymbolTree.ts +18 -47
- package/src/cycle/dom/classNameModule.ts +76 -0
- package/src/cycle/dom/controlledInputModule.ts +50 -0
- package/src/cycle/dom/enrichEventStream.ts +29 -45
- package/src/cycle/dom/fragment.ts +7 -0
- package/src/cycle/dom/isolate.ts +30 -27
- package/src/cycle/dom/makeDOMDriver.ts +115 -57
- package/src/cycle/dom/mockDOMSource.ts +83 -9
- package/src/cycle/dom/modules.ts +21 -4
- package/src/cycle/dom/propsModule.ts +65 -0
- package/src/cycle/dom/selectModule.ts +22 -17
- package/src/cycle/dom/snabbdom.ts +1 -6
- package/src/cycle/dom/thunk.ts +3 -0
- package/src/cycle/dom/utils.ts +98 -0
- package/src/cycle/dom/viewTransition.ts +43 -0
- package/src/cycle/state/StateSource.ts +20 -4
- package/src/cycle/state/objIsEqual.ts +50 -0
- package/src/cycle/state/types.ts +0 -10
- package/src/defineComponent.ts +34 -0
- package/src/devtools.d.ts +151 -0
- package/src/devtools.ts +34 -0
- package/src/element.d.ts +59 -0
- package/src/element.ts +235 -0
- package/src/extra/backoff.ts +9 -0
- package/src/extra/behaviors.ts +169 -0
- package/src/extra/browserSignals.ts +23 -0
- package/src/extra/browserSources.ts +326 -0
- package/src/extra/command.ts +3 -3
- package/src/extra/controls.ts +47 -0
- package/src/extra/copyAsTest.ts +286 -0
- package/src/extra/devtools.ts +109 -31
- package/src/extra/devtoolsActions.ts +379 -0
- package/src/extra/devtoolsHook.ts +9 -0
- package/src/extra/devtoolsNext.ts +83 -0
- package/src/extra/diagnostics/checks/actionLog.ts +108 -0
- package/src/extra/diagnostics/checks/behaviors.ts +49 -0
- package/src/extra/diagnostics/checks/browserSources.ts +96 -0
- package/src/extra/diagnostics/checks/collections.ts +67 -0
- package/src/extra/diagnostics/checks/controls.ts +148 -0
- package/src/extra/diagnostics/checks/dataset.ts +57 -0
- package/src/extra/diagnostics/checks/dom.ts +250 -0
- package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
- package/src/extra/diagnostics/checks/events.ts +83 -0
- package/src/extra/diagnostics/checks/fetch.ts +135 -0
- package/src/extra/diagnostics/checks/forms.ts +163 -0
- package/src/extra/diagnostics/checks/index.ts +202 -0
- package/src/extra/diagnostics/checks/inspect.ts +427 -0
- package/src/extra/diagnostics/checks/next.ts +417 -0
- package/src/extra/diagnostics/checks/persist.ts +54 -0
- package/src/extra/diagnostics/checks/props.ts +56 -0
- package/src/extra/diagnostics/checks/public.d.ts +302 -0
- package/src/extra/diagnostics/checks/replies.ts +128 -0
- package/src/extra/diagnostics/checks/router.ts +100 -0
- package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
- package/src/extra/diagnostics/checks/shared.ts +203 -0
- package/src/extra/diagnostics/checks/shorthand.ts +115 -0
- package/src/extra/diagnostics/checks/sortable.ts +129 -0
- package/src/extra/diagnostics/checks/state.ts +148 -0
- package/src/extra/diagnostics/checks/statics.ts +48 -0
- package/src/extra/diagnostics/checks/strict.ts +55 -0
- package/src/extra/diagnostics/checks/timers.ts +80 -0
- package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
- package/src/extra/diagnostics/checks/virtual.ts +73 -0
- package/src/extra/diagnostics/checks/widgets.ts +109 -0
- package/src/extra/diagnostics/checks/wiring.ts +121 -0
- package/src/extra/diagnostics/codes.ts +477 -0
- package/src/extra/diagnostics/index.ts +353 -0
- package/src/extra/diagnostics/legacy.ts +76 -0
- package/src/extra/driverFactories.ts +172 -60
- package/src/extra/elementCommands.ts +53 -0
- package/src/extra/eventDriver.ts +4 -0
- package/src/extra/fetchDriver.ts +519 -0
- package/src/extra/flatten.ts +75 -0
- package/src/extra/focusWithin.ts +27 -0
- package/src/extra/form.ts +268 -0
- package/src/extra/formHelpers.ts +139 -0
- package/src/extra/head.ts +106 -0
- package/src/extra/hmr.ts +2 -3
- package/src/extra/owned.ts +24 -0
- package/src/extra/pager.ts +50 -0
- package/src/extra/persist.ts +133 -0
- package/src/extra/pwa.ts +1 -1
- package/src/extra/queryCache.ts +107 -0
- package/src/extra/reducers.ts +13 -6
- package/src/extra/reduxDevtools.ts +92 -0
- package/src/extra/replies.ts +54 -0
- package/src/extra/router.ts +323 -0
- package/src/extra/run.ts +94 -210
- package/src/extra/selection.ts +76 -0
- package/src/extra/socketDriver.ts +265 -0
- package/src/extra/sortable.ts +377 -0
- package/src/extra/ssr.ts +427 -160
- package/src/extra/standardSchema.ts +27 -0
- package/src/extra/testing.ts +3158 -190
- package/src/extra/timers.ts +95 -0
- package/src/extra/undo.ts +261 -0
- package/src/extra/viewTransitions.ts +38 -0
- package/src/extra/virtual.ts +513 -0
- package/src/extra/widget.ts +201 -0
- package/src/extra/xstreamExtras.ts +269 -0
- package/src/index.d.ts +3012 -87
- package/src/index.ts +32 -10
- package/src/jsx-runtime.ts +15 -1
- package/src/jsx.ts +2 -1
- package/src/lazy.ts +50 -7
- package/src/portal.ts +3 -1
- package/src/pragma/index.ts +262 -134
- package/src/react-peers.d.ts +5 -0
- package/src/react.d.ts +43 -0
- package/src/react.ts +110 -0
- package/src/shared.ts +48 -0
- package/src/slot.ts +1 -1
- package/src/suspense.ts +3 -1
- package/src/switchable.ts +6 -119
- package/src/transition.ts +3 -1
- package/src/ui/accordion.ts +64 -0
- package/src/ui/dialog.ts +129 -0
- package/src/ui/disclosure.ts +35 -0
- package/src/ui/popover.ts +45 -0
- package/src/ui/shared.ts +94 -0
- package/src/ui/tabs.ts +82 -0
- package/src/ui/toaster.ts +198 -0
- package/src/ui/tooltip.ts +70 -0
- package/src/ui/zag/combobox.ts +115 -0
- package/src/ui/zag/menu.ts +40 -0
- package/src/ui/zag/select.ts +54 -0
- package/src/ui/zag/shared.ts +43 -0
- package/src/ui-combobox.d.ts +20 -0
- package/src/ui-combobox.ts +6 -0
- package/src/ui-menu.d.ts +30 -0
- package/src/ui-menu.ts +6 -0
- package/src/ui-select.d.ts +17 -0
- package/src/ui-select.ts +6 -0
- package/src/ui-zag-types.d.ts +42 -0
- package/src/ui.d.ts +208 -0
- package/src/ui.ts +15 -0
- package/src/vike/+config.ts +9 -1
- package/src/vike/ClientOnly.ts +1 -1
- package/src/vike/onRenderClient.ts +144 -96
- package/src/vike/onRenderHtml.ts +69 -26
- package/src/vike/types.ts +27 -4
- package/src/vite/globalthis-shim.ts +18 -0
- package/src/vite/globalthis.ts +56 -0
- package/src/vite/plugin.d.ts +114 -2
- package/src/vite/plugin.ts +920 -56
- package/src/zag.d.ts +64 -0
- package/src/zag.ts +238 -0
- package/dist/astro/astro/client.d.ts +0 -5
- package/dist/astro/astro/index.d.ts +0 -16
- package/dist/astro/astro/server.d.ts +0 -12
- package/dist/astro/client.d.ts +0 -5
- package/dist/astro/client.esm.js +0 -4665
- package/dist/astro/collection.d.ts +0 -12
- package/dist/astro/component.d.ts +0 -22
- package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/astro/cycle/dom/index.d.ts +0 -8
- package/dist/astro/cycle/dom/isolate.d.ts +0 -9
- package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/astro/cycle/dom/modules.d.ts +0 -5
- package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
- package/dist/astro/cycle/dom/thunk.d.ts +0 -11
- package/dist/astro/cycle/dom/utils.d.ts +0 -8
- package/dist/astro/cycle/isolate/index.d.ts +0 -42
- package/dist/astro/cycle/run/adapt.d.ts +0 -6
- package/dist/astro/cycle/run/index.d.ts +0 -36
- package/dist/astro/cycle/run/internals.d.ts +0 -8
- package/dist/astro/cycle/run/types.d.ts +0 -49
- package/dist/astro/cycle/state/Collection.d.ts +0 -29
- package/dist/astro/cycle/state/StateSource.d.ts +0 -20
- package/dist/astro/cycle/state/index.d.ts +0 -5
- package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
- package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
- package/dist/astro/cycle/state/types.d.ts +0 -18
- package/dist/astro/cycle/state/withState.d.ts +0 -17
- package/dist/astro/extra/classes.d.ts +0 -7
- package/dist/astro/extra/devtools.d.ts +0 -78
- package/dist/astro/extra/dragDriver.d.ts +0 -20
- package/dist/astro/extra/driverFactories.d.ts +0 -12
- package/dist/astro/extra/eventDriver.d.ts +0 -9
- package/dist/astro/extra/exactState.d.ts +0 -1
- package/dist/astro/extra/hmr.d.ts +0 -17
- package/dist/astro/extra/logDriver.d.ts +0 -2
- package/dist/astro/extra/processDrag.d.ts +0 -19
- package/dist/astro/extra/processForm.d.ts +0 -15
- package/dist/astro/extra/run.d.ts +0 -13
- package/dist/astro/extra/xstreamCompat.d.ts +0 -5
- package/dist/astro/index.d.ts +0 -19
- package/dist/astro/index.esm.js +0 -27
- package/dist/astro/jsx-dev-runtime.d.ts +0 -1
- package/dist/astro/jsx-runtime.d.ts +0 -4
- package/dist/astro/jsx.d.ts +0 -2
- package/dist/astro/pragma/fn.d.ts +0 -7
- package/dist/astro/pragma/index.d.ts +0 -7
- package/dist/astro/pragma/is.d.ts +0 -10
- package/dist/astro/server.d.ts +0 -12
- package/dist/astro/server.esm.js +0 -25
- package/dist/astro/switchable.d.ts +0 -7
- package/dist/collection.d.ts +0 -12
- package/dist/component.d.ts +0 -22
- package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/cycle/dom/index.d.ts +0 -8
- package/dist/cycle/dom/isolate.d.ts +0 -9
- package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/cycle/dom/modules.d.ts +0 -5
- package/dist/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/cycle/dom/styleModule.d.ts +0 -13
- package/dist/cycle/dom/thunk.d.ts +0 -11
- package/dist/cycle/dom/utils.d.ts +0 -8
- package/dist/cycle/isolate/index.d.ts +0 -42
- package/dist/cycle/run/adapt.d.ts +0 -6
- package/dist/cycle/run/index.d.ts +0 -36
- package/dist/cycle/run/internals.d.ts +0 -8
- package/dist/cycle/run/types.d.ts +0 -49
- package/dist/cycle/state/Collection.d.ts +0 -29
- package/dist/cycle/state/StateSource.d.ts +0 -20
- package/dist/cycle/state/index.d.ts +0 -5
- package/dist/cycle/state/pickCombine.d.ts +0 -3
- package/dist/cycle/state/pickMerge.d.ts +0 -3
- package/dist/cycle/state/types.d.ts +0 -18
- package/dist/cycle/state/withState.d.ts +0 -17
- package/dist/extra/classes.d.ts +0 -7
- package/dist/extra/devtools.d.ts +0 -78
- package/dist/extra/dragDriver.d.ts +0 -20
- package/dist/extra/driverFactories.d.ts +0 -12
- package/dist/extra/eventDriver.d.ts +0 -9
- package/dist/extra/exactState.d.ts +0 -1
- package/dist/extra/hmr.d.ts +0 -17
- package/dist/extra/logDriver.d.ts +0 -2
- package/dist/extra/processDrag.d.ts +0 -19
- package/dist/extra/processForm.d.ts +0 -15
- package/dist/extra/run.d.ts +0 -13
- package/dist/extra/xstreamCompat.d.ts +0 -5
- package/dist/jsx-dev-runtime.d.ts +0 -1
- package/dist/jsx-dev-runtime.js +0 -224
- package/dist/jsx-runtime.d.ts +0 -4
- package/dist/jsx-runtime.js +0 -224
- package/dist/jsx.d.ts +0 -2
- package/dist/pragma/fn.d.ts +0 -7
- package/dist/pragma/index.d.ts +0 -7
- package/dist/pragma/is.d.ts +0 -10
- package/dist/switchable.d.ts +0 -7
- package/dist/vike/+config.cjs.js +0 -65
- package/src/component.ts +0 -2256
- package/src/cycle/isolate/index.ts +0 -196
- package/src/cycle/run/index.ts +0 -151
- package/src/cycle/run/internals.ts +0 -143
- package/src/cycle/state/Collection.ts +0 -174
- package/src/cycle/state/index.ts +0 -5
- package/src/cycle/state/pickCombine.ts +0 -167
- package/src/cycle/state/pickMerge.ts +0 -122
- package/src/cycle/state/withState.ts +0 -47
- package/src/pragma/fn.ts +0 -55
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 'sygnal/diagnostics' — runtime consistency checks (PLAN-1 workstream 1A).
|
|
3
|
+
*
|
|
4
|
+
* import 'sygnal/diagnostics'
|
|
5
|
+
*
|
|
6
|
+
* Importing this entry registers every check with the diagnostics core of the
|
|
7
|
+
* 'sygnal' package (a side-effect import) and installs the RxJS-operator hints.
|
|
8
|
+
* Checks only run while diagnostics are on (run(App, drivers, { diagnostics }),
|
|
9
|
+
* or globalThis.__SYGNAL_DEV__ from the Vite plugin in dev). None of this code
|
|
10
|
+
* is in the main 'sygnal' bundle.
|
|
11
|
+
*
|
|
12
|
+
* | Code | Check | Module |
|
|
13
|
+
* |--------|--------------------------------------------------------|----------------|
|
|
14
|
+
* | SYG101 | intent action has no model entry | wiring.ts |
|
|
15
|
+
* | SYG102 | model entry has no intent trigger (info) | wiring.ts |
|
|
16
|
+
* | SYG103 | intent selector never matched (info -> warn) | dom.ts |
|
|
17
|
+
* | SYG104 | intent selector only matches inside a child component | dom.ts |
|
|
18
|
+
* | SYG105 | EVENTS type emitted-not-selected / selected-not-emitted| events.ts |
|
|
19
|
+
* | SYG106 | parent prop overwritten by a reserved view argument | props.ts |
|
|
20
|
+
* | SYG112 | reply action has no model entry | replies.ts |
|
|
21
|
+
* | SYG630 | cached request that isn't idempotent (POST + cache) | fetch.ts |
|
|
22
|
+
* | SYG631 | validate is not a Standard Schema | fetch.ts |
|
|
23
|
+
* | SYG632 | invalidate matched nothing (info) | fetch.ts |
|
|
24
|
+
* | SYG633 | abort names a lane its requests don't use | fetch.ts |
|
|
25
|
+
* | SYG635 | cache: true / staleTime / prefetch without queryCache() | fetch.ts |
|
|
26
|
+
* | SYG115 | unknown DOM event shorthand (DOM.key(...)) | shorthand.ts |
|
|
27
|
+
* | SYG124 | component where a control or selector is expected | controls.ts |
|
|
28
|
+
* | SYG140 | widget emitted an event it doesn't declare | widgets.ts |
|
|
29
|
+
* | SYG142 | widget command not declared (also a reserved name) | elementCommands.ts, widgets.ts |
|
|
30
|
+
* | SYG143 | widget tag used as a selector | widgets.ts |
|
|
31
|
+
* | SYG144 | declared widget event the host also fires (info) | widgets.ts |
|
|
32
|
+
* | SYG660 | widget mount / update / unmount threw (660/661/662) | widgets.ts |
|
|
33
|
+
* | SYG430 | VirtualCollection: no bounded height; SYG431 items without ids; SYG432 item not one element; SYG433 scroll target not in the list; SYG434 bad estimateSize / overscan | virtual.ts |
|
|
34
|
+
* | SYG125 | control given component statics / bad spec vnode() | controls.ts |
|
|
35
|
+
* | SYG127 | behavior key in initialState / unresolvable uses entry | behaviors.ts |
|
|
36
|
+
* | SYG230 | form: field name not in values; SYG231 not a Standard Schema; SYG232 submit dropped (info); SYG233 value missing from the schema output | forms.ts |
|
|
37
|
+
* | SYG234 | form submit action has no model entry; SYG235 check names an unknown field / sets reply fields; SYG236 rows without an id | forms.ts |
|
|
38
|
+
* | SYG145 | sortable: item without its id attribute; SYG146 item / handle selector matches nothing; SYG147 from is not an array | sortable.ts |
|
|
39
|
+
* | SYG116 | EVENTS value with no string type (a function) | events.ts |
|
|
40
|
+
* | SYG130 | href() names no route / leaves out a param | router.ts |
|
|
41
|
+
* | SYG131 | route params the pattern doesn't use | router.ts |
|
|
42
|
+
* | SYG132 | declaration static never sent: a root without initialState | router.ts |
|
|
43
|
+
* | SYG133 | SPA router inside a Vike app | router.ts |
|
|
44
|
+
* | SYG422 | timer spec makeTimerDriver() can't run | timers.ts |
|
|
45
|
+
* | SYG643 | timers/connections/resources/browser with no driver | timers.ts |
|
|
46
|
+
* | SYG663 | browser entry / BROWSER command that can't run | browserSources.ts |
|
|
47
|
+
* | SYG664 | browser source the driver wasn't made with | browserSources.ts |
|
|
48
|
+
* | SYG665 | browser source failed with no error action | browserSources.ts |
|
|
49
|
+
* | SYG668 | intersection / resize with no element to observe | browserSources.ts |
|
|
50
|
+
* | SYG238 | a root with a model but no initialState: renders nothing | state.ts |
|
|
51
|
+
* | SYG223 | persist pick/omit key not in initialState | persist.ts |
|
|
52
|
+
* | SYG224 | persist on a component that isn't the root | persist.ts |
|
|
53
|
+
* | SYG645 | viewTransitions without makeViewTransitionDOMDriver(), or not an array | viewTransitions.ts |
|
|
54
|
+
* | SYG201 | STATE reducer dropped keys | state.ts |
|
|
55
|
+
* | SYG202 | STATE reducer returned undefined | state.ts |
|
|
56
|
+
* | SYG221 | set() called with a string | state.ts |
|
|
57
|
+
* | SYG222 | same object returned after an in-place mutation | state.ts |
|
|
58
|
+
* | SYG301 | RxJS operator used on an xstream stream | rxjsHints.ts |
|
|
59
|
+
* | SYG401 | Collection `from` missing or not an array | collections.ts |
|
|
60
|
+
* | SYG421 | invalid data (dataset) key in a view | dataset.ts |
|
|
61
|
+
* | SYG612 | a form 6.0 removed (also SYG501/504 statically) | next.ts |
|
|
62
|
+
* | SYG502 | retired in 6.0 (never reported; GS-4) | — |
|
|
63
|
+
* | SYG508 | strict: select()/errors() round trip on a reply source | replies.ts |
|
|
64
|
+
* | — | D152: shared statics frozen (initialState deep) | statics.ts |
|
|
65
|
+
* | — | inspect(): the runtime app graph (2B) | inspect.ts |
|
|
66
|
+
*
|
|
67
|
+
* SYG112, SYG130-133 (PLAN-3), SYG115/116/221/421 (G-143) SYG124/125 (PLAN-4 CT-1) and SYG127 (GS-1) are dev-entry-only codes: their severities live in
|
|
68
|
+
* DEV_CODE_SEVERITY (codes.ts), registered by ./shared, not in the main bundle.
|
|
69
|
+
*
|
|
70
|
+
* Strict checks (SYG5xx) only report after configureStrict(true) (or
|
|
71
|
+
* renderComponent(C, { strict: true }), or globalThis.__SYGNAL_STRICT__).
|
|
72
|
+
*/
|
|
73
|
+
import type {DiagnosticCheck} from '../index'
|
|
74
|
+
import {Stream} from '../../xstreamCompat'
|
|
75
|
+
import {bridge, resetCheckState, timing} from './shared'
|
|
76
|
+
import {wiringCheck} from './wiring'
|
|
77
|
+
import {stateCheck} from './state'
|
|
78
|
+
import {eventsCheck} from './events'
|
|
79
|
+
import {propsCheck} from './props'
|
|
80
|
+
import {collectionsCheck} from './collections'
|
|
81
|
+
import {domCheck} from './dom'
|
|
82
|
+
import {shorthandCheck} from './shorthand'
|
|
83
|
+
import {controlsCheck, installControlHooks} from './controls'
|
|
84
|
+
import {elementCommandsCheck, installElementCommandHooks} from './elementCommands'
|
|
85
|
+
import {installWidgetHooks} from './widgets'
|
|
86
|
+
import {installVirtualHooks} from './virtual'
|
|
87
|
+
import {behaviorsCheck} from './behaviors'
|
|
88
|
+
import {formsCheck, installFormHooks} from './forms'
|
|
89
|
+
import {installSortableHooks} from './sortable'
|
|
90
|
+
import {datasetCheck} from './dataset'
|
|
91
|
+
import {strictCheck} from './strict'
|
|
92
|
+
import {repliesCheck} from './replies'
|
|
93
|
+
import {routerCheck, installRouterHooks} from './router'
|
|
94
|
+
import {fetchCheck} from './fetch'
|
|
95
|
+
import {timersCheck, installTimerHooks} from './timers'
|
|
96
|
+
import {installBrowserSourceHooks} from './browserSources'
|
|
97
|
+
import {persistCheck} from './persist'
|
|
98
|
+
import {viewTransitionsCheck} from './viewTransitions'
|
|
99
|
+
import {staticsCheck} from './statics'
|
|
100
|
+
import {installRxjsHints} from './rxjsHints'
|
|
101
|
+
import {inspectCheck, installInspect} from './inspect'
|
|
102
|
+
import {nextHooks} from './next'
|
|
103
|
+
|
|
104
|
+
export {checkEventBus} from './events'
|
|
105
|
+
export {configureStrict, isStrictEnabled} from './strict'
|
|
106
|
+
export type {EventBusSummary} from './events'
|
|
107
|
+
export {RXJS_HINTS} from './rxjsHints'
|
|
108
|
+
export {inspect} from './inspect'
|
|
109
|
+
export type {InspectResource, InspectCacheEntry, InspectGraph, InspectComponent, InspectAction, InspectActionTrigger, InspectChild, InspectSelector, InspectControl, InspectDiagnostic, InspectOptions, InspectRecentAction} from './public'
|
|
110
|
+
export {listCodes, getCodeInfo} from '../codes'
|
|
111
|
+
export type {DiagnosticCodeInfo} from '../codes'
|
|
112
|
+
|
|
113
|
+
/** Every runtime check in this entry. */
|
|
114
|
+
export const checks: DiagnosticCheck[] = [
|
|
115
|
+
wiringCheck,
|
|
116
|
+
stateCheck,
|
|
117
|
+
eventsCheck,
|
|
118
|
+
propsCheck,
|
|
119
|
+
collectionsCheck,
|
|
120
|
+
domCheck,
|
|
121
|
+
shorthandCheck,
|
|
122
|
+
controlsCheck,
|
|
123
|
+
elementCommandsCheck,
|
|
124
|
+
behaviorsCheck,
|
|
125
|
+
formsCheck,
|
|
126
|
+
datasetCheck,
|
|
127
|
+
strictCheck,
|
|
128
|
+
repliesCheck,
|
|
129
|
+
routerCheck,
|
|
130
|
+
fetchCheck,
|
|
131
|
+
timersCheck,
|
|
132
|
+
persistCheck,
|
|
133
|
+
viewTransitionsCheck,
|
|
134
|
+
staticsCheck,
|
|
135
|
+
inspectCheck,
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* (Re-)register all checks with the core and install the RxJS hints. Called
|
|
140
|
+
* on import. Idempotent across duplicate copies of this entry: the previous
|
|
141
|
+
* installation (stored on the core bridge) is removed first.
|
|
142
|
+
*/
|
|
143
|
+
export function installChecks(): () => void {
|
|
144
|
+
const core = bridge()
|
|
145
|
+
if (!core) throw new Error(`[Sygnal] 'sygnal/diagnostics' could not find the Sygnal diagnostics core`)
|
|
146
|
+
if (typeof core.__uninstallChecks === 'function') core.__uninstallChecks()
|
|
147
|
+
const unregister = checks.map(check => core.registerCheck(check))
|
|
148
|
+
const uninstallHints = installRxjsHints(Stream && Stream.prototype)
|
|
149
|
+
const uninstallInspect = installInspect()
|
|
150
|
+
const uninstallRouter = installRouterHooks()
|
|
151
|
+
const uninstallControls = installControlHooks()
|
|
152
|
+
const uninstallTimers = installTimerHooks()
|
|
153
|
+
const uninstallBrowser = installBrowserSourceHooks()
|
|
154
|
+
const uninstallElementCommands = installElementCommandHooks()
|
|
155
|
+
const uninstallWidgets = installWidgetHooks()
|
|
156
|
+
const uninstallVirtual = installVirtualHooks()
|
|
157
|
+
const uninstallForms = installFormHooks()
|
|
158
|
+
const uninstallSortable = installSortableHooks()
|
|
159
|
+
// PLAN-4.6 R4: the core reads its hooks from the bridge once per app (checks/next.ts)
|
|
160
|
+
;(core.layers ||= new Set()).add(nextHooks)
|
|
161
|
+
const uninstall = () => {
|
|
162
|
+
core.layers?.delete(nextHooks)
|
|
163
|
+
unregister.forEach(fn => fn())
|
|
164
|
+
uninstallHints()
|
|
165
|
+
uninstallInspect()
|
|
166
|
+
uninstallRouter()
|
|
167
|
+
uninstallControls()
|
|
168
|
+
uninstallTimers()
|
|
169
|
+
uninstallBrowser()
|
|
170
|
+
uninstallElementCommands()
|
|
171
|
+
uninstallWidgets()
|
|
172
|
+
uninstallVirtual()
|
|
173
|
+
uninstallForms()
|
|
174
|
+
uninstallSortable()
|
|
175
|
+
if (core.__uninstallChecks === uninstall) core.__uninstallChecks = undefined
|
|
176
|
+
}
|
|
177
|
+
core.__uninstallChecks = uninstall
|
|
178
|
+
return uninstall
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface ChecksOptions {
|
|
182
|
+
/** delay after a render before the DOM checks (SYG103/104) run; default 50 ms */
|
|
183
|
+
settleMs?: number
|
|
184
|
+
/** render-idle time before SYG103 escalates to warn; default 2000 ms */
|
|
185
|
+
idleMs?: number
|
|
186
|
+
/** renders required before SYG103 escalates to warn; default 3 */
|
|
187
|
+
minRenders?: number
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Tune the timing of the DOM checks (mostly for tests). */
|
|
191
|
+
export function configureChecks(options: ChecksOptions = {}): void {
|
|
192
|
+
for (const key of Object.keys(timing) as Array<keyof typeof timing>) {
|
|
193
|
+
if (typeof options[key] === 'number') timing[key] = options[key] as number
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Forget what the checks have seen and reported (dedupe state, registries). For tests. */
|
|
198
|
+
export function resetChecks(): void {
|
|
199
|
+
resetCheckState()
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
installChecks()
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* inspect() — the machine-readable app graph at runtime (PLAN-1 workstream 2B).
|
|
3
|
+
*
|
|
4
|
+
* Built only from what the diagnostics hooks already see, keyed by component
|
|
5
|
+
* instance (so diagnostics must be on while the app runs):
|
|
6
|
+
* onIntent registers the instance (name, parent, kind) and its intent
|
|
7
|
+
* action names; claims the EVENTS.select() types seen since the
|
|
8
|
+
* previous onIntent (intent runs synchronously right before it)
|
|
9
|
+
* onModel action -> sinks
|
|
10
|
+
* onSink (checks/next.ts: eventEmitted) the EVENTS types the instance emitted. Since
|
|
11
|
+
* B-023 the driver-side emitter name (onBusEmit) is the emitting
|
|
12
|
+
* component's, but it is only a name, and this graph is per instance
|
|
13
|
+
* onReducer which model-only actions actually ran (=> dispatched by next(),
|
|
14
|
+
* unless a request named them as reply actions: replies.ts, 'reply')
|
|
15
|
+
* onBusEmit EVENTS types seen on the bus
|
|
16
|
+
* onBusSelect EVENTS types selected (see onIntent)
|
|
17
|
+
* onRender (PLAN-4 CT-1) the controls the instance renders: its own vtree, up to the
|
|
18
|
+
* isolated child components, through ./controls' vnode -> control map
|
|
19
|
+
* onDispose prunes the instance
|
|
20
|
+
* (PLAN-4 2-C) the action log (./actionLog: actionHooks, a layer of checks/next.ts) feeds
|
|
21
|
+
* inspect({ actions }): the recent actions (the last RECENT_MAX, any instance)
|
|
22
|
+
* Selectors come from the DOM check (real DOM) or from renderComponent (mock
|
|
23
|
+
* DOM, passed in as options.selectors). The same shape is produced statically
|
|
24
|
+
* by `sygnal-check --graph`; the JSON Schema is
|
|
25
|
+
* sygnal-check/schema/inspect.schema.json, the types are in ./public.d.ts.
|
|
26
|
+
*
|
|
27
|
+
* This lives in the 'sygnal/diagnostics' dev entry only (D29: zero bytes in
|
|
28
|
+
* app bundles). installInspect() publishes inspect() on the core bridge
|
|
29
|
+
* (renderComponent's t.inspect() reads it there) and on the devtools object
|
|
30
|
+
* (window.__SYGNAL_DEVTOOLS__, which is getDevTools()) once it exists.
|
|
31
|
+
*/
|
|
32
|
+
import type {DiagnosticCheck} from '../index'
|
|
33
|
+
import type {InspectGraph, InspectComponent, InspectOptions, InspectSelector, InspectDiagnostic, InspectChild, InspectResource, InspectControl, InspectRecentAction} from './public'
|
|
34
|
+
import {clockNow} from './actionLog'
|
|
35
|
+
import type {ActionListener, ActionRecord} from './actionLog'
|
|
36
|
+
import {bridge, onReset, nameOf, isPlainObject, BUILTIN_ACTIONS, replySeen} from './shared'
|
|
37
|
+
import {checkEventBus} from './events'
|
|
38
|
+
import {selectorStatus} from './dom'
|
|
39
|
+
import {controlOfVnode, keyOfSelector} from './controls'
|
|
40
|
+
|
|
41
|
+
type Kind = InspectComponent['kind']
|
|
42
|
+
|
|
43
|
+
interface Rec {
|
|
44
|
+
instance: any
|
|
45
|
+
id: string
|
|
46
|
+
name: string
|
|
47
|
+
parentId: string | null
|
|
48
|
+
kind: Kind
|
|
49
|
+
/** null: single-stream intent (no action names) */
|
|
50
|
+
intentActions: string[] | null
|
|
51
|
+
injected: Set<string>
|
|
52
|
+
modelMap: Record<string, string[]>
|
|
53
|
+
fired: Set<string>
|
|
54
|
+
eventsSelected: Set<string>
|
|
55
|
+
eventsEmitted: Set<string>
|
|
56
|
+
/** CT-1: controls seen in its renders, by key (first-seen order) */
|
|
57
|
+
controls: Map<string, {element: string | null; kind?: string}>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let records = new Map<any, Rec>()
|
|
61
|
+
let pendingSelects: string[] = []
|
|
62
|
+
/** every EVENTS type seen on the bus */
|
|
63
|
+
let busTypes = new Set<string>()
|
|
64
|
+
/** PLAN-4 2-C (GS-10): the most recent actions of any instance, oldest first */
|
|
65
|
+
const RECENT_MAX = 200
|
|
66
|
+
let recent: ActionRecord[] = []
|
|
67
|
+
let epoch = clockNow()
|
|
68
|
+
export const actionListener: ActionListener = {
|
|
69
|
+
action(r) { if (recent.push(r) > RECENT_MAX) recent.shift() },
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
onReset(() => {
|
|
73
|
+
records = new Map()
|
|
74
|
+
pendingSelects = []
|
|
75
|
+
busTypes = new Set()
|
|
76
|
+
recent = []
|
|
77
|
+
epoch = clockNow()
|
|
78
|
+
})
|
|
79
|
+
const uniq = <T>(list: Iterable<T>): T[] => [...new Set(list)]
|
|
80
|
+
|
|
81
|
+
const NEXT_KIND: Record<string, Kind> = {root: 'root', child: 'child', item: 'collection-item', page: 'switchable'}
|
|
82
|
+
|
|
83
|
+
function kindOf(c: any): Kind {
|
|
84
|
+
// PLAN-4.6 R4: the core's instance view says it (checks/next.ts)
|
|
85
|
+
return (c && c.__next && NEXT_KIND[c.__next.kind]) || 'child'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function ensure(c: any): Rec {
|
|
89
|
+
let r = records.get(c)
|
|
90
|
+
if (!r) {
|
|
91
|
+
const parent = c && c.__next && c.__next.parentId
|
|
92
|
+
r = {
|
|
93
|
+
instance: c,
|
|
94
|
+
id: String(c && c._componentNumber),
|
|
95
|
+
name: nameOf(c),
|
|
96
|
+
parentId: typeof parent === 'number' ? String(parent) : null,
|
|
97
|
+
kind: kindOf(c),
|
|
98
|
+
intentActions: [],
|
|
99
|
+
injected: new Set(),
|
|
100
|
+
modelMap: {},
|
|
101
|
+
fired: new Set(),
|
|
102
|
+
eventsSelected: new Set(),
|
|
103
|
+
eventsEmitted: new Set(),
|
|
104
|
+
controls: new Map(),
|
|
105
|
+
}
|
|
106
|
+
records.set(c, r)
|
|
107
|
+
}
|
|
108
|
+
return r
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let devtools: any
|
|
112
|
+
function attachDevtools(): void {
|
|
113
|
+
const dt = (globalThis as any).__SYGNAL_DEVTOOLS__
|
|
114
|
+
if (!dt || typeof dt !== 'object') return
|
|
115
|
+
devtools = dt
|
|
116
|
+
if (dt.inspect !== inspect) {
|
|
117
|
+
try { dt.inspect = inspect } catch (_) { /* frozen: ignore */ }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const inspectCheck: DiagnosticCheck = {
|
|
122
|
+
id: 'inspect',
|
|
123
|
+
|
|
124
|
+
onBusSelect(type) {
|
|
125
|
+
if (type === undefined || type === null || type === '') pendingSelects.push('*')
|
|
126
|
+
else for (const t of ([] as any[]).concat(type)) if (typeof t === 'string') pendingSelects.push(t)
|
|
127
|
+
if (pendingSelects.length > 1000) pendingSelects.shift()
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
onIntent(component, actionNames) {
|
|
131
|
+
attachDevtools()
|
|
132
|
+
const r = ensure(component)
|
|
133
|
+
const intent$ = component && component.intent$
|
|
134
|
+
r.intentActions = actionNames || []
|
|
135
|
+
r.injected = new Set((intent$ && typeof intent$ === 'object' && intent$.__sygnalTestActions) || [])
|
|
136
|
+
for (const t of pendingSelects) r.eventsSelected.add(t)
|
|
137
|
+
pendingSelects = []
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
onModel(component, modelMap) {
|
|
141
|
+
const r = ensure(component)
|
|
142
|
+
r.modelMap = modelMap || {}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
onRender(component, root) {
|
|
146
|
+
const r = records.get(component)
|
|
147
|
+
if (r) collectControls(root, r.controls, true)
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
onReducer(component, action) {
|
|
151
|
+
const r = records.get(component)
|
|
152
|
+
if (r && typeof action === 'string') r.fired.add(action)
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
onBusEmit(type) {
|
|
156
|
+
if (typeof type === 'string') busTypes.add(type)
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
onDispose(component) {
|
|
160
|
+
records.delete(component)
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** PLAN-4.6 R4 (onSink): an EVENTS value the instance sent */
|
|
165
|
+
export function eventEmitted(component: any, ev: any): void {
|
|
166
|
+
const r = records.get(component)
|
|
167
|
+
if (r && ev && typeof ev.type === 'string') r.eventsEmitted.add(ev.type)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* CT-1: record the controls in a component's rendered tree (data-control="<Key>"), stopping at
|
|
172
|
+
* isolated child components (their root carries data.isolate on the real DOM, a '.___<scope>'
|
|
173
|
+
* class in the mock DOM): the controls inside belong to the child.
|
|
174
|
+
*/
|
|
175
|
+
function collectControls(v: any, out: Rec['controls'], root: boolean): void {
|
|
176
|
+
if (!v || typeof v != 'object') return
|
|
177
|
+
if (!root && typeof v.sel == 'string' && ((v.data && v.data.isolate) || v.sel.includes('.___'))) return
|
|
178
|
+
const key = v.data && v.data.attrs && v.data.attrs['data-control']
|
|
179
|
+
if (typeof key == 'string' && !out.has(key)) {
|
|
180
|
+
const control = controlOfVnode(v)
|
|
181
|
+
const spec = control && control.spec
|
|
182
|
+
out.set(key, spec && typeof spec == 'object'
|
|
183
|
+
? {element: null, kind: String(spec.kind)}
|
|
184
|
+
: {element: typeof spec == 'string' ? spec : typeof v.sel == 'string' ? v.sel.split(/[.#]/)[0] : null})
|
|
185
|
+
}
|
|
186
|
+
for (const k of [].concat(v.children || [], (v.data && v.data.portalChildren) || [])) collectControls(k, out, false)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** CT-1: the controls a component rendered, `listened` from its intent's selectors */
|
|
190
|
+
function controlsOf(r: Rec, selectors: InspectSelector[]): InspectControl[] | undefined {
|
|
191
|
+
if (!r.controls.size) return undefined
|
|
192
|
+
const listened = new Set<string>()
|
|
193
|
+
for (const s of selectors) for (const m of s.selector.matchAll(/\[data-control="([^"]+)"\]/g)) listened.add(m[1])
|
|
194
|
+
return [...r.controls].map(([name, {element, kind}]) => ({name, element, ...(kind ? {kind} : {}), listened: listened.has(name)}))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** CT-1: mark a selector that is a control ([data-control="<Key>"]) with its key */
|
|
198
|
+
const withControl = (s: InspectSelector): InspectSelector => {
|
|
199
|
+
const key = keyOfSelector(s.selector)
|
|
200
|
+
return key ? {...s, control: key} : s
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const slim = (d: any): InspectDiagnostic => {
|
|
204
|
+
const out: InspectDiagnostic = {code: d.code, severity: d.severity, message: d.message}
|
|
205
|
+
if (d.component) out.component = d.component
|
|
206
|
+
if (d.fix) out.fix = d.fix
|
|
207
|
+
if (d.docsUrl) out.docsUrl = d.docsUrl
|
|
208
|
+
if (d.data !== undefined) {
|
|
209
|
+
// keep it JSON-safe (data can hold errors, vnodes, ...)
|
|
210
|
+
try { out.data = JSON.parse(JSON.stringify(d.data)) } catch (_) { /* drop */ }
|
|
211
|
+
}
|
|
212
|
+
return out
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function actionsOf(r: Rec): InspectComponent['actions'] {
|
|
216
|
+
const intent = (r.intentActions || []).filter(a => !r.injected.has(a))
|
|
217
|
+
const names = uniq([...intent, ...Object.keys(r.modelMap)]).filter(a => typeof a === 'string' && !a.startsWith('__'))
|
|
218
|
+
const replies = replySeen.get(r.instance)
|
|
219
|
+
return names.map(name => ({
|
|
220
|
+
name,
|
|
221
|
+
trigger: BUILTIN_ACTIONS.has(name) ? 'builtin'
|
|
222
|
+
: intent.includes(name) ? 'intent'
|
|
223
|
+
: replies?.has(name) ? 'reply'
|
|
224
|
+
: !r.injected.has(name) && r.fired.has(name) ? 'next'
|
|
225
|
+
: 'unknown',
|
|
226
|
+
sinks: [...(r.modelMap[name] || [])],
|
|
227
|
+
}))
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function stateKeysOf(c: any, calculated: string[]): string[] {
|
|
231
|
+
const s = c && c.currentState
|
|
232
|
+
return isPlainObject(s) ? Object.keys(s).filter(k => !calculated.includes(k)) : []
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** PLAN-3 5-3: the instance's resources (`resources` static) and their state slots */
|
|
236
|
+
function resourcesOf(c: any): InspectResource[] | undefined {
|
|
237
|
+
const res = c && c.view && c.view.resources
|
|
238
|
+
if (!res || typeof res !== 'object') return undefined
|
|
239
|
+
const s = c.currentState || {}
|
|
240
|
+
return Object.keys(res).map(name => {
|
|
241
|
+
const r = s[name] || {}
|
|
242
|
+
return {name, status: r.status ?? 'idle', refreshing: !!r.refreshing, hasData: r.data !== undefined, error: r.error ? String(r.error.message ?? r.error) : undefined}
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** PLAN-3 5-3: the cache entries of every makeFetchDriver source the instances use, by sink name (sinks with an empty cache left out) */
|
|
247
|
+
function cacheOf(recs: Rec[]): InspectGraph['cache'] {
|
|
248
|
+
const out: NonNullable<InspectGraph['cache']> = {}
|
|
249
|
+
for (const r of recs) {
|
|
250
|
+
const sources = r.instance && r.instance.sources
|
|
251
|
+
if (!sources || typeof sources !== 'object') continue
|
|
252
|
+
for (const k of Object.keys(sources)) {
|
|
253
|
+
const src = sources[k]
|
|
254
|
+
if (out[k] || !src || src.__sygnalStatic !== 'resources' || typeof src.__inspect !== 'function') continue
|
|
255
|
+
try { const list = src.__inspect().cache; if (list.length) out[k] = list } catch (_) { /* a driver without the cache listing */ }
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return out
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* renderComponent's mock DOM (src/extra/testing.ts passes its listener registry):
|
|
263
|
+
* listener paths are the select() chain with isolation scopes as '.___<scope>' entries;
|
|
264
|
+
* probe(selectors, scope) matches one against the latest vtree: own = in the component's
|
|
265
|
+
* own scope, child = the scope of the first (isolated) child component it matches inside.
|
|
266
|
+
*/
|
|
267
|
+
interface MockDom {
|
|
268
|
+
listeners: Map<string, string[]>
|
|
269
|
+
evTypes: Record<string, string[]>
|
|
270
|
+
owners: Map<string, string>
|
|
271
|
+
scopeIds: Map<string, number>
|
|
272
|
+
probe: (selectors: string[], scope?: string) => {own: boolean; child?: string}
|
|
273
|
+
vtree: any
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const isScope = (s: string) => s.startsWith('.___')
|
|
277
|
+
|
|
278
|
+
function mockSelectors(mock: MockDom): Record<string, InspectSelector[]> {
|
|
279
|
+
const out: Record<string, InspectSelector[]> = {}
|
|
280
|
+
mock.listeners.forEach((path, key) => {
|
|
281
|
+
const scope = path.filter(isScope).pop()
|
|
282
|
+
const id = mock.scopeIds.get(scope || '')
|
|
283
|
+
if (id === undefined) return
|
|
284
|
+
const sels = path.filter(s => !isScope(s)).join(' ').split(/[\s>]+/).filter(Boolean)
|
|
285
|
+
const page = !sels.length || /^(document|body)$/.test(sels[0])
|
|
286
|
+
const {own, child} = mock.vtree && !page ? mock.probe(sels, scope) : {own: false, child: undefined}
|
|
287
|
+
;(out[id] = out[id] || []).push({
|
|
288
|
+
selector: sels.join(' '),
|
|
289
|
+
events: uniq(mock.evTypes[key] || []),
|
|
290
|
+
matched: mock.vtree && !page ? own : null,
|
|
291
|
+
isolationHit: !own && child ? mock.owners.get(child) || 'a child component' : null,
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
return out
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function selectorsOf(r: Rec, options: InspectOptions, diags: any[]): InspectSelector[] {
|
|
298
|
+
const given = options.selectors && options.selectors[r.id]
|
|
299
|
+
if (given) return given.map(s => withControl({...s}))
|
|
300
|
+
return (selectorStatus(r.instance) || []).map(({selector, matched, crossed}) => {
|
|
301
|
+
const hit = diags.find(d => d.code === 'SYG104' && d.component === r.name && d.data && d.data.selector === selector)
|
|
302
|
+
const missed = diags.some(d => d.code === 'SYG103' && d.component === r.name && d.data && d.data.selector === selector)
|
|
303
|
+
return withControl({
|
|
304
|
+
selector,
|
|
305
|
+
events: null,
|
|
306
|
+
matched: matched === null && missed ? false : matched,
|
|
307
|
+
isolationHit: crossed ? ((hit && hit.data.child) || 'a child component') : null,
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function childrenOf(r: Rec, all: Rec[]): InspectChild[] {
|
|
313
|
+
const via: Record<Kind, InspectChild['via']> = {root: 'tag', child: 'tag', 'collection-item': 'collection', switchable: 'switchable'}
|
|
314
|
+
const out = new Map<string, InspectChild>()
|
|
315
|
+
for (const c of all) {
|
|
316
|
+
if (c.parentId !== r.id) continue
|
|
317
|
+
const key = `${c.name}\u0000${via[c.kind]}`
|
|
318
|
+
const entry = out.get(key)
|
|
319
|
+
if (entry) entry.count = (entry.count || 1) + 1
|
|
320
|
+
else out.set(key, {name: c.name, via: via[c.kind], count: 1})
|
|
321
|
+
}
|
|
322
|
+
return [...out.values()]
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** The app graph of the live component instances (see ./public.d.ts). */
|
|
326
|
+
export function inspect(options: InspectOptions = {}): InspectGraph {
|
|
327
|
+
// report SYG105 (info) for EVENTS types selected but never emitted so far
|
|
328
|
+
try { checkEventBus() } catch (_) { /* 'error' mode: info never throws; be safe */ }
|
|
329
|
+
|
|
330
|
+
let diags: any[] = options.diagnostics as any[] || []
|
|
331
|
+
if (!options.diagnostics) {
|
|
332
|
+
attachDevtools()
|
|
333
|
+
try { diags = (devtools && typeof devtools.getDiagnostics === 'function' && devtools.getDiagnostics()) || [] } catch (_) { diags = [] }
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const mock: MockDom | undefined = (options as any).mock
|
|
337
|
+
if (mock) options = {...options, selectors: {...mockSelectors(mock), ...options.selectors}}
|
|
338
|
+
|
|
339
|
+
const all = [...records.values()]
|
|
340
|
+
const ids = options.ids && new Set(options.ids.map(String))
|
|
341
|
+
const recs = ids ? all.filter(r => ids.has(r.id)) : all
|
|
342
|
+
const names = new Set(recs.map(r => r.name))
|
|
343
|
+
|
|
344
|
+
const components: InspectComponent[] = recs.map(r => {
|
|
345
|
+
const c = r.instance
|
|
346
|
+
const calculated = c && c.calculated && typeof c.calculated === 'object' ? Object.keys(c.calculated) : []
|
|
347
|
+
const selectors = selectorsOf(r, options, diags)
|
|
348
|
+
const controls = controlsOf(r, selectors)
|
|
349
|
+
return {
|
|
350
|
+
name: r.name,
|
|
351
|
+
id: r.id,
|
|
352
|
+
parentId: r.parentId,
|
|
353
|
+
kind: r.kind,
|
|
354
|
+
actions: actionsOf(r),
|
|
355
|
+
stateKeys: stateKeysOf(c, calculated),
|
|
356
|
+
calculated,
|
|
357
|
+
contextProvides: c && isPlainObject(c.context) ? Object.keys(c.context) : [],
|
|
358
|
+
contextConsumes: null,
|
|
359
|
+
eventsEmitted: [...r.eventsEmitted],
|
|
360
|
+
eventsSelected: [...r.eventsSelected],
|
|
361
|
+
children: childrenOf(r, all),
|
|
362
|
+
selectors,
|
|
363
|
+
...(controls ? {controls} : {}),
|
|
364
|
+
diagnostics: diags.filter(d => d && d.component === r.name).map(slim),
|
|
365
|
+
...(resourcesOf(c) ? {resources: resourcesOf(c)} : {}),
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
const cache = cacheOf(recs) || {}
|
|
370
|
+
const events: InspectGraph['events'] = {}
|
|
371
|
+
const ev = (type: string) => events[type] || (events[type] = {emitters: [], selectors: []})
|
|
372
|
+
const add = (list: string[], name: string) => { if (!list.includes(name)) list.push(name) }
|
|
373
|
+
for (const c of components) {
|
|
374
|
+
for (const t of c.eventsEmitted) add(ev(t).emitters, c.name)
|
|
375
|
+
for (const t of c.eventsSelected) add(ev(t).selectors, c.name)
|
|
376
|
+
}
|
|
377
|
+
// emitted on the bus by something that isn't a listed component (e.g. a driver, a pruned component)
|
|
378
|
+
if (!ids) for (const t of busTypes) ev(t)
|
|
379
|
+
|
|
380
|
+
return {
|
|
381
|
+
version: 1,
|
|
382
|
+
source: 'runtime',
|
|
383
|
+
components,
|
|
384
|
+
events,
|
|
385
|
+
diagnostics: diags.filter(d => d && (!d.component || !names.has(d.component))).map(slim),
|
|
386
|
+
...(Object.keys(cache).length ? {cache} : {}),
|
|
387
|
+
...(options.actions ? {recentActions: recentActions(options.actions, ids)} : {}),
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** a JSON-safe copy of an action's data (dropped when it doesn't serialize, or is large: a DOM event) */
|
|
392
|
+
function jsonData(d: any): {data?: any} {
|
|
393
|
+
if (d === undefined) return {}
|
|
394
|
+
try {
|
|
395
|
+
const text = JSON.stringify(d)
|
|
396
|
+
return text === undefined || text.length > 1000 ? {} : {data: JSON.parse(text)}
|
|
397
|
+
} catch (_) { return {} }
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** PLAN-4 2-C: the last `limit` actions (true: all kept) of the listed instances */
|
|
401
|
+
function recentActions(limit: true | number, ids: Set<string> | undefined): InspectRecentAction[] {
|
|
402
|
+
const list = ids ? recent.filter(r => ids.has(r.instance)) : recent
|
|
403
|
+
const n = limit === true ? list.length : Math.max(0, Math.floor(limit))
|
|
404
|
+
return list.slice(list.length - n).map(r => ({
|
|
405
|
+
type: r.type,
|
|
406
|
+
...jsonData(r.data),
|
|
407
|
+
component: r.component,
|
|
408
|
+
instance: r.instance,
|
|
409
|
+
sinks: [...r.sinks],
|
|
410
|
+
cause: r.cause,
|
|
411
|
+
at: r.time - epoch,
|
|
412
|
+
}))
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Publish inspect() on the core bridge and the devtools object. Returns an uninstall function. */
|
|
416
|
+
export function installInspect(): () => void {
|
|
417
|
+
const core = bridge()
|
|
418
|
+
if (core) core.inspect = inspect
|
|
419
|
+
attachDevtools()
|
|
420
|
+
return () => {
|
|
421
|
+
if (core && core.inspect === inspect) core.inspect = undefined
|
|
422
|
+
const dt = (globalThis as any).__SYGNAL_DEVTOOLS__
|
|
423
|
+
if (dt && dt.inspect === inspect) {
|
|
424
|
+
try { delete dt.inspect } catch (_) { /* ignore */ }
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|