@askrjs/askr 0.2.4 → 0.3.1

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 (117) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/access-CEA2pOry.js +1046 -0
  3. package/dist/actions/index.d.ts +16 -2
  4. package/dist/actions/index.js +5 -5
  5. package/dist/{activity-FirwPXA_.js → activity-oy2YFTFF.js} +10 -16
  6. package/dist/benchmark.js +8 -9
  7. package/dist/boot/index.d.ts +19 -9
  8. package/dist/boot/index.js +1 -1
  9. package/dist/{boot-tWyF6121.js → boot-DLplW9h4.js} +700 -441
  10. package/dist/capabilities-Bbf0mlp9.js +42 -0
  11. package/dist/components/index.d.ts +11 -8
  12. package/dist/components/index.js +1 -1
  13. package/dist/{compose-ref-Bfaf4kUC.js → compose-ref-v0qGlHoN.js} +7 -1
  14. package/dist/control/index.d.ts +20 -2
  15. package/dist/control/index.js +1 -1
  16. package/dist/{control-C-wSaq9V.js → control-BR_mrX__.js} +4 -4
  17. package/dist/core.d.ts +163 -0
  18. package/dist/csp-nonce-BfFWcd0w.js +173 -0
  19. package/dist/data/index.d.ts +74 -2
  20. package/dist/data/index.js +3 -3
  21. package/dist/{data-ghKopAbp.js → data-2edW0jhF.js} +108 -122
  22. package/dist/{data-runtime-7t_Y0iv3.js → data-runtime-CxoY98lX.js} +22 -15
  23. package/dist/{deferred-CxjWCkIn.js → deferred-CbgNhf67.js} +5 -5
  24. package/dist/dom-renderer.d.ts +77 -0
  25. package/dist/domains/actions.d.ts +70 -0
  26. package/dist/domains/component.d.ts +119 -0
  27. package/dist/domains/context.d.ts +73 -0
  28. package/dist/domains/control.d.ts +328 -0
  29. package/dist/domains/data.d.ts +461 -0
  30. package/dist/domains/diagnostics.d.ts +21 -0
  31. package/dist/domains/lifecycle.d.ts +112 -0
  32. package/dist/domains/refs.d.ts +18 -0
  33. package/dist/domains/renderer.d.ts +127 -0
  34. package/dist/domains/routing.d.ts +501 -0
  35. package/dist/domains/scheduler.d.ts +79 -0
  36. package/dist/domains/server.d.ts +112 -0
  37. package/dist/domains/state.d.ts +129 -0
  38. package/dist/domains/telemetry.d.ts +29 -0
  39. package/dist/eager-control.d.ts +8 -0
  40. package/dist/{effect-CNwstBBD.js → effect-C3Zsc1k6.js} +14 -41
  41. package/dist/{types-DWVrKn9N.d.ts → elements.d.ts} +79 -42
  42. package/dist/{for-internal-DyBHfKJA.js → for-state-BDykeOJL.js} +598 -494
  43. package/dist/foundations/icon/index.d.ts +67 -16
  44. package/dist/foundations/icon/index.js +1 -1
  45. package/dist/foundations/index.d.ts +26 -3
  46. package/dist/foundations/index.js +1 -1
  47. package/dist/foundations/interactions/index.d.ts +73 -34
  48. package/dist/foundations/interactions/index.js +1 -1
  49. package/dist/foundations/state/index.d.ts +12 -5
  50. package/dist/foundations/state/index.js +1 -1
  51. package/dist/foundations/structures/index.d.ts +44 -3
  52. package/dist/foundations/structures/index.js +1 -1
  53. package/dist/foundations/utilities/index.d.ts +34 -3
  54. package/dist/foundations/utilities/index.js +1 -1
  55. package/dist/fx/index.d.ts +72 -25
  56. package/dist/fx/index.js +8 -8
  57. package/dist/index.d.ts +121 -4
  58. package/dist/index.js +316 -47
  59. package/dist/{component-internal-C4hKKQBF.js → instance-VAFYVJOa.js} +495 -283
  60. package/dist/{interactions-D102JxBR.js → interactions-CTeACdT_.js} +1 -1
  61. package/dist/jsx-dev-runtime.d.ts +51 -11
  62. package/dist/jsx-globals.d.ts +2 -0
  63. package/dist/jsx-runtime-CPJXAOBF.js +43 -0
  64. package/dist/jsx-runtime.d.ts +17 -3
  65. package/dist/jsx-runtime.js +2 -42
  66. package/dist/jsx.d.ts +108 -0
  67. package/dist/{manifest-D6rfj_jC.js → manifest-D1P3UNWV.js} +4 -9
  68. package/dist/{navigate-ZZu1IV0B.js → navigate-prC5V8XV.js} +125 -472
  69. package/dist/{navigate-F4sHgWbw.d.ts → navigation.d.ts} +8 -8
  70. package/dist/{readable-Di1fzSwm.js → notify-DxxuDPeY.js} +96 -34
  71. package/dist/{query-registry-Bua3cDyb.js → query-registry-LrYpQsDJ.js} +1 -1
  72. package/dist/{compose-ref-DOJHoW5X.d.ts → refs.d.ts} +11 -7
  73. package/dist/{ssr-Doog-AfJ.js → render-resolved-BC0W7_5b.js} +165 -558
  74. package/dist/{renderer-Cl23O0hV.js → renderer-CT0HeY58.js} +6825 -5692
  75. package/dist/{resolution-ClD-K7Lz.js → resolution-3DskUkjG.js} +189 -180
  76. package/dist/{resource-operation-Vz1S5h2k.js → resource-18-sFRl9.js} +98 -58
  77. package/dist/resources/index.d.ts +64 -12
  78. package/dist/resources/index.js +214 -8
  79. package/dist/route-activity.d.ts +21 -0
  80. package/dist/{route-matching-Bo6UqG-5.js → route-matching-CUzZ31gT.js} +68 -82
  81. package/dist/router/index.d.ts +378 -79
  82. package/dist/router/index.js +9 -9
  83. package/dist/router-internal-7nuNEHfG.js +36 -0
  84. package/dist/scope-Cq_iYbTR.js +403 -0
  85. package/dist/{selector-CsKuomw0.js → selector-BSPVkjKP.js} +26 -27
  86. package/dist/{shared-CYBH3F8I.js → shared-kU8yvryp.js} +3 -6
  87. package/dist/{snapshot-source-BB42xgwb.js → snapshot-source-An4iKajG.js} +1 -1
  88. package/dist/ssg/index.d.ts +51 -15
  89. package/dist/ssg/index.js +269 -209
  90. package/dist/ssr/index.d.ts +121 -68
  91. package/dist/ssr/index.js +2 -1
  92. package/dist/ssr-CiNm6Vzl.js +393 -0
  93. package/dist/{ssr-DSHd_Q9K.js → ssr-EPjwJH5R.js} +5 -1
  94. package/dist/{state-BGJgYSyQ.js → state-BXJfudq1.js} +10 -15
  95. package/dist/{structures-DFyK5AdQ.js → structures-CjEzfj4h.js} +37 -57
  96. package/dist/{index-CTpMmzgN.d.ts → structures.d.ts} +57 -36
  97. package/dist/testing/index.d.ts +123 -24
  98. package/dist/testing/index.js +24 -61
  99. package/dist/timer-C7uqnJVt.js +85 -0
  100. package/dist/{index-B1gu0_m0.d.ts → utilities.d.ts} +24 -13
  101. package/dist/{verify-hydration-BZPJ_kYa.js → verify-hydration-ikaxotf7.js} +8 -5
  102. package/package.json +12 -14
  103. package/dist/access-BucjYZcX.js +0 -509
  104. package/dist/activity-DooIuxQO.d.ts +0 -14
  105. package/dist/benchmark.d.ts +0 -26
  106. package/dist/cleanup-TXSsApEl.js +0 -535
  107. package/dist/component-cleanup-jdbgjkT1.js +0 -143
  108. package/dist/component-scope-4I3yEMkb.js +0 -195
  109. package/dist/control-Cxag1yqV.d.ts +0 -8
  110. package/dist/csp-nonce-9NFUb7hJ.js +0 -72
  111. package/dist/css-BuPaTOfe.js +0 -70
  112. package/dist/fastlane-BKZduiBQ.js +0 -166
  113. package/dist/index-Dgjbo2gU.d.ts +0 -1456
  114. package/dist/jsx-runtime-Cg7GqY1S.d.ts +0 -2
  115. package/dist/jsx-runtime-gVIaTPw0.d.ts +0 -38
  116. package/dist/lifecycle-batch-63aXFf2S.js +0 -253
  117. package/dist/lifecycle-operations-Q0k3EFnG.js +0 -287
