@askrjs/askr 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +874 -0
  2. package/README.md +61 -29
  3. package/capabilities.json +19 -9
  4. package/dist/actions/index.js +56 -12
  5. package/dist/benchmark.js +10 -15
  6. package/dist/boot/index.d.ts +3 -2
  7. package/dist/boot/index.js +1 -1
  8. package/dist/boot-DaoTYoCw.js +3989 -0
  9. package/dist/browser-activity-CB8e-V4f.js +220 -0
  10. package/dist/components/index.d.ts +8 -1
  11. package/dist/components/index.js +1 -43
  12. package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
  13. package/dist/control/index.d.ts +2 -0
  14. package/dist/control/index.js +1 -1
  15. package/dist/control-nfpT2fbK.js +209 -0
  16. package/dist/core.d.ts +5 -9
  17. package/dist/csp-nonce-DwGw1A6Q.js +35 -0
  18. package/dist/data/index.js +3 -3
  19. package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
  20. package/dist/data-runtime-C1bFAlba.js +242 -0
  21. package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
  22. package/dist/domains/actions.d.ts +8 -3
  23. package/dist/domains/component.d.ts +1 -107
  24. package/dist/domains/context.d.ts +0 -15
  25. package/dist/domains/control.d.ts +36 -249
  26. package/dist/domains/data.d.ts +31 -13
  27. package/dist/domains/diagnostics.d.ts +1 -2
  28. package/dist/domains/lifecycle.d.ts +2 -5
  29. package/dist/domains/refs.d.ts +0 -2
  30. package/dist/domains/routing.d.ts +43 -8
  31. package/dist/domains/scheduler.d.ts +1 -76
  32. package/dist/domains/server.d.ts +5 -2
  33. package/dist/domains/state.d.ts +2 -5
  34. package/dist/domains/telemetry.d.ts +0 -2
  35. package/dist/elements.d.ts +214 -51
  36. package/dist/error-boundary-Bpwofwps.js +293 -0
  37. package/dist/foundations/icon/index.d.ts +0 -58
  38. package/dist/foundations/icon/index.js +2 -2
  39. package/dist/foundations/index.js +2 -1
  40. package/dist/foundations/interactions/index.js +1 -1
  41. package/dist/foundations/state/index.d.ts +3 -3
  42. package/dist/foundations/state/index.js +5 -3
  43. package/dist/foundations/structures/index.js +2 -1
  44. package/dist/foundations/utilities/index.d.ts +2 -0
  45. package/dist/foundations/utilities/index.js +1 -2
  46. package/dist/fx/index.d.ts +31 -58
  47. package/dist/fx/index.js +313 -195
  48. package/dist/hooks-BimKStr4.js +202 -0
  49. package/dist/index.d.ts +11 -74
  50. package/dist/index.js +8 -447
  51. package/dist/instance-BAnfmXOR.js +988 -0
  52. package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
  53. package/dist/jsx-dev-runtime.d.ts +41 -18
  54. package/dist/jsx-dev-runtime.js +1 -6
  55. package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
  56. package/dist/jsx-runtime.js +1 -1
  57. package/dist/jsx.d.ts +61 -37
  58. package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
  59. package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
  60. package/dist/navigation.d.ts +12 -3
  61. package/dist/peer-types.d.ts +8 -0
  62. package/dist/portal-DuOKfnLa.js +349 -0
  63. package/dist/promise-Dz8iIHAm.js +16 -0
  64. package/dist/query-registry-WMCN0BJL.js +320 -0
  65. package/dist/readable-DFWOsTac.js +21 -0
  66. package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
  67. package/dist/render-sync-IC5lMFpq.js +1240 -0
  68. package/dist/resolution-Cx82-xjW.js +1244 -0
  69. package/dist/resource-CLjB7RBQ.js +377 -0
  70. package/dist/resources/index.d.ts +21 -11
  71. package/dist/resources/index.js +45 -244
  72. package/dist/router/index.d.ts +14 -5
  73. package/dist/router/index.js +22 -53
  74. package/dist/scope-CwpVSHVf.js +55 -0
  75. package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
  76. package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
  77. package/dist/ssg/index.d.ts +1 -2
  78. package/dist/ssg/index.js +5 -13
  79. package/dist/ssr/index.d.ts +26 -28
  80. package/dist/ssr/index.js +4 -4
  81. package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
  82. package/dist/ssr-DoV-vJ-5.js +229 -0
  83. package/dist/state-DWO1KzkX.js +232 -0
  84. package/dist/structures-D4dDMqHX.js +231 -0
  85. package/dist/testing/index.d.ts +8 -4
  86. package/dist/testing/index.js +29 -34
  87. package/dist/url-CnbfpX0K.js +185 -0
  88. package/dist/utilities.d.ts +48 -2
  89. package/dist/verify-hydration-DpVaDnqz.js +152 -0
  90. package/package.json +19 -9
  91. package/dist/access-CEA2pOry.js +0 -1046
  92. package/dist/activity-oy2YFTFF.js +0 -201
  93. package/dist/boot-BMBMWUGI.js +0 -1084
  94. package/dist/capabilities-Bbf0mlp9.js +0 -42
  95. package/dist/compose-ref-v0qGlHoN.js +0 -26
  96. package/dist/control-BR_mrX__.js +0 -173
  97. package/dist/control-C-ApnFs1.js +0 -20
  98. package/dist/csp-nonce-BfFWcd0w.js +0 -173
  99. package/dist/data-runtime-CxoY98lX.js +0 -149
  100. package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
  101. package/dist/dom-renderer.d.ts +0 -77
  102. package/dist/domains/renderer.d.ts +0 -127
  103. package/dist/eager-control.d.ts +0 -8
  104. package/dist/effect-C3Zsc1k6.js +0 -292
  105. package/dist/for-state-BDykeOJL.js +0 -1753
  106. package/dist/instance-VAFYVJOa.js +0 -1027
  107. package/dist/notify-DxxuDPeY.js +0 -266
  108. package/dist/portal-w3oQ6oQU.js +0 -29
  109. package/dist/query-registry-LrYpQsDJ.js +0 -83
  110. package/dist/render-resolved-BC0W7_5b.js +0 -1123
  111. package/dist/renderer-CT0HeY58.js +0 -8623
  112. package/dist/resolution-3DskUkjG.js +0 -577
  113. package/dist/resource-18-sFRl9.js +0 -344
  114. package/dist/route-matching-CUzZ31gT.js +0 -551
  115. package/dist/router-internal-7nuNEHfG.js +0 -36
  116. package/dist/scope-Cq_iYbTR.js +0 -403
  117. package/dist/selector-BSPVkjKP.js +0 -311
  118. package/dist/ssr-EPjwJH5R.js +0 -29
  119. package/dist/state-BXJfudq1.js +0 -91
  120. package/dist/structures-CjEzfj4h.js +0 -654
  121. package/dist/timer-C7uqnJVt.js +0 -85
  122. package/dist/verify-hydration-ikaxotf7.js +0 -27
  123. package/dist/vnode-D24p6IW2.js +0 -7
