@solidjs/signals 2.0.0-rc.15 → 2.0.0-rc.17
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/dist/dev-shared.js +2268 -1734
- package/dist/dev.attribution.js +75 -52
- package/dist/dev.js +1348 -658
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +22 -73
- package/dist/observe/boundaries.js +192 -190
- package/dist/observe/core/async.js +177 -131
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +176 -159
- package/dist/observe/core/constants.js +17 -3
- package/dist/observe/core/context.js +5 -3
- package/dist/observe/core/core.js +520 -364
- package/dist/observe/core/dev.js +66 -38
- package/dist/observe/core/effect.js +50 -48
- package/dist/observe/core/error.js +5 -3
- package/dist/observe/core/external.js +5 -6
- package/dist/observe/core/graph.js +60 -44
- package/dist/observe/core/heap.js +33 -33
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/lanes.js +238 -260
- package/dist/observe/core/owner.js +117 -79
- package/dist/observe/core/scheduler.js +381 -217
- package/dist/observe/core/truth.js +45 -0
- package/dist/observe/core/verdict.js +91 -50
- package/dist/observe/deferred.js +184 -0
- package/dist/observe/index.js +7 -1
- package/dist/observe/map.js +345 -260
- package/dist/observe/reveal.js +76 -76
- package/dist/observe/signals.js +47 -31
- package/dist/observe/store/affects.js +18 -18
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/optimistic.js +146 -100
- package/dist/observe/store/projection.js +68 -55
- package/dist/observe/store/store.js +180 -118
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +23 -72
- package/dist/prod/boundaries.js +156 -154
- package/dist/prod/core/async.js +173 -127
- package/dist/prod/core/constants.js +17 -3
- package/dist/prod/core/context.js +5 -3
- package/dist/prod/core/core.js +495 -343
- package/dist/prod/core/effect.js +70 -68
- package/dist/prod/core/error.js +5 -3
- package/dist/prod/core/external.js +5 -6
- package/dist/prod/core/graph.js +60 -44
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/lanes.js +230 -252
- package/dist/prod/core/owner.js +114 -77
- package/dist/prod/core/scheduler.js +327 -163
- package/dist/prod/core/truth.js +45 -0
- package/dist/prod/core/verdict.js +90 -49
- package/dist/prod/deferred.js +182 -0
- package/dist/prod/index.js +7 -1
- package/dist/prod/map.js +360 -275
- package/dist/prod/reveal.js +76 -76
- package/dist/prod/signals.js +42 -26
- package/dist/prod/store/affects.js +6 -6
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/optimistic.js +143 -98
- package/dist/prod/store/projection.js +25 -19
- package/dist/prod/store/store.js +157 -100
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/boundaries.d.ts +1 -1
- package/dist/types/core/async.d.ts +10 -0
- package/dist/types/core/constants.d.ts +13 -1
- package/dist/types/core/core.d.ts +54 -5
- package/dist/types/core/dev.d.ts +51 -13
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/graph.d.ts +11 -0
- package/dist/types/core/identities.d.ts +17 -0
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +2 -14
- package/dist/types/core/owner.d.ts +9 -3
- package/dist/types/core/scheduler.d.ts +70 -32
- package/dist/types/core/truth.d.ts +16 -0
- package/dist/types/core/types.d.ts +21 -0
- package/dist/types/core/verdict.d.ts +32 -0
- package/dist/types/deferred.d.ts +28 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/map.d.ts +2 -2
- package/dist/types/signals.d.ts +28 -7
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/index.d.ts +10 -3
- package/dist/types/store/optimistic.d.ts +3 -2
- package/dist/types/store/projection.d.ts +4 -3
- package/dist/types/store/store.d.ts +1 -1
- package/dist/types/store/target.d.ts +16 -8
- package/dist/types/store/types.d.ts +14 -0
- package/package.json +1 -1
package/dist/observe/reveal.js
CHANGED
|
@@ -32,124 +32,124 @@ const SEQUENTIAL_ACCESSOR = () => "sequential";
|
|
|
32
32
|
|
|
33
33
|
const isController = t => t instanceof RevealController;
|
|
34
34
|
|
|
35
|
-
const slotReady = t => isController(t) ? t.
|
|
35
|
+
const slotReady = t => isController(t) ? t.Lt() : ready(t);
|
|
36
36
|
|
|
37
|
-
const slotMinReady = t => isController(t) ? t.
|
|
37
|
+
const slotMinReady = t => isController(t) ? t.Qt() : ready(t);
|
|
38
38
|
|
|
39
39
|
/** Force a slot's state. A boundary re-derives its output when it changes;
|
|
40
40
|
* a nested controller passes the state on to its own slots. Released
|
|
41
41
|
* (`!gated`), a nested controller leaves its parent's ownership and runs its
|
|
42
42
|
* own order; a boundary leaves when it has shown content (boundaries.ts). */ function setSlotState(t, e, s, r) {
|
|
43
43
|
if (isController(t)) {
|
|
44
|
-
t
|
|
45
|
-
t.
|
|
46
|
-
t.
|
|
44
|
+
t.$ = s;
|
|
45
|
+
t.ee = r;
|
|
46
|
+
t.Bt();
|
|
47
47
|
// Released and ready — every slot of its own has shown — it graduates,
|
|
48
48
|
// as a boundary does when it shows content. Released at the frontier
|
|
49
49
|
// but not ready, it stays the parent's frontier.
|
|
50
|
-
if (!s && t.
|
|
50
|
+
if (!s && t.Jt && t._parent === e) t._parent = null;
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
if (t
|
|
54
|
-
t
|
|
55
|
-
t.
|
|
53
|
+
if (t.$ !== s || t.ee !== r) {
|
|
54
|
+
t.$ = s;
|
|
55
|
+
t.ee = r;
|
|
56
56
|
redraw(t);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
class RevealController {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
Xt;
|
|
62
|
+
Yt;
|
|
63
|
+
Zt=[];
|
|
64
64
|
/** The controller gating this one, until it releases this one. */
|
|
65
65
|
_parent=null;
|
|
66
66
|
/** The state a parent forces on this whole group. */
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
$=false;
|
|
68
|
+
ee=false;
|
|
69
|
+
Jt=true;
|
|
70
|
+
ts=true;
|
|
71
|
+
es=false;
|
|
72
72
|
constructor(t, e) {
|
|
73
|
-
this.
|
|
74
|
-
this.
|
|
73
|
+
this.Xt = t;
|
|
74
|
+
this.Yt = e;
|
|
75
75
|
}
|
|
76
76
|
/** A slot that has left this controller's ownership: a boundary that has
|
|
77
77
|
* shown content, a nested group that is ready. Shown is shown — it counts
|
|
78
|
-
* as ready whatever happens to it later (a re-arm gates nobody else). */
|
|
79
|
-
return (isController(t) ? t._parent : t.
|
|
78
|
+
* as ready whatever happens to it later (a re-arm gates nobody else). */ ss(t) {
|
|
79
|
+
return (isController(t) ? t._parent : t.v) !== this;
|
|
80
80
|
}
|
|
81
81
|
/** The slots this controller still owns, in registration order — the
|
|
82
|
-
* ones the order's state is forced on. */
|
|
83
|
-
for (let e = 0; e < this.
|
|
84
|
-
const s = this.
|
|
85
|
-
if (!this.
|
|
82
|
+
* ones the order's state is forced on. */ rs(t) {
|
|
83
|
+
for (let e = 0; e < this.Zt.length; e++) {
|
|
84
|
+
const s = this.Zt[e];
|
|
85
|
+
if (!this.ss(s) && t(s) === false) return false;
|
|
86
86
|
}
|
|
87
87
|
return true;
|
|
88
88
|
}
|
|
89
|
-
/** Readiness is judged over every slot, done ones as ready. */
|
|
90
|
-
for (let t = 0; t < this.
|
|
91
|
-
const e = this.
|
|
92
|
-
if (!this.
|
|
89
|
+
/** Readiness is judged over every slot, done ones as ready. */ Lt() {
|
|
90
|
+
for (let t = 0; t < this.Zt.length; t++) {
|
|
91
|
+
const e = this.Zt[t];
|
|
92
|
+
if (!this.ss(e) && !slotReady(e)) return false;
|
|
93
93
|
}
|
|
94
94
|
return true;
|
|
95
95
|
}
|
|
96
96
|
/** Something visible to show under its own order — what an enclosing
|
|
97
97
|
* `together` waits for: `together` — every slot minimally ready;
|
|
98
|
-
* `sequential` — the first slot; `natural` — any. */
|
|
99
|
-
const t = untrack(this.
|
|
100
|
-
const e = this.
|
|
98
|
+
* `sequential` — the first slot; `natural` — any. */ Qt() {
|
|
99
|
+
const t = untrack(this.Xt);
|
|
100
|
+
const e = this.Zt;
|
|
101
101
|
if (e.length === 0) return true;
|
|
102
|
-
if (t === "sequential") return this.
|
|
102
|
+
if (t === "sequential") return this.ss(e[0]) || slotMinReady(e[0]);
|
|
103
103
|
for (let s = 0; s < e.length; s++) {
|
|
104
|
-
const r = this.
|
|
104
|
+
const r = this.ss(e[s]) || slotMinReady(e[s]);
|
|
105
105
|
if (t === "natural" ? r : !r) return t === "natural";
|
|
106
106
|
}
|
|
107
107
|
return t !== "natural";
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
if (this.
|
|
111
|
-
this.
|
|
109
|
+
oe(t) {
|
|
110
|
+
if (this.Zt.includes(t)) return;
|
|
111
|
+
this.Zt.push(t);
|
|
112
112
|
// Gated from the start (collapsed in a collapsed sequential tail); the
|
|
113
113
|
// evaluation releases what the order allows.
|
|
114
|
-
const e = untrack(this.
|
|
114
|
+
const e = untrack(this.Xt) === "sequential" && !!untrack(this.Yt);
|
|
115
115
|
if (isController(t)) {
|
|
116
116
|
t._parent = this;
|
|
117
|
-
t
|
|
118
|
-
t.
|
|
119
|
-
t.
|
|
117
|
+
t.$ = true;
|
|
118
|
+
t.ee = e;
|
|
119
|
+
t.Bt();
|
|
120
120
|
} else {
|
|
121
|
-
t.
|
|
122
|
-
t
|
|
123
|
-
t.
|
|
121
|
+
t.v = this;
|
|
122
|
+
t.$ = true;
|
|
123
|
+
t.ee = e;
|
|
124
124
|
}
|
|
125
|
-
untrack(() => this.
|
|
125
|
+
untrack(() => this.Bt());
|
|
126
126
|
}
|
|
127
|
-
|
|
128
|
-
const e = this.
|
|
129
|
-
if (e >= 0) this.
|
|
130
|
-
untrack(() => this.
|
|
127
|
+
te(t) {
|
|
128
|
+
const e = this.Zt.indexOf(t);
|
|
129
|
+
if (e >= 0) this.Zt.splice(e, 1);
|
|
130
|
+
untrack(() => this.Bt());
|
|
131
131
|
}
|
|
132
132
|
/** Apply the order to the owned slots — or, gated by a parent, its state
|
|
133
|
-
* to all of them. */
|
|
134
|
-
if (this.
|
|
135
|
-
this.
|
|
136
|
-
const t = this.
|
|
137
|
-
const e = this.
|
|
133
|
+
* to all of them. */ Bt() {
|
|
134
|
+
if (this.es) return;
|
|
135
|
+
this.es = true;
|
|
136
|
+
const t = this.Jt;
|
|
137
|
+
const e = this.ts;
|
|
138
138
|
try {
|
|
139
|
-
const t = untrack(this.
|
|
140
|
-
const e = t === "sequential" && !!untrack(this.
|
|
141
|
-
if (this
|
|
142
|
-
this.
|
|
139
|
+
const t = untrack(this.Xt);
|
|
140
|
+
const e = t === "sequential" && !!untrack(this.Yt);
|
|
141
|
+
if (this.$) {
|
|
142
|
+
this.rs(t => setSlotState(t, this, true, this.ee));
|
|
143
143
|
} else if (t === "natural") {
|
|
144
|
-
this.
|
|
144
|
+
this.rs(t => {
|
|
145
145
|
if (isController(t)) setSlotState(t, this, false, false); else setSlotState(t, this, !ready(t), false);
|
|
146
146
|
});
|
|
147
147
|
} else if (t === "together") {
|
|
148
|
-
const t = this.
|
|
149
|
-
this.
|
|
148
|
+
const t = this.rs(slotMinReady);
|
|
149
|
+
this.rs(e => setSlotState(e, this, !t, false));
|
|
150
150
|
} else {
|
|
151
151
|
let t = false;
|
|
152
|
-
this.
|
|
152
|
+
this.rs(s => {
|
|
153
153
|
if (t) return setSlotState(s, this, true, e);
|
|
154
154
|
if (slotReady(s)) return setSlotState(s, this, false, false);
|
|
155
155
|
t = true;
|
|
@@ -159,11 +159,11 @@ class RevealController {
|
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
} finally {
|
|
162
|
-
this.
|
|
163
|
-
this.
|
|
164
|
-
this.
|
|
162
|
+
this.Jt = this.Lt();
|
|
163
|
+
this.ts = this.Qt();
|
|
164
|
+
this.es = false;
|
|
165
165
|
}
|
|
166
|
-
if (this._parent !== null && (t !== this.
|
|
166
|
+
if (this._parent !== null && (t !== this.Jt || e !== this.ts)) this._parent.Bt();
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -179,23 +179,23 @@ class RevealController {
|
|
|
179
179
|
* slots behind the frontier render nothing instead of their fallbacks
|
|
180
180
|
*/ function createRevealOrder(t, e) {
|
|
181
181
|
const s = createOwner();
|
|
182
|
-
const r = s.
|
|
182
|
+
const r = s.A[REVEAL];
|
|
183
183
|
const i = new RevealController(e?.order || SEQUENTIAL_ACCESSOR, e?.collapsed || FALSE_ACCESSOR);
|
|
184
|
-
s.
|
|
185
|
-
...s.
|
|
184
|
+
s.A = {
|
|
185
|
+
...s.A,
|
|
186
186
|
[REVEAL]: i
|
|
187
187
|
};
|
|
188
188
|
return runWithOwner(s, () => {
|
|
189
189
|
const e = t();
|
|
190
190
|
const s = computed(() => {
|
|
191
|
-
i.
|
|
192
|
-
i.
|
|
193
|
-
i.
|
|
191
|
+
i.Xt();
|
|
192
|
+
i.Yt();
|
|
193
|
+
i.Bt();
|
|
194
194
|
});
|
|
195
195
|
if (true) s._name = "reveal order";
|
|
196
196
|
if (r) {
|
|
197
|
-
r.
|
|
198
|
-
cleanup(() => r.
|
|
197
|
+
r.oe(i);
|
|
198
|
+
cleanup(() => r.te(i));
|
|
199
199
|
}
|
|
200
200
|
return e;
|
|
201
201
|
});
|
|
@@ -204,9 +204,9 @@ class RevealController {
|
|
|
204
204
|
// Installed at module evaluation — present exactly when something imports
|
|
205
205
|
// `createRevealOrder`; a Loading boundary without one pays a null check.
|
|
206
206
|
setRevealHooks({
|
|
207
|
-
ue: (t, e) => t.ue(e),
|
|
208
207
|
oe: (t, e) => t.oe(e),
|
|
209
|
-
|
|
208
|
+
te: (t, e) => t.te(e),
|
|
209
|
+
P: t => t.Bt()
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
export { createRevealOrder };
|
package/dist/observe/signals.js
CHANGED
|
@@ -12,9 +12,13 @@ import { globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, pass
|
|
|
12
12
|
|
|
13
13
|
import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
|
|
14
14
|
|
|
15
|
+
import { signalHook } from "./core/identities.js";
|
|
16
|
+
|
|
15
17
|
import { effect, trackedEffect } from "./core/effect.js";
|
|
16
18
|
|
|
17
|
-
import { optimisticWrite
|
|
19
|
+
import { optimisticWrite } from "./core/lanes.js";
|
|
20
|
+
|
|
21
|
+
import { truthRead, truthConfirmed } from "./core/truth.js";
|
|
18
22
|
|
|
19
23
|
/**
|
|
20
24
|
* Low-level reactive-cleanup primitive. Registers a callback that runs when
|
|
@@ -73,18 +77,19 @@ function accessor(e) {
|
|
|
73
77
|
function createSignal(e, t) {
|
|
74
78
|
if (typeof e === "function") {
|
|
75
79
|
const r = computed(e, t);
|
|
76
|
-
r.
|
|
80
|
+
r.l &= ~CONFIG_AUTO_DISPOSE;
|
|
77
81
|
return [ accessor(r), setMemo.bind(null, r) ];
|
|
78
82
|
}
|
|
79
83
|
const r = signal(e, t);
|
|
80
84
|
registerGraph(r, getOwner());
|
|
85
|
+
if (signalHook !== null) signalHook(r);
|
|
81
86
|
return [ accessor(r), setSignal.bind(null, r) ];
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
function createOptimistic(e, t) {
|
|
85
90
|
if (typeof e === "function") {
|
|
86
91
|
const r = computed(e, t);
|
|
87
|
-
r.
|
|
92
|
+
r.l &= ~CONFIG_AUTO_DISPOSE;
|
|
88
93
|
return [ accessor(r), optimisticWrite.bind(null, r) ];
|
|
89
94
|
}
|
|
90
95
|
const r = signal(e, t);
|
|
@@ -162,7 +167,7 @@ function createMemo(e, t) {
|
|
|
162
167
|
* );
|
|
163
168
|
* ```
|
|
164
169
|
*
|
|
165
|
-
* @description https://
|
|
170
|
+
* @description https://v2.solidjs.com/reference/solid-js/reactivity/create-effect
|
|
166
171
|
*/ function createEffect(e, t, r) {
|
|
167
172
|
effect(e, t.effect || t, t.error, {
|
|
168
173
|
user: true,
|
|
@@ -197,7 +202,7 @@ function createMemo(e, t) {
|
|
|
197
202
|
* }
|
|
198
203
|
* ```
|
|
199
204
|
*
|
|
200
|
-
* @description https://
|
|
205
|
+
* @description https://v2.solidjs.com/reference/solid-js/advanced/specialized-reactivity/create-render-effect
|
|
201
206
|
*/ function createRenderEffect(e, t, r) {
|
|
202
207
|
effect(e, t, undefined, r);
|
|
203
208
|
}
|
|
@@ -245,7 +250,7 @@ function createMemo(e, t) {
|
|
|
245
250
|
* });
|
|
246
251
|
* ```
|
|
247
252
|
*
|
|
248
|
-
* @description https://
|
|
253
|
+
* @description https://v2.solidjs.com/reference/solid-js/advanced/specialized-reactivity/create-tracked-effect
|
|
249
254
|
*/ function createTrackedEffect(e, t) {
|
|
250
255
|
trackedEffect(e, t);
|
|
251
256
|
}
|
|
@@ -274,7 +279,7 @@ function createMemo(e, t) {
|
|
|
274
279
|
* setCount(1); // logs once, reaction re-armed for next change
|
|
275
280
|
* ```
|
|
276
281
|
*
|
|
277
|
-
* @description https://
|
|
282
|
+
* @description https://v2.solidjs.com/reference/solid-js/advanced/specialized-reactivity/create-reaction
|
|
278
283
|
*/ function createReaction(e, t) {
|
|
279
284
|
let r = undefined;
|
|
280
285
|
cleanup(() => r?.());
|
|
@@ -291,7 +296,12 @@ function createMemo(e, t) {
|
|
|
291
296
|
o = undefined;
|
|
292
297
|
}
|
|
293
298
|
runWithOwner(n, () => {
|
|
294
|
-
effect(() =>
|
|
299
|
+
effect(() => {
|
|
300
|
+
const e = getOwner();
|
|
301
|
+
o = e;
|
|
302
|
+
c();
|
|
303
|
+
return e;
|
|
304
|
+
}, t => {
|
|
295
305
|
o = undefined;
|
|
296
306
|
r?.();
|
|
297
307
|
const n = (e.effect || e)?.();
|
|
@@ -325,34 +335,40 @@ function createMemo(e, t) {
|
|
|
325
335
|
* joined it (L2, born held — A29) and delivers at that commit: the
|
|
326
336
|
* committed view, never a foreign hold's unrevealed frame. */ function watch(e, t, r, n = 0, o, c = flushTransaction) {
|
|
327
337
|
if (n & CONFIG_AUTHORITATIVE) {
|
|
328
|
-
GlobalQueue.
|
|
329
|
-
GlobalQueue.
|
|
338
|
+
GlobalQueue.rn = truthRead;
|
|
339
|
+
GlobalQueue.tn = truthConfirmed;
|
|
330
340
|
}
|
|
331
341
|
// `config` is on the node for its first pass too (the pass runs inside
|
|
332
342
|
// `computed()`): `until`'s predicate is authoritative from its first read,
|
|
333
343
|
// or an already-displayed guess would satisfy it in a later slice. (REDERIVE
|
|
334
344
|
// after: the first pass's own error is the promise's rejection.)
|
|
335
345
|
computed(() => {
|
|
336
|
-
let
|
|
346
|
+
let i, u = false;
|
|
337
347
|
try {
|
|
338
|
-
|
|
348
|
+
i = e();
|
|
339
349
|
} catch (e) {
|
|
340
350
|
if (e instanceof NotReadyError) throw e;
|
|
341
|
-
|
|
342
|
-
|
|
351
|
+
// An error is an answer (D-41): delivered by the same frame rule.
|
|
352
|
+
i = unwrapStatusError(e);
|
|
353
|
+
u = true;
|
|
343
354
|
}
|
|
344
|
-
const
|
|
355
|
+
const s = getOwner();
|
|
356
|
+
// A truth reader waits out a `createDeferred` flight its value derives
|
|
357
|
+
// from, which serves everyone else the stale answer (D-40).
|
|
358
|
+
const f = n & CONFIG_AUTHORITATIVE && GlobalQueue.er?.(s);
|
|
359
|
+
if (f) throw new NotReadyError(f);
|
|
345
360
|
// (Outside a flush a mainline pass joins through `passTx`.)
|
|
346
|
-
const
|
|
347
|
-
if (
|
|
348
|
-
staleReader(
|
|
361
|
+
const a = flushTransaction ?? passTx;
|
|
362
|
+
if (s.R & REACTIVE_JOINED && a !== null && (c === null || resolveTx(c) !== resolveTx(a))) {
|
|
363
|
+
staleReader(s, resolveTx(a));
|
|
349
364
|
return;
|
|
350
365
|
}
|
|
351
|
-
|
|
352
|
-
|
|
366
|
+
if (u) return void queueMicrotask(() => r(i));
|
|
367
|
+
o?.(i);
|
|
368
|
+
queueMicrotask(() => t(i));
|
|
353
369
|
}, {
|
|
354
|
-
|
|
355
|
-
}).
|
|
370
|
+
St: n
|
|
371
|
+
}).l |= CONFIG_REDERIVE;
|
|
356
372
|
}
|
|
357
373
|
|
|
358
374
|
/**
|
|
@@ -451,7 +467,7 @@ function createMemo(e, t) {
|
|
|
451
467
|
// guessed node's own re-ask is not answered by it (#3895): park
|
|
452
468
|
// on that flight, or reject with its error.
|
|
453
469
|
const e = read(t);
|
|
454
|
-
if (t.
|
|
470
|
+
if (t.l & CONFIG_GUESS && t.m & (STATUS_PENDING | STATUS_ERROR)) throw t.T?.F;
|
|
455
471
|
return e;
|
|
456
472
|
}, t => {
|
|
457
473
|
n(typeof e === "function" ? t : e);
|
|
@@ -509,14 +525,14 @@ function createMemo(e, t) {
|
|
|
509
525
|
// (`saving=true` beside the confirmed `version=1` is a tear no timeline
|
|
510
526
|
// contains). Updates that do not flip the predicate reveal freely.
|
|
511
527
|
const c = flushTransaction;
|
|
512
|
-
createRoot(
|
|
513
|
-
let
|
|
528
|
+
createRoot(i => {
|
|
529
|
+
let u;
|
|
514
530
|
let s;
|
|
515
531
|
const settle = e => {
|
|
516
|
-
if (
|
|
532
|
+
if (u !== undefined) clearTimeout(u);
|
|
517
533
|
if (s !== undefined) o.removeEventListener("abort", s);
|
|
518
534
|
e();
|
|
519
|
-
|
|
535
|
+
i();
|
|
520
536
|
};
|
|
521
537
|
// Authoritative: the predicate sees the truth, never the action's own
|
|
522
538
|
// optimistic guess — a guess cannot satisfy the wait for its own
|
|
@@ -529,9 +545,9 @@ function createMemo(e, t) {
|
|
|
529
545
|
// The flip, inside the pass of the flush carrying it: the flush
|
|
530
546
|
// joins the action's transaction, and what it staged is held and
|
|
531
547
|
// revealed with the action.
|
|
532
|
-
if (e && c !== null && globalQueue.
|
|
548
|
+
if (e && c !== null && globalQueue.q && resolveTx(c).tt !== 0) joinFuture(c);
|
|
533
549
|
});
|
|
534
|
-
if (t?.timeout !== undefined)
|
|
550
|
+
if (t?.timeout !== undefined) u = setTimeout(() => settle(() => n(new TimeoutError)), t.timeout);
|
|
535
551
|
if (o !== undefined) {
|
|
536
552
|
s = () => settle(() => n(o.reason));
|
|
537
553
|
o.addEventListener("abort", s, {
|
|
@@ -637,7 +653,7 @@ function createMemo(e, t) {
|
|
|
637
653
|
* on owner disposal
|
|
638
654
|
*/ function onSettled(e) {
|
|
639
655
|
const t = getOwner();
|
|
640
|
-
t && !(t.
|
|
656
|
+
t && !(t.l & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), {
|
|
641
657
|
name: "onSettled"
|
|
642
658
|
}) : globalQueue.enqueue(EFFECT_USER, function fire() {
|
|
643
659
|
// Settled means derived. A settle that reverts optimism (or replays
|
|
@@ -647,7 +663,7 @@ function createMemo(e, t) {
|
|
|
647
663
|
// still holding the optimistic value — reads do not pull (#3411). Fall
|
|
648
664
|
// to the next pass while the heap has work; `run` swapped the queue,
|
|
649
665
|
// so this lands there, and `enqueue` keeps the drain alive.
|
|
650
|
-
if (dirtyQueue.
|
|
666
|
+
if (dirtyQueue.jt >= dirtyQueue.st) return globalQueue.enqueue(EFFECT_USER, fire);
|
|
651
667
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
652
668
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
653
669
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GlobalQueue } from "../core/scheduler.js";
|
|
1
|
+
import { GlobalQueue, releaseMarksHook } from "../core/scheduler.js";
|
|
2
2
|
|
|
3
3
|
import { optHooks, installAffectsHooks } from "./hooks.js";
|
|
4
4
|
|
|
@@ -38,24 +38,24 @@ const scopes = new Map;
|
|
|
38
38
|
function scopeOf(e, o) {
|
|
39
39
|
let n = scopes.get(e);
|
|
40
40
|
if (n === undefined) scopes.set(e, n = {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
oo: new Set,
|
|
42
|
+
no: [],
|
|
43
|
+
Vt: o
|
|
44
44
|
});
|
|
45
45
|
return n;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/** The nodes an `affects(store[, key])` declaration marks (affects.ts
|
|
49
49
|
* registers each). */ function storeMarks(e, o) {
|
|
50
|
-
const n = GlobalQueue.
|
|
50
|
+
const n = GlobalQueue.so(e, o === undefined ? $AFFECTS : o);
|
|
51
51
|
const t = scopeOf(n, o);
|
|
52
52
|
if (o === undefined) {
|
|
53
53
|
const o = [ n ];
|
|
54
54
|
walk(e.px, t, o, e.fam, new Set);
|
|
55
55
|
return o;
|
|
56
56
|
}
|
|
57
|
-
t.
|
|
58
|
-
if (e.pb !== null) t.
|
|
57
|
+
t.oo.add(e.v);
|
|
58
|
+
if (e.pb !== null) t.oo.add(e.pb);
|
|
59
59
|
return [ n ];
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -63,14 +63,14 @@ function scopeOf(e, o) {
|
|
|
63
63
|
* the committed backing both, when a draft is open; an optimistic family's
|
|
64
64
|
* view), every live node under each record into `found`. Untracked by
|
|
65
65
|
* construction: raws, never traps. */ function walk(e, o, n, t, s) {
|
|
66
|
-
if (!GlobalQueue.
|
|
66
|
+
if (!GlobalQueue.fo(e)) return;
|
|
67
67
|
const f = e[$TARGET] ?? lookupTarget(e, t);
|
|
68
68
|
let r = f !== undefined ? f.pb ?? f.v : e;
|
|
69
69
|
if (s.has(r)) return;
|
|
70
70
|
s.add(r);
|
|
71
|
-
o.
|
|
71
|
+
o.oo.add(r);
|
|
72
72
|
if (f !== undefined) {
|
|
73
|
-
if (f.pb !== null) o.
|
|
73
|
+
if (f.pb !== null) o.oo.add(f.v);
|
|
74
74
|
// The writer's view: the tick's own unflushed guesses are in motion too.
|
|
75
75
|
if (f.fam?.opt === true) r = optHooks.view(f, r, true);
|
|
76
76
|
const e = f.n;
|
|
@@ -94,9 +94,9 @@ function scopeOf(e, o) {
|
|
|
94
94
|
* backings (§7b): a view's backing is another store's proxy — marks cover
|
|
95
95
|
* the BASE raw, so every identity along the chain is checked. */ function covering(e, o, n) {
|
|
96
96
|
for (const [t, s] of scopes) {
|
|
97
|
-
if (t === n || s.
|
|
97
|
+
if (t === n || s.Vt !== undefined && s.Vt !== o) continue;
|
|
98
98
|
for (let o = e.v; ;) {
|
|
99
|
-
if (s.
|
|
99
|
+
if (s.oo.has(o)) return t;
|
|
100
100
|
const e = o?.[$TARGET];
|
|
101
101
|
if (e === undefined) break;
|
|
102
102
|
const n = e.pb ?? e.v;
|
|
@@ -112,18 +112,18 @@ function scopeOf(e, o) {
|
|
|
112
112
|
* no work. */ const hooks = {
|
|
113
113
|
// A node born on a record a live mark covers inherits it (released with
|
|
114
114
|
// the carrier's last registration).
|
|
115
|
-
|
|
115
|
+
ro(e, o, n) {
|
|
116
116
|
if (scopes.size === 0 || n === $AFFECTS) return;
|
|
117
117
|
const t = covering(e, n, o);
|
|
118
118
|
if (!t) return;
|
|
119
|
-
GlobalQueue.
|
|
120
|
-
scopes.get(t).
|
|
119
|
+
GlobalQueue.N(o);
|
|
120
|
+
scopes.get(t).no.push(o);
|
|
121
121
|
},
|
|
122
122
|
// An untracked probe (`isPending(() => s.x)` with no observer) reading a
|
|
123
123
|
// record a live mark covers: no node carries the mark for it — the
|
|
124
124
|
// verdict is told directly.
|
|
125
|
-
|
|
126
|
-
if (e.n?.[$AFFECTS]?.
|
|
125
|
+
io(e, o) {
|
|
126
|
+
if (e.n?.[$AFFECTS]?.T?.I || covering(e, o)) GlobalQueue.bt();
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
|
|
@@ -136,7 +136,7 @@ function scopeOf(e, o) {
|
|
|
136
136
|
const o = scopes.get(e);
|
|
137
137
|
if (o === undefined) return;
|
|
138
138
|
scopes.delete(e);
|
|
139
|
-
|
|
139
|
+
releaseMarksHook(o.no);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
export { installStoreAffects, releaseMarkScope, storeMarks };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CONFIG_SLOT_NODE } from "../core/constants.js";
|
|
2
|
+
|
|
3
|
+
import { signalName } from "../core/identities.js";
|
|
4
|
+
|
|
5
|
+
import { $TARGET } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Deferred hydration, dependency edges for stores. Only the frames client
|
|
9
|
+
* imports this module, so nothing here ships without it.
|
|
10
|
+
*
|
|
11
|
+
* A plain store root (`createStore` over an object) is named like a plain
|
|
12
|
+
* signal (core/identities.ts: `<owner id>~<n>`, on the same count), and the
|
|
13
|
+
* whole store goes by that one name: the server records it for any read of
|
|
14
|
+
* the store, at any depth, and a setter call on the store — on its root or
|
|
15
|
+
* on a proxy nested in it — is a write to it. Its readers mount at the
|
|
16
|
+
* setter's entry, before the draft runs, as a plain signal's do.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* @internal The name of the store `x` belongs to — `x` a store proxy (a
|
|
20
|
+
* setter's entry) or one of its property nodes (the setter notifying it) —
|
|
21
|
+
* or undefined when it has none or it cannot be placed: a projection or
|
|
22
|
+
* optimistic family, a store chained over another store's proxy, a root
|
|
23
|
+
* named twice, or a proxy reached through a store other than the one it
|
|
24
|
+
* was named as the root of.
|
|
25
|
+
*/ function storeName(e) {
|
|
26
|
+
if (e === undefined) return undefined;
|
|
27
|
+
let n = e.l & CONFIG_SLOT_NODE ? e.O : e[$TARGET];
|
|
28
|
+
if (n === undefined) return undefined;
|
|
29
|
+
// Up to the root; a target on the way named as a root of its own is one
|
|
30
|
+
// object in two stores.
|
|
31
|
+
while (n.u !== null) {
|
|
32
|
+
if (n.fam !== null || n.ch || signalName(n) !== undefined) return undefined;
|
|
33
|
+
n = n.u;
|
|
34
|
+
}
|
|
35
|
+
if (n.fam !== null || n.ch) return undefined;
|
|
36
|
+
return signalName(n) || undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { storeName };
|