@vidact/runtime 0.2.0-beta.0 → 0.2.0-beta.5
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 +52 -0
- package/README.md +1 -1
- package/dist/actions.d.ts +32 -30
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +251 -266
- package/dist/actions.js.map +1 -1
- package/dist/async.d.ts +20 -17
- package/dist/async.d.ts.map +1 -1
- package/dist/async.js +18 -17
- package/dist/async.js.map +1 -1
- package/dist/compiled/async-resource.d.ts +9 -6
- package/dist/compiled/async-resource.d.ts.map +1 -1
- package/dist/compiled/async-resource.js +69 -77
- package/dist/compiled/async-resource.js.map +1 -1
- package/dist/compiled/core.d.ts +136 -147
- package/dist/compiled/core.d.ts.map +1 -1
- package/dist/compiled/core.js +2672 -2985
- package/dist/compiled/core.js.map +1 -1
- package/dist/compiled/types.d.ts +44 -56
- package/dist/compiled/types.d.ts.map +1 -1
- package/dist/compiled/types.js +10 -6
- package/dist/compiled/types.js.map +1 -1
- package/dist/compiled/validation.d.ts +4 -1
- package/dist/compiled/validation.d.ts.map +1 -1
- package/dist/compiled/validation.js +17 -20
- package/dist/compiled/validation.js.map +1 -1
- package/dist/component-spread.d.ts +5 -3
- package/dist/component-spread.d.ts.map +1 -1
- package/dist/component-spread.js +49 -67
- package/dist/component-spread.js.map +1 -1
- package/dist/concurrent.d.ts +20 -18
- package/dist/concurrent.d.ts.map +1 -1
- package/dist/concurrent.js +191 -210
- package/dist/concurrent.js.map +1 -1
- package/dist/direct-dom.d.ts +17 -12
- package/dist/direct-dom.d.ts.map +1 -1
- package/dist/direct-dom.js +187 -221
- package/dist/direct-dom.js.map +1 -1
- package/dist/dom/attributes.d.ts +9 -6
- package/dist/dom/attributes.d.ts.map +1 -1
- package/dist/dom/attributes.js +65 -47
- package/dist/dom/attributes.js.map +1 -1
- package/dist/dom/events.d.ts +5 -2
- package/dist/dom/events.d.ts.map +1 -1
- package/dist/dom/events.js +53 -65
- package/dist/dom/events.js.map +1 -1
- package/dist/dom/forms.d.ts +9 -6
- package/dist/dom/forms.d.ts.map +1 -1
- package/dist/dom/forms.js +152 -198
- package/dist/dom/forms.js.map +1 -1
- package/dist/dom/intrinsic.d.ts +17 -15
- package/dist/dom/intrinsic.d.ts.map +1 -1
- package/dist/dom/intrinsic.js +48 -50
- package/dist/dom/intrinsic.js.map +1 -1
- package/dist/dom/namespace.d.ts +4 -1
- package/dist/dom/namespace.d.ts.map +1 -1
- package/dist/dom/namespace.js +25 -28
- package/dist/dom/namespace.js.map +1 -1
- package/dist/dom/namespaces.d.ts +11 -8
- package/dist/dom/namespaces.d.ts.map +1 -1
- package/dist/dom/namespaces.js +14 -12
- package/dist/dom/namespaces.js.map +1 -1
- package/dist/dom/properties.d.ts +18 -16
- package/dist/dom/properties.d.ts.map +1 -1
- package/dist/dom/properties.js +273 -296
- package/dist/dom/properties.js.map +1 -1
- package/dist/dom/style-properties.d.ts +4 -1
- package/dist/dom/style-properties.d.ts.map +1 -1
- package/dist/dom/style-properties.js +49 -45
- package/dist/dom/style-properties.js.map +1 -1
- package/dist/dom/styles.d.ts +5 -2
- package/dist/dom/styles.d.ts.map +1 -1
- package/dist/dom/styles.js +47 -67
- package/dist/dom/styles.js.map +1 -1
- package/dist/dom-forms.d.ts +4 -1
- package/dist/dom-forms.d.ts.map +1 -1
- package/dist/dom-forms.js +16 -13
- package/dist/dom-forms.js.map +1 -1
- package/dist/dom-styles.d.ts +4 -1
- package/dist/dom-styles.d.ts.map +1 -1
- package/dist/dom-styles.js +10 -7
- package/dist/dom-styles.js.map +1 -1
- package/dist/framework-hydrate.d.ts +20 -17
- package/dist/framework-hydrate.d.ts.map +1 -1
- package/dist/framework-hydrate.js +128 -146
- package/dist/framework-hydrate.js.map +1 -1
- package/dist/framework-protocol.d.ts +27 -25
- package/dist/framework-protocol.d.ts.map +1 -1
- package/dist/framework-protocol.js +173 -211
- package/dist/framework-protocol.js.map +1 -1
- package/dist/framework.d.ts +34 -32
- package/dist/framework.d.ts.map +1 -1
- package/dist/framework.js +74 -93
- package/dist/framework.js.map +1 -1
- package/dist/hydrate.d.ts +11 -8
- package/dist/hydrate.d.ts.map +1 -1
- package/dist/hydrate.js +13 -9
- package/dist/hydrate.js.map +1 -1
- package/dist/hydration-bridge.d.ts +70 -58
- package/dist/hydration-bridge.d.ts.map +1 -1
- package/dist/hydration-bridge.js +77 -66
- package/dist/hydration-bridge.js.map +1 -1
- package/dist/hydration.d.ts +54 -28
- package/dist/hydration.d.ts.map +1 -1
- package/dist/hydration.js +450 -463
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.js +11 -13
- package/dist/indexed-list.d.ts +8 -5
- package/dist/indexed-list.d.ts.map +1 -1
- package/dist/indexed-list.js +14 -7
- package/dist/indexed-list.js.map +1 -1
- package/dist/jsx-runtime.d.ts +10 -8
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js +28 -23
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/keyed-list.d.ts +13 -14
- package/dist/keyed-list.d.ts.map +1 -1
- package/dist/keyed-list.js +132 -160
- package/dist/keyed-list.js.map +1 -1
- package/dist/metadata.d.ts +6 -3
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +131 -164
- package/dist/metadata.js.map +1 -1
- package/dist/nested-prop.d.ts +4 -2
- package/dist/nested-prop.d.ts.map +1 -1
- package/dist/nested-prop.js +17 -16
- package/dist/nested-prop.js.map +1 -1
- package/dist/profiling.d.ts +11 -8
- package/dist/profiling.d.ts.map +1 -1
- package/dist/profiling.js +17 -17
- package/dist/profiling.js.map +1 -1
- package/dist/protocol.d.ts +5 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +8 -5
- package/dist/protocol.js.map +1 -1
- package/dist/raw-html.d.ts +5 -2
- package/dist/raw-html.d.ts.map +1 -1
- package/dist/raw-html.js +86 -146
- package/dist/raw-html.js.map +1 -1
- package/dist/ref.d.ts +8 -3
- package/dist/ref.d.ts.map +1 -1
- package/dist/ref.js +10 -2
- package/dist/ref.js.map +1 -1
- package/dist/renderable-protocol.d.ts +26 -8
- package/dist/renderable-protocol.d.ts.map +1 -1
- package/dist/renderable-protocol.js +30 -9
- package/dist/renderable-protocol.js.map +1 -1
- package/dist/renderable.d.ts +27 -22
- package/dist/renderable.d.ts.map +1 -1
- package/dist/renderable.js +141 -133
- package/dist/renderable.js.map +1 -1
- package/dist/retained-ui.d.ts +9 -6
- package/dist/retained-ui.d.ts.map +1 -1
- package/dist/retained-ui.js +12 -10
- package/dist/retained-ui.js.map +1 -1
- package/dist/root.d.ts +18 -15
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +73 -85
- package/dist/root.js.map +1 -1
- package/dist/scheduler.d.ts +10 -8
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +97 -105
- package/dist/scheduler.js.map +1 -1
- package/dist/server-framework.d.ts +45 -42
- package/dist/server-framework.d.ts.map +1 -1
- package/dist/server-framework.js +209 -217
- package/dist/server-framework.js.map +1 -1
- package/dist/server.d.ts +130 -128
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +603 -710
- package/dist/server.js.map +1 -1
- package/dist/shared/promise.d.ts +6 -3
- package/dist/shared/promise.d.ts.map +1 -1
- package/dist/shared/promise.js +21 -19
- package/dist/shared/promise.js.map +1 -1
- package/dist/source-mask.d.ts +9 -6
- package/dist/source-mask.d.ts.map +1 -1
- package/dist/source-mask.js +45 -63
- package/dist/source-mask.js.map +1 -1
- package/dist/spread.d.ts +5 -2
- package/dist/spread.d.ts.map +1 -1
- package/dist/spread.js +79 -99
- package/dist/spread.js.map +1 -1
- package/dist/state-slot.d.ts +18 -15
- package/dist/state-slot.d.ts.map +1 -1
- package/dist/state-slot.js +43 -42
- package/dist/state-slot.js.map +1 -1
- package/dist/testing.d.ts +9 -6
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +16 -12
- package/dist/testing.js.map +1 -1
- package/package.json +8 -7
- package/src/actions.ts +415 -0
- package/src/async.ts +78 -0
- package/src/compiled/async-resource.ts +113 -0
- package/src/compiled/core.ts +4041 -0
- package/src/compiled/types.ts +96 -0
- package/src/compiled/validation.ts +23 -0
- package/src/component-spread.ts +86 -0
- package/src/concurrent.ts +310 -0
- package/src/direct-dom.ts +365 -0
- package/src/dom/attributes.ts +55 -0
- package/src/dom/events.ts +93 -0
- package/src/dom/forms.ts +220 -0
- package/src/dom/intrinsic.ts +94 -0
- package/src/dom/namespace.ts +30 -0
- package/src/dom/namespaces.ts +14 -0
- package/src/dom/properties.ts +355 -0
- package/src/dom/style-properties.ts +46 -0
- package/src/dom/styles.ts +86 -0
- package/src/dom-forms.ts +23 -0
- package/src/dom-styles.ts +11 -0
- package/src/env.d.ts +6 -0
- package/src/framework-hydrate.ts +224 -0
- package/src/framework-protocol.ts +335 -0
- package/src/framework.ts +161 -0
- package/src/hydrate.ts +38 -0
- package/src/hydration-bridge.ts +196 -0
- package/src/hydration.ts +642 -0
- package/src/index.ts +92 -0
- package/src/indexed-list.ts +20 -0
- package/src/jsx-runtime.ts +55 -0
- package/src/keyed-list.ts +233 -0
- package/src/metadata.ts +212 -0
- package/src/nested-prop.ts +27 -0
- package/src/profiling.ts +43 -0
- package/src/protocol.ts +8 -0
- package/src/raw-html.ts +206 -0
- package/src/ref.ts +13 -0
- package/src/renderable-protocol.ts +63 -0
- package/src/renderable.ts +283 -0
- package/src/retained-ui.ts +19 -0
- package/src/root.ts +122 -0
- package/src/scheduler.ts +136 -0
- package/src/server-framework.ts +397 -0
- package/src/server.ts +1160 -0
- package/src/shared/promise.ts +28 -0
- package/src/source-mask.ts +83 -0
- package/src/spread.ts +131 -0
- package/src/state-slot.ts +76 -0
- package/src/testing.ts +27 -0
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/src/index.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// oxlint-disable-next-line typescript/triple-slash-reference -- Include the build define in consuming TypeScript programs.
|
|
2
|
+
/// <reference path="./env.d.ts" />
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
binding,
|
|
6
|
+
choose,
|
|
7
|
+
compiledEvent,
|
|
8
|
+
compiledEffect,
|
|
9
|
+
compiledImperativeHandle,
|
|
10
|
+
compiledInsertionEffect,
|
|
11
|
+
compiledLayoutEffect,
|
|
12
|
+
compiledRoot,
|
|
13
|
+
createCompiledContext,
|
|
14
|
+
createCompiledEffectEvent,
|
|
15
|
+
createCompiledExternalStore,
|
|
16
|
+
createCompiledId,
|
|
17
|
+
createCompiledMemo,
|
|
18
|
+
createCompiledProp,
|
|
19
|
+
createCompiledReducer,
|
|
20
|
+
createCompiledRestProp,
|
|
21
|
+
createCompiledScope,
|
|
22
|
+
createCompiledState,
|
|
23
|
+
createContext,
|
|
24
|
+
createNarrowCompiledScope,
|
|
25
|
+
createPortal,
|
|
26
|
+
deferred,
|
|
27
|
+
dispatch,
|
|
28
|
+
errorBoundary,
|
|
29
|
+
indexed,
|
|
30
|
+
keyed,
|
|
31
|
+
mountCompiled,
|
|
32
|
+
mountCompiledRef,
|
|
33
|
+
objectRest,
|
|
34
|
+
runWithCompiledContext,
|
|
35
|
+
use,
|
|
36
|
+
useCallback,
|
|
37
|
+
useContext,
|
|
38
|
+
useEffect,
|
|
39
|
+
useEffectEvent,
|
|
40
|
+
useId,
|
|
41
|
+
useImperativeHandle,
|
|
42
|
+
useInsertionEffect,
|
|
43
|
+
useLayoutEffect,
|
|
44
|
+
useMemo,
|
|
45
|
+
useSyncExternalStore,
|
|
46
|
+
when,
|
|
47
|
+
type ChoiceMode,
|
|
48
|
+
type MountCompiledOptions,
|
|
49
|
+
} from './compiled/core.ts'
|
|
50
|
+
export type {
|
|
51
|
+
CompiledBinding,
|
|
52
|
+
CompiledComponentResult,
|
|
53
|
+
CompiledContext,
|
|
54
|
+
CompiledErrorHandler,
|
|
55
|
+
CompiledRenderValue,
|
|
56
|
+
CompiledScope,
|
|
57
|
+
OwnedBlock,
|
|
58
|
+
StructuralBinding,
|
|
59
|
+
} from './compiled/types.ts'
|
|
60
|
+
export { compiledComponentSpread } from './component-spread.ts'
|
|
61
|
+
export {
|
|
62
|
+
Fragment,
|
|
63
|
+
h,
|
|
64
|
+
type DirectChild,
|
|
65
|
+
type DirectComponent,
|
|
66
|
+
type DirectProps,
|
|
67
|
+
} from './direct-dom.ts'
|
|
68
|
+
export { nestedProp } from './nested-prop.ts'
|
|
69
|
+
export { assertRuntimeProtocol, VIDACT_RUNTIME_PROTOCOL } from './protocol.ts'
|
|
70
|
+
export { createRef, useRef, type MutableRef } from './ref.ts'
|
|
71
|
+
export {
|
|
72
|
+
cloneRenderable,
|
|
73
|
+
cloneRenderableComponent,
|
|
74
|
+
createReactElement,
|
|
75
|
+
createReactElement as createElement,
|
|
76
|
+
createRenderable,
|
|
77
|
+
dynamicIntrinsicComponent,
|
|
78
|
+
forwardedRef,
|
|
79
|
+
isRenderable,
|
|
80
|
+
keyedFragmentComponent,
|
|
81
|
+
renderableChildren,
|
|
82
|
+
renderableMarker,
|
|
83
|
+
renderableProps,
|
|
84
|
+
renderableRef,
|
|
85
|
+
renderableToArray,
|
|
86
|
+
type CompiledRenderable,
|
|
87
|
+
type RenderablePropsInput,
|
|
88
|
+
} from './renderable.ts'
|
|
89
|
+
export { createRoot, mountHotRoot, type CompiledRoot, type HotContext } from './root.ts'
|
|
90
|
+
export { combineSources, intersectsSources, source, type SourceMask } from './source-mask.ts'
|
|
91
|
+
export { compiledSpread } from './spread.ts'
|
|
92
|
+
export type { StateUpdate } from './state-slot.ts'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createKeyedList, type KeyedList, type KeyedRenderResult } from './keyed-list.ts'
|
|
2
|
+
|
|
3
|
+
export interface IndexedListOptions<T> {
|
|
4
|
+
readonly render: (value: T, index: number) => KeyedRenderResult<T>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type IndexedList<T> = KeyedList<T>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Reconciles records by their current position. Existing owners are retained at
|
|
11
|
+
* an index and receive the new value at that index, matching React's unkeyed
|
|
12
|
+
* collection identity semantics.
|
|
13
|
+
*/
|
|
14
|
+
export function createIndexedList<T>(
|
|
15
|
+
parent: Node,
|
|
16
|
+
options: IndexedListOptions<T>,
|
|
17
|
+
before: Node | null = null,
|
|
18
|
+
): IndexedList<T> {
|
|
19
|
+
return createKeyedList(parent, { key: (_value, index) => index, render: options.render }, before)
|
|
20
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// oxlint-disable-next-line typescript/triple-slash-reference -- Include the build define in consuming TypeScript programs.
|
|
2
|
+
/// <reference path="./env.d.ts" />
|
|
3
|
+
|
|
4
|
+
import { h, type DirectChild, type DirectComponent } from './direct-dom.ts'
|
|
5
|
+
import {
|
|
6
|
+
isRenderableProtocol,
|
|
7
|
+
renderableCloneHandler,
|
|
8
|
+
type RenderableProtocol,
|
|
9
|
+
} from './renderable-protocol.ts'
|
|
10
|
+
import type { CompiledRenderable } from './renderable.ts'
|
|
11
|
+
|
|
12
|
+
export const Fragment: symbol = Symbol.for('vidact.v1.Fragment')
|
|
13
|
+
|
|
14
|
+
type ElementType = string | typeof Fragment | DirectComponent | CompiledRenderable
|
|
15
|
+
|
|
16
|
+
interface JsxProps extends Record<string, unknown> {
|
|
17
|
+
readonly children?: DirectChild | readonly DirectChild[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function jsx(type: ElementType, props: JsxProps | null, _key?: unknown): DirectChild {
|
|
21
|
+
if (isRenderableProtocol(type)) return cloneElementType(type, props)
|
|
22
|
+
const children = props?.children
|
|
23
|
+
const hasChildren = props !== null && Object.hasOwn(props, 'children')
|
|
24
|
+
if (!hasChildren) return h(type, props)
|
|
25
|
+
return h(type, props, children)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function jsxs(type: ElementType, props: JsxProps | null, _key?: unknown): DirectChild {
|
|
29
|
+
if (isRenderableProtocol(type)) return cloneElementType(type, props)
|
|
30
|
+
const children = props?.children
|
|
31
|
+
const hasChildren = props !== null && Object.hasOwn(props, 'children')
|
|
32
|
+
if (!hasChildren) return h(type, props)
|
|
33
|
+
return Array.isArray(children) ? h(type, props, ...children) : h(type, props, children)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function jsxDEV(
|
|
37
|
+
type: ElementType,
|
|
38
|
+
props: JsxProps | null,
|
|
39
|
+
key?: unknown,
|
|
40
|
+
isStaticChildren = false,
|
|
41
|
+
): DirectChild {
|
|
42
|
+
return isStaticChildren ? jsxs(type, props, key) : jsx(type, props, key)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A renderable can only reach `jsx` as an element type if something already
|
|
47
|
+
* built one, which is what registers the clone.
|
|
48
|
+
*/
|
|
49
|
+
function cloneElementType(type: RenderableProtocol, props: JsxProps | null): DirectChild {
|
|
50
|
+
const clone = renderableCloneHandler()
|
|
51
|
+
if (clone === undefined) {
|
|
52
|
+
throw new TypeError('V107')
|
|
53
|
+
}
|
|
54
|
+
return clone(type, props ?? {}) as DirectChild
|
|
55
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
export type KeyedItem<T> = readonly [
|
|
2
|
+
nodes: readonly Node[],
|
|
3
|
+
update?: ((value: T, index: number) => void) | undefined,
|
|
4
|
+
dispose?: (() => void) | undefined,
|
|
5
|
+
]
|
|
6
|
+
|
|
7
|
+
export type KeyedRenderResult<T> = Node | readonly Node[] | KeyedItem<T>
|
|
8
|
+
|
|
9
|
+
export interface KeyedListOptions<T, K> {
|
|
10
|
+
readonly key: (value: T, index: number) => K
|
|
11
|
+
readonly render: (value: T, index: number) => KeyedRenderResult<T>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface KeyedList<T> {
|
|
15
|
+
readonly dispose: () => void
|
|
16
|
+
readonly parent: () => Node | null
|
|
17
|
+
readonly update: (values: readonly T[]) => readonly Node[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type RecordState<T, K> = readonly [
|
|
21
|
+
key: K,
|
|
22
|
+
nodes: readonly Node[],
|
|
23
|
+
update: ((value: T, index: number) => void) | undefined,
|
|
24
|
+
dispose: (() => void) | undefined,
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
28
|
+
|
|
29
|
+
export function createKeyedList<T, K>(
|
|
30
|
+
parent: Node,
|
|
31
|
+
options: KeyedListOptions<T, K>,
|
|
32
|
+
before: Node | null = null,
|
|
33
|
+
): KeyedList<T> {
|
|
34
|
+
const hydratedRange = claimHydrationArrayRange(parent)
|
|
35
|
+
const start = hydratedRange?.[0] ?? document.createComment(DEV ? 'vidact:list' : '')
|
|
36
|
+
const end = hydratedRange?.[1] ?? document.createComment(DEV ? '/vidact:list' : '')
|
|
37
|
+
if (hydratedRange === undefined) {
|
|
38
|
+
parent.insertBefore(start, before)
|
|
39
|
+
parent.insertBefore(end, before)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let disposed = false
|
|
43
|
+
let hydrationPending = hydratedRange !== undefined
|
|
44
|
+
let records: readonly RecordState<T, K>[] = []
|
|
45
|
+
|
|
46
|
+
const update = (values: readonly T[]): readonly Node[] => {
|
|
47
|
+
if (disposed) throw new Error(DEV ? 'cannot update a disposed keyed list' : 'V801')
|
|
48
|
+
const currentParent = end.parentNode
|
|
49
|
+
if (currentParent === null || start.parentNode !== currentParent) {
|
|
50
|
+
throw new Error(DEV ? 'cannot update a detached keyed list' : 'V802')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const keys = values.map(options.key)
|
|
54
|
+
assertValidKeys(keys)
|
|
55
|
+
assertUniqueKeys(keys)
|
|
56
|
+
|
|
57
|
+
const previousByKey = new Map<K, RecordState<T, K>>()
|
|
58
|
+
for (const record of records) previousByKey.set(record[0], record)
|
|
59
|
+
const created: RecordState<T, K>[] = []
|
|
60
|
+
const retained: Array<readonly [RecordState<T, K>, T, number]> = []
|
|
61
|
+
let nextRecords: RecordState<T, K>[]
|
|
62
|
+
try {
|
|
63
|
+
nextRecords = values.map((value, index): RecordState<T, K> => {
|
|
64
|
+
const key = keys[index] as K
|
|
65
|
+
const previous = previousByKey.get(key)
|
|
66
|
+
if (previous !== undefined) {
|
|
67
|
+
previousByKey.delete(key)
|
|
68
|
+
retained.push([previous, value, index])
|
|
69
|
+
return previous
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const item = normalizeRenderResult(
|
|
73
|
+
withHydrationInsertion(parent, end, () => options.render(value, index)),
|
|
74
|
+
)
|
|
75
|
+
const record: RecordState<T, K> = [key, item[0], item[1], item[2]]
|
|
76
|
+
created.push(record)
|
|
77
|
+
return record
|
|
78
|
+
})
|
|
79
|
+
for (const [record, value, index] of retained) record[2]?.(value, index)
|
|
80
|
+
} catch (error) {
|
|
81
|
+
disposeRecords(currentParent, created)
|
|
82
|
+
throw error
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const cleanup = disposeRecords(currentParent, previousByKey.values())
|
|
86
|
+
|
|
87
|
+
const activeElement =
|
|
88
|
+
document.activeElement instanceof HTMLElement &&
|
|
89
|
+
currentParent.contains(document.activeElement)
|
|
90
|
+
? document.activeElement
|
|
91
|
+
: null
|
|
92
|
+
const selectionControl =
|
|
93
|
+
activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement
|
|
94
|
+
? activeElement
|
|
95
|
+
: null
|
|
96
|
+
const selection =
|
|
97
|
+
selectionControl === null
|
|
98
|
+
? null
|
|
99
|
+
: ([selectionControl.selectionStart, selectionControl.selectionEnd] as const)
|
|
100
|
+
let cursor: Node = end
|
|
101
|
+
for (let recordIndex = nextRecords.length - 1; recordIndex >= 0; recordIndex -= 1) {
|
|
102
|
+
const record = nextRecords[recordIndex] as RecordState<T, K>
|
|
103
|
+
for (let nodeIndex = record[1].length - 1; nodeIndex >= 0; nodeIndex -= 1) {
|
|
104
|
+
const node = record[1][nodeIndex] as Node
|
|
105
|
+
if (node.nextSibling !== cursor) moveBefore(currentParent, node, cursor)
|
|
106
|
+
cursor = node
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (
|
|
110
|
+
activeElement !== null &&
|
|
111
|
+
document.activeElement !== activeElement &&
|
|
112
|
+
currentParent.contains(activeElement)
|
|
113
|
+
) {
|
|
114
|
+
activeElement.focus({ preventScroll: true })
|
|
115
|
+
if (
|
|
116
|
+
selectionControl !== null &&
|
|
117
|
+
selection !== null &&
|
|
118
|
+
selection[0] !== null &&
|
|
119
|
+
selection[1] !== null
|
|
120
|
+
) {
|
|
121
|
+
selectionControl.setSelectionRange(selection[0], selection[1])
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
records = nextRecords
|
|
126
|
+
if (hydrationPending) {
|
|
127
|
+
hydrationPending = false
|
|
128
|
+
finishHydrationArrayRange(currentParent, end)
|
|
129
|
+
}
|
|
130
|
+
if (cleanup[1]) throw cleanup[0]
|
|
131
|
+
return created.flatMap((record) => record[1])
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const dispose = (): void => {
|
|
135
|
+
if (disposed) return
|
|
136
|
+
disposed = true
|
|
137
|
+
const currentParent = end.parentNode
|
|
138
|
+
const cleanup =
|
|
139
|
+
currentParent === null
|
|
140
|
+
? ([undefined, false] as const)
|
|
141
|
+
: disposeRecords(currentParent, records)
|
|
142
|
+
records = []
|
|
143
|
+
start.remove()
|
|
144
|
+
end.remove()
|
|
145
|
+
if (cleanup[1]) throw cleanup[0]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { dispose, parent: () => end.parentNode, update }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function moveBefore(parent: Node, node: Node, before: Node): void {
|
|
152
|
+
const statePreservingParent = parent as Node & {
|
|
153
|
+
moveBefore?: (node: Node, before: Node | null) => void
|
|
154
|
+
}
|
|
155
|
+
if (statePreservingParent.moveBefore !== undefined && node.parentNode === parent) {
|
|
156
|
+
statePreservingParent.moveBefore(node, before)
|
|
157
|
+
} else {
|
|
158
|
+
parent.insertBefore(node, before)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function assertValidKeys<K>(keys: readonly K[]): void {
|
|
163
|
+
for (const key of keys) {
|
|
164
|
+
if (typeof key !== 'string' && typeof key !== 'number' && typeof key !== 'bigint') {
|
|
165
|
+
throw new Error(DEV ? `invalid key in keyed list: ${String(key)}` : 'V803')
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function assertUniqueKeys<K>(keys: readonly K[]): void {
|
|
171
|
+
const seen = new Set<K>()
|
|
172
|
+
for (const key of keys) {
|
|
173
|
+
if (seen.has(key)) {
|
|
174
|
+
throw new Error(DEV ? `duplicate key in keyed list: ${String(key)}` : 'V804')
|
|
175
|
+
}
|
|
176
|
+
seen.add(key)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function normalizeRenderResult<T>(result: KeyedRenderResult<T>): KeyedItem<T> {
|
|
181
|
+
if (isNode(result)) return [normalizeNodes([result])]
|
|
182
|
+
if (isNodeArray(result)) return [normalizeNodes(result)]
|
|
183
|
+
return [normalizeNodes(result[0]), result[1], result[2]]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function normalizeNodes(nodes: readonly Node[]): readonly Node[] {
|
|
187
|
+
const normalized: Node[] = []
|
|
188
|
+
for (const node of nodes) {
|
|
189
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
190
|
+
normalized.push(...node.childNodes)
|
|
191
|
+
} else {
|
|
192
|
+
normalized.push(node)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return normalized.length === 0 ? [document.createComment(DEV ? 'vidact:empty' : '')] : normalized
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function isNode(value: unknown): value is Node {
|
|
199
|
+
return typeof value === 'object' && value !== null && 'nodeType' in value
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function isNodeArray<T>(value: KeyedRenderResult<T>): value is readonly Node[] {
|
|
203
|
+
return Array.isArray(value) && (value.length === 0 || isNode(value[0]))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function removeNodes(parent: Node, nodes: readonly Node[]): void {
|
|
207
|
+
for (const node of nodes) {
|
|
208
|
+
if (node.parentNode === parent) parent.removeChild(node)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function disposeRecords<T, K>(
|
|
213
|
+
parent: Node,
|
|
214
|
+
records: Iterable<RecordState<T, K>>,
|
|
215
|
+
): readonly [error: unknown, failed: boolean] {
|
|
216
|
+
let firstError: unknown
|
|
217
|
+
let failed = false
|
|
218
|
+
for (const record of records) {
|
|
219
|
+
removeNodes(parent, record[1])
|
|
220
|
+
try {
|
|
221
|
+
record[3]?.()
|
|
222
|
+
} catch (error) {
|
|
223
|
+
if (!failed) firstError = error
|
|
224
|
+
failed = true
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return [firstError, failed]
|
|
228
|
+
}
|
|
229
|
+
import {
|
|
230
|
+
claimHydrationArrayRange,
|
|
231
|
+
finishHydrationArrayRange,
|
|
232
|
+
withHydrationInsertion,
|
|
233
|
+
} from './hydration-bridge.ts'
|
package/src/metadata.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { registerCompiledCleanup } from './compiled/core.ts'
|
|
2
|
+
import {
|
|
3
|
+
LINK_IDENTITY_PROPS,
|
|
4
|
+
META_IDENTITY_ATTRIBUTES,
|
|
5
|
+
META_IDENTITY_PROPS,
|
|
6
|
+
} from './dom/attributes.ts'
|
|
7
|
+
import { applyBaseDomProp, installDomPropHandler } from './dom/properties.ts'
|
|
8
|
+
|
|
9
|
+
type MetadataEntry = {
|
|
10
|
+
readonly elements: Element[]
|
|
11
|
+
readonly baseline: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type MetadataState = {
|
|
15
|
+
readonly entries: Map<string, MetadataEntry>
|
|
16
|
+
readonly stylePrecedence: string[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type MetadataOwner = {
|
|
20
|
+
readonly element: Element
|
|
21
|
+
readonly state: MetadataState
|
|
22
|
+
entry: MetadataEntry
|
|
23
|
+
key: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const metadataByDocument = new WeakMap<Document, MetadataState>()
|
|
27
|
+
const metadataOwners = new WeakMap<Element, MetadataOwner>()
|
|
28
|
+
let propRekeyingInstalled = false
|
|
29
|
+
|
|
30
|
+
export function installFrameworkMetadataPropRekeying(): void {
|
|
31
|
+
if (propRekeyingInstalled) return
|
|
32
|
+
propRekeyingInstalled = true
|
|
33
|
+
installDomPropHandler((element, name, value) => {
|
|
34
|
+
const owner = metadataOwners.get(element)
|
|
35
|
+
if (owner === undefined || !isMetadataIdentityProp(element.localName, name)) return false
|
|
36
|
+
detachMetadataOwner(owner)
|
|
37
|
+
applyBaseDomProp(element, name, value)
|
|
38
|
+
if (name === 'precedence') {
|
|
39
|
+
element.setAttribute('data-precedence', String(value ?? 'default'))
|
|
40
|
+
element.removeAttribute('precedence')
|
|
41
|
+
}
|
|
42
|
+
attachMetadataOwner(owner)
|
|
43
|
+
return true
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isFrameworkMetadataElement(
|
|
48
|
+
element: Element,
|
|
49
|
+
props: Readonly<Record<string, unknown>> | null = null,
|
|
50
|
+
): boolean {
|
|
51
|
+
const name = element.localName
|
|
52
|
+
if (
|
|
53
|
+
(name === 'title' || name === 'meta' || name === 'link') &&
|
|
54
|
+
element.hasAttribute('itemprop')
|
|
55
|
+
) {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
if (name === 'title' || name === 'meta') return true
|
|
59
|
+
if (name === 'link') {
|
|
60
|
+
if (
|
|
61
|
+
props !== null &&
|
|
62
|
+
['onLoad', 'onError', 'disabled'].some((key) => Object.hasOwn(props, key))
|
|
63
|
+
) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
return element.getAttribute('rel') !== 'stylesheet' || element.hasAttribute('precedence')
|
|
67
|
+
}
|
|
68
|
+
if (name === 'style') return element.hasAttribute('href') && element.hasAttribute('precedence')
|
|
69
|
+
return name === 'script' && element.hasAttribute('async') && element.hasAttribute('src')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function hoistFrameworkMetadata(element: Element): DocumentFragment {
|
|
73
|
+
const document = element.ownerDocument
|
|
74
|
+
const state = metadataState(document)
|
|
75
|
+
const key = metadataKey(element)
|
|
76
|
+
const owner: MetadataOwner = {
|
|
77
|
+
element,
|
|
78
|
+
state,
|
|
79
|
+
key,
|
|
80
|
+
entry: metadataEntry(document, state, key),
|
|
81
|
+
}
|
|
82
|
+
attachMetadataOwner(owner)
|
|
83
|
+
metadataOwners.set(element, owner)
|
|
84
|
+
element.removeAttribute('precedence')
|
|
85
|
+
registerCompiledCleanup(() => {
|
|
86
|
+
detachMetadataOwner(owner)
|
|
87
|
+
metadataOwners.delete(element)
|
|
88
|
+
})
|
|
89
|
+
return document.createDocumentFragment()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function metadataState(document: Document): MetadataState {
|
|
93
|
+
let state = metadataByDocument.get(document)
|
|
94
|
+
if (state !== undefined) return state
|
|
95
|
+
state = {
|
|
96
|
+
entries: new Map(),
|
|
97
|
+
stylePrecedence: [...document.head.children]
|
|
98
|
+
.filter((candidate) => metadataTier(candidate) === 2)
|
|
99
|
+
.map(stylePrecedence)
|
|
100
|
+
.filter((value, index, values) => values.indexOf(value) === index),
|
|
101
|
+
}
|
|
102
|
+
metadataByDocument.set(document, state)
|
|
103
|
+
return state
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function metadataEntry(document: Document, state: MetadataState, key: string): MetadataEntry {
|
|
107
|
+
let entry = state.entries.get(key)
|
|
108
|
+
if (entry !== undefined) return entry
|
|
109
|
+
const existing = [...document.head.children].find(
|
|
110
|
+
(candidate) => isFrameworkMetadataElement(candidate) && metadataKey(candidate) === key,
|
|
111
|
+
)
|
|
112
|
+
entry = {
|
|
113
|
+
elements: existing === undefined ? [] : [existing],
|
|
114
|
+
baseline: existing === undefined ? 0 : 1,
|
|
115
|
+
}
|
|
116
|
+
state.entries.set(key, entry)
|
|
117
|
+
return entry
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function attachMetadataOwner(owner: MetadataOwner): void {
|
|
121
|
+
const document = owner.element.ownerDocument
|
|
122
|
+
owner.key = metadataKey(owner.element)
|
|
123
|
+
owner.entry = metadataEntry(document, owner.state, owner.key)
|
|
124
|
+
owner.entry.elements.at(-1)?.remove()
|
|
125
|
+
owner.entry.elements.push(owner.element)
|
|
126
|
+
insertByPrecedence(document.head, owner.element, owner.state)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function detachMetadataOwner(owner: MetadataOwner): void {
|
|
130
|
+
const { element, entry, key, state } = owner
|
|
131
|
+
const index = entry.elements.indexOf(element)
|
|
132
|
+
if (index === -1) return
|
|
133
|
+
const visible = index === entry.elements.length - 1
|
|
134
|
+
entry.elements.splice(index, 1)
|
|
135
|
+
element.remove()
|
|
136
|
+
if (entry.elements.length === entry.baseline) {
|
|
137
|
+
if (visible && entry.elements.length !== 0) {
|
|
138
|
+
element.ownerDocument.head.append(entry.elements.at(-1)!)
|
|
139
|
+
}
|
|
140
|
+
if (state.entries.get(key) === entry) state.entries.delete(key)
|
|
141
|
+
} else if (visible) {
|
|
142
|
+
insertByPrecedence(element.ownerDocument.head, entry.elements.at(-1)!, state)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function isMetadataIdentityProp(elementName: string, propName: string): boolean {
|
|
147
|
+
if (propName === 'precedence') return elementName === 'link' || elementName === 'style'
|
|
148
|
+
if (elementName === 'meta') {
|
|
149
|
+
return (META_IDENTITY_PROPS as readonly string[]).includes(propName)
|
|
150
|
+
}
|
|
151
|
+
if (elementName === 'link') return (LINK_IDENTITY_PROPS as readonly string[]).includes(propName)
|
|
152
|
+
if (elementName === 'script') return propName === 'src'
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function metadataKey(element: Element): string {
|
|
157
|
+
const name = element.localName
|
|
158
|
+
if (name === 'title') return 'title'
|
|
159
|
+
if (name === 'meta') {
|
|
160
|
+
for (const attribute of META_IDENTITY_ATTRIBUTES) {
|
|
161
|
+
if (element.hasAttribute(attribute))
|
|
162
|
+
return `meta:${attribute}:${element.getAttribute(attribute)}`
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (name === 'link') {
|
|
166
|
+
return `link:${element.getAttribute('rel') ?? ''}:${element.getAttribute('href') ?? ''}:${element.getAttribute('as') ?? ''}`
|
|
167
|
+
}
|
|
168
|
+
if (name === 'style') return `style:${element.getAttribute('href') ?? ''}`
|
|
169
|
+
return `script:${element.getAttribute('src') ?? ''}`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function insertByPrecedence(head: HTMLHeadElement, element: Element, state: MetadataState): void {
|
|
173
|
+
const tier = metadataTier(element) ?? 1
|
|
174
|
+
const precedence = stylePrecedence(element)
|
|
175
|
+
if (tier === 2) {
|
|
176
|
+
if (!state.stylePrecedence.includes(precedence)) state.stylePrecedence.push(precedence)
|
|
177
|
+
element.setAttribute('data-precedence', precedence)
|
|
178
|
+
}
|
|
179
|
+
const before = [...head.children].find((candidate) => {
|
|
180
|
+
const candidateTier = metadataTier(candidate)
|
|
181
|
+
if (candidateTier === undefined) return false
|
|
182
|
+
if (candidateTier !== tier) return candidateTier > tier
|
|
183
|
+
return (
|
|
184
|
+
tier === 2 &&
|
|
185
|
+
state.stylePrecedence.indexOf(stylePrecedence(candidate)) >
|
|
186
|
+
state.stylePrecedence.indexOf(precedence)
|
|
187
|
+
)
|
|
188
|
+
})
|
|
189
|
+
head.insertBefore(element, before ?? null)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function metadataTier(element: Element): number | undefined {
|
|
193
|
+
const name = element.localName
|
|
194
|
+
if (name === 'style') return element.hasAttribute('data-precedence') ? 2 : undefined
|
|
195
|
+
if (name === 'script') return element.hasAttribute('src') ? 3 : undefined
|
|
196
|
+
if (name === 'link') {
|
|
197
|
+
const relation = element.getAttribute('rel')
|
|
198
|
+
if (relation === 'stylesheet') {
|
|
199
|
+
return element.hasAttribute('precedence') || element.hasAttribute('data-precedence')
|
|
200
|
+
? 2
|
|
201
|
+
: undefined
|
|
202
|
+
}
|
|
203
|
+
if (['preconnect', 'dns-prefetch', 'preload', 'modulepreload'].includes(relation ?? ''))
|
|
204
|
+
return 0
|
|
205
|
+
return 1
|
|
206
|
+
}
|
|
207
|
+
return name === 'title' || name === 'meta' ? 1 : undefined
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function stylePrecedence(element: Element): string {
|
|
211
|
+
return element.getAttribute('precedence') ?? element.getAttribute('data-precedence') ?? 'default'
|
|
212
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { binding, isCompiledBinding } from './compiled/core.ts'
|
|
2
|
+
|
|
3
|
+
const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
|
|
4
|
+
|
|
5
|
+
type ContainerFallback = (() => unknown) | null
|
|
6
|
+
|
|
7
|
+
export function nestedProp(
|
|
8
|
+
input: unknown,
|
|
9
|
+
path: readonly string[],
|
|
10
|
+
containerFallbacks: readonly ContainerFallback[],
|
|
11
|
+
): unknown {
|
|
12
|
+
const read = (): unknown => {
|
|
13
|
+
let value = isCompiledBinding(input) ? input[1]() : input
|
|
14
|
+
for (const [index, name] of path.entries()) {
|
|
15
|
+
if (value === undefined) value = containerFallbacks[index]?.()
|
|
16
|
+
if (value === null || value === undefined) {
|
|
17
|
+
throw new TypeError(
|
|
18
|
+
DEV ? `cannot destructure nested prop ${name} from a nullish value` : 'V015',
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
value = (value as Record<string, unknown>)[name]
|
|
22
|
+
}
|
|
23
|
+
return value
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return isCompiledBinding(input) ? binding(input[2], input[3], read, input[4], input[5]) : read()
|
|
27
|
+
}
|
package/src/profiling.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
captureCompiledOwnerStack,
|
|
3
|
+
enableProfiling,
|
|
4
|
+
profiled,
|
|
5
|
+
recordCompiledDebugValue,
|
|
6
|
+
} from './compiled/core.ts'
|
|
7
|
+
import type {
|
|
8
|
+
CompiledBinding,
|
|
9
|
+
CompiledRenderValue,
|
|
10
|
+
ProfilerOnRender,
|
|
11
|
+
StructuralBinding,
|
|
12
|
+
} from './compiled/types.ts'
|
|
13
|
+
|
|
14
|
+
export interface ProfilerProps {
|
|
15
|
+
readonly children?: (() => CompiledRenderValue) | readonly [() => CompiledRenderValue]
|
|
16
|
+
readonly id: string | CompiledBinding<string>
|
|
17
|
+
readonly onRender: ProfilerOnRender | CompiledBinding<ProfilerOnRender>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function Profiler(props: ProfilerProps): StructuralBinding {
|
|
21
|
+
const render = Array.isArray(props.children) ? props.children[0] : props.children
|
|
22
|
+
if (typeof render !== 'function') {
|
|
23
|
+
throw new TypeError('Profiler children must be a compiler-generated render function')
|
|
24
|
+
}
|
|
25
|
+
enableProfiling()
|
|
26
|
+
return profiled(props.id, props.onRender, render)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function useDebugValue<Value>(
|
|
30
|
+
value: Value | CompiledBinding<Value>,
|
|
31
|
+
format?: (value: Value) => unknown,
|
|
32
|
+
): void {
|
|
33
|
+
if (format !== undefined && typeof format !== 'function') {
|
|
34
|
+
throw new TypeError('useDebugValue formatter must be a function')
|
|
35
|
+
}
|
|
36
|
+
enableProfiling()
|
|
37
|
+
recordCompiledDebugValue(value, format)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function captureOwnerStack(): string | null {
|
|
41
|
+
enableProfiling()
|
|
42
|
+
return captureCompiledOwnerStack()
|
|
43
|
+
}
|
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const VIDACT_RUNTIME_PROTOCOL = 'vidact-runtime-v2'
|
|
2
|
+
|
|
3
|
+
export function assertRuntimeProtocol(expected: string): void {
|
|
4
|
+
if (expected === VIDACT_RUNTIME_PROTOCOL) return
|
|
5
|
+
throw new Error(
|
|
6
|
+
`Vidact compiler/runtime protocol mismatch: compiled for ${expected}, runtime provides ${VIDACT_RUNTIME_PROTOCOL}`,
|
|
7
|
+
)
|
|
8
|
+
}
|