@@ -1,1753 +0,0 @@
1
- import { a as getRuntimeEvaluation, c as getRuntimeScopes, i as getRuntimeCleanup, v as logger, w as isDevelopmentEnvironment } from "./access-CEA2pOry.js";
2
- import { C as rebaseVNodeTreeWithContextFrame, I as DIRECT_RANGE_OWNER, O as registerOwnedChildScope, T as cleanupComponent, _ as haveEquivalentContextFrames, j as finalizeInlineReadSubscriptions, n as createComponentInstance, s as renderScopedComponent } from "./instance-VAFYVJOa.js";
3
- import { A as releaseOwnedChild, C as disposeOwnership, D as ownChild, O as ownCleanup, S as detachOwnedChildren, b as attachOwnership, f as getCurrentComponentInstance, i as claimHookIndex, k as registerScopedOwnership, m as getCurrentStateIndex, o as clearRenderTracking, y as OwnershipRecord } from "./scope-Cq_iYbTR.js";
4
- import { t as adoptComponentParent } from "./capabilities-Bbf0mlp9.js";
5
- import { i as commitTransaction, l as registerCommitParticipant, n as applyTransaction, o as discardTransaction, p as suspendTransaction, r as beginCommitTransaction, s as getCurrentCommitTransaction, t as notifyReadableSource, u as registerCommitRollback, v as recordReadableRead, y as shouldCoalesceFineGrainedItemReads } from "./notify-DxxuDPeY.js";
6
- import { n as _isDOMElement } from "./vnode-D24p6IW2.js";
7
- //#region src/runtime/ownership/child-scope.ts
8
- const EMPTY_CHILD_SCOPE_PROPS = {};
9
- const childScopesByInstance = /* @__PURE__ */ new WeakMap();
10
- function executeChildScopeComponent() {
11
- const instance = getCurrentComponentInstance();
12
- const scope = instance ? childScopesByInstance.get(instance) : void 0;
13
- if (!scope?._renderFn) return null;
14
- return scope._renderFn();
15
- }
16
- function ensureChildScopeFlushTask(scope) {
17
- const instance = scope.componentInstance;
18
- if (instance._pendingFlushTask) return;
19
- instance._pendingFlushTask = () => {
20
- instance.hasPendingUpdate = false;
21
- if (instance.notifyUpdate === null || instance.owner.disposed) return;
22
- if (scope._preparedTransaction) discardTransaction(scope._preparedTransaction);
23
- const transaction = beginCommitTransaction();
24
- scope._preparedTransaction = transaction;
25
- const snapshot = captureChildScopeTransactionSnapshot(scope);
26
- registerCommitRollback(() => {
27
- if (!instance.owner.disposed) restoreChildScopeTransactionSnapshot(scope, snapshot);
28
- });
29
- try {
30
- renderScope(scope);
31
- suspendTransaction(transaction);
32
- if (scope._onDirty) scope._onDirty();
33
- else {
34
- scope._preparedTransaction = void 0;
35
- commitTransaction(transaction);
36
- }
37
- } catch (error) {
38
- discardTransaction(transaction);
39
- scope._preparedTransaction = void 0;
40
- throw error;
41
- } finally {
42
- suspendTransaction(transaction);
43
- }
44
- };
45
- }
46
- var ChildScopeImpl = class {
47
- get [DIRECT_RANGE_OWNER]() {
48
- return true;
49
- }
50
- constructor(parent, key, onDirty, ownership) {
51
- this.previousVnode = void 0;
52
- this.vnode = void 0;
53
- this.dom = void 0;
54
- this.range = void 0;
55
- this.needsDomUpdate = true;
56
- this.hydrationPending = true;
57
- this.blueprintOwner = void 0;
58
- this._renderFn = void 0;
59
- this._renderedOwnerFrame = null;
60
- this.key = key;
61
- this._parentOwnership = parent?.owner ?? null;
62
- this._onDirty = onDirty;
63
- this._ownership = ownership;
64
- this._startStateIndex = getCurrentStateIndex();
65
- this.componentInstance = createComponentInstance("child-scope", executeChildScopeComponent, EMPTY_CHILD_SCOPE_PROPS, null);
66
- childScopesByInstance.set(this.componentInstance, this);
67
- this.componentInstance.owner.finalizer = this;
68
- registerScopedOwnership(this, this.componentInstance.owner);
69
- if (parent) {
70
- adoptComponentParent(this.componentInstance, parent);
71
- this.componentInstance.ownerFrame = parent.ownerFrame;
72
- this.componentInstance.portalScope = parent.portalScope;
73
- if (ownership) ownership.add(this);
74
- else registerOwnedChildScope(parent, this);
75
- }
76
- }
77
- markDirty() {
78
- this.needsDomUpdate = true;
79
- }
80
- render(renderFn) {
81
- this._renderFn = renderFn;
82
- return renderScope(this);
83
- }
84
- dispose() {
85
- cleanupComponent(this.componentInstance);
86
- }
87
- release() {
88
- try {
89
- if (this._preparedTransaction) discardTransaction(this._preparedTransaction);
90
- this._preparedTransaction = void 0;
91
- if (this._ownership) this._ownership.delete(this);
92
- else if (this._parentOwnership) releaseOwnedChild(this._parentOwnership, this);
93
- } finally {
94
- childScopesByInstance.delete(this.componentInstance);
95
- this._renderFn = void 0;
96
- this.previousVnode = void 0;
97
- this.vnode = void 0;
98
- getRuntimeScopes().clearChildScopeHost(this);
99
- this.needsDomUpdate = false;
100
- this.hydrationPending = false;
101
- this.blueprintOwner = void 0;
102
- this.componentInstance.hasPendingUpdate = false;
103
- this._parentOwnership = null;
104
- this._onDirty = void 0;
105
- this._ownership = void 0;
106
- this._renderedOwnerFrame = null;
107
- }
108
- }
109
- };
110
- function renderScope(scope) {
111
- if (scope.componentInstance.owner.disposed) {
112
- if (isDevelopmentEnvironment()) throw new Error(`[askr] Attempted to render disposed child scope ${String(scope.key)}.`);
113
- return scope.vnode;
114
- }
115
- if (!scope._renderFn) return scope.vnode;
116
- joinChildScopePreparation(scope);
117
- const { componentInstance } = scope;
118
- const previousVNode = scope.vnode;
119
- try {
120
- const nextVNode = rebaseVNodeTreeWithContextFrame(renderScopedComponent(componentInstance, scope._startStateIndex, scope._renderFn), componentInstance.ownerFrame, scope._renderedOwnerFrame);
121
- if (previousVNode && nextVNode && _isDOMElement(previousVNode) && _isDOMElement(nextVNode) && typeof previousVNode.type === "function" && previousVNode.type === nextVNode.type && "__instance" in previousVNode && !("__instance" in nextVNode)) nextVNode.__instance = previousVNode.__instance;
122
- scope.previousVnode = previousVNode;
123
- scope.vnode = nextVNode;
124
- scope._renderedOwnerFrame = componentInstance.ownerFrame;
125
- scope.markDirty();
126
- if ((componentInstance._pendingReadSources?.size ?? 0) > 0) ensureChildScopeFlushTask(scope);
127
- finalizeInlineReadSubscriptions(componentInstance, componentInstance._currentRenderToken, componentInstance._pendingReadSources, componentInstance._pendingReadSourceVersions);
128
- clearRenderTracking(componentInstance);
129
- return scope.vnode;
130
- } catch (error) {
131
- componentInstance.hasPendingUpdate = false;
132
- throw error;
133
- }
134
- }
135
- function rerenderChildScope(scope) {
136
- return renderScope(scope);
137
- }
138
- /** Join prepared reads and scope restoration to the transaction applying its output. */
139
- function joinChildScopePreparation(scope) {
140
- const mutable = scope;
141
- const transaction = mutable._preparedTransaction;
142
- const current = getCurrentCommitTransaction();
143
- if (!transaction || !current || transaction === current) return;
144
- mutable._preparedTransaction = void 0;
145
- applyTransaction(transaction, () => {});
146
- commitTransaction(transaction);
147
- }
148
- /** @internal */
149
- function captureChildScopeTransactionSnapshot(scope) {
150
- const mutableScope = scope;
151
- return {
152
- previousVnode: scope.previousVnode,
153
- vnode: scope.vnode,
154
- host: getRuntimeScopes().captureChildScopeHost(scope),
155
- needsDomUpdate: scope.needsDomUpdate,
156
- hydrationPending: scope.hydrationPending,
157
- renderFn: mutableScope._renderFn,
158
- renderedOwnerFrame: mutableScope._renderedOwnerFrame
159
- };
160
- }
161
- /** @internal */
162
- function restoreChildScopeTransactionSnapshot(scope, snapshot) {
163
- const mutableScope = scope;
164
- scope.previousVnode = snapshot.previousVnode;
165
- scope.vnode = snapshot.vnode;
166
- snapshot.host?.restore(scope);
167
- scope.needsDomUpdate = snapshot.needsDomUpdate;
168
- scope.hydrationPending = snapshot.hydrationPending;
169
- mutableScope._renderFn = snapshot.renderFn;
170
- mutableScope._renderedOwnerFrame = snapshot.renderedOwnerFrame;
171
- }
172
- function disposeChildScope(scope) {
173
- scope.dispose();
174
- }
175
- function createChildScope(parent, key, onDirty, ownership) {
176
- return new ChildScopeImpl(parent, key, onDirty, ownership);
177
- }
178
- //#endregion
179
- //#region src/runtime/control/branches.ts
180
- function setScopeContextFrame(scope, frame) {
181
- if (scope) scope.componentInstance.ownerFrame = frame;
182
- }
183
- function setControlBoundaryContextFrame(controlState, frame) {
184
- const previousFrame = controlState._contextFrame;
185
- controlState._contextFrame = frame;
186
- if (controlState.kind === "for") {
187
- controlState._contextFrameChanged ||= previousFrame !== null && !haveEquivalentContextFrames(previousFrame, frame);
188
- setScopeContextFrame(controlState.fallbackScope, frame);
189
- for (const item of controlState.items.values()) setScopeContextFrame(item.scope, frame);
190
- return;
191
- }
192
- setScopeContextFrame(controlState.activeScope, frame);
193
- if (controlState.kind === "show") {
194
- setScopeContextFrame(controlState.truthyScope, frame);
195
- setScopeContextFrame(controlState.fallbackScope, frame);
196
- }
197
- }
198
- const SHOW_TRUTHY_KEY = "__show-truthy__";
199
- const SHOW_FALLBACK_KEY = "__show-fallback__";
200
- const CASE_FALLBACK_KEY = "__case-fallback__";
201
- function getBranchScopes(state) {
202
- const scopes = [];
203
- if (state.activeScope) scopes.push(state.activeScope);
204
- if (state instanceof Object && "fallbackScope" in state) {
205
- if (state.fallbackScope) scopes.push(state.fallbackScope);
206
- }
207
- if (state instanceof Object && "truthyScope" in state) {
208
- if (state.truthyScope) scopes.push(state.truthyScope);
209
- }
210
- return scopes;
211
- }
212
- function beginControlTransaction(state) {
213
- if (state._transaction) return state._transaction;
214
- const scopeSnapshots = /* @__PURE__ */ new Map();
215
- for (const scope of getBranchScopes(state)) scopeSnapshots.set(scope, captureChildScopeTransactionSnapshot(scope));
216
- const transaction = {
217
- state,
218
- snapshot: {
219
- activeKey: state.activeKey,
220
- activeScope: state.activeScope,
221
- activeVNodes: state.activeVNodes.slice(),
222
- lastRemovedNodes: state.lastRemovedNodes.slice(),
223
- lastRemovedRanges: state.lastRemovedRanges.slice(),
224
- scopeSnapshots,
225
- fallbackScope: "fallbackScope" in state ? state.fallbackScope : void 0,
226
- truthyScope: "truthyScope" in state ? state.truthyScope : void 0
227
- },
228
- removedScopes: [],
229
- shouldClearDomUpdateState: false,
230
- registered: false
231
- };
232
- state._transaction = transaction;
233
- transaction.registered = registerCommitParticipant({
234
- key: transaction,
235
- collision: "keep-first",
236
- publish: () => publishControlTransaction(state, transaction),
237
- settle: () => commitControlTransaction(state, transaction),
238
- rollback: () => rollbackControlTransaction(state, transaction)
239
- });
240
- return transaction;
241
- }
242
- function stageBranchRemoval(state, scope) {
243
- if (!scope) return;
244
- const transaction = state._transaction;
245
- if (transaction && !transaction.removedScopes.includes(scope)) transaction.removedScopes.push(scope);
246
- else if (!transaction) disposeChildScope(scope);
247
- const removedRange = getRuntimeEvaluation().resolveChildScopeRange?.(scope) ?? scope.range;
248
- const removedDom = removedRange?.single ? removedRange.start : scope.dom;
249
- if (removedDom) state.lastRemovedNodes.push(removedDom);
250
- if (removedRange) state.lastRemovedRanges.push(removedRange);
251
- }
252
- function publishControlTransaction(state, transaction) {
253
- if (state._transaction !== transaction) return;
254
- if (transaction.shouldClearDomUpdateState) {
255
- for (const scope of getBranchScopes(state)) scope.needsDomUpdate = false;
256
- state.lastRemovedNodes = [];
257
- state.lastRemovedRanges = [];
258
- }
259
- state._transaction = null;
260
- transaction.published = true;
261
- }
262
- function commitControlTransaction(state, transaction) {
263
- if (!transaction.published) publishControlTransaction(state, transaction);
264
- if (!transaction.published) return;
265
- transaction.published = false;
266
- const errors = [];
267
- for (const scope of transaction.removedScopes) try {
268
- disposeChildScope(scope);
269
- } catch (error) {
270
- errors.push(error);
271
- }
272
- transaction.removedScopes.length = 0;
273
- if (errors.length) throw new AggregateError(errors, "Control branch cleanup failed");
274
- }
275
- function rollbackControlTransaction(state, transaction) {
276
- if (state._transaction !== transaction && !transaction.published) return;
277
- transaction.published = false;
278
- const committedScopes = new Set(transaction.snapshot.scopeSnapshots.keys());
279
- const currentScopes = getBranchScopes(state);
280
- const errors = [];
281
- for (const scope of currentScopes) {
282
- if (committedScopes.has(scope)) continue;
283
- try {
284
- disposeChildScope(scope);
285
- } catch (error) {
286
- errors.push(error);
287
- }
288
- }
289
- state.activeKey = transaction.snapshot.activeKey;
290
- state.activeScope = transaction.snapshot.activeScope;
291
- state.activeVNodes = transaction.snapshot.activeVNodes;
292
- state.lastRemovedNodes = transaction.snapshot.lastRemovedNodes;
293
- state.lastRemovedRanges = transaction.snapshot.lastRemovedRanges;
294
- if ("truthyScope" in state) state.truthyScope = transaction.snapshot.truthyScope ?? null;
295
- if ("fallbackScope" in state) state.fallbackScope = transaction.snapshot.fallbackScope ?? null;
296
- for (const [scope, snapshot] of transaction.snapshot.scopeSnapshots) restoreChildScopeTransactionSnapshot(scope, snapshot);
297
- state._transaction = null;
298
- if (errors.length > 0) throw new AggregateError(errors, "Control branch rollback cleanup failed");
299
- }
300
- function finishImmediateControlTransaction(state, transaction) {
301
- if (state._transaction === transaction && !transaction.registered) commitControlTransaction(state, transaction);
302
- }
303
- function createBranchScope(state, key) {
304
- const scope = createChildScope(state.parentInstance, key, () => {
305
- if (state._enqueueBoundaryCommit) {
306
- state._enqueueBoundaryCommit();
307
- return;
308
- }
309
- state.parentInstance?._enqueueRun?.();
310
- });
311
- if (state._contextFrame) scope.componentInstance.ownerFrame = state._contextFrame;
312
- return scope;
313
- }
314
- function createShowState(value, renderTruthy, renderFallback) {
315
- return {
316
- kind: "show",
317
- _contextFrame: null,
318
- activeKey: null,
319
- activeScope: null,
320
- activeVNodes: [],
321
- fallbackScope: null,
322
- lastRemovedNodes: [],
323
- lastRemovedRanges: [],
324
- parentInstance: getCurrentComponentInstance(),
325
- _enqueueBoundaryCommit: null,
326
- _hasPendingBoundaryCommit: false,
327
- _transaction: null,
328
- renderFallback,
329
- renderTruthy,
330
- selectedValue: value,
331
- truthyScope: null
332
- };
333
- }
334
- function evaluateShowState(state) {
335
- const transaction = beginControlTransaction(state);
336
- state.lastRemovedNodes = [];
337
- state.lastRemovedRanges = [];
338
- try {
339
- if (state.selectedValue) {
340
- if (state.fallbackScope) {
341
- stageBranchRemoval(state, state.fallbackScope);
342
- state.fallbackScope = null;
343
- }
344
- const truthyScope = state.truthyScope ?? createBranchScope(state, SHOW_TRUTHY_KEY);
345
- state.truthyScope = truthyScope;
346
- state.activeScope = truthyScope;
347
- state.activeKey = SHOW_TRUTHY_KEY;
348
- const vnode = truthyScope.render(() => state.renderTruthy(state.selectedValue));
349
- state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];
350
- } else {
351
- if (state.truthyScope) {
352
- stageBranchRemoval(state, state.truthyScope);
353
- state.truthyScope = null;
354
- }
355
- if (!state.renderFallback) {
356
- if (state.fallbackScope) {
357
- stageBranchRemoval(state, state.fallbackScope);
358
- state.fallbackScope = null;
359
- }
360
- state.activeKey = null;
361
- state.activeScope = null;
362
- state.activeVNodes = [];
363
- } else {
364
- const fallbackScope = state.fallbackScope ?? createBranchScope(state, SHOW_FALLBACK_KEY);
365
- state.fallbackScope = fallbackScope;
366
- state.activeScope = fallbackScope;
367
- state.activeKey = SHOW_FALLBACK_KEY;
368
- const vnode = fallbackScope.render(state.renderFallback);
369
- state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];
370
- }
371
- }
372
- finishImmediateControlTransaction(state, transaction);
373
- return state.activeVNodes;
374
- } catch (error) {
375
- rollbackControlTransaction(state, transaction);
376
- throw error;
377
- }
378
- }
379
- function clearShowDomUpdateState(state) {
380
- if (state.truthyScope) state.truthyScope.needsDomUpdate = false;
381
- if (state.fallbackScope) state.fallbackScope.needsDomUpdate = false;
382
- if (state._transaction) {
383
- state._transaction.shouldClearDomUpdateState = true;
384
- return;
385
- }
386
- state.lastRemovedNodes = [];
387
- state.lastRemovedRanges = [];
388
- }
389
- function createCaseState(matches, fallback) {
390
- return {
391
- kind: "case",
392
- _contextFrame: null,
393
- activeKey: null,
394
- activeScope: null,
395
- activeVNodes: [],
396
- fallback,
397
- lastRemovedNodes: [],
398
- lastRemovedRanges: [],
399
- matches,
400
- parentInstance: getCurrentComponentInstance(),
401
- _enqueueBoundaryCommit: null,
402
- _hasPendingBoundaryCommit: false,
403
- _transaction: null
404
- };
405
- }
406
- function evaluateCaseState(state) {
407
- const transaction = beginControlTransaction(state);
408
- state.lastRemovedNodes = [];
409
- state.lastRemovedRanges = [];
410
- try {
411
- const selectedMatch = state.matches.find((candidate) => Boolean(candidate.when)) ?? null;
412
- const nextKey = selectedMatch?.key ?? (state.fallback ? CASE_FALLBACK_KEY : null);
413
- if (nextKey === null) {
414
- if (state.activeScope) stageBranchRemoval(state, state.activeScope);
415
- state.activeKey = null;
416
- state.activeScope = null;
417
- state.activeVNodes = [];
418
- } else {
419
- if (state.activeScope && state.activeKey !== nextKey) {
420
- stageBranchRemoval(state, state.activeScope);
421
- state.activeScope = null;
422
- }
423
- const activeScope = state.activeScope ?? createBranchScope(state, nextKey);
424
- state.activeKey = nextKey;
425
- state.activeScope = activeScope;
426
- const renderBranch = selectedMatch?.render ?? state.fallback;
427
- const vnode = renderBranch ? activeScope.render(renderBranch) : null;
428
- state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];
429
- }
430
- finishImmediateControlTransaction(state, transaction);
431
- return state.activeVNodes;
432
- } catch (error) {
433
- rollbackControlTransaction(state, transaction);
434
- throw error;
435
- }
436
- }
437
- function clearCaseDomUpdateState(state) {
438
- if (state.activeScope) state.activeScope.needsDomUpdate = false;
439
- if (state._transaction) {
440
- state._transaction.shouldClearDomUpdateState = true;
441
- return;
442
- }
443
- state.lastRemovedNodes = [];
444
- state.lastRemovedRanges = [];
445
- }
446
- const recordBenchEvent = (_event) => {};
447
- //#endregion
448
- //#region src/runtime/control/for-signals.ts
449
- function peekForSignal() {
450
- return this._value;
451
- }
452
- function setForValueSignal(newValue, notifyReaders = true) {
453
- if (Object.is(this._value, newValue)) return;
454
- this._value = newValue;
455
- if (notifyReaders) notifyForSignalReaders(this);
456
- }
457
- function setForIndexValue(newValue, notifyReaders = true) {
458
- const nextValue = typeof newValue === "function" ? newValue(this._value) : newValue;
459
- if (nextValue === this._value) return;
460
- this._value = nextValue;
461
- if (notifyReaders) notifyForSignalReaders(this);
462
- }
463
- function notifyForSignalReaders(source, skipInstance, skipOwnedBy) {
464
- notifyReadableSource(source, {
465
- skipInstance,
466
- skipOwnedBy
467
- });
468
- }
469
- function createForIndexSignal(initialIndex) {
470
- function readIndexSignal() {
471
- const signal = readIndexSignal;
472
- signal._hasBeenRead = true;
473
- recordReadableRead(signal);
474
- return signal._value;
475
- }
476
- const indexSignal = readIndexSignal;
477
- indexSignal._value = initialIndex;
478
- indexSignal.peek = peekForSignal;
479
- indexSignal.set = setForIndexValue;
480
- indexSignal._hasBeenRead = false;
481
- return indexSignal;
482
- }
483
- function syncForIndexSignal(indexSignal, nextIndex) {
484
- if (indexSignal.peek() === nextIndex) return false;
485
- indexSignal.set(nextIndex, indexSignal._hasBeenRead);
486
- return indexSignal._hasBeenRead === true;
487
- }
488
- function createForItemSignal(initialItem) {
489
- function readItemSignal() {
490
- const signal = readItemSignal;
491
- signal._hasBeenRead = true;
492
- recordReadableRead(signal);
493
- return signal._value;
494
- }
495
- const itemSignal = readItemSignal;
496
- itemSignal._value = initialItem;
497
- itemSignal.peek = peekForSignal;
498
- itemSignal.set = setForValueSignal;
499
- itemSignal._hasBeenRead = false;
500
- return itemSignal;
501
- }
502
- function createForItemPropertySignal(initialValue) {
503
- function readPropertySignal() {
504
- const signal = readPropertySignal;
505
- signal._hasBeenRead = true;
506
- recordReadableRead(signal);
507
- return signal._value;
508
- }
509
- const propertySignal = readPropertySignal;
510
- propertySignal._value = initialValue;
511
- propertySignal.peek = peekForSignal;
512
- propertySignal.set = setForValueSignal;
513
- propertySignal._hasBeenRead = false;
514
- return propertySignal;
515
- }
516
- function readForItemProperty(item, prop) {
517
- return Reflect.get(Object(item), prop);
518
- }
519
- function haveSameOwnKeys(previousItem, nextItem) {
520
- const previousKeys = Reflect.ownKeys(Object(previousItem));
521
- const nextKeys = Reflect.ownKeys(Object(nextItem));
522
- if (previousKeys.length !== nextKeys.length) return false;
523
- for (let i = 0; i < previousKeys.length; i += 1) if (previousKeys[i] !== nextKeys[i]) return false;
524
- return true;
525
- }
526
- function scopeReadsSource(scope, source) {
527
- const readers = source._readers;
528
- if (!readers || readers.size === 0) return false;
529
- for (const reader of readers.keys()) {
530
- let current = reader;
531
- while (current) {
532
- if (current === scope.componentInstance) return true;
533
- current = current.parentInstance;
534
- }
535
- }
536
- return false;
537
- }
538
- function scopeDirectlyReadsSource(scope, source) {
539
- return source._readers?.has(scope.componentInstance) ?? false;
540
- }
541
- function isForParentReader(parentInstance, reader) {
542
- let current = parentInstance;
543
- while (current) {
544
- if (current === reader) return true;
545
- current = current.parentInstance;
546
- }
547
- return false;
548
- }
549
- function removeForParentReaders(parentInstance, source) {
550
- const readers = source._readers;
551
- if (!readers || readers.size === 0) return;
552
- for (const reader of readers.keys()) if (isForParentReader(parentInstance, reader)) {
553
- if (readers.delete(reader) && false);
554
- }
555
- }
556
- function getOrCreateForItemPropertySignal(state, prop) {
557
- const item = state.currentItem;
558
- const propertySignals = state.propertySignals ?? (state.propertySignals = /* @__PURE__ */ new Map());
559
- const existingSignal = propertySignals.get(prop);
560
- if (existingSignal) return existingSignal;
561
- const propertySignal = createForItemPropertySignal(readForItemProperty(item, prop));
562
- propertySignals.set(prop, propertySignal);
563
- return propertySignal;
564
- }
565
- function canProxyForItem(item) {
566
- return typeof item === "function" || typeof item === "object" && item !== null && !Array.isArray(item);
567
- }
568
- function createReactiveForItem(item) {
569
- const target = Object.create(null);
570
- const state = {
571
- currentItem: item,
572
- itemSignal: null,
573
- propertySignals: null,
574
- coalescedProperties: null,
575
- coalescedProperty2: null,
576
- wholeItemRead: false,
577
- proxy: void 0
578
- };
579
- target[REACTIVE_FOR_ITEM_STATE] = state;
580
- state.proxy = new Proxy(target, REACTIVE_FOR_ITEM_PROXY_HANDLER);
581
- return state;
582
- }
583
- const REACTIVE_FOR_ITEM_STATE = Symbol("askr.reactive-for-item-state");
584
- function getReactiveForItemState(target) {
585
- return target[REACTIVE_FOR_ITEM_STATE];
586
- }
587
- function getWholeItemSignal(state) {
588
- let signal = state.itemSignal;
589
- if (!signal) {
590
- signal = createForItemSignal(state.currentItem);
591
- state.itemSignal = signal;
592
- }
593
- return signal;
594
- }
595
- const REACTIVE_FOR_ITEM_PROXY_HANDLER = {
596
- get(target, prop, receiver) {
597
- if (prop !== REACTIVE_FOR_ITEM_STATE && prop in target) return Reflect.get(target, prop, receiver);
598
- const metadata = getReactiveForItemState(target);
599
- const currentItem = metadata.currentItem;
600
- if (typeof prop !== "symbol") {
601
- if (shouldCoalesceFineGrainedItemReads()) {
602
- const properties = metadata.coalescedProperties;
603
- if (properties === null) metadata.coalescedProperties = prop;
604
- else if (Array.isArray(properties)) {
605
- if (!properties.includes(prop)) properties.push(prop);
606
- } else if (properties !== prop && metadata.coalescedProperty2 !== prop) {
607
- if (metadata.coalescedProperty2 === null) metadata.coalescedProperty2 = prop;
608
- else {
609
- metadata.coalescedProperties = [
610
- properties,
611
- metadata.coalescedProperty2,
612
- prop
613
- ];
614
- metadata.coalescedProperty2 = null;
615
- }
616
- }
617
- let itemSignal = metadata.itemSignal;
618
- if (!itemSignal) {
619
- itemSignal = createForItemSignal(currentItem);
620
- metadata.itemSignal = itemSignal;
621
- }
622
- itemSignal();
623
- return readForItemProperty(currentItem, prop);
624
- }
625
- return getOrCreateForItemPropertySignal(metadata, prop)();
626
- }
627
- metadata.wholeItemRead = true;
628
- recordReadableRead(getWholeItemSignal(metadata));
629
- return Reflect.get(Object(currentItem), prop, receiver);
630
- },
631
- has(target, prop) {
632
- if (prop === REACTIVE_FOR_ITEM_STATE) return false;
633
- const metadata = getReactiveForItemState(target);
634
- metadata.wholeItemRead = true;
635
- const itemSignal = getWholeItemSignal(metadata);
636
- recordReadableRead(itemSignal);
637
- return prop in target || prop in Object(metadata.currentItem);
638
- },
639
- ownKeys(target) {
640
- const metadata = getReactiveForItemState(target);
641
- metadata.wholeItemRead = true;
642
- const itemSignal = getWholeItemSignal(metadata);
643
- recordReadableRead(itemSignal);
644
- const keys = /* @__PURE__ */ new Set();
645
- for (const key of Reflect.ownKeys(target)) if (key !== REACTIVE_FOR_ITEM_STATE) keys.add(key);
646
- for (const key of Reflect.ownKeys(Object(metadata.currentItem))) keys.add(key);
647
- return Array.from(keys);
648
- },
649
- getOwnPropertyDescriptor(target, prop) {
650
- if (prop === REACTIVE_FOR_ITEM_STATE) return;
651
- const metadata = getReactiveForItemState(target);
652
- metadata.wholeItemRead = true;
653
- const itemSignal = getWholeItemSignal(metadata);
654
- recordReadableRead(itemSignal);
655
- const ownDescriptor = Reflect.getOwnPropertyDescriptor(target, prop);
656
- if (ownDescriptor) return ownDescriptor;
657
- return Object.getOwnPropertyDescriptor(Object(metadata.currentItem), prop);
658
- },
659
- getPrototypeOf(target) {
660
- const metadata = getReactiveForItemState(target);
661
- metadata.wholeItemRead = true;
662
- const itemSignal = getWholeItemSignal(metadata);
663
- recordReadableRead(itemSignal);
664
- return Object.getPrototypeOf(Object(metadata.currentItem));
665
- },
666
- set(target, prop, value) {
667
- if (!(prop in target) && typeof prop !== "symbol" && isDevelopmentEnvironment()) {
668
- const metadata = getReactiveForItemState(target);
669
- if (prop in Object(metadata.currentItem)) logger.warn(`[Askr] Assigning to "${String(prop)}" on a <For> item shadows a property from the source data - it will not update when the source item changes and does not trigger a re-render. Use a different property name for cached/derived per-row values, or a state() cell for values that should be reactive.`);
670
- }
671
- return Reflect.defineProperty(target, prop, {
672
- value,
673
- writable: true,
674
- enumerable: true,
675
- configurable: true
676
- });
677
- }
678
- };
679
- //#endregion
680
- //#region src/runtime/control/for-scopes.ts
681
- function recordRemovedBoundary(forState, dom, range) {
682
- getRuntimeScopes().recordRemovedScopeBoundary(dom, range, forState.lastRemovedNodes, forState.lastRemovedRanges);
683
- }
684
- function prepareRemovedScope(forState, scope) {
685
- const transaction = forState._transaction;
686
- if (!transaction) return getRuntimeScopes().resolveScopeBoundary(scope);
687
- return getRuntimeScopes().prepareScopeRemoval(scope, forState.lastRemovedNodes, forState.lastRemovedRanges, transaction.removedScopeNodes ??= []);
688
- }
689
- function enqueueForScopeUpdate(parent) {
690
- parent?._enqueueRun?.();
691
- }
692
- const forStatesByScope = /* @__PURE__ */ new WeakMap();
693
- function enqueueForBoundaryScopeCommit() {
694
- const forState = this.blueprintOwner ?? forStatesByScope.get(this);
695
- if (!forState) return;
696
- if (forState._enqueueBoundaryCommit) {
697
- forState._enqueueBoundaryCommit();
698
- return;
699
- }
700
- enqueueForScopeUpdate(forState.parentInstance);
701
- }
702
- function createForOwnedChildScope(forState, key) {
703
- const scope = createChildScope(forState.parentInstance, key, enqueueForBoundaryScopeCommit, forState._scopeOwnership);
704
- if (forState._contextFrame) scope.componentInstance.ownerFrame = forState._contextFrame;
705
- return scope;
706
- }
707
- function captureForItemTransactionSnapshot(forState, itemInstance) {
708
- const transaction = forState._transaction;
709
- if (!transaction || transaction.itemSnapshots?.has(itemInstance)) return;
710
- if (transaction.collectionSnapshotMode === "reset-empty" || transaction.items.get(itemInstance.key) !== itemInstance) return;
711
- const itemSnapshots = transaction.itemSnapshots ??= /* @__PURE__ */ new Map();
712
- const propertySignals = itemInstance.reactiveItemState?.propertySignals ?? null;
713
- const itemSignal = itemInstance.reactiveItemState?.itemSignal ?? null;
714
- const propertySnapshots = propertySignals && propertySignals.size > 0 ? new Map(Array.from(propertySignals, ([property, signal]) => [property, {
715
- signal,
716
- value: signal.peek(),
717
- hasBeenRead: signal._hasBeenRead === true
718
- }])) : null;
719
- itemSnapshots.set(itemInstance, {
720
- item: itemInstance.item,
721
- itemSignalExists: itemSignal !== null,
722
- itemSignalValue: itemSignal?.peek(),
723
- itemSignalHasBeenRead: itemSignal?._hasBeenRead === true,
724
- indexValue: itemInstance.indexSignal.peek(),
725
- indexHasBeenRead: itemInstance.indexSignal._hasBeenRead === true,
726
- propertySignalStore: propertySignals,
727
- propertySignals: propertySnapshots,
728
- scope: captureChildScopeTransactionSnapshot(itemInstance.scope)
729
- });
730
- }
731
- function captureForFallbackTransactionSnapshot(forState, fallbackScope = forState.fallbackScope) {
732
- const transaction = forState._transaction;
733
- if (!transaction || !fallbackScope || transaction.fallbackScope !== fallbackScope || transaction.fallbackScopeSnapshot) return;
734
- transaction.fallbackScopeSnapshot = captureChildScopeTransactionSnapshot(fallbackScope);
735
- }
736
- function stageForSignalEffect(forState, source, notify, skipInstance = null, skipOwnedBy = null) {
737
- const transaction = forState._transaction;
738
- if (!transaction) return false;
739
- const effects = transaction.signalEffects ??= /* @__PURE__ */ new Map();
740
- const existing = effects.get(source);
741
- if (existing) {
742
- existing.notify ||= notify;
743
- if (existing.skipInstance !== skipInstance) existing.skipInstance = null;
744
- if (existing.skipOwnedBy !== skipOwnedBy) existing.skipOwnedBy = null;
745
- } else effects.set(source, {
746
- parentInstance: forState.parentInstance,
747
- notify,
748
- skipInstance,
749
- skipOwnedBy
750
- });
751
- return true;
752
- }
753
- function syncForItemIndex(forState, itemInstance, nextIndex) {
754
- const indexSignal = itemInstance.indexSignal;
755
- const previousIndex = indexSignal.peek();
756
- if (previousIndex === nextIndex) return false;
757
- if (indexSignal._hasBeenRead !== true) {
758
- const transaction = forState._transaction;
759
- if (transaction) {
760
- const snapshots = transaction.unreadIndexSnapshots ??= /* @__PURE__ */ new Map();
761
- if (!snapshots.has(indexSignal)) snapshots.set(indexSignal, previousIndex);
762
- }
763
- indexSignal.set(nextIndex, false);
764
- return false;
765
- }
766
- captureForItemTransactionSnapshot(forState, itemInstance);
767
- const scopeReadsIndex = scopeReadsSource(itemInstance.scope, indexSignal);
768
- const scopeDirectlyReadsIndex = scopeDirectlyReadsSource(itemInstance.scope, indexSignal);
769
- if (forState._transaction) {
770
- const shouldNotify = indexSignal._hasBeenRead === true;
771
- indexSignal.set(nextIndex, false);
772
- stageForSignalEffect(forState, indexSignal, shouldNotify, scopeReadsIndex ? itemInstance.scope.componentInstance : null);
773
- if (!scopeReadsIndex) return false;
774
- if (scopeDirectlyReadsIndex) rerenderItemInstance(forState, itemInstance, itemInstance.reactiveItem);
775
- else itemInstance.scope.markDirty();
776
- return true;
777
- }
778
- if (!scopeReadsIndex) {
779
- syncForIndexSignal(indexSignal, nextIndex);
780
- return false;
781
- }
782
- indexSignal.set(nextIndex, false);
783
- notifyForSignalReaders(indexSignal, itemInstance.scope.componentInstance);
784
- rerenderItemInstance(forState, itemInstance, itemInstance.reactiveItem);
785
- return true;
786
- }
787
- function materializeItemVnode(forState, key, vnode) {
788
- if (vnode && typeof vnode === "object" && "type" in vnode) {
789
- const vn = vnode;
790
- vn.key = key;
791
- if (forState.parentInstance?.ssr && typeof vn.type === "string") {
792
- if (!vn.props) vn.props = {};
793
- if (vn.props["data-key"] === void 0) vn.props["data-key"] = String(key);
794
- if (vn.props["data-askr-key-kind"] === void 0) vn.props["data-askr-key-kind"] = typeof key;
795
- }
796
- }
797
- }
798
- function renderItemScope(forState, scope, item, indexSignal, key) {
799
- const vnode = scope.render(() => forState.renderFn(item, indexSignal));
800
- materializeItemVnode(forState, key, vnode);
801
- return vnode;
802
- }
803
- function disposeItemInstance(forState, itemInstance, domCleanup) {
804
- const { dom: removedDom, range: removedRange } = prepareRemovedScope(forState, itemInstance.scope);
805
- const transaction = forState._transaction;
806
- if (transaction) {
807
- (transaction.removedScopes ??= []).push(itemInstance.scope);
808
- return;
809
- }
810
- try {
811
- disposeChildScope(itemInstance.scope);
812
- } catch (err) {
813
- if (isDevelopmentEnvironment()) console.error("[For] Cleanup error:", err);
814
- }
815
- if (!removedDom && !removedRange) return;
816
- if (domCleanup === "teardown") getRuntimeScopes().teardownScopeHost(removedDom, void 0);
817
- recordRemovedBoundary(forState, removedDom, removedRange);
818
- }
819
- function createItemInstance(key, item, index, forState) {
820
- const indexSignal = createForIndexSignal(index);
821
- const reactiveItemState = canProxyForItem(item) ? createReactiveForItem(item) : null;
822
- const reactiveItem = reactiveItemState?.proxy ?? item;
823
- const scope = createForOwnedChildScope(forState, key);
824
- scope.blueprintOwner = forState;
825
- try {
826
- renderItemScope(forState, scope, reactiveItem, indexSignal, key);
827
- } catch (error) {
828
- disposeChildScope(scope);
829
- throw error;
830
- }
831
- return {
832
- key,
833
- item,
834
- reactiveItem,
835
- reactiveItemState,
836
- indexSignal,
837
- scope
838
- };
839
- }
840
- function rerenderItemInstance(forState, itemInstance, item) {
841
- renderItemScope(forState, itemInstance.scope, item, itemInstance.indexSignal, itemInstance.key);
842
- }
843
- function refreshForContextScopes(forState) {
844
- for (const itemInstance of forState.items.values()) {
845
- captureForItemTransactionSnapshot(forState, itemInstance);
846
- rerenderItemInstance(forState, itemInstance, itemInstance.reactiveItem);
847
- }
848
- }
849
- function updateItemInstance(forState, itemInstance, item) {
850
- if (itemInstance.item === item) return false;
851
- captureForItemTransactionSnapshot(forState, itemInstance);
852
- const previousItem = itemInstance.item;
853
- itemInstance.item = item;
854
- const scope = itemInstance.scope;
855
- let scopeReadsChangedSignal = false;
856
- const reactiveItemState = itemInstance.reactiveItemState;
857
- if (!reactiveItemState) {
858
- rerenderItemInstance(forState, itemInstance, item);
859
- return true;
860
- }
861
- const itemSignal = reactiveItemState.itemSignal;
862
- reactiveItemState.currentItem = item;
863
- const propertySignals = reactiveItemState.propertySignals;
864
- const changedPropertySignals = [];
865
- if (propertySignals && propertySignals.size > 0) for (const [prop, propertySignal] of propertySignals) {
866
- const previousValue = readForItemProperty(previousItem, prop);
867
- const nextValue = readForItemProperty(item, prop);
868
- if (Object.is(previousValue, nextValue)) continue;
869
- if (scopeReadsSource(scope, propertySignal)) scopeReadsChangedSignal = true;
870
- changedPropertySignals.push([propertySignal, nextValue]);
871
- }
872
- if (itemSignal && scopeReadsSource(scope, itemSignal)) scopeReadsChangedSignal = true;
873
- let coalescedPropertyChanged = false;
874
- const coalescedProperties = reactiveItemState.coalescedProperties;
875
- if (coalescedProperties !== null) {
876
- if (Array.isArray(coalescedProperties)) {
877
- for (const property of coalescedProperties) if (!Object.is(readForItemProperty(previousItem, property), readForItemProperty(item, property))) {
878
- coalescedPropertyChanged = true;
879
- break;
880
- }
881
- } else {
882
- coalescedPropertyChanged = !Object.is(readForItemProperty(previousItem, coalescedProperties), readForItemProperty(item, coalescedProperties));
883
- const secondProperty = reactiveItemState.coalescedProperty2;
884
- if (secondProperty !== null && !coalescedPropertyChanged) coalescedPropertyChanged = !Object.is(readForItemProperty(previousItem, secondProperty), readForItemProperty(item, secondProperty));
885
- }
886
- }
887
- const wholeItemChanged = itemSignal?._hasBeenRead === true && (reactiveItemState.wholeItemRead || coalescedPropertyChanged);
888
- const itemShapeChanged = !wholeItemChanged && changedPropertySignals.length === 0 && !haveSameOwnKeys(previousItem, item);
889
- const notifyReaders = !scopeReadsChangedSignal && (changedPropertySignals.length > 0 || itemShapeChanged || wholeItemChanged);
890
- const visibleChange = scopeReadsChangedSignal || changedPropertySignals.length > 0 || itemShapeChanged || wholeItemChanged;
891
- for (const [propertySignal, nextValue] of changedPropertySignals) if (stageForSignalEffect(forState, propertySignal, notifyReaders, null, itemInstance.scope.componentInstance)) propertySignal.set(nextValue, false);
892
- else {
893
- removeForParentReaders(forState.parentInstance, propertySignal);
894
- propertySignal.set(nextValue, notifyReaders);
895
- }
896
- if (itemSignal && stageForSignalEffect(forState, itemSignal, notifyReaders, null, itemInstance.scope.componentInstance)) itemSignal.set(item, false);
897
- else if (itemSignal) {
898
- removeForParentReaders(forState.parentInstance, itemSignal);
899
- itemSignal.set(item, notifyReaders);
900
- }
901
- if (scopeReadsChangedSignal) {
902
- if (itemSignal !== null && scopeDirectlyReadsSource(scope, itemSignal) || changedPropertySignals.some(([propertySignal]) => scopeDirectlyReadsSource(scope, propertySignal))) rerenderItemInstance(forState, itemInstance, itemInstance.reactiveItem);
903
- else scope.markDirty();
904
- }
905
- return visibleChange;
906
- }
907
- const FOR_FALLBACK_SCOPE_KEY = "__for-fallback__";
908
- function disposeFallbackScope(forState, domCleanup) {
909
- const fallbackScope = forState.fallbackScope;
910
- if (!fallbackScope) return;
911
- const { dom: removedDom, range: removedRange } = prepareRemovedScope(forState, fallbackScope);
912
- const transaction = forState._transaction;
913
- if (transaction) (transaction.removedScopes ??= []).push(fallbackScope);
914
- else disposeChildScope(fallbackScope);
915
- forState.fallbackScope = null;
916
- if (!removedDom && !removedRange) return;
917
- if (domCleanup === "teardown") getRuntimeScopes().teardownScopeHost(removedDom, void 0);
918
- if (!transaction) recordRemovedBoundary(forState, removedDom, removedRange);
919
- }
920
- function renderFallbackScope(forState) {
921
- if (forState.fallback == null || forState.fallback === false) {
922
- if (forState.fallbackScope) disposeFallbackScope(forState, "none");
923
- forState.orderedVNodes = [];
924
- forState.orderedItems = [];
925
- return [];
926
- }
927
- const fallbackScope = forState.fallbackScope ?? createForOwnedChildScope(forState, FOR_FALLBACK_SCOPE_KEY);
928
- if (!forState.fallbackScope) forStatesByScope.set(fallbackScope, forState);
929
- forState.fallbackScope = fallbackScope;
930
- captureForFallbackTransactionSnapshot(forState, fallbackScope);
931
- const fallbackVNode = forState.fallback;
932
- const vnode = fallbackScope.render(() => fallbackVNode);
933
- forState.orderedVNodes = vnode == null || vnode === false ? [] : [vnode];
934
- forState.orderedItems = [];
935
- return forState.orderedVNodes;
936
- }
937
- function disposeAllItems(forState, domCleanup) {
938
- const { items, orderedKeys } = forState;
939
- if (forState._transaction?.collectionSnapshotMode === "preserve-clear") {
940
- const transaction = forState._transaction;
941
- transaction.removeAllItems = true;
942
- for (let index = 0; index < forState.orderedItems.length; index++) {
943
- const scope = forState.orderedItems[index]?.scope;
944
- if (scope) prepareRemovedScope(forState, scope);
945
- }
946
- forState.items = /* @__PURE__ */ new Map();
947
- forState.orderedKeys = [];
948
- return;
949
- }
950
- for (let index = 0; index < orderedKeys.length; index += 1) {
951
- const key = orderedKeys[index];
952
- const itemInstance = items.get(key);
953
- if (!itemInstance) continue;
954
- disposeItemInstance(forState, itemInstance, domCleanup);
955
- items.delete(key);
956
- }
957
- orderedKeys.length = 0;
958
- forState.orderedKeys = orderedKeys;
959
- }
960
- //#endregion
961
- //#region src/runtime/control/for-paths/pending.ts
962
- /**
963
- * Publish the strategy a path chose, together with the three pending fields
964
- * every path owns.
965
- *
966
- * Every parameter is required, so a path cannot leave one of these behind by
967
- * omission — which is how they were previously written, one scattered
968
- * assignment at a time. The three remaining `pending*` fields belong to exactly
969
- * one path each (`pendingInsertedIndex`, `pendingAppendStart`,
970
- * `pendingRemovedKey`) and are assigned by that path directly; the others leave
971
- * them as reconciliation found them, since each commit clears them through
972
- * `clearForDomUpdateState`.
973
- */
974
- function setForCommitPending(forState, strategy, pendingDirtyIndices, pendingSwapIndices, pendingMoveOnly) {
975
- forState.lastCommitStrategy = strategy;
976
- forState.pendingDirtyIndices = pendingDirtyIndices;
977
- forState.pendingSwapIndices = pendingSwapIndices;
978
- forState.pendingMoveOnly = pendingMoveOnly;
979
- }
980
- //#endregion
981
- //#region src/runtime/control/for-paths/append.ts
982
- /**
983
- * Rows added at the tail, every existing key still at its own index.
984
- *
985
- * When the retained prefix is also clean the commit can skip it entirely, which
986
- * `pendingAppendStart` reports; otherwise the prefix is updated in place and the
987
- * commit starts from zero.
988
- *
989
- * Guarded by `oldLen < newLen`.
990
- */
991
- function tryAppendPath(forState, newArray, items, orderedKeys, byFn, oldLen, newLen) {
992
- let canUseAppendPath = true;
993
- let canSkipCommittedPrefix = true;
994
- for (let i = 0; i < oldLen; i++) {
995
- const key = byFn(newArray[i], i);
996
- if (key !== orderedKeys[i]) {
997
- canUseAppendPath = false;
998
- break;
999
- }
1000
- const existing = forState.orderedItems[i] ?? items.get(key);
1001
- if (!existing || existing.item !== newArray[i] || existing.scope.needsDomUpdate || existing.scope.hydrationPending) canSkipCommittedPrefix = false;
1002
- }
1003
- if (!canUseAppendPath) return null;
1004
- const resultVNodes = forState.orderedVNodes;
1005
- const resultItems = forState.orderedItems;
1006
- resultVNodes.length = newLen;
1007
- resultItems.length = newLen;
1008
- if (!canSkipCommittedPrefix) for (let i = 0; i < oldLen; i++) {
1009
- const item = newArray[i];
1010
- const key = orderedKeys[i];
1011
- const existing = resultItems[i] ?? items.get(key);
1012
- updateItemInstance(forState, existing, item);
1013
- resultItems[i] = existing;
1014
- resultVNodes[i] = existing.scope.vnode;
1015
- }
1016
- for (let i = oldLen; i < newLen; i++) {
1017
- const item = newArray[i];
1018
- const key = byFn(item, i);
1019
- const itemInstance = createItemInstance(key, item, i, forState);
1020
- items.set(key, itemInstance);
1021
- resultItems[i] = itemInstance;
1022
- resultVNodes[i] = itemInstance.scope.vnode;
1023
- orderedKeys[i] = key;
1024
- }
1025
- forState.orderedVNodes = resultVNodes;
1026
- setForCommitPending(forState, "APPEND", null, null, false);
1027
- forState.pendingAppendStart = canSkipCommittedPrefix ? oldLen : 0;
1028
- return resultVNodes;
1029
- }
1030
- //#endregion
1031
- //#region src/runtime/control/for-paths/full-keyed.ts
1032
- /**
1033
- * A pure permutation: every new key resolves to an existing, unchanged item
1034
- * whose index signal is either unread or already correct.
1035
- *
1036
- * Commits as FULL_KEYED, but flagged `pendingMoveOnly` so the commit can move
1037
- * the existing nodes instead of rebuilding them.
1038
- *
1039
- * Guarded by `oldLen === newLen`, and runs only after NO_REORDER and SWAP
1040
- * decline.
1041
- */
1042
- function tryMoveOnlyKeyedPath(forState, newArray, items, byFn, oldLen) {
1043
- const moveOnlyKeys = [];
1044
- const moveOnlyItems = [];
1045
- const moveOnlyVNodes = [];
1046
- for (let i = 0; i < oldLen; i++) {
1047
- const item = newArray[i];
1048
- const key = byFn(item, i);
1049
- const existing = items.get(key);
1050
- if (!existing || existing.item !== item || existing.indexSignal._hasBeenRead && existing.indexSignal.peek() !== i) return null;
1051
- moveOnlyKeys[i] = key;
1052
- moveOnlyItems[i] = existing;
1053
- moveOnlyVNodes[i] = existing.scope.vnode;
1054
- }
1055
- for (let i = 0; i < moveOnlyItems.length; i++) {
1056
- syncForItemIndex(forState, moveOnlyItems[i], i);
1057
- moveOnlyVNodes[i] = moveOnlyItems[i].scope.vnode;
1058
- }
1059
- forState.orderedKeys = moveOnlyKeys;
1060
- forState.orderedItems = moveOnlyItems;
1061
- forState.orderedVNodes = moveOnlyVNodes;
1062
- setForCommitPending(forState, "FULL_KEYED", null, null, true);
1063
- return moveOnlyVNodes;
1064
- }
1065
- /**
1066
- * The general keyed reconciliation every other path declines to handle.
1067
- *
1068
- * One pass over the new array creates, reuses or reindexes each row while
1069
- * tracking which old keys survive; whatever is left over is disposed. Always
1070
- * succeeds, so it takes no guard and returns no `null`.
1071
- */
1072
- function fullKeyedPath(forState, newArray, items, orderedKeys, byFn) {
1073
- const toRemove = new Set(orderedKeys);
1074
- const newOrderedKeys = [];
1075
- const newOrderedItems = [];
1076
- const resultVNodes = [];
1077
- let moveOnly = toRemove.size === newArray.length;
1078
- for (let i = 0; i < newArray.length; i++) {
1079
- const item = newArray[i];
1080
- const key = byFn(item, i);
1081
- toRemove.delete(key);
1082
- newOrderedKeys.push(key);
1083
- const existing = items.get(key);
1084
- if (!existing) {
1085
- const itemInstance = createItemInstance(key, item, i, forState);
1086
- items.set(key, itemInstance);
1087
- newOrderedItems.push(itemInstance);
1088
- resultVNodes.push(itemInstance.scope.vnode);
1089
- } else {
1090
- const itemChanged = existing.item !== item;
1091
- const indexChanged = existing.indexSignal.peek() !== i;
1092
- if (itemChanged) {
1093
- moveOnly = false;
1094
- updateItemInstance(forState, existing, item);
1095
- }
1096
- if (indexChanged) syncForItemIndex(forState, existing, i);
1097
- newOrderedItems.push(existing);
1098
- resultVNodes.push(existing.scope.vnode);
1099
- }
1100
- }
1101
- for (const key of toRemove) {
1102
- moveOnly = false;
1103
- const itemInstance = items.get(key);
1104
- if (itemInstance) {
1105
- disposeItemInstance(forState, itemInstance, "none");
1106
- items.delete(key);
1107
- }
1108
- }
1109
- forState.orderedKeys = newOrderedKeys;
1110
- forState.orderedItems = newOrderedItems;
1111
- forState.orderedVNodes = resultVNodes;
1112
- setForCommitPending(forState, "FULL_KEYED", null, null, moveOnly);
1113
- return resultVNodes;
1114
- }
1115
- //#endregion
1116
- //#region src/runtime/control/for-paths/insert-one.ts
1117
- /**
1118
- * One row inserted, every existing DOM node retained.
1119
- *
1120
- * Requires that no shifted row has read its index signal and that no retained
1121
- * row is already dirty: this path only syncs the inserted index, so a pending
1122
- * update anywhere else would be silently dropped. Every other shape falls
1123
- * through to the general keyed path.
1124
- *
1125
- * Guarded by `newLen === oldLen + 1`.
1126
- */
1127
- function tryInsertOnePath(forState, newArray, items, orderedKeys, byFn, oldLen, newLen) {
1128
- let oldIndex = 0;
1129
- let insertedIndex = -1;
1130
- let insertedKey = null;
1131
- for (let newIndex = 0; newIndex < newLen; newIndex++) {
1132
- const item = newArray[newIndex];
1133
- const key = byFn(item, newIndex);
1134
- const expectedKey = orderedKeys[oldIndex];
1135
- if (oldIndex < oldLen && key === expectedKey) {
1136
- const existing = items.get(key);
1137
- if (!existing || existing.item !== item || existing.scope.needsDomUpdate || oldIndex !== newIndex && existing.indexSignal._hasBeenRead) {
1138
- insertedIndex = -2;
1139
- break;
1140
- }
1141
- oldIndex++;
1142
- } else if (insertedIndex === -1 && !items.has(key)) {
1143
- insertedIndex = newIndex;
1144
- insertedKey = key;
1145
- } else {
1146
- insertedIndex = -2;
1147
- break;
1148
- }
1149
- }
1150
- if (!(insertedIndex >= 0 && oldIndex === oldLen && insertedKey !== null)) return null;
1151
- const insertedItem = createItemInstance(insertedKey, newArray[insertedIndex], insertedIndex, forState);
1152
- const resultVNodes = forState.orderedVNodes.slice();
1153
- const resultItems = forState.orderedItems.slice();
1154
- const resultKeys = orderedKeys.slice();
1155
- resultVNodes.splice(insertedIndex, 0, insertedItem.scope.vnode);
1156
- resultItems.splice(insertedIndex, 0, insertedItem);
1157
- resultKeys.splice(insertedIndex, 0, insertedKey);
1158
- items.set(insertedKey, insertedItem);
1159
- forState.orderedKeys = resultKeys;
1160
- forState.orderedItems = resultItems;
1161
- forState.orderedVNodes = resultVNodes;
1162
- for (let index = insertedIndex; index < resultItems.length; index += 1) syncForItemIndex(forState, resultItems[index], index);
1163
- setForCommitPending(forState, "INSERT_ONE", null, null, false);
1164
- forState.pendingInsertedIndex = insertedIndex;
1165
- return resultVNodes;
1166
- }
1167
- //#endregion
1168
- //#region src/runtime/control/for-paths/no-reorder.ts
1169
- /**
1170
- * Same length, same key at every index: an in-place update with no DOM moves.
1171
- *
1172
- * Dirtiness is read from the scope after `updateItemInstance`, so a row whose
1173
- * item is unchanged but whose subtree was invalidated still commits.
1174
- *
1175
- * Guarded by `oldLen === newLen`.
1176
- */
1177
- function tryNoReorderPath(forState, newArray, items, orderedKeys, byFn, oldLen) {
1178
- for (let i = 0; i < oldLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i]) return null;
1179
- const resultVNodes = forState.orderedVNodes;
1180
- const resultItems = forState.orderedItems;
1181
- resultVNodes.length = oldLen;
1182
- resultItems.length = oldLen;
1183
- const dirtyIndices = [];
1184
- for (let i = 0; i < oldLen; i++) {
1185
- const item = newArray[i];
1186
- const key = orderedKeys[i];
1187
- const existing = items.get(key);
1188
- if (existing.item !== item) updateItemInstance(forState, existing, item);
1189
- if (existing.scope.needsDomUpdate) dirtyIndices.push(i);
1190
- resultItems[i] = existing;
1191
- resultVNodes[i] = existing.scope.vnode;
1192
- }
1193
- setForCommitPending(forState, "NO_REORDER", dirtyIndices, null, false);
1194
- return resultVNodes;
1195
- }
1196
- //#endregion
1197
- //#region src/runtime/control/for-paths/remove-one.ts
1198
- /**
1199
- * Exactly one row removed, the suffix shifted up by one.
1200
- *
1201
- * The shifted suffix keeps its instances; only rows whose item or index
1202
- * actually changed land in the dirty list. `pendingRemovedKey` tells the commit
1203
- * which keyed-map entry to drop, and the commit detaches that node before
1204
- * applying the plan so dirty rows anchor on post-removal indices.
1205
- *
1206
- * Guarded by `oldLen === newLen + 1`.
1207
- */
1208
- function tryRemoveOnePath(forState, newArray, items, orderedKeys, byFn, newLen) {
1209
- let removedIndex = -1;
1210
- for (let i = 0; i < newLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i]) {
1211
- removedIndex = i;
1212
- break;
1213
- }
1214
- if (removedIndex === -1) return null;
1215
- for (let i = removedIndex; i < newLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i + 1]) return null;
1216
- const resultVNodes = forState.orderedVNodes;
1217
- const resultItems = forState.orderedItems;
1218
- const removedKey = orderedKeys[removedIndex];
1219
- const removedItem = resultItems[removedIndex] ?? items.get(removedKey);
1220
- orderedKeys.copyWithin(removedIndex, removedIndex + 1);
1221
- resultItems.copyWithin(removedIndex, removedIndex + 1);
1222
- resultVNodes.copyWithin(removedIndex, removedIndex + 1);
1223
- orderedKeys.length = newLen;
1224
- resultItems.length = newLen;
1225
- resultVNodes.length = newLen;
1226
- const dirtyIndices = [];
1227
- for (let i = 0; i < newLen; i++) {
1228
- const item = newArray[i];
1229
- const existing = resultItems[i];
1230
- const scopeNeedsDomUpdate = existing.scope.needsDomUpdate;
1231
- const itemChanged = existing.item !== item;
1232
- const indexSignal = existing.indexSignal;
1233
- const indexChanged = i >= removedIndex && indexSignal.peek() !== i;
1234
- if (itemChanged) updateItemInstance(forState, existing, item);
1235
- const indexVisibleChange = indexChanged ? syncForItemIndex(forState, existing, i) : false;
1236
- if (itemChanged || indexVisibleChange || scopeNeedsDomUpdate) dirtyIndices.push(i);
1237
- resultVNodes[i] = existing.scope.vnode;
1238
- }
1239
- if (removedItem) {
1240
- disposeItemInstance(forState, removedItem, "teardown");
1241
- items.delete(removedKey);
1242
- }
1243
- setForCommitPending(forState, "REMOVE_ONE", dirtyIndices, null, false);
1244
- forState.pendingRemovedKey = removedKey;
1245
- return resultVNodes;
1246
- }
1247
- //#endregion
1248
- //#region src/runtime/control/for-paths/swap.ts
1249
- /**
1250
- * Exactly two rows exchanged, everything else untouched.
1251
- *
1252
- * Bails when any key-matched row already carries a pending DOM update: SWAP
1253
- * only ever syncs the two swapped indices, so such a row would silently lose
1254
- * its update. This mirrors the INSERT_ONE guard.
1255
- *
1256
- * Guarded by `oldLen === newLen`, and runs only after NO_REORDER declines.
1257
- */
1258
- function trySwapPath(forState, newArray, items, orderedKeys, byFn, oldLen) {
1259
- let firstMismatch = -1;
1260
- let secondMismatch = -1;
1261
- let firstMismatchKey = null;
1262
- let secondMismatchKey = null;
1263
- let mismatchCount = 0;
1264
- let canUseSwapPath = true;
1265
- for (let i = 0; i < oldLen; i++) {
1266
- const item = newArray[i];
1267
- const key = byFn(newArray[i], i);
1268
- if (key === orderedKeys[i]) {
1269
- const existing = items.get(key);
1270
- if (existing && (existing.item !== item || existing.scope.needsDomUpdate)) {
1271
- canUseSwapPath = false;
1272
- break;
1273
- }
1274
- continue;
1275
- }
1276
- mismatchCount++;
1277
- if (firstMismatch === -1) {
1278
- firstMismatch = i;
1279
- firstMismatchKey = key;
1280
- continue;
1281
- }
1282
- if (secondMismatch === -1) {
1283
- secondMismatch = i;
1284
- secondMismatchKey = key;
1285
- continue;
1286
- }
1287
- mismatchCount = 3;
1288
- break;
1289
- }
1290
- if (!(canUseSwapPath && mismatchCount === 2 && firstMismatch !== -1 && secondMismatch !== -1 && firstMismatchKey === orderedKeys[secondMismatch] && secondMismatchKey === orderedKeys[firstMismatch])) return null;
1291
- const nextOrderedKeys = orderedKeys.slice();
1292
- nextOrderedKeys[firstMismatch] = firstMismatchKey;
1293
- nextOrderedKeys[secondMismatch] = secondMismatchKey;
1294
- const resultVNodes = forState.orderedVNodes;
1295
- const firstExisting = items.get(firstMismatchKey);
1296
- const secondExisting = items.get(secondMismatchKey);
1297
- const firstItem = newArray[firstMismatch];
1298
- const secondItem = newArray[secondMismatch];
1299
- const nextOrderedItems = forState.orderedItems.slice();
1300
- nextOrderedItems[firstMismatch] = firstExisting;
1301
- nextOrderedItems[secondMismatch] = secondExisting;
1302
- if (firstExisting.item !== firstItem) updateItemInstance(forState, firstExisting, firstItem);
1303
- if (secondExisting.item !== secondItem) updateItemInstance(forState, secondExisting, secondItem);
1304
- syncForItemIndex(forState, firstExisting, firstMismatch);
1305
- syncForItemIndex(forState, secondExisting, secondMismatch);
1306
- resultVNodes[firstMismatch] = firstExisting.scope.vnode;
1307
- resultVNodes[secondMismatch] = secondExisting.scope.vnode;
1308
- forState.orderedKeys = nextOrderedKeys;
1309
- forState.orderedItems = nextOrderedItems;
1310
- setForCommitPending(forState, "SWAP", null, [firstMismatch, secondMismatch], true);
1311
- return resultVNodes;
1312
- }
1313
- //#endregion
1314
- //#region src/runtime/control/for-paths/truncate.ts
1315
- /**
1316
- * The tail dropped, the surviving prefix keeping its keys and positions.
1317
- *
1318
- * Survivors are updated in place; the removed tail is disposed here, so the
1319
- * commit only has to patch the dirty survivors and detach the orphaned nodes.
1320
- * A survivor also counts as dirty when its component host was unmounted out
1321
- * from under it.
1322
- *
1323
- * Guarded by `newLen < oldLen`.
1324
- */
1325
- function tryTruncatePath(forState, newArray, items, orderedKeys, byFn, oldLen, newLen) {
1326
- for (let i = 0; i < newLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i]) return null;
1327
- const resultVNodes = forState.orderedVNodes;
1328
- const resultItems = forState.orderedItems;
1329
- resultVNodes.length = newLen;
1330
- resultItems.length = newLen;
1331
- const isFullClear = newLen === 0;
1332
- const dirtyIndices = [];
1333
- for (let i = 0; i < newLen; i++) {
1334
- const item = newArray[i];
1335
- const key = orderedKeys[i];
1336
- const existing = items.get(key);
1337
- const itemChanged = existing.item !== item;
1338
- const scopeNeedsDomUpdate = existing.scope.needsDomUpdate || getRuntimeScopes().hasUnmountedComponentHost(existing.scope.dom);
1339
- if (itemChanged) updateItemInstance(forState, existing, item);
1340
- if (itemChanged || scopeNeedsDomUpdate) dirtyIndices.push(i);
1341
- resultItems[i] = existing;
1342
- resultVNodes[i] = existing.scope.vnode;
1343
- }
1344
- for (let i = newLen; i < oldLen; i++) {
1345
- const key = orderedKeys[i];
1346
- const itemInstance = items.get(key);
1347
- if (itemInstance) {
1348
- disposeItemInstance(forState, itemInstance, isFullClear ? "full-clear" : "teardown");
1349
- items.delete(key);
1350
- }
1351
- }
1352
- orderedKeys.length = newLen;
1353
- forState.orderedKeys = orderedKeys;
1354
- forState.orderedItems.length = newLen;
1355
- forState.orderedVNodes = resultVNodes;
1356
- setForCommitPending(forState, "TRUNCATE", dirtyIndices, null, false);
1357
- return resultVNodes;
1358
- }
1359
- //#endregion
1360
- //#region src/runtime/control/for-reconcile.ts
1361
- function failForValidation(message) {
1362
- throw new Error(message);
1363
- }
1364
- function validateForKeys(forState, newArray) {
1365
- if (!isDevelopmentEnvironment()) return;
1366
- const seen = /* @__PURE__ */ new Set();
1367
- const keyKinds = /* @__PURE__ */ new Map();
1368
- for (let i = 0; i < newArray.length; i++) {
1369
- const key = forState.byFn(newArray[i], i);
1370
- if (key === null || key === void 0) failForValidation("[askr] Invalid For key detected. Keys should be stable, non-null, and unique within a For list.");
1371
- if (seen.has(key)) failForValidation(`[askr] Duplicate For key detected: ${String(key)}. Keys should be stable, non-null, and unique within a For list.`);
1372
- seen.add(key);
1373
- const keyKind = typeof key;
1374
- const previousKeyKind = forState.devKeyKinds?.get(key);
1375
- if (previousKeyKind && previousKeyKind !== keyKind) failForValidation(`[askr] For key type changed for ${String(key)}. Keys must remain consistently typed across renders.`);
1376
- keyKinds.set(key, keyKind);
1377
- }
1378
- forState.devKeyKinds = keyKinds;
1379
- }
1380
- function reconcileForItems(forState, newArray) {
1381
- forState.currentItems = newArray;
1382
- validateForKeys(forState, newArray);
1383
- const { items, orderedKeys, byFn } = forState;
1384
- const oldLen = orderedKeys.length;
1385
- const newLen = newArray.length;
1386
- forState.lastRemovedNodes = [];
1387
- forState.lastRemovedRanges = [];
1388
- forState.pendingRemovedKey = null;
1389
- if (newLen === 0) {
1390
- if (oldLen > 0) disposeAllItems(forState, forState.fallback ? "teardown" : "none");
1391
- forState.lastCommitStrategy = "TRUNCATE";
1392
- forState.pendingDirtyIndices = null;
1393
- forState.pendingSwapIndices = null;
1394
- forState.pendingMoveOnly = false;
1395
- return renderFallbackScope(forState);
1396
- }
1397
- if (forState.fallbackScope) disposeFallbackScope(forState, "none");
1398
- /** Close out the pass. Each path has already published its own decision. */
1399
- const finish = (vnodes) => {
1400
- return vnodes;
1401
- };
1402
- if (newLen === oldLen + 1) {
1403
- const inserted = tryInsertOnePath(forState, newArray, items, orderedKeys, byFn, oldLen, newLen);
1404
- if (inserted) return finish(inserted);
1405
- }
1406
- if (oldLen < newLen) {
1407
- const appended = tryAppendPath(forState, newArray, items, orderedKeys, byFn, oldLen, newLen);
1408
- if (appended) return finish(appended);
1409
- }
1410
- if (newLen < oldLen) {
1411
- if (oldLen === newLen + 1) {
1412
- const removed = tryRemoveOnePath(forState, newArray, items, orderedKeys, byFn, newLen);
1413
- if (removed) return finish(removed);
1414
- }
1415
- const truncated = tryTruncatePath(forState, newArray, items, orderedKeys, byFn, oldLen, newLen);
1416
- if (truncated) return finish(truncated);
1417
- }
1418
- if (oldLen === newLen) {
1419
- const unmoved = tryNoReorderPath(forState, newArray, items, orderedKeys, byFn, oldLen);
1420
- if (unmoved) return finish(unmoved);
1421
- const swapped = trySwapPath(forState, newArray, items, orderedKeys, byFn, oldLen);
1422
- if (swapped) return finish(swapped);
1423
- const moved = tryMoveOnlyKeyedPath(forState, newArray, items, byFn, oldLen);
1424
- if (moved) return finish(moved);
1425
- }
1426
- return finish(fullKeyedPath(forState, newArray, items, orderedKeys, byFn));
1427
- }
1428
- //#endregion
1429
- //#region src/runtime/control/for-state.ts
1430
- const forStates = /* @__PURE__ */ new WeakMap();
1431
- function getForStore(instance) {
1432
- const generation = instance.owner.identity;
1433
- let store = forStates.get(generation);
1434
- if (!store) {
1435
- store = /* @__PURE__ */ new Map();
1436
- forStates.set(generation, store);
1437
- }
1438
- return store;
1439
- }
1440
- function createForState(eachSource, byFn, renderFn, fallback) {
1441
- const parentInstance = getCurrentComponentInstance();
1442
- const scopeOwner = new OwnershipRecord();
1443
- const scopeOwnership = {
1444
- add: (scope) => ownChild(scopeOwner, scope),
1445
- delete: (scope) => releaseOwnedChild(scopeOwner, scope),
1446
- bulkDispose(run) {
1447
- detachOwnedChildren(scopeOwner);
1448
- run();
1449
- }
1450
- };
1451
- if (parentInstance) {
1452
- registerScopedOwnership({
1453
- key: "for-boundary",
1454
- dispose() {
1455
- disposeOwnership(scopeOwner);
1456
- }
1457
- }, scopeOwner);
1458
- attachOwnership(scopeOwner, parentInstance.owner);
1459
- }
1460
- return {
1461
- kind: "for",
1462
- _contextFrame: null,
1463
- _contextFrameChanged: false,
1464
- currentItems: [],
1465
- _committedItems: [],
1466
- eachSource,
1467
- fallback,
1468
- fallbackScope: null,
1469
- items: /* @__PURE__ */ new Map(),
1470
- orderedKeys: [],
1471
- orderedItems: [],
1472
- orderedVNodes: [],
1473
- byFn,
1474
- renderFn,
1475
- parentInstance,
1476
- lastCommitStrategy: "NO_REORDER",
1477
- lastRemovedNodes: [],
1478
- lastRemovedRanges: [],
1479
- pendingDirtyIndices: null,
1480
- pendingSwapIndices: null,
1481
- pendingMoveOnly: false,
1482
- pendingInsertedIndex: null,
1483
- pendingRemovedKey: null,
1484
- pendingAppendStart: null,
1485
- _hasResolvedItemDom: false,
1486
- _needsSourceReconcile: false,
1487
- _sourceEffect: null,
1488
- _suspendSourceCommit: false,
1489
- _enqueueBoundaryCommit: null,
1490
- _scopeOwnership: scopeOwnership,
1491
- _hasPendingBoundaryCommit: false,
1492
- _transaction: null
1493
- };
1494
- }
1495
- function useForState(eachSource, byFn, renderFn, fallback) {
1496
- const instance = getCurrentComponentInstance();
1497
- if (!instance) throw new Error("For can only be created during component render execution.");
1498
- const hookIndex = claimHookIndex(instance, "For");
1499
- const generation = instance.owner.identity;
1500
- const store = getForStore(instance);
1501
- const existing = store.get(hookIndex);
1502
- if (existing) {
1503
- existing.eachSource = eachSource;
1504
- existing.byFn = byFn;
1505
- existing.renderFn = renderFn;
1506
- existing.fallback = fallback;
1507
- return existing;
1508
- }
1509
- const created = createForState(eachSource, byFn, renderFn, fallback);
1510
- store.set(hookIndex, created);
1511
- ownCleanup(instance.owner, () => {
1512
- try {
1513
- created._sourceEffect?.cleanup();
1514
- } finally {
1515
- created._sourceEffect = null;
1516
- store.delete(hookIndex);
1517
- if (store.size === 0 && forStates.get(generation) === store) forStates.delete(generation);
1518
- }
1519
- });
1520
- return created;
1521
- }
1522
- function evaluateForState(forState) {
1523
- if (!Array.isArray(forState.currentItems)) throw new Error("For source must evaluate to an array");
1524
- beginForStateTransaction(forState);
1525
- forState._needsSourceReconcile = false;
1526
- try {
1527
- if (forState._contextFrameChanged) refreshForContextScopes(forState);
1528
- const result = reconcileForItems(forState, forState.currentItems);
1529
- forState._contextFrameChanged = false;
1530
- return result;
1531
- } catch (error) {
1532
- rollbackForStateTransaction(forState);
1533
- throw error;
1534
- }
1535
- }
1536
- /**
1537
- * Reconciliation changes ownership before DOM work can fail. Keep a private
1538
- * structural snapshot until the boundary has committed so failed work cannot
1539
- * leave provisional child scopes in the parent owner graph.
1540
- */
1541
- function beginForStateTransaction(forState, collectionMode = "auto") {
1542
- if (forState._transaction) return;
1543
- const hasEmptyCollections = forState.items.size === 0 && forState.orderedKeys.length === 0 && forState.orderedItems.length === 0 && forState.orderedVNodes.length === 0;
1544
- const isFullClear = forState.currentItems.length === 0 && forState.orderedKeys.length > 0;
1545
- const collectionSnapshotMode = collectionMode === "reuse" ? "reuse" : hasEmptyCollections ? "reset-empty" : isFullClear ? "preserve-clear" : "copy";
1546
- const transaction = {
1547
- collectionSnapshotMode,
1548
- currentItems: forState._committedItems,
1549
- items: collectionSnapshotMode === "copy" ? new Map(forState.items) : forState.items,
1550
- orderedKeys: collectionSnapshotMode === "copy" ? forState.orderedKeys.slice() : forState.orderedKeys,
1551
- orderedItems: collectionSnapshotMode === "copy" ? forState.orderedItems.slice() : forState.orderedItems,
1552
- orderedVNodes: collectionSnapshotMode === "copy" ? forState.orderedVNodes.slice() : forState.orderedVNodes,
1553
- fallbackScope: forState.fallbackScope,
1554
- lastCommitStrategy: forState.lastCommitStrategy,
1555
- lastRemovedNodes: forState.lastRemovedNodes,
1556
- lastRemovedRanges: forState.lastRemovedRanges,
1557
- pendingDirtyIndices: forState.pendingDirtyIndices,
1558
- pendingSwapIndices: forState.pendingSwapIndices,
1559
- pendingMoveOnly: forState.pendingMoveOnly,
1560
- pendingInsertedIndex: forState.pendingInsertedIndex,
1561
- pendingRemovedKey: forState.pendingRemovedKey,
1562
- pendingAppendStart: forState.pendingAppendStart,
1563
- hasResolvedItemDom: forState._hasResolvedItemDom,
1564
- needsSourceReconcile: forState._needsSourceReconcile,
1565
- devKeyKinds: forState.devKeyKinds,
1566
- itemSnapshots: null,
1567
- unreadIndexSnapshots: null,
1568
- fallbackScopeSnapshot: null,
1569
- removedScopes: null,
1570
- removedScopeNodes: null,
1571
- removeAllItems: false,
1572
- signalEffects: null,
1573
- shouldClearDomUpdateState: false
1574
- };
1575
- forState._transaction = transaction;
1576
- registerForStateTransaction(forState, transaction);
1577
- }
1578
- function registerForStateTransaction(forState, transaction = forState._transaction) {
1579
- if (!transaction || forState._transaction !== transaction) return false;
1580
- return registerCommitParticipant({
1581
- key: transaction,
1582
- collision: "keep-first",
1583
- publish: () => publishForStateTransaction(forState, transaction),
1584
- settle: () => commitForStateTransaction(forState, transaction),
1585
- rollback: () => rollbackForStateTransaction(forState, transaction)
1586
- });
1587
- }
1588
- function finalizeForStateRemovals(forState, transaction) {
1589
- const removedScopes = transaction.removedScopes;
1590
- if (!transaction.removeAllItems && !removedScopes) return;
1591
- const cleanupErrors = [];
1592
- const finalizeScope = (scope) => {
1593
- const removedDom = scope.dom;
1594
- const removedRange = scope.range;
1595
- try {
1596
- disposeChildScope(scope);
1597
- } catch (error) {
1598
- cleanupErrors.push(error);
1599
- }
1600
- if (transaction.removedScopeNodes) return;
1601
- getRuntimeScopes().teardownScopeHost(removedDom, removedRange, (error) => cleanupErrors.push(error));
1602
- };
1603
- if (transaction.removeAllItems) forState._scopeOwnership.bulkDispose(() => {
1604
- for (let index = 0; index < transaction.orderedItems.length; index++) {
1605
- const item = transaction.orderedItems[index];
1606
- if (item) finalizeScope(item.scope);
1607
- }
1608
- });
1609
- for (const scope of removedScopes ?? []) finalizeScope(scope);
1610
- const removedScopeNodes = transaction.removedScopeNodes;
1611
- if (removedScopeNodes) for (const node of removedScopeNodes) try {
1612
- getRuntimeCleanup().teardownNodeSubtree(node);
1613
- } catch (error) {
1614
- cleanupErrors.push(error);
1615
- }
1616
- if (removedScopes) removedScopes.length = 0;
1617
- if (removedScopeNodes) removedScopeNodes.length = 0;
1618
- transaction.removeAllItems = false;
1619
- if (cleanupErrors.length > 0) logger.error("[Askr] For removal cleanup failed:", new AggregateError(cleanupErrors, "For removal cleanup failed"));
1620
- }
1621
- function finalizeForSignalEffects(transaction) {
1622
- if (!transaction.signalEffects) return;
1623
- for (const [source, effect] of transaction.signalEffects) {
1624
- removeForParentReaders(effect.parentInstance, source);
1625
- if (effect.notify) notifyForSignalReaders(source, effect.skipInstance, effect.skipOwnedBy);
1626
- }
1627
- transaction.signalEffects.clear();
1628
- }
1629
- function finalizeForDomUpdateFlags(forState) {
1630
- for (let index = 0; index < forState.orderedItems.length; index++) {
1631
- const item = forState.orderedItems[index];
1632
- if (item) item.scope.needsDomUpdate = false;
1633
- }
1634
- if (forState.fallbackScope) forState.fallbackScope.needsDomUpdate = false;
1635
- }
1636
- function publishForStateTransaction(forState, transaction) {
1637
- if (forState._transaction !== transaction) return;
1638
- if (transaction.shouldClearDomUpdateState) finalizeForDomUpdateFlags(forState);
1639
- forState._committedItems = forState.currentItems;
1640
- forState._transaction = null;
1641
- transaction.published = true;
1642
- }
1643
- function commitForStateTransaction(forState, transaction = forState._transaction) {
1644
- if (!transaction) return;
1645
- if (!transaction.published) publishForStateTransaction(forState, transaction);
1646
- if (!transaction.published) return;
1647
- transaction.published = false;
1648
- const errors = [];
1649
- try {
1650
- try {
1651
- finalizeForStateRemovals(forState, transaction);
1652
- } catch (error) {
1653
- errors.push(error);
1654
- }
1655
- try {
1656
- finalizeForSignalEffects(transaction);
1657
- } catch (error) {
1658
- errors.push(error);
1659
- }
1660
- } finally {
1661
- transaction.itemSnapshots?.clear();
1662
- transaction.unreadIndexSnapshots?.clear();
1663
- transaction.fallbackScopeSnapshot = null;
1664
- }
1665
- if (errors.length) throw new AggregateError(errors, "For settlement failed");
1666
- }
1667
- function rollbackForStateTransaction(forState, transaction = forState._transaction) {
1668
- if (!transaction || forState._transaction !== transaction && !transaction.published) return;
1669
- transaction.published = false;
1670
- const rollbackCleanupErrors = [];
1671
- const scopesToDispose = /* @__PURE__ */ new Set();
1672
- const committedScopes = transaction.collectionSnapshotMode === "reset-empty" ? null : new Set(transaction.orderedItems.map((item) => item.scope));
1673
- if (transaction.fallbackScope) committedScopes?.add(transaction.fallbackScope);
1674
- if (transaction.collectionSnapshotMode === "reset-empty") for (const item of forState.items.values()) scopesToDispose.add(item.scope);
1675
- else for (const [key, item] of forState.items) if (transaction.items.get(key) !== item) scopesToDispose.add(item.scope);
1676
- for (const scope of transaction.removedScopes ?? []) if (scope !== transaction.fallbackScope && !committedScopes?.has(scope)) scopesToDispose.add(scope);
1677
- if (forState.fallbackScope && forState.fallbackScope !== transaction.fallbackScope) scopesToDispose.add(forState.fallbackScope);
1678
- for (const scope of scopesToDispose) try {
1679
- disposeChildScope(scope);
1680
- } catch (error) {
1681
- rollbackCleanupErrors.push(error);
1682
- }
1683
- if (transaction.collectionSnapshotMode === "reset-empty") {
1684
- forState.items.clear();
1685
- forState.orderedKeys.length = 0;
1686
- forState.orderedItems.length = 0;
1687
- forState.orderedVNodes.length = 0;
1688
- }
1689
- for (const [itemInstance, snapshot] of transaction.itemSnapshots ?? []) {
1690
- itemInstance.item = snapshot.item;
1691
- const reactiveItemState = itemInstance.reactiveItemState;
1692
- if (reactiveItemState) reactiveItemState.currentItem = snapshot.item;
1693
- const itemSignal = reactiveItemState?.itemSignal;
1694
- if (itemSignal && snapshot.itemSignalExists) {
1695
- itemSignal.set(snapshot.itemSignalValue, false);
1696
- itemSignal._hasBeenRead = snapshot.itemSignalHasBeenRead;
1697
- }
1698
- itemInstance.indexSignal.set(snapshot.indexValue, false);
1699
- itemInstance.indexSignal._hasBeenRead = snapshot.indexHasBeenRead;
1700
- const propertySignals = snapshot.propertySignalStore;
1701
- if (reactiveItemState) reactiveItemState.propertySignals = propertySignals;
1702
- if (propertySignals) {
1703
- propertySignals.clear();
1704
- for (const [property, propertySnapshot] of snapshot.propertySignals ?? []) {
1705
- propertySnapshot.signal.set(propertySnapshot.value, false);
1706
- propertySnapshot.signal._hasBeenRead = propertySnapshot.hasBeenRead;
1707
- propertySignals.set(property, propertySnapshot.signal);
1708
- }
1709
- }
1710
- restoreChildScopeTransactionSnapshot(itemInstance.scope, snapshot.scope);
1711
- }
1712
- for (const [indexSignal, index] of transaction.unreadIndexSnapshots ?? []) indexSignal.set(index, false);
1713
- if (transaction.fallbackScope && transaction.fallbackScopeSnapshot) restoreChildScopeTransactionSnapshot(transaction.fallbackScope, transaction.fallbackScopeSnapshot);
1714
- forState.currentItems = transaction.currentItems;
1715
- forState._committedItems = transaction.currentItems;
1716
- forState.items = transaction.items;
1717
- forState.orderedKeys = transaction.orderedKeys;
1718
- forState.orderedItems = transaction.orderedItems;
1719
- forState.orderedVNodes = transaction.orderedVNodes;
1720
- forState.fallbackScope = transaction.fallbackScope;
1721
- forState.lastCommitStrategy = transaction.lastCommitStrategy;
1722
- forState.lastRemovedNodes = transaction.lastRemovedNodes;
1723
- forState.lastRemovedRanges = transaction.lastRemovedRanges;
1724
- forState.pendingDirtyIndices = transaction.pendingDirtyIndices;
1725
- forState.pendingSwapIndices = transaction.pendingSwapIndices;
1726
- forState.pendingMoveOnly = transaction.pendingMoveOnly;
1727
- forState.pendingInsertedIndex = transaction.pendingInsertedIndex;
1728
- forState.pendingRemovedKey = transaction.pendingRemovedKey;
1729
- forState.pendingAppendStart = transaction.pendingAppendStart;
1730
- forState._hasResolvedItemDom = transaction.hasResolvedItemDom;
1731
- forState._needsSourceReconcile = transaction.needsSourceReconcile;
1732
- forState.devKeyKinds = transaction.devKeyKinds;
1733
- forState._transaction = null;
1734
- if (rollbackCleanupErrors.length > 0) logger.error("[Askr] transaction rollback cleanup failed:", new AggregateError(rollbackCleanupErrors, "Transaction rollback cleanup failed"));
1735
- }
1736
- function clearForDomUpdateState(forState) {
1737
- const transaction = forState._transaction;
1738
- if (transaction) transaction.shouldClearDomUpdateState = true;
1739
- if (transaction && !registerForStateTransaction(forState, transaction)) commitForStateTransaction(forState, transaction);
1740
- if (!transaction) finalizeForDomUpdateFlags(forState);
1741
- forState.lastRemovedNodes = [];
1742
- forState.lastRemovedRanges = [];
1743
- forState.pendingDirtyIndices = null;
1744
- forState.pendingSwapIndices = null;
1745
- forState.pendingMoveOnly = false;
1746
- forState.pendingInsertedIndex = null;
1747
- forState.pendingRemovedKey = null;
1748
- forState.pendingAppendStart = null;
1749
- forState._needsSourceReconcile = false;
1750
- forState._hasResolvedItemDom = forState.orderedKeys.length > 0;
1751
- }
1752
- //#endregion
1753
- export { setControlBoundaryContextFrame as _, registerForStateTransaction as a, joinChildScopePreparation as b, captureForFallbackTransactionSnapshot as c, clearCaseDomUpdateState as d, clearShowDomUpdateState as f, evaluateShowState as g, evaluateCaseState as h, evaluateForState as i, captureForItemTransactionSnapshot as l, createShowState as m, clearForDomUpdateState as n, rollbackForStateTransaction as o, createCaseState as p, commitForStateTransaction as r, useForState as s, beginForStateTransaction as t, recordBenchEvent as u, createChildScope as v, rerenderChildScope as x, disposeChildScope as y };