@solidjs/signals 0.9.1 → 0.9.3
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 +227 -85
- package/dist/node.cjs +703 -571
- package/dist/prod.js +505 -376
- package/dist/types/core/constants.d.ts +1 -0
- package/dist/types/core/core.d.ts +5 -2
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/scheduler.d.ts +10 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/store/projection.d.ts +8 -3
- package/dist/types/store/store.d.ts +10 -6
- package/package.json +3 -3
package/dist/dev.js
CHANGED
|
@@ -34,6 +34,7 @@ const EFFECT_USER = 2;
|
|
|
34
34
|
const NOT_PENDING = {};
|
|
35
35
|
const SUPPORTS_PROXY = typeof Proxy === "function";
|
|
36
36
|
const defaultContext = {};
|
|
37
|
+
const $REFRESH = Symbol("refresh");
|
|
37
38
|
function actualInsertIntoHeap(n, heap) {
|
|
38
39
|
const parentHeight =
|
|
39
40
|
(n._parent?._root ? n._parent._parentComputed?._height : n._parent?._height) ?? -1;
|
|
@@ -132,6 +133,7 @@ function adjustHeight(el, heap) {
|
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
const transitions = new Set();
|
|
136
|
+
let optimisticRun = false;
|
|
135
137
|
const dirtyQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
|
|
136
138
|
const zombieQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
|
|
137
139
|
let clock = 0;
|
|
@@ -140,7 +142,7 @@ let scheduled = false;
|
|
|
140
142
|
function schedule() {
|
|
141
143
|
if (scheduled) return;
|
|
142
144
|
scheduled = true;
|
|
143
|
-
if (!globalQueue._running) queueMicrotask(flush);
|
|
145
|
+
if (!globalQueue._running) Promise.resolve().then(() => queueMicrotask(flush));
|
|
144
146
|
}
|
|
145
147
|
class Queue {
|
|
146
148
|
_parent = null;
|
|
@@ -203,6 +205,7 @@ class Queue {
|
|
|
203
205
|
class GlobalQueue extends Queue {
|
|
204
206
|
_running = false;
|
|
205
207
|
_pendingNodes = [];
|
|
208
|
+
_optimisticNodes = [];
|
|
206
209
|
static _update;
|
|
207
210
|
static _dispose;
|
|
208
211
|
flush() {
|
|
@@ -212,6 +215,7 @@ class GlobalQueue extends Queue {
|
|
|
212
215
|
runHeap(dirtyQueue, GlobalQueue._update);
|
|
213
216
|
if (activeTransition) {
|
|
214
217
|
if (!transitionComplete(activeTransition)) {
|
|
218
|
+
let t = activeTransition;
|
|
215
219
|
runHeap(zombieQueue, GlobalQueue._update);
|
|
216
220
|
this._pendingNodes = [];
|
|
217
221
|
this.stashQueues(activeTransition.queueStash);
|
|
@@ -219,20 +223,18 @@ class GlobalQueue extends Queue {
|
|
|
219
223
|
scheduled = false;
|
|
220
224
|
runTransitionPending(activeTransition.pendingNodes, true);
|
|
221
225
|
activeTransition = null;
|
|
226
|
+
runOptimistic(t);
|
|
222
227
|
return;
|
|
223
228
|
}
|
|
224
229
|
this._pendingNodes.push(...activeTransition.pendingNodes);
|
|
230
|
+
this._optimisticNodes !== activeTransition.optimisticNodes &&
|
|
231
|
+
this._optimisticNodes.push(...activeTransition.optimisticNodes);
|
|
225
232
|
this.restoreQueues(activeTransition.queueStash);
|
|
226
233
|
transitions.delete(activeTransition);
|
|
227
234
|
activeTransition = null;
|
|
228
235
|
runTransitionPending(this._pendingNodes, false);
|
|
229
|
-
dirtyQueue._max >= dirtyQueue._min && runHeap(dirtyQueue, GlobalQueue._update);
|
|
230
236
|
} else if (transitions.size) runHeap(zombieQueue, GlobalQueue._update);
|
|
231
|
-
|
|
232
|
-
while (dirtyQueue._max >= dirtyQueue._min) {
|
|
233
|
-
runHeap(dirtyQueue, GlobalQueue._update);
|
|
234
|
-
runPending(this._pendingNodes);
|
|
235
|
-
}
|
|
237
|
+
runOptimistic();
|
|
236
238
|
clock++;
|
|
237
239
|
scheduled = false;
|
|
238
240
|
this.run(EFFECT_RENDER);
|
|
@@ -256,11 +258,14 @@ class GlobalQueue extends Queue {
|
|
|
256
258
|
initTransition(node) {
|
|
257
259
|
if (activeTransition && activeTransition.time === clock) return;
|
|
258
260
|
if (!activeTransition) {
|
|
259
|
-
activeTransition = node
|
|
261
|
+
activeTransition = node?._transition ?? {
|
|
260
262
|
time: clock,
|
|
261
263
|
pendingNodes: [],
|
|
262
264
|
asyncNodes: [],
|
|
263
|
-
|
|
265
|
+
optimisticNodes: [],
|
|
266
|
+
actions: [],
|
|
267
|
+
queueStash: { _queues: [[], []], _children: [] },
|
|
268
|
+
done: false
|
|
264
269
|
};
|
|
265
270
|
}
|
|
266
271
|
transitions.add(activeTransition);
|
|
@@ -270,9 +275,47 @@ class GlobalQueue extends Queue {
|
|
|
270
275
|
n._transition = activeTransition;
|
|
271
276
|
activeTransition.pendingNodes.push(n);
|
|
272
277
|
}
|
|
278
|
+
for (let i = 0; i < this._optimisticNodes.length; i++) {
|
|
279
|
+
const n = this._optimisticNodes[i];
|
|
280
|
+
n._transition = activeTransition;
|
|
281
|
+
activeTransition.optimisticNodes.push(n);
|
|
282
|
+
}
|
|
273
283
|
this._pendingNodes = activeTransition.pendingNodes;
|
|
284
|
+
this._optimisticNodes = activeTransition.optimisticNodes;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function notifySubs(node) {
|
|
288
|
+
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
289
|
+
const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
290
|
+
if (queue._min > s._sub._height) queue._min = s._sub._height;
|
|
291
|
+
insertIntoHeap(s._sub, queue);
|
|
274
292
|
}
|
|
275
293
|
}
|
|
294
|
+
function runOptimistic(activeTransition = null) {
|
|
295
|
+
let resolvePending = !activeTransition;
|
|
296
|
+
const optimisticNodes = globalQueue._optimisticNodes;
|
|
297
|
+
optimisticRun = true;
|
|
298
|
+
for (let i = 0; i < optimisticNodes.length; i++) {
|
|
299
|
+
const n = optimisticNodes[i];
|
|
300
|
+
if (
|
|
301
|
+
!activeTransition &&
|
|
302
|
+
(!n._transition || n._transition.done) &&
|
|
303
|
+
n._pendingValue !== NOT_PENDING
|
|
304
|
+
) {
|
|
305
|
+
n._value = n._pendingValue;
|
|
306
|
+
n._pendingValue = NOT_PENDING;
|
|
307
|
+
}
|
|
308
|
+
n._transition = activeTransition;
|
|
309
|
+
notifySubs(n);
|
|
310
|
+
}
|
|
311
|
+
globalQueue._optimisticNodes = [];
|
|
312
|
+
if (dirtyQueue._max >= dirtyQueue._min) {
|
|
313
|
+
resolvePending = true;
|
|
314
|
+
runHeap(dirtyQueue, GlobalQueue._update);
|
|
315
|
+
}
|
|
316
|
+
optimisticRun = false;
|
|
317
|
+
resolvePending && runPending(globalQueue._pendingNodes);
|
|
318
|
+
}
|
|
276
319
|
function runPending(pendingNodes) {
|
|
277
320
|
for (let i = 0; i < pendingNodes.length; i++) {
|
|
278
321
|
const n = pendingNodes[i];
|
|
@@ -281,8 +324,6 @@ function runPending(pendingNodes) {
|
|
|
281
324
|
n._pendingValue = NOT_PENDING;
|
|
282
325
|
if (n._type) n._modified = true;
|
|
283
326
|
}
|
|
284
|
-
if (n._pendingSignal && n._pendingSignal._pendingValue !== NOT_PENDING)
|
|
285
|
-
n._pendingSignal._set(n._pendingSignal._pendingValue);
|
|
286
327
|
if (n._fn) GlobalQueue._dispose(n, false, true);
|
|
287
328
|
}
|
|
288
329
|
pendingNodes.length = 0;
|
|
@@ -293,10 +334,6 @@ function runTransitionPending(pendingNodes, value) {
|
|
|
293
334
|
const n = p[i];
|
|
294
335
|
n._transition = activeTransition;
|
|
295
336
|
if (n._pendingCheck) n._pendingCheck._set(value);
|
|
296
|
-
if (n._pendingSignal && n._pendingSignal._pendingValue !== NOT_PENDING) {
|
|
297
|
-
n._pendingSignal._set(n._pendingSignal._pendingValue);
|
|
298
|
-
n._pendingSignal._pendingValue = NOT_PENDING;
|
|
299
|
-
}
|
|
300
337
|
}
|
|
301
338
|
}
|
|
302
339
|
const globalQueue = new GlobalQueue();
|
|
@@ -311,6 +348,8 @@ function runQueue(queue, type) {
|
|
|
311
348
|
for (let i = 0; i < queue.length; i++) queue[i](type);
|
|
312
349
|
}
|
|
313
350
|
function transitionComplete(transition) {
|
|
351
|
+
if (transition.done) return true;
|
|
352
|
+
if (transition.actions.length) return false;
|
|
314
353
|
let done = true;
|
|
315
354
|
for (let i = 0; i < transition.asyncNodes.length; i++) {
|
|
316
355
|
if (transition.asyncNodes[i]._statusFlags & STATUS_PENDING) {
|
|
@@ -318,13 +357,43 @@ function transitionComplete(transition) {
|
|
|
318
357
|
break;
|
|
319
358
|
}
|
|
320
359
|
}
|
|
360
|
+
done && (transition.done = true);
|
|
321
361
|
return done;
|
|
322
362
|
}
|
|
323
|
-
function runInTransition(
|
|
363
|
+
function runInTransition(transition, fn) {
|
|
324
364
|
const prevTransition = activeTransition;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
365
|
+
try {
|
|
366
|
+
activeTransition = transition;
|
|
367
|
+
return fn();
|
|
368
|
+
} finally {
|
|
369
|
+
activeTransition = prevTransition;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function action(genFn) {
|
|
373
|
+
return (...args) => {
|
|
374
|
+
const iterator = genFn(...args);
|
|
375
|
+
globalQueue.initTransition();
|
|
376
|
+
let ctx = activeTransition;
|
|
377
|
+
ctx.actions.push(iterator);
|
|
378
|
+
const step = input => {
|
|
379
|
+
let nextValue = iterator.next(input);
|
|
380
|
+
if (nextValue instanceof Promise) return nextValue.then(process);
|
|
381
|
+
process(nextValue);
|
|
382
|
+
};
|
|
383
|
+
const process = result => {
|
|
384
|
+
if (result.done) {
|
|
385
|
+
ctx.actions.splice(ctx.actions.indexOf(iterator), 1);
|
|
386
|
+
activeTransition = ctx;
|
|
387
|
+
schedule();
|
|
388
|
+
flush();
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const yielded = result.value;
|
|
392
|
+
if (yielded instanceof Promise) return yielded.then(step);
|
|
393
|
+
runInTransition(ctx, () => step(yielded));
|
|
394
|
+
};
|
|
395
|
+
runInTransition(ctx, () => step());
|
|
396
|
+
};
|
|
328
397
|
}
|
|
329
398
|
GlobalQueue._update = recompute;
|
|
330
399
|
GlobalQueue._dispose = disposeChildren;
|
|
@@ -334,13 +403,6 @@ let pendingValueCheck = false;
|
|
|
334
403
|
let pendingCheck = null;
|
|
335
404
|
let refreshing = false;
|
|
336
405
|
let context = null;
|
|
337
|
-
function notifySubs(node) {
|
|
338
|
-
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
339
|
-
const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
340
|
-
if (queue._min > s._sub._height) queue._min = s._sub._height;
|
|
341
|
-
insertIntoHeap(s._sub, queue);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
406
|
function recompute(el, create = false) {
|
|
345
407
|
const honoraryOptimistic = el._type && el._transition != activeTransition;
|
|
346
408
|
if (!create) {
|
|
@@ -361,7 +423,10 @@ function recompute(el, create = false) {
|
|
|
361
423
|
el._depsTail = null;
|
|
362
424
|
el._flags = REACTIVE_RECOMPUTING_DEPS;
|
|
363
425
|
el._time = clock;
|
|
364
|
-
let value =
|
|
426
|
+
let value =
|
|
427
|
+
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
|
|
428
|
+
? el._value
|
|
429
|
+
: el._pendingValue;
|
|
365
430
|
let oldHeight = el._height;
|
|
366
431
|
let prevStatusFlags = el._statusFlags;
|
|
367
432
|
let prevError = el._error;
|
|
@@ -395,7 +460,7 @@ function recompute(el, create = false) {
|
|
|
395
460
|
const valueChanged =
|
|
396
461
|
!el._equals ||
|
|
397
462
|
!el._equals(
|
|
398
|
-
el._pendingValue === NOT_PENDING || el._optimistic || honoraryOptimistic
|
|
463
|
+
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition) || honoraryOptimistic
|
|
399
464
|
? el._value
|
|
400
465
|
: el._pendingValue,
|
|
401
466
|
value
|
|
@@ -406,21 +471,19 @@ function recompute(el, create = false) {
|
|
|
406
471
|
if (valueChanged) {
|
|
407
472
|
if (create || el._optimistic || honoraryOptimistic) el._value = value;
|
|
408
473
|
else el._pendingValue = value;
|
|
409
|
-
if (el._pendingSignal) el._pendingSignal
|
|
410
|
-
}
|
|
411
|
-
for (let s = el._subs; s !== null; s = s._nextSub) {
|
|
412
|
-
const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
413
|
-
if (s._sub._height < el._height && queue._min > s._sub._height) queue._min = s._sub._height;
|
|
414
|
-
insertIntoHeap(s._sub, queue);
|
|
474
|
+
if (el._pendingSignal) setSignal(el._pendingSignal, value);
|
|
415
475
|
}
|
|
476
|
+
(!el._optimistic || optimisticRun) && notifySubs(el);
|
|
416
477
|
} else if (el._height != oldHeight) {
|
|
417
478
|
for (let s = el._subs; s !== null; s = s._nextSub) {
|
|
418
479
|
insertIntoHeapHeight(s._sub, s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
419
480
|
}
|
|
420
481
|
}
|
|
421
|
-
|
|
482
|
+
el._optimistic && !optimisticRun && globalQueue._optimisticNodes.push(el);
|
|
483
|
+
(!create || el._statusFlags & STATUS_PENDING) &&
|
|
484
|
+
!el._transition &&
|
|
422
485
|
globalQueue._pendingNodes.push(el);
|
|
423
|
-
|
|
486
|
+
el._transition && honoraryOptimistic && runInTransition(el._transition, () => recompute(el));
|
|
424
487
|
}
|
|
425
488
|
function handleAsync(el, result, setter) {
|
|
426
489
|
const isObject = typeof result === "object" && result !== null;
|
|
@@ -671,7 +734,7 @@ function computed(fn, initialValue, options) {
|
|
|
671
734
|
}
|
|
672
735
|
}
|
|
673
736
|
if (parent) self._height = parent._height + 1;
|
|
674
|
-
recompute(self, true);
|
|
737
|
+
!options?.lazy && recompute(self, true);
|
|
675
738
|
return self;
|
|
676
739
|
}
|
|
677
740
|
function signal(v, options, firewall = null) {
|
|
@@ -726,22 +789,10 @@ function read(el) {
|
|
|
726
789
|
}
|
|
727
790
|
}
|
|
728
791
|
}
|
|
729
|
-
if (pendingCheck) {
|
|
730
|
-
if (!el._pendingCheck) {
|
|
731
|
-
el._pendingCheck = signal(false);
|
|
732
|
-
el._pendingCheck._optimistic = true;
|
|
733
|
-
el._pendingCheck._set = v => setSignal(el._pendingCheck, v);
|
|
734
|
-
}
|
|
735
|
-
const prev = pendingCheck;
|
|
736
|
-
pendingCheck = null;
|
|
737
|
-
prev._value = read(el._pendingCheck) || prev._value;
|
|
738
|
-
pendingCheck = prev;
|
|
739
|
-
}
|
|
740
792
|
if (pendingValueCheck) {
|
|
741
793
|
if (!el._pendingSignal) {
|
|
742
794
|
el._pendingSignal = signal(el._value);
|
|
743
795
|
el._pendingSignal._optimistic = true;
|
|
744
|
-
el._pendingSignal._set = v => setSignal(el._pendingSignal, v);
|
|
745
796
|
}
|
|
746
797
|
pendingValueCheck = false;
|
|
747
798
|
try {
|
|
@@ -750,10 +801,23 @@ function read(el) {
|
|
|
750
801
|
pendingValueCheck = true;
|
|
751
802
|
}
|
|
752
803
|
}
|
|
753
|
-
|
|
754
|
-
|
|
804
|
+
const asyncCompute = el._firewall || el;
|
|
805
|
+
if (pendingCheck) {
|
|
806
|
+
if (!asyncCompute._pendingCheck) {
|
|
807
|
+
asyncCompute._pendingCheck = signal(false);
|
|
808
|
+
asyncCompute._pendingCheck._optimistic = true;
|
|
809
|
+
asyncCompute._pendingCheck._set = v => setSignal(asyncCompute._pendingCheck, v);
|
|
810
|
+
}
|
|
811
|
+
const prev = pendingCheck;
|
|
812
|
+
pendingCheck = null;
|
|
813
|
+
prev._value = read(asyncCompute._pendingCheck) || prev._value;
|
|
814
|
+
pendingCheck = prev;
|
|
815
|
+
}
|
|
816
|
+
if (!pendingCheck && asyncCompute._statusFlags & STATUS_PENDING) {
|
|
817
|
+
if ((c && !stale) || asyncCompute._statusFlags & STATUS_UNINITIALIZED || el._firewall)
|
|
818
|
+
throw asyncCompute._error;
|
|
755
819
|
else if (c && stale) {
|
|
756
|
-
setStatusFlags(c, c._statusFlags |
|
|
820
|
+
setStatusFlags(c, c._statusFlags | STATUS_PENDING, asyncCompute._error);
|
|
757
821
|
}
|
|
758
822
|
}
|
|
759
823
|
if (el._statusFlags & STATUS_ERROR) {
|
|
@@ -767,7 +831,9 @@ function read(el) {
|
|
|
767
831
|
return !c ||
|
|
768
832
|
el._optimistic ||
|
|
769
833
|
el._pendingValue === NOT_PENDING ||
|
|
770
|
-
(stale &&
|
|
834
|
+
(stale &&
|
|
835
|
+
!pendingCheck &&
|
|
836
|
+
(c._optimistic || (el._transition && activeTransition !== el._transition)))
|
|
771
837
|
? el._value
|
|
772
838
|
: el._pendingValue;
|
|
773
839
|
}
|
|
@@ -775,12 +841,18 @@ function setSignal(el, v) {
|
|
|
775
841
|
if (!el._pureWrite && context && el._firewall !== context)
|
|
776
842
|
console.warn("A Signal was written to in an owned scope.");
|
|
777
843
|
if (typeof v === "function") {
|
|
778
|
-
v = v(
|
|
844
|
+
v = v(
|
|
845
|
+
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
|
|
846
|
+
? el._value
|
|
847
|
+
: el._pendingValue
|
|
848
|
+
);
|
|
779
849
|
}
|
|
780
850
|
const valueChanged =
|
|
781
851
|
!el._equals ||
|
|
782
852
|
!el._equals(
|
|
783
|
-
el._pendingValue === NOT_PENDING || el._optimistic
|
|
853
|
+
el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
|
|
854
|
+
? el._value
|
|
855
|
+
: el._pendingValue,
|
|
784
856
|
v
|
|
785
857
|
);
|
|
786
858
|
if (!valueChanged && !el._statusFlags) return v;
|
|
@@ -790,11 +862,11 @@ function setSignal(el, v) {
|
|
|
790
862
|
if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
|
|
791
863
|
el._pendingValue = v;
|
|
792
864
|
}
|
|
793
|
-
if (el._pendingSignal) el._pendingSignal
|
|
865
|
+
if (el._pendingSignal) setSignal(el._pendingSignal, v);
|
|
794
866
|
}
|
|
795
867
|
setStatusFlags(el, STATUS_NONE);
|
|
796
868
|
el._time = clock;
|
|
797
|
-
notifySubs(el);
|
|
869
|
+
el._optimistic && !optimisticRun ? globalQueue._optimisticNodes.push(el) : notifySubs(el);
|
|
798
870
|
schedule();
|
|
799
871
|
return v;
|
|
800
872
|
}
|
|
@@ -894,6 +966,10 @@ function refresh(fn) {
|
|
|
894
966
|
let prevRefreshing = refreshing;
|
|
895
967
|
refreshing = true;
|
|
896
968
|
try {
|
|
969
|
+
if (typeof fn !== "function") {
|
|
970
|
+
recompute(fn[$REFRESH]);
|
|
971
|
+
return fn;
|
|
972
|
+
}
|
|
897
973
|
return untrack(fn);
|
|
898
974
|
} finally {
|
|
899
975
|
refreshing = prevRefreshing;
|
|
@@ -1064,7 +1140,30 @@ function resolve(fn) {
|
|
|
1064
1140
|
});
|
|
1065
1141
|
}
|
|
1066
1142
|
function createOptimistic(first, second, third) {
|
|
1067
|
-
|
|
1143
|
+
if (typeof first === "function") {
|
|
1144
|
+
const node = computed(
|
|
1145
|
+
prev => {
|
|
1146
|
+
let n = node || getOwner();
|
|
1147
|
+
n._pendingValue = first(prev);
|
|
1148
|
+
return prev;
|
|
1149
|
+
},
|
|
1150
|
+
second,
|
|
1151
|
+
third
|
|
1152
|
+
);
|
|
1153
|
+
node._optimistic = true;
|
|
1154
|
+
return [read.bind(null, node), setSignal.bind(null, node)];
|
|
1155
|
+
}
|
|
1156
|
+
const o = getOwner();
|
|
1157
|
+
const needsId = o?.id != null;
|
|
1158
|
+
const node = signal(first, needsId ? { id: getNextChildId(o), ...second } : second);
|
|
1159
|
+
node._optimistic = true;
|
|
1160
|
+
return [
|
|
1161
|
+
read.bind(null, node),
|
|
1162
|
+
v => {
|
|
1163
|
+
node._pendingValue = first;
|
|
1164
|
+
return setSignal(node, v);
|
|
1165
|
+
}
|
|
1166
|
+
];
|
|
1068
1167
|
}
|
|
1069
1168
|
function onSettled(callback) {
|
|
1070
1169
|
let cleanup;
|
|
@@ -1079,11 +1178,7 @@ function unwrap(value) {
|
|
|
1079
1178
|
return value?.[$TARGET]?.[STORE_NODE] ?? value;
|
|
1080
1179
|
}
|
|
1081
1180
|
function getOverrideValue(value, override, nodes, key) {
|
|
1082
|
-
return
|
|
1083
|
-
? read(nodes[key])
|
|
1084
|
-
: override && key in override
|
|
1085
|
-
? override[key]
|
|
1086
|
-
: value[key];
|
|
1181
|
+
return override && key in override ? override[key] : value[key];
|
|
1087
1182
|
}
|
|
1088
1183
|
function getAllKeys(value, override, next) {
|
|
1089
1184
|
const keys = getKeys(value, override);
|
|
@@ -1169,10 +1264,12 @@ function applyState(next, state, keyFn, all) {
|
|
|
1169
1264
|
} else target[STORE_NODE][j] && setSignal(target[STORE_NODE][j], wrap(next[j], target));
|
|
1170
1265
|
}
|
|
1171
1266
|
if (start < next.length) changed = true;
|
|
1172
|
-
} else if (
|
|
1267
|
+
} else if (next.length) {
|
|
1173
1268
|
for (let i = 0, len = next.length; i < len; i++) {
|
|
1174
1269
|
const item = getOverrideValue(previous, override, nodes, i);
|
|
1175
|
-
isWrappable(item)
|
|
1270
|
+
isWrappable(item)
|
|
1271
|
+
? applyState(next[i], wrap(item, target), keyFn, all)
|
|
1272
|
+
: target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]);
|
|
1176
1273
|
}
|
|
1177
1274
|
}
|
|
1178
1275
|
if (prevLength !== next.length) {
|
|
@@ -1222,36 +1319,74 @@ function reconcile(value, key, all = false) {
|
|
|
1222
1319
|
function createProjectionInternal(fn, initialValue = {}, options) {
|
|
1223
1320
|
let node;
|
|
1224
1321
|
const wrappedMap = new WeakMap();
|
|
1322
|
+
const wrapper = s => {
|
|
1323
|
+
s[STORE_WRAP] = wrapProjection;
|
|
1324
|
+
s[STORE_LOOKUP] = wrappedMap;
|
|
1325
|
+
Object.defineProperty(s, STORE_FIREWALL, {
|
|
1326
|
+
get() {
|
|
1327
|
+
return node;
|
|
1328
|
+
},
|
|
1329
|
+
configurable: true
|
|
1330
|
+
});
|
|
1331
|
+
};
|
|
1225
1332
|
const wrapProjection = source => {
|
|
1226
1333
|
if (wrappedMap.has(source)) return wrappedMap.get(source);
|
|
1227
1334
|
if (source[$TARGET]?.[STORE_WRAP] === wrapProjection) return source;
|
|
1228
|
-
const wrapped = createStoreProxy(source, storeTraps,
|
|
1229
|
-
[STORE_WRAP]: wrapProjection,
|
|
1230
|
-
[STORE_LOOKUP]: wrappedMap,
|
|
1231
|
-
[STORE_FIREWALL]() {
|
|
1232
|
-
return node;
|
|
1233
|
-
}
|
|
1234
|
-
});
|
|
1335
|
+
const wrapped = createStoreProxy(source, storeTraps, wrapper);
|
|
1235
1336
|
wrappedMap.set(source, wrapped);
|
|
1236
1337
|
return wrapped;
|
|
1237
1338
|
};
|
|
1238
1339
|
const wrappedStore = wrapProjection(initialValue);
|
|
1239
1340
|
node = computed(() => {
|
|
1240
1341
|
const owner = node || getOwner();
|
|
1241
|
-
storeSetter(wrappedStore, s => {
|
|
1342
|
+
storeSetter(new Proxy(wrappedStore, writeTraps), s => {
|
|
1242
1343
|
const value = handleAsync(owner, fn(s), value => {
|
|
1243
|
-
value !==
|
|
1344
|
+
value !== wrappedStore &&
|
|
1244
1345
|
value !== undefined &&
|
|
1245
1346
|
storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
|
|
1347
|
+
setSignal(node, undefined);
|
|
1246
1348
|
});
|
|
1247
|
-
value !==
|
|
1349
|
+
value !== wrappedStore &&
|
|
1350
|
+
value !== undefined &&
|
|
1351
|
+
reconcile(value, options?.key || "id", options?.all)(wrappedStore);
|
|
1248
1352
|
});
|
|
1249
1353
|
});
|
|
1354
|
+
node._preventAutoDisposal = true;
|
|
1250
1355
|
return { store: wrappedStore, node: node };
|
|
1251
1356
|
}
|
|
1252
1357
|
function createProjection(fn, initialValue = {}, options) {
|
|
1253
1358
|
return createProjectionInternal(fn, initialValue, options).store;
|
|
1254
1359
|
}
|
|
1360
|
+
const writeTraps = {
|
|
1361
|
+
get(_, prop) {
|
|
1362
|
+
let value;
|
|
1363
|
+
setWriteOverride(true);
|
|
1364
|
+
try {
|
|
1365
|
+
value = _[prop];
|
|
1366
|
+
} finally {
|
|
1367
|
+
setWriteOverride(false);
|
|
1368
|
+
}
|
|
1369
|
+
return typeof value === "object" && value !== null ? new Proxy(value, writeTraps) : value;
|
|
1370
|
+
},
|
|
1371
|
+
set(_, prop, value) {
|
|
1372
|
+
setWriteOverride(true);
|
|
1373
|
+
try {
|
|
1374
|
+
_[prop] = value;
|
|
1375
|
+
} finally {
|
|
1376
|
+
setWriteOverride(false);
|
|
1377
|
+
}
|
|
1378
|
+
return true;
|
|
1379
|
+
},
|
|
1380
|
+
deleteProperty(_, prop) {
|
|
1381
|
+
setWriteOverride(true);
|
|
1382
|
+
try {
|
|
1383
|
+
delete _[prop];
|
|
1384
|
+
} finally {
|
|
1385
|
+
setWriteOverride(false);
|
|
1386
|
+
}
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1255
1390
|
const $TRACK = Symbol("STORE_TRACK"),
|
|
1256
1391
|
$DEEP = Symbol("STORE_DEEP"),
|
|
1257
1392
|
$TARGET = Symbol("STORE_TARGET"),
|
|
@@ -1271,7 +1406,7 @@ function createStoreProxy(value, traps = storeTraps, extend) {
|
|
|
1271
1406
|
newTarget = [];
|
|
1272
1407
|
newTarget.v = value;
|
|
1273
1408
|
} else newTarget = { v: value };
|
|
1274
|
-
extend &&
|
|
1409
|
+
extend && extend(newTarget);
|
|
1275
1410
|
return (newTarget[$PROXY] = new Proxy(newTarget, traps));
|
|
1276
1411
|
}
|
|
1277
1412
|
const storeLookup = new WeakMap();
|
|
@@ -1284,6 +1419,13 @@ function wrap(value, target) {
|
|
|
1284
1419
|
function isWrappable(obj) {
|
|
1285
1420
|
return obj != null && typeof obj === "object" && !Object.isFrozen(obj);
|
|
1286
1421
|
}
|
|
1422
|
+
let writeOverride = false;
|
|
1423
|
+
function setWriteOverride(value) {
|
|
1424
|
+
writeOverride = value;
|
|
1425
|
+
}
|
|
1426
|
+
function writeOnly(proxy) {
|
|
1427
|
+
return writeOverride || !!Writing?.has(proxy);
|
|
1428
|
+
}
|
|
1287
1429
|
function getNodes(target, type) {
|
|
1288
1430
|
let nodes = target[type];
|
|
1289
1431
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
@@ -1304,9 +1446,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual) {
|
|
|
1304
1446
|
}
|
|
1305
1447
|
function trackSelf(target, symbol = $TRACK) {
|
|
1306
1448
|
getObserver() &&
|
|
1307
|
-
read(
|
|
1308
|
-
getNode(getNodes(target, STORE_NODE), symbol, undefined, target[STORE_FIREWALL]?.(), false)
|
|
1309
|
-
);
|
|
1449
|
+
read(getNode(getNodes(target, STORE_NODE), symbol, undefined, target[STORE_FIREWALL], false));
|
|
1310
1450
|
}
|
|
1311
1451
|
function getKeys(source, override, enumerable = true) {
|
|
1312
1452
|
const baseKeys = untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)));
|
|
@@ -1332,6 +1472,7 @@ const storeTraps = {
|
|
|
1332
1472
|
get(target, property, receiver) {
|
|
1333
1473
|
if (property === $TARGET) return target;
|
|
1334
1474
|
if (property === $PROXY) return receiver;
|
|
1475
|
+
if (property === $REFRESH) return target[STORE_FIREWALL];
|
|
1335
1476
|
if (property === $TRACK || property === $DEEP) {
|
|
1336
1477
|
trackSelf(target, property);
|
|
1337
1478
|
return receiver;
|
|
@@ -1345,7 +1486,7 @@ const storeTraps = {
|
|
|
1345
1486
|
const desc = Object.getOwnPropertyDescriptor(storeValue, property);
|
|
1346
1487
|
if (desc && desc.get) return desc.get.call(receiver);
|
|
1347
1488
|
}
|
|
1348
|
-
if (
|
|
1489
|
+
if (writeOnly(receiver)) {
|
|
1349
1490
|
let value =
|
|
1350
1491
|
tracked && (overridden || !proxySource)
|
|
1351
1492
|
? tracked._pendingValue !== NOT_PENDING
|
|
@@ -1355,7 +1496,7 @@ const storeTraps = {
|
|
|
1355
1496
|
value === $DELETED && (value = undefined);
|
|
1356
1497
|
if (!isWrappable(value)) return value;
|
|
1357
1498
|
const wrapped = wrap(value, target);
|
|
1358
|
-
Writing
|
|
1499
|
+
Writing?.add(wrapped);
|
|
1359
1500
|
return wrapped;
|
|
1360
1501
|
}
|
|
1361
1502
|
let value = tracked
|
|
@@ -1378,7 +1519,7 @@ const storeTraps = {
|
|
|
1378
1519
|
nodes,
|
|
1379
1520
|
property,
|
|
1380
1521
|
isWrappable(value) ? wrap(value, target) : value,
|
|
1381
|
-
target[STORE_FIREWALL]
|
|
1522
|
+
target[STORE_FIREWALL]
|
|
1382
1523
|
)
|
|
1383
1524
|
);
|
|
1384
1525
|
}
|
|
@@ -1392,12 +1533,12 @@ const storeTraps = {
|
|
|
1392
1533
|
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
1393
1534
|
: property in target[STORE_VALUE];
|
|
1394
1535
|
getObserver() &&
|
|
1395
|
-
read(getNode(getNodes(target, STORE_HAS), property, has, target[STORE_FIREWALL]
|
|
1536
|
+
read(getNode(getNodes(target, STORE_HAS), property, has, target[STORE_FIREWALL]));
|
|
1396
1537
|
return has;
|
|
1397
1538
|
},
|
|
1398
1539
|
set(target, property, rawValue) {
|
|
1399
1540
|
const store = target[$PROXY];
|
|
1400
|
-
if (
|
|
1541
|
+
if (writeOnly(store)) {
|
|
1401
1542
|
untrack(() => {
|
|
1402
1543
|
const state = target[STORE_VALUE];
|
|
1403
1544
|
const base = state[property];
|
|
@@ -1432,7 +1573,7 @@ const storeTraps = {
|
|
|
1432
1573
|
return true;
|
|
1433
1574
|
},
|
|
1434
1575
|
deleteProperty(target, property) {
|
|
1435
|
-
if (
|
|
1576
|
+
if (writeOnly(target[$PROXY]) && target[STORE_OVERRIDE]?.[property] !== $DELETED) {
|
|
1436
1577
|
untrack(() => {
|
|
1437
1578
|
const prev =
|
|
1438
1579
|
target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
@@ -2157,6 +2298,7 @@ export {
|
|
|
2157
2298
|
NoOwnerError,
|
|
2158
2299
|
NotReadyError,
|
|
2159
2300
|
SUPPORTS_PROXY,
|
|
2301
|
+
action,
|
|
2160
2302
|
createBoundary,
|
|
2161
2303
|
createContext,
|
|
2162
2304
|
createEffect,
|