@solidjs/signals 0.9.5 → 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 +715 -380
- package/dist/node.cjs +1259 -984
- package/dist/prod.js +1114 -799
- 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 +14 -4
- 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,39 +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
255
|
this._pendingNodes !== activeTransition.pendingNodes &&
|
|
230
256
|
this._pendingNodes.push(...activeTransition.pendingNodes);
|
|
231
|
-
this._optimisticNodes !== activeTransition.optimisticNodes &&
|
|
232
|
-
this._optimisticNodes.push(...activeTransition.optimisticNodes);
|
|
233
257
|
this.restoreQueues(activeTransition.queueStash);
|
|
234
258
|
transitions.delete(activeTransition);
|
|
259
|
+
const completingTransition = activeTransition;
|
|
235
260
|
activeTransition = null;
|
|
236
|
-
runTransitionPending(this._pendingNodes
|
|
237
|
-
|
|
238
|
-
|
|
261
|
+
runTransitionPending(this._pendingNodes);
|
|
262
|
+
finalizePureQueue(completingTransition);
|
|
263
|
+
} else {
|
|
264
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue._update);
|
|
265
|
+
finalizePureQueue();
|
|
266
|
+
}
|
|
239
267
|
clock++;
|
|
240
|
-
scheduled =
|
|
268
|
+
scheduled = dirtyQueue._max >= dirtyQueue._min;
|
|
269
|
+
this.runOptimistic(EFFECT_RENDER);
|
|
241
270
|
this.run(EFFECT_RENDER);
|
|
271
|
+
this.runOptimistic(EFFECT_USER);
|
|
242
272
|
this.run(EFFECT_USER);
|
|
243
273
|
} finally {
|
|
244
274
|
this._running = false;
|
|
@@ -247,7 +277,11 @@ class GlobalQueue extends Queue {
|
|
|
247
277
|
notify(node, mask, flags) {
|
|
248
278
|
if (mask & STATUS_PENDING) {
|
|
249
279
|
if (flags & STATUS_PENDING) {
|
|
250
|
-
if (
|
|
280
|
+
if (
|
|
281
|
+
activeTransition &&
|
|
282
|
+
node._error &&
|
|
283
|
+
!activeTransition.asyncNodes.includes(node._error.cause)
|
|
284
|
+
) {
|
|
251
285
|
activeTransition.asyncNodes.push(node._error.cause);
|
|
252
286
|
schedule();
|
|
253
287
|
}
|
|
@@ -266,6 +300,7 @@ class GlobalQueue extends Queue {
|
|
|
266
300
|
pendingNodes: [],
|
|
267
301
|
asyncNodes: [],
|
|
268
302
|
optimisticNodes: [],
|
|
303
|
+
optimisticStores: new Set(),
|
|
269
304
|
actions: [],
|
|
270
305
|
queueStash: { _queues: [[], []], _children: [] },
|
|
271
306
|
done: false
|
|
@@ -283,68 +318,86 @@ class GlobalQueue extends Queue {
|
|
|
283
318
|
n._transition = activeTransition;
|
|
284
319
|
activeTransition.pendingNodes.push(n);
|
|
285
320
|
}
|
|
321
|
+
this._pendingNodes = activeTransition.pendingNodes;
|
|
286
322
|
for (let i = 0; i < this._optimisticNodes.length; i++) {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
activeTransition.optimisticNodes.push(
|
|
323
|
+
const node = this._optimisticNodes[i];
|
|
324
|
+
node._transition = activeTransition;
|
|
325
|
+
activeTransition.optimisticNodes.push(node);
|
|
290
326
|
}
|
|
291
|
-
this._pendingNodes = activeTransition.pendingNodes;
|
|
292
327
|
this._optimisticNodes = activeTransition.optimisticNodes;
|
|
328
|
+
for (const store of this._optimisticStores) {
|
|
329
|
+
activeTransition.optimisticStores.add(store);
|
|
330
|
+
}
|
|
331
|
+
this._optimisticStores = activeTransition.optimisticStores;
|
|
293
332
|
}
|
|
294
333
|
}
|
|
295
|
-
function
|
|
334
|
+
function insertSubs(node, optimistic = false) {
|
|
296
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
|
+
}
|
|
297
345
|
const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
298
346
|
if (queue._min > s._sub._height) queue._min = s._sub._height;
|
|
299
347
|
insertIntoHeap(s._sub, queue);
|
|
300
348
|
}
|
|
301
349
|
}
|
|
302
|
-
function
|
|
303
|
-
let resolvePending = !
|
|
304
|
-
const optimisticNodes = globalQueue._optimisticNodes;
|
|
305
|
-
optimisticRun = true;
|
|
306
|
-
for (let i = 0; i < optimisticNodes.length; i++) {
|
|
307
|
-
const n = optimisticNodes[i];
|
|
308
|
-
if (
|
|
309
|
-
!activeTransition &&
|
|
310
|
-
(!n._transition || n._transition.done) &&
|
|
311
|
-
n._pendingValue !== NOT_PENDING
|
|
312
|
-
) {
|
|
313
|
-
n._value = n._pendingValue;
|
|
314
|
-
n._pendingValue = NOT_PENDING;
|
|
315
|
-
}
|
|
316
|
-
n._transition = activeTransition;
|
|
317
|
-
notifySubs(n);
|
|
318
|
-
}
|
|
319
|
-
globalQueue._optimisticNodes = [];
|
|
350
|
+
function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
351
|
+
let resolvePending = !incomplete;
|
|
320
352
|
if (dirtyQueue._max >= dirtyQueue._min) {
|
|
321
353
|
resolvePending = true;
|
|
322
354
|
runHeap(dirtyQueue, GlobalQueue._update);
|
|
323
355
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
+
}
|
|
332
378
|
n._pendingValue = NOT_PENDING;
|
|
333
|
-
|
|
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();
|
|
334
391
|
}
|
|
335
|
-
if (n._fn) GlobalQueue._dispose(n, false, true);
|
|
336
392
|
}
|
|
337
|
-
pendingNodes.length = 0;
|
|
338
393
|
}
|
|
339
|
-
function
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
n._pendingCheck._set(value);
|
|
347
|
-
}
|
|
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;
|
|
348
401
|
}
|
|
349
402
|
}
|
|
350
403
|
const globalQueue = new GlobalQueue();
|
|
@@ -377,7 +430,6 @@ function currentTransition(transition) {
|
|
|
377
430
|
}
|
|
378
431
|
function runInTransition(transition, fn) {
|
|
379
432
|
const prevTransition = activeTransition;
|
|
380
|
-
activeTransition = null;
|
|
381
433
|
try {
|
|
382
434
|
activeTransition = currentTransition(transition);
|
|
383
435
|
return fn();
|
|
@@ -385,45 +437,67 @@ function runInTransition(transition, fn) {
|
|
|
385
437
|
activeTransition = prevTransition;
|
|
386
438
|
}
|
|
387
439
|
}
|
|
440
|
+
function restoreTransition(transition, fn) {
|
|
441
|
+
globalQueue.initTransition(transition);
|
|
442
|
+
const result = fn();
|
|
443
|
+
flush();
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
388
446
|
function action(genFn) {
|
|
389
|
-
return (...args) =>
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (nextValue instanceof Promise) return nextValue.then(process);
|
|
397
|
-
process(nextValue);
|
|
398
|
-
};
|
|
399
|
-
const process = result => {
|
|
400
|
-
if (result.done) {
|
|
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) => {
|
|
401
454
|
ctx = currentTransition(ctx);
|
|
402
|
-
ctx.actions.
|
|
455
|
+
const i = ctx.actions.indexOf(it);
|
|
456
|
+
if (i >= 0) ctx.actions.splice(i, 1);
|
|
403
457
|
activeTransition = ctx;
|
|
404
458
|
schedule();
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
+
});
|
|
414
483
|
}
|
|
415
484
|
GlobalQueue._update = recompute;
|
|
416
485
|
GlobalQueue._dispose = disposeChildren;
|
|
417
486
|
let tracking = false;
|
|
418
487
|
let stale = false;
|
|
419
|
-
let pendingValueCheck = false;
|
|
420
|
-
let pendingCheck = null;
|
|
421
488
|
let refreshing = false;
|
|
489
|
+
let pendingCheckActive = false;
|
|
490
|
+
let foundPending = false;
|
|
491
|
+
let pendingReadActive = false;
|
|
422
492
|
let context = null;
|
|
493
|
+
let leafEffectActive = false;
|
|
494
|
+
function setLeafEffectActive(v) {
|
|
495
|
+
leafEffectActive = v;
|
|
496
|
+
}
|
|
423
497
|
function recompute(el, create = false) {
|
|
424
|
-
const
|
|
498
|
+
const isEffect = el._type;
|
|
425
499
|
if (!create) {
|
|
426
|
-
if (el._transition && activeTransition !== el._transition
|
|
500
|
+
if (el._transition && (!isEffect || activeTransition) && activeTransition !== el._transition)
|
|
427
501
|
globalQueue.initTransition(el._transition);
|
|
428
502
|
deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
429
503
|
if (el._transition) disposeChildren(el);
|
|
@@ -435,35 +509,33 @@ function recompute(el, create = false) {
|
|
|
435
509
|
el._firstChild = null;
|
|
436
510
|
}
|
|
437
511
|
}
|
|
512
|
+
const isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
|
|
513
|
+
const hasOptimisticOverride = el._optimistic && el._pendingValue !== NOT_PENDING;
|
|
438
514
|
const oldcontext = context;
|
|
439
515
|
context = el;
|
|
440
516
|
el._depsTail = null;
|
|
441
517
|
el._flags = REACTIVE_RECOMPUTING_DEPS;
|
|
442
518
|
el._time = clock;
|
|
443
|
-
let value =
|
|
444
|
-
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
|
|
445
|
-
? el._value
|
|
446
|
-
: el._pendingValue;
|
|
519
|
+
let value = el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
|
|
447
520
|
let oldHeight = el._height;
|
|
448
|
-
let prevStatusFlags = el._statusFlags;
|
|
449
|
-
let prevError = el._error;
|
|
450
521
|
let prevTracking = tracking;
|
|
451
|
-
|
|
522
|
+
let prevOptimisticRead = optimisticReadActive;
|
|
452
523
|
tracking = true;
|
|
524
|
+
if (isOptimisticDirty) setOptimisticReadActive(true);
|
|
453
525
|
try {
|
|
454
526
|
value = handleAsync(el, el._fn(value));
|
|
455
|
-
el
|
|
527
|
+
clearStatus(el);
|
|
456
528
|
} catch (e) {
|
|
457
529
|
if (e instanceof NotReadyError) {
|
|
458
530
|
if (e.cause !== el) link(e.cause, el);
|
|
459
|
-
|
|
460
|
-
} else
|
|
531
|
+
notifyStatus(el, STATUS_PENDING, e);
|
|
532
|
+
} else notifyStatus(el, STATUS_ERROR, e);
|
|
461
533
|
} finally {
|
|
462
534
|
tracking = prevTracking;
|
|
535
|
+
el._flags = REACTIVE_NONE;
|
|
536
|
+
context = oldcontext;
|
|
463
537
|
}
|
|
464
|
-
el.
|
|
465
|
-
context = oldcontext;
|
|
466
|
-
if (!(el._statusFlags & STATUS_PENDING)) {
|
|
538
|
+
if (!el._error) {
|
|
467
539
|
const depsTail = el._depsTail;
|
|
468
540
|
let toRemove = depsTail !== null ? depsTail._nextDep : el._deps;
|
|
469
541
|
if (toRemove !== null) {
|
|
@@ -473,85 +545,158 @@ function recompute(el, create = false) {
|
|
|
473
545
|
if (depsTail !== null) depsTail._nextDep = null;
|
|
474
546
|
else el._deps = null;
|
|
475
547
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
!el._equals(
|
|
480
|
-
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition) || honoraryOptimistic
|
|
481
|
-
? el._value
|
|
482
|
-
: el._pendingValue,
|
|
483
|
-
value
|
|
484
|
-
);
|
|
485
|
-
const statusFlagsChanged = el._statusFlags !== prevStatusFlags || el._error !== prevError;
|
|
486
|
-
if (el._child && el._statusFlags & STATUS_PENDING && activeTransition)
|
|
487
|
-
activeTransition.asyncNodes.push(el);
|
|
488
|
-
el._notifyQueue?.(statusFlagsChanged, prevStatusFlags);
|
|
489
|
-
if (valueChanged || statusFlagsChanged) {
|
|
548
|
+
const valueChanged =
|
|
549
|
+
!el._equals ||
|
|
550
|
+
!el._equals(el._pendingValue === NOT_PENDING ? el._value : el._pendingValue, value);
|
|
490
551
|
if (valueChanged) {
|
|
491
|
-
if (create ||
|
|
552
|
+
if (create || (isEffect && activeTransition !== el._transition) || isOptimisticDirty)
|
|
553
|
+
el._value = value;
|
|
492
554
|
else el._pendingValue = value;
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
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
|
+
}
|
|
499
560
|
}
|
|
500
561
|
}
|
|
501
|
-
|
|
562
|
+
setOptimisticReadActive(prevOptimisticRead);
|
|
502
563
|
(!create || el._statusFlags & STATUS_PENDING) &&
|
|
503
564
|
!el._transition &&
|
|
504
565
|
globalQueue._pendingNodes.push(el);
|
|
505
|
-
el._transition &&
|
|
566
|
+
el._transition &&
|
|
567
|
+
isEffect &&
|
|
568
|
+
activeTransition !== el._transition &&
|
|
569
|
+
runInTransition(el._transition, () => recompute(el));
|
|
506
570
|
}
|
|
507
571
|
function handleAsync(el, result, setter) {
|
|
508
572
|
const isObject = typeof result === "object" && result !== null;
|
|
509
|
-
const isPromise = isObject && result instanceof Promise;
|
|
510
573
|
const iterator = isObject && untrack(() => result[Symbol.asyncIterator]);
|
|
511
|
-
|
|
574
|
+
const isThenable = !iterator && isObject && untrack(() => typeof result.then === "function");
|
|
575
|
+
if (!isThenable && !iterator) {
|
|
512
576
|
el._inFlight = null;
|
|
513
577
|
return result;
|
|
514
578
|
}
|
|
515
579
|
el._inFlight = result;
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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();
|
|
533
668
|
} else {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
globalQueue.initTransition(el._transition);
|
|
539
|
-
setter ? setter(value) : setSignal(el, () => value);
|
|
540
|
-
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);
|
|
541
673
|
}
|
|
542
|
-
} catch (error) {
|
|
543
|
-
if (el._inFlight !== result) return;
|
|
544
|
-
globalQueue.initTransition(el._transition);
|
|
545
|
-
setStatusFlags(el, STATUS_ERROR, error);
|
|
546
|
-
el._time = clock;
|
|
547
|
-
notifySubs(el);
|
|
548
|
-
schedule();
|
|
549
|
-
flush();
|
|
550
674
|
}
|
|
551
|
-
}
|
|
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
|
+
}
|
|
552
699
|
}
|
|
553
|
-
globalQueue.initTransition(el._transition);
|
|
554
|
-
throw new NotReadyError(context);
|
|
555
700
|
}
|
|
556
701
|
function updateIfNecessary(el) {
|
|
557
702
|
if (el._flags & REACTIVE_CHECK) {
|
|
@@ -633,10 +778,6 @@ function isValidLink(checkLink, sub) {
|
|
|
633
778
|
}
|
|
634
779
|
return false;
|
|
635
780
|
}
|
|
636
|
-
function setStatusFlags(signal, flags, error = null) {
|
|
637
|
-
signal._statusFlags = flags;
|
|
638
|
-
signal._error = error;
|
|
639
|
-
}
|
|
640
781
|
function markDisposal(el) {
|
|
641
782
|
let child = el._firstChild;
|
|
642
783
|
while (child) {
|
|
@@ -739,10 +880,12 @@ function computed(fn, initialValue, options) {
|
|
|
739
880
|
_inFlight: null,
|
|
740
881
|
_transition: null
|
|
741
882
|
};
|
|
742
|
-
if (options?._internal) Object.assign(self, options._internal);
|
|
743
883
|
self._name = options?.name ?? "computed";
|
|
744
884
|
self._prevHeap = self;
|
|
745
885
|
const parent = context?._root ? context._parentComputed : context;
|
|
886
|
+
if (leafEffectActive && context) {
|
|
887
|
+
throw new Error("Cannot create reactive primitives inside createTrackedEffect");
|
|
888
|
+
}
|
|
746
889
|
if (context) {
|
|
747
890
|
const lastChild = context._firstChild;
|
|
748
891
|
if (lastChild === null) {
|
|
@@ -758,14 +901,12 @@ function computed(fn, initialValue, options) {
|
|
|
758
901
|
}
|
|
759
902
|
function signal(v, options, firewall = null) {
|
|
760
903
|
const s = {
|
|
761
|
-
id: options?.id ?? (context?.id != null ? getNextChildId(context) : undefined),
|
|
762
904
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
763
905
|
_pureWrite: !!options?.pureWrite,
|
|
764
906
|
_unobserved: options?.unobserved,
|
|
765
907
|
_value: v,
|
|
766
908
|
_subs: null,
|
|
767
909
|
_subsTail: null,
|
|
768
|
-
_statusFlags: STATUS_NONE,
|
|
769
910
|
_time: clock,
|
|
770
911
|
_firewall: firewall,
|
|
771
912
|
_nextChild: firewall?._child || null,
|
|
@@ -775,6 +916,40 @@ function signal(v, options, firewall = null) {
|
|
|
775
916
|
firewall && (firewall._child = s);
|
|
776
917
|
return s;
|
|
777
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
|
+
}
|
|
778
953
|
function isEqual(a, b) {
|
|
779
954
|
return a === b;
|
|
780
955
|
}
|
|
@@ -788,10 +963,30 @@ function untrack(fn) {
|
|
|
788
963
|
}
|
|
789
964
|
}
|
|
790
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
|
+
}
|
|
791
986
|
let c = context;
|
|
792
987
|
if (c?._root) c = c._parentComputed;
|
|
793
988
|
if (refreshing && el._fn) recompute(el);
|
|
794
|
-
if (c && tracking
|
|
989
|
+
if (c && tracking) {
|
|
795
990
|
if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
|
|
796
991
|
link(el, c);
|
|
797
992
|
const owner = el._firewall || el;
|
|
@@ -808,51 +1003,24 @@ function read(el) {
|
|
|
808
1003
|
}
|
|
809
1004
|
}
|
|
810
1005
|
}
|
|
811
|
-
if (pendingValueCheck) {
|
|
812
|
-
if (!el._pendingSignal) {
|
|
813
|
-
el._pendingSignal = signal(el._value);
|
|
814
|
-
el._pendingSignal._optimistic = true;
|
|
815
|
-
}
|
|
816
|
-
pendingValueCheck = false;
|
|
817
|
-
try {
|
|
818
|
-
return read(el._pendingSignal);
|
|
819
|
-
} finally {
|
|
820
|
-
pendingValueCheck = true;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
1006
|
const asyncCompute = el._firewall || el;
|
|
824
|
-
if (
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
prev._value = read(asyncCompute._pendingCheck) || prev._value;
|
|
833
|
-
pendingCheck = prev;
|
|
834
|
-
}
|
|
835
|
-
if (!pendingCheck && asyncCompute._statusFlags & STATUS_PENDING) {
|
|
836
|
-
if ((c && !stale) || asyncCompute._statusFlags & STATUS_UNINITIALIZED || el._firewall)
|
|
837
|
-
throw asyncCompute._error;
|
|
838
|
-
else if (c && stale) {
|
|
839
|
-
setStatusFlags(c, c._statusFlags | STATUS_PENDING, asyncCompute._error);
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
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) {
|
|
843
1015
|
if (el._time < clock) {
|
|
844
1016
|
recompute(el, true);
|
|
845
1017
|
return read(el);
|
|
846
|
-
} else
|
|
847
|
-
throw el._error;
|
|
848
|
-
}
|
|
1018
|
+
} else throw el._error;
|
|
849
1019
|
}
|
|
850
1020
|
return !c ||
|
|
851
|
-
|
|
1021
|
+
optimisticReadActive ||
|
|
852
1022
|
el._pendingValue === NOT_PENDING ||
|
|
853
|
-
(stale &&
|
|
854
|
-
!pendingCheck &&
|
|
855
|
-
(c._optimistic || (el._transition && activeTransition !== el._transition)))
|
|
1023
|
+
(stale && el._transition && activeTransition !== el._transition)
|
|
856
1024
|
? el._value
|
|
857
1025
|
: el._pendingValue;
|
|
858
1026
|
}
|
|
@@ -861,37 +1029,41 @@ function setSignal(el, v) {
|
|
|
861
1029
|
console.warn("A Signal was written to in an owned scope.");
|
|
862
1030
|
if (el._transition && activeTransition !== el._transition)
|
|
863
1031
|
globalQueue.initTransition(el._transition);
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
const valueChanged =
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
v
|
|
878
|
-
);
|
|
879
|
-
if (!valueChanged && !el._statusFlags) return v;
|
|
880
|
-
if (valueChanged) {
|
|
881
|
-
if (el._optimistic) el._value = v;
|
|
882
|
-
else {
|
|
883
|
-
if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
|
|
884
|
-
el._pendingValue = v;
|
|
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);
|
|
885
1045
|
}
|
|
886
|
-
if (
|
|
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;
|
|
1054
|
+
}
|
|
1055
|
+
updatePendingSignal(el);
|
|
1056
|
+
if (el._pendingValueComputed) {
|
|
1057
|
+
setSignal(el._pendingValueComputed, v);
|
|
887
1058
|
}
|
|
888
|
-
setStatusFlags(el, STATUS_NONE);
|
|
889
1059
|
el._time = clock;
|
|
890
|
-
|
|
1060
|
+
insertSubs(el, isOptimistic);
|
|
891
1061
|
schedule();
|
|
892
1062
|
return v;
|
|
893
1063
|
}
|
|
1064
|
+
const PENDING_OWNER = {};
|
|
894
1065
|
function getObserver() {
|
|
1066
|
+
if (pendingCheckActive || pendingReadActive) return PENDING_OWNER;
|
|
895
1067
|
return tracking ? context : null;
|
|
896
1068
|
}
|
|
897
1069
|
function getOwner() {
|
|
@@ -899,25 +1071,20 @@ function getOwner() {
|
|
|
899
1071
|
}
|
|
900
1072
|
function onCleanup(fn) {
|
|
901
1073
|
if (!context) return fn;
|
|
902
|
-
|
|
903
|
-
if (
|
|
904
|
-
|
|
905
|
-
} else if (Array.isArray(node._disposal)) {
|
|
906
|
-
node._disposal.push(fn);
|
|
907
|
-
} else {
|
|
908
|
-
node._disposal = [node._disposal, fn];
|
|
909
|
-
}
|
|
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];
|
|
910
1077
|
return fn;
|
|
911
1078
|
}
|
|
912
1079
|
function createOwner(options) {
|
|
913
1080
|
const parent = context;
|
|
914
1081
|
const owner = {
|
|
1082
|
+
id: options?.id ?? (parent?.id != null ? getNextChildId(parent) : undefined),
|
|
915
1083
|
_root: true,
|
|
916
1084
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
917
1085
|
_firstChild: null,
|
|
918
1086
|
_nextSibling: null,
|
|
919
1087
|
_disposal: null,
|
|
920
|
-
id: options?.id ?? (parent?.id != null ? getNextChildId(parent) : undefined),
|
|
921
1088
|
_queue: parent?._queue ?? globalQueue,
|
|
922
1089
|
_context: parent?._context || defaultContext,
|
|
923
1090
|
_childCount: 0,
|
|
@@ -928,6 +1095,9 @@ function createOwner(options) {
|
|
|
928
1095
|
disposeChildren(owner, self);
|
|
929
1096
|
}
|
|
930
1097
|
};
|
|
1098
|
+
if (leafEffectActive && parent) {
|
|
1099
|
+
throw new Error("Cannot create reactive primitives inside createTrackedEffect");
|
|
1100
|
+
}
|
|
931
1101
|
if (parent) {
|
|
932
1102
|
const lastChild = parent._firstChild;
|
|
933
1103
|
if (lastChild === null) {
|
|
@@ -965,25 +1135,25 @@ function staleValues(fn, set = true) {
|
|
|
965
1135
|
}
|
|
966
1136
|
}
|
|
967
1137
|
function pending(fn) {
|
|
968
|
-
const
|
|
969
|
-
|
|
1138
|
+
const prevPending = pendingReadActive;
|
|
1139
|
+
pendingReadActive = true;
|
|
970
1140
|
try {
|
|
971
|
-
return
|
|
1141
|
+
return fn();
|
|
972
1142
|
} finally {
|
|
973
|
-
|
|
1143
|
+
pendingReadActive = prevPending;
|
|
974
1144
|
}
|
|
975
1145
|
}
|
|
976
1146
|
function isPending(fn) {
|
|
977
|
-
const
|
|
978
|
-
|
|
1147
|
+
const prevPendingCheck = pendingCheckActive;
|
|
1148
|
+
const prevFoundPending = foundPending;
|
|
1149
|
+
pendingCheckActive = true;
|
|
1150
|
+
foundPending = false;
|
|
979
1151
|
try {
|
|
980
|
-
|
|
981
|
-
return
|
|
982
|
-
} catch (err) {
|
|
983
|
-
if (!(err instanceof NotReadyError)) return false;
|
|
984
|
-
throw err;
|
|
1152
|
+
fn();
|
|
1153
|
+
return foundPending;
|
|
985
1154
|
} finally {
|
|
986
|
-
|
|
1155
|
+
pendingCheckActive = prevPendingCheck;
|
|
1156
|
+
foundPending = prevFoundPending;
|
|
987
1157
|
}
|
|
988
1158
|
}
|
|
989
1159
|
function refresh(fn) {
|
|
@@ -999,7 +1169,6 @@ function refresh(fn) {
|
|
|
999
1169
|
refreshing = prevRefreshing;
|
|
1000
1170
|
if (!prevRefreshing) {
|
|
1001
1171
|
schedule();
|
|
1002
|
-
flush();
|
|
1003
1172
|
}
|
|
1004
1173
|
}
|
|
1005
1174
|
}
|
|
@@ -1036,54 +1205,50 @@ function isUndefined(value) {
|
|
|
1036
1205
|
}
|
|
1037
1206
|
function effect(compute, effect, error, initialValue, options) {
|
|
1038
1207
|
let initialized = false;
|
|
1039
|
-
const node = computed(
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
if (!this._queue.notify(this, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1074
|
-
} else if (this._type === EFFECT_RENDER) {
|
|
1075
|
-
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;
|
|
1076
1240
|
}
|
|
1077
1241
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
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);
|
|
1082
1247
|
!options?.defer &&
|
|
1083
|
-
!(node._statusFlags & (STATUS_ERROR | STATUS_PENDING)) &&
|
|
1084
1248
|
(node._type === EFFECT_USER
|
|
1085
1249
|
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
1086
1250
|
: runEffect.call(node));
|
|
1251
|
+
initialized = true;
|
|
1087
1252
|
onCleanup(() => node._cleanup?.());
|
|
1088
1253
|
if (!node._parent)
|
|
1089
1254
|
console.warn("Effects created outside a reactive context will never be disposed");
|
|
@@ -1101,6 +1266,35 @@ function runEffect() {
|
|
|
1101
1266
|
this._modified = false;
|
|
1102
1267
|
}
|
|
1103
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
|
+
}
|
|
1104
1298
|
function createSignal(first, second, third) {
|
|
1105
1299
|
if (typeof first === "function") {
|
|
1106
1300
|
const node = computed(first, second, third);
|
|
@@ -1114,18 +1308,20 @@ function createMemo(compute, value, options) {
|
|
|
1114
1308
|
return read.bind(null, node);
|
|
1115
1309
|
}
|
|
1116
1310
|
function createEffect(compute, effectFn, value, options) {
|
|
1117
|
-
|
|
1311
|
+
effect(compute, effectFn.effect || effectFn, effectFn.error, value, {
|
|
1118
1312
|
...options,
|
|
1119
1313
|
name: options?.name ?? "effect"
|
|
1120
1314
|
});
|
|
1121
1315
|
}
|
|
1122
1316
|
function createRenderEffect(compute, effectFn, value, options) {
|
|
1123
|
-
|
|
1317
|
+
effect(compute, effectFn, undefined, value, {
|
|
1124
1318
|
render: true,
|
|
1125
1319
|
...{ ...options, name: options?.name ?? "effect" }
|
|
1126
1320
|
});
|
|
1127
1321
|
}
|
|
1128
|
-
function createTrackedEffect(compute, options) {
|
|
1322
|
+
function createTrackedEffect(compute, options) {
|
|
1323
|
+
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
1324
|
+
}
|
|
1129
1325
|
function createReaction(effectFn, options) {
|
|
1130
1326
|
let cleanup = undefined;
|
|
1131
1327
|
onCleanup(() => cleanup?.());
|
|
@@ -1162,39 +1358,19 @@ function resolve(fn) {
|
|
|
1162
1358
|
});
|
|
1163
1359
|
}
|
|
1164
1360
|
function createOptimistic(first, second, third) {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
if (n._statusFlags & STATUS_UNINITIALIZED) return value;
|
|
1171
|
-
n._pendingValue = value;
|
|
1172
|
-
return prev;
|
|
1173
|
-
},
|
|
1174
|
-
second,
|
|
1175
|
-
third
|
|
1176
|
-
);
|
|
1177
|
-
node._optimistic = true;
|
|
1178
|
-
return [read.bind(null, node), setSignal.bind(null, node)];
|
|
1179
|
-
}
|
|
1180
|
-
const node = signal(first, second);
|
|
1181
|
-
node._optimistic = true;
|
|
1182
|
-
return [
|
|
1183
|
-
read.bind(null, node),
|
|
1184
|
-
v => {
|
|
1185
|
-
node._pendingValue = first;
|
|
1186
|
-
return setSignal(node, v);
|
|
1187
|
-
}
|
|
1188
|
-
];
|
|
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)];
|
|
1189
1366
|
}
|
|
1190
1367
|
function onSettled(callback) {
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
});
|
|
1368
|
+
getOwner()
|
|
1369
|
+
? createTrackedEffect(() => untrack(callback))
|
|
1370
|
+
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
1371
|
+
const cleanup = callback();
|
|
1372
|
+
cleanup?.();
|
|
1373
|
+
});
|
|
1198
1374
|
}
|
|
1199
1375
|
function unwrap(value) {
|
|
1200
1376
|
return value?.[$TARGET]?.[STORE_NODE] ?? value;
|
|
@@ -1363,12 +1539,12 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
1363
1539
|
const owner = getOwner();
|
|
1364
1540
|
storeSetter(new Proxy(wrappedStore, writeTraps), s => {
|
|
1365
1541
|
const value = handleAsync(owner, fn(s), value => {
|
|
1366
|
-
value !==
|
|
1542
|
+
value !== s &&
|
|
1367
1543
|
value !== undefined &&
|
|
1368
1544
|
storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
|
|
1369
1545
|
setSignal(owner, undefined);
|
|
1370
1546
|
});
|
|
1371
|
-
value !==
|
|
1547
|
+
value !== s &&
|
|
1372
1548
|
value !== undefined &&
|
|
1373
1549
|
reconcile(value, options?.key || "id", options?.all)(wrappedStore);
|
|
1374
1550
|
});
|
|
@@ -1383,28 +1559,34 @@ const writeTraps = {
|
|
|
1383
1559
|
get(_, prop) {
|
|
1384
1560
|
let value;
|
|
1385
1561
|
setWriteOverride(true);
|
|
1562
|
+
setProjectionWriteActive(true);
|
|
1386
1563
|
try {
|
|
1387
1564
|
value = _[prop];
|
|
1388
1565
|
} finally {
|
|
1389
1566
|
setWriteOverride(false);
|
|
1567
|
+
setProjectionWriteActive(false);
|
|
1390
1568
|
}
|
|
1391
1569
|
return typeof value === "object" && value !== null ? new Proxy(value, writeTraps) : value;
|
|
1392
1570
|
},
|
|
1393
1571
|
set(_, prop, value) {
|
|
1394
1572
|
setWriteOverride(true);
|
|
1573
|
+
setProjectionWriteActive(true);
|
|
1395
1574
|
try {
|
|
1396
1575
|
_[prop] = value;
|
|
1397
1576
|
} finally {
|
|
1398
1577
|
setWriteOverride(false);
|
|
1578
|
+
setProjectionWriteActive(false);
|
|
1399
1579
|
}
|
|
1400
1580
|
return true;
|
|
1401
1581
|
},
|
|
1402
1582
|
deleteProperty(_, prop) {
|
|
1403
1583
|
setWriteOverride(true);
|
|
1584
|
+
setProjectionWriteActive(true);
|
|
1404
1585
|
try {
|
|
1405
1586
|
delete _[prop];
|
|
1406
1587
|
} finally {
|
|
1407
1588
|
setWriteOverride(false);
|
|
1589
|
+
setProjectionWriteActive(false);
|
|
1408
1590
|
}
|
|
1409
1591
|
return true;
|
|
1410
1592
|
}
|
|
@@ -1417,11 +1599,13 @@ const $TRACK = Symbol("STORE_TRACK"),
|
|
|
1417
1599
|
const PARENTS = new WeakMap();
|
|
1418
1600
|
const STORE_VALUE = "v",
|
|
1419
1601
|
STORE_OVERRIDE = "o",
|
|
1602
|
+
STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
1420
1603
|
STORE_NODE = "n",
|
|
1421
1604
|
STORE_HAS = "h",
|
|
1422
1605
|
STORE_WRAP = "w",
|
|
1423
1606
|
STORE_LOOKUP = "l",
|
|
1424
|
-
STORE_FIREWALL = "f"
|
|
1607
|
+
STORE_FIREWALL = "f",
|
|
1608
|
+
STORE_OPTIMISTIC = "p";
|
|
1425
1609
|
function createStoreProxy(value, traps = storeTraps, extend) {
|
|
1426
1610
|
let newTarget;
|
|
1427
1611
|
if (Array.isArray(value)) {
|
|
@@ -1453,9 +1637,9 @@ function getNodes(target, type) {
|
|
|
1453
1637
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
1454
1638
|
return nodes;
|
|
1455
1639
|
}
|
|
1456
|
-
function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
1640
|
+
function getNode(nodes, property, value, firewall, equals = isEqual, optimistic) {
|
|
1457
1641
|
if (nodes[property]) return nodes[property];
|
|
1458
|
-
|
|
1642
|
+
const s = signal(
|
|
1459
1643
|
value,
|
|
1460
1644
|
{
|
|
1461
1645
|
equals: equals,
|
|
@@ -1464,11 +1648,22 @@ function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
|
1464
1648
|
}
|
|
1465
1649
|
},
|
|
1466
1650
|
firewall
|
|
1467
|
-
)
|
|
1651
|
+
);
|
|
1652
|
+
if (optimistic) s._optimistic = true;
|
|
1653
|
+
return (nodes[property] = s);
|
|
1468
1654
|
}
|
|
1469
1655
|
function trackSelf(target, symbol = $TRACK) {
|
|
1470
1656
|
getObserver() &&
|
|
1471
|
-
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
|
+
);
|
|
1472
1667
|
}
|
|
1473
1668
|
function getKeys(source, override, enumerable = true) {
|
|
1474
1669
|
const baseKeys = untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)));
|
|
@@ -1501,9 +1696,16 @@ const storeTraps = {
|
|
|
1501
1696
|
}
|
|
1502
1697
|
const nodes = getNodes(target, STORE_NODE);
|
|
1503
1698
|
const tracked = nodes[property];
|
|
1504
|
-
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]);
|
|
1505
1703
|
const proxySource = !!target[STORE_VALUE][$TARGET];
|
|
1506
|
-
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];
|
|
1507
1709
|
if (!tracked) {
|
|
1508
1710
|
const desc = Object.getOwnPropertyDescriptor(storeValue, property);
|
|
1509
1711
|
if (desc && desc.get) return desc.get.call(receiver);
|
|
@@ -1512,7 +1714,9 @@ const storeTraps = {
|
|
|
1512
1714
|
let value =
|
|
1513
1715
|
tracked && (overridden || !proxySource)
|
|
1514
1716
|
? tracked._pendingValue !== NOT_PENDING
|
|
1515
|
-
? tracked.
|
|
1717
|
+
? tracked._optimistic
|
|
1718
|
+
? tracked._value
|
|
1719
|
+
: tracked._pendingValue
|
|
1516
1720
|
: tracked._value
|
|
1517
1721
|
: storeValue[property];
|
|
1518
1722
|
value === $DELETED && (value = undefined);
|
|
@@ -1541,7 +1745,9 @@ const storeTraps = {
|
|
|
1541
1745
|
nodes,
|
|
1542
1746
|
property,
|
|
1543
1747
|
isWrappable(value) ? wrap(value, target) : value,
|
|
1544
|
-
target[STORE_FIREWALL]
|
|
1748
|
+
target[STORE_FIREWALL],
|
|
1749
|
+
isEqual,
|
|
1750
|
+
target[STORE_OPTIMISTIC]
|
|
1545
1751
|
)
|
|
1546
1752
|
);
|
|
1547
1753
|
}
|
|
@@ -1551,30 +1757,53 @@ const storeTraps = {
|
|
|
1551
1757
|
has(target, property) {
|
|
1552
1758
|
if (property === $PROXY || property === $TRACK || property === "__proto__") return true;
|
|
1553
1759
|
const has =
|
|
1554
|
-
target[
|
|
1555
|
-
? target[
|
|
1556
|
-
: 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];
|
|
1557
1765
|
getObserver() &&
|
|
1558
|
-
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
|
+
);
|
|
1559
1776
|
return has;
|
|
1560
1777
|
},
|
|
1561
1778
|
set(target, property, rawValue) {
|
|
1562
1779
|
const store = target[$PROXY];
|
|
1563
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
|
+
}
|
|
1564
1787
|
untrack(() => {
|
|
1565
1788
|
const state = target[STORE_VALUE];
|
|
1566
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);
|
|
1567
1793
|
const prev =
|
|
1568
|
-
target[
|
|
1569
|
-
? target[
|
|
1570
|
-
:
|
|
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;
|
|
1571
1799
|
const value = rawValue?.[$TARGET]?.[STORE_VALUE] ?? rawValue;
|
|
1572
1800
|
if (prev === value) return true;
|
|
1573
|
-
const len =
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
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;
|
|
1578
1807
|
const wrappable = isWrappable(value);
|
|
1579
1808
|
if (isWrappable(prev)) {
|
|
1580
1809
|
const parents = PARENTS.get(prev);
|
|
@@ -1586,8 +1815,12 @@ const storeTraps = {
|
|
|
1586
1815
|
nodes[property] &&
|
|
1587
1816
|
setSignal(nodes[property], () => (wrappable ? wrap(value, target) : value));
|
|
1588
1817
|
if (Array.isArray(state)) {
|
|
1589
|
-
|
|
1590
|
-
|
|
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
|
+
}
|
|
1591
1824
|
}
|
|
1592
1825
|
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
1593
1826
|
});
|
|
@@ -1595,17 +1828,26 @@ const storeTraps = {
|
|
|
1595
1828
|
return true;
|
|
1596
1829
|
},
|
|
1597
1830
|
deleteProperty(target, property) {
|
|
1598
|
-
|
|
1831
|
+
const optDeleted = target[STORE_OPTIMISTIC_OVERRIDE]?.[property] === $DELETED;
|
|
1832
|
+
const regDeleted = target[STORE_OVERRIDE]?.[property] === $DELETED;
|
|
1833
|
+
if (writeOnly(target[$PROXY]) && !optDeleted && !regDeleted) {
|
|
1599
1834
|
untrack(() => {
|
|
1835
|
+
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
1836
|
+
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
1837
|
+
if (useOptimistic) trackOptimisticStore(target[$PROXY]);
|
|
1600
1838
|
const prev =
|
|
1601
|
-
target[
|
|
1602
|
-
? target[
|
|
1603
|
-
: target[
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
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];
|
|
1609
1851
|
} else return true;
|
|
1610
1852
|
if (isWrappable(prev)) {
|
|
1611
1853
|
const parents = PARENTS.get(prev);
|
|
@@ -1621,10 +1863,32 @@ const storeTraps = {
|
|
|
1621
1863
|
},
|
|
1622
1864
|
ownKeys(target) {
|
|
1623
1865
|
trackSelf(target);
|
|
1624
|
-
|
|
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;
|
|
1625
1876
|
},
|
|
1626
1877
|
getOwnPropertyDescriptor(target, property) {
|
|
1627
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
|
+
}
|
|
1628
1892
|
return getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
|
|
1629
1893
|
},
|
|
1630
1894
|
getPrototypeOf(target) {
|
|
@@ -1713,7 +1977,82 @@ function deep(store) {
|
|
|
1713
1977
|
return store[$DEEP];
|
|
1714
1978
|
}
|
|
1715
1979
|
function createOptimisticStore(first, second, options) {
|
|
1716
|
-
|
|
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 };
|
|
1717
2056
|
}
|
|
1718
2057
|
function snapshot(item, map, lookup) {
|
|
1719
2058
|
let target, isArray, override, result, unwrapped, v;
|
|
@@ -2108,21 +2447,15 @@ function compare(key, a, b) {
|
|
|
2108
2447
|
return key ? key(a) === key(b) : true;
|
|
2109
2448
|
}
|
|
2110
2449
|
function boundaryComputed(fn, propagationMask) {
|
|
2111
|
-
const node = computed(fn, undefined, {
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
flags &= ~STATUS_PENDING;
|
|
2118
|
-
}
|
|
2119
|
-
this._queue.notify(this, this._propagationMask, flags);
|
|
2120
|
-
},
|
|
2121
|
-
_propagationMask: propagationMask
|
|
2122
|
-
}
|
|
2123
|
-
});
|
|
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
|
+
};
|
|
2124
2456
|
node._propagationMask = propagationMask;
|
|
2125
2457
|
node._preventAutoDisposal = true;
|
|
2458
|
+
recompute(node, true);
|
|
2126
2459
|
return node;
|
|
2127
2460
|
}
|
|
2128
2461
|
function createBoundChildren(owner, fn, queue, mask) {
|
|
@@ -2222,8 +2555,10 @@ function createCollectionBoundary(type, fn, fallback) {
|
|
|
2222
2555
|
const decision = computed(() => {
|
|
2223
2556
|
if (!read(queue._disabled)) {
|
|
2224
2557
|
const resolved = read(tree);
|
|
2225
|
-
if (!untrack(() => read(queue._disabled)))
|
|
2226
|
-
|
|
2558
|
+
if (!untrack(() => read(queue._disabled))) {
|
|
2559
|
+
queue._initialized = true;
|
|
2560
|
+
return resolved;
|
|
2561
|
+
}
|
|
2227
2562
|
}
|
|
2228
2563
|
return fallback(queue);
|
|
2229
2564
|
});
|