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.
- package/CHANGELOG.md +646 -0
- package/README.md +24 -9
- package/dist/astro/client.cjs.js +16 -9
- package/dist/astro/client.cjs.js.map +1 -1
- package/dist/astro/client.mjs +16 -9
- package/dist/astro/client.mjs.map +1 -1
- package/dist/astro/index.cjs.js +362 -91
- package/dist/astro/index.cjs.js.map +1 -1
- package/dist/astro/index.mjs +362 -92
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/server.cjs.js +3396 -165
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs +3396 -165
- package/dist/astro/server.mjs.map +1 -1
- 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 +3032 -296
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +3032 -296
- package/dist/diagnostics.esm.js.map +1 -1
- 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 +13178 -5769
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2908 -276
- package/dist/index.esm.js +13149 -5779
- package/dist/index.esm.js.map +1 -1
- package/dist/jsx-dev-runtime.cjs.js +26 -334
- package/dist/jsx-dev-runtime.cjs.js.map +1 -1
- package/dist/jsx-dev-runtime.esm.js +19 -327
- package/dist/jsx-dev-runtime.esm.js.map +1 -1
- package/dist/jsx-runtime.cjs.js +26 -334
- package/dist/jsx-runtime.cjs.js.map +1 -1
- package/dist/jsx-runtime.esm.js +19 -327
- package/dist/jsx-runtime.esm.js.map +1 -1
- package/dist/jsx.cjs.js +10 -314
- package/dist/jsx.cjs.js.map +1 -1
- package/dist/jsx.esm.js +8 -315
- package/dist/jsx.esm.js.map +1 -1
- 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 +1 -1
- package/dist/sygnal.min.js.map +1 -1
- 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 +4 -14
- package/dist/vike/ClientOnly.cjs.js.map +1 -1
- package/dist/vike/ClientOnly.mjs +4 -14
- package/dist/vike/ClientOnly.mjs.map +1 -1
- package/dist/vike/{+config.js → config/+config.js} +9 -1
- package/dist/vike/config/+config.js.map +1 -0
- package/dist/vike/config/package.json +6 -0
- package/dist/vike/onRenderClient.cjs.js +165 -95
- package/dist/vike/onRenderClient.cjs.js.map +1 -1
- package/dist/vike/onRenderClient.mjs +165 -95
- package/dist/vike/onRenderClient.mjs.map +1 -1
- package/dist/vike/onRenderHtml.cjs.js +59 -24
- package/dist/vike/onRenderHtml.cjs.js.map +1 -1
- package/dist/vike/onRenderHtml.mjs +60 -25
- package/dist/vike/onRenderHtml.mjs.map +1 -1
- package/dist/vite/plugin.cjs.js +323 -88
- package/dist/vite/plugin.cjs.js.map +1 -1
- package/dist/vite/plugin.mjs +323 -89
- package/dist/vite/plugin.mjs.map +1 -1
- 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 +166 -103
- package/package.json +98 -14
- package/src/astro/client.ts +27 -16
- package/src/astro/index.d.ts +24 -0
- package/src/astro/index.ts +69 -3
- package/src/astro/server.ts +8 -2
- package/src/collection.ts +6 -93
- 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 +9 -2
- package/src/cycle/dom/PriorityQueue.ts +4 -2
- package/src/cycle/dom/SymbolTree.ts +18 -47
- package/src/cycle/dom/classNameModule.ts +9 -7
- package/src/cycle/dom/controlledInputModule.ts +23 -6
- package/src/cycle/dom/enrichEventStream.ts +25 -47
- package/src/cycle/dom/fragment.ts +7 -0
- package/src/cycle/dom/isolate.ts +30 -27
- package/src/cycle/dom/makeDOMDriver.ts +115 -56
- package/src/cycle/dom/mockDOMSource.ts +21 -1
- package/src/cycle/dom/modules.ts +16 -3
- 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 +19 -3
- 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 +101 -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 +1 -1
- 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 +20 -11
- package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
- package/src/extra/diagnostics/checks/events.ts +17 -2
- 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 +97 -4
- package/src/extra/diagnostics/checks/inspect.ts +140 -32
- 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 +10 -5
- package/src/extra/diagnostics/checks/public.d.ts +98 -7
- 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 +1 -1
- package/src/extra/diagnostics/checks/shared.ts +86 -2
- 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 +100 -7
- package/src/extra/diagnostics/checks/statics.ts +48 -0
- package/src/extra/diagnostics/checks/strict.ts +10 -67
- 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 +66 -10
- package/src/extra/diagnostics/codes.ts +268 -23
- package/src/extra/diagnostics/index.ts +34 -9
- package/src/extra/diagnostics/legacy.ts +17 -0
- package/src/extra/driverFactories.ts +83 -19
- package/src/extra/elementCommands.ts +53 -0
- package/src/extra/fetchDriver.ts +519 -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 +1 -1
- 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 +90 -217
- 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 +2433 -175
- 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/index.d.ts +2631 -117
- package/src/index.ts +25 -4
- 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 +256 -133
- 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 -121
- 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 +7 -1
- package/src/vite/globalthis-shim.ts +18 -0
- package/src/vite/globalthis.ts +56 -0
- package/src/vite/plugin.d.ts +22 -3
- package/src/vite/plugin.ts +222 -24
- package/src/zag.d.ts +64 -0
- package/src/zag.ts +238 -0
- package/dist/vike/+config.cjs.js +0 -66
- package/dist/vike/+config.cjs.js.map +0 -1
- package/dist/vike/+config.js.map +0 -1
- package/src/component.ts +0 -2301
- 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 -184
- package/src/cycle/state/index.ts +0 -5
- package/src/cycle/state/pickCombine.ts +0 -201
- 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,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* makeFetchDriver requests (PLAN-3 5-3: the query cache, D79/D80; G-175). Dev-entry codes
|
|
3
|
+
* (DEV_CODE_SEVERITY):
|
|
4
|
+
*
|
|
5
|
+
* SYG630 — a cached request that is not idempotent: `cache: true` or `staleTime` on a
|
|
6
|
+
* POST/PUT/PATCH/DELETE (a request with a body defaults to POST) (warn)
|
|
7
|
+
* SYG631 — `validate` is not a Standard Schema (no `~standard.validate`): the request
|
|
8
|
+
* fails (error)
|
|
9
|
+
* SYG632 — `{ invalidate }` matched no cache entry and no mounted resource (info)
|
|
10
|
+
* SYG633 — `{ abort: 'X' }` cancels the lane 'X', but this instance sends its `ok: 'X'`
|
|
11
|
+
* requests under another `key`, so nothing is cancelled (warn)
|
|
12
|
+
* SYG635 — `cache: true` / `staleTime` / `{ prefetch }` sent to a driver without a
|
|
13
|
+
* `queryCache()` (D88): nothing is cached (warn). The source's `__inspect().cache`
|
|
14
|
+
* is undefined without one
|
|
15
|
+
*
|
|
16
|
+
* Mechanism: onModel wraps the component's own model stream for every sink whose source
|
|
17
|
+
* takes the `resources` static (makeFetchDriver and renderComponent's HTTP fake) and checks
|
|
18
|
+
* each value as it is sent: requests, and each entry of a `{ resources }` declaration.
|
|
19
|
+
* SYG632 asks the source how many entries/resources the value matches (`__matches`).
|
|
20
|
+
* Each is reported once per component name and request URL / name.
|
|
21
|
+
*/
|
|
22
|
+
import type {DiagnosticCheck} from '../index'
|
|
23
|
+
import {devReport, once, nameOf} from './shared'
|
|
24
|
+
import {isStandardSchema} from '../../standardSchema'
|
|
25
|
+
|
|
26
|
+
const IDEMPOTENT = /^(GET|HEAD)$/i
|
|
27
|
+
|
|
28
|
+
/** instance → reply key lanes it has sent, and ok name → the other key it was sent under */
|
|
29
|
+
const lanes = new WeakMap<object, {used: Set<string>; keyed: Map<string, string>}>()
|
|
30
|
+
|
|
31
|
+
const fetchSink = (component: any, name: string) => component?.sources?.[name]?.__sygnalStatic === 'resources'
|
|
32
|
+
/** 5-5: the sink's driver has no queryCache() */
|
|
33
|
+
const noCache = (component: any, sink: string) => {
|
|
34
|
+
const i = component?.sources?.[sink]?.__inspect?.()
|
|
35
|
+
return !!i && i.cache === undefined
|
|
36
|
+
}
|
|
37
|
+
const reportNoCache = (component: any, sink: string, what: string, url: string) => {
|
|
38
|
+
if (!noCache(component, sink) || !once(`SYG635:${nameOf(component)}:${what}:${url}`)) return
|
|
39
|
+
devReport('SYG635', {
|
|
40
|
+
component,
|
|
41
|
+
message: `${sink} ${url ? url + ' ' : ''}uses ${what}, but the ${sink} driver has no queryCache(), so nothing is cached`,
|
|
42
|
+
fix: `Give the driver a cache: makeFetchDriver({ cache: queryCache({ staleTime: 30000 }) }) (import { queryCache } from 'sygnal'); in tests renderComponent(C, { http: { cache: queryCache() } }). Or remove ${what}`,
|
|
43
|
+
data: {sink, url, what},
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function checkOne(component: any, sink: string, req: any, where: string) {
|
|
48
|
+
if (!req || typeof req !== 'object') return
|
|
49
|
+
const name = nameOf(component)
|
|
50
|
+
const url = typeof req.url === 'string' ? req.url : ''
|
|
51
|
+
const method = String(req.method || (req.json !== undefined || req.body !== undefined ? 'POST' : 'GET')).toUpperCase()
|
|
52
|
+
if ((req.cache === true || req.staleTime != null) && !IDEMPOTENT.test(method) && once(`SYG630:${name}:${method}:${url}`)) {
|
|
53
|
+
devReport('SYG630', {
|
|
54
|
+
component,
|
|
55
|
+
message: `${where} ${method} ${url} sets ${req.cache === true ? 'cache: true' : 'staleTime'}, so a cached reply answers it instead of sending it again`,
|
|
56
|
+
fix: `Cache reads only: remove ${req.cache === true ? 'cache' : 'staleTime'} from the ${method}, and refresh the cached reads after it succeeds with invalidates: ['tag']`,
|
|
57
|
+
data: {sink, method, url},
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
if (req.cache === true || req.staleTime != null) reportNoCache(component, sink, req.cache === true ? 'cache: true' : 'staleTime', url)
|
|
61
|
+
if ('validate' in req && !isStandardSchema(req.validate) && once(`SYG631:${name}:${url}`)) {
|
|
62
|
+
devReport('SYG631', {
|
|
63
|
+
component,
|
|
64
|
+
message: `${where} ${url} has validate: ${typeof req.validate}, which is not a Standard Schema, so the request fails`,
|
|
65
|
+
fix: "Pass a Standard Schema object (zod, valibot, arktype, ...: anything with a '~standard'.validate function), e.g. validate: QuoteSchema",
|
|
66
|
+
data: {sink, url},
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function check(component: any, sink: string, req: any) {
|
|
72
|
+
if (!req || typeof req !== 'object') return
|
|
73
|
+
const name = nameOf(component)
|
|
74
|
+
const res = req.resources
|
|
75
|
+
if (res && typeof res === 'object') {
|
|
76
|
+
for (const k of Object.keys(res)) checkOne(component, sink, typeof res[k] === 'string' ? {url: res[k]} : res[k], `${name}.resources.${k}:`)
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
if (req.prefetch) {
|
|
80
|
+
const p = req.prefetch
|
|
81
|
+
reportNoCache(component, sink, '{ prefetch }', typeof p === 'string' ? p : String(p?.url ?? ''))
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
if ('invalidate' in req) {
|
|
85
|
+
const count = component.sources[sink]?.__matches?.(req.invalidate)
|
|
86
|
+
const what = typeof req.invalidate === 'function' ? 'the predicate' : JSON.stringify(req.invalidate)
|
|
87
|
+
if (count === 0 && once(`SYG632:${name}:${what}`)) {
|
|
88
|
+
devReport('SYG632', {
|
|
89
|
+
component,
|
|
90
|
+
message: `${sink} { invalidate: ${what} } matched no cache entry and no mounted resource`,
|
|
91
|
+
fix: "Give the resources (or cached requests) to refresh tags: ['quotes'] and invalidate that tag, or a URL prefix starting with '/' ('/api/quotes')",
|
|
92
|
+
data: {sink, invalidate: what},
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
let l = lanes.get(component)
|
|
98
|
+
if (!l) lanes.set(component, (l = {used: new Set(), keyed: new Map()}))
|
|
99
|
+
const {ok, error, key, abort} = req
|
|
100
|
+
if (typeof abort === 'string' && key === undefined) {
|
|
101
|
+
const other = l.keyed.get(abort)
|
|
102
|
+
if (other !== undefined && !l.used.has(abort) && once(`SYG633:${name}:${abort}`)) {
|
|
103
|
+
devReport('SYG633', {
|
|
104
|
+
component,
|
|
105
|
+
message: `${sink} { abort: '${abort}' } cancels the requests with key '${abort}', but ${name} sends its ok: '${abort}' requests with key: '${other}', so nothing is cancelled`,
|
|
106
|
+
fix: `Cancel by that key: { abort: true, key: '${other}' } (or drop the key, so the lane is the ok action)`,
|
|
107
|
+
data: {sink, abort, key: other},
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
if (typeof ok === 'string' || typeof error === 'string') {
|
|
113
|
+
const lane = key ?? ok ?? error
|
|
114
|
+
l.used.add(lane)
|
|
115
|
+
if (typeof ok === 'string' && key !== undefined && key !== ok) l.keyed.set(ok, String(key))
|
|
116
|
+
}
|
|
117
|
+
checkOne(component, sink, req, `A ${sink} request`)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const fetchCheck: DiagnosticCheck = {
|
|
121
|
+
id: 'fetch',
|
|
122
|
+
|
|
123
|
+
onModel(component) {
|
|
124
|
+
const model$ = component?.model$
|
|
125
|
+
if (!model$ || typeof model$ !== 'object') return
|
|
126
|
+
for (const sink of Object.keys(model$)) {
|
|
127
|
+
const s$ = model$[sink]
|
|
128
|
+
if (!fetchSink(component, sink) || !s$ || typeof s$.map !== 'function') continue
|
|
129
|
+
model$[sink] = s$.map((req: any) => {
|
|
130
|
+
try { check(component, sink, req) } catch (_) {}
|
|
131
|
+
return req
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PLAN-5 F-1: `form` behavior diagnostics (dev entry; src/extra/form.ts carries no text).
|
|
3
|
+
*
|
|
4
|
+
* The form module calls `__SYGNAL_DIAGNOSTICS__.form(code, ...args)`:
|
|
5
|
+
* 231 form(schema) with a schema that isn't a Standard Schema: throws the SYG231 Error (in
|
|
6
|
+
* production the first validation throws a plain TypeError)
|
|
7
|
+
* 230 (name, values) an input / focusout from a named field whose name isn't in `values`:
|
|
8
|
+
* SYG230 (warn, once per name); the event is ignored
|
|
9
|
+
* 232 (slice) a submit while submitting or while a queued submit waits for a check: SYG232
|
|
10
|
+
* (info, every time); the submit is dropped
|
|
11
|
+
* 233 (values, output) a valid submit: each top-level `values` key missing from the schema's
|
|
12
|
+
* output, SYG233 (warn, once per key): the schema strips it (zod's z.object does). G-377:
|
|
13
|
+
* only when every output key is a values key (an output with other keys reshapes: a rename)
|
|
14
|
+
* 235 (field, request) a check's request with `ok` / `error` / `latest` keys, which the form
|
|
15
|
+
* overwrites: SYG235 (warn, once per field)
|
|
16
|
+
* 234 (submit, key) G-577: a valid submit whose `submit` names one of the form's own actions,
|
|
17
|
+
* so it dispatched '<key>.<submit>' instead of the host's action: SYG234 (warn, once per
|
|
18
|
+
* key and name), at the submit (the form's own action then often throws: SYG214 / SYG216)
|
|
19
|
+
* Host checks (onModel, once per component name), for each `uses` entry made by form():
|
|
20
|
+
* SYG234 (warn) `submit` missing, not a host model entry, or one of the form's own action names
|
|
21
|
+
* (G-577: every action in that form's model, CHECKED_<field> included)
|
|
22
|
+
* SYG235 (warn) a `check` key that isn't a field of `values`
|
|
23
|
+
* SYG236 (warn) an array of objects in `values` with a row without an `id`
|
|
24
|
+
* SYG237 (warn) two form uses of one host with the same form selector (G-374)
|
|
25
|
+
*/
|
|
26
|
+
import type {DiagnosticCheck} from '../index'
|
|
27
|
+
import {devReport, once, nameOf} from './shared'
|
|
28
|
+
import {docsUrlFor} from '../codes'
|
|
29
|
+
import {hasField} from '../../formHelpers'
|
|
30
|
+
|
|
31
|
+
// the form's own action names (G-577: read from the form's model, so CHECKED_<field> counts)
|
|
32
|
+
const ownActions = (b: any): string[] => Object.keys(b?.model || {})
|
|
33
|
+
const SUBMIT_FIX = (key: string, a: string, own: string[]) =>
|
|
34
|
+
`Name the submit after a host action the form doesn't define (not ${own.join(', ')}): submit: 'SAVE', and rename the model entry '${a}' to SAVE: { HTTP: (state, values) => ({ url, json: values, ok: '${key}.DONE', error: '${key}.ERRORS' }) }`
|
|
35
|
+
const RESERVED = ['ok', 'error', 'latest']
|
|
36
|
+
|
|
37
|
+
const what = (v: any): string =>
|
|
38
|
+
v === null || v === undefined ? String(v)
|
|
39
|
+
: typeof v == 'function' ? 'a function'
|
|
40
|
+
: Array.isArray(v) ? 'an array'
|
|
41
|
+
: typeof v == 'object' ? `an object without ~standard.validate${typeof v.parse == 'function' ? ' (a validator from before Standard Schema?)' : ''}`
|
|
42
|
+
: `a ${typeof v}`
|
|
43
|
+
|
|
44
|
+
export function reportForm(code: number, a?: any, b?: any, c?: any): any {
|
|
45
|
+
if (code == 231) {
|
|
46
|
+
const err: any = new TypeError(`[Sygnal SYG231] form(schema, options): the schema is ${what(a)}, not a Standard Schema. ` +
|
|
47
|
+
`Pass a Standard Schema object: a zod, valibot or arktype schema, or an object with '~standard': { version: 1, vendor, validate }. ${docsUrlFor('SYG231')}`)
|
|
48
|
+
err.code = 'SYG231'
|
|
49
|
+
throw err
|
|
50
|
+
}
|
|
51
|
+
if (code == 230) {
|
|
52
|
+
if (!once(`SYG230:${a}`)) return
|
|
53
|
+
devReport('SYG230', {
|
|
54
|
+
component: 'form',
|
|
55
|
+
message: `form: a field named '${a}' changed, but '${a}' isn't a field of the form's values (${Object.keys(b || {}).join(', ') || 'none'}); the change is ignored`,
|
|
56
|
+
fix: `Name the input after a path in values (name="email", name="addresses.<row id>.city"), add '${a}' to values, or move the input out of the form element`,
|
|
57
|
+
data: {name: a},
|
|
58
|
+
})
|
|
59
|
+
} else if (code == 232) {
|
|
60
|
+
devReport('SYG232', {
|
|
61
|
+
component: 'form',
|
|
62
|
+
message: `form: a submit was dropped: ${a?.submitting ? 'the previous submit is still being sent (no form.DONE / form.ERRORS yet)' : 'a submit is already queued, waiting for an async check or an async schema'}`,
|
|
63
|
+
fix: `Disable the submit button while state.form.submitting (or queued) is true; answer the submit with ok: 'form.DONE', error: 'form.ERRORS'`,
|
|
64
|
+
})
|
|
65
|
+
} else if (code == 233) {
|
|
66
|
+
if (!b || typeof b != 'object' || Object.keys(b).some(k => !(k in (a || {})))) return
|
|
67
|
+
for (const k of Object.keys(a || {})) {
|
|
68
|
+
if (!(k in b) && once(`SYG233:${k}`)) devReport('SYG233', {
|
|
69
|
+
component: 'form',
|
|
70
|
+
message: `form: values.${k} is not in the schema's output (stripped or renamed), so the submit action doesn't get it under that name (a schema strips keys it doesn't declare)`,
|
|
71
|
+
fix: `Declare '${k}' in the schema (or make the schema keep unknown keys), or remove it from values; if the schema renames it on purpose, ignore this`,
|
|
72
|
+
data: {key: k},
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
} else if (code == 234) {
|
|
76
|
+
if (!once(`SYG234:run:${b}:${a}`)) return
|
|
77
|
+
devReport('SYG234', {
|
|
78
|
+
component: 'form',
|
|
79
|
+
message: `form '${b}': a valid submit dispatched '${b}.${a}' (the form's own ${a} action), not the host's '${a}': submit: '${a}' names one of the form's own actions, which next() prefers`,
|
|
80
|
+
fix: SUBMIT_FIX(b, a, ownActions(c)),
|
|
81
|
+
data: {key: b, submit: a},
|
|
82
|
+
})
|
|
83
|
+
} else if (code == 235) {
|
|
84
|
+
const set = RESERVED.filter(k => b && k in b)
|
|
85
|
+
if (set.length && once(`SYG235:req:${a}`)) devReport('SYG235', {
|
|
86
|
+
component: 'form',
|
|
87
|
+
message: `form: the check for '${a}' returns a request with ${set.map(k => `'${k}'`).join(', ')}; the form sets them itself (its reply action and latest: true), so they are replaced`,
|
|
88
|
+
fix: `Return only the request: check: { ${a}: { request: (v) => ({ url, query }), error: (body) => message } }`,
|
|
89
|
+
data: {field: a, keys: set},
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** row ids missing in `values`: the names of the arrays of objects that have a row without an id */
|
|
95
|
+
const missingIds = (v: any, at = '', out: string[] = []): string[] => {
|
|
96
|
+
if (v && typeof v == 'object') {
|
|
97
|
+
if (Array.isArray(v) && v.some(r => r && typeof r == 'object' && !Array.isArray(r) && r.id == null)) out.push(at)
|
|
98
|
+
for (const k in v) missingIds(v[k], at ? `${at}.${k}` : k, out)
|
|
99
|
+
}
|
|
100
|
+
return out
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const formsCheck: DiagnosticCheck = {
|
|
104
|
+
id: 'forms',
|
|
105
|
+
|
|
106
|
+
onModel(component) {
|
|
107
|
+
const view = component?.view, uses = view?.uses
|
|
108
|
+
if (!uses || typeof uses != 'object') return
|
|
109
|
+
const name = nameOf(component), sels: Record<string, string> = {}
|
|
110
|
+
for (const key of Object.keys(uses)) {
|
|
111
|
+
const b = uses[key]
|
|
112
|
+
if (!b?.form) continue
|
|
113
|
+
// G-374: each form listens on its selector inside the host, so two with one selector hear
|
|
114
|
+
// each other's fields and submits
|
|
115
|
+
const sel = b.options?.form || 'form'
|
|
116
|
+
if (sel in sels) {
|
|
117
|
+
if (once(`SYG237:${name}:${sel}`)) devReport('SYG237', {
|
|
118
|
+
component,
|
|
119
|
+
message: `${name}'s forms '${sels[sel]}' and '${key}' both listen on '${sel}', so each hears the other's fields and submits`,
|
|
120
|
+
fix: `Give each form element its own class and pass it: ${sels[sel]}: form(schema, { ..., form: '.${sels[sel]}' }), ${key}: form(schema, { ..., form: '.${key}' })`,
|
|
121
|
+
data: {keys: [sels[sel], key], form: sel},
|
|
122
|
+
})
|
|
123
|
+
} else sels[sel] = key
|
|
124
|
+
if (!once(`SYG23x:${name}:${key}`)) continue
|
|
125
|
+
const o = b.options || {}, values = o.values || {}
|
|
126
|
+
const model = Object.keys(view.model || {}).map(a => a.split('|')[0].trim()), own = ownActions(b)
|
|
127
|
+
const clash = own.includes(o.submit)
|
|
128
|
+
if (typeof o.submit != 'string' || !model.includes(o.submit) || clash) {
|
|
129
|
+
devReport('SYG234', {
|
|
130
|
+
component,
|
|
131
|
+
message: typeof o.submit != 'string' ? `${name}'s form '${key}' has no submit action, so a valid submit dispatches nothing`
|
|
132
|
+
: clash ? `${name}'s form '${key}' names submit: '${o.submit}', one of the form's own actions; a valid submit dispatches the form's '${key}.${o.submit}'${model.includes(o.submit) ? `, never ${name}'s '${o.submit}' entry` : ''}`
|
|
133
|
+
: `${name}'s form '${key}' dispatches '${o.submit}' on a valid submit, but ${name} has no model entry '${o.submit}'`,
|
|
134
|
+
fix: clash ? SUBMIT_FIX(key, o.submit, own)
|
|
135
|
+
: `Name a host action and add it to the model: submit: 'SIGN_UP', model: { SIGN_UP: { HTTP: (state, values) => ({ url, json: values, ok: '${key}.DONE', error: '${key}.ERRORS' }) } }`,
|
|
136
|
+
data: {key, submit: o.submit},
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
for (const f of Object.keys(o.check || {})) {
|
|
140
|
+
if (!hasField(values, f)) devReport('SYG235', {
|
|
141
|
+
component,
|
|
142
|
+
message: `${name}'s form '${key}' has a check for '${f}', which isn't a field of its values; it never runs`,
|
|
143
|
+
fix: `Use a field name from values (${Object.keys(values).join(', ')})`,
|
|
144
|
+
data: {key, field: f},
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
for (const at of missingIds(values)) devReport('SYG236', {
|
|
148
|
+
component,
|
|
149
|
+
message: `${name}'s form '${key}': values.${at} has rows without an id, so its fields are named by index and errors, touched state and focus don't follow a row when another is removed`,
|
|
150
|
+
fix: `Give each row a unique id: ${at}: [{ id: 1, ... }] (form.ADD numbers new rows itself)`,
|
|
151
|
+
data: {key, field: at},
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Install the `form` hook on the core bridge (form.ts calls it). */
|
|
158
|
+
export function installFormHooks(): () => void {
|
|
159
|
+
const c = (globalThis as any).__SYGNAL_DIAGNOSTICS__
|
|
160
|
+
if (!c) return () => {}
|
|
161
|
+
c.form = reportForm
|
|
162
|
+
return () => { if (c.form === reportForm) c.form = undefined }
|
|
163
|
+
}
|
|
@@ -17,15 +17,56 @@
|
|
|
17
17
|
* | SYG104 | intent selector only matches inside a child component | dom.ts |
|
|
18
18
|
* | SYG105 | EVENTS type emitted-not-selected / selected-not-emitted| events.ts |
|
|
19
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 |
|
|
20
54
|
* | SYG201 | STATE reducer dropped keys | state.ts |
|
|
21
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 |
|
|
22
58
|
* | SYG301 | RxJS operator used on an xstream stream | rxjsHints.ts |
|
|
23
59
|
* | SYG401 | Collection `from` missing or not an array | collections.ts |
|
|
24
|
-
* |
|
|
25
|
-
* |
|
|
26
|
-
* |
|
|
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 |
|
|
27
65
|
* | — | inspect(): the runtime app graph (2B) | inspect.ts |
|
|
28
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
|
+
*
|
|
29
70
|
* Strict checks (SYG5xx) only report after configureStrict(true) (or
|
|
30
71
|
* renderComponent(C, { strict: true }), or globalThis.__SYGNAL_STRICT__).
|
|
31
72
|
*/
|
|
@@ -38,16 +79,34 @@ import {eventsCheck} from './events'
|
|
|
38
79
|
import {propsCheck} from './props'
|
|
39
80
|
import {collectionsCheck} from './collections'
|
|
40
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'
|
|
41
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'
|
|
42
100
|
import {installRxjsHints} from './rxjsHints'
|
|
43
101
|
import {inspectCheck, installInspect} from './inspect'
|
|
102
|
+
import {nextHooks} from './next'
|
|
44
103
|
|
|
45
104
|
export {checkEventBus} from './events'
|
|
46
105
|
export {configureStrict, isStrictEnabled} from './strict'
|
|
47
106
|
export type {EventBusSummary} from './events'
|
|
48
107
|
export {RXJS_HINTS} from './rxjsHints'
|
|
49
108
|
export {inspect} from './inspect'
|
|
50
|
-
export type {InspectGraph, InspectComponent, InspectAction, InspectActionTrigger, InspectChild, InspectSelector, InspectDiagnostic, InspectOptions} from './public'
|
|
109
|
+
export type {InspectResource, InspectCacheEntry, InspectGraph, InspectComponent, InspectAction, InspectActionTrigger, InspectChild, InspectSelector, InspectControl, InspectDiagnostic, InspectOptions, InspectRecentAction} from './public'
|
|
51
110
|
export {listCodes, getCodeInfo} from '../codes'
|
|
52
111
|
export type {DiagnosticCodeInfo} from '../codes'
|
|
53
112
|
|
|
@@ -59,7 +118,20 @@ export const checks: DiagnosticCheck[] = [
|
|
|
59
118
|
propsCheck,
|
|
60
119
|
collectionsCheck,
|
|
61
120
|
domCheck,
|
|
121
|
+
shorthandCheck,
|
|
122
|
+
controlsCheck,
|
|
123
|
+
elementCommandsCheck,
|
|
124
|
+
behaviorsCheck,
|
|
125
|
+
formsCheck,
|
|
126
|
+
datasetCheck,
|
|
62
127
|
strictCheck,
|
|
128
|
+
repliesCheck,
|
|
129
|
+
routerCheck,
|
|
130
|
+
fetchCheck,
|
|
131
|
+
timersCheck,
|
|
132
|
+
persistCheck,
|
|
133
|
+
viewTransitionsCheck,
|
|
134
|
+
staticsCheck,
|
|
63
135
|
inspectCheck,
|
|
64
136
|
]
|
|
65
137
|
|
|
@@ -75,10 +147,31 @@ export function installChecks(): () => void {
|
|
|
75
147
|
const unregister = checks.map(check => core.registerCheck(check))
|
|
76
148
|
const uninstallHints = installRxjsHints(Stream && Stream.prototype)
|
|
77
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)
|
|
78
161
|
const uninstall = () => {
|
|
162
|
+
core.layers?.delete(nextHooks)
|
|
79
163
|
unregister.forEach(fn => fn())
|
|
80
164
|
uninstallHints()
|
|
81
165
|
uninstallInspect()
|
|
166
|
+
uninstallRouter()
|
|
167
|
+
uninstallControls()
|
|
168
|
+
uninstallTimers()
|
|
169
|
+
uninstallBrowser()
|
|
170
|
+
uninstallElementCommands()
|
|
171
|
+
uninstallWidgets()
|
|
172
|
+
uninstallVirtual()
|
|
173
|
+
uninstallForms()
|
|
174
|
+
uninstallSortable()
|
|
82
175
|
if (core.__uninstallChecks === uninstall) core.__uninstallChecks = undefined
|
|
83
176
|
}
|
|
84
177
|
core.__uninstallChecks = uninstall
|