@askrjs/askr 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/access-CEA2pOry.js +1046 -0
- package/dist/actions/index.d.ts +16 -2
- package/dist/actions/index.js +5 -5
- package/dist/{activity-FirwPXA_.js → activity-oy2YFTFF.js} +10 -16
- package/dist/benchmark.js +8 -9
- package/dist/boot/index.d.ts +19 -9
- package/dist/boot/index.js +1 -1
- package/dist/{boot-tWyF6121.js → boot-BMBMWUGI.js} +680 -441
- package/dist/capabilities-Bbf0mlp9.js +42 -0
- package/dist/components/index.d.ts +11 -8
- package/dist/components/index.js +1 -1
- package/dist/{compose-ref-Bfaf4kUC.js → compose-ref-v0qGlHoN.js} +7 -1
- package/dist/control/index.d.ts +20 -2
- package/dist/control/index.js +1 -1
- package/dist/{control-C-wSaq9V.js → control-BR_mrX__.js} +4 -4
- package/dist/core.d.ts +163 -0
- package/dist/csp-nonce-BfFWcd0w.js +173 -0
- package/dist/data/index.d.ts +74 -2
- package/dist/data/index.js +3 -3
- package/dist/{data-ghKopAbp.js → data-2edW0jhF.js} +108 -122
- package/dist/{data-runtime-7t_Y0iv3.js → data-runtime-CxoY98lX.js} +22 -15
- package/dist/{deferred-CxjWCkIn.js → deferred-CbgNhf67.js} +5 -5
- package/dist/dom-renderer.d.ts +77 -0
- package/dist/domains/actions.d.ts +70 -0
- package/dist/domains/component.d.ts +119 -0
- package/dist/domains/context.d.ts +73 -0
- package/dist/domains/control.d.ts +328 -0
- package/dist/domains/data.d.ts +461 -0
- package/dist/domains/diagnostics.d.ts +21 -0
- package/dist/domains/lifecycle.d.ts +112 -0
- package/dist/domains/refs.d.ts +18 -0
- package/dist/domains/renderer.d.ts +127 -0
- package/dist/domains/routing.d.ts +501 -0
- package/dist/domains/scheduler.d.ts +79 -0
- package/dist/domains/server.d.ts +112 -0
- package/dist/domains/state.d.ts +129 -0
- package/dist/domains/telemetry.d.ts +29 -0
- package/dist/eager-control.d.ts +8 -0
- package/dist/{effect-CNwstBBD.js → effect-C3Zsc1k6.js} +14 -41
- package/dist/{types-DWVrKn9N.d.ts → elements.d.ts} +79 -42
- package/dist/{for-internal-DyBHfKJA.js → for-state-BDykeOJL.js} +598 -494
- package/dist/foundations/icon/index.d.ts +67 -16
- package/dist/foundations/icon/index.js +1 -1
- package/dist/foundations/index.d.ts +26 -3
- package/dist/foundations/index.js +1 -1
- package/dist/foundations/interactions/index.d.ts +73 -34
- package/dist/foundations/interactions/index.js +1 -1
- package/dist/foundations/state/index.d.ts +12 -5
- package/dist/foundations/state/index.js +1 -1
- package/dist/foundations/structures/index.d.ts +44 -3
- package/dist/foundations/structures/index.js +1 -1
- package/dist/foundations/utilities/index.d.ts +34 -3
- package/dist/foundations/utilities/index.js +1 -1
- package/dist/fx/index.d.ts +72 -25
- package/dist/fx/index.js +8 -8
- package/dist/index.d.ts +121 -4
- package/dist/index.js +316 -47
- package/dist/{component-internal-C4hKKQBF.js → instance-VAFYVJOa.js} +495 -283
- package/dist/{interactions-D102JxBR.js → interactions-CTeACdT_.js} +1 -1
- package/dist/jsx-dev-runtime.d.ts +51 -11
- package/dist/jsx-globals.d.ts +2 -0
- package/dist/jsx-runtime-CPJXAOBF.js +43 -0
- package/dist/jsx-runtime.d.ts +17 -3
- package/dist/jsx-runtime.js +2 -42
- package/dist/jsx.d.ts +108 -0
- package/dist/{manifest-D6rfj_jC.js → manifest-D1P3UNWV.js} +4 -9
- package/dist/{navigate-ZZu1IV0B.js → navigate-prC5V8XV.js} +125 -472
- package/dist/{navigate-F4sHgWbw.d.ts → navigation.d.ts} +8 -8
- package/dist/{readable-Di1fzSwm.js → notify-DxxuDPeY.js} +96 -34
- package/dist/{query-registry-Bua3cDyb.js → query-registry-LrYpQsDJ.js} +1 -1
- package/dist/{compose-ref-DOJHoW5X.d.ts → refs.d.ts} +11 -7
- package/dist/{ssr-Doog-AfJ.js → render-resolved-BC0W7_5b.js} +165 -558
- package/dist/{renderer-Cl23O0hV.js → renderer-CT0HeY58.js} +6825 -5692
- package/dist/{resolution-ClD-K7Lz.js → resolution-3DskUkjG.js} +189 -180
- package/dist/{resource-operation-Vz1S5h2k.js → resource-18-sFRl9.js} +98 -58
- package/dist/resources/index.d.ts +64 -12
- package/dist/resources/index.js +214 -8
- package/dist/route-activity.d.ts +21 -0
- package/dist/{route-matching-Bo6UqG-5.js → route-matching-CUzZ31gT.js} +68 -82
- package/dist/router/index.d.ts +378 -79
- package/dist/router/index.js +9 -9
- package/dist/router-internal-7nuNEHfG.js +36 -0
- package/dist/scope-Cq_iYbTR.js +403 -0
- package/dist/{selector-CsKuomw0.js → selector-BSPVkjKP.js} +26 -27
- package/dist/{shared-CYBH3F8I.js → shared-kU8yvryp.js} +3 -6
- package/dist/{snapshot-source-BB42xgwb.js → snapshot-source-An4iKajG.js} +1 -1
- package/dist/ssg/index.d.ts +51 -15
- package/dist/ssg/index.js +269 -209
- package/dist/ssr/index.d.ts +121 -68
- package/dist/ssr/index.js +2 -1
- package/dist/ssr-CiNm6Vzl.js +393 -0
- package/dist/{ssr-DSHd_Q9K.js → ssr-EPjwJH5R.js} +5 -1
- package/dist/{state-BGJgYSyQ.js → state-BXJfudq1.js} +10 -15
- package/dist/{structures-DFyK5AdQ.js → structures-CjEzfj4h.js} +37 -57
- package/dist/{index-CTpMmzgN.d.ts → structures.d.ts} +57 -36
- package/dist/testing/index.d.ts +123 -24
- package/dist/testing/index.js +24 -61
- package/dist/timer-C7uqnJVt.js +85 -0
- package/dist/{index-B1gu0_m0.d.ts → utilities.d.ts} +24 -13
- package/dist/{verify-hydration-BZPJ_kYa.js → verify-hydration-ikaxotf7.js} +8 -5
- package/package.json +12 -14
- package/dist/access-BucjYZcX.js +0 -509
- package/dist/activity-DooIuxQO.d.ts +0 -14
- package/dist/benchmark.d.ts +0 -26
- package/dist/cleanup-TXSsApEl.js +0 -535
- package/dist/component-cleanup-jdbgjkT1.js +0 -143
- package/dist/component-scope-4I3yEMkb.js +0 -195
- package/dist/control-Cxag1yqV.d.ts +0 -8
- package/dist/csp-nonce-9NFUb7hJ.js +0 -72
- package/dist/css-BuPaTOfe.js +0 -70
- package/dist/fastlane-BKZduiBQ.js +0 -166
- package/dist/index-Dgjbo2gU.d.ts +0 -1456
- package/dist/jsx-runtime-Cg7GqY1S.d.ts +0 -2
- package/dist/jsx-runtime-gVIaTPw0.d.ts +0 -38
- package/dist/lifecycle-batch-63aXFf2S.js +0 -253
- 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
|
-
|
|
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 =
|
|
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 ||
|
|
23
|
-
|
|
24
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
219
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
641
|
-
else if (dom) forState.lastRemovedNodes.push(dom);
|
|
682
|
+
getRuntimeScopes().recordRemovedScopeBoundary(dom, range, forState.lastRemovedNodes, forState.lastRemovedRanges);
|
|
642
683
|
}
|
|
643
|
-
function
|
|
684
|
+
function prepareRemovedScope(forState, scope) {
|
|
644
685
|
const transaction = forState._transaction;
|
|
645
|
-
if (!transaction) return;
|
|
646
|
-
|
|
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 } =
|
|
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
|
|
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 } =
|
|
911
|
+
const { dom: removedDom, range: removedRange } = prepareRemovedScope(forState, fallbackScope);
|
|
880
912
|
const transaction = forState._transaction;
|
|
881
|
-
if (transaction)
|
|
882
|
-
|
|
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
|
|
888
|
-
|
|
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
|
-
|
|
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-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
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
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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 (
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
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
|
-
|
|
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
|
|
1317
|
-
|
|
1318
|
-
|
|
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-
|
|
1314
|
+
//#region src/runtime/control/for-paths/truncate.ts
|
|
1323
1315
|
/**
|
|
1324
|
-
*
|
|
1316
|
+
* The tail dropped, the surviving prefix keeping its keys and positions.
|
|
1325
1317
|
*
|
|
1326
|
-
*
|
|
1327
|
-
* and
|
|
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.
|
|
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 =
|
|
1341
|
-
const
|
|
1342
|
-
let bulkDisposing = false;
|
|
1441
|
+
const parentInstance = getCurrentComponentInstance();
|
|
1442
|
+
const scopeOwner = new OwnershipRecord();
|
|
1343
1443
|
const scopeOwnership = {
|
|
1344
|
-
add: (scope) =>
|
|
1345
|
-
delete: (scope) =>
|
|
1444
|
+
add: (scope) => ownChild(scopeOwner, scope),
|
|
1445
|
+
delete: (scope) => releaseOwnedChild(scopeOwner, scope),
|
|
1346
1446
|
bulkDispose(run) {
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
run();
|
|
1350
|
-
} finally {
|
|
1351
|
-
bulkDisposing = false;
|
|
1352
|
-
ownedScopes.clear();
|
|
1353
|
-
}
|
|
1447
|
+
detachOwnedChildren(scopeOwner);
|
|
1448
|
+
run();
|
|
1354
1449
|
}
|
|
1355
1450
|
};
|
|
1356
|
-
if (parentInstance)
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
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,
|
|
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 };
|