@solidjs/signals 0.9.4 → 0.9.6
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.js +739 -380
- package/dist/node.cjs +1273 -977
- package/dist/prod.js +1132 -796
- package/dist/types/core/constants.d.ts +2 -0
- package/dist/types/core/core.d.ts +12 -14
- package/dist/types/core/effect.d.ts +11 -0
- package/dist/types/core/index.d.ts +3 -3
- package/dist/types/core/scheduler.d.ts +15 -5
- package/dist/types/signals.d.ts +50 -3
- package/dist/types/store/optimistic.d.ts +7 -7
- package/dist/types/store/projection.d.ts +1 -0
- package/dist/types/store/store.d.ts +4 -2
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -25,12 +25,14 @@ const REACTIVE_IN_HEAP = 1 << 3;
|
|
|
25
25
|
const REACTIVE_IN_HEAP_HEIGHT = 1 << 4;
|
|
26
26
|
const REACTIVE_ZOMBIE = 1 << 5;
|
|
27
27
|
const REACTIVE_DISPOSED = 1 << 6;
|
|
28
|
+
const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
|
|
28
29
|
const STATUS_NONE = 0;
|
|
29
30
|
const STATUS_PENDING = 1 << 0;
|
|
30
31
|
const STATUS_ERROR = 1 << 1;
|
|
31
32
|
const STATUS_UNINITIALIZED = 1 << 2;
|
|
32
33
|
const EFFECT_RENDER = 1;
|
|
33
34
|
const EFFECT_USER = 2;
|
|
35
|
+
const EFFECT_TRACKED = 3;
|
|
34
36
|
const NOT_PENDING = {};
|
|
35
37
|
const SUPPORTS_PROXY = typeof Proxy === "function";
|
|
36
38
|
const defaultContext = {};
|
|
@@ -133,20 +135,28 @@ function adjustHeight(el, heap) {
|
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
137
|
const transitions = new Set();
|
|
136
|
-
let optimisticRun = false;
|
|
137
138
|
const dirtyQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
|
|
138
139
|
const zombieQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
|
|
139
140
|
let clock = 0;
|
|
140
141
|
let activeTransition = null;
|
|
141
142
|
let scheduled = false;
|
|
143
|
+
let optimisticReadActive = false;
|
|
144
|
+
let projectionWriteActive = false;
|
|
145
|
+
function setOptimisticReadActive(value) {
|
|
146
|
+
optimisticReadActive = value;
|
|
147
|
+
}
|
|
148
|
+
function setProjectionWriteActive(value) {
|
|
149
|
+
projectionWriteActive = value;
|
|
150
|
+
}
|
|
142
151
|
function schedule() {
|
|
143
152
|
if (scheduled) return;
|
|
144
153
|
scheduled = true;
|
|
145
|
-
if (!globalQueue._running)
|
|
154
|
+
if (!globalQueue._running) queueMicrotask(flush);
|
|
146
155
|
}
|
|
147
156
|
class Queue {
|
|
148
157
|
_parent = null;
|
|
149
158
|
_queues = [[], []];
|
|
159
|
+
_optimisticQueues = [[], []];
|
|
150
160
|
_children = [];
|
|
151
161
|
created = clock;
|
|
152
162
|
addChild(child) {
|
|
@@ -164,18 +174,27 @@ class Queue {
|
|
|
164
174
|
if (this._parent) return this._parent.notify(node, mask, flags);
|
|
165
175
|
return false;
|
|
166
176
|
}
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
const effects =
|
|
170
|
-
|
|
177
|
+
_runQueue(type, queues, method) {
|
|
178
|
+
if (queues[type - 1].length) {
|
|
179
|
+
const effects = queues[type - 1];
|
|
180
|
+
queues[type - 1] = [];
|
|
171
181
|
runQueue(effects, type);
|
|
172
182
|
}
|
|
173
183
|
for (let i = 0; i < this._children.length; i++) {
|
|
174
|
-
this._children[i]
|
|
184
|
+
this._children[i][method]?.(type);
|
|
175
185
|
}
|
|
176
186
|
}
|
|
187
|
+
run(type) {
|
|
188
|
+
this._runQueue(type, this._queues, "run");
|
|
189
|
+
}
|
|
190
|
+
runOptimistic(type) {
|
|
191
|
+
this._runQueue(type, this._optimisticQueues, "runOptimistic");
|
|
192
|
+
}
|
|
177
193
|
enqueue(type, fn) {
|
|
178
|
-
if (type)
|
|
194
|
+
if (type) {
|
|
195
|
+
const queue = optimisticReadActive ? this._optimisticQueues : this._queues;
|
|
196
|
+
queue[type - 1].push(fn);
|
|
197
|
+
}
|
|
179
198
|
schedule();
|
|
180
199
|
}
|
|
181
200
|
stashQueues(stub) {
|
|
@@ -206,38 +225,50 @@ class GlobalQueue extends Queue {
|
|
|
206
225
|
_running = false;
|
|
207
226
|
_pendingNodes = [];
|
|
208
227
|
_optimisticNodes = [];
|
|
228
|
+
_optimisticStores = new Set();
|
|
209
229
|
static _update;
|
|
210
230
|
static _dispose;
|
|
231
|
+
static _clearOptimisticStore = null;
|
|
211
232
|
flush() {
|
|
212
233
|
if (this._running) return;
|
|
213
234
|
this._running = true;
|
|
214
235
|
try {
|
|
215
236
|
runHeap(dirtyQueue, GlobalQueue._update);
|
|
216
237
|
if (activeTransition) {
|
|
217
|
-
|
|
238
|
+
const isComplete = transitionComplete(activeTransition);
|
|
239
|
+
if (!isComplete) {
|
|
218
240
|
let t = activeTransition;
|
|
219
241
|
runHeap(zombieQueue, GlobalQueue._update);
|
|
220
242
|
this._pendingNodes = [];
|
|
243
|
+
this._optimisticNodes = [];
|
|
244
|
+
this._optimisticStores = new Set();
|
|
245
|
+
this.runOptimistic(EFFECT_RENDER);
|
|
246
|
+
this.runOptimistic(EFFECT_USER);
|
|
221
247
|
this.stashQueues(activeTransition.queueStash);
|
|
222
248
|
clock++;
|
|
223
249
|
scheduled = false;
|
|
224
|
-
runTransitionPending(activeTransition.pendingNodes
|
|
250
|
+
runTransitionPending(activeTransition.pendingNodes);
|
|
225
251
|
activeTransition = null;
|
|
226
|
-
|
|
252
|
+
finalizePureQueue(null, true);
|
|
227
253
|
return;
|
|
228
254
|
}
|
|
229
|
-
this._pendingNodes
|
|
230
|
-
|
|
231
|
-
this._optimisticNodes.push(...activeTransition.optimisticNodes);
|
|
255
|
+
this._pendingNodes !== activeTransition.pendingNodes &&
|
|
256
|
+
this._pendingNodes.push(...activeTransition.pendingNodes);
|
|
232
257
|
this.restoreQueues(activeTransition.queueStash);
|
|
233
258
|
transitions.delete(activeTransition);
|
|
259
|
+
const completingTransition = activeTransition;
|
|
234
260
|
activeTransition = null;
|
|
235
|
-
runTransitionPending(this._pendingNodes
|
|
236
|
-
|
|
237
|
-
|
|
261
|
+
runTransitionPending(this._pendingNodes);
|
|
262
|
+
finalizePureQueue(completingTransition);
|
|
263
|
+
} else {
|
|
264
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue._update);
|
|
265
|
+
finalizePureQueue();
|
|
266
|
+
}
|
|
238
267
|
clock++;
|
|
239
|
-
scheduled =
|
|
268
|
+
scheduled = dirtyQueue._max >= dirtyQueue._min;
|
|
269
|
+
this.runOptimistic(EFFECT_RENDER);
|
|
240
270
|
this.run(EFFECT_RENDER);
|
|
271
|
+
this.runOptimistic(EFFECT_USER);
|
|
241
272
|
this.run(EFFECT_USER);
|
|
242
273
|
} finally {
|
|
243
274
|
this._running = false;
|
|
@@ -246,7 +277,11 @@ class GlobalQueue extends Queue {
|
|
|
246
277
|
notify(node, mask, flags) {
|
|
247
278
|
if (mask & STATUS_PENDING) {
|
|
248
279
|
if (flags & STATUS_PENDING) {
|
|
249
|
-
if (
|
|
280
|
+
if (
|
|
281
|
+
activeTransition &&
|
|
282
|
+
node._error &&
|
|
283
|
+
!activeTransition.asyncNodes.includes(node._error.cause)
|
|
284
|
+
) {
|
|
250
285
|
activeTransition.asyncNodes.push(node._error.cause);
|
|
251
286
|
schedule();
|
|
252
287
|
}
|
|
@@ -255,18 +290,26 @@ class GlobalQueue extends Queue {
|
|
|
255
290
|
}
|
|
256
291
|
return false;
|
|
257
292
|
}
|
|
258
|
-
initTransition(
|
|
259
|
-
if (
|
|
293
|
+
initTransition(transition) {
|
|
294
|
+
if (transition) transition = currentTransition(transition);
|
|
295
|
+
if (transition && transition === activeTransition) return;
|
|
296
|
+
if (!transition && activeTransition && activeTransition.time === clock) return;
|
|
260
297
|
if (!activeTransition) {
|
|
261
|
-
activeTransition =
|
|
298
|
+
activeTransition = transition ?? {
|
|
262
299
|
time: clock,
|
|
263
300
|
pendingNodes: [],
|
|
264
301
|
asyncNodes: [],
|
|
265
302
|
optimisticNodes: [],
|
|
303
|
+
optimisticStores: new Set(),
|
|
266
304
|
actions: [],
|
|
267
305
|
queueStash: { _queues: [[], []], _children: [] },
|
|
268
306
|
done: false
|
|
269
307
|
};
|
|
308
|
+
} else if (transition) {
|
|
309
|
+
activeTransition.done = transition;
|
|
310
|
+
transition.actions.push(...activeTransition.actions);
|
|
311
|
+
transitions.delete(activeTransition);
|
|
312
|
+
activeTransition = transition;
|
|
270
313
|
}
|
|
271
314
|
transitions.add(activeTransition);
|
|
272
315
|
activeTransition.time = clock;
|
|
@@ -275,65 +318,86 @@ class GlobalQueue extends Queue {
|
|
|
275
318
|
n._transition = activeTransition;
|
|
276
319
|
activeTransition.pendingNodes.push(n);
|
|
277
320
|
}
|
|
321
|
+
this._pendingNodes = activeTransition.pendingNodes;
|
|
278
322
|
for (let i = 0; i < this._optimisticNodes.length; i++) {
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
activeTransition.optimisticNodes.push(
|
|
323
|
+
const node = this._optimisticNodes[i];
|
|
324
|
+
node._transition = activeTransition;
|
|
325
|
+
activeTransition.optimisticNodes.push(node);
|
|
282
326
|
}
|
|
283
|
-
this._pendingNodes = activeTransition.pendingNodes;
|
|
284
327
|
this._optimisticNodes = activeTransition.optimisticNodes;
|
|
328
|
+
for (const store of this._optimisticStores) {
|
|
329
|
+
activeTransition.optimisticStores.add(store);
|
|
330
|
+
}
|
|
331
|
+
this._optimisticStores = activeTransition.optimisticStores;
|
|
285
332
|
}
|
|
286
333
|
}
|
|
287
|
-
function
|
|
334
|
+
function insertSubs(node, optimistic = false) {
|
|
288
335
|
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
336
|
+
if (optimistic) s._sub._flags |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
337
|
+
const sub = s._sub;
|
|
338
|
+
if (sub._type === EFFECT_TRACKED) {
|
|
339
|
+
if (!sub._modified) {
|
|
340
|
+
sub._modified = true;
|
|
341
|
+
sub._queue.enqueue(EFFECT_USER, sub._run);
|
|
342
|
+
}
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
289
345
|
const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
290
346
|
if (queue._min > s._sub._height) queue._min = s._sub._height;
|
|
291
347
|
insertIntoHeap(s._sub, queue);
|
|
292
348
|
}
|
|
293
349
|
}
|
|
294
|
-
function
|
|
295
|
-
let resolvePending = !
|
|
296
|
-
const optimisticNodes = globalQueue._optimisticNodes;
|
|
297
|
-
optimisticRun = true;
|
|
298
|
-
for (let i = 0; i < optimisticNodes.length; i++) {
|
|
299
|
-
const n = optimisticNodes[i];
|
|
300
|
-
if (
|
|
301
|
-
!activeTransition &&
|
|
302
|
-
(!n._transition || n._transition.done) &&
|
|
303
|
-
n._pendingValue !== NOT_PENDING
|
|
304
|
-
) {
|
|
305
|
-
n._value = n._pendingValue;
|
|
306
|
-
n._pendingValue = NOT_PENDING;
|
|
307
|
-
}
|
|
308
|
-
n._transition = activeTransition;
|
|
309
|
-
notifySubs(n);
|
|
310
|
-
}
|
|
311
|
-
globalQueue._optimisticNodes = [];
|
|
350
|
+
function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
351
|
+
let resolvePending = !incomplete;
|
|
312
352
|
if (dirtyQueue._max >= dirtyQueue._min) {
|
|
313
353
|
resolvePending = true;
|
|
314
354
|
runHeap(dirtyQueue, GlobalQueue._update);
|
|
315
355
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
356
|
+
if (resolvePending) {
|
|
357
|
+
const pendingNodes = globalQueue._pendingNodes;
|
|
358
|
+
for (let i = 0; i < pendingNodes.length; i++) {
|
|
359
|
+
const n = pendingNodes[i];
|
|
360
|
+
if (n._pendingValue !== NOT_PENDING) {
|
|
361
|
+
n._value = n._pendingValue;
|
|
362
|
+
n._pendingValue = NOT_PENDING;
|
|
363
|
+
if (n._type && n._type !== EFFECT_TRACKED) n._modified = true;
|
|
364
|
+
}
|
|
365
|
+
if (n._fn) GlobalQueue._dispose(n, false, true);
|
|
366
|
+
}
|
|
367
|
+
pendingNodes.length = 0;
|
|
368
|
+
const optimisticNodes = completingTransition
|
|
369
|
+
? completingTransition.optimisticNodes
|
|
370
|
+
: globalQueue._optimisticNodes;
|
|
371
|
+
for (let i = 0; i < optimisticNodes.length; i++) {
|
|
372
|
+
const n = optimisticNodes[i];
|
|
373
|
+
const original = n._pendingValue;
|
|
374
|
+
if (original !== NOT_PENDING && n._value !== original) {
|
|
375
|
+
n._value = original;
|
|
376
|
+
insertSubs(n, true);
|
|
377
|
+
}
|
|
324
378
|
n._pendingValue = NOT_PENDING;
|
|
325
|
-
|
|
379
|
+
n._transition = null;
|
|
380
|
+
}
|
|
381
|
+
optimisticNodes.length = 0;
|
|
382
|
+
const optimisticStores = completingTransition
|
|
383
|
+
? completingTransition.optimisticStores
|
|
384
|
+
: globalQueue._optimisticStores;
|
|
385
|
+
if (GlobalQueue._clearOptimisticStore && optimisticStores.size) {
|
|
386
|
+
for (const store of optimisticStores) {
|
|
387
|
+
GlobalQueue._clearOptimisticStore(store);
|
|
388
|
+
}
|
|
389
|
+
optimisticStores.clear();
|
|
390
|
+
schedule();
|
|
326
391
|
}
|
|
327
|
-
if (n._fn) GlobalQueue._dispose(n, false, true);
|
|
328
392
|
}
|
|
329
|
-
pendingNodes.length = 0;
|
|
330
393
|
}
|
|
331
|
-
function
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
394
|
+
function trackOptimisticStore(store) {
|
|
395
|
+
globalQueue._optimisticStores.add(store);
|
|
396
|
+
schedule();
|
|
397
|
+
}
|
|
398
|
+
function runTransitionPending(pendingNodes) {
|
|
399
|
+
for (let i = 0; i < pendingNodes.length; i++) {
|
|
400
|
+
pendingNodes[i]._transition = activeTransition;
|
|
337
401
|
}
|
|
338
402
|
}
|
|
339
403
|
const globalQueue = new GlobalQueue();
|
|
@@ -360,54 +424,81 @@ function transitionComplete(transition) {
|
|
|
360
424
|
done && (transition.done = true);
|
|
361
425
|
return done;
|
|
362
426
|
}
|
|
427
|
+
function currentTransition(transition) {
|
|
428
|
+
while (transition.done && typeof transition.done === "object") transition = transition.done;
|
|
429
|
+
return transition;
|
|
430
|
+
}
|
|
363
431
|
function runInTransition(transition, fn) {
|
|
364
432
|
const prevTransition = activeTransition;
|
|
365
433
|
try {
|
|
366
|
-
activeTransition = transition;
|
|
434
|
+
activeTransition = currentTransition(transition);
|
|
367
435
|
return fn();
|
|
368
436
|
} finally {
|
|
369
437
|
activeTransition = prevTransition;
|
|
370
438
|
}
|
|
371
439
|
}
|
|
440
|
+
function restoreTransition(transition, fn) {
|
|
441
|
+
globalQueue.initTransition(transition);
|
|
442
|
+
const result = fn();
|
|
443
|
+
flush();
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
372
446
|
function action(genFn) {
|
|
373
|
-
return (...args) =>
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const process = result => {
|
|
384
|
-
if (result.done) {
|
|
385
|
-
ctx.actions.splice(ctx.actions.indexOf(iterator), 1);
|
|
447
|
+
return (...args) =>
|
|
448
|
+
new Promise((resolve, reject) => {
|
|
449
|
+
const it = genFn(...args);
|
|
450
|
+
globalQueue.initTransition();
|
|
451
|
+
let ctx = activeTransition;
|
|
452
|
+
ctx.actions.push(it);
|
|
453
|
+
const done = (v, e) => {
|
|
454
|
+
ctx = currentTransition(ctx);
|
|
455
|
+
const i = ctx.actions.indexOf(it);
|
|
456
|
+
if (i >= 0) ctx.actions.splice(i, 1);
|
|
386
457
|
activeTransition = ctx;
|
|
387
458
|
schedule();
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
459
|
+
e ? reject(e) : resolve(v);
|
|
460
|
+
};
|
|
461
|
+
const step = (v, err) => {
|
|
462
|
+
let r;
|
|
463
|
+
try {
|
|
464
|
+
r = err ? it.throw(v) : it.next(v);
|
|
465
|
+
} catch (e) {
|
|
466
|
+
return done(undefined, e);
|
|
467
|
+
}
|
|
468
|
+
if (r instanceof Promise)
|
|
469
|
+
return void r.then(run, e => restoreTransition(ctx, () => step(e, true)));
|
|
470
|
+
run(r);
|
|
471
|
+
};
|
|
472
|
+
const run = r => {
|
|
473
|
+
if (r.done) return done(r.value);
|
|
474
|
+
if (r.value instanceof Promise)
|
|
475
|
+
return void r.value.then(
|
|
476
|
+
v => restoreTransition(ctx, () => step(v)),
|
|
477
|
+
e => restoreTransition(ctx, () => step(e, true))
|
|
478
|
+
);
|
|
479
|
+
restoreTransition(ctx, () => step(r.value));
|
|
480
|
+
};
|
|
481
|
+
step();
|
|
482
|
+
});
|
|
397
483
|
}
|
|
398
484
|
GlobalQueue._update = recompute;
|
|
399
485
|
GlobalQueue._dispose = disposeChildren;
|
|
400
486
|
let tracking = false;
|
|
401
487
|
let stale = false;
|
|
402
|
-
let pendingValueCheck = false;
|
|
403
|
-
let pendingCheck = null;
|
|
404
488
|
let refreshing = false;
|
|
489
|
+
let pendingCheckActive = false;
|
|
490
|
+
let foundPending = false;
|
|
491
|
+
let pendingReadActive = false;
|
|
405
492
|
let context = null;
|
|
493
|
+
let leafEffectActive = false;
|
|
494
|
+
function setLeafEffectActive(v) {
|
|
495
|
+
leafEffectActive = v;
|
|
496
|
+
}
|
|
406
497
|
function recompute(el, create = false) {
|
|
407
|
-
const
|
|
498
|
+
const isEffect = el._type;
|
|
408
499
|
if (!create) {
|
|
409
|
-
if (el._transition && activeTransition !== el._transition
|
|
410
|
-
globalQueue.initTransition(el);
|
|
500
|
+
if (el._transition && (!isEffect || activeTransition) && activeTransition !== el._transition)
|
|
501
|
+
globalQueue.initTransition(el._transition);
|
|
411
502
|
deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
412
503
|
if (el._transition) disposeChildren(el);
|
|
413
504
|
else {
|
|
@@ -418,35 +509,33 @@ function recompute(el, create = false) {
|
|
|
418
509
|
el._firstChild = null;
|
|
419
510
|
}
|
|
420
511
|
}
|
|
512
|
+
const isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
|
|
513
|
+
const hasOptimisticOverride = el._optimistic && el._pendingValue !== NOT_PENDING;
|
|
421
514
|
const oldcontext = context;
|
|
422
515
|
context = el;
|
|
423
516
|
el._depsTail = null;
|
|
424
517
|
el._flags = REACTIVE_RECOMPUTING_DEPS;
|
|
425
518
|
el._time = clock;
|
|
426
|
-
let value =
|
|
427
|
-
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
|
|
428
|
-
? el._value
|
|
429
|
-
: el._pendingValue;
|
|
519
|
+
let value = el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
|
|
430
520
|
let oldHeight = el._height;
|
|
431
|
-
let prevStatusFlags = el._statusFlags;
|
|
432
|
-
let prevError = el._error;
|
|
433
521
|
let prevTracking = tracking;
|
|
434
|
-
|
|
522
|
+
let prevOptimisticRead = optimisticReadActive;
|
|
435
523
|
tracking = true;
|
|
524
|
+
if (isOptimisticDirty) setOptimisticReadActive(true);
|
|
436
525
|
try {
|
|
437
526
|
value = handleAsync(el, el._fn(value));
|
|
438
|
-
el
|
|
527
|
+
clearStatus(el);
|
|
439
528
|
} catch (e) {
|
|
440
529
|
if (e instanceof NotReadyError) {
|
|
441
530
|
if (e.cause !== el) link(e.cause, el);
|
|
442
|
-
|
|
443
|
-
} else
|
|
531
|
+
notifyStatus(el, STATUS_PENDING, e);
|
|
532
|
+
} else notifyStatus(el, STATUS_ERROR, e);
|
|
444
533
|
} finally {
|
|
445
534
|
tracking = prevTracking;
|
|
535
|
+
el._flags = REACTIVE_NONE;
|
|
536
|
+
context = oldcontext;
|
|
446
537
|
}
|
|
447
|
-
el.
|
|
448
|
-
context = oldcontext;
|
|
449
|
-
if (!(el._statusFlags & STATUS_PENDING)) {
|
|
538
|
+
if (!el._error) {
|
|
450
539
|
const depsTail = el._depsTail;
|
|
451
540
|
let toRemove = depsTail !== null ? depsTail._nextDep : el._deps;
|
|
452
541
|
if (toRemove !== null) {
|
|
@@ -456,83 +545,158 @@ function recompute(el, create = false) {
|
|
|
456
545
|
if (depsTail !== null) depsTail._nextDep = null;
|
|
457
546
|
else el._deps = null;
|
|
458
547
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
!el._equals(
|
|
463
|
-
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition) || honoraryOptimistic
|
|
464
|
-
? el._value
|
|
465
|
-
: el._pendingValue,
|
|
466
|
-
value
|
|
467
|
-
);
|
|
468
|
-
const statusFlagsChanged = el._statusFlags !== prevStatusFlags || el._error !== prevError;
|
|
469
|
-
el._notifyQueue?.(statusFlagsChanged, prevStatusFlags);
|
|
470
|
-
if (valueChanged || statusFlagsChanged) {
|
|
548
|
+
const valueChanged =
|
|
549
|
+
!el._equals ||
|
|
550
|
+
!el._equals(el._pendingValue === NOT_PENDING ? el._value : el._pendingValue, value);
|
|
471
551
|
if (valueChanged) {
|
|
472
|
-
if (create ||
|
|
552
|
+
if (create || (isEffect && activeTransition !== el._transition) || isOptimisticDirty)
|
|
553
|
+
el._value = value;
|
|
473
554
|
else el._pendingValue = value;
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
insertIntoHeapHeight(s._sub, s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
555
|
+
insertSubs(el, isOptimisticDirty || hasOptimisticOverride);
|
|
556
|
+
} else if (el._height != oldHeight) {
|
|
557
|
+
for (let s = el._subs; s !== null; s = s._nextSub) {
|
|
558
|
+
insertIntoHeapHeight(s._sub, s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
559
|
+
}
|
|
480
560
|
}
|
|
481
561
|
}
|
|
482
|
-
|
|
562
|
+
setOptimisticReadActive(prevOptimisticRead);
|
|
483
563
|
(!create || el._statusFlags & STATUS_PENDING) &&
|
|
484
564
|
!el._transition &&
|
|
485
565
|
globalQueue._pendingNodes.push(el);
|
|
486
|
-
el._transition &&
|
|
566
|
+
el._transition &&
|
|
567
|
+
isEffect &&
|
|
568
|
+
activeTransition !== el._transition &&
|
|
569
|
+
runInTransition(el._transition, () => recompute(el));
|
|
487
570
|
}
|
|
488
571
|
function handleAsync(el, result, setter) {
|
|
489
572
|
const isObject = typeof result === "object" && result !== null;
|
|
490
|
-
const isPromise = isObject && result instanceof Promise;
|
|
491
573
|
const iterator = isObject && untrack(() => result[Symbol.asyncIterator]);
|
|
492
|
-
|
|
574
|
+
const isThenable = !iterator && isObject && untrack(() => typeof result.then === "function");
|
|
575
|
+
if (!isThenable && !iterator) {
|
|
493
576
|
el._inFlight = null;
|
|
494
577
|
return result;
|
|
495
578
|
}
|
|
496
579
|
el._inFlight = result;
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
580
|
+
let syncValue;
|
|
581
|
+
const handleError = error => {
|
|
582
|
+
if (el._inFlight !== result) return;
|
|
583
|
+
globalQueue.initTransition(el._transition);
|
|
584
|
+
if (error instanceof NotReadyError) {
|
|
585
|
+
if (error.cause !== el) link(error.cause, el);
|
|
586
|
+
notifyStatus(el, STATUS_PENDING, error);
|
|
587
|
+
} else notifyStatus(el, STATUS_ERROR, error);
|
|
588
|
+
el._time = clock;
|
|
589
|
+
};
|
|
590
|
+
const asyncWrite = (value, then) => {
|
|
591
|
+
if (el._inFlight !== result) return;
|
|
592
|
+
globalQueue.initTransition(el._transition);
|
|
593
|
+
clearStatus(el);
|
|
594
|
+
if (setter) setter(value);
|
|
595
|
+
else if (el._optimistic) {
|
|
596
|
+
const hasOverride = el._pendingValue !== NOT_PENDING;
|
|
597
|
+
if (el._fn) el._pendingValue = value;
|
|
598
|
+
if (!hasOverride) {
|
|
599
|
+
el._value = value;
|
|
600
|
+
insertSubs(el);
|
|
601
|
+
}
|
|
602
|
+
el._time = clock;
|
|
603
|
+
schedule();
|
|
604
|
+
} else setSignal(el, () => value);
|
|
605
|
+
flush();
|
|
606
|
+
then?.();
|
|
607
|
+
};
|
|
608
|
+
if (isThenable) {
|
|
609
|
+
let resolved = false,
|
|
610
|
+
isSync = true;
|
|
611
|
+
result.then(
|
|
612
|
+
v => {
|
|
613
|
+
if (isSync) {
|
|
614
|
+
syncValue = v;
|
|
615
|
+
resolved = true;
|
|
616
|
+
} else asyncWrite(v);
|
|
617
|
+
},
|
|
618
|
+
e => {
|
|
619
|
+
if (!isSync) handleError(e);
|
|
620
|
+
}
|
|
621
|
+
);
|
|
622
|
+
isSync = false;
|
|
623
|
+
if (!resolved) {
|
|
624
|
+
globalQueue.initTransition(el._transition);
|
|
625
|
+
throw new NotReadyError(context);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (iterator) {
|
|
629
|
+
const it = result[Symbol.asyncIterator]();
|
|
630
|
+
let hadSyncValue = false;
|
|
631
|
+
const iterate = () => {
|
|
632
|
+
let syncResult,
|
|
633
|
+
resolved = false,
|
|
634
|
+
isSync = true;
|
|
635
|
+
it.next().then(
|
|
636
|
+
r => {
|
|
637
|
+
if (isSync) {
|
|
638
|
+
syncResult = r;
|
|
639
|
+
resolved = true;
|
|
640
|
+
} else if (!r.done) asyncWrite(r.value, iterate);
|
|
641
|
+
},
|
|
642
|
+
e => {
|
|
643
|
+
if (!isSync) handleError(e);
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
isSync = false;
|
|
647
|
+
if (resolved && !syncResult.done) {
|
|
648
|
+
syncValue = syncResult.value;
|
|
649
|
+
hadSyncValue = true;
|
|
650
|
+
return iterate();
|
|
651
|
+
}
|
|
652
|
+
return resolved && syncResult.done;
|
|
653
|
+
};
|
|
654
|
+
const immediatelyDone = iterate();
|
|
655
|
+
if (!hadSyncValue && !immediatelyDone) {
|
|
656
|
+
globalQueue.initTransition(el._transition);
|
|
657
|
+
throw new NotReadyError(context);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return syncValue;
|
|
661
|
+
}
|
|
662
|
+
function clearStatus(el) {
|
|
663
|
+
el._statusFlags = STATUS_NONE;
|
|
664
|
+
el._error = null;
|
|
665
|
+
updatePendingSignal(el);
|
|
666
|
+
if (el._notifyStatus) {
|
|
667
|
+
el._notifyStatus();
|
|
514
668
|
} else {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
globalQueue.initTransition(el);
|
|
520
|
-
setter?.(value) ?? setSignal(el, () => value);
|
|
521
|
-
flush();
|
|
669
|
+
if (!el._transition) {
|
|
670
|
+
for (let s = el._subs; s !== null; s = s._nextSub) {
|
|
671
|
+
if (s._sub._statusFlags & STATUS_PENDING) {
|
|
672
|
+
insertIntoHeap(s._sub, s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
522
673
|
}
|
|
523
|
-
} catch (error) {
|
|
524
|
-
if (el._inFlight !== result) return;
|
|
525
|
-
globalQueue.initTransition(el);
|
|
526
|
-
setStatusFlags(el, STATUS_ERROR, error);
|
|
527
|
-
el._time = clock;
|
|
528
|
-
notifySubs(el);
|
|
529
|
-
schedule();
|
|
530
|
-
flush();
|
|
531
674
|
}
|
|
532
|
-
}
|
|
675
|
+
}
|
|
676
|
+
schedule();
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
function notifyStatus(el, status, error) {
|
|
680
|
+
el._statusFlags = status | (el._statusFlags & STATUS_UNINITIALIZED);
|
|
681
|
+
el._error = error;
|
|
682
|
+
updatePendingSignal(el);
|
|
683
|
+
if (el._notifyStatus) return el._notifyStatus();
|
|
684
|
+
for (let s = el._subs; s !== null; s = s._nextSub) {
|
|
685
|
+
s._sub._time = clock;
|
|
686
|
+
if (s._sub._error !== error) {
|
|
687
|
+
!s._sub._transition && globalQueue._pendingNodes.push(s._sub);
|
|
688
|
+
notifyStatus(s._sub, status, error);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
for (let child = el._child; child !== null; child = child._nextChild) {
|
|
692
|
+
for (let s = child._subs; s !== null; s = s._nextSub) {
|
|
693
|
+
s._sub._time = clock;
|
|
694
|
+
if (s._sub._error !== error) {
|
|
695
|
+
!s._sub._transition && globalQueue._pendingNodes.push(s._sub);
|
|
696
|
+
notifyStatus(s._sub, status, error);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
533
699
|
}
|
|
534
|
-
globalQueue.initTransition(el);
|
|
535
|
-
throw new NotReadyError(context);
|
|
536
700
|
}
|
|
537
701
|
function updateIfNecessary(el) {
|
|
538
702
|
if (el._flags & REACTIVE_CHECK) {
|
|
@@ -614,10 +778,6 @@ function isValidLink(checkLink, sub) {
|
|
|
614
778
|
}
|
|
615
779
|
return false;
|
|
616
780
|
}
|
|
617
|
-
function setStatusFlags(signal, flags, error = null) {
|
|
618
|
-
signal._statusFlags = flags;
|
|
619
|
-
signal._error = error;
|
|
620
|
-
}
|
|
621
781
|
function markDisposal(el) {
|
|
622
782
|
let child = el._firstChild;
|
|
623
783
|
while (child) {
|
|
@@ -720,10 +880,12 @@ function computed(fn, initialValue, options) {
|
|
|
720
880
|
_inFlight: null,
|
|
721
881
|
_transition: null
|
|
722
882
|
};
|
|
723
|
-
if (options?._internal) Object.assign(self, options._internal);
|
|
724
883
|
self._name = options?.name ?? "computed";
|
|
725
884
|
self._prevHeap = self;
|
|
726
885
|
const parent = context?._root ? context._parentComputed : context;
|
|
886
|
+
if (leafEffectActive && context) {
|
|
887
|
+
throw new Error("Cannot create reactive primitives inside createTrackedEffect");
|
|
888
|
+
}
|
|
727
889
|
if (context) {
|
|
728
890
|
const lastChild = context._firstChild;
|
|
729
891
|
if (lastChild === null) {
|
|
@@ -739,14 +901,12 @@ function computed(fn, initialValue, options) {
|
|
|
739
901
|
}
|
|
740
902
|
function signal(v, options, firewall = null) {
|
|
741
903
|
const s = {
|
|
742
|
-
id: options?.id ?? (context?.id != null ? getNextChildId(context) : undefined),
|
|
743
904
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
744
905
|
_pureWrite: !!options?.pureWrite,
|
|
745
906
|
_unobserved: options?.unobserved,
|
|
746
907
|
_value: v,
|
|
747
908
|
_subs: null,
|
|
748
909
|
_subsTail: null,
|
|
749
|
-
_statusFlags: STATUS_NONE,
|
|
750
910
|
_time: clock,
|
|
751
911
|
_firewall: firewall,
|
|
752
912
|
_nextChild: firewall?._child || null,
|
|
@@ -756,6 +916,40 @@ function signal(v, options, firewall = null) {
|
|
|
756
916
|
firewall && (firewall._child = s);
|
|
757
917
|
return s;
|
|
758
918
|
}
|
|
919
|
+
function optimisticSignal(v, options) {
|
|
920
|
+
const s = signal(v, options);
|
|
921
|
+
s._optimistic = true;
|
|
922
|
+
return s;
|
|
923
|
+
}
|
|
924
|
+
function optimisticComputed(fn, initialValue, options) {
|
|
925
|
+
const c = computed(fn, initialValue, options);
|
|
926
|
+
c._optimistic = true;
|
|
927
|
+
return c;
|
|
928
|
+
}
|
|
929
|
+
function getPendingSignal(el) {
|
|
930
|
+
if (!el._pendingSignal) {
|
|
931
|
+
el._pendingSignal = optimisticSignal(false, { pureWrite: true });
|
|
932
|
+
if (computePendingState(el)) setSignal(el._pendingSignal, true);
|
|
933
|
+
}
|
|
934
|
+
return el._pendingSignal;
|
|
935
|
+
}
|
|
936
|
+
function computePendingState(el) {
|
|
937
|
+
if (el._pendingValue !== NOT_PENDING) return true;
|
|
938
|
+
const comp = el;
|
|
939
|
+
return !!(comp._statusFlags & STATUS_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED));
|
|
940
|
+
}
|
|
941
|
+
function getPendingValueComputed(el) {
|
|
942
|
+
if (!el._pendingValueComputed) {
|
|
943
|
+
const prevPending = pendingReadActive;
|
|
944
|
+
pendingReadActive = false;
|
|
945
|
+
el._pendingValueComputed = optimisticComputed(() => read(el));
|
|
946
|
+
pendingReadActive = prevPending;
|
|
947
|
+
}
|
|
948
|
+
return el._pendingValueComputed;
|
|
949
|
+
}
|
|
950
|
+
function updatePendingSignal(el) {
|
|
951
|
+
if (el._pendingSignal) setSignal(el._pendingSignal, computePendingState(el));
|
|
952
|
+
}
|
|
759
953
|
function isEqual(a, b) {
|
|
760
954
|
return a === b;
|
|
761
955
|
}
|
|
@@ -769,10 +963,30 @@ function untrack(fn) {
|
|
|
769
963
|
}
|
|
770
964
|
}
|
|
771
965
|
function read(el) {
|
|
966
|
+
if (pendingCheckActive) {
|
|
967
|
+
const target = el._firewall || el;
|
|
968
|
+
const pendingSig = getPendingSignal(target);
|
|
969
|
+
const prevCheck = pendingCheckActive;
|
|
970
|
+
pendingCheckActive = false;
|
|
971
|
+
if (read(pendingSig)) {
|
|
972
|
+
foundPending = true;
|
|
973
|
+
}
|
|
974
|
+
pendingCheckActive = prevCheck;
|
|
975
|
+
return el._value;
|
|
976
|
+
}
|
|
977
|
+
if (pendingReadActive) {
|
|
978
|
+
const pendingComputed = getPendingValueComputed(el);
|
|
979
|
+
const prevPending = pendingReadActive;
|
|
980
|
+
pendingReadActive = false;
|
|
981
|
+
const value = read(pendingComputed);
|
|
982
|
+
pendingReadActive = prevPending;
|
|
983
|
+
if (pendingComputed._statusFlags & STATUS_PENDING) return el._value;
|
|
984
|
+
return value;
|
|
985
|
+
}
|
|
772
986
|
let c = context;
|
|
773
987
|
if (c?._root) c = c._parentComputed;
|
|
774
988
|
if (refreshing && el._fn) recompute(el);
|
|
775
|
-
if (c && tracking
|
|
989
|
+
if (c && tracking) {
|
|
776
990
|
if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
|
|
777
991
|
link(el, c);
|
|
778
992
|
const owner = el._firewall || el;
|
|
@@ -789,88 +1003,67 @@ function read(el) {
|
|
|
789
1003
|
}
|
|
790
1004
|
}
|
|
791
1005
|
}
|
|
792
|
-
if (pendingValueCheck) {
|
|
793
|
-
if (!el._pendingSignal) {
|
|
794
|
-
el._pendingSignal = signal(el._value);
|
|
795
|
-
el._pendingSignal._optimistic = true;
|
|
796
|
-
}
|
|
797
|
-
pendingValueCheck = false;
|
|
798
|
-
try {
|
|
799
|
-
return read(el._pendingSignal);
|
|
800
|
-
} finally {
|
|
801
|
-
pendingValueCheck = true;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
1006
|
const asyncCompute = el._firewall || el;
|
|
805
|
-
if (
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
prev._value = read(asyncCompute._pendingCheck) || prev._value;
|
|
814
|
-
pendingCheck = prev;
|
|
815
|
-
}
|
|
816
|
-
if (!pendingCheck && asyncCompute._statusFlags & STATUS_PENDING) {
|
|
817
|
-
if ((c && !stale) || asyncCompute._statusFlags & STATUS_UNINITIALIZED || el._firewall)
|
|
818
|
-
throw asyncCompute._error;
|
|
819
|
-
else if (c && stale) {
|
|
820
|
-
setStatusFlags(c, c._statusFlags | STATUS_PENDING, asyncCompute._error);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
if (el._statusFlags & STATUS_ERROR) {
|
|
1007
|
+
if (
|
|
1008
|
+
c &&
|
|
1009
|
+
!optimisticReadActive &&
|
|
1010
|
+
asyncCompute._statusFlags & STATUS_PENDING &&
|
|
1011
|
+
!(stale && asyncCompute._transition && activeTransition !== asyncCompute._transition)
|
|
1012
|
+
)
|
|
1013
|
+
throw asyncCompute._error;
|
|
1014
|
+
if (el._fn && el._statusFlags & STATUS_ERROR) {
|
|
824
1015
|
if (el._time < clock) {
|
|
825
1016
|
recompute(el, true);
|
|
826
1017
|
return read(el);
|
|
827
|
-
} else
|
|
828
|
-
throw el._error;
|
|
829
|
-
}
|
|
1018
|
+
} else throw el._error;
|
|
830
1019
|
}
|
|
831
1020
|
return !c ||
|
|
832
|
-
|
|
1021
|
+
optimisticReadActive ||
|
|
833
1022
|
el._pendingValue === NOT_PENDING ||
|
|
834
|
-
(stale &&
|
|
835
|
-
!pendingCheck &&
|
|
836
|
-
(c._optimistic || (el._transition && activeTransition !== el._transition)))
|
|
1023
|
+
(stale && el._transition && activeTransition !== el._transition)
|
|
837
1024
|
? el._value
|
|
838
1025
|
: el._pendingValue;
|
|
839
1026
|
}
|
|
840
1027
|
function setSignal(el, v) {
|
|
841
1028
|
if (!el._pureWrite && context && el._firewall !== context)
|
|
842
1029
|
console.warn("A Signal was written to in an owned scope.");
|
|
843
|
-
if (
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1030
|
+
if (el._transition && activeTransition !== el._transition)
|
|
1031
|
+
globalQueue.initTransition(el._transition);
|
|
1032
|
+
const isOptimistic = el._optimistic && !projectionWriteActive;
|
|
1033
|
+
const currentValue = isOptimistic
|
|
1034
|
+
? el._value
|
|
1035
|
+
: el._pendingValue === NOT_PENDING
|
|
1036
|
+
? el._value
|
|
1037
|
+
: el._pendingValue;
|
|
1038
|
+
if (typeof v === "function") v = v(currentValue);
|
|
1039
|
+
const valueChanged = !el._equals || !el._equals(currentValue, v);
|
|
1040
|
+
if (!valueChanged) return v;
|
|
1041
|
+
if (isOptimistic) {
|
|
1042
|
+
const isFirstWrite = el._pendingValue === NOT_PENDING;
|
|
1043
|
+
if (el._transition && !isFirstWrite) {
|
|
1044
|
+
globalQueue.initTransition(el._transition);
|
|
1045
|
+
}
|
|
1046
|
+
if (isFirstWrite) {
|
|
1047
|
+
el._pendingValue = el._value;
|
|
1048
|
+
globalQueue._optimisticNodes.push(el);
|
|
1049
|
+
}
|
|
1050
|
+
el._value = v;
|
|
1051
|
+
} else {
|
|
1052
|
+
if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
|
|
1053
|
+
el._pendingValue = v;
|
|
849
1054
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
|
|
854
|
-
? el._value
|
|
855
|
-
: el._pendingValue,
|
|
856
|
-
v
|
|
857
|
-
);
|
|
858
|
-
if (!valueChanged && !el._statusFlags) return v;
|
|
859
|
-
if (valueChanged) {
|
|
860
|
-
if (el._optimistic) el._value = v;
|
|
861
|
-
else {
|
|
862
|
-
if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
|
|
863
|
-
el._pendingValue = v;
|
|
864
|
-
}
|
|
865
|
-
if (el._pendingSignal) setSignal(el._pendingSignal, v);
|
|
1055
|
+
updatePendingSignal(el);
|
|
1056
|
+
if (el._pendingValueComputed) {
|
|
1057
|
+
setSignal(el._pendingValueComputed, v);
|
|
866
1058
|
}
|
|
867
|
-
setStatusFlags(el, STATUS_NONE);
|
|
868
1059
|
el._time = clock;
|
|
869
|
-
|
|
1060
|
+
insertSubs(el, isOptimistic);
|
|
870
1061
|
schedule();
|
|
871
1062
|
return v;
|
|
872
1063
|
}
|
|
1064
|
+
const PENDING_OWNER = {};
|
|
873
1065
|
function getObserver() {
|
|
1066
|
+
if (pendingCheckActive || pendingReadActive) return PENDING_OWNER;
|
|
874
1067
|
return tracking ? context : null;
|
|
875
1068
|
}
|
|
876
1069
|
function getOwner() {
|
|
@@ -878,25 +1071,20 @@ function getOwner() {
|
|
|
878
1071
|
}
|
|
879
1072
|
function onCleanup(fn) {
|
|
880
1073
|
if (!context) return fn;
|
|
881
|
-
|
|
882
|
-
if (
|
|
883
|
-
|
|
884
|
-
} else if (Array.isArray(node._disposal)) {
|
|
885
|
-
node._disposal.push(fn);
|
|
886
|
-
} else {
|
|
887
|
-
node._disposal = [node._disposal, fn];
|
|
888
|
-
}
|
|
1074
|
+
if (!context._disposal) context._disposal = fn;
|
|
1075
|
+
else if (Array.isArray(context._disposal)) context._disposal.push(fn);
|
|
1076
|
+
else context._disposal = [context._disposal, fn];
|
|
889
1077
|
return fn;
|
|
890
1078
|
}
|
|
891
1079
|
function createOwner(options) {
|
|
892
1080
|
const parent = context;
|
|
893
1081
|
const owner = {
|
|
1082
|
+
id: options?.id ?? (parent?.id != null ? getNextChildId(parent) : undefined),
|
|
894
1083
|
_root: true,
|
|
895
1084
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
896
1085
|
_firstChild: null,
|
|
897
1086
|
_nextSibling: null,
|
|
898
1087
|
_disposal: null,
|
|
899
|
-
id: options?.id ?? (parent?.id != null ? getNextChildId(parent) : undefined),
|
|
900
1088
|
_queue: parent?._queue ?? globalQueue,
|
|
901
1089
|
_context: parent?._context || defaultContext,
|
|
902
1090
|
_childCount: 0,
|
|
@@ -907,6 +1095,9 @@ function createOwner(options) {
|
|
|
907
1095
|
disposeChildren(owner, self);
|
|
908
1096
|
}
|
|
909
1097
|
};
|
|
1098
|
+
if (leafEffectActive && parent) {
|
|
1099
|
+
throw new Error("Cannot create reactive primitives inside createTrackedEffect");
|
|
1100
|
+
}
|
|
910
1101
|
if (parent) {
|
|
911
1102
|
const lastChild = parent._firstChild;
|
|
912
1103
|
if (lastChild === null) {
|
|
@@ -924,11 +1115,14 @@ function createRoot(init, options) {
|
|
|
924
1115
|
}
|
|
925
1116
|
function runWithOwner(owner, fn) {
|
|
926
1117
|
const oldContext = context;
|
|
1118
|
+
const prevTracking = tracking;
|
|
927
1119
|
context = owner;
|
|
1120
|
+
tracking = false;
|
|
928
1121
|
try {
|
|
929
1122
|
return fn();
|
|
930
1123
|
} finally {
|
|
931
1124
|
context = oldContext;
|
|
1125
|
+
tracking = prevTracking;
|
|
932
1126
|
}
|
|
933
1127
|
}
|
|
934
1128
|
function staleValues(fn, set = true) {
|
|
@@ -941,25 +1135,25 @@ function staleValues(fn, set = true) {
|
|
|
941
1135
|
}
|
|
942
1136
|
}
|
|
943
1137
|
function pending(fn) {
|
|
944
|
-
const
|
|
945
|
-
|
|
1138
|
+
const prevPending = pendingReadActive;
|
|
1139
|
+
pendingReadActive = true;
|
|
946
1140
|
try {
|
|
947
|
-
return
|
|
1141
|
+
return fn();
|
|
948
1142
|
} finally {
|
|
949
|
-
|
|
1143
|
+
pendingReadActive = prevPending;
|
|
950
1144
|
}
|
|
951
1145
|
}
|
|
952
1146
|
function isPending(fn) {
|
|
953
|
-
const
|
|
954
|
-
|
|
1147
|
+
const prevPendingCheck = pendingCheckActive;
|
|
1148
|
+
const prevFoundPending = foundPending;
|
|
1149
|
+
pendingCheckActive = true;
|
|
1150
|
+
foundPending = false;
|
|
955
1151
|
try {
|
|
956
|
-
|
|
957
|
-
return
|
|
958
|
-
} catch (err) {
|
|
959
|
-
if (!(err instanceof NotReadyError)) return false;
|
|
960
|
-
throw err;
|
|
1152
|
+
fn();
|
|
1153
|
+
return foundPending;
|
|
961
1154
|
} finally {
|
|
962
|
-
|
|
1155
|
+
pendingCheckActive = prevPendingCheck;
|
|
1156
|
+
foundPending = prevFoundPending;
|
|
963
1157
|
}
|
|
964
1158
|
}
|
|
965
1159
|
function refresh(fn) {
|
|
@@ -975,7 +1169,6 @@ function refresh(fn) {
|
|
|
975
1169
|
refreshing = prevRefreshing;
|
|
976
1170
|
if (!prevRefreshing) {
|
|
977
1171
|
schedule();
|
|
978
|
-
flush();
|
|
979
1172
|
}
|
|
980
1173
|
}
|
|
981
1174
|
}
|
|
@@ -1012,54 +1205,50 @@ function isUndefined(value) {
|
|
|
1012
1205
|
}
|
|
1013
1206
|
function effect(compute, effect, error, initialValue, options) {
|
|
1014
1207
|
let initialized = false;
|
|
1015
|
-
const node = computed(
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
if (!this._queue.notify(this, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1050
|
-
} else if (this._type === EFFECT_RENDER) {
|
|
1051
|
-
this._queue.notify(this, STATUS_PENDING | STATUS_ERROR, this._statusFlags);
|
|
1208
|
+
const node = computed(
|
|
1209
|
+
options?.render ? p => staleValues(() => compute(p)) : compute,
|
|
1210
|
+
initialValue,
|
|
1211
|
+
{
|
|
1212
|
+
...options,
|
|
1213
|
+
equals: () => {
|
|
1214
|
+
node._modified = !node._error;
|
|
1215
|
+
if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
|
|
1216
|
+
return false;
|
|
1217
|
+
},
|
|
1218
|
+
lazy: true
|
|
1219
|
+
}
|
|
1220
|
+
);
|
|
1221
|
+
node._prevValue = initialValue;
|
|
1222
|
+
node._effectFn = effect;
|
|
1223
|
+
node._errorFn = error;
|
|
1224
|
+
node._cleanup = undefined;
|
|
1225
|
+
node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
|
|
1226
|
+
node._notifyStatus = () => {
|
|
1227
|
+
if (node._statusFlags & STATUS_ERROR) {
|
|
1228
|
+
let error = node._error;
|
|
1229
|
+
node._queue.notify(node, STATUS_PENDING, 0);
|
|
1230
|
+
if (node._type === EFFECT_USER) {
|
|
1231
|
+
try {
|
|
1232
|
+
return node._errorFn
|
|
1233
|
+
? node._errorFn(error, () => {
|
|
1234
|
+
node._cleanup?.();
|
|
1235
|
+
node._cleanup = undefined;
|
|
1236
|
+
})
|
|
1237
|
+
: console.error(error);
|
|
1238
|
+
} catch (e) {
|
|
1239
|
+
error = e;
|
|
1052
1240
|
}
|
|
1053
1241
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1242
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1243
|
+
} else if (node._type === EFFECT_RENDER)
|
|
1244
|
+
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, node._statusFlags);
|
|
1245
|
+
};
|
|
1246
|
+
recompute(node, true);
|
|
1058
1247
|
!options?.defer &&
|
|
1059
|
-
!(node._statusFlags & (STATUS_ERROR | STATUS_PENDING)) &&
|
|
1060
1248
|
(node._type === EFFECT_USER
|
|
1061
1249
|
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
1062
1250
|
: runEffect.call(node));
|
|
1251
|
+
initialized = true;
|
|
1063
1252
|
onCleanup(() => node._cleanup?.());
|
|
1064
1253
|
if (!node._parent)
|
|
1065
1254
|
console.warn("Effects created outside a reactive context will never be disposed");
|
|
@@ -1077,6 +1266,35 @@ function runEffect() {
|
|
|
1077
1266
|
this._modified = false;
|
|
1078
1267
|
}
|
|
1079
1268
|
}
|
|
1269
|
+
function trackedEffect(fn, options) {
|
|
1270
|
+
const run = () => {
|
|
1271
|
+
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
1272
|
+
node._modified = false;
|
|
1273
|
+
recompute(node);
|
|
1274
|
+
};
|
|
1275
|
+
const node = computed(
|
|
1276
|
+
() => {
|
|
1277
|
+
setLeafEffectActive(true);
|
|
1278
|
+
try {
|
|
1279
|
+
node._cleanup?.();
|
|
1280
|
+
node._cleanup = undefined;
|
|
1281
|
+
node._cleanup = staleValues(fn) || undefined;
|
|
1282
|
+
} finally {
|
|
1283
|
+
setLeafEffectActive(false);
|
|
1284
|
+
}
|
|
1285
|
+
},
|
|
1286
|
+
undefined,
|
|
1287
|
+
{ ...options, lazy: true, pureWrite: true }
|
|
1288
|
+
);
|
|
1289
|
+
node._cleanup = undefined;
|
|
1290
|
+
node._modified = true;
|
|
1291
|
+
node._type = EFFECT_TRACKED;
|
|
1292
|
+
node._run = run;
|
|
1293
|
+
node._queue.enqueue(EFFECT_USER, run);
|
|
1294
|
+
onCleanup(() => node._cleanup?.());
|
|
1295
|
+
if (!node._parent)
|
|
1296
|
+
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1297
|
+
}
|
|
1080
1298
|
function createSignal(first, second, third) {
|
|
1081
1299
|
if (typeof first === "function") {
|
|
1082
1300
|
const node = computed(first, second, third);
|
|
@@ -1090,18 +1308,20 @@ function createMemo(compute, value, options) {
|
|
|
1090
1308
|
return read.bind(null, node);
|
|
1091
1309
|
}
|
|
1092
1310
|
function createEffect(compute, effectFn, value, options) {
|
|
1093
|
-
|
|
1311
|
+
effect(compute, effectFn.effect || effectFn, effectFn.error, value, {
|
|
1094
1312
|
...options,
|
|
1095
1313
|
name: options?.name ?? "effect"
|
|
1096
1314
|
});
|
|
1097
1315
|
}
|
|
1098
1316
|
function createRenderEffect(compute, effectFn, value, options) {
|
|
1099
|
-
|
|
1317
|
+
effect(compute, effectFn, undefined, value, {
|
|
1100
1318
|
render: true,
|
|
1101
1319
|
...{ ...options, name: options?.name ?? "effect" }
|
|
1102
1320
|
});
|
|
1103
1321
|
}
|
|
1104
|
-
function createTrackedEffect(compute, options) {
|
|
1322
|
+
function createTrackedEffect(compute, options) {
|
|
1323
|
+
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
1324
|
+
}
|
|
1105
1325
|
function createReaction(effectFn, options) {
|
|
1106
1326
|
let cleanup = undefined;
|
|
1107
1327
|
onCleanup(() => cleanup?.());
|
|
@@ -1138,39 +1358,19 @@ function resolve(fn) {
|
|
|
1138
1358
|
});
|
|
1139
1359
|
}
|
|
1140
1360
|
function createOptimistic(first, second, third) {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
if (n._statusFlags & STATUS_UNINITIALIZED) return value;
|
|
1147
|
-
n._pendingValue = value;
|
|
1148
|
-
return prev;
|
|
1149
|
-
},
|
|
1150
|
-
second,
|
|
1151
|
-
third
|
|
1152
|
-
);
|
|
1153
|
-
node._optimistic = true;
|
|
1154
|
-
return [read.bind(null, node), setSignal.bind(null, node)];
|
|
1155
|
-
}
|
|
1156
|
-
const node = signal(first, second);
|
|
1157
|
-
node._optimistic = true;
|
|
1158
|
-
return [
|
|
1159
|
-
read.bind(null, node),
|
|
1160
|
-
v => {
|
|
1161
|
-
node._pendingValue = first;
|
|
1162
|
-
return setSignal(node, v);
|
|
1163
|
-
}
|
|
1164
|
-
];
|
|
1361
|
+
const node =
|
|
1362
|
+
typeof first === "function"
|
|
1363
|
+
? optimisticComputed(first, second, third)
|
|
1364
|
+
: optimisticSignal(first, second);
|
|
1365
|
+
return [read.bind(null, node), setSignal.bind(null, node)];
|
|
1165
1366
|
}
|
|
1166
1367
|
function onSettled(callback) {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
});
|
|
1368
|
+
getOwner()
|
|
1369
|
+
? createTrackedEffect(() => untrack(callback))
|
|
1370
|
+
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
1371
|
+
const cleanup = callback();
|
|
1372
|
+
cleanup?.();
|
|
1373
|
+
});
|
|
1174
1374
|
}
|
|
1175
1375
|
function unwrap(value) {
|
|
1176
1376
|
return value?.[$TARGET]?.[STORE_NODE] ?? value;
|
|
@@ -1339,12 +1539,12 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
1339
1539
|
const owner = getOwner();
|
|
1340
1540
|
storeSetter(new Proxy(wrappedStore, writeTraps), s => {
|
|
1341
1541
|
const value = handleAsync(owner, fn(s), value => {
|
|
1342
|
-
value !==
|
|
1542
|
+
value !== s &&
|
|
1343
1543
|
value !== undefined &&
|
|
1344
1544
|
storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
|
|
1345
1545
|
setSignal(owner, undefined);
|
|
1346
1546
|
});
|
|
1347
|
-
value !==
|
|
1547
|
+
value !== s &&
|
|
1348
1548
|
value !== undefined &&
|
|
1349
1549
|
reconcile(value, options?.key || "id", options?.all)(wrappedStore);
|
|
1350
1550
|
});
|
|
@@ -1359,28 +1559,34 @@ const writeTraps = {
|
|
|
1359
1559
|
get(_, prop) {
|
|
1360
1560
|
let value;
|
|
1361
1561
|
setWriteOverride(true);
|
|
1562
|
+
setProjectionWriteActive(true);
|
|
1362
1563
|
try {
|
|
1363
1564
|
value = _[prop];
|
|
1364
1565
|
} finally {
|
|
1365
1566
|
setWriteOverride(false);
|
|
1567
|
+
setProjectionWriteActive(false);
|
|
1366
1568
|
}
|
|
1367
1569
|
return typeof value === "object" && value !== null ? new Proxy(value, writeTraps) : value;
|
|
1368
1570
|
},
|
|
1369
1571
|
set(_, prop, value) {
|
|
1370
1572
|
setWriteOverride(true);
|
|
1573
|
+
setProjectionWriteActive(true);
|
|
1371
1574
|
try {
|
|
1372
1575
|
_[prop] = value;
|
|
1373
1576
|
} finally {
|
|
1374
1577
|
setWriteOverride(false);
|
|
1578
|
+
setProjectionWriteActive(false);
|
|
1375
1579
|
}
|
|
1376
1580
|
return true;
|
|
1377
1581
|
},
|
|
1378
1582
|
deleteProperty(_, prop) {
|
|
1379
1583
|
setWriteOverride(true);
|
|
1584
|
+
setProjectionWriteActive(true);
|
|
1380
1585
|
try {
|
|
1381
1586
|
delete _[prop];
|
|
1382
1587
|
} finally {
|
|
1383
1588
|
setWriteOverride(false);
|
|
1589
|
+
setProjectionWriteActive(false);
|
|
1384
1590
|
}
|
|
1385
1591
|
return true;
|
|
1386
1592
|
}
|
|
@@ -1393,11 +1599,13 @@ const $TRACK = Symbol("STORE_TRACK"),
|
|
|
1393
1599
|
const PARENTS = new WeakMap();
|
|
1394
1600
|
const STORE_VALUE = "v",
|
|
1395
1601
|
STORE_OVERRIDE = "o",
|
|
1602
|
+
STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
1396
1603
|
STORE_NODE = "n",
|
|
1397
1604
|
STORE_HAS = "h",
|
|
1398
1605
|
STORE_WRAP = "w",
|
|
1399
1606
|
STORE_LOOKUP = "l",
|
|
1400
|
-
STORE_FIREWALL = "f"
|
|
1607
|
+
STORE_FIREWALL = "f",
|
|
1608
|
+
STORE_OPTIMISTIC = "p";
|
|
1401
1609
|
function createStoreProxy(value, traps = storeTraps, extend) {
|
|
1402
1610
|
let newTarget;
|
|
1403
1611
|
if (Array.isArray(value)) {
|
|
@@ -1429,9 +1637,9 @@ function getNodes(target, type) {
|
|
|
1429
1637
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
1430
1638
|
return nodes;
|
|
1431
1639
|
}
|
|
1432
|
-
function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
1640
|
+
function getNode(nodes, property, value, firewall, equals = isEqual, optimistic) {
|
|
1433
1641
|
if (nodes[property]) return nodes[property];
|
|
1434
|
-
|
|
1642
|
+
const s = signal(
|
|
1435
1643
|
value,
|
|
1436
1644
|
{
|
|
1437
1645
|
equals: equals,
|
|
@@ -1440,11 +1648,22 @@ function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
|
1440
1648
|
}
|
|
1441
1649
|
},
|
|
1442
1650
|
firewall
|
|
1443
|
-
)
|
|
1651
|
+
);
|
|
1652
|
+
if (optimistic) s._optimistic = true;
|
|
1653
|
+
return (nodes[property] = s);
|
|
1444
1654
|
}
|
|
1445
1655
|
function trackSelf(target, symbol = $TRACK) {
|
|
1446
1656
|
getObserver() &&
|
|
1447
|
-
read(
|
|
1657
|
+
read(
|
|
1658
|
+
getNode(
|
|
1659
|
+
getNodes(target, STORE_NODE),
|
|
1660
|
+
symbol,
|
|
1661
|
+
undefined,
|
|
1662
|
+
target[STORE_FIREWALL],
|
|
1663
|
+
false,
|
|
1664
|
+
target[STORE_OPTIMISTIC]
|
|
1665
|
+
)
|
|
1666
|
+
);
|
|
1448
1667
|
}
|
|
1449
1668
|
function getKeys(source, override, enumerable = true) {
|
|
1450
1669
|
const baseKeys = untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)));
|
|
@@ -1477,9 +1696,16 @@ const storeTraps = {
|
|
|
1477
1696
|
}
|
|
1478
1697
|
const nodes = getNodes(target, STORE_NODE);
|
|
1479
1698
|
const tracked = nodes[property];
|
|
1480
|
-
const
|
|
1699
|
+
const optOverridden =
|
|
1700
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE];
|
|
1701
|
+
const overridden =
|
|
1702
|
+
optOverridden || (target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]);
|
|
1481
1703
|
const proxySource = !!target[STORE_VALUE][$TARGET];
|
|
1482
|
-
const storeValue =
|
|
1704
|
+
const storeValue = optOverridden
|
|
1705
|
+
? target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1706
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1707
|
+
? target[STORE_OVERRIDE]
|
|
1708
|
+
: target[STORE_VALUE];
|
|
1483
1709
|
if (!tracked) {
|
|
1484
1710
|
const desc = Object.getOwnPropertyDescriptor(storeValue, property);
|
|
1485
1711
|
if (desc && desc.get) return desc.get.call(receiver);
|
|
@@ -1488,7 +1714,9 @@ const storeTraps = {
|
|
|
1488
1714
|
let value =
|
|
1489
1715
|
tracked && (overridden || !proxySource)
|
|
1490
1716
|
? tracked._pendingValue !== NOT_PENDING
|
|
1491
|
-
? tracked.
|
|
1717
|
+
? tracked._optimistic
|
|
1718
|
+
? tracked._value
|
|
1719
|
+
: tracked._pendingValue
|
|
1492
1720
|
: tracked._value
|
|
1493
1721
|
: storeValue[property];
|
|
1494
1722
|
value === $DELETED && (value = undefined);
|
|
@@ -1517,7 +1745,9 @@ const storeTraps = {
|
|
|
1517
1745
|
nodes,
|
|
1518
1746
|
property,
|
|
1519
1747
|
isWrappable(value) ? wrap(value, target) : value,
|
|
1520
|
-
target[STORE_FIREWALL]
|
|
1748
|
+
target[STORE_FIREWALL],
|
|
1749
|
+
isEqual,
|
|
1750
|
+
target[STORE_OPTIMISTIC]
|
|
1521
1751
|
)
|
|
1522
1752
|
);
|
|
1523
1753
|
}
|
|
@@ -1527,30 +1757,53 @@ const storeTraps = {
|
|
|
1527
1757
|
has(target, property) {
|
|
1528
1758
|
if (property === $PROXY || property === $TRACK || property === "__proto__") return true;
|
|
1529
1759
|
const has =
|
|
1530
|
-
target[
|
|
1531
|
-
? target[
|
|
1532
|
-
: property in target[
|
|
1760
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1761
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
|
|
1762
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1763
|
+
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
1764
|
+
: property in target[STORE_VALUE];
|
|
1533
1765
|
getObserver() &&
|
|
1534
|
-
read(
|
|
1766
|
+
read(
|
|
1767
|
+
getNode(
|
|
1768
|
+
getNodes(target, STORE_HAS),
|
|
1769
|
+
property,
|
|
1770
|
+
has,
|
|
1771
|
+
target[STORE_FIREWALL],
|
|
1772
|
+
isEqual,
|
|
1773
|
+
target[STORE_OPTIMISTIC]
|
|
1774
|
+
)
|
|
1775
|
+
);
|
|
1535
1776
|
return has;
|
|
1536
1777
|
},
|
|
1537
1778
|
set(target, property, rawValue) {
|
|
1538
1779
|
const store = target[$PROXY];
|
|
1539
1780
|
if (writeOnly(store)) {
|
|
1781
|
+
if (target[STORE_OPTIMISTIC]) {
|
|
1782
|
+
const firewall = target[STORE_FIREWALL];
|
|
1783
|
+
if (firewall?._transition) {
|
|
1784
|
+
globalQueue.initTransition(firewall._transition);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1540
1787
|
untrack(() => {
|
|
1541
1788
|
const state = target[STORE_VALUE];
|
|
1542
1789
|
const base = state[property];
|
|
1790
|
+
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
1791
|
+
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
1792
|
+
if (useOptimistic) trackOptimisticStore(store);
|
|
1543
1793
|
const prev =
|
|
1544
|
-
target[
|
|
1545
|
-
? target[
|
|
1546
|
-
:
|
|
1794
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1795
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property]
|
|
1796
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1797
|
+
? target[STORE_OVERRIDE][property]
|
|
1798
|
+
: base;
|
|
1547
1799
|
const value = rawValue?.[$TARGET]?.[STORE_VALUE] ?? rawValue;
|
|
1548
1800
|
if (prev === value) return true;
|
|
1549
|
-
const len =
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1801
|
+
const len =
|
|
1802
|
+
target[STORE_OPTIMISTIC_OVERRIDE]?.length ||
|
|
1803
|
+
target[STORE_OVERRIDE]?.length ||
|
|
1804
|
+
state.length;
|
|
1805
|
+
if (value !== undefined && value === base) delete target[overrideKey][property];
|
|
1806
|
+
else (target[overrideKey] || (target[overrideKey] = Object.create(null)))[property] = value;
|
|
1554
1807
|
const wrappable = isWrappable(value);
|
|
1555
1808
|
if (isWrappable(prev)) {
|
|
1556
1809
|
const parents = PARENTS.get(prev);
|
|
@@ -1562,8 +1815,12 @@ const storeTraps = {
|
|
|
1562
1815
|
nodes[property] &&
|
|
1563
1816
|
setSignal(nodes[property], () => (wrappable ? wrap(value, target) : value));
|
|
1564
1817
|
if (Array.isArray(state)) {
|
|
1565
|
-
|
|
1566
|
-
|
|
1818
|
+
if (property === "length") {
|
|
1819
|
+
nodes.length && setSignal(nodes.length, value);
|
|
1820
|
+
} else {
|
|
1821
|
+
const index = parseInt(property) + 1;
|
|
1822
|
+
if (index > len) nodes.length && setSignal(nodes.length, index);
|
|
1823
|
+
}
|
|
1567
1824
|
}
|
|
1568
1825
|
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
1569
1826
|
});
|
|
@@ -1571,17 +1828,26 @@ const storeTraps = {
|
|
|
1571
1828
|
return true;
|
|
1572
1829
|
},
|
|
1573
1830
|
deleteProperty(target, property) {
|
|
1574
|
-
|
|
1831
|
+
const optDeleted = target[STORE_OPTIMISTIC_OVERRIDE]?.[property] === $DELETED;
|
|
1832
|
+
const regDeleted = target[STORE_OVERRIDE]?.[property] === $DELETED;
|
|
1833
|
+
if (writeOnly(target[$PROXY]) && !optDeleted && !regDeleted) {
|
|
1575
1834
|
untrack(() => {
|
|
1835
|
+
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
1836
|
+
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
1837
|
+
if (useOptimistic) trackOptimisticStore(target[$PROXY]);
|
|
1576
1838
|
const prev =
|
|
1577
|
-
target[
|
|
1578
|
-
? target[
|
|
1579
|
-
: target[
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1839
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1840
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property]
|
|
1841
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1842
|
+
? target[STORE_OVERRIDE][property]
|
|
1843
|
+
: target[STORE_VALUE][property];
|
|
1844
|
+
if (
|
|
1845
|
+
property in target[STORE_VALUE] ||
|
|
1846
|
+
(target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE])
|
|
1847
|
+
) {
|
|
1848
|
+
(target[overrideKey] || (target[overrideKey] = Object.create(null)))[property] = $DELETED;
|
|
1849
|
+
} else if (target[overrideKey] && property in target[overrideKey]) {
|
|
1850
|
+
delete target[overrideKey][property];
|
|
1585
1851
|
} else return true;
|
|
1586
1852
|
if (isWrappable(prev)) {
|
|
1587
1853
|
const parents = PARENTS.get(prev);
|
|
@@ -1597,10 +1863,32 @@ const storeTraps = {
|
|
|
1597
1863
|
},
|
|
1598
1864
|
ownKeys(target) {
|
|
1599
1865
|
trackSelf(target);
|
|
1600
|
-
|
|
1866
|
+
let keys = getKeys(target[STORE_VALUE], target[STORE_OVERRIDE], false);
|
|
1867
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
1868
|
+
const keySet = new Set(keys);
|
|
1869
|
+
for (const key of Reflect.ownKeys(target[STORE_OPTIMISTIC_OVERRIDE])) {
|
|
1870
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE][key] !== $DELETED) keySet.add(key);
|
|
1871
|
+
else keySet.delete(key);
|
|
1872
|
+
}
|
|
1873
|
+
keys = Array.from(keySet);
|
|
1874
|
+
}
|
|
1875
|
+
return keys;
|
|
1601
1876
|
},
|
|
1602
1877
|
getOwnPropertyDescriptor(target, property) {
|
|
1603
1878
|
if (property === $PROXY) return { value: target[$PROXY], writable: true, configurable: true };
|
|
1879
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
1880
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE][property] === $DELETED) return undefined;
|
|
1881
|
+
const baseDesc = getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
|
|
1882
|
+
if (baseDesc) {
|
|
1883
|
+
return { ...baseDesc, value: target[STORE_OPTIMISTIC_OVERRIDE][property] };
|
|
1884
|
+
}
|
|
1885
|
+
return {
|
|
1886
|
+
value: target[STORE_OPTIMISTIC_OVERRIDE][property],
|
|
1887
|
+
writable: true,
|
|
1888
|
+
enumerable: true,
|
|
1889
|
+
configurable: true
|
|
1890
|
+
};
|
|
1891
|
+
}
|
|
1604
1892
|
return getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
|
|
1605
1893
|
},
|
|
1606
1894
|
getPrototypeOf(target) {
|
|
@@ -1689,7 +1977,82 @@ function deep(store) {
|
|
|
1689
1977
|
return store[$DEEP];
|
|
1690
1978
|
}
|
|
1691
1979
|
function createOptimisticStore(first, second, options) {
|
|
1692
|
-
|
|
1980
|
+
GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
|
|
1981
|
+
const derived = typeof first === "function";
|
|
1982
|
+
const initialValue = (derived ? second : first) ?? {};
|
|
1983
|
+
const fn = derived ? first : undefined;
|
|
1984
|
+
const { store: wrappedStore } = createOptimisticProjectionInternal(fn, initialValue, options);
|
|
1985
|
+
return [wrappedStore, fn => storeSetter(wrappedStore, fn)];
|
|
1986
|
+
}
|
|
1987
|
+
function clearOptimisticStore(store) {
|
|
1988
|
+
const target = store[$TARGET];
|
|
1989
|
+
if (!target || !target[STORE_OPTIMISTIC_OVERRIDE]) return;
|
|
1990
|
+
const override = target[STORE_OPTIMISTIC_OVERRIDE];
|
|
1991
|
+
const nodes = target[STORE_NODE];
|
|
1992
|
+
if (nodes) {
|
|
1993
|
+
for (const key of Reflect.ownKeys(override)) {
|
|
1994
|
+
if (nodes[key]) {
|
|
1995
|
+
const baseValue =
|
|
1996
|
+
target[STORE_OVERRIDE] && key in target[STORE_OVERRIDE]
|
|
1997
|
+
? target[STORE_OVERRIDE][key]
|
|
1998
|
+
: target[STORE_VALUE][key];
|
|
1999
|
+
const value = baseValue === $DELETED ? undefined : baseValue;
|
|
2000
|
+
setSignal(nodes[key], isWrappable(value) ? wrap(value, target) : value);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
2004
|
+
}
|
|
2005
|
+
delete target[STORE_OPTIMISTIC_OVERRIDE];
|
|
2006
|
+
}
|
|
2007
|
+
function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
|
|
2008
|
+
let node;
|
|
2009
|
+
const wrappedMap = new WeakMap();
|
|
2010
|
+
const wrapper = s => {
|
|
2011
|
+
s[STORE_WRAP] = wrapProjection;
|
|
2012
|
+
s[STORE_LOOKUP] = wrappedMap;
|
|
2013
|
+
s[STORE_OPTIMISTIC] = true;
|
|
2014
|
+
Object.defineProperty(s, STORE_FIREWALL, {
|
|
2015
|
+
get() {
|
|
2016
|
+
return node;
|
|
2017
|
+
},
|
|
2018
|
+
configurable: true
|
|
2019
|
+
});
|
|
2020
|
+
};
|
|
2021
|
+
const wrapProjection = source => {
|
|
2022
|
+
if (wrappedMap.has(source)) return wrappedMap.get(source);
|
|
2023
|
+
if (source[$TARGET]?.[STORE_WRAP] === wrapProjection) return source;
|
|
2024
|
+
const wrapped = createStoreProxy(source, storeTraps, wrapper);
|
|
2025
|
+
wrappedMap.set(source, wrapped);
|
|
2026
|
+
return wrapped;
|
|
2027
|
+
};
|
|
2028
|
+
const wrappedStore = wrapProjection(initialValue);
|
|
2029
|
+
if (fn) {
|
|
2030
|
+
node = computed(() => {
|
|
2031
|
+
const owner = getOwner();
|
|
2032
|
+
setProjectionWriteActive(true);
|
|
2033
|
+
try {
|
|
2034
|
+
storeSetter(new Proxy(wrappedStore, writeTraps), s => {
|
|
2035
|
+
const value = handleAsync(owner, fn(s), value => {
|
|
2036
|
+
setProjectionWriteActive(true);
|
|
2037
|
+
try {
|
|
2038
|
+
value !== s &&
|
|
2039
|
+
value !== undefined &&
|
|
2040
|
+
storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
|
|
2041
|
+
} finally {
|
|
2042
|
+
setProjectionWriteActive(false);
|
|
2043
|
+
}
|
|
2044
|
+
});
|
|
2045
|
+
value !== s &&
|
|
2046
|
+
value !== undefined &&
|
|
2047
|
+
reconcile(value, options?.key || "id", options?.all)(wrappedStore);
|
|
2048
|
+
});
|
|
2049
|
+
} finally {
|
|
2050
|
+
setProjectionWriteActive(false);
|
|
2051
|
+
}
|
|
2052
|
+
});
|
|
2053
|
+
node._preventAutoDisposal = true;
|
|
2054
|
+
}
|
|
2055
|
+
return { store: wrappedStore, node: node };
|
|
1693
2056
|
}
|
|
1694
2057
|
function snapshot(item, map, lookup) {
|
|
1695
2058
|
let target, isArray, override, result, unwrapped, v;
|
|
@@ -2084,21 +2447,15 @@ function compare(key, a, b) {
|
|
|
2084
2447
|
return key ? key(a) === key(b) : true;
|
|
2085
2448
|
}
|
|
2086
2449
|
function boundaryComputed(fn, propagationMask) {
|
|
2087
|
-
const node = computed(fn, undefined, {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
flags &= ~STATUS_PENDING;
|
|
2094
|
-
}
|
|
2095
|
-
this._queue.notify(this, this._propagationMask, flags);
|
|
2096
|
-
},
|
|
2097
|
-
_propagationMask: propagationMask
|
|
2098
|
-
}
|
|
2099
|
-
});
|
|
2450
|
+
const node = computed(fn, undefined, { lazy: true });
|
|
2451
|
+
node._notifyStatus = () => {
|
|
2452
|
+
const flags = node._statusFlags;
|
|
2453
|
+
node._statusFlags &= ~node._propagationMask;
|
|
2454
|
+
node._queue.notify(node, node._propagationMask, flags);
|
|
2455
|
+
};
|
|
2100
2456
|
node._propagationMask = propagationMask;
|
|
2101
2457
|
node._preventAutoDisposal = true;
|
|
2458
|
+
recompute(node, true);
|
|
2102
2459
|
return node;
|
|
2103
2460
|
}
|
|
2104
2461
|
function createBoundChildren(owner, fn, queue, mask) {
|
|
@@ -2198,8 +2555,10 @@ function createCollectionBoundary(type, fn, fallback) {
|
|
|
2198
2555
|
const decision = computed(() => {
|
|
2199
2556
|
if (!read(queue._disabled)) {
|
|
2200
2557
|
const resolved = read(tree);
|
|
2201
|
-
if (!untrack(() => read(queue._disabled)))
|
|
2202
|
-
|
|
2558
|
+
if (!untrack(() => read(queue._disabled))) {
|
|
2559
|
+
queue._initialized = true;
|
|
2560
|
+
return resolved;
|
|
2561
|
+
}
|
|
2203
2562
|
}
|
|
2204
2563
|
return fallback(queue);
|
|
2205
2564
|
});
|