@vidact/runtime 0.2.0-beta.0 → 0.2.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +1 -1
  3. package/dist/actions.d.ts +32 -30
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +251 -266
  6. package/dist/actions.js.map +1 -1
  7. package/dist/async.d.ts +20 -17
  8. package/dist/async.d.ts.map +1 -1
  9. package/dist/async.js +18 -17
  10. package/dist/async.js.map +1 -1
  11. package/dist/compiled/async-resource.d.ts +9 -6
  12. package/dist/compiled/async-resource.d.ts.map +1 -1
  13. package/dist/compiled/async-resource.js +69 -77
  14. package/dist/compiled/async-resource.js.map +1 -1
  15. package/dist/compiled/core.d.ts +148 -147
  16. package/dist/compiled/core.d.ts.map +1 -1
  17. package/dist/compiled/core.js +3064 -2987
  18. package/dist/compiled/core.js.map +1 -1
  19. package/dist/compiled/types.d.ts +44 -56
  20. package/dist/compiled/types.d.ts.map +1 -1
  21. package/dist/compiled/types.js +10 -6
  22. package/dist/compiled/types.js.map +1 -1
  23. package/dist/compiled/validation.d.ts +4 -1
  24. package/dist/compiled/validation.d.ts.map +1 -1
  25. package/dist/compiled/validation.js +17 -20
  26. package/dist/compiled/validation.js.map +1 -1
  27. package/dist/component-spread.d.ts +5 -3
  28. package/dist/component-spread.d.ts.map +1 -1
  29. package/dist/component-spread.js +49 -67
  30. package/dist/component-spread.js.map +1 -1
  31. package/dist/concurrent.d.ts +20 -18
  32. package/dist/concurrent.d.ts.map +1 -1
  33. package/dist/concurrent.js +191 -210
  34. package/dist/concurrent.js.map +1 -1
  35. package/dist/direct-dom.d.ts +17 -12
  36. package/dist/direct-dom.d.ts.map +1 -1
  37. package/dist/direct-dom.js +279 -222
  38. package/dist/direct-dom.js.map +1 -1
  39. package/dist/dom/attributes.d.ts +9 -6
  40. package/dist/dom/attributes.d.ts.map +1 -1
  41. package/dist/dom/attributes.js +65 -47
  42. package/dist/dom/attributes.js.map +1 -1
  43. package/dist/dom/events.d.ts +8 -2
  44. package/dist/dom/events.d.ts.map +1 -1
  45. package/dist/dom/events.js +118 -65
  46. package/dist/dom/events.js.map +1 -1
  47. package/dist/dom/forms.d.ts +9 -6
  48. package/dist/dom/forms.d.ts.map +1 -1
  49. package/dist/dom/forms.js +152 -198
  50. package/dist/dom/forms.js.map +1 -1
  51. package/dist/dom/intrinsic.d.ts +17 -15
  52. package/dist/dom/intrinsic.d.ts.map +1 -1
  53. package/dist/dom/intrinsic.js +48 -50
  54. package/dist/dom/intrinsic.js.map +1 -1
  55. package/dist/dom/namespace.d.ts +4 -1
  56. package/dist/dom/namespace.d.ts.map +1 -1
  57. package/dist/dom/namespace.js +25 -28
  58. package/dist/dom/namespace.js.map +1 -1
  59. package/dist/dom/namespaces.d.ts +11 -8
  60. package/dist/dom/namespaces.d.ts.map +1 -1
  61. package/dist/dom/namespaces.js +14 -12
  62. package/dist/dom/namespaces.js.map +1 -1
  63. package/dist/dom/properties.d.ts +18 -16
  64. package/dist/dom/properties.d.ts.map +1 -1
  65. package/dist/dom/properties.js +273 -296
  66. package/dist/dom/properties.js.map +1 -1
  67. package/dist/dom/style-properties.d.ts +4 -1
  68. package/dist/dom/style-properties.d.ts.map +1 -1
  69. package/dist/dom/style-properties.js +49 -45
  70. package/dist/dom/style-properties.js.map +1 -1
  71. package/dist/dom/styles.d.ts +5 -2
  72. package/dist/dom/styles.d.ts.map +1 -1
  73. package/dist/dom/styles.js +47 -67
  74. package/dist/dom/styles.js.map +1 -1
  75. package/dist/dom-forms.d.ts +4 -1
  76. package/dist/dom-forms.d.ts.map +1 -1
  77. package/dist/dom-forms.js +16 -13
  78. package/dist/dom-forms.js.map +1 -1
  79. package/dist/dom-styles.d.ts +4 -1
  80. package/dist/dom-styles.d.ts.map +1 -1
  81. package/dist/dom-styles.js +10 -7
  82. package/dist/dom-styles.js.map +1 -1
  83. package/dist/framework-hydrate.d.ts +20 -17
  84. package/dist/framework-hydrate.d.ts.map +1 -1
  85. package/dist/framework-hydrate.js +128 -146
  86. package/dist/framework-hydrate.js.map +1 -1
  87. package/dist/framework-protocol.d.ts +27 -25
  88. package/dist/framework-protocol.d.ts.map +1 -1
  89. package/dist/framework-protocol.js +173 -211
  90. package/dist/framework-protocol.js.map +1 -1
  91. package/dist/framework.d.ts +34 -32
  92. package/dist/framework.d.ts.map +1 -1
  93. package/dist/framework.js +74 -93
  94. package/dist/framework.js.map +1 -1
  95. package/dist/hydrate.d.ts +11 -8
  96. package/dist/hydrate.d.ts.map +1 -1
  97. package/dist/hydrate.js +13 -9
  98. package/dist/hydrate.js.map +1 -1
  99. package/dist/hydration-bridge.d.ts +70 -58
  100. package/dist/hydration-bridge.d.ts.map +1 -1
  101. package/dist/hydration-bridge.js +77 -66
  102. package/dist/hydration-bridge.js.map +1 -1
  103. package/dist/hydration.d.ts +54 -28
  104. package/dist/hydration.d.ts.map +1 -1
  105. package/dist/hydration.js +450 -463
  106. package/dist/hydration.js.map +1 -1
  107. package/dist/index.d.ts +13 -13
  108. package/dist/index.js +11 -13
  109. package/dist/indexed-list.d.ts +8 -5
  110. package/dist/indexed-list.d.ts.map +1 -1
  111. package/dist/indexed-list.js +14 -7
  112. package/dist/indexed-list.js.map +1 -1
  113. package/dist/jsx-runtime.d.ts +10 -8
  114. package/dist/jsx-runtime.d.ts.map +1 -1
  115. package/dist/jsx-runtime.js +28 -23
  116. package/dist/jsx-runtime.js.map +1 -1
  117. package/dist/keyed-list.d.ts +17 -14
  118. package/dist/keyed-list.d.ts.map +1 -1
  119. package/dist/keyed-list.js +244 -161
  120. package/dist/keyed-list.js.map +1 -1
  121. package/dist/metadata.d.ts +6 -3
  122. package/dist/metadata.d.ts.map +1 -1
  123. package/dist/metadata.js +131 -164
  124. package/dist/metadata.js.map +1 -1
  125. package/dist/nested-prop.d.ts +4 -2
  126. package/dist/nested-prop.d.ts.map +1 -1
  127. package/dist/nested-prop.js +17 -16
  128. package/dist/nested-prop.js.map +1 -1
  129. package/dist/profiling.d.ts +11 -8
  130. package/dist/profiling.d.ts.map +1 -1
  131. package/dist/profiling.js +17 -17
  132. package/dist/profiling.js.map +1 -1
  133. package/dist/protocol.d.ts +5 -2
  134. package/dist/protocol.d.ts.map +1 -1
  135. package/dist/protocol.js +8 -5
  136. package/dist/protocol.js.map +1 -1
  137. package/dist/raw-html.d.ts +5 -2
  138. package/dist/raw-html.d.ts.map +1 -1
  139. package/dist/raw-html.js +86 -146
  140. package/dist/raw-html.js.map +1 -1
  141. package/dist/ref.d.ts +8 -3
  142. package/dist/ref.d.ts.map +1 -1
  143. package/dist/ref.js +10 -2
  144. package/dist/ref.js.map +1 -1
  145. package/dist/renderable-protocol.d.ts +26 -8
  146. package/dist/renderable-protocol.d.ts.map +1 -1
  147. package/dist/renderable-protocol.js +30 -9
  148. package/dist/renderable-protocol.js.map +1 -1
  149. package/dist/renderable.d.ts +28 -22
  150. package/dist/renderable.d.ts.map +1 -1
  151. package/dist/renderable.js +152 -133
  152. package/dist/renderable.js.map +1 -1
  153. package/dist/retained-ui.d.ts +9 -6
  154. package/dist/retained-ui.d.ts.map +1 -1
  155. package/dist/retained-ui.js +12 -10
  156. package/dist/retained-ui.js.map +1 -1
  157. package/dist/root.d.ts +18 -15
  158. package/dist/root.d.ts.map +1 -1
  159. package/dist/root.js +73 -85
  160. package/dist/root.js.map +1 -1
  161. package/dist/scheduler.d.ts +10 -8
  162. package/dist/scheduler.d.ts.map +1 -1
  163. package/dist/scheduler.js +97 -105
  164. package/dist/scheduler.js.map +1 -1
  165. package/dist/server-framework.d.ts +45 -42
  166. package/dist/server-framework.d.ts.map +1 -1
  167. package/dist/server-framework.js +209 -217
  168. package/dist/server-framework.js.map +1 -1
  169. package/dist/server.d.ts +130 -128
  170. package/dist/server.d.ts.map +1 -1
  171. package/dist/server.js +603 -710
  172. package/dist/server.js.map +1 -1
  173. package/dist/shared/promise.d.ts +6 -3
  174. package/dist/shared/promise.d.ts.map +1 -1
  175. package/dist/shared/promise.js +21 -19
  176. package/dist/shared/promise.js.map +1 -1
  177. package/dist/source-mask.d.ts +10 -6
  178. package/dist/source-mask.d.ts.map +1 -1
  179. package/dist/source-mask.js +60 -63
  180. package/dist/source-mask.js.map +1 -1
  181. package/dist/spread.d.ts +5 -2
  182. package/dist/spread.d.ts.map +1 -1
  183. package/dist/spread.js +79 -99
  184. package/dist/spread.js.map +1 -1
  185. package/dist/state-slot.d.ts +29 -15
  186. package/dist/state-slot.d.ts.map +1 -1
  187. package/dist/state-slot.js +73 -42
  188. package/dist/state-slot.js.map +1 -1
  189. package/dist/testing.d.ts +9 -6
  190. package/dist/testing.d.ts.map +1 -1
  191. package/dist/testing.js +16 -12
  192. package/dist/testing.js.map +1 -1
  193. package/package.json +8 -7
  194. package/src/actions.ts +415 -0
  195. package/src/async.ts +78 -0
  196. package/src/compiled/async-resource.ts +113 -0
  197. package/src/compiled/core.ts +4647 -0
  198. package/src/compiled/types.ts +96 -0
  199. package/src/compiled/validation.ts +23 -0
  200. package/src/component-spread.ts +86 -0
  201. package/src/concurrent.ts +310 -0
  202. package/src/direct-dom.ts +491 -0
  203. package/src/dom/attributes.ts +55 -0
  204. package/src/dom/events.ts +179 -0
  205. package/src/dom/forms.ts +220 -0
  206. package/src/dom/intrinsic.ts +94 -0
  207. package/src/dom/namespace.ts +30 -0
  208. package/src/dom/namespaces.ts +14 -0
  209. package/src/dom/properties.ts +355 -0
  210. package/src/dom/style-properties.ts +46 -0
  211. package/src/dom/styles.ts +86 -0
  212. package/src/dom-forms.ts +23 -0
  213. package/src/dom-styles.ts +11 -0
  214. package/src/env.d.ts +6 -0
  215. package/src/framework-hydrate.ts +224 -0
  216. package/src/framework-protocol.ts +335 -0
  217. package/src/framework.ts +161 -0
  218. package/src/hydrate.ts +38 -0
  219. package/src/hydration-bridge.ts +202 -0
  220. package/src/hydration.ts +644 -0
  221. package/src/index.ts +94 -0
  222. package/src/indexed-list.ts +20 -0
  223. package/src/jsx-runtime.ts +55 -0
  224. package/src/keyed-list.ts +379 -0
  225. package/src/metadata.ts +212 -0
  226. package/src/nested-prop.ts +27 -0
  227. package/src/profiling.ts +43 -0
  228. package/src/protocol.ts +8 -0
  229. package/src/raw-html.ts +206 -0
  230. package/src/ref.ts +13 -0
  231. package/src/renderable-protocol.ts +63 -0
  232. package/src/renderable.ts +313 -0
  233. package/src/retained-ui.ts +19 -0
  234. package/src/root.ts +122 -0
  235. package/src/scheduler.ts +136 -0
  236. package/src/server-framework.ts +397 -0
  237. package/src/server.ts +1160 -0
  238. package/src/shared/promise.ts +28 -0
  239. package/src/source-mask.ts +103 -0
  240. package/src/spread.ts +131 -0
  241. package/src/state-slot.ts +132 -0
  242. package/src/testing.ts +27 -0
  243. package/dist/index.d.ts.map +0 -1
  244. package/dist/index.js.map +0 -1
