@solidjs/signals 2.0.0-beta.20 → 2.0.0-beta.22
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/README.md +5 -1
- package/dist/dev.js +267 -307
- package/dist/node.cjs +1125 -1168
- package/dist/prod/affects.js +71 -163
- package/dist/prod/boundaries.js +141 -137
- package/dist/prod/core/action.js +50 -12
- package/dist/prod/core/async.js +83 -99
- package/dist/prod/core/core.js +255 -298
- package/dist/prod/core/effect.js +46 -46
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +54 -46
- package/dist/prod/core/heap.js +58 -50
- package/dist/prod/core/lanes.js +34 -34
- package/dist/prod/core/optimistic.js +64 -106
- package/dist/prod/core/owner.js +52 -52
- package/dist/prod/core/scheduler.js +217 -211
- package/dist/prod/core/verdict.js +144 -78
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +23 -5
- package/dist/prod/store/optimistic.js +11 -11
- package/dist/prod/store/projection.js +2 -2
- package/dist/prod/store/store.js +14 -14
- package/dist/types/affects.d.ts +9 -9
- package/dist/types/core/action.d.ts +16 -0
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/error.d.ts +7 -0
- package/dist/types/core/scheduler.d.ts +1 -6
- package/dist/types/core/types.d.ts +6 -11
- package/dist/types-cjs/affects.d.cts +9 -9
- package/dist/types-cjs/core/action.d.cts +16 -0
- package/dist/types-cjs/core/async.d.cts +1 -1
- package/dist/types-cjs/core/error.d.cts +7 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -6
- package/dist/types-cjs/core/types.d.cts +6 -11
- package/package.json +1 -1
package/dist/prod/core/lanes.js
CHANGED
|
@@ -18,15 +18,15 @@ const activeLanes = new Set;
|
|
|
18
18
|
}
|
|
19
19
|
// Detect parent lane: _parentSource chains from pendingSignal → pendingValueComputed → original.
|
|
20
20
|
// The child lane should not merge with the parent lane.
|
|
21
|
-
const i = n.
|
|
22
|
-
const r = i?.
|
|
21
|
+
const i = n.nn;
|
|
22
|
+
const r = i?.je ? findLane(i.je) : null;
|
|
23
23
|
e = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
en: n,
|
|
25
|
+
de: new Set,
|
|
26
|
+
rn: [ [], [] ],
|
|
27
|
+
tn: null,
|
|
28
|
+
Ue: activeTransition,
|
|
29
|
+
an: r
|
|
30
30
|
};
|
|
31
31
|
signalLanes.set(n, e);
|
|
32
32
|
activeLanes.add(e);
|
|
@@ -36,8 +36,8 @@ const activeLanes = new Set;
|
|
|
36
36
|
// parent-child is a property of the nodes, not of write order — otherwise
|
|
37
37
|
// the owner's write merges the companion's subscribers into this lane and
|
|
38
38
|
// their effects wait on its async instead of flushing immediately.
|
|
39
|
-
adoptCompanionLane(n.
|
|
40
|
-
adoptCompanionLane(n.
|
|
39
|
+
adoptCompanionLane(n.ge, e);
|
|
40
|
+
adoptCompanionLane(n.he, e);
|
|
41
41
|
return e;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -48,13 +48,13 @@ function adoptCompanionLane(n, e) {
|
|
|
48
48
|
const r = findLane(i);
|
|
49
49
|
// Only the companion's own unmerged root is safely re-parentable: a root
|
|
50
50
|
// that absorbed other lanes carries work that is not a child of this owner.
|
|
51
|
-
if (r !== e && r.
|
|
51
|
+
if (r !== e && r.en === n && !r.an) r.an = e;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Union-find: find the root lane.
|
|
56
56
|
*/ function findLane(n) {
|
|
57
|
-
while (n.
|
|
57
|
+
while (n.tn) n = n.tn;
|
|
58
58
|
return n;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -64,27 +64,27 @@ function adoptCompanionLane(n, e) {
|
|
|
64
64
|
n = findLane(n);
|
|
65
65
|
e = findLane(e);
|
|
66
66
|
if (n === e) return n;
|
|
67
|
-
e.
|
|
67
|
+
e.tn = n;
|
|
68
68
|
// Move (not copy) the merged lane's work: after the merge all routing goes
|
|
69
69
|
// through findLane() to the root, so anything left behind here is dead —
|
|
70
70
|
// and anything *added* here later is a routing bug (INV-5).
|
|
71
|
-
for (const i of e.
|
|
72
|
-
e.
|
|
73
|
-
n.
|
|
74
|
-
n.
|
|
75
|
-
e.
|
|
76
|
-
e.
|
|
71
|
+
for (const i of e.de) n.de.add(i);
|
|
72
|
+
e.de.clear();
|
|
73
|
+
n.rn[0].push(...e.rn[0]);
|
|
74
|
+
n.rn[1].push(...e.rn[1]);
|
|
75
|
+
e.rn[0].length = 0;
|
|
76
|
+
e.rn[1].length = 0;
|
|
77
77
|
return n;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
81
|
* Resolve a node's lane: follow union-find chain, verify active, clear if stale.
|
|
82
82
|
*/ function resolveLane(n) {
|
|
83
|
-
const e = n.
|
|
83
|
+
const e = n.je;
|
|
84
84
|
if (!e) return undefined;
|
|
85
85
|
const i = findLane(e);
|
|
86
86
|
if (activeLanes.has(i)) return i;
|
|
87
|
-
n.
|
|
87
|
+
n.je = undefined;
|
|
88
88
|
return undefined;
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -94,18 +94,18 @@ function resolveTransition(n) {
|
|
|
94
94
|
// transactions (#2912) — the merged root's _transition would hand this
|
|
95
95
|
// node's override to whichever action wrote last through the shared
|
|
96
96
|
// reader. Chase merge chains; a dead owner settled through another path.
|
|
97
|
-
if (hasActiveOverride(n) && n.
|
|
98
|
-
const e = n.
|
|
99
|
-
if (e.
|
|
100
|
-
n.
|
|
97
|
+
if (hasActiveOverride(n) && n.sn) {
|
|
98
|
+
const e = n.sn = currentTransition(n.sn);
|
|
99
|
+
if (e.fn !== true) return e;
|
|
100
|
+
n.sn = null;
|
|
101
101
|
}
|
|
102
|
-
return resolveLane(n)?.
|
|
102
|
+
return resolveLane(n)?.Ue ?? n.Ue;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Check if a node has an active optimistic override.
|
|
107
107
|
*/ function hasActiveOverride(n) {
|
|
108
|
-
return !!(n.
|
|
108
|
+
return !!(n.Ee !== undefined && n.Ee !== NOT_PENDING);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
/**
|
|
@@ -113,13 +113,13 @@ function resolveTransition(n) {
|
|
|
113
113
|
* a different active lane), merge unless the node has an active override.
|
|
114
114
|
*/ function assignOrMergeLane(n, e) {
|
|
115
115
|
const i = findLane(e);
|
|
116
|
-
const r = n.
|
|
116
|
+
const r = n.je;
|
|
117
117
|
if (r) {
|
|
118
118
|
// If the subscriber's lane was merged into another lane, it's stale —
|
|
119
119
|
// replace it with the new source lane instead of following the merge chain
|
|
120
120
|
// (which would incorrectly merge the new lane into the old group)
|
|
121
|
-
if (r.
|
|
122
|
-
n.
|
|
121
|
+
if (r.tn) {
|
|
122
|
+
n.je = e;
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
const t = findLane(r);
|
|
@@ -127,14 +127,14 @@ function resolveTransition(n) {
|
|
|
127
127
|
if (t !== i && !hasActiveOverride(n)) {
|
|
128
128
|
// Parent-child lanes stay independent so isPending resolves without
|
|
129
129
|
// waiting for the parent's async. The child keeps ownership.
|
|
130
|
-
if (i.
|
|
131
|
-
n.
|
|
132
|
-
} else if (t.
|
|
130
|
+
if (i.an && findLane(i.an) === t) {
|
|
131
|
+
n.je = e;
|
|
132
|
+
} else if (t.an && findLane(t.an) === i) ; else mergeLanes(i, t);
|
|
133
133
|
}
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
-
n.
|
|
137
|
+
n.je = e;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
export { activeLanes, assignOrMergeLane, findLane, getOrCreateLane, hasActiveOverride, mergeLanes, resolveLane, resolveTransition, signalLanes };
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, OVERRIDE_UNDEFINED, STATUS_PENDING,
|
|
1
|
+
import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, OVERRIDE_UNDEFINED, STATUS_PENDING, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, EFFECT_RENDER, EFFECT_USER } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { latestReadActive, currentOptimisticLane, stale } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
7
|
-
import { enqueueSub } from "./heap.js";
|
|
8
|
-
|
|
9
7
|
import "./invariants.js";
|
|
10
8
|
|
|
11
9
|
import { resolveTransition, getOrCreateLane, hasActiveOverride, activeLanes, signalLanes, findLane, resolveLane, assignOrMergeLane } from "./lanes.js";
|
|
12
10
|
|
|
13
|
-
import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
11
|
+
import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule } from "./scheduler.js";
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
14
|
* The optimistic write engine, moved out of core.ts/scheduler.ts. Everything
|
|
@@ -25,15 +23,11 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
25
23
|
* `_optimisticNodes.length`, `activeLanes.size`), so `!` invocations are safe
|
|
26
24
|
* once the gate holds — the same late-binding contract as verdict.ts.
|
|
27
25
|
*/
|
|
28
|
-
// When a background transition is stashed, plain optimistic signals need one
|
|
29
|
-
// committed-view rerun. Keep that override local to the stash flush.
|
|
30
|
-
let stashedOptimisticReads = null;
|
|
31
|
-
|
|
32
26
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, n) {
|
|
33
|
-
const t = e.
|
|
34
|
-
const i = t ? unwrapOverride(e.
|
|
27
|
+
const t = e.Ee !== NOT_PENDING;
|
|
28
|
+
const i = t ? unwrapOverride(e.Ee) : e.Re;
|
|
35
29
|
if (typeof n === "function") n = n(i);
|
|
36
|
-
const u = !!(e.
|
|
30
|
+
const u = !!(e.S & STATUS_UNINITIALIZED) || !e.Pe || !e.Pe(i, n);
|
|
37
31
|
if (!u) {
|
|
38
32
|
// Same-value write with an active override still entangles the current
|
|
39
33
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -47,66 +41,32 @@ let stashedOptimisticReads = null;
|
|
|
47
41
|
// No revert target is stashed: while the override is active every reader
|
|
48
42
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
49
43
|
// reverting is just dropping the override — _value is already correct.
|
|
50
|
-
else globalQueue.
|
|
44
|
+
else globalQueue.m.Ze.push(e);
|
|
51
45
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
52
46
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
53
47
|
// which a shared subscriber can merge across transactions (#2912).
|
|
54
|
-
e.
|
|
55
|
-
const
|
|
56
|
-
e.
|
|
48
|
+
e.sn = activeTransition;
|
|
49
|
+
const o = getOrCreateLane(e);
|
|
50
|
+
e.je = o;
|
|
57
51
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
58
52
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
59
53
|
// writes off the optimistic path into permanent commits (#2898).
|
|
60
|
-
e.
|
|
61
|
-
GlobalQueue.
|
|
62
|
-
e.
|
|
54
|
+
e.Ee = n === undefined ? OVERRIDE_UNDEFINED : n;
|
|
55
|
+
GlobalQueue.Ie !== null && GlobalQueue.Ie(e, n);
|
|
56
|
+
e.ce = clock;
|
|
63
57
|
insertSubs(e, true);
|
|
64
58
|
schedule();
|
|
65
59
|
return n;
|
|
66
60
|
}
|
|
67
61
|
|
|
68
|
-
function readStashed(e) {
|
|
69
|
-
return !!stashedOptimisticReads?.has(e);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function queueStashedOptimisticEffects(e) {
|
|
73
|
-
for (let n = e.p; n !== null; n = n.de) {
|
|
74
|
-
const e = n.Ee;
|
|
75
|
-
if (!e.De) continue;
|
|
76
|
-
enqueueSub(e);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Incomplete-transition finalization when the stashed transition holds
|
|
82
|
-
* optimistic nodes: give plain optimistic signals one committed-view rerun.
|
|
83
|
-
*/ function stashOptimistic(e) {
|
|
84
|
-
stashedOptimisticReads = new Set;
|
|
85
|
-
for (let n = 0; n < e.Be.length; n++) {
|
|
86
|
-
const t = e.Be[n];
|
|
87
|
-
if (t.xe || t.U & CONFIG_OWNED_WRITE) continue;
|
|
88
|
-
stashedOptimisticReads.add(t);
|
|
89
|
-
queueStashedOptimisticEffects(t);
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
finalizePureQueue(null, true);
|
|
93
|
-
} finally {
|
|
94
|
-
stashedOptimisticReads = null;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
62
|
/**
|
|
99
63
|
* transitionComplete's override blockage: a settling transition stays open
|
|
100
64
|
* while one of its optimistic nodes holds an active override that is still
|
|
101
65
|
* pending on real (non-affects-sentinel) async.
|
|
102
66
|
*/ function transitionBlocked(e) {
|
|
103
|
-
for (let n = 0; n < e.
|
|
104
|
-
const t = e.
|
|
105
|
-
if (hasActiveOverride(t) && "
|
|
106
|
-
// Mark-sourced pending never blocks settlement: affects() releases AT
|
|
107
|
-
// settle, so counting its sentinel here would deadlock the window it
|
|
108
|
-
// is scoped to.
|
|
109
|
-
!t.k.source?.l) {
|
|
67
|
+
for (let n = 0; n < e.Ze.length; n++) {
|
|
68
|
+
const t = e.Ze[n];
|
|
69
|
+
if (hasActiveOverride(t) && "S" in t && t.S & STATUS_PENDING && t._ instanceof NotReadyError) {
|
|
110
70
|
return true;
|
|
111
71
|
}
|
|
112
72
|
}
|
|
@@ -120,25 +80,25 @@ function resolveOptimisticNodes(e) {
|
|
|
120
80
|
const n = e.length;
|
|
121
81
|
for (let t = 0; t < n; t++) {
|
|
122
82
|
const n = e[t];
|
|
123
|
-
n.
|
|
83
|
+
n.je = undefined;
|
|
124
84
|
// Revert is a pure drop: there is no revert target to commit —
|
|
125
85
|
// override-covered authoritative values hold in _pendingValue and
|
|
126
86
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
127
|
-
if (!(n.
|
|
128
|
-
const i = n.
|
|
129
|
-
n.
|
|
130
|
-
if (i !== NOT_PENDING && n.
|
|
131
|
-
n.
|
|
132
|
-
n.
|
|
87
|
+
if (!(n.S & STATUS_PENDING)) n.S &= ~STATUS_UNINITIALIZED;
|
|
88
|
+
const i = n.Ee;
|
|
89
|
+
n.Ee = NOT_PENDING;
|
|
90
|
+
if (i !== NOT_PENDING && n.Re !== unwrapOverride(i)) insertSubs(n, true);
|
|
91
|
+
n.Ue = null;
|
|
92
|
+
n.sn = null;
|
|
133
93
|
}
|
|
134
94
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
135
95
|
// by a node in it) re-derive from committed state, so verdicts survive the
|
|
136
96
|
// transition that produced them (A19 — pending is a property of the data).
|
|
137
97
|
for (let t = 0; t < n; t++) {
|
|
138
98
|
const n = e[t];
|
|
139
|
-
if (n.
|
|
140
|
-
const i = n.
|
|
141
|
-
if (i && (i.
|
|
99
|
+
if (n.ge || n.he) GlobalQueue.un(n);
|
|
100
|
+
const i = n.nn;
|
|
101
|
+
if (i && (i.ge === n || i.he === n)) GlobalQueue.un(i);
|
|
142
102
|
}
|
|
143
103
|
e.splice(0, n);
|
|
144
104
|
}
|
|
@@ -151,10 +111,10 @@ function runQueue(e, n) {
|
|
|
151
111
|
* Run effects from all lanes that are ready (no pending async).
|
|
152
112
|
*/ function runLaneEffects(e) {
|
|
153
113
|
for (const n of activeLanes) {
|
|
154
|
-
if (n.
|
|
155
|
-
const t = n.
|
|
114
|
+
if (n.tn || n.de.size > 0) continue;
|
|
115
|
+
const t = n.rn[e - 1];
|
|
156
116
|
if (t.length) {
|
|
157
|
-
n.
|
|
117
|
+
n.rn[e - 1] = [];
|
|
158
118
|
runQueue(t, e);
|
|
159
119
|
}
|
|
160
120
|
}
|
|
@@ -162,18 +122,18 @@ function runQueue(e, n) {
|
|
|
162
122
|
|
|
163
123
|
function cleanupCompletedLanes(e) {
|
|
164
124
|
for (const n of activeLanes) {
|
|
165
|
-
const t = e ? n.
|
|
125
|
+
const t = e ? n.Ue === e : !n.Ue;
|
|
166
126
|
if (!t) continue;
|
|
167
|
-
if (!n.
|
|
168
|
-
if (n.
|
|
169
|
-
if (n.
|
|
127
|
+
if (!n.tn) {
|
|
128
|
+
if (n.rn[0].length) runQueue(n.rn[0], EFFECT_RENDER);
|
|
129
|
+
if (n.rn[1].length) runQueue(n.rn[1], EFFECT_USER);
|
|
170
130
|
}
|
|
171
|
-
if (n.
|
|
172
|
-
n.
|
|
173
|
-
n.
|
|
174
|
-
n.
|
|
131
|
+
if (n.en.je === n) n.en.je = undefined;
|
|
132
|
+
n.de.clear();
|
|
133
|
+
n.rn[0].length = 0;
|
|
134
|
+
n.rn[1].length = 0;
|
|
175
135
|
activeLanes.delete(n);
|
|
176
|
-
signalLanes.delete(n.
|
|
136
|
+
signalLanes.delete(n.en);
|
|
177
137
|
}
|
|
178
138
|
}
|
|
179
139
|
|
|
@@ -181,7 +141,7 @@ function cleanupCompletedLanes(e) {
|
|
|
181
141
|
// Per-lane suspension: only throw if in same lane as pending async
|
|
182
142
|
// AND the node doesn't have an active override (overrides are the visible value,
|
|
183
143
|
// downstream in the lane should read the override, not throw)
|
|
184
|
-
const n = e.
|
|
144
|
+
const n = e.je;
|
|
185
145
|
if (!n) return false;
|
|
186
146
|
return findLane(n) === findLane(currentOptimisticLane) && !hasActiveOverride(e);
|
|
187
147
|
}
|
|
@@ -191,10 +151,10 @@ function cleanupCompletedLanes(e) {
|
|
|
191
151
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
192
152
|
* is recorded for replay at commit.
|
|
193
153
|
*/ function gatedRead(e, n, t) {
|
|
194
|
-
if (latestReadActive || e.
|
|
154
|
+
if (latestReadActive || e.Ne === NOT_PENDING || e.ke || n !== e && !(n.se & REACTIVE_MANUAL_WRITE)) {
|
|
195
155
|
return false;
|
|
196
156
|
}
|
|
197
|
-
activeTransition.
|
|
157
|
+
activeTransition.ln.add(t);
|
|
198
158
|
return true;
|
|
199
159
|
}
|
|
200
160
|
|
|
@@ -202,7 +162,7 @@ function cleanupCompletedLanes(e) {
|
|
|
202
162
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
203
163
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
204
164
|
*/ function laneReadsCommitted(e, n, t) {
|
|
205
|
-
return e.
|
|
165
|
+
return e.Ee !== undefined || !!e.je || n === e && stale && t.nn !== e || !!(n.S & STATUS_PENDING);
|
|
206
166
|
}
|
|
207
167
|
|
|
208
168
|
/**
|
|
@@ -211,12 +171,12 @@ function cleanupCompletedLanes(e) {
|
|
|
211
171
|
* can run before its OPT-dirty child propagates).
|
|
212
172
|
*/ function recomputeLane(e, n) {
|
|
213
173
|
if (n) return resolveLane(e) ?? null;
|
|
214
|
-
for (let n = e.
|
|
215
|
-
const t = n.
|
|
216
|
-
if (t.
|
|
174
|
+
for (let n = e.Xe; n; n = n.et) {
|
|
175
|
+
const t = n.tt;
|
|
176
|
+
if (t.se & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
217
177
|
const n = resolveLane(t);
|
|
218
178
|
if (n) {
|
|
219
|
-
e.
|
|
179
|
+
e.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
220
180
|
assignOrMergeLane(e, n);
|
|
221
181
|
return n;
|
|
222
182
|
}
|
|
@@ -227,24 +187,24 @@ function cleanupCompletedLanes(e) {
|
|
|
227
187
|
|
|
228
188
|
/** recompute()'s catch path: track pending async in the current lane. */ function laneAsyncPending(e) {
|
|
229
189
|
const n = findLane(currentOptimisticLane);
|
|
230
|
-
if (n.
|
|
231
|
-
n.
|
|
232
|
-
e.
|
|
233
|
-
GlobalQueue.
|
|
190
|
+
if (n.en !== e) {
|
|
191
|
+
n.de.add(e);
|
|
192
|
+
e.je = n;
|
|
193
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(n.en);
|
|
234
194
|
}
|
|
235
195
|
}
|
|
236
196
|
|
|
237
197
|
/** recompute()'s success path: the node's async settled, clear it from its lane. */ function laneAsyncSettled(e) {
|
|
238
198
|
const n = resolveLane(e);
|
|
239
199
|
if (n) {
|
|
240
|
-
n.
|
|
241
|
-
GlobalQueue.
|
|
200
|
+
n.de.delete(e);
|
|
201
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(n.en);
|
|
242
202
|
}
|
|
243
203
|
}
|
|
244
204
|
|
|
245
205
|
function trackOptimisticStore(e) {
|
|
246
206
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
247
|
-
globalQueue.
|
|
207
|
+
globalQueue.m.cn.add(e);
|
|
248
208
|
schedule();
|
|
249
209
|
}
|
|
250
210
|
|
|
@@ -253,21 +213,19 @@ function trackOptimisticStore(e) {
|
|
|
253
213
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
254
214
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
255
215
|
*/ function installOptimisticEngine() {
|
|
256
|
-
if (GlobalQueue.
|
|
257
|
-
GlobalQueue.
|
|
216
|
+
if (GlobalQueue.Pt !== null) return;
|
|
217
|
+
GlobalQueue.Pt = optimisticWrite;
|
|
258
218
|
GlobalQueue.En = resolveOptimisticNodes;
|
|
259
|
-
GlobalQueue.Tn =
|
|
260
|
-
GlobalQueue.
|
|
261
|
-
GlobalQueue.
|
|
262
|
-
GlobalQueue.
|
|
263
|
-
GlobalQueue.
|
|
264
|
-
GlobalQueue.
|
|
265
|
-
GlobalQueue.
|
|
266
|
-
GlobalQueue.
|
|
267
|
-
GlobalQueue
|
|
268
|
-
GlobalQueue.
|
|
269
|
-
GlobalQueue.Xe = laneAsyncSettled;
|
|
270
|
-
GlobalQueue.mn = trackOptimisticStore;
|
|
219
|
+
GlobalQueue.Tn = transitionBlocked;
|
|
220
|
+
GlobalQueue.dn = cleanupCompletedLanes;
|
|
221
|
+
GlobalQueue.In = runLaneEffects;
|
|
222
|
+
GlobalQueue.Ct = gatedRead;
|
|
223
|
+
GlobalQueue.At = laneSuspends;
|
|
224
|
+
GlobalQueue.Ot = laneReadsCommitted;
|
|
225
|
+
GlobalQueue.We = recomputeLane;
|
|
226
|
+
GlobalQueue.Ke = laneAsyncPending;
|
|
227
|
+
GlobalQueue.Me = laneAsyncSettled;
|
|
228
|
+
GlobalQueue.Nn = trackOptimisticStore;
|
|
271
229
|
}
|
|
272
230
|
|
|
273
231
|
export { installOptimisticEngine };
|
package/dist/prod/core/owner.js
CHANGED
|
@@ -12,10 +12,10 @@ const PENDING_OWNER = {};
|
|
|
12
12
|
|
|
13
13
|
// Dummy owner to trigger store's read() path
|
|
14
14
|
function markDisposal(e) {
|
|
15
|
-
let n = e.
|
|
15
|
+
let n = e.me;
|
|
16
16
|
while (n) {
|
|
17
|
-
const e = n.
|
|
18
|
-
n.
|
|
17
|
+
const e = n.se;
|
|
18
|
+
n.se = e | REACTIVE_ZOMBIE;
|
|
19
19
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
20
20
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
21
21
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -26,79 +26,79 @@ function markDisposal(e) {
|
|
|
26
26
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(n, zombieQueue); else insertIntoHeapHeight(n, zombieQueue);
|
|
27
27
|
}
|
|
28
28
|
markDisposal(n);
|
|
29
|
-
n = n.
|
|
29
|
+
n = n.ve;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function dispose(e) {
|
|
34
|
-
let n = e.
|
|
34
|
+
let n = e.Xe;
|
|
35
35
|
while (n !== null) {
|
|
36
36
|
n = unlinkSubs(n);
|
|
37
37
|
}
|
|
38
|
-
e.
|
|
39
|
-
e.
|
|
38
|
+
e.Xe = null;
|
|
39
|
+
e.qe = null;
|
|
40
40
|
disposeChildren(e, true);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function disposeChildren(e, n = false, t) {
|
|
44
|
-
const i = e.
|
|
44
|
+
const i = e.se;
|
|
45
45
|
if (i & REACTIVE_DISPOSED) return;
|
|
46
46
|
if (n) {
|
|
47
|
-
e.
|
|
47
|
+
e.se = i | REACTIVE_DISPOSED;
|
|
48
48
|
// Companions are created detached and outlive their owner, but a verdict
|
|
49
49
|
// must not: a disposed source can never settle, so an isPending companion
|
|
50
50
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
51
51
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
52
52
|
// false, and notifies subscribers still watching the companion.
|
|
53
53
|
const n = e;
|
|
54
|
-
if (n.
|
|
54
|
+
if (n.ge || n.he) GlobalQueue.un(n);
|
|
55
55
|
}
|
|
56
|
-
if (n && e.
|
|
57
|
-
let l = t ? e.
|
|
56
|
+
if (n && e.ke) e.Te = null;
|
|
57
|
+
let l = t ? e.Le : e.me;
|
|
58
58
|
while (l) {
|
|
59
|
-
const e = l.
|
|
60
|
-
if (l.
|
|
59
|
+
const e = l.ve;
|
|
60
|
+
if (l.Xe) {
|
|
61
61
|
const e = l;
|
|
62
62
|
deleteFromHeap(e, queueFor(e));
|
|
63
|
-
let n = e.
|
|
63
|
+
let n = e.Xe;
|
|
64
64
|
do {
|
|
65
65
|
n = unlinkSubs(n);
|
|
66
66
|
} while (n !== null);
|
|
67
|
-
e.
|
|
68
|
-
e.
|
|
67
|
+
e.Xe = null;
|
|
68
|
+
e.qe = null;
|
|
69
69
|
}
|
|
70
70
|
disposeChildren(l, true);
|
|
71
71
|
l = e;
|
|
72
72
|
}
|
|
73
73
|
if (t) {
|
|
74
|
-
e.
|
|
74
|
+
e.Le = null;
|
|
75
75
|
} else {
|
|
76
|
-
e.
|
|
77
|
-
e.
|
|
76
|
+
e.me = null;
|
|
77
|
+
e.Qe = 0;
|
|
78
78
|
}
|
|
79
79
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
80
80
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
81
81
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
82
82
|
// walks that already advanced past us still reach later siblings.
|
|
83
|
-
if (n && !t && !(i & REACTIVE_ZOMBIE) && e.
|
|
84
|
-
const n = e.
|
|
85
|
-
const t = e.
|
|
86
|
-
if (n !== null) n.
|
|
87
|
-
if (t !== null) t.
|
|
88
|
-
e.
|
|
83
|
+
if (n && !t && !(i & REACTIVE_ZOMBIE) && e.Ge !== null && !(e.Ge.se & REACTIVE_DISPOSED)) {
|
|
84
|
+
const n = e.st;
|
|
85
|
+
const t = e.ve;
|
|
86
|
+
if (n !== null) n.ve = t; else e.Ge.me = t;
|
|
87
|
+
if (t !== null) t.st = n;
|
|
88
|
+
e.st = null;
|
|
89
89
|
}
|
|
90
90
|
runDisposal(e, t);
|
|
91
91
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
92
92
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
93
|
-
if (n && e.
|
|
94
|
-
const n = e.
|
|
95
|
-
e.
|
|
93
|
+
if (n && e.Et) {
|
|
94
|
+
const n = e.Et;
|
|
95
|
+
e.Et = undefined;
|
|
96
96
|
n();
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
function runDisposal(e, n) {
|
|
101
|
-
let t = n ? e.
|
|
101
|
+
let t = n ? e.ye : e.xe;
|
|
102
102
|
if (!t) return;
|
|
103
103
|
if (Array.isArray(t)) {
|
|
104
104
|
for (let e = 0; e < t.length; e++) {
|
|
@@ -108,13 +108,13 @@ function runDisposal(e, n) {
|
|
|
108
108
|
} else {
|
|
109
109
|
t.call(t);
|
|
110
110
|
}
|
|
111
|
-
n ? e.
|
|
111
|
+
n ? e.ye = null : e.xe = null;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
function childId(e, n) {
|
|
115
115
|
let t = e;
|
|
116
|
-
while (t.
|
|
117
|
-
if (t.id != null) return formatId(t.id, n ? t.
|
|
116
|
+
while (t.T & CONFIG_TRANSPARENT && t.Ge) t = t.Ge;
|
|
117
|
+
if (t.id != null) return formatId(t.id, n ? t.Qe++ : t.Qe);
|
|
118
118
|
throw new Error("");
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -195,7 +195,7 @@ function formatId(e, n) {
|
|
|
195
195
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
196
196
|
*/ function cleanup(e) {
|
|
197
197
|
if (!context) return e;
|
|
198
|
-
if (!context.
|
|
198
|
+
if (!context.xe) context.xe = e; else if (Array.isArray(context.xe)) context.xe.push(e); else context.xe = [ context.xe, e ];
|
|
199
199
|
return e;
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -215,7 +215,7 @@ function formatId(e, n) {
|
|
|
215
215
|
* }
|
|
216
216
|
* ```
|
|
217
217
|
*/ function isDisposed(e) {
|
|
218
|
-
return !!(e.
|
|
218
|
+
return !!(e.se & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
function disposeRootSelf(e = true) {
|
|
@@ -234,29 +234,29 @@ function disposeRootSelf(e = true) {
|
|
|
234
234
|
const t = e?.transparent ?? false;
|
|
235
235
|
const i = {
|
|
236
236
|
id: inheritId(e, t, n),
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
237
|
+
T: t ? CONFIG_TRANSPARENT : 0,
|
|
238
|
+
ft: true,
|
|
239
|
+
Nt: n?.ft ? n.Nt : n,
|
|
240
|
+
me: null,
|
|
241
|
+
ve: null,
|
|
242
|
+
st: null,
|
|
243
|
+
xe: null,
|
|
244
|
+
C: n?.C ?? globalQueue,
|
|
245
245
|
we: n?.we || defaultContext,
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
Qe: 0,
|
|
247
|
+
ye: null,
|
|
248
|
+
Le: null,
|
|
249
|
+
Ge: n,
|
|
250
250
|
dispose: disposeRootSelf
|
|
251
251
|
};
|
|
252
252
|
if (n) {
|
|
253
|
-
const e = n.
|
|
253
|
+
const e = n.me;
|
|
254
254
|
if (e === null) {
|
|
255
|
-
n.
|
|
255
|
+
n.me = i;
|
|
256
256
|
} else {
|
|
257
|
-
i.
|
|
258
|
-
e.
|
|
259
|
-
n.
|
|
257
|
+
i.ve = e;
|
|
258
|
+
e.st = i;
|
|
259
|
+
n.me = i;
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
return i;
|