@solidjs/signals 0.9.5 → 0.9.7
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 +718 -380
- package/dist/node.cjs +1262 -984
- package/dist/prod.js +1117 -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 | (status !== STATUS_ERROR ? el._statusFlags & STATUS_UNINITIALIZED : 0);
|
|
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,43 @@ 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
|
+
const prevContext = context;
|
|
946
|
+
context = null;
|
|
947
|
+
el._pendingValueComputed = optimisticComputed(() => read(el));
|
|
948
|
+
context = prevContext;
|
|
949
|
+
pendingReadActive = prevPending;
|
|
950
|
+
}
|
|
951
|
+
return el._pendingValueComputed;
|
|
952
|
+
}
|
|
953
|
+
function updatePendingSignal(el) {
|
|
954
|
+
if (el._pendingSignal) setSignal(el._pendingSignal, computePendingState(el));
|
|
955
|
+
}
|
|
778
956
|
function isEqual(a, b) {
|
|
779
957
|
return a === b;
|
|
780
958
|
}
|
|
@@ -788,10 +966,30 @@ function untrack(fn) {
|
|
|
788
966
|
}
|
|
789
967
|
}
|
|
790
968
|
function read(el) {
|
|
969
|
+
if (pendingCheckActive) {
|
|
970
|
+
const target = el._firewall || el;
|
|
971
|
+
const pendingSig = getPendingSignal(target);
|
|
972
|
+
const prevCheck = pendingCheckActive;
|
|
973
|
+
pendingCheckActive = false;
|
|
974
|
+
if (read(pendingSig)) {
|
|
975
|
+
foundPending = true;
|
|
976
|
+
}
|
|
977
|
+
pendingCheckActive = prevCheck;
|
|
978
|
+
return el._value;
|
|
979
|
+
}
|
|
980
|
+
if (pendingReadActive) {
|
|
981
|
+
const pendingComputed = getPendingValueComputed(el);
|
|
982
|
+
const prevPending = pendingReadActive;
|
|
983
|
+
pendingReadActive = false;
|
|
984
|
+
const value = read(pendingComputed);
|
|
985
|
+
pendingReadActive = prevPending;
|
|
986
|
+
if (pendingComputed._statusFlags & STATUS_PENDING) return el._value;
|
|
987
|
+
return value;
|
|
988
|
+
}
|
|
791
989
|
let c = context;
|
|
792
990
|
if (c?._root) c = c._parentComputed;
|
|
793
991
|
if (refreshing && el._fn) recompute(el);
|
|
794
|
-
if (c && tracking
|
|
992
|
+
if (c && tracking) {
|
|
795
993
|
if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
|
|
796
994
|
link(el, c);
|
|
797
995
|
const owner = el._firewall || el;
|
|
@@ -808,51 +1006,24 @@ function read(el) {
|
|
|
808
1006
|
}
|
|
809
1007
|
}
|
|
810
1008
|
}
|
|
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
1009
|
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) {
|
|
1010
|
+
if (
|
|
1011
|
+
c &&
|
|
1012
|
+
!optimisticReadActive &&
|
|
1013
|
+
asyncCompute._statusFlags & STATUS_PENDING &&
|
|
1014
|
+
!(stale && asyncCompute._transition && activeTransition !== asyncCompute._transition)
|
|
1015
|
+
)
|
|
1016
|
+
throw asyncCompute._error;
|
|
1017
|
+
if (el._fn && el._statusFlags & STATUS_ERROR) {
|
|
843
1018
|
if (el._time < clock) {
|
|
844
1019
|
recompute(el, true);
|
|
845
1020
|
return read(el);
|
|
846
|
-
} else
|
|
847
|
-
throw el._error;
|
|
848
|
-
}
|
|
1021
|
+
} else throw el._error;
|
|
849
1022
|
}
|
|
850
1023
|
return !c ||
|
|
851
|
-
|
|
1024
|
+
optimisticReadActive ||
|
|
852
1025
|
el._pendingValue === NOT_PENDING ||
|
|
853
|
-
(stale &&
|
|
854
|
-
!pendingCheck &&
|
|
855
|
-
(c._optimistic || (el._transition && activeTransition !== el._transition)))
|
|
1026
|
+
(stale && el._transition && activeTransition !== el._transition)
|
|
856
1027
|
? el._value
|
|
857
1028
|
: el._pendingValue;
|
|
858
1029
|
}
|
|
@@ -861,37 +1032,41 @@ function setSignal(el, v) {
|
|
|
861
1032
|
console.warn("A Signal was written to in an owned scope.");
|
|
862
1033
|
if (el._transition && activeTransition !== el._transition)
|
|
863
1034
|
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;
|
|
1035
|
+
const isOptimistic = el._optimistic && !projectionWriteActive;
|
|
1036
|
+
const currentValue = isOptimistic
|
|
1037
|
+
? el._value
|
|
1038
|
+
: el._pendingValue === NOT_PENDING
|
|
1039
|
+
? el._value
|
|
1040
|
+
: el._pendingValue;
|
|
1041
|
+
if (typeof v === "function") v = v(currentValue);
|
|
1042
|
+
const valueChanged = !el._equals || !el._equals(currentValue, v);
|
|
1043
|
+
if (!valueChanged) return v;
|
|
1044
|
+
if (isOptimistic) {
|
|
1045
|
+
const isFirstWrite = el._pendingValue === NOT_PENDING;
|
|
1046
|
+
if (el._transition && !isFirstWrite) {
|
|
1047
|
+
globalQueue.initTransition(el._transition);
|
|
885
1048
|
}
|
|
886
|
-
if (
|
|
1049
|
+
if (isFirstWrite) {
|
|
1050
|
+
el._pendingValue = el._value;
|
|
1051
|
+
globalQueue._optimisticNodes.push(el);
|
|
1052
|
+
}
|
|
1053
|
+
el._value = v;
|
|
1054
|
+
} else {
|
|
1055
|
+
if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
|
|
1056
|
+
el._pendingValue = v;
|
|
1057
|
+
}
|
|
1058
|
+
updatePendingSignal(el);
|
|
1059
|
+
if (el._pendingValueComputed) {
|
|
1060
|
+
setSignal(el._pendingValueComputed, v);
|
|
887
1061
|
}
|
|
888
|
-
setStatusFlags(el, STATUS_NONE);
|
|
889
1062
|
el._time = clock;
|
|
890
|
-
|
|
1063
|
+
insertSubs(el, isOptimistic);
|
|
891
1064
|
schedule();
|
|
892
1065
|
return v;
|
|
893
1066
|
}
|
|
1067
|
+
const PENDING_OWNER = {};
|
|
894
1068
|
function getObserver() {
|
|
1069
|
+
if (pendingCheckActive || pendingReadActive) return PENDING_OWNER;
|
|
895
1070
|
return tracking ? context : null;
|
|
896
1071
|
}
|
|
897
1072
|
function getOwner() {
|
|
@@ -899,25 +1074,20 @@ function getOwner() {
|
|
|
899
1074
|
}
|
|
900
1075
|
function onCleanup(fn) {
|
|
901
1076
|
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
|
-
}
|
|
1077
|
+
if (!context._disposal) context._disposal = fn;
|
|
1078
|
+
else if (Array.isArray(context._disposal)) context._disposal.push(fn);
|
|
1079
|
+
else context._disposal = [context._disposal, fn];
|
|
910
1080
|
return fn;
|
|
911
1081
|
}
|
|
912
1082
|
function createOwner(options) {
|
|
913
1083
|
const parent = context;
|
|
914
1084
|
const owner = {
|
|
1085
|
+
id: options?.id ?? (parent?.id != null ? getNextChildId(parent) : undefined),
|
|
915
1086
|
_root: true,
|
|
916
1087
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
917
1088
|
_firstChild: null,
|
|
918
1089
|
_nextSibling: null,
|
|
919
1090
|
_disposal: null,
|
|
920
|
-
id: options?.id ?? (parent?.id != null ? getNextChildId(parent) : undefined),
|
|
921
1091
|
_queue: parent?._queue ?? globalQueue,
|
|
922
1092
|
_context: parent?._context || defaultContext,
|
|
923
1093
|
_childCount: 0,
|
|
@@ -928,6 +1098,9 @@ function createOwner(options) {
|
|
|
928
1098
|
disposeChildren(owner, self);
|
|
929
1099
|
}
|
|
930
1100
|
};
|
|
1101
|
+
if (leafEffectActive && parent) {
|
|
1102
|
+
throw new Error("Cannot create reactive primitives inside createTrackedEffect");
|
|
1103
|
+
}
|
|
931
1104
|
if (parent) {
|
|
932
1105
|
const lastChild = parent._firstChild;
|
|
933
1106
|
if (lastChild === null) {
|
|
@@ -965,25 +1138,25 @@ function staleValues(fn, set = true) {
|
|
|
965
1138
|
}
|
|
966
1139
|
}
|
|
967
1140
|
function pending(fn) {
|
|
968
|
-
const
|
|
969
|
-
|
|
1141
|
+
const prevPending = pendingReadActive;
|
|
1142
|
+
pendingReadActive = true;
|
|
970
1143
|
try {
|
|
971
|
-
return
|
|
1144
|
+
return fn();
|
|
972
1145
|
} finally {
|
|
973
|
-
|
|
1146
|
+
pendingReadActive = prevPending;
|
|
974
1147
|
}
|
|
975
1148
|
}
|
|
976
1149
|
function isPending(fn) {
|
|
977
|
-
const
|
|
978
|
-
|
|
1150
|
+
const prevPendingCheck = pendingCheckActive;
|
|
1151
|
+
const prevFoundPending = foundPending;
|
|
1152
|
+
pendingCheckActive = true;
|
|
1153
|
+
foundPending = false;
|
|
979
1154
|
try {
|
|
980
|
-
|
|
981
|
-
return
|
|
982
|
-
} catch (err) {
|
|
983
|
-
if (!(err instanceof NotReadyError)) return false;
|
|
984
|
-
throw err;
|
|
1155
|
+
fn();
|
|
1156
|
+
return foundPending;
|
|
985
1157
|
} finally {
|
|
986
|
-
|
|
1158
|
+
pendingCheckActive = prevPendingCheck;
|
|
1159
|
+
foundPending = prevFoundPending;
|
|
987
1160
|
}
|
|
988
1161
|
}
|
|
989
1162
|
function refresh(fn) {
|
|
@@ -999,7 +1172,6 @@ function refresh(fn) {
|
|
|
999
1172
|
refreshing = prevRefreshing;
|
|
1000
1173
|
if (!prevRefreshing) {
|
|
1001
1174
|
schedule();
|
|
1002
|
-
flush();
|
|
1003
1175
|
}
|
|
1004
1176
|
}
|
|
1005
1177
|
}
|
|
@@ -1036,54 +1208,50 @@ function isUndefined(value) {
|
|
|
1036
1208
|
}
|
|
1037
1209
|
function effect(compute, effect, error, initialValue, options) {
|
|
1038
1210
|
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);
|
|
1211
|
+
const node = computed(
|
|
1212
|
+
options?.render ? p => staleValues(() => compute(p)) : compute,
|
|
1213
|
+
initialValue,
|
|
1214
|
+
{
|
|
1215
|
+
...options,
|
|
1216
|
+
equals: () => {
|
|
1217
|
+
node._modified = !node._error;
|
|
1218
|
+
if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
|
|
1219
|
+
return false;
|
|
1220
|
+
},
|
|
1221
|
+
lazy: true
|
|
1222
|
+
}
|
|
1223
|
+
);
|
|
1224
|
+
node._prevValue = initialValue;
|
|
1225
|
+
node._effectFn = effect;
|
|
1226
|
+
node._errorFn = error;
|
|
1227
|
+
node._cleanup = undefined;
|
|
1228
|
+
node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
|
|
1229
|
+
node._notifyStatus = () => {
|
|
1230
|
+
if (node._statusFlags & STATUS_ERROR) {
|
|
1231
|
+
let error = node._error;
|
|
1232
|
+
node._queue.notify(node, STATUS_PENDING, 0);
|
|
1233
|
+
if (node._type === EFFECT_USER) {
|
|
1234
|
+
try {
|
|
1235
|
+
return node._errorFn
|
|
1236
|
+
? node._errorFn(error, () => {
|
|
1237
|
+
node._cleanup?.();
|
|
1238
|
+
node._cleanup = undefined;
|
|
1239
|
+
})
|
|
1240
|
+
: console.error(error);
|
|
1241
|
+
} catch (e) {
|
|
1242
|
+
error = e;
|
|
1076
1243
|
}
|
|
1077
1244
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1245
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1246
|
+
} else if (node._type === EFFECT_RENDER)
|
|
1247
|
+
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, node._statusFlags);
|
|
1248
|
+
};
|
|
1249
|
+
recompute(node, true);
|
|
1082
1250
|
!options?.defer &&
|
|
1083
|
-
!(node._statusFlags & (STATUS_ERROR | STATUS_PENDING)) &&
|
|
1084
1251
|
(node._type === EFFECT_USER
|
|
1085
1252
|
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
1086
1253
|
: runEffect.call(node));
|
|
1254
|
+
initialized = true;
|
|
1087
1255
|
onCleanup(() => node._cleanup?.());
|
|
1088
1256
|
if (!node._parent)
|
|
1089
1257
|
console.warn("Effects created outside a reactive context will never be disposed");
|
|
@@ -1101,6 +1269,35 @@ function runEffect() {
|
|
|
1101
1269
|
this._modified = false;
|
|
1102
1270
|
}
|
|
1103
1271
|
}
|
|
1272
|
+
function trackedEffect(fn, options) {
|
|
1273
|
+
const run = () => {
|
|
1274
|
+
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
1275
|
+
node._modified = false;
|
|
1276
|
+
recompute(node);
|
|
1277
|
+
};
|
|
1278
|
+
const node = computed(
|
|
1279
|
+
() => {
|
|
1280
|
+
setLeafEffectActive(true);
|
|
1281
|
+
try {
|
|
1282
|
+
node._cleanup?.();
|
|
1283
|
+
node._cleanup = undefined;
|
|
1284
|
+
node._cleanup = staleValues(fn) || undefined;
|
|
1285
|
+
} finally {
|
|
1286
|
+
setLeafEffectActive(false);
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
undefined,
|
|
1290
|
+
{ ...options, lazy: true, pureWrite: true }
|
|
1291
|
+
);
|
|
1292
|
+
node._cleanup = undefined;
|
|
1293
|
+
node._modified = true;
|
|
1294
|
+
node._type = EFFECT_TRACKED;
|
|
1295
|
+
node._run = run;
|
|
1296
|
+
node._queue.enqueue(EFFECT_USER, run);
|
|
1297
|
+
onCleanup(() => node._cleanup?.());
|
|
1298
|
+
if (!node._parent)
|
|
1299
|
+
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1300
|
+
}
|
|
1104
1301
|
function createSignal(first, second, third) {
|
|
1105
1302
|
if (typeof first === "function") {
|
|
1106
1303
|
const node = computed(first, second, third);
|
|
@@ -1114,18 +1311,20 @@ function createMemo(compute, value, options) {
|
|
|
1114
1311
|
return read.bind(null, node);
|
|
1115
1312
|
}
|
|
1116
1313
|
function createEffect(compute, effectFn, value, options) {
|
|
1117
|
-
|
|
1314
|
+
effect(compute, effectFn.effect || effectFn, effectFn.error, value, {
|
|
1118
1315
|
...options,
|
|
1119
1316
|
name: options?.name ?? "effect"
|
|
1120
1317
|
});
|
|
1121
1318
|
}
|
|
1122
1319
|
function createRenderEffect(compute, effectFn, value, options) {
|
|
1123
|
-
|
|
1320
|
+
effect(compute, effectFn, undefined, value, {
|
|
1124
1321
|
render: true,
|
|
1125
1322
|
...{ ...options, name: options?.name ?? "effect" }
|
|
1126
1323
|
});
|
|
1127
1324
|
}
|
|
1128
|
-
function createTrackedEffect(compute, options) {
|
|
1325
|
+
function createTrackedEffect(compute, options) {
|
|
1326
|
+
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
1327
|
+
}
|
|
1129
1328
|
function createReaction(effectFn, options) {
|
|
1130
1329
|
let cleanup = undefined;
|
|
1131
1330
|
onCleanup(() => cleanup?.());
|
|
@@ -1162,39 +1361,19 @@ function resolve(fn) {
|
|
|
1162
1361
|
});
|
|
1163
1362
|
}
|
|
1164
1363
|
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
|
-
];
|
|
1364
|
+
const node =
|
|
1365
|
+
typeof first === "function"
|
|
1366
|
+
? optimisticComputed(first, second, third)
|
|
1367
|
+
: optimisticSignal(first, second);
|
|
1368
|
+
return [read.bind(null, node), setSignal.bind(null, node)];
|
|
1189
1369
|
}
|
|
1190
1370
|
function onSettled(callback) {
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
});
|
|
1371
|
+
getOwner()
|
|
1372
|
+
? createTrackedEffect(() => untrack(callback))
|
|
1373
|
+
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
1374
|
+
const cleanup = callback();
|
|
1375
|
+
cleanup?.();
|
|
1376
|
+
});
|
|
1198
1377
|
}
|
|
1199
1378
|
function unwrap(value) {
|
|
1200
1379
|
return value?.[$TARGET]?.[STORE_NODE] ?? value;
|
|
@@ -1363,12 +1542,12 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
1363
1542
|
const owner = getOwner();
|
|
1364
1543
|
storeSetter(new Proxy(wrappedStore, writeTraps), s => {
|
|
1365
1544
|
const value = handleAsync(owner, fn(s), value => {
|
|
1366
|
-
value !==
|
|
1545
|
+
value !== s &&
|
|
1367
1546
|
value !== undefined &&
|
|
1368
1547
|
storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
|
|
1369
1548
|
setSignal(owner, undefined);
|
|
1370
1549
|
});
|
|
1371
|
-
value !==
|
|
1550
|
+
value !== s &&
|
|
1372
1551
|
value !== undefined &&
|
|
1373
1552
|
reconcile(value, options?.key || "id", options?.all)(wrappedStore);
|
|
1374
1553
|
});
|
|
@@ -1383,28 +1562,34 @@ const writeTraps = {
|
|
|
1383
1562
|
get(_, prop) {
|
|
1384
1563
|
let value;
|
|
1385
1564
|
setWriteOverride(true);
|
|
1565
|
+
setProjectionWriteActive(true);
|
|
1386
1566
|
try {
|
|
1387
1567
|
value = _[prop];
|
|
1388
1568
|
} finally {
|
|
1389
1569
|
setWriteOverride(false);
|
|
1570
|
+
setProjectionWriteActive(false);
|
|
1390
1571
|
}
|
|
1391
1572
|
return typeof value === "object" && value !== null ? new Proxy(value, writeTraps) : value;
|
|
1392
1573
|
},
|
|
1393
1574
|
set(_, prop, value) {
|
|
1394
1575
|
setWriteOverride(true);
|
|
1576
|
+
setProjectionWriteActive(true);
|
|
1395
1577
|
try {
|
|
1396
1578
|
_[prop] = value;
|
|
1397
1579
|
} finally {
|
|
1398
1580
|
setWriteOverride(false);
|
|
1581
|
+
setProjectionWriteActive(false);
|
|
1399
1582
|
}
|
|
1400
1583
|
return true;
|
|
1401
1584
|
},
|
|
1402
1585
|
deleteProperty(_, prop) {
|
|
1403
1586
|
setWriteOverride(true);
|
|
1587
|
+
setProjectionWriteActive(true);
|
|
1404
1588
|
try {
|
|
1405
1589
|
delete _[prop];
|
|
1406
1590
|
} finally {
|
|
1407
1591
|
setWriteOverride(false);
|
|
1592
|
+
setProjectionWriteActive(false);
|
|
1408
1593
|
}
|
|
1409
1594
|
return true;
|
|
1410
1595
|
}
|
|
@@ -1417,11 +1602,13 @@ const $TRACK = Symbol("STORE_TRACK"),
|
|
|
1417
1602
|
const PARENTS = new WeakMap();
|
|
1418
1603
|
const STORE_VALUE = "v",
|
|
1419
1604
|
STORE_OVERRIDE = "o",
|
|
1605
|
+
STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
1420
1606
|
STORE_NODE = "n",
|
|
1421
1607
|
STORE_HAS = "h",
|
|
1422
1608
|
STORE_WRAP = "w",
|
|
1423
1609
|
STORE_LOOKUP = "l",
|
|
1424
|
-
STORE_FIREWALL = "f"
|
|
1610
|
+
STORE_FIREWALL = "f",
|
|
1611
|
+
STORE_OPTIMISTIC = "p";
|
|
1425
1612
|
function createStoreProxy(value, traps = storeTraps, extend) {
|
|
1426
1613
|
let newTarget;
|
|
1427
1614
|
if (Array.isArray(value)) {
|
|
@@ -1453,9 +1640,9 @@ function getNodes(target, type) {
|
|
|
1453
1640
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
1454
1641
|
return nodes;
|
|
1455
1642
|
}
|
|
1456
|
-
function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
1643
|
+
function getNode(nodes, property, value, firewall, equals = isEqual, optimistic) {
|
|
1457
1644
|
if (nodes[property]) return nodes[property];
|
|
1458
|
-
|
|
1645
|
+
const s = signal(
|
|
1459
1646
|
value,
|
|
1460
1647
|
{
|
|
1461
1648
|
equals: equals,
|
|
@@ -1464,11 +1651,22 @@ function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
|
1464
1651
|
}
|
|
1465
1652
|
},
|
|
1466
1653
|
firewall
|
|
1467
|
-
)
|
|
1654
|
+
);
|
|
1655
|
+
if (optimistic) s._optimistic = true;
|
|
1656
|
+
return (nodes[property] = s);
|
|
1468
1657
|
}
|
|
1469
1658
|
function trackSelf(target, symbol = $TRACK) {
|
|
1470
1659
|
getObserver() &&
|
|
1471
|
-
read(
|
|
1660
|
+
read(
|
|
1661
|
+
getNode(
|
|
1662
|
+
getNodes(target, STORE_NODE),
|
|
1663
|
+
symbol,
|
|
1664
|
+
undefined,
|
|
1665
|
+
target[STORE_FIREWALL],
|
|
1666
|
+
false,
|
|
1667
|
+
target[STORE_OPTIMISTIC]
|
|
1668
|
+
)
|
|
1669
|
+
);
|
|
1472
1670
|
}
|
|
1473
1671
|
function getKeys(source, override, enumerable = true) {
|
|
1474
1672
|
const baseKeys = untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)));
|
|
@@ -1501,9 +1699,16 @@ const storeTraps = {
|
|
|
1501
1699
|
}
|
|
1502
1700
|
const nodes = getNodes(target, STORE_NODE);
|
|
1503
1701
|
const tracked = nodes[property];
|
|
1504
|
-
const
|
|
1702
|
+
const optOverridden =
|
|
1703
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE];
|
|
1704
|
+
const overridden =
|
|
1705
|
+
optOverridden || (target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]);
|
|
1505
1706
|
const proxySource = !!target[STORE_VALUE][$TARGET];
|
|
1506
|
-
const storeValue =
|
|
1707
|
+
const storeValue = optOverridden
|
|
1708
|
+
? target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1709
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1710
|
+
? target[STORE_OVERRIDE]
|
|
1711
|
+
: target[STORE_VALUE];
|
|
1507
1712
|
if (!tracked) {
|
|
1508
1713
|
const desc = Object.getOwnPropertyDescriptor(storeValue, property);
|
|
1509
1714
|
if (desc && desc.get) return desc.get.call(receiver);
|
|
@@ -1512,7 +1717,9 @@ const storeTraps = {
|
|
|
1512
1717
|
let value =
|
|
1513
1718
|
tracked && (overridden || !proxySource)
|
|
1514
1719
|
? tracked._pendingValue !== NOT_PENDING
|
|
1515
|
-
? tracked.
|
|
1720
|
+
? tracked._optimistic
|
|
1721
|
+
? tracked._value
|
|
1722
|
+
: tracked._pendingValue
|
|
1516
1723
|
: tracked._value
|
|
1517
1724
|
: storeValue[property];
|
|
1518
1725
|
value === $DELETED && (value = undefined);
|
|
@@ -1541,7 +1748,9 @@ const storeTraps = {
|
|
|
1541
1748
|
nodes,
|
|
1542
1749
|
property,
|
|
1543
1750
|
isWrappable(value) ? wrap(value, target) : value,
|
|
1544
|
-
target[STORE_FIREWALL]
|
|
1751
|
+
target[STORE_FIREWALL],
|
|
1752
|
+
isEqual,
|
|
1753
|
+
target[STORE_OPTIMISTIC]
|
|
1545
1754
|
)
|
|
1546
1755
|
);
|
|
1547
1756
|
}
|
|
@@ -1551,30 +1760,53 @@ const storeTraps = {
|
|
|
1551
1760
|
has(target, property) {
|
|
1552
1761
|
if (property === $PROXY || property === $TRACK || property === "__proto__") return true;
|
|
1553
1762
|
const has =
|
|
1554
|
-
target[
|
|
1555
|
-
? target[
|
|
1556
|
-
: property in target[
|
|
1763
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1764
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
|
|
1765
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1766
|
+
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
1767
|
+
: property in target[STORE_VALUE];
|
|
1557
1768
|
getObserver() &&
|
|
1558
|
-
read(
|
|
1769
|
+
read(
|
|
1770
|
+
getNode(
|
|
1771
|
+
getNodes(target, STORE_HAS),
|
|
1772
|
+
property,
|
|
1773
|
+
has,
|
|
1774
|
+
target[STORE_FIREWALL],
|
|
1775
|
+
isEqual,
|
|
1776
|
+
target[STORE_OPTIMISTIC]
|
|
1777
|
+
)
|
|
1778
|
+
);
|
|
1559
1779
|
return has;
|
|
1560
1780
|
},
|
|
1561
1781
|
set(target, property, rawValue) {
|
|
1562
1782
|
const store = target[$PROXY];
|
|
1563
1783
|
if (writeOnly(store)) {
|
|
1784
|
+
if (target[STORE_OPTIMISTIC]) {
|
|
1785
|
+
const firewall = target[STORE_FIREWALL];
|
|
1786
|
+
if (firewall?._transition) {
|
|
1787
|
+
globalQueue.initTransition(firewall._transition);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1564
1790
|
untrack(() => {
|
|
1565
1791
|
const state = target[STORE_VALUE];
|
|
1566
1792
|
const base = state[property];
|
|
1793
|
+
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
1794
|
+
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
1795
|
+
if (useOptimistic) trackOptimisticStore(store);
|
|
1567
1796
|
const prev =
|
|
1568
|
-
target[
|
|
1569
|
-
? target[
|
|
1570
|
-
:
|
|
1797
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1798
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property]
|
|
1799
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1800
|
+
? target[STORE_OVERRIDE][property]
|
|
1801
|
+
: base;
|
|
1571
1802
|
const value = rawValue?.[$TARGET]?.[STORE_VALUE] ?? rawValue;
|
|
1572
1803
|
if (prev === value) return true;
|
|
1573
|
-
const len =
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1804
|
+
const len =
|
|
1805
|
+
target[STORE_OPTIMISTIC_OVERRIDE]?.length ||
|
|
1806
|
+
target[STORE_OVERRIDE]?.length ||
|
|
1807
|
+
state.length;
|
|
1808
|
+
if (value !== undefined && value === base) delete target[overrideKey][property];
|
|
1809
|
+
else (target[overrideKey] || (target[overrideKey] = Object.create(null)))[property] = value;
|
|
1578
1810
|
const wrappable = isWrappable(value);
|
|
1579
1811
|
if (isWrappable(prev)) {
|
|
1580
1812
|
const parents = PARENTS.get(prev);
|
|
@@ -1586,8 +1818,12 @@ const storeTraps = {
|
|
|
1586
1818
|
nodes[property] &&
|
|
1587
1819
|
setSignal(nodes[property], () => (wrappable ? wrap(value, target) : value));
|
|
1588
1820
|
if (Array.isArray(state)) {
|
|
1589
|
-
|
|
1590
|
-
|
|
1821
|
+
if (property === "length") {
|
|
1822
|
+
nodes.length && setSignal(nodes.length, value);
|
|
1823
|
+
} else {
|
|
1824
|
+
const index = parseInt(property) + 1;
|
|
1825
|
+
if (index > len) nodes.length && setSignal(nodes.length, index);
|
|
1826
|
+
}
|
|
1591
1827
|
}
|
|
1592
1828
|
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
1593
1829
|
});
|
|
@@ -1595,17 +1831,26 @@ const storeTraps = {
|
|
|
1595
1831
|
return true;
|
|
1596
1832
|
},
|
|
1597
1833
|
deleteProperty(target, property) {
|
|
1598
|
-
|
|
1834
|
+
const optDeleted = target[STORE_OPTIMISTIC_OVERRIDE]?.[property] === $DELETED;
|
|
1835
|
+
const regDeleted = target[STORE_OVERRIDE]?.[property] === $DELETED;
|
|
1836
|
+
if (writeOnly(target[$PROXY]) && !optDeleted && !regDeleted) {
|
|
1599
1837
|
untrack(() => {
|
|
1838
|
+
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
1839
|
+
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
1840
|
+
if (useOptimistic) trackOptimisticStore(target[$PROXY]);
|
|
1600
1841
|
const prev =
|
|
1601
|
-
target[
|
|
1602
|
-
? target[
|
|
1603
|
-
: target[
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1842
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
1843
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property]
|
|
1844
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
1845
|
+
? target[STORE_OVERRIDE][property]
|
|
1846
|
+
: target[STORE_VALUE][property];
|
|
1847
|
+
if (
|
|
1848
|
+
property in target[STORE_VALUE] ||
|
|
1849
|
+
(target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE])
|
|
1850
|
+
) {
|
|
1851
|
+
(target[overrideKey] || (target[overrideKey] = Object.create(null)))[property] = $DELETED;
|
|
1852
|
+
} else if (target[overrideKey] && property in target[overrideKey]) {
|
|
1853
|
+
delete target[overrideKey][property];
|
|
1609
1854
|
} else return true;
|
|
1610
1855
|
if (isWrappable(prev)) {
|
|
1611
1856
|
const parents = PARENTS.get(prev);
|
|
@@ -1621,10 +1866,32 @@ const storeTraps = {
|
|
|
1621
1866
|
},
|
|
1622
1867
|
ownKeys(target) {
|
|
1623
1868
|
trackSelf(target);
|
|
1624
|
-
|
|
1869
|
+
let keys = getKeys(target[STORE_VALUE], target[STORE_OVERRIDE], false);
|
|
1870
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
1871
|
+
const keySet = new Set(keys);
|
|
1872
|
+
for (const key of Reflect.ownKeys(target[STORE_OPTIMISTIC_OVERRIDE])) {
|
|
1873
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE][key] !== $DELETED) keySet.add(key);
|
|
1874
|
+
else keySet.delete(key);
|
|
1875
|
+
}
|
|
1876
|
+
keys = Array.from(keySet);
|
|
1877
|
+
}
|
|
1878
|
+
return keys;
|
|
1625
1879
|
},
|
|
1626
1880
|
getOwnPropertyDescriptor(target, property) {
|
|
1627
1881
|
if (property === $PROXY) return { value: target[$PROXY], writable: true, configurable: true };
|
|
1882
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
1883
|
+
if (target[STORE_OPTIMISTIC_OVERRIDE][property] === $DELETED) return undefined;
|
|
1884
|
+
const baseDesc = getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
|
|
1885
|
+
if (baseDesc) {
|
|
1886
|
+
return { ...baseDesc, value: target[STORE_OPTIMISTIC_OVERRIDE][property] };
|
|
1887
|
+
}
|
|
1888
|
+
return {
|
|
1889
|
+
value: target[STORE_OPTIMISTIC_OVERRIDE][property],
|
|
1890
|
+
writable: true,
|
|
1891
|
+
enumerable: true,
|
|
1892
|
+
configurable: true
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1628
1895
|
return getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
|
|
1629
1896
|
},
|
|
1630
1897
|
getPrototypeOf(target) {
|
|
@@ -1713,7 +1980,82 @@ function deep(store) {
|
|
|
1713
1980
|
return store[$DEEP];
|
|
1714
1981
|
}
|
|
1715
1982
|
function createOptimisticStore(first, second, options) {
|
|
1716
|
-
|
|
1983
|
+
GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
|
|
1984
|
+
const derived = typeof first === "function";
|
|
1985
|
+
const initialValue = (derived ? second : first) ?? {};
|
|
1986
|
+
const fn = derived ? first : undefined;
|
|
1987
|
+
const { store: wrappedStore } = createOptimisticProjectionInternal(fn, initialValue, options);
|
|
1988
|
+
return [wrappedStore, fn => storeSetter(wrappedStore, fn)];
|
|
1989
|
+
}
|
|
1990
|
+
function clearOptimisticStore(store) {
|
|
1991
|
+
const target = store[$TARGET];
|
|
1992
|
+
if (!target || !target[STORE_OPTIMISTIC_OVERRIDE]) return;
|
|
1993
|
+
const override = target[STORE_OPTIMISTIC_OVERRIDE];
|
|
1994
|
+
const nodes = target[STORE_NODE];
|
|
1995
|
+
if (nodes) {
|
|
1996
|
+
for (const key of Reflect.ownKeys(override)) {
|
|
1997
|
+
if (nodes[key]) {
|
|
1998
|
+
const baseValue =
|
|
1999
|
+
target[STORE_OVERRIDE] && key in target[STORE_OVERRIDE]
|
|
2000
|
+
? target[STORE_OVERRIDE][key]
|
|
2001
|
+
: target[STORE_VALUE][key];
|
|
2002
|
+
const value = baseValue === $DELETED ? undefined : baseValue;
|
|
2003
|
+
setSignal(nodes[key], isWrappable(value) ? wrap(value, target) : value);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
2007
|
+
}
|
|
2008
|
+
delete target[STORE_OPTIMISTIC_OVERRIDE];
|
|
2009
|
+
}
|
|
2010
|
+
function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
|
|
2011
|
+
let node;
|
|
2012
|
+
const wrappedMap = new WeakMap();
|
|
2013
|
+
const wrapper = s => {
|
|
2014
|
+
s[STORE_WRAP] = wrapProjection;
|
|
2015
|
+
s[STORE_LOOKUP] = wrappedMap;
|
|
2016
|
+
s[STORE_OPTIMISTIC] = true;
|
|
2017
|
+
Object.defineProperty(s, STORE_FIREWALL, {
|
|
2018
|
+
get() {
|
|
2019
|
+
return node;
|
|
2020
|
+
},
|
|
2021
|
+
configurable: true
|
|
2022
|
+
});
|
|
2023
|
+
};
|
|
2024
|
+
const wrapProjection = source => {
|
|
2025
|
+
if (wrappedMap.has(source)) return wrappedMap.get(source);
|
|
2026
|
+
if (source[$TARGET]?.[STORE_WRAP] === wrapProjection) return source;
|
|
2027
|
+
const wrapped = createStoreProxy(source, storeTraps, wrapper);
|
|
2028
|
+
wrappedMap.set(source, wrapped);
|
|
2029
|
+
return wrapped;
|
|
2030
|
+
};
|
|
2031
|
+
const wrappedStore = wrapProjection(initialValue);
|
|
2032
|
+
if (fn) {
|
|
2033
|
+
node = computed(() => {
|
|
2034
|
+
const owner = getOwner();
|
|
2035
|
+
setProjectionWriteActive(true);
|
|
2036
|
+
try {
|
|
2037
|
+
storeSetter(new Proxy(wrappedStore, writeTraps), s => {
|
|
2038
|
+
const value = handleAsync(owner, fn(s), value => {
|
|
2039
|
+
setProjectionWriteActive(true);
|
|
2040
|
+
try {
|
|
2041
|
+
value !== s &&
|
|
2042
|
+
value !== undefined &&
|
|
2043
|
+
storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
|
|
2044
|
+
} finally {
|
|
2045
|
+
setProjectionWriteActive(false);
|
|
2046
|
+
}
|
|
2047
|
+
});
|
|
2048
|
+
value !== s &&
|
|
2049
|
+
value !== undefined &&
|
|
2050
|
+
reconcile(value, options?.key || "id", options?.all)(wrappedStore);
|
|
2051
|
+
});
|
|
2052
|
+
} finally {
|
|
2053
|
+
setProjectionWriteActive(false);
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
node._preventAutoDisposal = true;
|
|
2057
|
+
}
|
|
2058
|
+
return { store: wrappedStore, node: node };
|
|
1717
2059
|
}
|
|
1718
2060
|
function snapshot(item, map, lookup) {
|
|
1719
2061
|
let target, isArray, override, result, unwrapped, v;
|
|
@@ -2108,21 +2450,15 @@ function compare(key, a, b) {
|
|
|
2108
2450
|
return key ? key(a) === key(b) : true;
|
|
2109
2451
|
}
|
|
2110
2452
|
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
|
-
});
|
|
2453
|
+
const node = computed(fn, undefined, { lazy: true });
|
|
2454
|
+
node._notifyStatus = () => {
|
|
2455
|
+
const flags = node._statusFlags;
|
|
2456
|
+
node._statusFlags &= ~node._propagationMask;
|
|
2457
|
+
node._queue.notify(node, node._propagationMask, flags);
|
|
2458
|
+
};
|
|
2124
2459
|
node._propagationMask = propagationMask;
|
|
2125
2460
|
node._preventAutoDisposal = true;
|
|
2461
|
+
recompute(node, true);
|
|
2126
2462
|
return node;
|
|
2127
2463
|
}
|
|
2128
2464
|
function createBoundChildren(owner, fn, queue, mask) {
|
|
@@ -2222,8 +2558,10 @@ function createCollectionBoundary(type, fn, fallback) {
|
|
|
2222
2558
|
const decision = computed(() => {
|
|
2223
2559
|
if (!read(queue._disabled)) {
|
|
2224
2560
|
const resolved = read(tree);
|
|
2225
|
-
if (!untrack(() => read(queue._disabled)))
|
|
2226
|
-
|
|
2561
|
+
if (!untrack(() => read(queue._disabled))) {
|
|
2562
|
+
queue._initialized = true;
|
|
2563
|
+
return resolved;
|
|
2564
|
+
}
|
|
2227
2565
|
}
|
|
2228
2566
|
return fallback(queue);
|
|
2229
2567
|
});
|