@@ -0,0 +1,4647 @@
1
+ import { COMPILED_DELEGATED_EVENT_INVOKE, retainCompiledEventRoot } from '../dom/events.ts'
2
+ import {
3
+ currentIntrinsicNamespace,
4
+ withIntrinsicNamespace,
5
+ type IntrinsicNamespace,
6
+ } from '../dom/intrinsic.ts'
7
+ import {
8
+ HydrationMismatch,
9
+ beginHydration,
10
+ borrowHydrationSlotRange,
11
+ claimHydrationArrayRange,
12
+ claimHydrationComponentMount,
13
+ claimHydrationComponentRange,
14
+ claimHydrationNode,
15
+ claimHydrationSlotRange,
16
+ claimHydrationSuspenseFallback,
17
+ claimHydrationText,
18
+ claimHydrationTextRange,
19
+ hydrationRangeParent,
20
+ hydrationRootMarkers,
21
+ finishHydration,
22
+ finishHydrationArrayRange,
23
+ hydrationCursor,
24
+ hydrationFragmentChildren,
25
+ hydrationInsertionPoint,
26
+ isHydrating,
27
+ isHydrationMismatch,
28
+ noteHydrationStructuralParent,
29
+ skipHydrationRange,
30
+ withoutHydration,
31
+ withHydrationComponentRange,
32
+ withHydrationInsertion,
33
+ withHydrationCursor,
34
+ } from '../hydration-bridge.ts'
35
+ import { createIndexedList } from '../indexed-list.ts'
36
+ import { createKeyedList } from '../keyed-list.ts'
37
+ import {
38
+ canReconcileRenderable,
39
+ isRenderableProtocol,
40
+ materializeRenderable,
41
+ materializeRenderableWithInput,
42
+ RENDERABLE,
43
+ renderableIdentity,
44
+ renderablePropsSnapshot,
45
+ type RenderableProtocol,
46
+ } from '../renderable-protocol.ts'
47
+ import { scheduleDeferredTask, scheduleTask, type CancelScheduledTask } from '../scheduler.ts'
48
+ import {
49
+ forEachSource,
50
+ intersectsSources,
51
+ isEmptySources,
52
+ unionSources,
53
+ type SourceMask,
54
+ } from '../source-mask.ts'
55
+ import {
56
+ createReadOnlyStateSlot,
57
+ createStateSlot,
58
+ replaceReadOnlyStateSlot,
59
+ type ReadOnlyStateCell,
60
+ type StateSlot,
61
+ } from '../state-slot.ts'
62
+ import { isSuspension, subscribeResource, useAsync } from './async-resource.ts'
63
+ import {
64
+ BINDING,
65
+ COMPONENT_SPREAD_SOURCE as componentSpreadSourceSymbol,
66
+ CONTEXT,
67
+ STRUCTURAL,
68
+ type AsyncResource,
69
+ type CompiledBinding,
70
+ type CompiledComponentResult,
71
+ type CompiledContext,
72
+ type CompiledErrorHandler,
73
+ type CompiledRenderValue,
74
+ type CompiledScope,
75
+ type ProfilerOnRender,
76
+ type StructuralBinding,
77
+ } from './types.ts'
78
+ import { hasInvalidChild } from './validation.ts'
79
+
80
+ export const COMPONENT_SPREAD_SOURCE = componentSpreadSourceSymbol
81
+
82
+ const MAX_FLUSH_PASSES = 100
83
+ export const DEV = typeof __VIDACT_DEV__ === 'undefined' || __VIDACT_DEV__
84
+ let retainedUiEnabled = typeof __VIDACT_RETAINED_UI__ !== 'undefined' && __VIDACT_RETAINED_UI__
85
+ let profilingEnabled = false
86
+ let activeOwnerCount = 0
87
+ let createdOwnerCount = 0
88
+ let createdUpdaterCount = 0
89
+ let createdSchedulerPlanCount = 0
90
+ const noop = (): void => {}
91
+ const COMPILED_EVENT_HANDLER = Symbol('vidact.compiled-event')
92
+ const COMPILED_INLINE_EVENT_OWNER = Symbol('vidact.compiled-event.owner')
93
+ const UNSET_BINDING = Symbol(DEV ? 'Vidact.UnsetBinding' : undefined)
94
+
95
+ type CompiledEventHandler = ((...arguments_: never[]) => void) & {
96
+ [COMPILED_EVENT_HANDLER]: true
97
+ }
98
+
99
+ type CompiledInlineEventHandler<Arguments extends unknown[]> = ((
100
+ ...arguments_: Arguments
101
+ ) => void) & {
102
+ [COMPILED_INLINE_EVENT_OWNER]: Owner
103
+ [COMPILED_DELEGATED_EVENT_INVOKE]: (...arguments_: Arguments) => void
104
+ }
105
+
106
+ type CompiledEventMetadata = {
107
+ [COMPILED_EVENT_HANDLER]?: true
108
+ [COMPILED_DELEGATED_EVENT_INVOKE]?: (...arguments_: never[]) => void
109
+ }
110
+
111
+ type ContextFrame = {
112
+ readonly context: CompiledContext<unknown>
113
+ readonly input: unknown
114
+ readonly parent: ContextFrame | null
115
+ readonly owner: Owner | null
116
+ }
117
+
118
+ type ErrorBoundaryHandler = {
119
+ readonly handle: (error: unknown) => void
120
+ readonly parent: ErrorBoundaryHandler | null
121
+ }
122
+
123
+ type RootIdentity = {
124
+ mounted: boolean
125
+ nextId: number
126
+ readonly prefix: string
127
+ readonly onCaughtError: CompiledErrorHandler | undefined
128
+ readonly onUncaughtError: CompiledErrorHandler | undefined
129
+ }
130
+
131
+ type PortalPublication = readonly [commit: () => void, rollback: () => void]
132
+
133
+ type Owner = [
134
+ disposed: boolean,
135
+ cleanups: Array<() => void>,
136
+ context: ContextFrame | null,
137
+ rootIdentity: RootIdentity,
138
+ errorBoundary: ErrorBoundaryHandler | null,
139
+ retainedConnection?: RetainedConnection | null,
140
+ profileContext?: ProfileContext | null,
141
+ debugName?: string | null,
142
+ ]
143
+
144
+ type DebugOwnerFrame = {
145
+ readonly name: string
146
+ readonly parent: DebugOwnerFrame | null
147
+ readonly values: unknown[]
148
+ }
149
+
150
+ type ProfileContext = {
151
+ readonly frame: DebugOwnerFrame | null
152
+ readonly boundary: ProfileBoundary | null
153
+ }
154
+
155
+ type ProfileBoundary = {
156
+ readonly parent: ProfileBoundary | null
157
+ id: string
158
+ onRender: ProfilerOnRender
159
+ baseDuration: number
160
+ mounted: boolean
161
+ pendingDuration: number
162
+ pendingStart: number
163
+ scheduled: boolean
164
+ }
165
+
166
+ type RetainedResource = {
167
+ readonly owner: Owner
168
+ readonly connect: () => void
169
+ readonly disconnect: () => void
170
+ active: boolean
171
+ connected: boolean
172
+ disposed: boolean
173
+ readonly phase: number
174
+ }
175
+
176
+ type FlushTask = (() => void) | { readonly [1]: (sources?: SourceMask) => void }
177
+
178
+ type RetainedConnection = {
179
+ readonly parent: RetainedConnection | null
180
+ readonly children: Set<RetainedConnection>
181
+ readonly resources: Set<RetainedResource>
182
+ readonly deferredFlushes: Map<FlushTask, CancelScheduledTask>
183
+ readonly afterFlush: Set<() => void>
184
+ visible: boolean
185
+ connected: boolean
186
+ disposed: boolean
187
+ }
188
+
189
+ type CompiledUpdater = [
190
+ reads: SourceMask,
191
+ writes: SourceMask | undefined,
192
+ run: (active: SourceMask) => void,
193
+ active: boolean,
194
+ ]
195
+
196
+ type SourceOperations = readonly [
197
+ empty: (mask: SourceMask) => boolean,
198
+ intersects: (left: SourceMask, right: SourceMask) => boolean,
199
+ union: (left: SourceMask, right: SourceMask) => SourceMask,
200
+ visit: (mask: SourceMask, visitor: (index: number) => void) => void,
201
+ ]
202
+
203
+ const wideSourceOperations: SourceOperations = [
204
+ isEmptySources,
205
+ intersectsSources,
206
+ unionSources,
207
+ forEachSource,
208
+ ]
209
+ const narrowSourceOperations: SourceOperations = [
210
+ (mask) => mask === 0,
211
+ (left, right) => ((left as number) & (right as number)) !== 0,
212
+ (left, right) => ((left as number) | (right as number)) >>> 0,
213
+ (mask, visitor) => forEachSource(mask, visitor),
214
+ ]
215
+
216
+ type RenderValue = CompiledRenderValue
217
+
218
+ export function deferred(render: () => CompiledRenderValue): StructuralBinding {
219
+ return [
220
+ STRUCTURAL,
221
+ (parent, before) => {
222
+ const value = render()
223
+ if (ownedStructuralBinding(value)?.[2] === 'slot') {
224
+ insertValue(parent, value, before)
225
+ return
226
+ }
227
+ const hydrated = borrowHydrationSlotRange(parent, true)
228
+ if (hydrated === undefined) {
229
+ insertValue(parent, value, before)
230
+ return
231
+ }
232
+ claimHydrationSlotRange(parent)
233
+ insertValue(parent, value, hydrated[1])
234
+ },
235
+ 'slot',
236
+ ]
237
+ }
238
+
239
+ /** @internal */
240
+ export function retainedActivity(
241
+ modeInput: 'visible' | 'hidden' | CompiledBinding<'visible' | 'hidden'>,
242
+ render: () => CompiledRenderValue,
243
+ ): StructuralBinding {
244
+ const context = activeContextFrame ?? activeOwner?.[2] ?? null
245
+ const rootIdentity = activeOwner?.[3] ?? activeRootIdentity
246
+ if (rootIdentity === null) {
247
+ throw new Error(DEV ? 'Activity must run during compiled root construction' : 'V033')
248
+ }
249
+ const parentErrorBoundary = activeOwner?.[4] ?? null
250
+ const parentConnection = activeOwner?.[5] ?? null
251
+ let mounted = false
252
+ return [
253
+ STRUCTURAL,
254
+ (parent, before) => {
255
+ if (mounted) throw new Error(DEV ? 'compiled Activity is already mounted' : 'V008')
256
+ mounted = true
257
+ const lifetimeOwner = activeOwner
258
+ if (lifetimeOwner === null) {
259
+ throw new Error(DEV ? 'Activity must mount inside an owned compiled root' : 'V033')
260
+ }
261
+ const readMode = (): 'visible' | 'hidden' =>
262
+ validateActivityMode(isCompiledBinding(modeInput) ? modeInput[1]() : modeInput)
263
+ let currentMode = readMode()
264
+ const connection = createRetainedConnection(parentConnection, currentMode === 'visible')
265
+ const childOwner = createOwner(context, rootIdentity, parentErrorBoundary, connection)
266
+ const hydratedRange = claimHydrationSlotRange(parent)
267
+ const start = hydratedRange?.[0] ?? document.createComment(DEV ? 'vidact:activity' : '')
268
+ const end = hydratedRange?.[1] ?? document.createComment(DEV ? '/vidact:activity' : '')
269
+ if (hydratedRange === undefined) {
270
+ parent.insertBefore(start, before)
271
+ parent.insertBefore(end, before)
272
+ }
273
+ const currentParent = rangeParent(start, end, 'Activity boundary')
274
+ const hiddenDisplays = new Map<Element, readonly [string, string]>()
275
+ const hiddenTexts = new Map<Text, Comment>()
276
+ const heldText = document.createDocumentFragment()
277
+ let restoreHydratedDisplays = hydratedRange !== undefined && currentMode === 'hidden'
278
+
279
+ const conceal = (): void => {
280
+ for (const node of nodesBetween(start, end)) {
281
+ if (node instanceof Element && 'style' in node) {
282
+ const styled = node as HTMLElement | SVGElement
283
+ const previous = hiddenDisplays.get(node)
284
+ const hydratedDisplay = restoreHydratedDisplays
285
+ ? readServerHiddenDisplay(node)
286
+ : undefined
287
+ if (previous === undefined && hydratedDisplay !== undefined) {
288
+ hiddenDisplays.set(node, hydratedDisplay)
289
+ } else if (
290
+ previous === undefined ||
291
+ styled.style.display !== 'none' ||
292
+ styled.style.getPropertyPriority('display') !== 'important'
293
+ ) {
294
+ hiddenDisplays.set(node, [
295
+ styled.style.display,
296
+ styled.style.getPropertyPriority('display'),
297
+ ])
298
+ }
299
+ styled.style.setProperty('display', 'none', 'important')
300
+ } else if (node instanceof Text && !hiddenTexts.has(node)) {
301
+ const placeholder = document.createComment(DEV ? 'vidact:activity-text' : '')
302
+ node.replaceWith(placeholder)
303
+ heldText.append(node)
304
+ hiddenTexts.set(node, placeholder)
305
+ }
306
+ }
307
+ restoreHydratedDisplays = false
308
+ }
309
+ const reveal = (): void => {
310
+ for (const [element, [display, priority]] of hiddenDisplays) {
311
+ const styled = element as HTMLElement | SVGElement
312
+ if (display === '') styled.style.removeProperty('display')
313
+ else styled.style.setProperty('display', display, priority)
314
+ }
315
+ hiddenDisplays.clear()
316
+ for (const [text, placeholder] of hiddenTexts) {
317
+ if (placeholder.parentNode !== null) placeholder.replaceWith(text)
318
+ }
319
+ hiddenTexts.clear()
320
+ }
321
+ const setMode = (nextMode: 'visible' | 'hidden'): void => {
322
+ if (nextMode === currentMode) return
323
+ currentMode = nextMode
324
+ if (nextMode === 'hidden') {
325
+ connection.visible = false
326
+ updateRetainedConnection(connection)
327
+ conceal()
328
+ } else {
329
+ reveal()
330
+ connection.visible = true
331
+ updateRetainedConnection(connection)
332
+ concealDisconnectedDescendants(connection)
333
+ }
334
+ }
335
+
336
+ connection.afterFlush.add(conceal)
337
+ let stagedNodes: readonly Node[] = []
338
+ try {
339
+ const [fragment, nodes] =
340
+ hydratedRange === undefined
341
+ ? stageRender(render, childOwner)
342
+ : withHydrationInsertion(currentParent, end, () => stageRender(render, childOwner))
343
+ stagedNodes = nodes
344
+ currentParent.insertBefore(fragment, end)
345
+ if (currentMode === 'hidden') conceal()
346
+ commitPublishedNodes(nodes)
347
+ } catch (error) {
348
+ disposePublished(childOwner, stagedNodes)
349
+ disposeRetainedConnection(connection)
350
+ throw error
351
+ }
352
+ const removeModeUpdater = isCompiledBinding(modeInput)
353
+ ? subscribeBinding(modeInput, () => setMode(readMode()))
354
+ : noop
355
+ onCleanup(() => {
356
+ removeModeUpdater()
357
+ reveal()
358
+ try {
359
+ disposeRange(childOwner, start, end)
360
+ } finally {
361
+ disposeRetainedConnection(connection)
362
+ start.remove()
363
+ end.remove()
364
+ }
365
+ })
366
+ },
367
+ 'slot',
368
+ ]
369
+ }
370
+
371
+ /** @internal */
372
+ export function enableRetainedUi(): void {
373
+ retainedUiEnabled = true
374
+ }
375
+
376
+ /** @internal */
377
+ export function enableProfiling(): void {
378
+ profilingEnabled = DEV
379
+ }
380
+
381
+ /** @internal */
382
+ export function profiled(
383
+ idInput: string | CompiledBinding<string>,
384
+ onRenderInput: ProfilerOnRender | CompiledBinding<ProfilerOnRender>,
385
+ render: () => CompiledRenderValue,
386
+ ): StructuralBinding {
387
+ if (!DEV) return deferred(render)
388
+ const context = activeContextFrame ?? activeOwner?.[2] ?? null
389
+ const rootIdentity = activeOwner?.[3] ?? activeRootIdentity
390
+ if (rootIdentity === null) {
391
+ throw new Error(DEV ? 'Profiler must run during compiled root construction' : 'V035')
392
+ }
393
+ const parentErrorBoundary = activeOwner?.[4] ?? null
394
+ const parentConnection = activeOwner?.[5] ?? null
395
+ const parentProfile = activeOwner?.[6] ?? null
396
+ let mounted = false
397
+ return [
398
+ STRUCTURAL,
399
+ (parent, before) => {
400
+ if (mounted) throw new Error(DEV ? 'compiled Profiler is already mounted' : 'V008')
401
+ mounted = true
402
+ const readId = (): string => {
403
+ const id = isCompiledBinding(idInput) ? idInput[1]() : idInput
404
+ if (typeof id !== 'string') throw new TypeError('Profiler id must be a string')
405
+ return id
406
+ }
407
+ const readOnRender = (): ProfilerOnRender => {
408
+ const onRender = isCompiledBinding(onRenderInput) ? onRenderInput[1]() : onRenderInput
409
+ if (typeof onRender !== 'function') {
410
+ throw new TypeError('Profiler onRender must be a function')
411
+ }
412
+ return onRender
413
+ }
414
+ const boundary: ProfileBoundary = {
415
+ parent: parentProfile?.boundary ?? null,
416
+ id: readId(),
417
+ onRender: readOnRender(),
418
+ baseDuration: 0,
419
+ mounted: false,
420
+ pendingDuration: 0,
421
+ pendingStart: 0,
422
+ scheduled: false,
423
+ }
424
+ const childOwner = createOwner(context, rootIdentity, parentErrorBoundary, parentConnection, {
425
+ frame: parentProfile?.frame ?? null,
426
+ boundary,
427
+ })
428
+ const hydratedRange = claimHydrationSlotRange(parent)
429
+ const start = hydratedRange?.[0] ?? document.createComment(DEV ? 'vidact:profiler' : '')
430
+ const end = hydratedRange?.[1] ?? document.createComment(DEV ? '/vidact:profiler' : '')
431
+ if (hydratedRange === undefined) {
432
+ parent.insertBefore(start, before)
433
+ parent.insertBefore(end, before)
434
+ }
435
+ const currentParent = rangeParent(start, end, 'Profiler boundary')
436
+ let stagedNodes: readonly Node[] = []
437
+ const started = profileNow()
438
+ try {
439
+ const [fragment, nodes] =
440
+ hydratedRange === undefined
441
+ ? stageRender(render, childOwner)
442
+ : withHydrationInsertion(currentParent, end, () => stageRender(render, childOwner))
443
+ stagedNodes = nodes
444
+ currentParent.insertBefore(fragment, end)
445
+ commitPublishedNodes(nodes)
446
+ } catch (error) {
447
+ disposePublished(childOwner, stagedNodes)
448
+ throw error
449
+ }
450
+ const finished = profileNow()
451
+ boundary.baseDuration = finished - started
452
+ boundary.mounted = true
453
+ emitProfileMeasure(childOwner, 'range', started, finished)
454
+ runOwnerTask(childOwner, () =>
455
+ boundary.onRender(
456
+ boundary.id,
457
+ 'mount',
458
+ boundary.baseDuration,
459
+ boundary.baseDuration,
460
+ started,
461
+ finished,
462
+ ),
463
+ )
464
+ const removeIdUpdater = isCompiledBinding(idInput)
465
+ ? subscribeBinding(idInput, () => {
466
+ boundary.id = readId()
467
+ })
468
+ : noop
469
+ const removeCallbackUpdater = isCompiledBinding(onRenderInput)
470
+ ? subscribeBinding(onRenderInput, () => {
471
+ boundary.onRender = readOnRender()
472
+ })
473
+ : noop
474
+ onCleanup(() => {
475
+ removeCallbackUpdater()
476
+ removeIdUpdater()
477
+ disposeRange(childOwner, start, end)
478
+ })
479
+ },
480
+ 'slot',
481
+ ]
482
+ }
483
+
484
+ /** @internal */
485
+ export function recordCompiledDebugValue<Value>(
486
+ valueInput: Value | CompiledBinding<Value>,
487
+ format?: (value: Value) => unknown,
488
+ ): void {
489
+ if (!profilingEnabled) return
490
+ const owner = activeConstructionOwner ?? activeOwner
491
+ if (owner === null) {
492
+ throw new Error(DEV ? 'useDebugValue must run inside a compiled component' : 'V036')
493
+ }
494
+ const frame = ensureProfileContext(owner).frame
495
+ if (frame === null) {
496
+ throw new Error(DEV ? 'useDebugValue must run inside a compiled component' : 'V036')
497
+ }
498
+ const read = (): unknown => {
499
+ const value = isCompiledBinding(valueInput) ? valueInput[1]() : valueInput
500
+ return format === undefined ? value : format(value)
501
+ }
502
+ const index = frame.values.length
503
+ frame.values.push(read())
504
+ if (isCompiledBinding(valueInput)) {
505
+ const remove = subscribeBinding(valueInput, () => {
506
+ frame.values[index] = read()
507
+ })
508
+ owner[1].push(remove)
509
+ }
510
+ }
511
+
512
+ /** @internal */
513
+ export function captureCompiledOwnerStack(): string | null {
514
+ if (!profilingEnabled) return null
515
+ const owner = activeConstructionOwner ?? activeOwner
516
+ let frame = owner === null ? null : ensureProfileContext(owner).frame
517
+ if (frame === null) return null
518
+ const lines: string[] = []
519
+ while (frame !== null) {
520
+ const values = frame.values.length === 0 ? '' : ` [${frame.values.map(String).join(', ')}]`
521
+ lines.push(`\n at ${frame.name}${values}`)
522
+ frame = frame.parent
523
+ }
524
+ return lines.join('')
525
+ }
526
+
527
+ function validateActivityMode(mode: unknown): 'visible' | 'hidden' {
528
+ if (mode === 'visible' || mode === 'hidden') return mode
529
+ throw new TypeError(DEV ? 'Activity mode must be "visible" or "hidden"' : 'V034')
530
+ }
531
+
532
+ function readServerHiddenDisplay(element: Element): readonly [string, string] | undefined {
533
+ const cssText = element.getAttribute('style')
534
+ const hiddenDeclaration = 'display:none!important'
535
+ if (cssText === null || !cssText.endsWith(hiddenDeclaration)) return undefined
536
+ let authoredCssText = cssText.slice(0, -hiddenDeclaration.length)
537
+ if (authoredCssText.endsWith(';')) authoredCssText = authoredCssText.slice(0, -1)
538
+ const style = document.createElement('div').style
539
+ style.cssText = authoredCssText
540
+ return [style.display, style.getPropertyPriority('display')]
541
+ }
542
+
543
+ export function errorBoundary(
544
+ render: () => CompiledRenderValue,
545
+ fallback: (error: unknown, reset: () => void) => CompiledRenderValue,
546
+ onError?: CompiledErrorHandler,
547
+ ): StructuralBinding {
548
+ const context = activeContextFrame ?? activeOwner?.[2] ?? null
549
+ const rootIdentity = activeOwner?.[3] ?? activeRootIdentity
550
+ if (rootIdentity === null) {
551
+ throw new Error(DEV ? 'errorBoundary must run during compiled root construction' : 'V028')
552
+ }
553
+ const parentBoundary = activeOwner?.[4] ?? null
554
+ let mounted = false
555
+ return [
556
+ STRUCTURAL,
557
+ (parent, before) => {
558
+ if (mounted) throw new Error(DEV ? 'compiled error boundary is already mounted' : 'V008')
559
+ mounted = true
560
+ const hydratedRange = claimHydrationSlotRange(parent)
561
+ const start = hydratedRange?.[0] ?? document.createComment(DEV ? 'vidact:error' : '')
562
+ const end = hydratedRange?.[1] ?? document.createComment(DEV ? '/vidact:error' : '')
563
+ if (hydratedRange === undefined) {
564
+ parent.insertBefore(start, before)
565
+ parent.insertBefore(end, before)
566
+ }
567
+ let currentOwner: Owner | null = null
568
+ let currentNodes: readonly Node[] = []
569
+ let failed = false
570
+
571
+ const publish = (
572
+ read: () => CompiledRenderValue,
573
+ boundary: ErrorBoundaryHandler | null,
574
+ ): void => {
575
+ const currentParent = rangeParent(start, end, 'error boundary')
576
+ const nextOwner = createOwner(context, rootIdentity, boundary)
577
+ const [fragment, nodes] =
578
+ hydratedRange === undefined
579
+ ? stageRender(read, nextOwner)
580
+ : withHydrationInsertion(currentParent, end, () => stageRender(read, nextOwner))
581
+ try {
582
+ currentParent.insertBefore(fragment, end)
583
+ commitPublishedNodes(nodes)
584
+ } catch (error) {
585
+ disposePublished(nextOwner, nodes)
586
+ throw error
587
+ }
588
+ const previousOwner = currentOwner
589
+ const previousNodes = currentNodes
590
+ currentOwner = nextOwner
591
+ currentNodes = nodes
592
+ disposePublished(previousOwner, previousNodes)
593
+ }
594
+
595
+ const reset = (): void => {
596
+ if (!failed) return
597
+ try {
598
+ failed = false
599
+ publish(render, boundary)
600
+ } catch (error) {
601
+ recover(error)
602
+ }
603
+ }
604
+ const recover = (error: unknown): void => {
605
+ failed = true
606
+ publish(() => fallback(error, reset), parentBoundary)
607
+ onError?.(error)
608
+ rootIdentity.onCaughtError?.(error)
609
+ }
610
+ const boundary: ErrorBoundaryHandler = { handle: recover, parent: parentBoundary }
611
+
612
+ try {
613
+ publish(render, boundary)
614
+ } catch (error) {
615
+ recover(error)
616
+ }
617
+ onCleanup(() => {
618
+ try {
619
+ disposePublished(currentOwner, currentNodes)
620
+ } finally {
621
+ start.remove()
622
+ end.remove()
623
+ }
624
+ })
625
+ },
626
+ 'slot',
627
+ ]
628
+ }
629
+
630
+ export function suspense(
631
+ render: () => CompiledRenderValue,
632
+ fallback: () => CompiledRenderValue,
633
+ ): StructuralBinding {
634
+ const context = activeContextFrame ?? activeOwner?.[2] ?? null
635
+ const rootIdentity = activeOwner?.[3] ?? activeRootIdentity
636
+ if (rootIdentity === null) {
637
+ throw new Error(DEV ? 'Suspense must run during compiled root construction' : 'V032')
638
+ }
639
+ const parentErrorBoundary = activeOwner?.[4] ?? null
640
+ let mounted = false
641
+ return [
642
+ STRUCTURAL,
643
+ (parent, before) => {
644
+ if (mounted) throw new Error(DEV ? 'compiled Suspense boundary is already mounted' : 'V008')
645
+ mounted = true
646
+ const lifetimeOwner = activeOwner
647
+ if (lifetimeOwner === null) {
648
+ throw new Error(DEV ? 'Suspense must mount inside an owned compiled root' : 'V032')
649
+ }
650
+ const hydratedRange = claimHydrationSlotRange(parent)
651
+ const start = hydratedRange?.[0] ?? document.createComment(DEV ? 'vidact:suspense' : '')
652
+ const end = hydratedRange?.[1] ?? document.createComment(DEV ? '/vidact:suspense' : '')
653
+ if (hydratedRange === undefined) {
654
+ parent.insertBefore(start, before)
655
+ parent.insertBefore(end, before)
656
+ }
657
+ const pendingMarker =
658
+ hydratedRange === undefined ? undefined : claimHydrationSuspenseFallback(parent)
659
+ let currentOwner: Owner | null = null
660
+ let currentNodes: readonly Node[] = []
661
+ let currentKind: 'content' | 'fallback' | null = null
662
+ let removeResourceListener = noop
663
+ let generation = 0
664
+ let boundary: ErrorBoundaryHandler
665
+ // Server content is on screen but the client suspended while hydrating it (a lazy
666
+ // chunk still loading, say). The server nodes are kept until the next publish,
667
+ // which renders client-side and replaces them — the same shape as a claimed
668
+ // pending fallback, without ever showing the fallback over content the visitor
669
+ // can already see.
670
+ let dehydrated = false
671
+
672
+ const publish = (
673
+ read: () => CompiledRenderValue,
674
+ kind: 'content' | 'fallback',
675
+ replaceServerNodes = false,
676
+ ): void => {
677
+ const currentParent = rangeParent(start, end, 'Suspense boundary')
678
+ const nextOwner = createOwner(
679
+ context,
680
+ rootIdentity,
681
+ kind === 'content' ? boundary : parentErrorBoundary,
682
+ )
683
+ const serverNodes = replaceServerNodes ? nodesBetween(start, end) : []
684
+ const [fragment, nodes] = replaceServerNodes
685
+ ? withoutHydration(() => stageRender(read, nextOwner))
686
+ : hydratedRange === undefined || currentKind !== null
687
+ ? stageRender(read, nextOwner)
688
+ : withHydrationInsertion(currentParent, end, () => stageRender(read, nextOwner))
689
+ try {
690
+ currentParent.insertBefore(fragment, end)
691
+ commitPublishedNodes(nodes)
692
+ } catch (error) {
693
+ disposePublished(nextOwner, nodes)
694
+ throw error
695
+ }
696
+ const previousOwner = currentOwner
697
+ const previousNodes = currentNodes
698
+ currentOwner = nextOwner
699
+ currentNodes = nodes
700
+ currentKind = kind
701
+ disposePublished(previousOwner, previousNodes)
702
+ for (const node of serverNodes) node.parentNode?.removeChild(node)
703
+ }
704
+
705
+ const beginAttempt = (): number => {
706
+ const attemptGeneration = ++generation
707
+ removeResourceListener()
708
+ removeResourceListener = noop
709
+ return attemptGeneration
710
+ }
711
+
712
+ const suspend = (failure: unknown, attemptGeneration: number): void => {
713
+ if (!isSuspension(failure)) throw failure
714
+ const retry = (): void => {
715
+ if (lifetimeOwner[0] || attemptGeneration !== generation) return
716
+ runOwnerTask(lifetimeOwner, () => attempt(false))
717
+ }
718
+ removeResourceListener = subscribeResource(failure.resource, retry)
719
+ if (
720
+ currentKind === null &&
721
+ hydratedRange !== undefined &&
722
+ pendingMarker === undefined &&
723
+ isHydrating()
724
+ ) {
725
+ dehydrated = true
726
+ skipHydrationRange(start, end)
727
+ return
728
+ }
729
+ if (currentKind !== 'fallback') {
730
+ try {
731
+ publish(fallback, 'fallback', dehydrated)
732
+ dehydrated = false
733
+ if (pendingMarker !== undefined) {
734
+ currentNodes = [pendingMarker, ...currentNodes]
735
+ }
736
+ } catch (fallbackError) {
737
+ removeResourceListener()
738
+ removeResourceListener = noop
739
+ throw fallbackError
740
+ }
741
+ }
742
+ }
743
+
744
+ const attempt = (initial: boolean): void => {
745
+ const attemptGeneration = beginAttempt()
746
+ try {
747
+ publish(render, 'content', (initial && pendingMarker !== undefined) || dehydrated)
748
+ dehydrated = false
749
+ } catch (error) {
750
+ if (!isSuspension(error)) {
751
+ if (initial || !routeOwnerError(lifetimeOwner, error)) throw error
752
+ return
753
+ }
754
+ suspend(error, attemptGeneration)
755
+ }
756
+ }
757
+
758
+ boundary = {
759
+ handle: (error) => suspend(error, beginAttempt()),
760
+ parent: parentErrorBoundary,
761
+ }
762
+ attempt(true)
763
+ onCleanup(() => {
764
+ generation += 1
765
+ removeResourceListener()
766
+ try {
767
+ disposePublished(currentOwner, currentNodes)
768
+ } finally {
769
+ start.remove()
770
+ end.remove()
771
+ }
772
+ })
773
+ },
774
+ 'slot',
775
+ ]
776
+ }
777
+
778
+ type PortalRenderableProps = {
779
+ readonly children: CompiledRenderValue | readonly CompiledRenderValue[]
780
+ }
781
+
782
+ const keyedPortalIdentities = new WeakMap<ParentNode, Map<string | number | bigint, object>>()
783
+
784
+ export function createPortal(
785
+ children: CompiledRenderValue | readonly CompiledRenderValue[],
786
+ container: ParentNode,
787
+ key?: string | number | bigint | null,
788
+ ): CompiledRenderValue {
789
+ if (!(container instanceof Node) || typeof container.insertBefore !== 'function') {
790
+ throw new TypeError(DEV ? 'createPortal requires a DOM container' : 'V026')
791
+ }
792
+ const input: PortalRenderableProps = { children }
793
+ const capability = { props: input } as RenderableProtocol & {
794
+ readonly props: PortalRenderableProps
795
+ }
796
+ Object.defineProperty(capability, RENDERABLE, {
797
+ configurable: false,
798
+ enumerable: false,
799
+ value: {
800
+ identity: portalIdentity(container, key),
801
+ input,
802
+ reconcile: true,
803
+ construct: (currentInput: PortalRenderableProps | CompiledBinding<PortalRenderableProps>) =>
804
+ createPortalStructural(portalChildren(currentInput), container),
805
+ },
806
+ })
807
+ return capability as unknown as CompiledRenderValue
808
+ }
809
+
810
+ function portalIdentity(
811
+ container: ParentNode,
812
+ key: string | number | bigint | null | undefined,
813
+ ): object {
814
+ if (key == null) return container
815
+ let identities = keyedPortalIdentities.get(container)
816
+ if (identities === undefined) {
817
+ identities = new Map()
818
+ keyedPortalIdentities.set(container, identities)
819
+ }
820
+ let identity = identities.get(key)
821
+ if (identity === undefined) {
822
+ identity = {}
823
+ identities.set(key, identity)
824
+ }
825
+ return identity
826
+ }
827
+
828
+ function portalChildren(
829
+ input: PortalRenderableProps | CompiledBinding<PortalRenderableProps>,
830
+ ): CompiledRenderValue | readonly CompiledRenderValue[] {
831
+ if (!isCompiledBinding(input)) return input.children
832
+ return binding(
833
+ input[2],
834
+ input[3],
835
+ () => input[1]().children,
836
+ input[4],
837
+ input[5],
838
+ ) as CompiledBinding<CompiledRenderValue>
839
+ }
840
+
841
+ function createPortalStructural(
842
+ children: CompiledRenderValue | readonly CompiledRenderValue[],
843
+ container: ParentNode,
844
+ ): StructuralBinding {
845
+ const context = activeContextFrame ?? activeOwner?.[2] ?? null
846
+ const rootIdentity = activeOwner?.[3] ?? activeRootIdentity
847
+ if (rootIdentity === null) {
848
+ throw new Error(DEV ? 'createPortal must run during compiled root construction' : 'V027')
849
+ }
850
+ let mounted = false
851
+ return [
852
+ STRUCTURAL,
853
+ (logicalParent, before) => {
854
+ if (mounted) throw new Error(DEV ? 'compiled portal is already mounted' : 'V008')
855
+ mounted = true
856
+ const logicalMarker = document.createComment(DEV ? 'vidact:portal' : '')
857
+ logicalParent.insertBefore(logicalMarker, before)
858
+ const start = document.createComment(DEV ? 'vidact:portal:start' : '')
859
+ const end = document.createComment(DEV ? 'vidact:portal:end' : '')
860
+ const fragment = document.createDocumentFragment()
861
+ fragment.append(start, end)
862
+ const portalOwner = withRootIdentity(rootIdentity, () =>
863
+ withContextFrame(context, createOwner),
864
+ )
865
+ let releaseEventRoot: (() => void) | undefined
866
+ try {
867
+ withOwner(portalOwner, () => insertValue(fragment, children, end))
868
+ } catch (error) {
869
+ disposeOwner(portalOwner)
870
+ logicalMarker.remove()
871
+ throw error
872
+ }
873
+ const rollback = (): void => {
874
+ releaseEventRoot?.()
875
+ releaseEventRoot = undefined
876
+ removeBetween(start, end)
877
+ start.remove()
878
+ end.remove()
879
+ }
880
+ const publication: PortalPublication = [
881
+ () => {
882
+ releaseEventRoot = retainCompiledEventRoot(container)
883
+ container.insertBefore(fragment, null)
884
+ try {
885
+ commitRangeRefs(start, end)
886
+ } catch (error) {
887
+ rollback()
888
+ throw error
889
+ }
890
+ },
891
+ rollback,
892
+ ]
893
+ if (rootIdentity.mounted) {
894
+ stagePublication([publication[0], publication[1], () => disposeOwner(portalOwner)])
895
+ } else {
896
+ let pending = pendingRootPortals.get(rootIdentity)
897
+ if (pending === undefined) {
898
+ pending = new Set()
899
+ pendingRootPortals.set(rootIdentity, pending)
900
+ }
901
+ pending.add(publication)
902
+ }
903
+ onCleanup(() => {
904
+ pendingRootPortals.get(rootIdentity)?.delete(publication)
905
+ try {
906
+ disposeOwner(portalOwner)
907
+ } finally {
908
+ publication[1]()
909
+ logicalMarker.remove()
910
+ }
911
+ })
912
+ },
913
+ ]
914
+ }
915
+
916
+ type RefValue<T = Element> =
917
+ | ((value: T | null) => void | (() => void))
918
+ | { current: unknown }
919
+ | null
920
+ | undefined
921
+
922
+ type PendingRef = [owner: Owner | null, value: RefValue, attached?: (cleanup: () => void) => void]
923
+
924
+ type NodePosition = readonly [node: Node, parent: Node | null, nextSibling: Node | null]
925
+
926
+ type PublicationOperation = readonly [
927
+ commit: () => void,
928
+ rollback: () => void,
929
+ abort?: (() => void) | undefined,
930
+ finalize?: (() => void) | undefined,
931
+ priority?: number | undefined,
932
+ errorOwner?: Owner | null | undefined,
933
+ ]
934
+
935
+ export type CompiledPropTransition = PublicationOperation
936
+
937
+ type ComponentRange = readonly [start: Comment, end: Comment, scope: CompiledScope]
938
+
939
+ let activeOwner: Owner | null = null
940
+ let activeContextFrame: ContextFrame | null = null
941
+ let activeRootIdentity: RootIdentity | null = null
942
+ let nextClientRoot = 0
943
+ let activeScopeCollector: Set<CompiledScope> | null = null
944
+ let activeConstructionOwner: Owner | null = null
945
+ let activeProfileName: string | null = null
946
+ let activeErrorOwner: Owner | null = null
947
+ let failedOwner: Owner | null = null
948
+ let transactionDepth = 0
949
+ let disposalCascadeDepth = 0
950
+ let drainingFlushes = false
951
+ let activePublication: PublicationOperation[] | null = null
952
+ const scheduledFlushes = new Set<FlushTask>()
953
+ const disposalCascadeOwners = new Set<Owner>()
954
+ const scopeOwners = new WeakMap<CompiledScope, Owner>()
955
+ const scopeNamespaces = new WeakMap<CompiledScope, IntrinsicNamespace>()
956
+ const componentRanges = new WeakMap<CompiledComponentResult, ComponentRange>()
957
+ const pendingRefs = new WeakMap<Element, PendingRef>()
958
+ const componentCommitOwners = new WeakMap<Comment, Owner>()
959
+ const pendingInsertionCommits = new WeakMap<Owner, Set<() => void>>()
960
+ const pendingOwnerCommits = new WeakMap<Owner, Set<() => void>>()
961
+ const pendingRootPortals = new WeakMap<RootIdentity, Set<PortalPublication>>()
962
+ let pendingRefCount = 0
963
+ let pendingInsertionOwnerCount = 0
964
+ let pendingOwnerCommitCount = 0
965
+ let visitedPublishedNodeCount = 0
966
+
967
+ function setPendingRef(element: Element, pending: PendingRef): void {
968
+ if (!pendingRefs.has(element)) pendingRefCount += 1
969
+ pendingRefs.set(element, pending)
970
+ }
971
+
972
+ function deletePendingRef(element: Element, expected?: PendingRef): boolean {
973
+ if (expected !== undefined && pendingRefs.get(element) !== expected) return false
974
+ if (!pendingRefs.delete(element)) return false
975
+ pendingRefCount -= 1
976
+ return true
977
+ }
978
+
979
+ export function createCompiledScope(): CompiledScope {
980
+ return createScope(wideSourceOperations)
981
+ }
982
+
983
+ export function createNarrowCompiledScope(): CompiledScope {
984
+ return createScope(narrowSourceOperations)
985
+ }
986
+
987
+ type CompilerKeyedUpdater = [
988
+ reads: SourceMask,
989
+ writes: SourceMask | undefined,
990
+ run: (active: SourceMask) => void,
991
+ active: boolean,
992
+ errorOwner: Owner,
993
+ context: ContextFrame | null,
994
+ ]
995
+
996
+ /** Compiler-emitted map callbacks only need a compact, narrow row scheduler. */
997
+ class CompilerKeyedScope {
998
+ readonly owner = createOwner()
999
+ readonly updaters: Array<CompilerKeyedUpdater | undefined> = []
1000
+ pending: SourceMask = 0
1001
+ batchDepth = 0
1002
+ flushing = false
1003
+ hasWriter = false
1004
+ cachedUpdaterOrder: number[] | undefined;
1005
+
1006
+ [1](sources?: SourceMask): void {
1007
+ if (this.owner[0]) return
1008
+ if (sources === undefined) {
1009
+ this.flush()
1010
+ return
1011
+ }
1012
+ if (narrowSourceOperations[0](sources)) return
1013
+ const wasIdle = narrowSourceOperations[0](this.pending)
1014
+ this.pending = narrowSourceOperations[2](this.pending, sources)
1015
+ if (wasIdle && this.batchDepth === 0) this.schedule()
1016
+ }
1017
+
1018
+ [3](): void {
1019
+ if (this.owner[0]) return
1020
+ try {
1021
+ disposeOwner(this.owner)
1022
+ } finally {
1023
+ this.pending = 0
1024
+ for (const updater of this.updaters) {
1025
+ if (updater !== undefined) updater[3] = false
1026
+ }
1027
+ this.updaters.length = 0
1028
+ this.cachedUpdaterOrder = undefined
1029
+ }
1030
+ }
1031
+
1032
+ constructor() {
1033
+ const scope = this as unknown as CompiledScope
1034
+ scopeOwners.set(scope, this.owner)
1035
+ scopeNamespaces.set(scope, currentIntrinsicNamespace())
1036
+ activeScopeCollector?.add(scope)
1037
+ if (activeScopeCollector !== null) activeConstructionOwner = this.owner
1038
+ }
1039
+
1040
+ [0](reads: SourceMask, run: (active: SourceMask) => void, writes?: SourceMask): () => void {
1041
+ if (this.owner[0]) {
1042
+ throw new Error(DEV ? 'cannot add an updater to a disposed scope' : 'V002')
1043
+ }
1044
+ const errorOwner = activeOwner ?? this.owner
1045
+ const entry: CompilerKeyedUpdater = [
1046
+ reads,
1047
+ writes,
1048
+ run,
1049
+ true,
1050
+ errorOwner,
1051
+ activeContextFrame ?? errorOwner[2],
1052
+ ]
1053
+ if (DEV) createdUpdaterCount += 1
1054
+ const index = this.updaters.length
1055
+ this.updaters.push(entry)
1056
+ this.hasWriter ||= writes !== undefined
1057
+ this.cachedUpdaterOrder = undefined
1058
+ if (activeOwner === this.owner) return noop
1059
+ const remove = (): void => {
1060
+ if (this.updaters[index] !== entry) return
1061
+ entry[3] = false
1062
+ this.updaters[index] = undefined
1063
+ this.cachedUpdaterOrder = undefined
1064
+ }
1065
+ activeOwner?.[1].push(remove)
1066
+ return remove
1067
+ }
1068
+
1069
+ [2]<T>(operation: () => T): T {
1070
+ this.batchDepth += 1
1071
+ transactionDepth += 1
1072
+ try {
1073
+ return operation()
1074
+ } finally {
1075
+ this.batchDepth -= 1
1076
+ if (this.batchDepth === 0 && !narrowSourceOperations[0](this.pending)) this.schedule()
1077
+ transactionDepth -= 1
1078
+ if (transactionDepth === 0) drainFlushes()
1079
+ }
1080
+ }
1081
+
1082
+ private schedule(): void {
1083
+ if (retainedUiEnabled) scheduleOwnerFlush(this.owner, this)
1084
+ else scheduleFlush(this)
1085
+ }
1086
+
1087
+ private flush(): void {
1088
+ if (this.flushing || narrowSourceOperations[0](this.pending)) return
1089
+ const operation = (): void => {
1090
+ this.flushing = true
1091
+ try {
1092
+ let pass = 0
1093
+ while (!narrowSourceOperations[0](this.pending)) {
1094
+ pass += 1
1095
+ if (pass > MAX_FLUSH_PASSES) {
1096
+ this.pending = 0
1097
+ throw new Error(DEV ? 'Vidact compiled scope did not stabilize' : 'V001')
1098
+ }
1099
+ let active = this.pending
1100
+ this.pending = 0
1101
+ const order = this.hasWriter
1102
+ ? (this.cachedUpdaterOrder ??= topologicalUpdaterOrder(
1103
+ this.updaters as ReadonlyArray<CompiledUpdater | undefined>,
1104
+ narrowSourceOperations,
1105
+ ))
1106
+ : undefined
1107
+ const count = order?.length ?? this.updaters.length
1108
+ for (let position = 0; position < count; position += 1) {
1109
+ const index = order?.[position] ?? position
1110
+ const updater = this.updaters[index]
1111
+ if (
1112
+ updater === undefined ||
1113
+ !updater[3] ||
1114
+ !narrowSourceOperations[1](active, updater[0])
1115
+ ) {
1116
+ continue
1117
+ }
1118
+ try {
1119
+ const invoke = () =>
1120
+ withOwner(updater[4], () =>
1121
+ withContextFrame(updater[5], () =>
1122
+ withScopeNamespace(this as unknown as CompiledScope, () => updater[2](active)),
1123
+ ),
1124
+ )
1125
+ if (profilingEnabled) measureProfileWork(this.owner, 'updater', invoke)
1126
+ else invoke()
1127
+ } catch (error) {
1128
+ if (!routeOwnerError(updater[4], error)) {
1129
+ failedOwner = updater[4]
1130
+ throw error
1131
+ }
1132
+ }
1133
+ if (updater[1] !== undefined) {
1134
+ active = narrowSourceOperations[2](active, updater[1])
1135
+ }
1136
+ }
1137
+ }
1138
+ } finally {
1139
+ this.flushing = false
1140
+ }
1141
+ if (retainedUiEnabled) notifyRetainedFlush(this.owner[5] ?? null)
1142
+ }
1143
+ if (profilingEnabled) measureProfileWork(this.owner, 'scheduler', operation, true)
1144
+ else operation()
1145
+ }
1146
+ }
1147
+
1148
+ function createCompilerKeyedScope(): CompiledScope {
1149
+ return new CompilerKeyedScope() as unknown as CompiledScope
1150
+ }
1151
+
1152
+ export function runCompiledTransaction<T>(operation: () => T): T {
1153
+ transactionDepth += 1
1154
+ try {
1155
+ return operation()
1156
+ } finally {
1157
+ transactionDepth -= 1
1158
+ if (transactionDepth === 0) drainFlushes()
1159
+ }
1160
+ }
1161
+
1162
+ function createScope(operations: SourceOperations): CompiledScope {
1163
+ const namespace = currentIntrinsicNamespace()
1164
+ const owner = createOwner()
1165
+ const updaters: Array<CompiledUpdater | undefined> = []
1166
+ let freeUpdaterIndexes: number[] | undefined
1167
+ let addedDuringFlush: Set<CompiledUpdater> | undefined
1168
+ let batchDepth = 0
1169
+ let flushing = false
1170
+ let pending: SourceMask = 0
1171
+ let cachedUpdaterOrder: number[] | undefined
1172
+ let hasWriter = false
1173
+
1174
+ const flush = (): void => {
1175
+ if (owner[0] || flushing) return
1176
+ const operation = (): void => {
1177
+ flushing = true
1178
+ try {
1179
+ let pass = 0
1180
+ const updaterOrder = hasWriter
1181
+ ? (cachedUpdaterOrder ??= topologicalUpdaterOrder(updaters, operations))
1182
+ : undefined
1183
+ while (!operations[0](pending)) {
1184
+ pass += 1
1185
+ if (pass > MAX_FLUSH_PASSES) {
1186
+ pending = 0
1187
+ throw new Error(DEV ? 'Vidact compiled scope did not stabilize' : 'V001')
1188
+ }
1189
+
1190
+ let active = pending
1191
+ pending = 0
1192
+ const updaterCount = updaterOrder?.length ?? updaters.length
1193
+ for (let position = 0; position < updaterCount; position += 1) {
1194
+ const index = updaterOrder?.[position] ?? position
1195
+ const updater = updaters[index]
1196
+ if (
1197
+ updater === undefined ||
1198
+ addedDuringFlush?.has(updater) ||
1199
+ !updater[3] ||
1200
+ !operations[1](active, updater[0])
1201
+ ) {
1202
+ continue
1203
+ }
1204
+ if (profilingEnabled) {
1205
+ measureProfileWork(owner, 'updater', () => updater[2](active))
1206
+ } else {
1207
+ updater[2](active)
1208
+ }
1209
+ if (updater[1] !== undefined) active = operations[2](active, updater[1])
1210
+ }
1211
+ addedDuringFlush?.clear()
1212
+ }
1213
+ } finally {
1214
+ addedDuringFlush?.clear()
1215
+ flushing = false
1216
+ }
1217
+ if (retainedUiEnabled) notifyRetainedFlush(owner[5] ?? null)
1218
+ }
1219
+ if (profilingEnabled) measureProfileWork(owner, 'scheduler', operation, true)
1220
+ else operation()
1221
+ }
1222
+
1223
+ const scope: CompiledScope = [
1224
+ (reads, run, writes) => {
1225
+ if (owner[0]) {
1226
+ throw new Error(DEV ? 'cannot add an updater to a disposed scope' : 'V002')
1227
+ }
1228
+ const errorOwner = activeOwner ?? owner
1229
+ const context = activeContextFrame ?? errorOwner[2]
1230
+ const entry: CompiledUpdater = [
1231
+ reads,
1232
+ writes,
1233
+ (active) => {
1234
+ try {
1235
+ withOwner(errorOwner, () =>
1236
+ withContextFrame(context, () => withScopeNamespace(scope, () => run(active))),
1237
+ )
1238
+ } catch (error) {
1239
+ if (!routeOwnerError(errorOwner, error)) {
1240
+ failedOwner = errorOwner
1241
+ throw error
1242
+ }
1243
+ }
1244
+ },
1245
+ true,
1246
+ ]
1247
+ if (DEV) createdUpdaterCount += 1
1248
+ const reusableIndex = freeUpdaterIndexes?.pop()
1249
+ const index = reusableIndex ?? updaters.length
1250
+ updaters[index] = entry
1251
+ hasWriter ||= writes !== undefined
1252
+ cachedUpdaterOrder = undefined
1253
+ if (flushing) (addedDuringFlush ??= new Set()).add(entry)
1254
+ const remove = (): void => {
1255
+ if (updaters[index] !== entry) return
1256
+ entry[3] = false
1257
+ updaters[index] = undefined
1258
+ cachedUpdaterOrder = undefined
1259
+ ;(freeUpdaterIndexes ??= []).push(index)
1260
+ }
1261
+ if (activeOwner !== null && activeOwner !== owner) activeOwner[1].push(remove)
1262
+ return remove
1263
+ },
1264
+ (sources) => {
1265
+ if (owner[0] || operations[0](sources)) return
1266
+ const wasIdle = operations[0](pending)
1267
+ pending = operations[2](pending, sources)
1268
+ if (wasIdle && batchDepth === 0) {
1269
+ if (retainedUiEnabled) scheduleOwnerFlush(owner, flush)
1270
+ else scheduleFlush(flush)
1271
+ }
1272
+ },
1273
+ <T>(operation: () => T): T => {
1274
+ batchDepth += 1
1275
+ transactionDepth += 1
1276
+ try {
1277
+ return operation()
1278
+ } finally {
1279
+ batchDepth -= 1
1280
+ if (batchDepth === 0 && !operations[0](pending)) {
1281
+ if (retainedUiEnabled) scheduleOwnerFlush(owner, flush)
1282
+ else scheduleFlush(flush)
1283
+ }
1284
+ transactionDepth -= 1
1285
+ if (transactionDepth === 0) drainFlushes()
1286
+ }
1287
+ },
1288
+ () => {
1289
+ if (owner[0]) return
1290
+ try {
1291
+ disposeOwner(owner)
1292
+ } finally {
1293
+ pending = 0
1294
+ for (const updater of updaters) {
1295
+ if (updater !== undefined) updater[3] = false
1296
+ }
1297
+ updaters.length = 0
1298
+ hasWriter = false
1299
+ if (freeUpdaterIndexes !== undefined) freeUpdaterIndexes.length = 0
1300
+ addedDuringFlush?.clear()
1301
+ }
1302
+ },
1303
+ ]
1304
+ scopeOwners.set(scope, owner)
1305
+ scopeNamespaces.set(scope, namespace)
1306
+ activeScopeCollector?.add(scope)
1307
+ if (activeScopeCollector !== null) activeConstructionOwner = owner
1308
+ return scope
1309
+ }
1310
+
1311
+ function topologicalUpdaterOrder(
1312
+ updaters: ReadonlyArray<CompiledUpdater | undefined>,
1313
+ operations: SourceOperations,
1314
+ ): number[] {
1315
+ if (DEV) createdSchedulerPlanCount += 1
1316
+ const activeIndexes: number[] = []
1317
+ let hasWriter = false
1318
+ for (let index = 0; index < updaters.length; index += 1) {
1319
+ const updater = updaters[index]
1320
+ if (updater === undefined || !updater[3]) continue
1321
+ activeIndexes.push(index)
1322
+ if (updater[1] !== undefined) hasWriter = true
1323
+ }
1324
+ if (!hasWriter) return activeIndexes
1325
+ const readersBySource = new Map<number, number[]>()
1326
+ for (const readerIndex of activeIndexes) {
1327
+ operations[3](updaters[readerIndex]![0], (sourceIndex) => {
1328
+ const readers = readersBySource.get(sourceIndex)
1329
+ if (readers === undefined) readersBySource.set(sourceIndex, [readerIndex])
1330
+ else readers.push(readerIndex)
1331
+ })
1332
+ }
1333
+ const edges = new Map<number, number[]>()
1334
+ for (const writerIndex of activeIndexes) {
1335
+ const writes = updaters[writerIndex]![1]
1336
+ if (writes === undefined) continue
1337
+ const readers = new Set<number>()
1338
+ operations[3](writes, (sourceIndex) => {
1339
+ for (const readerIndex of readersBySource.get(sourceIndex) ?? []) {
1340
+ if (writerIndex !== readerIndex) readers.add(readerIndex)
1341
+ }
1342
+ })
1343
+ if (readers.size > 0) {
1344
+ edges.set(
1345
+ writerIndex,
1346
+ [...readers].toSorted((left, right) => left - right),
1347
+ )
1348
+ }
1349
+ }
1350
+
1351
+ const visitIndexes = new Int32Array(updaters.length).fill(-1)
1352
+ const lowLinks = new Int32Array(updaters.length)
1353
+ const stack: number[] = []
1354
+ const onStack = new Uint8Array(updaters.length)
1355
+ const components: number[][] = []
1356
+ let nextVisitIndex = 0
1357
+
1358
+ const connect = (updaterIndex: number): void => {
1359
+ const visitIndex = nextVisitIndex++
1360
+ visitIndexes[updaterIndex] = visitIndex
1361
+ lowLinks[updaterIndex] = visitIndex
1362
+ stack.push(updaterIndex)
1363
+ onStack[updaterIndex] = 1
1364
+
1365
+ for (const readerIndex of edges.get(updaterIndex) ?? []) {
1366
+ if (visitIndexes[readerIndex] === -1) {
1367
+ connect(readerIndex)
1368
+ lowLinks[updaterIndex] = Math.min(lowLinks[updaterIndex]!, lowLinks[readerIndex]!)
1369
+ } else if (onStack[readerIndex] === 1) {
1370
+ lowLinks[updaterIndex] = Math.min(lowLinks[updaterIndex]!, visitIndexes[readerIndex]!)
1371
+ }
1372
+ }
1373
+
1374
+ if (lowLinks[updaterIndex] !== visitIndexes[updaterIndex]) return
1375
+ const component: number[] = []
1376
+ let member: number
1377
+ do {
1378
+ member = stack.pop()!
1379
+ onStack[member] = 0
1380
+ component.push(member)
1381
+ } while (member !== updaterIndex)
1382
+ component.sort((left, right) => left - right)
1383
+ components.push(component)
1384
+ }
1385
+
1386
+ for (const updaterIndex of activeIndexes) {
1387
+ if (visitIndexes[updaterIndex] === -1) connect(updaterIndex)
1388
+ }
1389
+
1390
+ const componentByUpdater = new Int32Array(updaters.length).fill(-1)
1391
+ const componentEdges = components.map(() => new Set<number>())
1392
+ const componentIndegrees = new Uint32Array(components.length)
1393
+ const componentFirstIndexes = components.map((component) => component[0]!)
1394
+ for (let componentIndex = 0; componentIndex < components.length; componentIndex += 1) {
1395
+ for (const updaterIndex of components[componentIndex]!) {
1396
+ componentByUpdater[updaterIndex] = componentIndex
1397
+ }
1398
+ }
1399
+ for (const [writerIndex, readers] of edges) {
1400
+ const writerComponent = componentByUpdater[writerIndex]!
1401
+ for (const readerIndex of readers) {
1402
+ const readerComponent = componentByUpdater[readerIndex]!
1403
+ if (
1404
+ writerComponent === readerComponent ||
1405
+ componentEdges[writerComponent]!.has(readerComponent)
1406
+ ) {
1407
+ continue
1408
+ }
1409
+ componentEdges[writerComponent]!.add(readerComponent)
1410
+ componentIndegrees[readerComponent] = componentIndegrees[readerComponent]! + 1
1411
+ }
1412
+ }
1413
+
1414
+ const ready = components
1415
+ .map((_, index) => index)
1416
+ .filter((index) => componentIndegrees[index] === 0)
1417
+ .sort((left, right) => componentFirstIndexes[left]! - componentFirstIndexes[right]!)
1418
+ const ordered: number[] = []
1419
+ while (ready.length > 0) {
1420
+ const componentIndex = ready.shift()!
1421
+ ordered.push(...components[componentIndex]!)
1422
+ for (const readerComponent of componentEdges[componentIndex]!) {
1423
+ componentIndegrees[readerComponent] = componentIndegrees[readerComponent]! - 1
1424
+ if (componentIndegrees[readerComponent] === 0) {
1425
+ ready.push(readerComponent)
1426
+ ready.sort((left, right) => componentFirstIndexes[left]! - componentFirstIndexes[right]!)
1427
+ }
1428
+ }
1429
+ }
1430
+ return ordered
1431
+ }
1432
+
1433
+ export function createCompiledState<T>(
1434
+ scope: CompiledScope,
1435
+ sourceMask: SourceMask,
1436
+ initialValue: T | (() => T),
1437
+ ): StateSlot<T> {
1438
+ const assertWritable = stateWriteGuard(scope)
1439
+ const value = typeof initialValue === 'function' ? (initialValue as () => T)() : initialValue
1440
+ return createStateSlot(scope[1], sourceMask, value, assertWritable)
1441
+ }
1442
+
1443
+ export function createCompiledReducer<State, Action, Initial>(
1444
+ scope: CompiledScope,
1445
+ sourceMask: SourceMask,
1446
+ reducer: (state: State, action: Action) => State,
1447
+ initialArg: Initial,
1448
+ initialize?: (initialArg: Initial) => State,
1449
+ ): { readonly get: () => State; readonly set: (action: Action) => void } {
1450
+ const state = createStateSlot<State>(
1451
+ scope[1],
1452
+ sourceMask,
1453
+ initialize === undefined ? (initialArg as unknown as State) : initialize(initialArg),
1454
+ stateWriteGuard(scope),
1455
+ )
1456
+ return {
1457
+ get: state.get,
1458
+ set: (action) => state.set((previous) => reducer(previous, action)),
1459
+ }
1460
+ }
1461
+
1462
+ export function createCompiledMemo<T>(
1463
+ scope: CompiledScope,
1464
+ reads: SourceMask,
1465
+ writes: SourceMask,
1466
+ evaluate: () => T,
1467
+ readDependencies: () => readonly unknown[],
1468
+ ): StateSlot<T> {
1469
+ let currentDependencies = readDependencies()
1470
+ const slot = createStateSlot(scope[1], writes, evaluate(), stateWriteGuard(scope))
1471
+ const removeUpdater = scope[0](reads, () => {
1472
+ const nextDependencies = readDependencies()
1473
+ if (equalDependencies(nextDependencies, currentDependencies)) return
1474
+ slot.replace(evaluate())
1475
+ currentDependencies = nextDependencies
1476
+ })
1477
+ const owner = scopeOwners.get(scope)
1478
+ if (owner === undefined) {
1479
+ removeUpdater()
1480
+ throw new Error(DEV ? 'createCompiledMemo received an unknown scope' : 'V003')
1481
+ }
1482
+ owner[1].push(removeUpdater)
1483
+ return slot
1484
+ }
1485
+
1486
+ export function createContext<T>(defaultValue: T): CompiledContext<T> {
1487
+ let context: CompiledContext<T>
1488
+ const provider = ((props: {
1489
+ readonly children?: CompiledRenderValue | readonly CompiledRenderValue[]
1490
+ readonly value: T | CompiledBinding<T>
1491
+ }): StructuralBinding =>
1492
+ provideContext(context, props.value, props.children)) as CompiledContext<T>
1493
+ context = provider
1494
+ context.Provider = provider
1495
+ Object.defineProperty(context, CONTEXT, { value: defaultValue })
1496
+ return context
1497
+ }
1498
+
1499
+ /** @internal */
1500
+ export function runWithCompiledContext<Value, Result>(
1501
+ context: CompiledContext<Value>,
1502
+ value: Value | CompiledBinding<Value>,
1503
+ operation: () => Result,
1504
+ ): Result {
1505
+ if (!(CONTEXT in context)) {
1506
+ throw new Error(DEV ? 'runWithCompiledContext received an unknown context' : 'V003')
1507
+ }
1508
+ const parent = activeContextFrame ?? activeOwner?.[2] ?? null
1509
+ return withContextFrame(
1510
+ {
1511
+ context: context as CompiledContext<unknown>,
1512
+ input: value,
1513
+ parent,
1514
+ owner: activeOwner,
1515
+ },
1516
+ operation,
1517
+ )
1518
+ }
1519
+
1520
+ export function createCompiledContext<T>(
1521
+ scope: CompiledScope,
1522
+ sourceMask: SourceMask,
1523
+ context: CompiledContext<T>,
1524
+ ): StateSlot<T> {
1525
+ const input = contextInput(scope, context)
1526
+ return createCompiledProp(scope, sourceMask, input)
1527
+ }
1528
+
1529
+ export function createCompiledExternalStore<T>(
1530
+ scope: CompiledScope,
1531
+ sourceMask: SourceMask,
1532
+ storeSubscribe:
1533
+ | ((onStoreChange: () => void) => () => void)
1534
+ | CompiledBinding<readonly [(onStoreChange: () => void) => () => void, () => T, (() => T)?]>,
1535
+ getSnapshot?: () => T,
1536
+ _getServerSnapshot?: () => T,
1537
+ ): StateSlot<T> {
1538
+ const owner = scopeOwners.get(scope)
1539
+ if (owner === undefined) {
1540
+ throw new Error(DEV ? 'createCompiledExternalStore received an unknown scope' : 'V003')
1541
+ }
1542
+ const reactiveStore = isCompiledBinding(storeSubscribe) ? storeSubscribe : undefined
1543
+ let currentSubscribe: (onStoreChange: () => void) => () => void
1544
+ let currentGetSnapshot!: () => T
1545
+ const readStore = (): void => {
1546
+ const store = reactiveStore?.[1]()
1547
+ currentSubscribe = store?.[0] ?? (storeSubscribe as (onStoreChange: () => void) => () => void)
1548
+ currentGetSnapshot = store?.[1] ?? (getSnapshot as () => T)
1549
+ if (typeof currentSubscribe !== 'function' || typeof currentGetSnapshot !== 'function') {
1550
+ throw new TypeError(
1551
+ DEV ? 'external store requires subscribe and getSnapshot functions' : 'V020',
1552
+ )
1553
+ }
1554
+ }
1555
+ readStore()
1556
+ const slot = createStateSlot(scope[1], sourceMask, currentGetSnapshot(), stateWriteGuard(scope))
1557
+ let active = false
1558
+ let unsubscribe = noop
1559
+ const checkSnapshot = (): void => {
1560
+ if (!active) return
1561
+ const nextSnapshot = currentGetSnapshot()
1562
+ scope[2](() => slot.replace(nextSnapshot))
1563
+ }
1564
+ const activateStore = (): void => {
1565
+ readStore()
1566
+ active = true
1567
+ try {
1568
+ const remove = currentSubscribe(() => runOwnerTask(owner, checkSnapshot))
1569
+ if (typeof remove !== 'function') {
1570
+ throw new TypeError(
1571
+ DEV ? 'external store subscribe must return an unsubscribe function' : 'V020',
1572
+ )
1573
+ }
1574
+ unsubscribe = remove
1575
+ checkSnapshot()
1576
+ } catch (error) {
1577
+ active = false
1578
+ unsubscribe()
1579
+ unsubscribe = noop
1580
+ throw error
1581
+ }
1582
+ }
1583
+ const deactivateStore = (): void => {
1584
+ active = false
1585
+ unsubscribe()
1586
+ unsubscribe = noop
1587
+ }
1588
+ const reconnect = (): void => {
1589
+ if (!active) {
1590
+ readStore()
1591
+ return
1592
+ }
1593
+ deactivateStore()
1594
+ activateStore()
1595
+ }
1596
+ const removeStoreUpdater =
1597
+ reactiveStore === undefined ? noop : subscribeBinding(reactiveStore, reconnect)
1598
+
1599
+ if (!retainedUiEnabled) {
1600
+ try {
1601
+ activateStore()
1602
+ } catch (error) {
1603
+ removeStoreUpdater()
1604
+ throw error
1605
+ }
1606
+ owner[1].push(() => {
1607
+ removeStoreUpdater()
1608
+ deactivateStore()
1609
+ })
1610
+ return slot
1611
+ }
1612
+ const [activateResource, disposeResource] = createRetainedResource(
1613
+ owner,
1614
+ activateStore,
1615
+ deactivateStore,
1616
+ 0,
1617
+ )
1618
+ try {
1619
+ activateResource()
1620
+ } catch (error) {
1621
+ disposeResource()
1622
+ throw error
1623
+ }
1624
+ owner[1].push(() => {
1625
+ removeStoreUpdater()
1626
+ disposeResource()
1627
+ })
1628
+ return slot
1629
+ }
1630
+
1631
+ export function createCompiledEffectEvent<Arguments extends unknown[], Result>(
1632
+ scope: CompiledScope,
1633
+ callback: (...arguments_: Arguments) => Result,
1634
+ ): (...arguments_: Arguments) => Result {
1635
+ const owner = scopeOwners.get(scope)
1636
+ if (owner === undefined) {
1637
+ throw new Error(DEV ? 'createCompiledEffectEvent received an unknown scope' : 'V003')
1638
+ }
1639
+ return (...arguments_) => {
1640
+ if (owner[0]) throw new Error(DEV ? 'cannot call an effect event after disposal' : 'V022')
1641
+ return callback(...arguments_)
1642
+ }
1643
+ }
1644
+
1645
+ export function createCompiledId(scope: CompiledScope): string {
1646
+ const owner = scopeOwners.get(scope)
1647
+ if (owner === undefined) {
1648
+ throw new Error(DEV ? 'createCompiledId received an unknown scope' : 'V003')
1649
+ }
1650
+ const id = `:${owner[3].prefix}r${owner[3].nextId}:`
1651
+ owner[3].nextId += 1
1652
+ return id
1653
+ }
1654
+
1655
+ export function useContext<T>(context: CompiledContext<T>): T {
1656
+ if (activeConstructionOwner === null) {
1657
+ throw new Error(DEV ? 'useContext must run during compiled component construction' : 'V019')
1658
+ }
1659
+ const input = contextInputFromFrame(activeConstructionOwner[2], context)
1660
+ return isCompiledBinding(input) ? (input[1]() as T) : (input as T)
1661
+ }
1662
+
1663
+ export function use<T>(context: CompiledContext<T>): T {
1664
+ return useContext(context)
1665
+ }
1666
+
1667
+ export function createCompiledAsync<Value>(
1668
+ scope: CompiledScope,
1669
+ reads: SourceMask,
1670
+ writes: SourceMask,
1671
+ evaluate: () => CompiledContext<Value> | AsyncResource<Value> | PromiseLike<Value>,
1672
+ ): StateSlot<Value> {
1673
+ const input = evaluate()
1674
+ if (isCompiledContext<Value>(input)) return createCompiledContext(scope, writes, input)
1675
+ const slot = createCompiledState(scope, writes, useAsync(input))
1676
+ scope[0](reads, () => slot.replace(useAsync(evaluate())))
1677
+ return slot
1678
+ }
1679
+
1680
+ export function Suspense(props: {
1681
+ readonly children?: (() => CompiledRenderValue) | readonly [() => CompiledRenderValue] | undefined
1682
+ readonly fallback: () => CompiledRenderValue
1683
+ }): StructuralBinding {
1684
+ const render = Array.isArray(props.children) ? props.children[0] : props.children
1685
+ if (typeof render !== 'function' || typeof props.fallback !== 'function') {
1686
+ throw new TypeError(
1687
+ DEV
1688
+ ? `Suspense children and fallback must be compiler-generated render functions; received ${typeof render} and ${typeof props.fallback}`
1689
+ : 'V031',
1690
+ )
1691
+ }
1692
+ return suspense(render, props.fallback)
1693
+ }
1694
+
1695
+ export function useSyncExternalStore<T>(
1696
+ _subscribe: (onStoreChange: () => void) => () => void,
1697
+ _getSnapshot: () => T,
1698
+ _getServerSnapshot?: () => T,
1699
+ ): T {
1700
+ throw new Error(DEV ? 'useSyncExternalStore requires compiler lowering' : 'V021')
1701
+ }
1702
+
1703
+ export function useEffectEvent<Arguments extends unknown[], Result>(
1704
+ callback: (...arguments_: Arguments) => Result,
1705
+ ): (...arguments_: Arguments) => Result {
1706
+ return callback
1707
+ }
1708
+
1709
+ export function useId(): string {
1710
+ if (activeConstructionOwner === null) {
1711
+ throw new Error(DEV ? 'useId must run during compiled component construction' : 'V023')
1712
+ }
1713
+ const id = `:${activeConstructionOwner[3].prefix}r${activeConstructionOwner[3].nextId}:`
1714
+ activeConstructionOwner[3].nextId += 1
1715
+ return id
1716
+ }
1717
+
1718
+ export function useMemo<T>(factory: () => T, _dependencies: readonly unknown[]): T {
1719
+ return factory()
1720
+ }
1721
+
1722
+ export function useCallback<T extends Function>(callback: T, _dependencies: readonly unknown[]): T {
1723
+ return callback
1724
+ }
1725
+
1726
+ const ownedBlockFacades = new WeakMap<StructuralBinding, RenderableProtocol>()
1727
+ const ownedFacadeBlocks = new WeakMap<RenderableProtocol, StructuralBinding>()
1728
+
1729
+ function ownedStructuralBinding(value: unknown): StructuralBinding | undefined {
1730
+ if (isStructuralBinding(value)) return value
1731
+ return isRenderableProtocol(value) ? ownedFacadeBlocks.get(value) : undefined
1732
+ }
1733
+
1734
+ /**
1735
+ * Owned blocks are arrays internally, which user-level data flow must never
1736
+ * observe: dependency code inspects children with `Array.isArray` and spreads
1737
+ * them. Prop reads wrap a block in a stable renderable facade that
1738
+ * materializes back to the block when rendered.
1739
+ */
1740
+ function sanitizeCompiledPropValue<T>(value: T): T {
1741
+ if (!isStructuralBinding(value)) return value
1742
+ let facade = ownedBlockFacades.get(value)
1743
+ if (facade === undefined) {
1744
+ const capability = { props: {} } as unknown as RenderableProtocol
1745
+ Object.defineProperty(capability, RENDERABLE, {
1746
+ configurable: false,
1747
+ enumerable: false,
1748
+ value: {
1749
+ identity: value,
1750
+ input: {},
1751
+ reconcile: false,
1752
+ construct: () => value,
1753
+ },
1754
+ })
1755
+ facade = capability
1756
+ ownedBlockFacades.set(value, facade)
1757
+ ownedFacadeBlocks.set(facade, value)
1758
+ }
1759
+ return facade as T
1760
+ }
1761
+
1762
+ export function createCompiledProp<T>(
1763
+ scope: CompiledScope,
1764
+ sourceMask: SourceMask,
1765
+ input: T | CompiledBinding<T>,
1766
+ fallback?: () => T,
1767
+ ): StateSlot<T> {
1768
+ const assertWritable = stateWriteGuard(scope)
1769
+ const upstream = isCompiledBinding(input) ? input : undefined
1770
+ const read = (): T => {
1771
+ const value = upstream === undefined ? (input as T) : upstream[1]()
1772
+ return sanitizeCompiledPropValue(
1773
+ value === undefined && fallback !== undefined ? fallback() : value,
1774
+ )
1775
+ }
1776
+ const slot = createStateSlot<T>(scope[1], sourceMask, read(), assertWritable)
1777
+ if (upstream !== undefined) {
1778
+ const remove = subscribeBinding(upstream, () => slot.replace(read()))
1779
+ const owner = scopeOwners.get(scope)
1780
+ if (owner === undefined) {
1781
+ throw new Error(DEV ? 'createCompiledProp received an unknown scope' : 'V003')
1782
+ }
1783
+ owner[1].push(remove)
1784
+ }
1785
+ return slot
1786
+ }
1787
+
1788
+ export function createCompiledRestProp(
1789
+ scope: CompiledScope,
1790
+ sourceMask: SourceMask,
1791
+ input: Record<string, unknown>,
1792
+ excludedNames: readonly string[],
1793
+ ): StateSlot<Record<string, unknown>> {
1794
+ const excluded = new Set(excludedNames)
1795
+ const entries = (): Array<[string, unknown]> =>
1796
+ Object.entries(input).filter(([name]) => !excluded.has(name))
1797
+ const read = (): Record<string, unknown> =>
1798
+ Object.fromEntries(
1799
+ entries().map(([name, value]) => [
1800
+ name,
1801
+ sanitizeCompiledPropValue(isCompiledBinding(value) ? value[1]() : value),
1802
+ ]),
1803
+ )
1804
+ const slot = createStateSlot(scope[1], sourceMask, read(), stateWriteGuard(scope))
1805
+ const publish = (): void => {
1806
+ const previous = slot.get()
1807
+ const next = read()
1808
+ const names = Object.keys(next)
1809
+ if (
1810
+ names.length === Object.keys(previous).length &&
1811
+ names.every((name) => Object.hasOwn(previous, name) && Object.is(previous[name], next[name]))
1812
+ ) {
1813
+ return
1814
+ }
1815
+ slot.replace(next)
1816
+ }
1817
+ const componentSpreadSource = (input as Record<PropertyKey, unknown>)[COMPONENT_SPREAD_SOURCE]
1818
+ const upstreams = new Set(
1819
+ entries()
1820
+ .map(([, value]) => value)
1821
+ .filter(isCompiledBinding),
1822
+ )
1823
+ if (isCompiledBinding(componentSpreadSource)) upstreams.add(componentSpreadSource)
1824
+ const removers = [...upstreams].map((upstream) => subscribeBinding(upstream, publish))
1825
+ const owner = scopeOwners.get(scope)
1826
+ if (owner === undefined) {
1827
+ throw new Error(DEV ? 'createCompiledRestProp received an unknown scope' : 'V003')
1828
+ }
1829
+ owner[1].push(() => {
1830
+ for (const remove of removers) remove()
1831
+ })
1832
+ return slot
1833
+ }
1834
+
1835
+ /** @internal */
1836
+ export function objectRest(
1837
+ input: Record<PropertyKey, unknown>,
1838
+ excludedNames: readonly PropertyKey[],
1839
+ ): Record<PropertyKey, unknown> {
1840
+ const excluded = new Set(excludedNames)
1841
+ const output: Record<PropertyKey, unknown> = {}
1842
+ for (const key of Reflect.ownKeys(input)) {
1843
+ if (excluded.has(key) || !Object.getOwnPropertyDescriptor(input, key)?.enumerable) continue
1844
+ Object.defineProperty(output, key, {
1845
+ configurable: true,
1846
+ enumerable: true,
1847
+ value: input[key],
1848
+ writable: true,
1849
+ })
1850
+ }
1851
+ return output
1852
+ }
1853
+
1854
+ function stateWriteGuard(scope: CompiledScope): () => void {
1855
+ const owner = scopeOwners.get(scope)
1856
+ if (owner === undefined) {
1857
+ throw new Error(DEV ? 'compiled state received an unknown scope' : 'V003')
1858
+ }
1859
+ return () => {
1860
+ if (owner[0] && !disposalCascadeOwners.has(owner)) {
1861
+ throw new Error(DEV ? 'cannot update state after disposal' : 'V012')
1862
+ }
1863
+ }
1864
+ }
1865
+
1866
+ export function binding<T>(
1867
+ scope: CompiledScope,
1868
+ reads: SourceMask,
1869
+ evaluate: () => T,
1870
+ additionalScope?: CompiledScope,
1871
+ additionalReads?: SourceMask,
1872
+ ): CompiledBinding<T> {
1873
+ return [BINDING, evaluate, scope, reads, additionalScope, additionalReads]
1874
+ }
1875
+
1876
+ export function compiledEvent<Arguments extends unknown[]>(
1877
+ scope: CompiledScope,
1878
+ handler:
1879
+ | ((...arguments_: Arguments) => void)
1880
+ | CompiledBinding<((...arguments_: Arguments) => void) | null | undefined>
1881
+ | null
1882
+ | undefined,
1883
+ ): (...arguments_: Arguments) => void {
1884
+ const owner = scopeOwners.get(scope)
1885
+ if (owner === undefined) {
1886
+ throw new Error(DEV ? 'compiledEvent received an unknown scope' : 'V003')
1887
+ }
1888
+ const errorOwner = activeOwner ?? owner
1889
+ const listener = (...arguments_: Arguments) => {
1890
+ if (errorOwner[0]) return
1891
+ return runOwnerTask(errorOwner, () =>
1892
+ withOwner(errorOwner, () =>
1893
+ scope[2](() => {
1894
+ const current = isCompiledBinding(handler) ? handler[1]() : handler
1895
+ if (typeof current !== 'function') return
1896
+ return current(...arguments_)
1897
+ }),
1898
+ ),
1899
+ )
1900
+ }
1901
+ ;(listener as unknown as CompiledEventHandler)[COMPILED_EVENT_HANDLER] = true
1902
+ return listener
1903
+ }
1904
+
1905
+ export function compiledInlineEvent<Arguments extends unknown[]>(
1906
+ scope: CompiledScope,
1907
+ handler: (...arguments_: Arguments) => void,
1908
+ ): (...arguments_: Arguments) => void {
1909
+ const owner = scopeOwners.get(scope)
1910
+ if (owner === undefined) {
1911
+ throw new Error(DEV ? 'compiledInlineEvent received an unknown scope' : 'V003')
1912
+ }
1913
+ const listener = handler as unknown as CompiledInlineEventHandler<Arguments>
1914
+ listener[COMPILED_INLINE_EVENT_OWNER] = activeOwner ?? owner
1915
+ listener[COMPILED_DELEGATED_EVENT_INVOKE] = invokeCompiledInlineEvent
1916
+ return listener
1917
+ }
1918
+
1919
+ function invokeCompiledInlineEvent<Arguments extends unknown[]>(
1920
+ this: CompiledInlineEventHandler<Arguments>,
1921
+ ...arguments_: Arguments
1922
+ ): void {
1923
+ const owner = this[COMPILED_INLINE_EVENT_OWNER]
1924
+ if (owner[0]) return
1925
+ return runOwnerTask(owner, () =>
1926
+ withOwner(owner, () => runCompiledTransaction(() => this(...arguments_))),
1927
+ )
1928
+ }
1929
+
1930
+ export function isCompiledEventHandler(value: unknown): value is EventListener {
1931
+ if (typeof value !== 'function') return false
1932
+ const handler = value as typeof value & CompiledEventMetadata
1933
+ return (
1934
+ handler[COMPILED_EVENT_HANDLER] === true ||
1935
+ typeof handler[COMPILED_DELEGATED_EVENT_INVOKE] === 'function'
1936
+ )
1937
+ }
1938
+
1939
+ export interface CompiledTaskController {
1940
+ readonly disposed: () => boolean
1941
+ readonly report: (error: unknown) => void
1942
+ }
1943
+
1944
+ export function captureCompiledTask(scope?: CompiledScope): CompiledTaskController {
1945
+ const owner = scope === undefined ? activeOwner : scopeOwners.get(scope)
1946
+ if (owner === null || owner === undefined) {
1947
+ throw new Error(DEV ? 'compiled task must be captured during owned construction' : 'V034')
1948
+ }
1949
+ return {
1950
+ disposed: () => owner[0],
1951
+ report: (error) =>
1952
+ runOwnerTask(owner, () => {
1953
+ throw error
1954
+ }),
1955
+ }
1956
+ }
1957
+
1958
+ export function when(
1959
+ scope: CompiledScope,
1960
+ reads: SourceMask,
1961
+ condition: () => unknown,
1962
+ render: () => RenderValue,
1963
+ additionalScope?: CompiledScope,
1964
+ additionalReads?: SourceMask,
1965
+ ): StructuralBinding {
1966
+ return structural(
1967
+ scope,
1968
+ (parent, before) => {
1969
+ const [start, end, hydrated] = structuralRange(parent, before, 'when')
1970
+ let branchOwner: Owner | null = null
1971
+ let mounted = false
1972
+ let hydrationPending = hydrated
1973
+
1974
+ const update = (): void => {
1975
+ const next = Boolean(condition())
1976
+ if (hydrationPending && !next) {
1977
+ claimHydrationText(parent, '')
1978
+ hydrationPending = false
1979
+ return
1980
+ }
1981
+ if (next === mounted) return
1982
+ const currentParent = rangeParent(start, end, 'conditional block')
1983
+ if (!next) {
1984
+ const owner = branchOwner
1985
+ branchOwner = null
1986
+ mounted = false
1987
+ disposeRange(owner, start, end)
1988
+ return
1989
+ }
1990
+
1991
+ const nextOwner = createOwner()
1992
+ const [fragment, staged] = hydrationPending
1993
+ ? withHydrationInsertion(currentParent, end, () => stageRender(render, nextOwner))
1994
+ : stageRender(render, nextOwner)
1995
+ hydrationPending = false
1996
+ currentParent.insertBefore(fragment, end)
1997
+ commitPublishedNodes(staged)
1998
+ branchOwner = nextOwner
1999
+ mounted = true
2000
+ }
2001
+
2002
+ const removeUpdater = subscribe(scope, reads, update, additionalScope, additionalReads)
2003
+ try {
2004
+ update()
2005
+ } catch (error) {
2006
+ removeUpdater()
2007
+ throw error
2008
+ }
2009
+ onCleanup(() => {
2010
+ removeUpdater()
2011
+ try {
2012
+ disposeRange(branchOwner, start, end)
2013
+ } finally {
2014
+ start.remove()
2015
+ end.remove()
2016
+ }
2017
+ })
2018
+ },
2019
+ 'slot',
2020
+ )
2021
+ }
2022
+
2023
+ export type ChoiceMode = 'truthy' | 'not-nullish'
2024
+
2025
+ export function choose(
2026
+ scope: CompiledScope,
2027
+ reads: SourceMask,
2028
+ mode: ChoiceMode,
2029
+ select: () => unknown,
2030
+ consequent: () => CompiledRenderValue,
2031
+ alternate: () => CompiledRenderValue,
2032
+ additionalScope?: CompiledScope,
2033
+ additionalReads?: SourceMask,
2034
+ ): StructuralBinding {
2035
+ return structural(
2036
+ scope,
2037
+ (parent, before) => {
2038
+ const range = structuralRange(parent, before, 'choice', true, true)
2039
+ const markerlessHydration = range === undefined
2040
+ const start = range?.[0] ?? document.createComment(DEV ? 'vidact:choice' : '')
2041
+ const end = range?.[1] ?? document.createComment(DEV ? '/vidact:choice' : '')
2042
+ const hydrated = range?.[2] ?? true
2043
+ const ownsMarkers = range?.[3] ?? true
2044
+ let selected = -1
2045
+ let branchOwner: Owner | null = null
2046
+ let branchNodes: readonly Node[] = []
2047
+
2048
+ const update = (): void => {
2049
+ const value = select()
2050
+ const next =
2051
+ mode === 'not-nullish' ? (value === null || value === undefined ? 1 : 0) : value ? 0 : 1
2052
+ if (next === selected) return
2053
+ const nextOwner = createOwner()
2054
+ const render = next === 0 ? consequent : alternate
2055
+ let nodes: readonly Node[]
2056
+ if (markerlessHydration && selected === -1) {
2057
+ const [first, after, hydratedNodes] = stageMarkerlessHydrationRender(
2058
+ parent,
2059
+ before,
2060
+ render,
2061
+ nextOwner,
2062
+ )
2063
+ parent.insertBefore(start, first)
2064
+ parent.insertBefore(end, after)
2065
+ nodes = hydratedNodes
2066
+ } else {
2067
+ const currentParent = rangeParent(start, end, 'choice block')
2068
+ const [fragment, stagedNodes] =
2069
+ hydrated && selected === -1
2070
+ ? withHydrationInsertion(currentParent, end, () => stageRender(render, nextOwner))
2071
+ : stageRender(render, nextOwner)
2072
+ currentParent.insertBefore(fragment, end)
2073
+ nodes = stagedNodes
2074
+ }
2075
+ try {
2076
+ commitPublishedNodes(nodes)
2077
+ } catch (error) {
2078
+ disposePublished(nextOwner, nodes)
2079
+ throw error
2080
+ }
2081
+
2082
+ const previousOwner = branchOwner
2083
+ const previousNodes = branchNodes
2084
+ branchOwner = nextOwner
2085
+ branchNodes = nodes
2086
+ selected = next
2087
+ disposePublished(previousOwner, previousNodes)
2088
+ }
2089
+
2090
+ const removeUpdater = subscribe(scope, reads, update, additionalScope, additionalReads)
2091
+ try {
2092
+ update()
2093
+ } catch (error) {
2094
+ removeUpdater()
2095
+ throw error
2096
+ }
2097
+ onCleanup(() => {
2098
+ removeUpdater()
2099
+ try {
2100
+ disposePublished(branchOwner, branchNodes)
2101
+ } finally {
2102
+ if (ownsMarkers) {
2103
+ start.remove()
2104
+ end.remove()
2105
+ }
2106
+ }
2107
+ })
2108
+ },
2109
+ 'slot',
2110
+ )
2111
+ }
2112
+
2113
+ export function dispatch(
2114
+ scope: CompiledScope,
2115
+ reads: SourceMask,
2116
+ type: () => unknown,
2117
+ key: () => unknown,
2118
+ render: () => CompiledRenderValue,
2119
+ additionalScope?: CompiledScope,
2120
+ additionalReads?: SourceMask,
2121
+ ): StructuralBinding {
2122
+ return structural(
2123
+ scope,
2124
+ (parent, before) => {
2125
+ const [start, end, hydrated] = structuralRange(parent, before, 'dispatch')
2126
+ const unset = Symbol('Vidact.UnsetIdentity')
2127
+ let currentType: unknown = unset
2128
+ let currentKey: unknown = unset
2129
+ let currentOwner: Owner | null = null
2130
+ let currentNodes: readonly Node[] = []
2131
+
2132
+ const update = (): void => {
2133
+ const nextType = type()
2134
+ const nextKey = key()
2135
+ if (
2136
+ currentType !== unset &&
2137
+ Object.is(nextType, currentType) &&
2138
+ Object.is(nextKey, currentKey)
2139
+ ) {
2140
+ return
2141
+ }
2142
+ const currentParent = rangeParent(start, end, 'dispatch block')
2143
+ const nextOwner = createOwner()
2144
+ const [fragment, nodes] =
2145
+ hydrated && currentType === unset
2146
+ ? withHydrationInsertion(currentParent, end, () => stageRender(render, nextOwner))
2147
+ : stageRender(render, nextOwner)
2148
+ currentParent.insertBefore(fragment, end)
2149
+ try {
2150
+ commitPublishedNodes(nodes)
2151
+ } catch (error) {
2152
+ disposePublished(nextOwner, nodes)
2153
+ throw error
2154
+ }
2155
+
2156
+ const previousOwner = currentOwner
2157
+ const previousNodes = currentNodes
2158
+ currentType = nextType
2159
+ currentKey = nextKey
2160
+ currentOwner = nextOwner
2161
+ currentNodes = nodes
2162
+ disposePublished(previousOwner, previousNodes)
2163
+ }
2164
+
2165
+ const removeUpdater = subscribe(scope, reads, update, additionalScope, additionalReads)
2166
+ try {
2167
+ update()
2168
+ } catch (error) {
2169
+ removeUpdater()
2170
+ throw error
2171
+ }
2172
+ onCleanup(() => {
2173
+ removeUpdater()
2174
+ try {
2175
+ disposePublished(currentOwner, currentNodes)
2176
+ } finally {
2177
+ start.remove()
2178
+ end.remove()
2179
+ }
2180
+ })
2181
+ },
2182
+ 'slot',
2183
+ )
2184
+ }
2185
+
2186
+ export function keyed<T, K>(
2187
+ scope: CompiledScope,
2188
+ reads: SourceMask,
2189
+ values: () => readonly T[],
2190
+ key: (value: T, index: number) => K,
2191
+ render: (value: StateSlot<T>, index: StateSlot<number>, itemScope: CompiledScope) => RenderValue,
2192
+ trackIndexOrAdditionalScope?: boolean | CompiledScope,
2193
+ additionalScopeOrReads?: CompiledScope | SourceMask,
2194
+ additionalReads?: SourceMask,
2195
+ ): StructuralBinding {
2196
+ const compilerManaged = typeof trackIndexOrAdditionalScope === 'boolean'
2197
+ const trackIndex =
2198
+ typeof trackIndexOrAdditionalScope === 'boolean' ? trackIndexOrAdditionalScope : true
2199
+ const additionalScope =
2200
+ typeof trackIndexOrAdditionalScope === 'boolean'
2201
+ ? (additionalScopeOrReads as CompiledScope | undefined)
2202
+ : trackIndexOrAdditionalScope
2203
+ const resolvedAdditionalReads =
2204
+ typeof trackIndexOrAdditionalScope === 'boolean'
2205
+ ? additionalReads
2206
+ : (additionalScopeOrReads as SourceMask | undefined)
2207
+ return structural(
2208
+ scope,
2209
+ (parent, before) => {
2210
+ const itemSource = 1
2211
+ const indexSource = 2
2212
+ const list = createKeyedList(
2213
+ parent,
2214
+ {
2215
+ key,
2216
+ render(value, index) {
2217
+ const itemScope = compilerManaged
2218
+ ? createCompilerKeyedScope()
2219
+ : createNarrowCompiledScope()
2220
+ const owner = scopeOwners.get(itemScope)!
2221
+ const valueSlot = compilerManaged
2222
+ ? createReadOnlyStateSlot(itemScope, itemSource, value)
2223
+ : createCompiledState(itemScope, itemSource, value)
2224
+ const indexSlot = trackIndex
2225
+ ? compilerManaged
2226
+ ? createReadOnlyStateSlot(itemScope, indexSource, index)
2227
+ : createCompiledState(itemScope, indexSource, index)
2228
+ : undefined
2229
+ try {
2230
+ const nodes = withOwner(owner, () => {
2231
+ const rendered = render(
2232
+ valueSlot as StateSlot<T>,
2233
+ indexSlot as StateSlot<number>,
2234
+ itemScope,
2235
+ )
2236
+ return !isHydrating() &&
2237
+ rendered instanceof Node &&
2238
+ !(rendered instanceof DocumentFragment)
2239
+ ? [rendered]
2240
+ : materialize(rendered)
2241
+ })
2242
+ return [
2243
+ nodes,
2244
+ (nextValue: T, nextIndex: number) => {
2245
+ if (
2246
+ Object.is(valueSlot.get(), nextValue) &&
2247
+ (!trackIndex || indexSlot!.get() === nextIndex)
2248
+ ) {
2249
+ return
2250
+ }
2251
+ itemScope[2](() => {
2252
+ if (compilerManaged) {
2253
+ replaceReadOnlyStateSlot(valueSlot as ReadOnlyStateCell<T>, nextValue)
2254
+ if (indexSlot !== undefined) {
2255
+ replaceReadOnlyStateSlot(indexSlot as ReadOnlyStateCell<number>, nextIndex)
2256
+ }
2257
+ } else {
2258
+ ;(valueSlot as StateSlot<T>).set(nextValue)
2259
+ ;(indexSlot as StateSlot<number> | undefined)?.set(nextIndex)
2260
+ }
2261
+ })
2262
+ },
2263
+ itemScope,
2264
+ ] as const
2265
+ } catch (error) {
2266
+ itemScope[3]()
2267
+ throw error
2268
+ }
2269
+ },
2270
+ },
2271
+ before,
2272
+ )
2273
+ const update = (): void => {
2274
+ try {
2275
+ commitPublishedNodes(list.update(values()))
2276
+ } catch (error) {
2277
+ const currentParent = list.parent()
2278
+ if (currentParent !== null) commitPendingRefs(currentParent)
2279
+ throw error
2280
+ }
2281
+ }
2282
+ update()
2283
+ const removeUpdater = subscribe(
2284
+ scope,
2285
+ reads,
2286
+ update,
2287
+ additionalScope,
2288
+ resolvedAdditionalReads,
2289
+ )
2290
+ onCleanup(() => {
2291
+ removeUpdater()
2292
+ list.dispose()
2293
+ })
2294
+ },
2295
+ 'array',
2296
+ )
2297
+ }
2298
+
2299
+ export function indexed<T>(
2300
+ scope: CompiledScope,
2301
+ reads: SourceMask,
2302
+ values: () => readonly T[],
2303
+ render: (value: StateSlot<T>, index: StateSlot<number>, itemScope: CompiledScope) => RenderValue,
2304
+ additionalScope?: CompiledScope,
2305
+ additionalReads?: SourceMask,
2306
+ ): StructuralBinding {
2307
+ return structural(
2308
+ scope,
2309
+ (parent, before) => {
2310
+ const itemSource = 1
2311
+ const indexSource = 2
2312
+ const list = createIndexedList<T>(
2313
+ parent,
2314
+ {
2315
+ render(value, index) {
2316
+ const owner = createOwner()
2317
+ const itemScope = createNarrowCompiledScope()
2318
+ const valueSlot = createCompiledState(itemScope, itemSource, value)
2319
+ const indexSlot = createCompiledState(itemScope, indexSource, index)
2320
+ try {
2321
+ const nodes = withOwner(owner, () => {
2322
+ onCleanup(itemScope[3])
2323
+ return materialize(render(valueSlot, indexSlot, itemScope))
2324
+ })
2325
+ return [
2326
+ nodes,
2327
+ (nextValue: T, nextIndex: number) => {
2328
+ itemScope[2](() => {
2329
+ valueSlot.set(nextValue)
2330
+ indexSlot.set(nextIndex)
2331
+ })
2332
+ },
2333
+ () => disposeOwner(owner),
2334
+ ] as const
2335
+ } catch (error) {
2336
+ disposeOwner(owner)
2337
+ throw error
2338
+ }
2339
+ },
2340
+ },
2341
+ before,
2342
+ )
2343
+ const update = (): void => {
2344
+ try {
2345
+ commitPublishedNodes(list.update(values()))
2346
+ } catch (error) {
2347
+ const currentParent = list.parent()
2348
+ if (currentParent !== null) commitPendingRefs(currentParent)
2349
+ throw error
2350
+ }
2351
+ }
2352
+ update()
2353
+ const removeUpdater = subscribe(scope, reads, update, additionalScope, additionalReads)
2354
+ onCleanup(() => {
2355
+ removeUpdater()
2356
+ list.dispose()
2357
+ })
2358
+ },
2359
+ 'array',
2360
+ )
2361
+ }
2362
+
2363
+ export function compiledRoot(
2364
+ scope: CompiledScope,
2365
+ render: () => CompiledRenderValue,
2366
+ ): CompiledComponentResult {
2367
+ const owner = scopeOwners.get(scope)
2368
+ if (owner === undefined) {
2369
+ throw new Error(DEV ? 'compiledRoot received an unknown scope' : 'V004')
2370
+ }
2371
+ const hydratedRange = claimHydrationComponentRange()
2372
+ const start = hydratedRange?.[0] ?? document.createComment(DEV ? 'vidact:component' : '')
2373
+ const end = hydratedRange?.[1] ?? document.createComment(DEV ? '/vidact:component' : '')
2374
+ componentCommitOwners.set(end, owner)
2375
+ const fragment = document.createDocumentFragment()
2376
+ if (hydratedRange === undefined) fragment.append(start, end)
2377
+ owner[1].push(() => {
2378
+ try {
2379
+ removeBetween(start, end)
2380
+ } finally {
2381
+ start.remove()
2382
+ end.remove()
2383
+ }
2384
+ })
2385
+
2386
+ try {
2387
+ const renderParent = hydrationRangeParent(start, end) ?? fragment
2388
+ const insertRender = () =>
2389
+ withOwner(owner, () =>
2390
+ withScopeNamespace(scope, () => insertValue(renderParent, render(), end)),
2391
+ )
2392
+ const insert = () => {
2393
+ if (hydratedRange === undefined) insertRender()
2394
+ else
2395
+ withHydrationComponentRange(hydratedRange, () =>
2396
+ withHydrationCursor(renderParent, start.nextSibling, insertRender),
2397
+ )
2398
+ }
2399
+ if (profilingEnabled) measureProfileWork(owner, 'range', insert)
2400
+ else insert()
2401
+ } catch (error) {
2402
+ try {
2403
+ scope[3]()
2404
+ } catch {
2405
+ // Preserve the render error that made this component unmountable.
2406
+ }
2407
+ throw error
2408
+ }
2409
+
2410
+ let mounted = false
2411
+ const component: CompiledComponentResult = [
2412
+ STRUCTURAL,
2413
+ (parent, before) => {
2414
+ if (mounted) throw new Error(DEV ? 'compiled component is already mounted' : 'V005')
2415
+ mounted = true
2416
+ adoptCompiledRoot(component)
2417
+ try {
2418
+ if (!claimHydrationComponentMount(parent, start, end)) {
2419
+ parent.insertBefore(fragment, before)
2420
+ }
2421
+ } catch (error) {
2422
+ try {
2423
+ scope[3]()
2424
+ } catch {
2425
+ // Preserve the insertion error that made this component unmountable.
2426
+ }
2427
+ throw error
2428
+ }
2429
+ },
2430
+ ]
2431
+ componentRanges.set(component, [start, end, scope])
2432
+ return component
2433
+ }
2434
+
2435
+ export function adoptCompiledRoot(root: unknown): void {
2436
+ if (!isCompiledComponentResult(root)) return
2437
+ const range = componentRanges.get(root)
2438
+ if (range === undefined) return
2439
+ const owner = scopeOwners.get(range[2])
2440
+ if (activeOwner !== null && owner !== undefined && activeOwner !== owner) {
2441
+ activeOwner[1].push(range[2][3])
2442
+ }
2443
+ }
2444
+
2445
+ export function constructCompiledComponent<T extends CompiledRenderValue>(
2446
+ component: () => T,
2447
+ componentType?: unknown,
2448
+ ): T {
2449
+ const previousCollector = activeScopeCollector
2450
+ const previousConstructionOwner = activeConstructionOwner
2451
+ const previousProfileName = activeProfileName
2452
+ const scopes = new Set<CompiledScope>()
2453
+ activeScopeCollector = scopes
2454
+ activeConstructionOwner = null
2455
+ const profileType = componentType as
2456
+ | { readonly name?: string; readonly displayName?: string }
2457
+ | undefined
2458
+ if (DEV) activeProfileName = profileType?.displayName ?? profileType?.name ?? 'Anonymous'
2459
+ try {
2460
+ return component()
2461
+ } catch (error) {
2462
+ // oxlint-disable-next-line unicorn/no-array-reverse - scopes is already copied to avoid mutation during iteration
2463
+ for (const scope of [...scopes].reverse()) {
2464
+ try {
2465
+ scope[3]()
2466
+ } catch {
2467
+ // Preserve the construction error that made this component unmountable.
2468
+ }
2469
+ }
2470
+ throw error
2471
+ } finally {
2472
+ activeScopeCollector = previousCollector
2473
+ activeConstructionOwner = previousConstructionOwner
2474
+ if (DEV) activeProfileName = previousProfileName
2475
+ }
2476
+ }
2477
+
2478
+ export function queueElementRef(element: Element, value: unknown): void {
2479
+ if (!isRefValue(value)) {
2480
+ throw new TypeError(DEV ? 'ref must be a callback or an object with current' : 'V006')
2481
+ }
2482
+ const pending: PendingRef = [activeOwner, value]
2483
+ setPendingRef(element, pending)
2484
+ activeOwner?.[1].push(() => deletePendingRef(element, pending))
2485
+ }
2486
+
2487
+ export function useImperativeHandle<T>(
2488
+ ref: RefValue<T>,
2489
+ create: () => T,
2490
+ dependencies?: readonly unknown[],
2491
+ ): void {
2492
+ const owner = activeConstructionOwner
2493
+ if (owner === null) {
2494
+ throw new Error(
2495
+ DEV ? 'useImperativeHandle must run during compiled component construction' : 'V013',
2496
+ )
2497
+ }
2498
+ if (!isRefValue(ref)) {
2499
+ throw new TypeError(
2500
+ DEV ? 'imperative ref must be null, a callback, or an object with current' : 'V006',
2501
+ )
2502
+ }
2503
+ if (dependencies !== undefined && dependencies.length !== 0) {
2504
+ throw new Error(
2505
+ DEV ? 'reactive useImperativeHandle dependencies are not supported yet' : 'V014',
2506
+ )
2507
+ }
2508
+ queueOwnerCommit(owner, () => owner[1].push(attachRef(ref, create())))
2509
+ }
2510
+
2511
+ type EffectResult = void | (() => void)
2512
+
2513
+ export function useLayoutEffect(
2514
+ create: () => EffectResult,
2515
+ dependencies?: readonly unknown[],
2516
+ ): void {
2517
+ registerEffect(create, dependencies, false)
2518
+ }
2519
+
2520
+ export function useInsertionEffect(
2521
+ create: () => EffectResult,
2522
+ dependencies?: readonly unknown[],
2523
+ ): void {
2524
+ const owner = activeConstructionOwner
2525
+ if (owner === null) {
2526
+ throw new Error(
2527
+ DEV ? 'insertion effects must run during compiled component construction' : 'V016',
2528
+ )
2529
+ }
2530
+ if (dependencies !== undefined && dependencies.length !== 0) {
2531
+ throw new Error(
2532
+ DEV ? 'reactive insertion effect dependencies require compiler lowering' : 'V017',
2533
+ )
2534
+ }
2535
+ const lifetimeOwner = activeOwner ?? owner
2536
+ if (!retainedUiEnabled) {
2537
+ let cleanup = noop
2538
+ queueInsertionCommit(owner, () => {
2539
+ if (lifetimeOwner[0]) return
2540
+ cleanup()
2541
+ cleanup = profilingEnabled
2542
+ ? readProfiledEffectCleanup(owner, create)
2543
+ : readEffectCleanup(create())
2544
+ })
2545
+ lifetimeOwner[1].push(() => cleanup())
2546
+ return
2547
+ }
2548
+ let cleanup = noop
2549
+ const [activate, disposeResource] = createRetainedResource(
2550
+ lifetimeOwner,
2551
+ () => {
2552
+ stagePublication([
2553
+ noop,
2554
+ noop,
2555
+ undefined,
2556
+ () => {
2557
+ cleanup = profilingEnabled
2558
+ ? readProfiledEffectCleanup(owner, create)
2559
+ : readEffectCleanup(create())
2560
+ },
2561
+ -20,
2562
+ ])
2563
+ },
2564
+ () => {
2565
+ cleanup()
2566
+ cleanup = noop
2567
+ },
2568
+ )
2569
+ queueInsertionCommit(owner, () => {
2570
+ if (!lifetimeOwner[0]) activate()
2571
+ })
2572
+ lifetimeOwner[1].push(disposeResource)
2573
+ }
2574
+
2575
+ export function useEffect(create: () => EffectResult, dependencies?: readonly unknown[]): void {
2576
+ registerEffect(create, dependencies, true)
2577
+ }
2578
+
2579
+ function registerEffect(
2580
+ create: () => EffectResult,
2581
+ dependencies: readonly unknown[] | undefined,
2582
+ passive: boolean,
2583
+ ): void {
2584
+ const owner = activeConstructionOwner
2585
+ if (owner === null) {
2586
+ throw new Error(DEV ? 'effects must run during compiled component construction' : 'V016')
2587
+ }
2588
+ if (dependencies !== undefined && dependencies.length !== 0) {
2589
+ throw new Error(DEV ? 'reactive effect dependencies require compiler lowering' : 'V017')
2590
+ }
2591
+ const lifetimeOwner = activeOwner ?? owner
2592
+ if (!retainedUiEnabled) {
2593
+ let cleanup = noop
2594
+ let generation = 0
2595
+ const run = (): void => {
2596
+ cleanup()
2597
+ cleanup = profilingEnabled
2598
+ ? readProfiledEffectCleanup(owner, create)
2599
+ : readEffectCleanup(create())
2600
+ }
2601
+ queueOwnerCommit(owner, () => {
2602
+ if (lifetimeOwner[0]) return
2603
+ if (passive) {
2604
+ const scheduled = ++generation
2605
+ ;(DEV ? scheduleTask : queueMicrotask)(() => {
2606
+ if (!lifetimeOwner[0] && scheduled === generation) runOwnerTask(lifetimeOwner, run)
2607
+ })
2608
+ } else {
2609
+ run()
2610
+ }
2611
+ })
2612
+ lifetimeOwner[1].push(() => {
2613
+ generation += 1
2614
+ if (passive) (DEV ? scheduleTask : queueMicrotask)(() => runOwnerTask(lifetimeOwner, cleanup))
2615
+ else cleanup()
2616
+ })
2617
+ return
2618
+ }
2619
+ let cleanup = noop
2620
+ let generation = 0
2621
+ const [activate, disposeResource] = createRetainedResource(
2622
+ lifetimeOwner,
2623
+ () => {
2624
+ stagePublication([
2625
+ noop,
2626
+ noop,
2627
+ undefined,
2628
+ () => {
2629
+ if (passive) {
2630
+ const scheduled = ++generation
2631
+ ;(DEV ? scheduleTask : queueMicrotask)(() => {
2632
+ if (!lifetimeOwner[0] && scheduled === generation) {
2633
+ runOwnerTask(lifetimeOwner, () => {
2634
+ cleanup = profilingEnabled
2635
+ ? readProfiledEffectCleanup(owner, create)
2636
+ : readEffectCleanup(create())
2637
+ })
2638
+ }
2639
+ })
2640
+ } else {
2641
+ cleanup = profilingEnabled
2642
+ ? readProfiledEffectCleanup(owner, create)
2643
+ : readEffectCleanup(create())
2644
+ }
2645
+ },
2646
+ passive ? 40 : 20,
2647
+ ])
2648
+ },
2649
+ () => {
2650
+ generation += 1
2651
+ const previousCleanup = cleanup
2652
+ cleanup = noop
2653
+ if (passive)
2654
+ (DEV ? scheduleTask : queueMicrotask)(() => runOwnerTask(lifetimeOwner, previousCleanup))
2655
+ else previousCleanup()
2656
+ },
2657
+ )
2658
+ queueOwnerCommit(owner, () => {
2659
+ if (!lifetimeOwner[0]) activate()
2660
+ })
2661
+ lifetimeOwner[1].push(disposeResource)
2662
+ }
2663
+
2664
+ export function compiledLayoutEffect(
2665
+ scope: CompiledScope,
2666
+ reads: SourceMask,
2667
+ readCreate: () => () => EffectResult,
2668
+ readDependencies?: () => readonly unknown[],
2669
+ ): void {
2670
+ compiledEffect(scope, reads, readCreate, readDependencies, false)
2671
+ }
2672
+
2673
+ export function compiledInsertionEffect(
2674
+ scope: CompiledScope,
2675
+ reads: SourceMask,
2676
+ readCreate: () => () => EffectResult,
2677
+ readDependencies?: () => readonly unknown[],
2678
+ ): void {
2679
+ const owner = activeConstructionOwner
2680
+ if (owner === null || scopeOwners.get(scope) !== owner) {
2681
+ throw new Error(DEV ? 'compiled insertion effects must run in their component scope' : 'V016')
2682
+ }
2683
+ const lifetimeOwner = activeOwner ?? owner
2684
+ if (!retainedUiEnabled) {
2685
+ let mounted = false
2686
+ let currentDependencies: readonly unknown[] | undefined
2687
+ let cleanup = noop
2688
+ const run = (): void => {
2689
+ const nextDependencies = readDependencies?.()
2690
+ if (
2691
+ mounted &&
2692
+ readDependencies !== undefined &&
2693
+ equalDependencies(nextDependencies, currentDependencies)
2694
+ ) {
2695
+ return
2696
+ }
2697
+ cleanup()
2698
+ cleanup = profilingEnabled
2699
+ ? readProfiledEffectCleanup(owner, () => readCreate()())
2700
+ : readEffectCleanup(readCreate()())
2701
+ currentDependencies = nextDependencies
2702
+ mounted = true
2703
+ }
2704
+ queueInsertionCommit(owner, () => {
2705
+ if (!lifetimeOwner[0]) run()
2706
+ })
2707
+ const removeUpdater = subscribe(scope, reads, () =>
2708
+ stagePublication([noop, noop, undefined, run, -20]),
2709
+ )
2710
+ lifetimeOwner[1].push(() => {
2711
+ removeUpdater()
2712
+ cleanup()
2713
+ })
2714
+ return
2715
+ }
2716
+ let mounted = false
2717
+ let connected = false
2718
+ let currentDependencies: readonly unknown[] | undefined
2719
+ let cleanup = noop
2720
+ const run = (): void => {
2721
+ const nextDependencies = readDependencies?.()
2722
+ if (
2723
+ mounted &&
2724
+ readDependencies !== undefined &&
2725
+ equalDependencies(nextDependencies, currentDependencies)
2726
+ ) {
2727
+ return
2728
+ }
2729
+ cleanup()
2730
+ cleanup = profilingEnabled
2731
+ ? readProfiledEffectCleanup(owner, () => readCreate()())
2732
+ : readEffectCleanup(readCreate()())
2733
+ currentDependencies = nextDependencies
2734
+ mounted = true
2735
+ }
2736
+ const [activate, disposeResource] = createRetainedResource(
2737
+ lifetimeOwner,
2738
+ () => {
2739
+ stagePublication([
2740
+ noop,
2741
+ noop,
2742
+ undefined,
2743
+ () => {
2744
+ connected = true
2745
+ run()
2746
+ },
2747
+ -20,
2748
+ ])
2749
+ },
2750
+ () => {
2751
+ connected = false
2752
+ cleanup()
2753
+ cleanup = noop
2754
+ mounted = false
2755
+ },
2756
+ )
2757
+ queueInsertionCommit(owner, () => {
2758
+ if (!lifetimeOwner[0]) activate()
2759
+ })
2760
+ const removeUpdater = subscribe(scope, reads, () => {
2761
+ if (connected) stagePublication([noop, noop, undefined, run, -20])
2762
+ })
2763
+ lifetimeOwner[1].push(() => {
2764
+ removeUpdater()
2765
+ disposeResource()
2766
+ })
2767
+ }
2768
+
2769
+ export function compiledEffect(
2770
+ scope: CompiledScope,
2771
+ reads: SourceMask,
2772
+ readCreate: () => () => EffectResult,
2773
+ readDependencies?: () => readonly unknown[],
2774
+ passive = true,
2775
+ ): void {
2776
+ const owner = activeConstructionOwner
2777
+ if (owner === null || scopeOwners.get(scope) !== owner) {
2778
+ throw new Error(DEV ? 'compiled effects must run in their component scope' : 'V016')
2779
+ }
2780
+ const lifetimeOwner = activeOwner ?? owner
2781
+ if (!retainedUiEnabled) {
2782
+ let mounted = false
2783
+ let generation = 0
2784
+ let currentDependencies: readonly unknown[] | undefined
2785
+ let cleanup = noop
2786
+ const run = (): void => {
2787
+ const nextDependencies = readDependencies?.()
2788
+ if (
2789
+ mounted &&
2790
+ readDependencies !== undefined &&
2791
+ equalDependencies(nextDependencies, currentDependencies)
2792
+ ) {
2793
+ return
2794
+ }
2795
+ cleanup()
2796
+ cleanup = profilingEnabled
2797
+ ? readProfiledEffectCleanup(owner, () => readCreate()())
2798
+ : readEffectCleanup(readCreate()())
2799
+ currentDependencies = nextDependencies
2800
+ mounted = true
2801
+ }
2802
+ const schedule = (): void => {
2803
+ if (!passive) {
2804
+ run()
2805
+ return
2806
+ }
2807
+ const scheduled = ++generation
2808
+ ;(DEV ? scheduleTask : queueMicrotask)(() => {
2809
+ if (!lifetimeOwner[0] && scheduled === generation) runOwnerTask(lifetimeOwner, run)
2810
+ })
2811
+ }
2812
+ queueOwnerCommit(owner, () => {
2813
+ if (!lifetimeOwner[0]) schedule()
2814
+ })
2815
+ const removeUpdater = subscribe(scope, reads, () => {
2816
+ if (passive) schedule()
2817
+ else stagePublication([noop, noop, undefined, run, 20])
2818
+ })
2819
+ lifetimeOwner[1].push(() => {
2820
+ generation += 1
2821
+ removeUpdater()
2822
+ if (passive) (DEV ? scheduleTask : queueMicrotask)(() => runOwnerTask(lifetimeOwner, cleanup))
2823
+ else cleanup()
2824
+ })
2825
+ return
2826
+ }
2827
+ let mounted = false
2828
+ let connected = false
2829
+ let generation = 0
2830
+ let currentDependencies: readonly unknown[] | undefined
2831
+ let cleanup = noop
2832
+ const run = (): void => {
2833
+ const nextDependencies = readDependencies?.()
2834
+ if (
2835
+ mounted &&
2836
+ readDependencies !== undefined &&
2837
+ equalDependencies(nextDependencies, currentDependencies)
2838
+ ) {
2839
+ return
2840
+ }
2841
+ cleanup()
2842
+ cleanup = profilingEnabled
2843
+ ? readProfiledEffectCleanup(owner, () => readCreate()())
2844
+ : readEffectCleanup(readCreate()())
2845
+ currentDependencies = nextDependencies
2846
+ mounted = true
2847
+ }
2848
+ const schedule = (): void => {
2849
+ if (!connected) return
2850
+ if (!passive) {
2851
+ run()
2852
+ return
2853
+ }
2854
+ const scheduled = ++generation
2855
+ ;(DEV ? scheduleTask : queueMicrotask)(() => {
2856
+ if (!lifetimeOwner[0] && scheduled === generation) runOwnerTask(lifetimeOwner, run)
2857
+ })
2858
+ }
2859
+ const [activate, disposeResource] = createRetainedResource(
2860
+ lifetimeOwner,
2861
+ () => {
2862
+ stagePublication([
2863
+ noop,
2864
+ noop,
2865
+ undefined,
2866
+ () => {
2867
+ connected = true
2868
+ schedule()
2869
+ },
2870
+ passive ? 40 : 20,
2871
+ ])
2872
+ },
2873
+ () => {
2874
+ connected = false
2875
+ generation += 1
2876
+ const previousCleanup = cleanup
2877
+ cleanup = noop
2878
+ mounted = false
2879
+ if (passive)
2880
+ (DEV ? scheduleTask : queueMicrotask)(() => runOwnerTask(lifetimeOwner, previousCleanup))
2881
+ else previousCleanup()
2882
+ },
2883
+ )
2884
+ queueOwnerCommit(owner, () => {
2885
+ if (!lifetimeOwner[0]) activate()
2886
+ })
2887
+ const removeUpdater = subscribe(scope, reads, () => {
2888
+ if (!connected) return
2889
+ if (passive) schedule()
2890
+ else stagePublication([noop, noop, undefined, run, 20])
2891
+ })
2892
+ lifetimeOwner[1].push(() => {
2893
+ removeUpdater()
2894
+ disposeResource()
2895
+ })
2896
+ }
2897
+
2898
+ function readEffectCleanup(result: EffectResult): () => void {
2899
+ if (result === undefined) return noop
2900
+ if (typeof result === 'function') return result
2901
+ throw new TypeError(DEV ? 'an effect must return a cleanup function or undefined' : 'V018')
2902
+ }
2903
+
2904
+ export function compiledImperativeHandle<T>(
2905
+ scope: CompiledScope,
2906
+ reads: SourceMask,
2907
+ readRef: () => RefValue<T>,
2908
+ create: () => T,
2909
+ readDependencies?: () => readonly unknown[],
2910
+ ): void {
2911
+ const owner = activeConstructionOwner
2912
+ if (owner === null || scopeOwners.get(scope) !== owner) {
2913
+ throw new Error(
2914
+ DEV ? 'compiledImperativeHandle must run in its compiled component scope' : 'V013',
2915
+ )
2916
+ }
2917
+
2918
+ let mounted = false
2919
+ let currentRef: RefValue<T>
2920
+ let currentHandle: T
2921
+ let currentDependencies: readonly unknown[] | undefined
2922
+ // oxlint-disable-next-line unicorn/consistent-function-scoping -- This placeholder is replaced by the committed resource cleanup.
2923
+ let cleanup = noop
2924
+
2925
+ const commitInitial = (): void => {
2926
+ currentRef = readImperativeRef(readRef())
2927
+ currentDependencies = readDependencies?.()
2928
+ currentHandle = create()
2929
+ cleanup = attachRef(currentRef, currentHandle)
2930
+ mounted = true
2931
+ }
2932
+ queueOwnerCommit(owner, commitInitial)
2933
+
2934
+ const update = (): void => {
2935
+ if (!mounted) return
2936
+ const nextRef = readImperativeRef(readRef())
2937
+ const nextDependencies = readDependencies?.()
2938
+ if (
2939
+ Object.is(nextRef, currentRef) &&
2940
+ readDependencies !== undefined &&
2941
+ equalDependencies(nextDependencies, currentDependencies)
2942
+ ) {
2943
+ return
2944
+ }
2945
+
2946
+ const previousRef = currentRef
2947
+ const previousHandle = currentHandle
2948
+ const previousDependencies = currentDependencies
2949
+ const previousCleanup = cleanup
2950
+ let nextCleanup: (() => void) | undefined
2951
+ let finalized = false
2952
+ stagePublication([
2953
+ noop,
2954
+ () => {
2955
+ if (!finalized) return
2956
+ nextCleanup?.()
2957
+ cleanup = attachRef(previousRef, previousHandle)
2958
+ currentRef = previousRef
2959
+ currentHandle = previousHandle
2960
+ currentDependencies = previousDependencies
2961
+ finalized = false
2962
+ },
2963
+ undefined,
2964
+ () => {
2965
+ const nextHandle = create()
2966
+ if (Object.is(nextRef, previousRef)) {
2967
+ try {
2968
+ previousCleanup()
2969
+ } catch (error) {
2970
+ try {
2971
+ cleanup = attachRef(previousRef, previousHandle)
2972
+ } catch {
2973
+ // Preserve the cleanup error that aborted publication.
2974
+ }
2975
+ throw error
2976
+ }
2977
+ try {
2978
+ nextCleanup = attachRef(nextRef, nextHandle)
2979
+ } catch (error) {
2980
+ try {
2981
+ cleanup = attachRef(previousRef, previousHandle)
2982
+ } catch {
2983
+ // Preserve the next-ref attachment error.
2984
+ }
2985
+ throw error
2986
+ }
2987
+ } else {
2988
+ nextCleanup = attachRef(nextRef, nextHandle)
2989
+ try {
2990
+ previousCleanup()
2991
+ } catch (error) {
2992
+ nextCleanup()
2993
+ try {
2994
+ cleanup = attachRef(previousRef, previousHandle)
2995
+ } catch {
2996
+ // Preserve the previous-ref cleanup error.
2997
+ }
2998
+ throw error
2999
+ }
3000
+ }
3001
+ cleanup = nextCleanup
3002
+ currentRef = nextRef
3003
+ currentHandle = nextHandle
3004
+ currentDependencies = nextDependencies
3005
+ finalized = true
3006
+ },
3007
+ 10,
3008
+ ])
3009
+ }
3010
+ const removeUpdater = subscribe(scope, reads, update)
3011
+ owner[1].push(() => {
3012
+ removeUpdater()
3013
+ cleanup()
3014
+ })
3015
+ }
3016
+
3017
+ function queueOwnerCommit(owner: Owner, commit: () => void): void {
3018
+ let commits = pendingOwnerCommits.get(owner)
3019
+ if (commits === undefined) {
3020
+ commits = new Set()
3021
+ pendingOwnerCommits.set(owner, commits)
3022
+ pendingOwnerCommitCount += 1
3023
+ }
3024
+ commits.add(commit)
3025
+ }
3026
+
3027
+ function queueInsertionCommit(owner: Owner, commit: () => void): void {
3028
+ let commits = pendingInsertionCommits.get(owner)
3029
+ if (commits === undefined) {
3030
+ commits = new Set()
3031
+ pendingInsertionCommits.set(owner, commits)
3032
+ pendingInsertionOwnerCount += 1
3033
+ }
3034
+ commits.add(commit)
3035
+ }
3036
+
3037
+ function readImperativeRef<T>(ref: RefValue<T>): RefValue<T> {
3038
+ if (!isRefValue(ref)) {
3039
+ throw new TypeError(
3040
+ DEV ? 'imperative ref must be null, a callback, or an object with current' : 'V006',
3041
+ )
3042
+ }
3043
+ return ref
3044
+ }
3045
+
3046
+ function equalDependencies(
3047
+ next: readonly unknown[] | undefined,
3048
+ previous: readonly unknown[] | undefined,
3049
+ ): boolean {
3050
+ if (next === undefined || previous === undefined || next.length !== previous.length) return false
3051
+ return next.every((value, index) => Object.is(value, previous[index]))
3052
+ }
3053
+
3054
+ export function mountCompiledRef(element: Element, value: CompiledBinding<unknown>): void {
3055
+ const initial = value[1]()
3056
+ if (!isRefValue(initial)) {
3057
+ throw new TypeError(DEV ? 'ref must be null, a callback, or an object with current' : 'V006')
3058
+ }
3059
+ let current: RefValue = initial
3060
+ // oxlint-disable-next-line unicorn/consistent-function-scoping -- This placeholder is replaced when the ref attaches.
3061
+ let cleanup = noop
3062
+ const pending: PendingRef = [activeOwner, current, (attached) => (cleanup = attached)]
3063
+ setPendingRef(element, pending)
3064
+
3065
+ const removeUpdater = subscribeBinding(value, () => {
3066
+ const next = value[1]()
3067
+ if (Object.is(next, current)) return
3068
+ if (!isRefValue(next)) {
3069
+ throw new TypeError(DEV ? 'ref must be null, a callback, or an object with current' : 'V006')
3070
+ }
3071
+ const previous = current
3072
+ const previousCleanup = cleanup
3073
+ let nextCleanup: (() => void) | undefined
3074
+ let previousDetached = false
3075
+ let committed = false
3076
+ stagePublication([
3077
+ () => {
3078
+ try {
3079
+ previousCleanup()
3080
+ previousDetached = true
3081
+ } catch (error) {
3082
+ try {
3083
+ cleanup = attachRef(previous, element)
3084
+ } catch {
3085
+ // Preserve the previous-ref cleanup error.
3086
+ }
3087
+ throw error
3088
+ }
3089
+ try {
3090
+ nextCleanup = attachRef(next, element)
3091
+ } catch (error) {
3092
+ try {
3093
+ cleanup = attachRef(previous, element)
3094
+ previousDetached = false
3095
+ } catch {
3096
+ // Preserve the next-ref attachment error.
3097
+ }
3098
+ throw error
3099
+ }
3100
+ cleanup = nextCleanup
3101
+ current = next
3102
+ committed = true
3103
+ },
3104
+ () => {
3105
+ if (!committed) {
3106
+ nextCleanup?.()
3107
+ if (previousDetached) {
3108
+ cleanup = attachRef(previous, element)
3109
+ previousDetached = false
3110
+ }
3111
+ return
3112
+ }
3113
+ cleanup()
3114
+ cleanup = attachRef(previous, element)
3115
+ current = previous
3116
+ committed = false
3117
+ },
3118
+ ])
3119
+ })
3120
+ onCleanup(() => {
3121
+ removeUpdater()
3122
+ deletePendingRef(element, pending)
3123
+ cleanup()
3124
+ })
3125
+ }
3126
+
3127
+ export function registerCompiledCleanup(cleanup: () => void): void {
3128
+ onCleanup(cleanup)
3129
+ }
3130
+
3131
+ export interface MountCompiledOptions {
3132
+ readonly identifierPrefix?: string
3133
+ readonly onCaughtError?: CompiledErrorHandler
3134
+ readonly onRecoverableError?: CompiledErrorHandler
3135
+ readonly onUncaughtError?: CompiledErrorHandler
3136
+ }
3137
+
3138
+ export function hydrateCompiled(
3139
+ component: () => CompiledComponentResult,
3140
+ host: ParentNode,
3141
+ options?: MountCompiledOptions,
3142
+ ): { dispose: () => void } {
3143
+ let endHydration: (() => void) | undefined
3144
+ let hydratedMount: { dispose: () => void } | undefined
3145
+ try {
3146
+ endHydration = beginHydration(host)
3147
+ hydratedMount = mountCompiled(component, host, options)
3148
+ finishHydration()
3149
+ const rootMarkers = hydrationRootMarkers()
3150
+ return {
3151
+ dispose: () => {
3152
+ try {
3153
+ hydratedMount?.dispose()
3154
+ } finally {
3155
+ removeBetween(rootMarkers[0], rootMarkers[1])
3156
+ rootMarkers[0].remove()
3157
+ rootMarkers[1].remove()
3158
+ }
3159
+ },
3160
+ }
3161
+ } catch (error) {
3162
+ if (!isHydrationMismatch(error)) throw error
3163
+ try {
3164
+ hydratedMount?.dispose()
3165
+ } catch {
3166
+ // Preserve and report the mismatch that forced recovery.
3167
+ }
3168
+ hydratedMount = undefined
3169
+ endHydration?.()
3170
+ endHydration = undefined
3171
+ options?.onRecoverableError?.(error)
3172
+ return mountCompiled(component, host, options)
3173
+ } finally {
3174
+ endHydration?.()
3175
+ }
3176
+ }
3177
+
3178
+ export function mountCompiled(
3179
+ component: () => CompiledComponentResult,
3180
+ host: ParentNode,
3181
+ options?: MountCompiledOptions,
3182
+ ): { dispose: () => void } {
3183
+ const hydrating = isHydrating()
3184
+ const previousRootIdentity = activeRootIdentity
3185
+ const rootIdentity = createRootIdentity(
3186
+ options?.identifierPrefix,
3187
+ options?.onCaughtError,
3188
+ options?.onUncaughtError,
3189
+ )
3190
+ activeRootIdentity = rootIdentity
3191
+ let root: CompiledComponentResult
3192
+ try {
3193
+ root = constructCompiledComponent(component)
3194
+ } catch (error) {
3195
+ if (isHydrationMismatch(error)) throw error
3196
+ if (rootIdentity.onUncaughtError === undefined) throw error
3197
+ rootIdentity.onUncaughtError(error)
3198
+ return { dispose: noop }
3199
+ } finally {
3200
+ activeRootIdentity = previousRootIdentity
3201
+ }
3202
+ const range = componentRanges.get(root)
3203
+ if (range === undefined) {
3204
+ throw new Error(DEV ? 'mountCompiled received an unknown component result' : 'V007')
3205
+ }
3206
+ const previous = [...host.childNodes]
3207
+ const releaseEventRoot = retainCompiledEventRoot(host)
3208
+ try {
3209
+ root[1](host, previous[0] ?? null)
3210
+ const rootOwner = scopeOwners.get(range[2])
3211
+ const mountedRootIdentity = rootOwner?.[3]
3212
+ if (mountedRootIdentity !== undefined) {
3213
+ mountedRootIdentity.mounted = true
3214
+ commitRootPortals(mountedRootIdentity)
3215
+ }
3216
+ commitOwnerInsertions(rootOwner)
3217
+ commitRangeRefs(range[0], range[1])
3218
+ commitOwnerResources(rootOwner)
3219
+ if (!hydrating) {
3220
+ for (const node of previous) host.removeChild(node)
3221
+ }
3222
+ } catch (error) {
3223
+ releaseEventRoot()
3224
+ try {
3225
+ range[2][3]()
3226
+ } catch {
3227
+ // Preserve the mount error while still running every component cleanup.
3228
+ }
3229
+ if (isHydrationMismatch(error) || rootIdentity.onUncaughtError === undefined) throw error
3230
+ rootIdentity.onUncaughtError(error)
3231
+ return { dispose: noop }
3232
+ }
3233
+ let disposed = false
3234
+ return {
3235
+ dispose: () => {
3236
+ if (disposed) return
3237
+ disposed = true
3238
+ try {
3239
+ range[2][3]()
3240
+ } finally {
3241
+ releaseEventRoot()
3242
+ }
3243
+ },
3244
+ }
3245
+ }
3246
+
3247
+ export function isCompiledBinding(value: unknown): value is CompiledBinding<unknown> {
3248
+ return Array.isArray(value) && value[0] === BINDING
3249
+ }
3250
+
3251
+ export function isStructuralBinding(value: unknown): value is StructuralBinding {
3252
+ return Array.isArray(value) && value[0] === STRUCTURAL
3253
+ }
3254
+
3255
+ export function isCompiledComponentResult(value: unknown): value is CompiledComponentResult {
3256
+ return isStructuralBinding(value) && componentRanges.has(value)
3257
+ }
3258
+
3259
+ export function mountCompiledBinding(parent: Node, value: CompiledBinding<unknown>): void {
3260
+ mountCompiledBindingBefore(parent, value, null)
3261
+ }
3262
+
3263
+ type CompiledPropApply<T> =
3264
+ | ((next: T) => void | (() => void))
3265
+ | ((element: Element, name: string, next: T) => void | (() => void))
3266
+
3267
+ function applyCompiledPropValue<T>(
3268
+ apply: CompiledPropApply<T>,
3269
+ element: Element | undefined,
3270
+ name: string | undefined,
3271
+ next: T,
3272
+ ): void | (() => void) {
3273
+ return element === undefined
3274
+ ? (apply as (next: T) => void | (() => void))(next)
3275
+ : (apply as (element: Element, name: string, next: T) => void | (() => void))(
3276
+ element,
3277
+ name!,
3278
+ next,
3279
+ )
3280
+ }
3281
+
3282
+ export function mountCompiledProp<T>(
3283
+ value: CompiledBinding<T>,
3284
+ apply: (next: T) => void | (() => void),
3285
+ ): void
3286
+ export function mountCompiledProp<T>(
3287
+ value: CompiledBinding<T>,
3288
+ apply: (element: Element, name: string, next: T) => void | (() => void),
3289
+ element: Element,
3290
+ name: string,
3291
+ ): void
3292
+ export function mountCompiledProp<T>(
3293
+ value: CompiledBinding<T>,
3294
+ apply: CompiledPropApply<T>,
3295
+ element?: Element,
3296
+ name?: string,
3297
+ ): void {
3298
+ let current = value[1]()
3299
+ let cleanup = applyCompiledPropValue(apply, element, name, current)
3300
+ const removeUpdater = subscribeBinding(value, () => {
3301
+ const next = value[1]()
3302
+ if (Object.is(next, current)) return
3303
+ const previous = current
3304
+ let nextCleanup: void | (() => void)
3305
+ let committedNext = false
3306
+ stagePublication([
3307
+ () => {
3308
+ try {
3309
+ nextCleanup = applyCompiledPropValue(apply, element, name, next)
3310
+ } catch (error) {
3311
+ try {
3312
+ applyCompiledPropValue(apply, element, name, previous)
3313
+ } catch {
3314
+ // Preserve the setter error that aborted publication.
3315
+ }
3316
+ throw error
3317
+ }
3318
+ committedNext = true
3319
+ cleanup?.()
3320
+ cleanup = nextCleanup
3321
+ current = next
3322
+ },
3323
+ () => {
3324
+ if (!committedNext) return
3325
+ nextCleanup?.()
3326
+ cleanup = applyCompiledPropValue(apply, element, name, previous)
3327
+ current = previous
3328
+ committedNext = false
3329
+ },
3330
+ ])
3331
+ })
3332
+ onCleanup(() => {
3333
+ removeUpdater()
3334
+ cleanup?.()
3335
+ })
3336
+ }
3337
+
3338
+ export function mountCompiledPropTransition<T>(
3339
+ value: CompiledBinding<T>,
3340
+ initialize: (initial: T) => void,
3341
+ prepare: (next: T, previous: T) => CompiledPropTransition | undefined,
3342
+ ): void {
3343
+ let current = value[1]()
3344
+ initialize(current)
3345
+ const removeUpdater = subscribeBinding(value, () => {
3346
+ const next = value[1]()
3347
+ if (Object.is(next, current)) return
3348
+ const previous = current
3349
+ const transition = prepare(next, previous)
3350
+ let attempted = false
3351
+ stagePublication([
3352
+ () => {
3353
+ attempted = true
3354
+ transition?.[0]()
3355
+ current = next
3356
+ },
3357
+ () => {
3358
+ if (!attempted) return
3359
+ try {
3360
+ transition?.[1]()
3361
+ } finally {
3362
+ current = previous
3363
+ attempted = false
3364
+ }
3365
+ },
3366
+ transition?.[2],
3367
+ transition?.[3],
3368
+ transition?.[4],
3369
+ ])
3370
+ })
3371
+ onCleanup(removeUpdater)
3372
+ }
3373
+
3374
+ function structural(
3375
+ scope: CompiledScope,
3376
+ mount: StructuralBinding[1],
3377
+ hydrationKind?: StructuralBinding[2],
3378
+ ): StructuralBinding {
3379
+ // Only lists carry an array marker; a slot-kind structural must not bias the claim.
3380
+ if (hydrationKind === 'array') noteHydrationStructuralParent()
3381
+ let mounted = false
3382
+ const owner = activeOwner ?? scopeOwners.get(scope)!
3383
+ const context = activeContextFrame ?? owner[2]
3384
+ const mountOnce: StructuralBinding[1] = (parent, before) => {
3385
+ if (mounted) throw new Error(DEV ? 'compiled block is already mounted' : 'V008')
3386
+ mounted = true
3387
+ const operation = () =>
3388
+ withOwner(owner, () =>
3389
+ withContextFrame(context, () => withScopeNamespace(scope, () => mount(parent, before))),
3390
+ )
3391
+ if (profilingEnabled) measureProfileWork(owner, 'range', operation)
3392
+ else operation()
3393
+ }
3394
+ return hydrationKind === undefined
3395
+ ? [STRUCTURAL, mountOnce]
3396
+ : [STRUCTURAL, mountOnce, hydrationKind]
3397
+ }
3398
+
3399
+ function structuralRange(
3400
+ parent: Node,
3401
+ before: Node | null,
3402
+ label: string,
3403
+ borrowOuter?: boolean,
3404
+ allowMarkerlessHydration?: false,
3405
+ ): readonly [start: Comment, end: Comment, hydrated: boolean, ownsMarkers: boolean]
3406
+ function structuralRange(
3407
+ parent: Node,
3408
+ before: Node | null,
3409
+ label: string,
3410
+ borrowOuter: boolean,
3411
+ allowMarkerlessHydration: true,
3412
+ ): readonly [start: Comment, end: Comment, hydrated: boolean, ownsMarkers: boolean] | undefined
3413
+ function structuralRange(
3414
+ parent: Node,
3415
+ before: Node | null,
3416
+ label: string,
3417
+ borrowOuter = false,
3418
+ allowMarkerlessHydration = false,
3419
+ ): readonly [start: Comment, end: Comment, hydrated: boolean, ownsMarkers: boolean] | undefined {
3420
+ const current = borrowHydrationSlotRange(parent, true)
3421
+ if (current !== undefined) {
3422
+ claimHydrationSlotRange(parent)
3423
+ return [current[0], current[1], true, true]
3424
+ }
3425
+ if (borrowOuter) {
3426
+ const outer = borrowHydrationSlotRange(parent, false)
3427
+ if (outer !== undefined) return [outer[0], outer[1], true, false]
3428
+ }
3429
+ if (allowMarkerlessHydration && hydrationCursor(parent) !== undefined) return undefined
3430
+ const hydrated = claimHydrationSlotRange(parent)
3431
+ if (hydrated !== undefined) return [hydrated[0], hydrated[1], true, true]
3432
+ const start = document.createComment(DEV ? `vidact:${label}` : '')
3433
+ const end = document.createComment(DEV ? `/vidact:${label}` : '')
3434
+ parent.insertBefore(start, before)
3435
+ parent.insertBefore(end, before)
3436
+ return [start, end, false, true]
3437
+ }
3438
+
3439
+ function subscribe(
3440
+ scope: CompiledScope,
3441
+ reads: SourceMask,
3442
+ run: () => void,
3443
+ additionalScope?: CompiledScope,
3444
+ additionalReads?: SourceMask,
3445
+ ): () => void {
3446
+ let first: (() => void) | undefined
3447
+ if (!isEmptySources(reads)) {
3448
+ const remove = scope[0](reads, run)
3449
+ if (remove !== noop) first = remove
3450
+ }
3451
+ let second: (() => void) | undefined
3452
+ if (
3453
+ additionalScope !== undefined &&
3454
+ additionalReads !== undefined &&
3455
+ !isEmptySources(additionalReads)
3456
+ ) {
3457
+ const additionalRun =
3458
+ scopeNamespaces.get(additionalScope) === scopeNamespaces.get(scope)
3459
+ ? run
3460
+ : () => withScopeNamespace(scope, run)
3461
+ const remove = additionalScope[0](additionalReads, additionalRun)
3462
+ if (remove !== noop) second = remove
3463
+ }
3464
+ if (first === undefined) return second ?? noop
3465
+ if (second === undefined) return first
3466
+ return () => {
3467
+ first()
3468
+ second()
3469
+ }
3470
+ }
3471
+
3472
+ function subscribeBinding(compiledBinding: CompiledBinding<unknown>, run: () => void): () => void {
3473
+ return subscribe(
3474
+ compiledBinding[2],
3475
+ compiledBinding[3],
3476
+ run,
3477
+ compiledBinding[4],
3478
+ compiledBinding[5],
3479
+ )
3480
+ }
3481
+
3482
+ function withScopeNamespace<Result>(scope: CompiledScope, operation: () => Result): Result {
3483
+ return withIntrinsicNamespace(scopeNamespaces.get(scope), operation)
3484
+ }
3485
+
3486
+ function createOwner(
3487
+ context = activeContextFrame ?? activeOwner?.[2] ?? null,
3488
+ rootIdentity = activeOwner?.[3] ?? activeRootIdentity ?? createRootIdentity(),
3489
+ boundary = activeOwner?.[4] ?? null,
3490
+ retainedConnection = activeOwner?.[5] ?? null,
3491
+ profileContext = activeOwner?.[6] ?? activeConstructionOwner?.[6] ?? null,
3492
+ ): Owner {
3493
+ if (DEV) {
3494
+ activeOwnerCount += 1
3495
+ createdOwnerCount += 1
3496
+ }
3497
+ let nextProfile = profileContext
3498
+ if (profilingEnabled && activeProfileName !== null && activeConstructionOwner === null) {
3499
+ nextProfile = {
3500
+ frame: {
3501
+ name: activeProfileName,
3502
+ parent: profileContext?.frame ?? null,
3503
+ values: [],
3504
+ },
3505
+ boundary: profileContext?.boundary ?? null,
3506
+ }
3507
+ }
3508
+ if (profilingEnabled) {
3509
+ const owner: Owner = [
3510
+ false,
3511
+ [],
3512
+ context,
3513
+ rootIdentity,
3514
+ boundary,
3515
+ retainedUiEnabled ? retainedConnection : null,
3516
+ nextProfile,
3517
+ ]
3518
+ if (DEV) owner[7] = activeConstructionOwner?.[7] ?? activeProfileName
3519
+ return owner
3520
+ }
3521
+ const owner: Owner = retainedUiEnabled
3522
+ ? [false, [], context, rootIdentity, boundary, retainedConnection]
3523
+ : [false, [], context, rootIdentity, boundary]
3524
+ if (DEV) owner[7] = activeConstructionOwner?.[7] ?? activeProfileName
3525
+ return owner
3526
+ }
3527
+
3528
+ function ensureProfileContext(owner: Owner): ProfileContext {
3529
+ const current = owner[6]
3530
+ if (current?.frame !== null && current?.frame !== undefined) return current
3531
+ const parent =
3532
+ current ?? (activeOwner !== null && activeOwner !== owner ? (activeOwner[6] ?? null) : null)
3533
+ const next = {
3534
+ frame: {
3535
+ name: owner[7] ?? activeProfileName ?? 'Anonymous',
3536
+ parent: parent?.frame ?? null,
3537
+ values: [],
3538
+ },
3539
+ boundary: parent?.boundary ?? null,
3540
+ }
3541
+ owner[6] = next
3542
+ return next
3543
+ }
3544
+
3545
+ function profileNow(): number {
3546
+ return typeof performance === 'undefined' ? Date.now() : performance.now()
3547
+ }
3548
+
3549
+ function measureProfileWork<Result>(
3550
+ owner: Owner,
3551
+ kind: 'effect' | 'range' | 'scheduler' | 'updater',
3552
+ operation: () => Result,
3553
+ contribute = false,
3554
+ ): Result {
3555
+ const started = profileNow()
3556
+ try {
3557
+ return operation()
3558
+ } finally {
3559
+ const finished = profileNow()
3560
+ emitProfileMeasure(owner, kind, started, finished)
3561
+ if (contribute) recordProfileCommit(owner, started, finished)
3562
+ }
3563
+ }
3564
+
3565
+ function emitProfileMeasure(
3566
+ owner: Owner,
3567
+ kind: 'effect' | 'range' | 'scheduler' | 'updater',
3568
+ started: number,
3569
+ finished: number,
3570
+ ): void {
3571
+ if (typeof performance === 'undefined' || typeof performance.measure !== 'function') return
3572
+ const component = owner[6]?.frame?.name ?? 'Anonymous'
3573
+ performance.measure(`vidact.${kind}:${component}`, { start: started, end: finished })
3574
+ }
3575
+
3576
+ function recordProfileCommit(owner: Owner, started: number, finished: number): void {
3577
+ let boundary = owner[6]?.boundary ?? null
3578
+ while (boundary !== null) {
3579
+ queueProfileBoundaryCommit(boundary, owner, started, finished)
3580
+ boundary = boundary.parent
3581
+ }
3582
+ }
3583
+
3584
+ function queueProfileBoundaryCommit(
3585
+ boundary: ProfileBoundary,
3586
+ owner: Owner,
3587
+ started: number,
3588
+ finished: number,
3589
+ ): void {
3590
+ if (!boundary.mounted) return
3591
+ boundary.pendingDuration += finished - started
3592
+ boundary.pendingStart =
3593
+ boundary.pendingStart === 0 ? started : Math.min(boundary.pendingStart, started)
3594
+ if (boundary.scheduled) return
3595
+ boundary.scheduled = true
3596
+ stagePublication([
3597
+ noop,
3598
+ noop,
3599
+ undefined,
3600
+ () => {
3601
+ const actualDuration = boundary.pendingDuration
3602
+ const startTime = boundary.pendingStart
3603
+ boundary.pendingDuration = 0
3604
+ boundary.pendingStart = 0
3605
+ boundary.scheduled = false
3606
+ boundary.onRender(
3607
+ boundary.id,
3608
+ 'update',
3609
+ actualDuration,
3610
+ boundary.baseDuration,
3611
+ startTime,
3612
+ profileNow(),
3613
+ )
3614
+ },
3615
+ 100,
3616
+ owner,
3617
+ ])
3618
+ }
3619
+
3620
+ function readProfiledEffectCleanup(owner: Owner, evaluate: () => EffectResult): () => void {
3621
+ const cleanup = measureProfileWork(owner, 'effect', () => readEffectCleanup(evaluate()))
3622
+ if (cleanup === noop) return cleanup
3623
+ return () => measureProfileWork(owner, 'effect', cleanup)
3624
+ }
3625
+
3626
+ function createRetainedConnection(
3627
+ parent: RetainedConnection | null,
3628
+ visible: boolean,
3629
+ ): RetainedConnection {
3630
+ const connection: RetainedConnection = {
3631
+ parent,
3632
+ children: new Set(),
3633
+ resources: new Set(),
3634
+ deferredFlushes: new Map(),
3635
+ afterFlush: new Set(),
3636
+ visible,
3637
+ connected: visible && (parent?.connected ?? true),
3638
+ disposed: false,
3639
+ }
3640
+ parent?.children.add(connection)
3641
+ return connection
3642
+ }
3643
+
3644
+ function createRetainedResource(
3645
+ owner: Owner,
3646
+ connect: () => void,
3647
+ disconnect: () => void,
3648
+ phase = 1,
3649
+ ): readonly [activate: () => void, dispose: () => void] {
3650
+ const connection = owner[5]
3651
+ const resource: RetainedResource = {
3652
+ owner,
3653
+ connect,
3654
+ disconnect,
3655
+ active: false,
3656
+ connected: false,
3657
+ disposed: false,
3658
+ phase,
3659
+ }
3660
+ connection?.resources.add(resource)
3661
+ const activate = (): void => {
3662
+ if (resource.disposed) return
3663
+ resource.active = true
3664
+ reconcileRetainedResource(resource, connection?.connected ?? true)
3665
+ }
3666
+ const dispose = (): void => {
3667
+ if (resource.disposed) return
3668
+ resource.disposed = true
3669
+ resource.active = false
3670
+ connection?.resources.delete(resource)
3671
+ reconcileRetainedResource(resource, false)
3672
+ }
3673
+ return [activate, dispose]
3674
+ }
3675
+
3676
+ function reconcileRetainedResource(resource: RetainedResource, connected: boolean): void {
3677
+ const nextConnected = !resource.disposed && resource.active && connected
3678
+ if (resource.connected === nextConnected) return
3679
+ resource.connected = nextConnected
3680
+ try {
3681
+ runOwnerTask(resource.owner, nextConnected ? resource.connect : resource.disconnect)
3682
+ } catch (error) {
3683
+ resource.connected = false
3684
+ throw error
3685
+ }
3686
+ }
3687
+
3688
+ function updateRetainedConnection(connection: RetainedConnection): void {
3689
+ if (connection.disposed) return
3690
+ const nextConnected = connection.visible && (connection.parent?.connected ?? true)
3691
+ if (connection.connected === nextConnected) return
3692
+ connection.connected = nextConnected
3693
+ if (nextConnected) {
3694
+ for (const [flush, cancel] of connection.deferredFlushes) {
3695
+ cancel()
3696
+ scheduleFlush(flush)
3697
+ }
3698
+ connection.deferredFlushes.clear()
3699
+ for (const resource of [...connection.resources].toSorted(
3700
+ (left, right) => left.phase - right.phase,
3701
+ )) {
3702
+ reconcileRetainedResource(resource, true)
3703
+ }
3704
+ } else {
3705
+ for (const resource of [...connection.resources].toReversed()) {
3706
+ reconcileRetainedResource(resource, false)
3707
+ }
3708
+ }
3709
+ for (const child of connection.children) updateRetainedConnection(child)
3710
+ }
3711
+
3712
+ function concealDisconnectedDescendants(connection: RetainedConnection): void {
3713
+ for (const child of connection.children) {
3714
+ if (!child.connected) {
3715
+ for (const conceal of child.afterFlush) conceal()
3716
+ }
3717
+ concealDisconnectedDescendants(child)
3718
+ }
3719
+ }
3720
+
3721
+ function disposeRetainedConnection(connection: RetainedConnection): void {
3722
+ if (connection.disposed) return
3723
+ connection.disposed = true
3724
+ connection.parent?.children.delete(connection)
3725
+ for (const cancel of connection.deferredFlushes.values()) cancel()
3726
+ connection.deferredFlushes.clear()
3727
+ connection.afterFlush.clear()
3728
+ for (const child of connection.children) disposeRetainedConnection(child)
3729
+ connection.children.clear()
3730
+ for (const resource of [...connection.resources].toReversed()) {
3731
+ resource.disposed = true
3732
+ resource.active = false
3733
+ reconcileRetainedResource(resource, false)
3734
+ }
3735
+ connection.resources.clear()
3736
+ }
3737
+
3738
+ function notifyRetainedFlush(connection: RetainedConnection | null): void {
3739
+ for (let current = connection; current !== null; current = current.parent) {
3740
+ if (!current.connected) {
3741
+ for (const notify of current.afterFlush) notify()
3742
+ }
3743
+ }
3744
+ }
3745
+
3746
+ function createRootIdentity(
3747
+ identifierPrefix?: string,
3748
+ onCaughtError?: CompiledErrorHandler,
3749
+ onUncaughtError?: CompiledErrorHandler,
3750
+ ): RootIdentity {
3751
+ return {
3752
+ mounted: false,
3753
+ nextId: 0,
3754
+ prefix: identifierPrefix ?? `v${nextClientRoot++}-`,
3755
+ onCaughtError,
3756
+ onUncaughtError,
3757
+ }
3758
+ }
3759
+
3760
+ function commitRootPortals(rootIdentity: RootIdentity): void {
3761
+ const pending = pendingRootPortals.get(rootIdentity)
3762
+ if (pending === undefined) return
3763
+ pendingRootPortals.delete(rootIdentity)
3764
+ const committed: PortalPublication[] = []
3765
+ try {
3766
+ for (const publication of pending) {
3767
+ publication[0]()
3768
+ committed.push(publication)
3769
+ }
3770
+ } catch (error) {
3771
+ for (const publication of committed.toReversed()) publication[1]()
3772
+ throw error
3773
+ }
3774
+ }
3775
+
3776
+ function provideContext<T>(
3777
+ context: CompiledContext<T>,
3778
+ input: T | CompiledBinding<T>,
3779
+ children: CompiledRenderValue | readonly CompiledRenderValue[] | undefined,
3780
+ ): StructuralBinding {
3781
+ const parentContext = activeContextFrame ?? activeOwner?.[2] ?? null
3782
+ let mounted = false
3783
+ return [
3784
+ STRUCTURAL,
3785
+ (parent, before) => {
3786
+ if (mounted) throw new Error(DEV ? 'context provider is already mounted' : 'V008')
3787
+ mounted = true
3788
+ withContextFrame(
3789
+ {
3790
+ context: context as CompiledContext<unknown>,
3791
+ input,
3792
+ parent: parentContext,
3793
+ owner: activeOwner,
3794
+ },
3795
+ () => insertValue(parent, children, before),
3796
+ )
3797
+ },
3798
+ 'transparent',
3799
+ ]
3800
+ }
3801
+
3802
+ function contextInput<T>(
3803
+ scope: CompiledScope,
3804
+ context: CompiledContext<T>,
3805
+ ): T | CompiledBinding<T> {
3806
+ const owner = scopeOwners.get(scope)
3807
+ if (owner === undefined) {
3808
+ throw new Error(DEV ? 'createCompiledContext received an unknown scope' : 'V003')
3809
+ }
3810
+ return contextInputFromFrame(owner[2], context)
3811
+ }
3812
+
3813
+ function contextInputFromFrame<T>(
3814
+ frame: ContextFrame | null,
3815
+ context: CompiledContext<T>,
3816
+ ): T | CompiledBinding<T> {
3817
+ if (typeof context !== 'function' || !(CONTEXT in context)) {
3818
+ throw new TypeError(DEV ? 'useContext requires a context created by createContext' : 'V018')
3819
+ }
3820
+ for (let current = frame; current !== null; current = current.parent) {
3821
+ if (current.context === context) return current.input as T | CompiledBinding<T>
3822
+ }
3823
+ return context[CONTEXT]
3824
+ }
3825
+
3826
+ function withOwner<T>(owner: Owner, operation: () => T): T {
3827
+ const previous = activeOwner
3828
+ const previousContext = activeContextFrame
3829
+ const previousRootIdentity = activeRootIdentity
3830
+ const previousErrorOwner = activeErrorOwner
3831
+ activeOwner = owner
3832
+ activeContextFrame = owner[2]
3833
+ activeRootIdentity = owner[3]
3834
+ activeErrorOwner = owner
3835
+ try {
3836
+ return operation()
3837
+ } finally {
3838
+ activeOwner = previous
3839
+ activeContextFrame = previousContext
3840
+ activeRootIdentity = previousRootIdentity
3841
+ activeErrorOwner = previousErrorOwner
3842
+ }
3843
+ }
3844
+
3845
+ function withContextFrame<T>(frame: ContextFrame | null, operation: () => T): T {
3846
+ const previous = activeContextFrame
3847
+ activeContextFrame = frame
3848
+ try {
3849
+ return operation()
3850
+ } finally {
3851
+ activeContextFrame = previous
3852
+ }
3853
+ }
3854
+
3855
+ function withRootIdentity<T>(rootIdentity: RootIdentity | null, operation: () => T): T {
3856
+ const previous = activeRootIdentity
3857
+ activeRootIdentity = rootIdentity
3858
+ try {
3859
+ return operation()
3860
+ } finally {
3861
+ activeRootIdentity = previous
3862
+ }
3863
+ }
3864
+
3865
+ function onCleanup(cleanup: () => void): void {
3866
+ activeOwner?.[1].push(cleanup)
3867
+ }
3868
+
3869
+ function disposeOwner(owner: Owner): void {
3870
+ if (owner[0]) return
3871
+ owner[0] = true
3872
+ disposalCascadeDepth += 1
3873
+ disposalCascadeOwners.add(owner)
3874
+ if (DEV) activeOwnerCount -= 1
3875
+ if (pendingInsertionCommits.delete(owner)) pendingInsertionOwnerCount -= 1
3876
+ if (pendingOwnerCommits.delete(owner)) pendingOwnerCommitCount -= 1
3877
+ let firstError: unknown
3878
+ let hasError = false
3879
+ try {
3880
+ for (let remaining = owner[1].length; remaining > 0; remaining -= 1) {
3881
+ const cleanup = owner[1].pop()
3882
+ try {
3883
+ cleanup?.()
3884
+ } catch (error) {
3885
+ if (!hasError) firstError = error
3886
+ hasError = true
3887
+ }
3888
+ }
3889
+ owner[1].length = 0
3890
+ } finally {
3891
+ disposalCascadeDepth -= 1
3892
+ if (disposalCascadeDepth === 0) disposalCascadeOwners.clear()
3893
+ }
3894
+ if (hasError) throw firstError
3895
+ }
3896
+
3897
+ /** @internal Test-only allocation and retention evidence. */
3898
+ export function readCompiledOwnerMetrics(): {
3899
+ readonly active: number
3900
+ readonly created: number
3901
+ readonly updaters: number
3902
+ readonly schedulerPlans: number
3903
+ } {
3904
+ return {
3905
+ active: activeOwnerCount,
3906
+ created: createdOwnerCount,
3907
+ updaters: createdUpdaterCount,
3908
+ schedulerPlans: createdSchedulerPlanCount,
3909
+ }
3910
+ }
3911
+
3912
+ /** @internal Test-only publication traversal evidence. */
3913
+ export function readCompiledPublicationMetrics(): { readonly visitedNodes: number } {
3914
+ return { visitedNodes: visitedPublishedNodeCount }
3915
+ }
3916
+
3917
+ interface MountedBindingState {
3918
+ start: Comment | null
3919
+ end: Comment | null
3920
+ current: unknown
3921
+ currentOwner: Owner | null
3922
+ text: Text | null
3923
+ }
3924
+
3925
+ function ensureMountedBindingRange(state: MountedBindingState): readonly [Comment, Comment] {
3926
+ if (state.start !== null && state.end !== null) return [state.start, state.end]
3927
+ const anchor = state.text
3928
+ const parent = anchor?.parentNode
3929
+ if (anchor === null || parent === null || parent === undefined) {
3930
+ throw new Error(DEV ? 'markerless binding text is detached' : 'V010')
3931
+ }
3932
+ state.start = document.createComment(DEV ? 'vidact:binding' : '')
3933
+ state.end = document.createComment(DEV ? '/vidact:binding' : '')
3934
+ parent.insertBefore(state.start, anchor)
3935
+ parent.insertBefore(state.end, anchor.nextSibling)
3936
+ return [state.start, state.end]
3937
+ }
3938
+
3939
+ function clearMountedBinding(state: MountedBindingState): void {
3940
+ const [start, end] = ensureMountedBindingRange(state)
3941
+ const owner = state.currentOwner
3942
+ state.currentOwner = null
3943
+ state.text = null
3944
+ disposeRange(owner, start, end)
3945
+ }
3946
+
3947
+ function mountCompiledBindingBefore(
3948
+ parent: Node,
3949
+ value: CompiledBinding<unknown>,
3950
+ before: Node | null,
3951
+ ): void {
3952
+ const initial = value[1]()
3953
+ const scalarInitial = isScalarRenderValue(initial)
3954
+ const structuralInitial = ownedStructuralBinding(initial)
3955
+ const hydratedTextRange = scalarInitial
3956
+ ? claimHydrationTextRange(parent, toText(initial))
3957
+ : undefined
3958
+ const borrowedHydrationRange =
3959
+ isHydrating() && !scalarInitial
3960
+ ? borrowHydrationSlotRange(parent, structuralInitial?.[2] === 'slot')
3961
+ : undefined
3962
+ const hydratedStructuralRange =
3963
+ isHydrating() && !scalarInitial
3964
+ ? (borrowedHydrationRange ?? claimHydrationSlotRange(parent))
3965
+ : undefined
3966
+ const hydratedRange = hydratedTextRange ?? hydratedStructuralRange
3967
+ const markerlessScalar = hydratedRange === undefined && scalarInitial && !isHydrating()
3968
+ let start = hydratedRange?.[0] ?? null
3969
+ let end = hydratedRange?.[1] ?? null
3970
+ if (!markerlessScalar && hydratedRange === undefined) {
3971
+ start = document.createComment(DEV ? 'vidact:binding' : '')
3972
+ end = document.createComment(DEV ? '/vidact:binding' : '')
3973
+ parent.insertBefore(start, before)
3974
+ parent.insertBefore(end, before)
3975
+ }
3976
+ const state: MountedBindingState = {
3977
+ start,
3978
+ end,
3979
+ current: hydratedTextRange === undefined && !markerlessScalar ? UNSET_BINDING : initial,
3980
+ currentOwner: null,
3981
+ text: hydratedTextRange?.[2] ?? null,
3982
+ }
3983
+ if (markerlessScalar) {
3984
+ state.text = document.createTextNode(toText(initial))
3985
+ parent.insertBefore(state.text, before)
3986
+ }
3987
+ const update = (): void => {
3988
+ const next = value[1]()
3989
+ if (state.current !== UNSET_BINDING && Object.is(next, state.current)) return
3990
+ if (
3991
+ state.current !== UNSET_BINDING &&
3992
+ isRenderableProtocol(state.current) &&
3993
+ isRenderableProtocol(next) &&
3994
+ canReconcileRenderable(state.current) &&
3995
+ canReconcileRenderable(next) &&
3996
+ Object.is(renderableIdentity(state.current), renderableIdentity(next))
3997
+ ) {
3998
+ state.current = next
3999
+ return
4000
+ }
4001
+ if (isScalarRenderValue(next)) {
4002
+ const content = toText(next)
4003
+ if (state.text !== null) {
4004
+ const target = state.text
4005
+ const previousContent = target.data
4006
+ const previous = state.current
4007
+ stagePublication([
4008
+ () => {
4009
+ if (target.data !== content) target.data = content
4010
+ state.current = next
4011
+ },
4012
+ () => {
4013
+ if (target.data !== previousContent) target.data = previousContent
4014
+ state.current = previous
4015
+ },
4016
+ ])
4017
+ return
4018
+ }
4019
+ clearMountedBinding(state)
4020
+ const [rangeStart, rangeEnd] = ensureMountedBindingRange(state)
4021
+ const currentParent = rangeParent(rangeStart, rangeEnd, 'binding range')
4022
+ state.text = document.createTextNode(content)
4023
+ currentParent.insertBefore(state.text, rangeEnd)
4024
+ state.current = next
4025
+ return
4026
+ }
4027
+
4028
+ const [rangeStart, rangeEnd] = ensureMountedBindingRange(state)
4029
+ const currentParent = rangeParent(rangeStart, rangeEnd, 'binding range')
4030
+ const nextOwner = createOwner()
4031
+ const stagedValue =
4032
+ isRenderableProtocol(next) && canReconcileRenderable(next)
4033
+ ? stableRenderableBinding(value, next)
4034
+ : (next as RenderValue)
4035
+ const [fragment, staged] = stageValue(stagedValue as RenderValue, nextOwner)
4036
+ try {
4037
+ clearMountedBinding(state)
4038
+ } catch (error) {
4039
+ disposeOwner(nextOwner)
4040
+ throw error
4041
+ }
4042
+ state.currentOwner = nextOwner
4043
+ currentParent.insertBefore(fragment, rangeEnd)
4044
+ commitPublishedNodes(staged)
4045
+ state.current = next
4046
+ }
4047
+
4048
+ if (hydratedStructuralRange !== undefined) {
4049
+ const rangeEnd = hydratedStructuralRange[1]
4050
+ const nextOwner = createOwner()
4051
+ const [fragment, staged] = withHydrationInsertion(parent, rangeEnd, () =>
4052
+ stageRender(
4053
+ () =>
4054
+ (isRenderableProtocol(initial) && canReconcileRenderable(initial)
4055
+ ? stableRenderableBinding(value, initial)
4056
+ : initial) as RenderValue,
4057
+ nextOwner,
4058
+ ),
4059
+ )
4060
+ parent.insertBefore(fragment, rangeEnd)
4061
+ commitPublishedNodes(staged)
4062
+ state.currentOwner = nextOwner
4063
+ state.current = initial
4064
+ } else if (hydratedRange === undefined && !markerlessScalar) {
4065
+ update()
4066
+ }
4067
+ const removeUpdater = subscribeBinding(value, update)
4068
+ onCleanup(() => {
4069
+ removeUpdater()
4070
+ if (state.start === null || state.end === null) {
4071
+ state.text?.remove()
4072
+ state.text = null
4073
+ return
4074
+ }
4075
+ clearMountedBinding(state)
4076
+ if (borrowedHydrationRange === undefined) {
4077
+ state.start.remove()
4078
+ state.end.remove()
4079
+ }
4080
+ })
4081
+ }
4082
+
4083
+ function stableRenderableBinding(
4084
+ value: CompiledBinding<unknown>,
4085
+ renderable: RenderableProtocol,
4086
+ ): unknown {
4087
+ const identity = renderableIdentity(renderable)
4088
+ let previous = renderablePropsSnapshot(renderable)
4089
+ const input = binding(
4090
+ value[2],
4091
+ value[3],
4092
+ () => {
4093
+ const next = value[1]()
4094
+ if (!isRenderableProtocol(next) || !Object.is(renderableIdentity(next), identity)) {
4095
+ return previous
4096
+ }
4097
+ previous = renderablePropsSnapshot(next)
4098
+ return previous
4099
+ },
4100
+ value[4],
4101
+ value[5],
4102
+ )
4103
+ return materializeRenderableWithInput(renderable, input)
4104
+ }
4105
+
4106
+ function materialize(value: RenderValue): Node[] {
4107
+ const insertionPoint = hydrationInsertionPoint()
4108
+ if (insertionPoint !== undefined) {
4109
+ const [parent, before] = insertionPoint
4110
+ const first = hydrationCursor(parent)
4111
+ if (first === undefined) throw new Error('hydration insertion point requires active hydration')
4112
+ insertValue(parent, value, before)
4113
+ const after = hydrationCursor(parent)
4114
+ const nodes: Node[] = []
4115
+ for (let node = first; node !== null && node !== after; node = node.nextSibling) {
4116
+ nodes.push(node)
4117
+ }
4118
+ return nodes
4119
+ }
4120
+ const fragment = document.createDocumentFragment()
4121
+ const moves: NodePosition[] = []
4122
+ try {
4123
+ insertValue(fragment, value, null, moves)
4124
+ } catch (error) {
4125
+ restoreNodePositions(moves)
4126
+ throw error
4127
+ }
4128
+ return [...fragment.childNodes]
4129
+ }
4130
+
4131
+ function stageValue(
4132
+ value: RenderValue,
4133
+ owner: Owner,
4134
+ ): readonly [fragment: DocumentFragment, nodes: readonly Node[]] {
4135
+ const insertionPoint = hydrationInsertionPoint()
4136
+ if (insertionPoint !== undefined) {
4137
+ const [parent, before] = insertionPoint
4138
+ const first = hydrationCursor(parent)
4139
+ if (first === undefined) throw new Error('hydration insertion point requires active hydration')
4140
+ withOwner(owner, () => insertValue(parent, value, before))
4141
+ const nodes: Node[] = []
4142
+ for (let node = first; node !== null && node !== before; node = node.nextSibling) {
4143
+ nodes.push(node)
4144
+ }
4145
+ return [document.createDocumentFragment(), nodes]
4146
+ }
4147
+ const fragment = document.createDocumentFragment()
4148
+ const moves: NodePosition[] = []
4149
+ try {
4150
+ withOwner(owner, () => insertValue(fragment, value, null, moves))
4151
+ } catch (error) {
4152
+ restoreNodePositions(moves)
4153
+ try {
4154
+ disposeOwner(owner)
4155
+ } catch {
4156
+ // Preserve the staging error; cleanup still ran every registered disposer.
4157
+ }
4158
+ throw error
4159
+ }
4160
+ return [fragment, [...fragment.childNodes]]
4161
+ }
4162
+
4163
+ function stageRender(
4164
+ render: () => CompiledRenderValue,
4165
+ owner: Owner,
4166
+ ): readonly [fragment: DocumentFragment, nodes: readonly Node[]] {
4167
+ try {
4168
+ return stageValue(withOwner(owner, render), owner)
4169
+ } catch (error) {
4170
+ try {
4171
+ disposeOwner(owner)
4172
+ } catch {
4173
+ // Preserve the render or staging error after every registered cleanup ran.
4174
+ }
4175
+ throw error
4176
+ }
4177
+ }
4178
+
4179
+ function stageMarkerlessHydrationRender(
4180
+ parent: Node,
4181
+ before: Node | null,
4182
+ render: () => CompiledRenderValue,
4183
+ owner: Owner,
4184
+ ): readonly [first: Node | null, after: Node | null, nodes: readonly Node[]] {
4185
+ const first = hydrationCursor(parent)
4186
+ if (first === undefined) {
4187
+ throw new Error('markerless hydration render requires active hydration')
4188
+ }
4189
+ try {
4190
+ withHydrationInsertion(parent, before, () =>
4191
+ withOwner(owner, () => insertValue(parent, render(), before)),
4192
+ )
4193
+ } catch (error) {
4194
+ try {
4195
+ disposeOwner(owner)
4196
+ } catch {
4197
+ // Preserve the render or hydration error after every registered cleanup ran.
4198
+ }
4199
+ throw error
4200
+ }
4201
+ const after = hydrationCursor(parent)
4202
+ if (after === undefined) {
4203
+ disposeOwner(owner)
4204
+ throw new Error('markerless hydration render lost its hydration cursor')
4205
+ }
4206
+ const nodes: Node[] = []
4207
+ for (let node = first; node !== null && node !== after; node = node.nextSibling) {
4208
+ nodes.push(node)
4209
+ }
4210
+ return [first, after, nodes]
4211
+ }
4212
+
4213
+ function insertValue(
4214
+ parent: Node,
4215
+ value: RenderValue,
4216
+ before: Node | null,
4217
+ moves?: NodePosition[],
4218
+ ): void {
4219
+ if (value === null || value === undefined || typeof value === 'boolean') {
4220
+ claimHydrationText(parent, '')
4221
+ return
4222
+ }
4223
+ if (isStructuralBinding(value)) {
4224
+ if (isHydrating() && !isCompiledComponentResult(value) && value[2] === undefined) {
4225
+ throw new HydrationMismatch('structural binding hydration markers are not available')
4226
+ }
4227
+ adoptCompiledRoot(value)
4228
+ value[1](parent, before)
4229
+ return
4230
+ }
4231
+ if (isCompiledBinding(value)) {
4232
+ mountCompiledBindingBefore(parent, value, before)
4233
+ return
4234
+ }
4235
+ if (isRenderableProtocol(value)) {
4236
+ insertValue(parent, materializeRenderable(value) as RenderValue, before, moves)
4237
+ return
4238
+ }
4239
+ if (Array.isArray(value)) {
4240
+ if (hasInvalidChild(value)) {
4241
+ throw new TypeError(
4242
+ DEV ? 'unsupported compiled child value; expected a DOM node or owned block' : 'V009',
4243
+ )
4244
+ }
4245
+ const hydratedRange = claimHydrationArrayRange(parent)
4246
+ for (const item of value) insertValue(parent, item, before, moves)
4247
+ if (hydratedRange !== undefined) finishHydrationArrayRange(parent, hydratedRange[1])
4248
+ return
4249
+ }
4250
+ if (value instanceof DocumentFragment) {
4251
+ const hydrationChildren = hydrationFragmentChildren(value)
4252
+ if (hydrationChildren !== undefined) {
4253
+ for (const child of hydrationChildren) {
4254
+ insertValue(parent, child as RenderValue, before, moves)
4255
+ }
4256
+ return
4257
+ }
4258
+ // oxlint-disable-next-line unicorn/no-useless-spread -- Snapshot the live NodeList before moving nodes.
4259
+ for (const child of [...value.childNodes]) insertValue(parent, child, before, moves)
4260
+ return
4261
+ }
4262
+ if (value instanceof Node) {
4263
+ moves?.push([value, value.parentNode, value.nextSibling])
4264
+ adoptCompiledRoot(value)
4265
+ claimPendingRefOwners(value)
4266
+ if (!claimHydrationNode(parent, value)) parent.insertBefore(value, before)
4267
+ if (!(parent instanceof DocumentFragment)) commitPendingRefs(value)
4268
+ return
4269
+ }
4270
+ if (typeof value === 'object' || typeof value === 'function' || typeof value === 'symbol') {
4271
+ throw new TypeError(
4272
+ DEV ? 'unsupported compiled child value; expected a DOM node or owned block' : 'V009',
4273
+ )
4274
+ }
4275
+ const content = String(value)
4276
+ if (claimHydrationText(parent, content) === undefined) {
4277
+ parent.insertBefore(document.createTextNode(content), before)
4278
+ }
4279
+ }
4280
+
4281
+ function restoreNodePositions(positions: readonly NodePosition[]): void {
4282
+ for (let index = positions.length - 1; index >= 0; index -= 1) {
4283
+ const position = positions[index]
4284
+ if (position === undefined) continue
4285
+ if (position[1] === null) {
4286
+ position[0].parentNode?.removeChild(position[0])
4287
+ continue
4288
+ }
4289
+ const before = position[2]?.parentNode === position[1] ? position[2] : null
4290
+ position[1].insertBefore(position[0], before)
4291
+ }
4292
+ }
4293
+
4294
+ function removeBetween(start: Node, end: Node): void {
4295
+ let node = start.nextSibling
4296
+ while (node !== null && node !== end) {
4297
+ const next = node.nextSibling
4298
+ node.parentNode?.removeChild(node)
4299
+ node = next
4300
+ }
4301
+ }
4302
+
4303
+ function nodesBetween(start: Node, end: Node): Node[] {
4304
+ const nodes: Node[] = []
4305
+ for (let node = start.nextSibling; node !== null && node !== end; node = node.nextSibling) {
4306
+ nodes.push(node)
4307
+ }
4308
+ return nodes
4309
+ }
4310
+
4311
+ function rangeParent(start: Node, end: Node, description: string): Node {
4312
+ const parent = end.parentNode
4313
+ if (parent === null || start.parentNode !== parent) {
4314
+ throw new Error(DEV ? `cannot update a detached ${description}` : 'V010')
4315
+ }
4316
+ return parent
4317
+ }
4318
+
4319
+ function disposeRange(owner: Owner | null, start: Node, end: Node): void {
4320
+ try {
4321
+ if (owner !== null) disposeOwner(owner)
4322
+ } finally {
4323
+ removeBetween(start, end)
4324
+ }
4325
+ }
4326
+
4327
+ function disposePublished(owner: Owner | null, nodes: readonly Node[]): void {
4328
+ try {
4329
+ if (owner !== null) disposeOwner(owner)
4330
+ } finally {
4331
+ for (const node of nodes) node.parentNode?.removeChild(node)
4332
+ }
4333
+ }
4334
+
4335
+ function toText(value: unknown): string {
4336
+ return value === null || value === undefined || typeof value === 'boolean' ? '' : String(value)
4337
+ }
4338
+
4339
+ function isScalarRenderValue(
4340
+ value: unknown,
4341
+ ): value is string | number | bigint | boolean | null | undefined {
4342
+ return (
4343
+ value === null ||
4344
+ value === undefined ||
4345
+ typeof value === 'string' ||
4346
+ typeof value === 'number' ||
4347
+ typeof value === 'bigint' ||
4348
+ typeof value === 'boolean'
4349
+ )
4350
+ }
4351
+
4352
+ function isRefValue(value: unknown): value is RefValue {
4353
+ return (
4354
+ value === null ||
4355
+ value === undefined ||
4356
+ typeof value === 'function' ||
4357
+ (typeof value === 'object' && value !== null && 'current' in value)
4358
+ )
4359
+ }
4360
+
4361
+ function claimPendingRefOwners(root: Node): void {
4362
+ if (pendingRefCount === 0) return
4363
+ visitNodes(root, (node) => {
4364
+ if (!(node instanceof Element)) return
4365
+ const pending = pendingRefs.get(node)
4366
+ if (pending === undefined || pending[0] !== null) return
4367
+ pending[0] = activeOwner
4368
+ activeOwner?.[1].push(() => deletePendingRef(node, pending))
4369
+ })
4370
+ }
4371
+
4372
+ function commitPendingRefs(root: Node): void {
4373
+ if (!isHydrating()) commitPublishedNodesNow([root])
4374
+ }
4375
+
4376
+ function commitPublishedNodes(nodes: readonly Node[]): void {
4377
+ if (isHydrating()) return
4378
+ commitPublishedNodesNow(nodes)
4379
+ }
4380
+
4381
+ function commitPublishedNodesNow(nodes: readonly Node[]): void {
4382
+ const publicationRoot = nodes[0]?.getRootNode()
4383
+ if (publicationRoot instanceof DocumentFragment && !(publicationRoot instanceof ShadowRoot)) {
4384
+ return
4385
+ }
4386
+ if (pendingInsertionOwnerCount > 0) {
4387
+ for (const node of nodes) commitNodeInsertions(node)
4388
+ }
4389
+ if (pendingRefCount > 0) {
4390
+ for (const node of nodes) commitNodeRefs(node)
4391
+ }
4392
+ if (pendingOwnerCommitCount > 0) {
4393
+ for (const node of nodes) commitNodeResources(node)
4394
+ }
4395
+ }
4396
+
4397
+ function commitNodeInsertions(root: Node): void {
4398
+ visitNodes(root, (node) => {
4399
+ if (node instanceof Comment) commitOwnerInsertions(componentCommitOwners.get(node))
4400
+ })
4401
+ }
4402
+
4403
+ function commitNodeRefs(root: Node): void {
4404
+ visitNodes(root, (node) => {
4405
+ if (node instanceof Element) {
4406
+ const pending = pendingRefs.get(node)
4407
+ if (pending !== undefined) {
4408
+ deletePendingRef(node, pending)
4409
+ const owner = pending[0] ?? activeOwner
4410
+ commitContextInsertions(owner?.[2] ?? null)
4411
+ commitOwnerInsertions(owner ?? undefined)
4412
+ const cleanup = attachRef(pending[1], node)
4413
+ if (pending[2] === undefined) owner?.[1].push(cleanup)
4414
+ else pending[2](cleanup)
4415
+ }
4416
+ }
4417
+ })
4418
+ }
4419
+
4420
+ function commitContextInsertions(frame: ContextFrame | null): void {
4421
+ if (frame === null) return
4422
+ commitContextInsertions(frame.parent)
4423
+ commitOwnerInsertions(frame.owner ?? undefined)
4424
+ }
4425
+
4426
+ function commitNodeResources(root: Node): void {
4427
+ visitNodes(root, (node) => {
4428
+ if (node instanceof Comment) commitOwnerResources(componentCommitOwners.get(node))
4429
+ })
4430
+ }
4431
+
4432
+ function commitOwnerInsertions(owner: Owner | undefined): void {
4433
+ if (owner === undefined || owner[0]) return
4434
+ const commits = pendingInsertionCommits.get(owner)
4435
+ if (commits === undefined) return
4436
+ pendingInsertionCommits.delete(owner)
4437
+ pendingInsertionOwnerCount -= 1
4438
+ for (const commit of commits) commit()
4439
+ }
4440
+
4441
+ function commitOwnerResources(owner: Owner | undefined): void {
4442
+ if (owner === undefined || owner[0]) return
4443
+ const commits = pendingOwnerCommits.get(owner)
4444
+ if (commits === undefined) return
4445
+ pendingOwnerCommits.delete(owner)
4446
+ pendingOwnerCommitCount -= 1
4447
+ for (const commit of commits) commit()
4448
+ }
4449
+
4450
+ function commitRangeRefs(start: Node, end: Node): void {
4451
+ const nodes: Node[] = []
4452
+ let node = start.nextSibling
4453
+ while (node !== null && node !== end) {
4454
+ nodes.push(node)
4455
+ node = node.nextSibling
4456
+ }
4457
+ commitPublishedNodesNow(nodes)
4458
+ }
4459
+
4460
+ function visitNodes(root: Node, visit: (node: Node) => void): void {
4461
+ visitedPublishedNodeCount += 1
4462
+ visit(root)
4463
+ for (const child of root.childNodes) visitNodes(child, visit)
4464
+ }
4465
+
4466
+ function attachRef<T>(value: RefValue<T>, target: T): () => void {
4467
+ if (value === null || value === undefined) return noop
4468
+ if (typeof value === 'function') {
4469
+ const cleanup = value(target)
4470
+ return typeof cleanup === 'function' ? cleanup : () => value(null)
4471
+ }
4472
+ value.current = target
4473
+ return () => {
4474
+ if (value.current === target) value.current = null
4475
+ }
4476
+ }
4477
+
4478
+ function scheduleFlush(flush: FlushTask): void {
4479
+ scheduledFlushes.add(flush)
4480
+ if (transactionDepth === 0) drainFlushes()
4481
+ }
4482
+
4483
+ function scheduleOwnerFlush(owner: Owner, flush: FlushTask): void {
4484
+ const connection = owner[5]
4485
+ if (connection === null || connection === undefined || connection.connected) {
4486
+ scheduleFlush(flush)
4487
+ return
4488
+ }
4489
+ if (connection.deferredFlushes.has(flush)) return
4490
+ const cancel = scheduleDeferredTask(() => {
4491
+ connection.deferredFlushes.delete(flush)
4492
+ scheduleFlush(flush)
4493
+ })
4494
+ connection.deferredFlushes.set(flush, cancel)
4495
+ }
4496
+
4497
+ function drainFlushes(): void {
4498
+ if (drainingFlushes || transactionDepth > 0) return
4499
+ drainingFlushes = true
4500
+ const publication: PublicationOperation[] = []
4501
+ activePublication = publication
4502
+ const runs = new Map<FlushTask, number>()
4503
+ let committing = false
4504
+ let failure: unknown
4505
+ let failed = false
4506
+ try {
4507
+ while (scheduledFlushes.size > 0) {
4508
+ const flush = scheduledFlushes.values().next().value
4509
+ if (flush === undefined) break
4510
+ scheduledFlushes.delete(flush)
4511
+ const runCount = (runs.get(flush) ?? 0) + 1
4512
+ if (runCount > MAX_FLUSH_PASSES) {
4513
+ scheduledFlushes.clear()
4514
+ throw new Error(DEV ? 'Vidact compiled scopes did not stabilize' : 'V011')
4515
+ }
4516
+ runs.set(flush, runCount)
4517
+ if (typeof flush === 'function') flush()
4518
+ else flush[1]()
4519
+ }
4520
+ activePublication = null
4521
+ committing = true
4522
+ commitPublication(publication)
4523
+ } catch (error) {
4524
+ activePublication = null
4525
+ if (!committing) abortPublication(publication)
4526
+ failure = error
4527
+ failed = true
4528
+ } finally {
4529
+ activePublication = null
4530
+ drainingFlushes = false
4531
+ }
4532
+ if (failed) {
4533
+ const owner = failedOwner
4534
+ failedOwner = null
4535
+ if (!routeOwnerError(owner, failure)) throw failure
4536
+ }
4537
+ if (scheduledFlushes.size > 0) drainFlushes()
4538
+ }
4539
+
4540
+ function stagePublication(operation: PublicationOperation): void {
4541
+ if (activePublication === null) {
4542
+ operation[0]()
4543
+ try {
4544
+ operation[3]?.()
4545
+ } catch (error) {
4546
+ operation[1]()
4547
+ throw error
4548
+ }
4549
+ return
4550
+ }
4551
+ activePublication.push([
4552
+ operation[0],
4553
+ operation[1],
4554
+ operation[2],
4555
+ operation[3],
4556
+ operation[4],
4557
+ operation[5] ?? activeErrorOwner,
4558
+ ])
4559
+ }
4560
+
4561
+ function commitPublication(operations: readonly PublicationOperation[]): void {
4562
+ const ordered = operations.some((operation) => operation[4] !== undefined)
4563
+ ? operations.toSorted((left, right) => (left[4] ?? 0) - (right[4] ?? 0))
4564
+ : operations
4565
+ const applied: PublicationOperation[] = []
4566
+ let current: PublicationOperation | undefined
4567
+ try {
4568
+ for (const operation of ordered) {
4569
+ current = operation
4570
+ applied.push(operation)
4571
+ operation[0]()
4572
+ }
4573
+ } catch (error) {
4574
+ for (let index = applied.length - 1; index >= 0; index -= 1) {
4575
+ try {
4576
+ applied[index]?.[1]()
4577
+ } catch {
4578
+ // Preserve the publication error while attempting every inverse.
4579
+ }
4580
+ }
4581
+ for (const operation of ordered.slice(applied.length)) {
4582
+ try {
4583
+ operation[2]?.()
4584
+ } catch {
4585
+ // Preserve the publication error while disposing every staged value.
4586
+ }
4587
+ }
4588
+ failedOwner = current?.[5] ?? null
4589
+ throw error
4590
+ }
4591
+ try {
4592
+ for (const operation of ordered) {
4593
+ current = operation
4594
+ operation[3]?.()
4595
+ }
4596
+ } catch (error) {
4597
+ for (let index = applied.length - 1; index >= 0; index -= 1) {
4598
+ try {
4599
+ applied[index]?.[1]()
4600
+ } catch {
4601
+ // Preserve the finalization error while attempting every inverse.
4602
+ }
4603
+ }
4604
+ failedOwner = current?.[5] ?? null
4605
+ throw error
4606
+ }
4607
+ }
4608
+
4609
+ function runOwnerTask(owner: Owner, operation: () => void): void {
4610
+ try {
4611
+ operation()
4612
+ } catch (error) {
4613
+ if (!routeOwnerError(owner, error)) throw error
4614
+ }
4615
+ }
4616
+
4617
+ function routeOwnerError(owner: Owner | null, failure: unknown): boolean {
4618
+ let error = failure
4619
+ let boundary = owner?.[4] ?? null
4620
+ while (boundary !== null) {
4621
+ try {
4622
+ boundary.handle(error)
4623
+ return true
4624
+ } catch (nextError) {
4625
+ error = nextError
4626
+ boundary = boundary.parent
4627
+ }
4628
+ }
4629
+ const onUncaughtError = owner?.[3].onUncaughtError
4630
+ if (onUncaughtError === undefined) return false
4631
+ onUncaughtError(error)
4632
+ return true
4633
+ }
4634
+
4635
+ export function isCompiledContext<Value>(value: unknown): value is CompiledContext<Value> {
4636
+ return typeof value === 'function' && CONTEXT in value
4637
+ }
4638
+
4639
+ function abortPublication(operations: readonly PublicationOperation[]): void {
4640
+ for (let index = operations.length - 1; index >= 0; index -= 1) {
4641
+ try {
4642
+ operations[index]?.[2]?.()
4643
+ } catch {
4644
+ // Preserve the computation error while disposing every staged value.
4645
+ }
4646
+ }
4647
+ }