@@ -1,15 +1,14 @@
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";
1
6
  import { n as _isDOMElement } from "./vnode-D24p6IW2.js";
2
- import { o as getRuntimeRenderer, x as isDevelopmentEnvironment, y as logger } from "./access-BucjYZcX.js";
3
- import { h as getCurrentStateIndex, i as claimHookIndex, o as clearRenderTracking, p as getCurrentInstance } from "./component-scope-4I3yEMkb.js";
4
- import { n as createComponentInstance, s as renderScopedComponent, v as haveEquivalentContextFrames, x as rebaseVNodeTreeWithContextFrame } from "./component-internal-C4hKKQBF.js";
5
- import { d as shouldCoalesceFineGrainedItemReads, l as notifyReadableReaders, o as markReactivePropsDirtySource, s as markReadableDerivedSubscribersDirty, u as recordReadableRead } from "./readable-Di1fzSwm.js";
6
- import { i as unregisterOwnedChildScope, r as registerOwnedChildScope, t as cleanupComponent } from "./component-cleanup-jdbgjkT1.js";
7
- import { o as finalizeInlineReadSubscriptions, u as registerLifecycleTransaction } from "./lifecycle-batch-63aXFf2S.js";
8
- //#region src/runtime/child-scope.ts
7
+ //#region src/runtime/ownership/child-scope.ts
9
8
  const EMPTY_CHILD_SCOPE_PROPS = {};
10
9
  const childScopesByInstance = /* @__PURE__ */ new WeakMap();
11
10
  function executeChildScopeComponent() {
12
- const instance = getCurrentInstance();
11
+ const instance = getCurrentComponentInstance();
13
12
  const scope = instance ? childScopesByInstance.get(instance) : void 0;
14
13
  if (!scope?._renderFn) return null;
15
14
  return scope._renderFn();
@@ -19,12 +18,35 @@ function ensureChildScopeFlushTask(scope) {
19
18
  if (instance._pendingFlushTask) return;
20
19
  instance._pendingFlushTask = () => {
21
20
  instance.hasPendingUpdate = false;
22
- if (instance.notifyUpdate === null || scope._disposed) return;
23
- renderScope(scope);
24
- scope._onDirty?.();
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
+ }
25
44
  };
26
45
  }
27
46
  var ChildScopeImpl = class {
47
+ get [DIRECT_RANGE_OWNER]() {
48
+ return true;
49
+ }
28
50
  constructor(parent, key, onDirty, ownership) {
29
51
  this.previousVnode = void 0;
30
52
  this.vnode = void 0;
@@ -34,17 +56,18 @@ var ChildScopeImpl = class {
34
56
  this.hydrationPending = true;
35
57
  this.blueprintOwner = void 0;
36
58
  this._renderFn = void 0;
37
- this._disposed = false;
38
59
  this._renderedOwnerFrame = null;
39
60
  this.key = key;
40
- this._parent = parent;
61
+ this._parentOwnership = parent?.owner ?? null;
41
62
  this._onDirty = onDirty;
42
63
  this._ownership = ownership;
43
64
  this._startStateIndex = getCurrentStateIndex();
44
65
  this.componentInstance = createComponentInstance("child-scope", executeChildScopeComponent, EMPTY_CHILD_SCOPE_PROPS, null);
45
66
  childScopesByInstance.set(this.componentInstance, this);
67
+ this.componentInstance.owner.finalizer = this;
68
+ registerScopedOwnership(this, this.componentInstance.owner);
46
69
  if (parent) {
47
- this.componentInstance.parentInstance = parent;
70
+ adoptComponentParent(this.componentInstance, parent);
48
71
  this.componentInstance.ownerFrame = parent.ownerFrame;
49
72
  this.componentInstance.portalScope = parent.portalScope;
50
73
  if (ownership) ownership.add(this);
@@ -59,31 +82,38 @@ var ChildScopeImpl = class {
59
82
  return renderScope(this);
60
83
  }
61
84
  dispose() {
62
- if (this._disposed) return;
63
- this._disposed = true;
64
- if (this._parent) {
85
+ cleanupComponent(this.componentInstance);
86
+ }
87
+ release() {
88
+ try {
89
+ if (this._preparedTransaction) discardTransaction(this._preparedTransaction);
90
+ this._preparedTransaction = void 0;
65
91
  if (this._ownership) this._ownership.delete(this);
66
- else unregisterOwnedChildScope(this._parent, 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;
67
107
  }
68
- childScopesByInstance.delete(this.componentInstance);
69
- cleanupComponent(this.componentInstance);
70
- this._renderFn = void 0;
71
- this.previousVnode = void 0;
72
- this.vnode = void 0;
73
- this.dom = void 0;
74
- this.range = void 0;
75
- this.needsDomUpdate = false;
76
- this.hydrationPending = false;
77
- this.blueprintOwner = void 0;
78
- this.componentInstance.hasPendingUpdate = false;
79
108
  }
80
109
  };
81
110
  function renderScope(scope) {
82
- if (scope._disposed) {
111
+ if (scope.componentInstance.owner.disposed) {
83
112
  if (isDevelopmentEnvironment()) throw new Error(`[askr] Attempted to render disposed child scope ${String(scope.key)}.`);
84
113
  return scope.vnode;
85
114
  }
86
115
  if (!scope._renderFn) return scope.vnode;
116
+ joinChildScopePreparation(scope);
87
117
  const { componentInstance } = scope;
88
118
  const previousVNode = scope.vnode;
89
119
  try {
@@ -105,15 +135,23 @@ function renderScope(scope) {
105
135
  function rerenderChildScope(scope) {
106
136
  return renderScope(scope);
107
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
+ }
108
148
  /** @internal */
109
149
  function captureChildScopeTransactionSnapshot(scope) {
110
150
  const mutableScope = scope;
111
151
  return {
112
152
  previousVnode: scope.previousVnode,
113
153
  vnode: scope.vnode,
114
- dom: scope.dom,
115
- range: scope.range,
116
- domTextData: scope.dom?.nodeType === 3 ? scope.dom.data : void 0,
154
+ host: getRuntimeScopes().captureChildScopeHost(scope),
117
155
  needsDomUpdate: scope.needsDomUpdate,
118
156
  hydrationPending: scope.hydrationPending,
119
157
  renderFn: mutableScope._renderFn,
@@ -125,9 +163,7 @@ function restoreChildScopeTransactionSnapshot(scope, snapshot) {
125
163
  const mutableScope = scope;
126
164
  scope.previousVnode = snapshot.previousVnode;
127
165
  scope.vnode = snapshot.vnode;
128
- scope.dom = snapshot.dom;
129
- scope.range = snapshot.range;
130
- if (snapshot.domTextData !== void 0 && snapshot.dom?.nodeType === 3) snapshot.dom.data = snapshot.domTextData;
166
+ snapshot.host?.restore(scope);
131
167
  scope.needsDomUpdate = snapshot.needsDomUpdate;
132
168
  scope.hydrationPending = snapshot.hydrationPending;
133
169
  mutableScope._renderFn = snapshot.renderFn;
@@ -140,7 +176,7 @@ function createChildScope(parent, key, onDirty, ownership) {
140
176
  return new ChildScopeImpl(parent, key, onDirty, ownership);
141
177
  }
142
178
  //#endregion
143
- //#region src/runtime/control.ts
179
+ //#region src/runtime/control/branches.ts
144
180
  function setScopeContextFrame(scope, frame) {
145
181
  if (scope) scope.componentInstance.ownerFrame = frame;
146
182
  }
@@ -194,7 +230,13 @@ function beginControlTransaction(state) {
194
230
  registered: false
195
231
  };
196
232
  state._transaction = transaction;
197
- transaction.registered = registerLifecycleTransaction(transaction, () => commitControlTransaction(state, transaction), () => rollbackControlTransaction(state, 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
+ });
198
240
  return transaction;
199
241
  }
200
242
  function stageBranchRemoval(state, scope) {
@@ -202,31 +244,37 @@ function stageBranchRemoval(state, scope) {
202
244
  const transaction = state._transaction;
203
245
  if (transaction && !transaction.removedScopes.includes(scope)) transaction.removedScopes.push(scope);
204
246
  else if (!transaction) disposeChildScope(scope);
205
- const removedRange = getRuntimeRenderer().resolveChildScopeRange?.(scope) ?? scope.range;
247
+ const removedRange = getRuntimeEvaluation().resolveChildScopeRange?.(scope) ?? scope.range;
206
248
  const removedDom = removedRange?.single ? removedRange.start : scope.dom;
207
249
  if (removedDom) state.lastRemovedNodes.push(removedDom);
208
250
  if (removedRange) state.lastRemovedRanges.push(removedRange);
209
251
  }
210
- function commitControlTransaction(state, transaction) {
252
+ function publishControlTransaction(state, transaction) {
211
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;
212
266
  const errors = [];
213
267
  for (const scope of transaction.removedScopes) try {
214
268
  disposeChildScope(scope);
215
269
  } catch (error) {
216
270
  errors.push(error);
217
271
  }
218
- if (transaction.shouldClearDomUpdateState) {
219
- if ("truthyScope" in state && state.truthyScope) state.truthyScope.needsDomUpdate = false;
220
- if ("fallbackScope" in state && state.fallbackScope) state.fallbackScope.needsDomUpdate = false;
221
- if (state.activeScope) state.activeScope.needsDomUpdate = false;
222
- state.lastRemovedNodes = [];
223
- state.lastRemovedRanges = [];
224
- }
225
- state._transaction = null;
226
- if (errors.length > 0) throw new AggregateError(errors, "Control branch cleanup failed");
272
+ transaction.removedScopes.length = 0;
273
+ if (errors.length) throw new AggregateError(errors, "Control branch cleanup failed");
227
274
  }
228
275
  function rollbackControlTransaction(state, transaction) {
229
- if (state._transaction !== transaction) return;
276
+ if (state._transaction !== transaction && !transaction.published) return;
277
+ transaction.published = false;
230
278
  const committedScopes = new Set(transaction.snapshot.scopeSnapshots.keys());
231
279
  const currentScopes = getBranchScopes(state);
232
280
  const errors = [];
@@ -273,7 +321,7 @@ function createShowState(value, renderTruthy, renderFallback) {
273
321
  fallbackScope: null,
274
322
  lastRemovedNodes: [],
275
323
  lastRemovedRanges: [],
276
- parentInstance: getCurrentInstance(),
324
+ parentInstance: getCurrentComponentInstance(),
277
325
  _enqueueBoundaryCommit: null,
278
326
  _hasPendingBoundaryCommit: false,
279
327
  _transaction: null,
@@ -349,7 +397,7 @@ function createCaseState(matches, fallback) {
349
397
  lastRemovedNodes: [],
350
398
  lastRemovedRanges: [],
351
399
  matches,
352
- parentInstance: getCurrentInstance(),
400
+ parentInstance: getCurrentComponentInstance(),
353
401
  _enqueueBoundaryCommit: null,
354
402
  _hasPendingBoundaryCommit: false,
355
403
  _transaction: null
@@ -395,8 +443,9 @@ function clearCaseDomUpdateState(state) {
395
443
  state.lastRemovedNodes = [];
396
444
  state.lastRemovedRanges = [];
397
445
  }
446
+ const recordBenchEvent = (_event) => {};
398
447
  //#endregion
399
- //#region src/runtime/for-signals.ts
448
+ //#region src/runtime/control/for-signals.ts
400
449
  function peekForSignal() {
401
450
  return this._value;
402
451
  }
@@ -412,9 +461,10 @@ function setForIndexValue(newValue, notifyReaders = true) {
412
461
  if (notifyReaders) notifyForSignalReaders(this);
413
462
  }
414
463
  function notifyForSignalReaders(source, skipInstance, skipOwnedBy) {
415
- markReadableDerivedSubscribersDirty(source);
416
- markReactivePropsDirtySource(source);
417
- notifyReadableReaders(source, skipInstance, skipOwnedBy);
464
+ notifyReadableSource(source, {
465
+ skipInstance,
466
+ skipOwnedBy
467
+ });
418
468
  }
419
469
  function createForIndexSignal(initialIndex) {
420
470
  function readIndexSignal() {
@@ -626,29 +676,15 @@ const REACTIVE_FOR_ITEM_PROXY_HANDLER = {
626
676
  });
627
677
  }
628
678
  };
629
- const recordBenchEvent = (_event) => {};
630
679
  //#endregion
631
- //#region src/runtime/for-scopes.ts
632
- function resolveScopeBoundary(scope) {
633
- const range = getRuntimeRenderer().resolveChildScopeRange?.(scope) ?? scope.range;
634
- return {
635
- dom: range?.single ? range.start : scope.dom,
636
- range
637
- };
638
- }
680
+ //#region src/runtime/control/for-scopes.ts
639
681
  function recordRemovedBoundary(forState, dom, range) {
640
- if (range && !range.single) forState.lastRemovedRanges.push(range);
641
- else if (dom) forState.lastRemovedNodes.push(dom);
682
+ getRuntimeScopes().recordRemovedScopeBoundary(dom, range, forState.lastRemovedNodes, forState.lastRemovedRanges);
642
683
  }
643
- function captureRemovedScopeNodes(forState, dom, range) {
684
+ function prepareRemovedScope(forState, scope) {
644
685
  const transaction = forState._transaction;
645
- if (!transaction) return;
646
- const nodes = transaction.removedScopeNodes ??= [];
647
- if (range && !range.single) {
648
- nodes.push(range.start);
649
- for (let node = range.start.nextSibling; node && node !== range.end; node = node.nextSibling) nodes.push(node);
650
- nodes.push(range.end);
651
- } else if (dom) nodes.push(dom);
686
+ if (!transaction) return getRuntimeScopes().resolveScopeBoundary(scope);
687
+ return getRuntimeScopes().prepareScopeRemoval(scope, forState.lastRemovedNodes, forState.lastRemovedRanges, transaction.removedScopeNodes ??= []);
652
688
  }
653
689
  function enqueueForScopeUpdate(parent) {
654
690
  parent?._enqueueRun?.();
@@ -765,12 +801,10 @@ function renderItemScope(forState, scope, item, indexSignal, key) {
765
801
  return vnode;
766
802
  }
767
803
  function disposeItemInstance(forState, itemInstance, domCleanup) {
768
- const { dom: removedDom, range: removedRange } = resolveScopeBoundary(itemInstance.scope);
804
+ const { dom: removedDom, range: removedRange } = prepareRemovedScope(forState, itemInstance.scope);
769
805
  const transaction = forState._transaction;
770
806
  if (transaction) {
771
807
  (transaction.removedScopes ??= []).push(itemInstance.scope);
772
- captureRemovedScopeNodes(forState, removedDom, removedRange);
773
- recordRemovedBoundary(forState, removedDom, removedRange);
774
808
  return;
775
809
  }
776
810
  try {
@@ -779,9 +813,7 @@ function disposeItemInstance(forState, itemInstance, domCleanup) {
779
813
  if (isDevelopmentEnvironment()) console.error("[For] Cleanup error:", err);
780
814
  }
781
815
  if (!removedDom && !removedRange) return;
782
- if (removedDom instanceof Element) {
783
- if (domCleanup === "teardown") getRuntimeRenderer().teardownNodeSubtree(removedDom);
784
- }
816
+ if (domCleanup === "teardown") getRuntimeScopes().teardownScopeHost(removedDom, void 0);
785
817
  recordRemovedBoundary(forState, removedDom, removedRange);
786
818
  }
787
819
  function createItemInstance(key, item, index, forState) {
@@ -876,18 +908,14 @@ const FOR_FALLBACK_SCOPE_KEY = "__for-fallback__";
876
908
  function disposeFallbackScope(forState, domCleanup) {
877
909
  const fallbackScope = forState.fallbackScope;
878
910
  if (!fallbackScope) return;
879
- const { dom: removedDom, range: removedRange } = resolveScopeBoundary(fallbackScope);
911
+ const { dom: removedDom, range: removedRange } = prepareRemovedScope(forState, fallbackScope);
880
912
  const transaction = forState._transaction;
881
- if (transaction) {
882
- (transaction.removedScopes ??= []).push(fallbackScope);
883
- captureRemovedScopeNodes(forState, removedDom, removedRange);
884
- } else disposeChildScope(fallbackScope);
913
+ if (transaction) (transaction.removedScopes ??= []).push(fallbackScope);
914
+ else disposeChildScope(fallbackScope);
885
915
  forState.fallbackScope = null;
886
916
  if (!removedDom && !removedRange) return;
887
- if (removedDom instanceof Element) {
888
- if (domCleanup === "teardown") getRuntimeRenderer().teardownNodeSubtree(removedDom);
889
- }
890
- recordRemovedBoundary(forState, removedDom, removedRange);
917
+ if (domCleanup === "teardown") getRuntimeScopes().teardownScopeHost(removedDom, void 0);
918
+ if (!transaction) recordRemovedBoundary(forState, removedDom, removedRange);
891
919
  }
892
920
  function renderFallbackScope(forState) {
893
921
  if (forState.fallback == null || forState.fallback === false) {
@@ -913,12 +941,7 @@ function disposeAllItems(forState, domCleanup) {
913
941
  transaction.removeAllItems = true;
914
942
  for (let index = 0; index < forState.orderedItems.length; index++) {
915
943
  const scope = forState.orderedItems[index]?.scope;
916
- const { dom: removedDom, range } = scope ? resolveScopeBoundary(scope) : {
917
- dom: void 0,
918
- range: void 0
919
- };
920
- if (scope) captureRemovedScopeNodes(forState, removedDom, range);
921
- recordRemovedBoundary(forState, removedDom, range);
944
+ if (scope) prepareRemovedScope(forState, scope);
922
945
  }
923
946
  forState.items = /* @__PURE__ */ new Map();
924
947
  forState.orderedKeys = [];
@@ -935,345 +958,118 @@ function disposeAllItems(forState, domCleanup) {
935
958
  forState.orderedKeys = orderedKeys;
936
959
  }
937
960
  //#endregion
938
- //#region src/runtime/for-reconcile.ts
939
- function hasUnmountedComponentHost(node) {
940
- if (!node) return false;
941
- const host = node;
942
- if (host.__ASKR_INSTANCE?.mounted === false) return true;
943
- return host.__ASKR_INSTANCES?.some((instance) => !instance.mounted) ?? false;
944
- }
945
- function failForValidation(message) {
946
- throw new Error(message);
947
- }
948
- function validateForKeys(forState, newArray) {
949
- if (!isDevelopmentEnvironment()) return;
950
- const seen = /* @__PURE__ */ new Set();
951
- const keyKinds = /* @__PURE__ */ new Map();
952
- for (let i = 0; i < newArray.length; i++) {
953
- const key = forState.byFn(newArray[i], i);
954
- if (key === null || key === void 0) failForValidation("[askr] Invalid For key detected. Keys should be stable, non-null, and unique within a For list.");
955
- if (seen.has(key)) failForValidation(`[askr] Duplicate For key detected: ${String(key)}. Keys should be stable, non-null, and unique within a For list.`);
956
- seen.add(key);
957
- const keyKind = typeof key;
958
- const previousKeyKind = forState.devKeyKinds?.get(key);
959
- if (previousKeyKind && previousKeyKind !== keyKind) failForValidation(`[askr] For key type changed for ${String(key)}. Keys must remain consistently typed across renders.`);
960
- keyKinds.set(key, keyKind);
961
- }
962
- forState.devKeyKinds = keyKinds;
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;
963
979
  }
964
- function reconcileForItems(forState, newArray) {
965
- forState.currentItems = newArray;
966
- validateForKeys(forState, newArray);
967
- const { items, orderedKeys, byFn } = forState;
968
- const oldLen = orderedKeys.length;
969
- const newLen = newArray.length;
970
- forState.lastRemovedNodes = [];
971
- forState.lastRemovedRanges = [];
972
- forState.pendingRemovedKey = null;
973
- if (newLen === 0) {
974
- if (oldLen > 0) disposeAllItems(forState, forState.fallback ? "teardown" : "none");
975
- forState.lastCommitStrategy = "TRUNCATE";
976
- forState.pendingDirtyIndices = null;
977
- forState.pendingSwapIndices = null;
978
- forState.pendingMoveOnly = false;
979
- return renderFallbackScope(forState);
980
- }
981
- if (forState.fallbackScope) disposeFallbackScope(forState, "none");
982
- if (newLen === oldLen + 1) {
983
- let oldIndex = 0;
984
- let insertedIndex = -1;
985
- let insertedKey = null;
986
- for (let newIndex = 0; newIndex < newLen; newIndex++) {
987
- const item = newArray[newIndex];
988
- const key = byFn(item, newIndex);
989
- const expectedKey = orderedKeys[oldIndex];
990
- if (oldIndex < oldLen && key === expectedKey) {
991
- const existing = items.get(key);
992
- if (!existing || existing.item !== item || existing.scope.needsDomUpdate || oldIndex !== newIndex && existing.indexSignal._hasBeenRead) {
993
- insertedIndex = -2;
994
- break;
995
- }
996
- oldIndex++;
997
- } else if (insertedIndex === -1 && !items.has(key)) {
998
- insertedIndex = newIndex;
999
- insertedKey = key;
1000
- } else {
1001
- insertedIndex = -2;
1002
- break;
1003
- }
1004
- }
1005
- if (insertedIndex >= 0 && oldIndex === oldLen && insertedKey !== null) {
1006
- const insertedItem = createItemInstance(insertedKey, newArray[insertedIndex], insertedIndex, forState);
1007
- const resultVNodes = forState.orderedVNodes.slice();
1008
- const resultItems = forState.orderedItems.slice();
1009
- const resultKeys = orderedKeys.slice();
1010
- resultVNodes.splice(insertedIndex, 0, insertedItem.scope.vnode);
1011
- resultItems.splice(insertedIndex, 0, insertedItem);
1012
- resultKeys.splice(insertedIndex, 0, insertedKey);
1013
- items.set(insertedKey, insertedItem);
1014
- forState.lastCommitStrategy = "INSERT_ONE";
1015
- forState.orderedKeys = resultKeys;
1016
- forState.orderedItems = resultItems;
1017
- forState.orderedVNodes = resultVNodes;
1018
- forState.pendingDirtyIndices = null;
1019
- forState.pendingSwapIndices = null;
1020
- forState.pendingMoveOnly = false;
1021
- forState.pendingInsertedIndex = insertedIndex;
1022
- for (let index = insertedIndex; index < resultItems.length; index += 1) syncForItemIndex(forState, resultItems[index], index);
1023
- return resultVNodes;
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;
1024
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;
1025
1002
  }
1026
- if (oldLen < newLen) {
1027
- let canUseAppendPath = true;
1028
- let canSkipCommittedPrefix = true;
1029
- for (let i = 0; i < oldLen; i++) {
1030
- const key = byFn(newArray[i], i);
1031
- if (key !== orderedKeys[i]) {
1032
- canUseAppendPath = false;
1033
- break;
1034
- }
1035
- const existing = forState.orderedItems[i] ?? items.get(key);
1036
- if (!existing || existing.item !== newArray[i] || existing.scope.needsDomUpdate || existing.scope.hydrationPending) canSkipCommittedPrefix = false;
1037
- }
1038
- if (canUseAppendPath) {
1039
- forState.lastCommitStrategy = "APPEND";
1040
- const resultVNodes = forState.orderedVNodes;
1041
- const resultItems = forState.orderedItems;
1042
- resultVNodes.length = newLen;
1043
- resultItems.length = newLen;
1044
- if (!canSkipCommittedPrefix) for (let i = 0; i < oldLen; i++) {
1045
- const item = newArray[i];
1046
- const key = orderedKeys[i];
1047
- const existing = resultItems[i] ?? items.get(key);
1048
- updateItemInstance(forState, existing, item);
1049
- resultItems[i] = existing;
1050
- resultVNodes[i] = existing.scope.vnode;
1051
- }
1052
- for (let i = oldLen; i < newLen; i++) {
1053
- const item = newArray[i];
1054
- const key = byFn(item, i);
1055
- const itemInstance = createItemInstance(key, item, i, forState);
1056
- items.set(key, itemInstance);
1057
- resultItems[i] = itemInstance;
1058
- resultVNodes[i] = itemInstance.scope.vnode;
1059
- orderedKeys[i] = key;
1060
- }
1061
- forState.orderedVNodes = resultVNodes;
1062
- forState.pendingDirtyIndices = null;
1063
- forState.pendingSwapIndices = null;
1064
- forState.pendingMoveOnly = false;
1065
- forState.pendingAppendStart = canSkipCommittedPrefix ? oldLen : 0;
1066
- return resultVNodes;
1067
- }
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;
1068
1015
  }
1069
- if (newLen < oldLen) {
1070
- if (oldLen === newLen + 1) {
1071
- let removedIndex = -1;
1072
- for (let i = 0; i < newLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i]) {
1073
- removedIndex = i;
1074
- break;
1075
- }
1076
- if (removedIndex !== -1) {
1077
- let canUseRemoveOnePath = true;
1078
- for (let i = removedIndex; i < newLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i + 1]) {
1079
- canUseRemoveOnePath = false;
1080
- break;
1081
- }
1082
- if (canUseRemoveOnePath) {
1083
- forState.lastCommitStrategy = "REMOVE_ONE";
1084
- const resultVNodes = forState.orderedVNodes;
1085
- const resultItems = forState.orderedItems;
1086
- const removedKey = orderedKeys[removedIndex];
1087
- const removedItem = resultItems[removedIndex] ?? items.get(removedKey);
1088
- orderedKeys.copyWithin(removedIndex, removedIndex + 1);
1089
- resultItems.copyWithin(removedIndex, removedIndex + 1);
1090
- resultVNodes.copyWithin(removedIndex, removedIndex + 1);
1091
- orderedKeys.length = newLen;
1092
- resultItems.length = newLen;
1093
- resultVNodes.length = newLen;
1094
- const dirtyIndices = [];
1095
- for (let i = 0; i < newLen; i++) {
1096
- const item = newArray[i];
1097
- const existing = resultItems[i];
1098
- const scopeNeedsDomUpdate = existing.scope.needsDomUpdate;
1099
- const itemChanged = existing.item !== item;
1100
- const indexSignal = existing.indexSignal;
1101
- const indexChanged = i >= removedIndex && indexSignal.peek() !== i;
1102
- if (itemChanged) updateItemInstance(forState, existing, item);
1103
- const indexVisibleChange = indexChanged ? syncForItemIndex(forState, existing, i) : false;
1104
- if (itemChanged || indexVisibleChange || scopeNeedsDomUpdate) dirtyIndices.push(i);
1105
- resultVNodes[i] = existing.scope.vnode;
1106
- }
1107
- if (removedItem) {
1108
- disposeItemInstance(forState, removedItem, "teardown");
1109
- items.delete(removedKey);
1110
- }
1111
- forState.pendingRemovedKey = removedKey;
1112
- forState.pendingDirtyIndices = dirtyIndices;
1113
- forState.pendingSwapIndices = null;
1114
- forState.pendingMoveOnly = false;
1115
- return resultVNodes;
1116
- }
1117
- }
1118
- }
1119
- let canUseTruncatePath = true;
1120
- for (let i = 0; i < newLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i]) {
1121
- canUseTruncatePath = false;
1122
- break;
1123
- }
1124
- if (canUseTruncatePath) {
1125
- forState.lastCommitStrategy = "TRUNCATE";
1126
- const resultVNodes = forState.orderedVNodes;
1127
- const resultItems = forState.orderedItems;
1128
- resultVNodes.length = newLen;
1129
- resultItems.length = newLen;
1130
- const isFullClear = newLen === 0;
1131
- const dirtyIndices = [];
1132
- for (let i = 0; i < newLen; i++) {
1133
- const item = newArray[i];
1134
- const key = orderedKeys[i];
1135
- const existing = items.get(key);
1136
- const itemChanged = existing.item !== item;
1137
- const scopeNeedsDomUpdate = existing.scope.needsDomUpdate || hasUnmountedComponentHost(existing.scope.dom);
1138
- if (itemChanged) updateItemInstance(forState, existing, item);
1139
- if (itemChanged || scopeNeedsDomUpdate) dirtyIndices.push(i);
1140
- resultItems[i] = existing;
1141
- resultVNodes[i] = existing.scope.vnode;
1142
- }
1143
- for (let i = newLen; i < oldLen; i++) {
1144
- const key = orderedKeys[i];
1145
- const itemInstance = items.get(key);
1146
- if (itemInstance) {
1147
- disposeItemInstance(forState, itemInstance, isFullClear ? "full-clear" : "teardown");
1148
- items.delete(key);
1149
- }
1150
- }
1151
- orderedKeys.length = newLen;
1152
- forState.orderedKeys = orderedKeys;
1153
- forState.orderedItems.length = newLen;
1154
- forState.orderedVNodes = resultVNodes;
1155
- forState.pendingDirtyIndices = dirtyIndices;
1156
- forState.pendingSwapIndices = null;
1157
- forState.pendingMoveOnly = false;
1158
- return resultVNodes;
1159
- }
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;
1160
1024
  }
1161
- if (oldLen === newLen) {
1162
- let canUseNoReorderPath = true;
1163
- for (let i = 0; i < oldLen; i++) if (byFn(newArray[i], i) !== orderedKeys[i]) {
1164
- canUseNoReorderPath = false;
1165
- break;
1166
- }
1167
- if (canUseNoReorderPath) {
1168
- forState.lastCommitStrategy = "NO_REORDER";
1169
- const resultVNodes = forState.orderedVNodes;
1170
- const resultItems = forState.orderedItems;
1171
- resultVNodes.length = oldLen;
1172
- resultItems.length = oldLen;
1173
- const dirtyIndices = [];
1174
- for (let i = 0; i < oldLen; i++) {
1175
- const item = newArray[i];
1176
- const key = orderedKeys[i];
1177
- const existing = items.get(key);
1178
- if (existing.item !== item) updateItemInstance(forState, existing, item);
1179
- if (existing.scope.needsDomUpdate) dirtyIndices.push(i);
1180
- resultItems[i] = existing;
1181
- resultVNodes[i] = existing.scope.vnode;
1182
- }
1183
- forState.pendingDirtyIndices = dirtyIndices;
1184
- forState.pendingSwapIndices = null;
1185
- forState.pendingMoveOnly = false;
1186
- return resultVNodes;
1187
- }
1188
- let firstMismatch = -1;
1189
- let secondMismatch = -1;
1190
- let firstMismatchKey = null;
1191
- let secondMismatchKey = null;
1192
- let mismatchCount = 0;
1193
- let canUseSwapPath = true;
1194
- for (let i = 0; i < oldLen; i++) {
1195
- const item = newArray[i];
1196
- const key = byFn(newArray[i], i);
1197
- if (key === orderedKeys[i]) {
1198
- const existing = items.get(key);
1199
- if (existing && (existing.item !== item || existing.scope.needsDomUpdate)) {
1200
- canUseSwapPath = false;
1201
- break;
1202
- }
1203
- continue;
1204
- }
1205
- mismatchCount++;
1206
- if (firstMismatch === -1) {
1207
- firstMismatch = i;
1208
- firstMismatchKey = key;
1209
- continue;
1210
- }
1211
- if (secondMismatch === -1) {
1212
- secondMismatch = i;
1213
- secondMismatchKey = key;
1214
- continue;
1215
- }
1216
- mismatchCount = 3;
1217
- break;
1218
- }
1219
- if (canUseSwapPath && mismatchCount === 2 && firstMismatch !== -1 && secondMismatch !== -1 && firstMismatchKey === orderedKeys[secondMismatch] && secondMismatchKey === orderedKeys[firstMismatch]) {
1220
- forState.lastCommitStrategy = "SWAP";
1221
- const nextOrderedKeys = orderedKeys.slice();
1222
- nextOrderedKeys[firstMismatch] = firstMismatchKey;
1223
- nextOrderedKeys[secondMismatch] = secondMismatchKey;
1224
- const resultVNodes = forState.orderedVNodes;
1225
- const firstExisting = items.get(firstMismatchKey);
1226
- const secondExisting = items.get(secondMismatchKey);
1227
- const firstItem = newArray[firstMismatch];
1228
- const secondItem = newArray[secondMismatch];
1229
- const nextOrderedItems = forState.orderedItems.slice();
1230
- nextOrderedItems[firstMismatch] = firstExisting;
1231
- nextOrderedItems[secondMismatch] = secondExisting;
1232
- if (firstExisting.item !== firstItem) updateItemInstance(forState, firstExisting, firstItem);
1233
- if (secondExisting.item !== secondItem) updateItemInstance(forState, secondExisting, secondItem);
1234
- syncForItemIndex(forState, firstExisting, firstMismatch);
1235
- syncForItemIndex(forState, secondExisting, secondMismatch);
1236
- resultVNodes[firstMismatch] = firstExisting.scope.vnode;
1237
- resultVNodes[secondMismatch] = secondExisting.scope.vnode;
1238
- forState.orderedKeys = nextOrderedKeys;
1239
- forState.orderedItems = nextOrderedItems;
1240
- forState.pendingDirtyIndices = null;
1241
- forState.pendingSwapIndices = [firstMismatch, secondMismatch];
1242
- forState.pendingMoveOnly = true;
1243
- return resultVNodes;
1244
- }
1245
- let canUseMoveOnlyPath = true;
1246
- const moveOnlyKeys = [];
1247
- const moveOnlyItems = [];
1248
- const moveOnlyVNodes = [];
1249
- for (let i = 0; i < oldLen; i++) {
1250
- const item = newArray[i];
1251
- const key = byFn(item, i);
1252
- const existing = items.get(key);
1253
- if (!existing || existing.item !== item || existing.indexSignal._hasBeenRead && existing.indexSignal.peek() !== i) {
1254
- canUseMoveOnlyPath = false;
1255
- break;
1256
- }
1257
- moveOnlyKeys[i] = key;
1258
- moveOnlyItems[i] = existing;
1259
- moveOnlyVNodes[i] = existing.scope.vnode;
1260
- }
1261
- if (canUseMoveOnlyPath) {
1262
- forState.lastCommitStrategy = "FULL_KEYED";
1263
- for (let i = 0; i < moveOnlyItems.length; i++) {
1264
- syncForItemIndex(forState, moveOnlyItems[i], i);
1265
- moveOnlyVNodes[i] = moveOnlyItems[i].scope.vnode;
1266
- }
1267
- forState.orderedKeys = moveOnlyKeys;
1268
- forState.orderedItems = moveOnlyItems;
1269
- forState.orderedVNodes = moveOnlyVNodes;
1270
- forState.pendingDirtyIndices = null;
1271
- forState.pendingSwapIndices = null;
1272
- forState.pendingMoveOnly = true;
1273
- return moveOnlyVNodes;
1274
- }
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;
1275
1054
  }
1276
- forState.lastCommitStrategy = "FULL_KEYED";
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) {
1277
1073
  const toRemove = new Set(orderedKeys);
1278
1074
  const newOrderedKeys = [];
1279
1075
  const newOrderedItems = [];
@@ -1313,22 +1109,327 @@ function reconcileForItems(forState, newArray) {
1313
1109
  forState.orderedKeys = newOrderedKeys;
1314
1110
  forState.orderedItems = newOrderedItems;
1315
1111
  forState.orderedVNodes = resultVNodes;
1316
- forState.pendingDirtyIndices = null;
1317
- forState.pendingSwapIndices = null;
1318
- forState.pendingMoveOnly = moveOnly;
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);
1319
1311
  return resultVNodes;
1320
1312
  }
1321
1313
  //#endregion
1322
- //#region src/runtime/for-internal.ts
1314
+ //#region src/runtime/control/for-paths/truncate.ts
1323
1315
  /**
1324
- * For primitive runtime
1316
+ * The tail dropped, the surviving prefix keeping its keys and positions.
1325
1317
  *
1326
- * Manages For state storage, hook binding, source evaluation,
1327
- * and DOM update state cleanup.
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`.
1328
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
1329
1430
  const forStates = /* @__PURE__ */ new WeakMap();
1330
1431
  function getForStore(instance) {
1331
- const generation = instance._ownershipGeneration;
1432
+ const generation = instance.owner.identity;
1332
1433
  let store = forStates.get(generation);
1333
1434
  if (!store) {
1334
1435
  store = /* @__PURE__ */ new Map();
@@ -1337,36 +1438,25 @@ function getForStore(instance) {
1337
1438
  return store;
1338
1439
  }
1339
1440
  function createForState(eachSource, byFn, renderFn, fallback) {
1340
- const parentInstance = getCurrentInstance();
1341
- const ownedScopes = /* @__PURE__ */ new Set();
1342
- let bulkDisposing = false;
1441
+ const parentInstance = getCurrentComponentInstance();
1442
+ const scopeOwner = new OwnershipRecord();
1343
1443
  const scopeOwnership = {
1344
- add: (scope) => ownedScopes.add(scope),
1345
- delete: (scope) => bulkDisposing ? false : ownedScopes.delete(scope),
1444
+ add: (scope) => ownChild(scopeOwner, scope),
1445
+ delete: (scope) => releaseOwnedChild(scopeOwner, scope),
1346
1446
  bulkDispose(run) {
1347
- bulkDisposing = true;
1348
- try {
1349
- run();
1350
- } finally {
1351
- bulkDisposing = false;
1352
- ownedScopes.clear();
1353
- }
1447
+ detachOwnedChildren(scopeOwner);
1448
+ run();
1354
1449
  }
1355
1450
  };
1356
- if (parentInstance) registerOwnedChildScope(parentInstance, {
1357
- key: "for-boundary",
1358
- dispose() {
1359
- scopeOwnership.bulkDispose(() => {
1360
- const errors = [];
1361
- for (const scope of ownedScopes) try {
1362
- scope.dispose();
1363
- } catch (error) {
1364
- errors.push(error);
1365
- }
1366
- if (errors.length > 0) throw new AggregateError(errors, "For scope cleanup failed");
1367
- });
1368
- }
1369
- });
1451
+ if (parentInstance) {
1452
+ registerScopedOwnership({
1453
+ key: "for-boundary",
1454
+ dispose() {
1455
+ disposeOwnership(scopeOwner);
1456
+ }
1457
+ }, scopeOwner);
1458
+ attachOwnership(scopeOwner, parentInstance.owner);
1459
+ }
1370
1460
  return {
1371
1461
  kind: "for",
1372
1462
  _contextFrame: null,
@@ -1403,10 +1493,10 @@ function createForState(eachSource, byFn, renderFn, fallback) {
1403
1493
  };
1404
1494
  }
1405
1495
  function useForState(eachSource, byFn, renderFn, fallback) {
1406
- const instance = getCurrentInstance();
1496
+ const instance = getCurrentComponentInstance();
1407
1497
  if (!instance) throw new Error("For can only be created during component render execution.");
1408
1498
  const hookIndex = claimHookIndex(instance, "For");
1409
- const generation = instance._ownershipGeneration;
1499
+ const generation = instance.owner.identity;
1410
1500
  const store = getForStore(instance);
1411
1501
  const existing = store.get(hookIndex);
1412
1502
  if (existing) {
@@ -1418,11 +1508,14 @@ function useForState(eachSource, byFn, renderFn, fallback) {
1418
1508
  }
1419
1509
  const created = createForState(eachSource, byFn, renderFn, fallback);
1420
1510
  store.set(hookIndex, created);
1421
- (instance.cleanupFns ??= []).push(() => {
1422
- created._sourceEffect?.cleanup();
1423
- created._sourceEffect = null;
1424
- store.delete(hookIndex);
1425
- if (store.size === 0 && forStates.get(generation) === store) forStates.delete(generation);
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
+ }
1426
1519
  });
1427
1520
  return created;
1428
1521
  }
@@ -1484,7 +1577,13 @@ function beginForStateTransaction(forState, collectionMode = "auto") {
1484
1577
  }
1485
1578
  function registerForStateTransaction(forState, transaction = forState._transaction) {
1486
1579
  if (!transaction || forState._transaction !== transaction) return false;
1487
- return registerLifecycleTransaction(transaction, () => commitForStateTransaction(forState, transaction), () => rollbackForStateTransaction(forState, transaction));
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
+ });
1488
1587
  }
1489
1588
  function finalizeForStateRemovals(forState, transaction) {
1490
1589
  const removedScopes = transaction.removedScopes;
@@ -1499,20 +1598,7 @@ function finalizeForStateRemovals(forState, transaction) {
1499
1598
  cleanupErrors.push(error);
1500
1599
  }
1501
1600
  if (transaction.removedScopeNodes) return;
1502
- if (typeof Element !== "undefined" && removedDom instanceof Element) try {
1503
- getRuntimeRenderer().teardownNodeSubtree(removedDom);
1504
- } catch (error) {
1505
- cleanupErrors.push(error);
1506
- }
1507
- if (removedRange && !removedRange.single) for (let node = removedRange.start.nextSibling; node && node !== removedRange.end;) {
1508
- const next = node.nextSibling;
1509
- try {
1510
- getRuntimeRenderer().teardownNodeSubtree(node);
1511
- } catch (error) {
1512
- cleanupErrors.push(error);
1513
- }
1514
- node = next;
1515
- }
1601
+ getRuntimeScopes().teardownScopeHost(removedDom, removedRange, (error) => cleanupErrors.push(error));
1516
1602
  };
1517
1603
  if (transaction.removeAllItems) forState._scopeOwnership.bulkDispose(() => {
1518
1604
  for (let index = 0; index < transaction.orderedItems.length; index++) {
@@ -1523,7 +1609,7 @@ function finalizeForStateRemovals(forState, transaction) {
1523
1609
  for (const scope of removedScopes ?? []) finalizeScope(scope);
1524
1610
  const removedScopeNodes = transaction.removedScopeNodes;
1525
1611
  if (removedScopeNodes) for (const node of removedScopeNodes) try {
1526
- getRuntimeRenderer().teardownNodeSubtree(node);
1612
+ getRuntimeCleanup().teardownNodeSubtree(node);
1527
1613
  } catch (error) {
1528
1614
  cleanupErrors.push(error);
1529
1615
  }
@@ -1547,22 +1633,40 @@ function finalizeForDomUpdateFlags(forState) {
1547
1633
  }
1548
1634
  if (forState.fallbackScope) forState.fallbackScope.needsDomUpdate = false;
1549
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
+ }
1550
1643
  function commitForStateTransaction(forState, transaction = forState._transaction) {
1551
- if (!transaction || forState._transaction !== transaction) return;
1644
+ if (!transaction) return;
1645
+ if (!transaction.published) publishForStateTransaction(forState, transaction);
1646
+ if (!transaction.published) return;
1647
+ transaction.published = false;
1648
+ const errors = [];
1552
1649
  try {
1553
- finalizeForStateRemovals(forState, transaction);
1554
- finalizeForSignalEffects(transaction);
1555
- if (transaction.shouldClearDomUpdateState) finalizeForDomUpdateFlags(forState);
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
+ }
1556
1660
  } finally {
1557
1661
  transaction.itemSnapshots?.clear();
1558
1662
  transaction.unreadIndexSnapshots?.clear();
1559
1663
  transaction.fallbackScopeSnapshot = null;
1560
- forState._committedItems = forState.currentItems;
1561
- forState._transaction = null;
1562
1664
  }
1665
+ if (errors.length) throw new AggregateError(errors, "For settlement failed");
1563
1666
  }
1564
1667
  function rollbackForStateTransaction(forState, transaction = forState._transaction) {
1565
- if (!transaction || forState._transaction !== transaction) return;
1668
+ if (!transaction || forState._transaction !== transaction && !transaction.published) return;
1669
+ transaction.published = false;
1566
1670
  const rollbackCleanupErrors = [];
1567
1671
  const scopesToDispose = /* @__PURE__ */ new Set();
1568
1672
  const committedScopes = transaction.collectionSnapshotMode === "reset-empty" ? null : new Set(transaction.orderedItems.map((item) => item.scope));
@@ -1646,4 +1750,4 @@ function clearForDomUpdateState(forState) {
1646
1750
  forState._hasResolvedItemDom = forState.orderedKeys.length > 0;
1647
1751
  }
1648
1752
  //#endregion
1649
- export { setControlBoundaryContextFrame as _, registerForStateTransaction as a, rerenderChildScope 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, disposeChildScope as y };
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 };