valdres 1.0.0-beta.3 → 1.0.0-beta.5
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/index.js +647 -315
- package/dist/types/lib/IS_PROD.d.ts +1 -0
- package/dist/types/lib/asyncDependencyTracking.d.ts +0 -3
- package/dist/types/lib/atomFamilyIndex.d.ts +1 -0
- package/dist/types/lib/createStoreData.d.ts +2 -3
- package/dist/types/lib/initSelector.d.ts +10 -15
- package/dist/types/lib/mountAtom.d.ts +26 -4
- package/dist/types/lib/propagateUpdatedAtoms.d.ts +5 -3
- package/dist/types/lib/setAtoms.d.ts +1 -1
- package/dist/types/lib/setValueInData.d.ts +5 -4
- package/dist/types/lib/storeFromStoreData.d.ts +2 -2
- package/dist/types/lib/transaction.d.ts +1 -0
- package/dist/types/lib/writeAtoms.d.ts +21 -0
- package/dist/types/types/Atom.d.ts +3 -0
- package/dist/types/types/AtomFamily.d.ts +4 -0
- package/dist/types/types/GlobalAtom.d.ts +1 -1
- package/dist/types/types/Selector.d.ts +2 -0
- package/dist/types/types/Store.d.ts +2 -2
- package/dist/types/types/StoreData.d.ts +39 -9
- package/dist/types/types/Subscription.d.ts +7 -0
- package/dist/types/utils/deepFreeze.d.ts +1 -1
- package/package.json +1 -1
- package/dist/types/lib/isProd.d.ts +0 -1
package/dist/index.js
CHANGED
|
@@ -123,17 +123,18 @@ var isPromiseLike = (object) => {
|
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
// src/utils/deepFreeze.ts
|
|
126
|
-
var deepFreeze = (obj, seen
|
|
126
|
+
var deepFreeze = (obj, seen) => {
|
|
127
127
|
if (obj === null || obj === undefined)
|
|
128
128
|
return obj;
|
|
129
129
|
if (typeof obj !== "object" && typeof obj !== "function")
|
|
130
130
|
return obj;
|
|
131
|
-
if (
|
|
131
|
+
if (Object.isFrozen(obj) || seen?.has(obj))
|
|
132
132
|
return obj;
|
|
133
|
-
seen.add(obj);
|
|
134
133
|
if (Array.isArray(obj)) {
|
|
135
134
|
for (const item of obj) {
|
|
136
135
|
if (item && typeof item === "object") {
|
|
136
|
+
seen ??= new WeakSet;
|
|
137
|
+
seen.add(obj);
|
|
137
138
|
deepFreeze(item, seen);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
@@ -142,6 +143,8 @@ var deepFreeze = (obj, seen = new WeakSet) => {
|
|
|
142
143
|
for (const name of propNames) {
|
|
143
144
|
const value = obj[name];
|
|
144
145
|
if (value && typeof value === "object") {
|
|
146
|
+
seen ??= new WeakSet;
|
|
147
|
+
seen.add(obj);
|
|
145
148
|
deepFreeze(value, seen);
|
|
146
149
|
}
|
|
147
150
|
}
|
|
@@ -149,26 +152,28 @@ var deepFreeze = (obj, seen = new WeakSet) => {
|
|
|
149
152
|
return Object.freeze(obj);
|
|
150
153
|
};
|
|
151
154
|
|
|
152
|
-
// src/lib/
|
|
153
|
-
var
|
|
154
|
-
return false;
|
|
155
|
-
};
|
|
155
|
+
// src/lib/IS_PROD.ts
|
|
156
|
+
var IS_PROD = typeof process !== "undefined" && process.env != null && process.env.NODE_ENV === "production";
|
|
156
157
|
|
|
157
158
|
// src/lib/setValueInData.ts
|
|
158
159
|
var trackScopeValue = (key, data) => {
|
|
159
160
|
const parent = data.parent;
|
|
161
|
+
const indexKeys = data.scopeIndexKeys;
|
|
162
|
+
if (!parent || !indexKeys) {
|
|
163
|
+
throw new Error("trackScopeValue called on a root store");
|
|
164
|
+
}
|
|
160
165
|
let set = parent.scopeValueIndex.get(key);
|
|
161
166
|
if (!set) {
|
|
162
167
|
set = new Set;
|
|
163
168
|
parent.scopeValueIndex.set(key, set);
|
|
164
169
|
}
|
|
165
170
|
set.add(data);
|
|
166
|
-
|
|
171
|
+
indexKeys.add(key);
|
|
167
172
|
};
|
|
168
173
|
var setValueInData = (atom, value, data) => {
|
|
169
|
-
const isNewAtomInScope =
|
|
174
|
+
const isNewAtomInScope = data.parent && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
|
|
170
175
|
let written;
|
|
171
|
-
if (atom.mutable ||
|
|
176
|
+
if (atom.mutable || IS_PROD) {
|
|
172
177
|
data.values.set(atom, value);
|
|
173
178
|
written = value;
|
|
174
179
|
} else {
|
|
@@ -176,8 +181,14 @@ var setValueInData = (atom, value, data) => {
|
|
|
176
181
|
data.values.set(atom, frozenValue);
|
|
177
182
|
written = frozenValue;
|
|
178
183
|
}
|
|
179
|
-
if (isNewAtomInScope)
|
|
184
|
+
if (isNewAtomInScope) {
|
|
180
185
|
trackScopeValue(atom, data);
|
|
186
|
+
const subs = data.subscriptions.get(atom);
|
|
187
|
+
if (subs) {
|
|
188
|
+
for (const sub of subs)
|
|
189
|
+
sub.reRoot?.();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
181
192
|
if (atom.maxAge !== undefined) {
|
|
182
193
|
data.lastValueWriteAt.set(atom, Date.now());
|
|
183
194
|
}
|
|
@@ -245,14 +256,14 @@ var initFamilyIndex = (family, data) => {
|
|
|
245
256
|
if (data.values.has(family))
|
|
246
257
|
return data.values.get(family).__index;
|
|
247
258
|
let parentIndex;
|
|
248
|
-
if (
|
|
259
|
+
if (data.parent) {
|
|
249
260
|
parentIndex = initFamilyIndex(family, data.parent);
|
|
250
261
|
if (!parentIndex)
|
|
251
262
|
throw new Error("Parent index is missing");
|
|
252
263
|
}
|
|
253
264
|
const index = createAtomFamilyIndex(parentIndex);
|
|
254
265
|
data.values.set(family, renderAtomFamilyIndex(index));
|
|
255
|
-
if (
|
|
266
|
+
if (data.parent) {
|
|
256
267
|
trackScopeValue(family, data);
|
|
257
268
|
}
|
|
258
269
|
return index;
|
|
@@ -271,8 +282,10 @@ var recursivelyUpdateIndexes = (data, family) => {
|
|
|
271
282
|
const childScopesWithFamily = data.scopeValueIndex.get(family);
|
|
272
283
|
if (!childScopesWithFamily || childScopesWithFamily.size === 0)
|
|
273
284
|
return;
|
|
285
|
+
const parentIndex = data.values.get(family).__index;
|
|
274
286
|
for (const scopedData of childScopesWithFamily) {
|
|
275
287
|
const index = scopedData.values.get(family).__index;
|
|
288
|
+
index.parentIndex = parentIndex;
|
|
276
289
|
index.rendered = null;
|
|
277
290
|
index.renderedArray = null;
|
|
278
291
|
scopedData.values.set(family, renderAtomFamilyIndex(index));
|
|
@@ -343,7 +356,6 @@ ${generateSelectorTrace(this.selectors)}`;
|
|
|
343
356
|
|
|
344
357
|
// src/lib/asyncDependencyTracking.ts
|
|
345
358
|
var pendingAsyncDeps = new WeakMap;
|
|
346
|
-
var latestEvalContext = new WeakMap;
|
|
347
359
|
|
|
348
360
|
class SuspendAndWaitForResolveError extends Error {
|
|
349
361
|
promise;
|
|
@@ -379,7 +391,8 @@ var lateGet = (state, selector, data) => {
|
|
|
379
391
|
try {
|
|
380
392
|
return getState(state, data, lateInitSet);
|
|
381
393
|
} finally {
|
|
382
|
-
if (isNewDep &&
|
|
394
|
+
if (isNewDep && isLive(selector, data)) {
|
|
395
|
+
onLiveDependencyAdded(state, data);
|
|
383
396
|
mountTransitiveDeps(state, data);
|
|
384
397
|
}
|
|
385
398
|
}
|
|
@@ -391,23 +404,22 @@ var cleanUpRejectedPromise = (selector, data, promise) => {
|
|
|
391
404
|
};
|
|
392
405
|
|
|
393
406
|
// src/lib/initSelector.ts
|
|
394
|
-
class NeedsInitError {
|
|
395
|
-
selector;
|
|
396
|
-
constructor(selector) {
|
|
397
|
-
this.selector = selector;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
var _evalDepth = 0;
|
|
401
|
-
var _inTrampoline = false;
|
|
402
|
-
var MAX_EVAL_DEPTH = 100;
|
|
403
|
-
var sharedCircularDepSet = new WeakSet;
|
|
404
407
|
var neverAbortedSignal = new AbortController().signal;
|
|
405
408
|
var syncOptionsCache = new WeakMap;
|
|
406
|
-
var
|
|
409
|
+
var getSyncOptions = (data) => {
|
|
410
|
+
let cached = syncOptionsCache.get(data);
|
|
411
|
+
if (!cached) {
|
|
412
|
+
cached = { signal: neverAbortedSignal, storeId: data.id };
|
|
413
|
+
syncOptionsCache.set(data, cached);
|
|
414
|
+
}
|
|
415
|
+
return cached;
|
|
416
|
+
};
|
|
417
|
+
var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencySet = data.circularDepSet, depsChangeOut) => {
|
|
407
418
|
const currentDependencies = data.stateDependencies.get(selector);
|
|
408
419
|
const updatedDepsArray = [];
|
|
409
420
|
let depsChanged = false;
|
|
410
421
|
let evaluationComplete = false;
|
|
422
|
+
const latestEvalContext = data.latestEvalContext;
|
|
411
423
|
const prevCtx = latestEvalContext.get(selector);
|
|
412
424
|
if (prevCtx)
|
|
413
425
|
prevCtx.revoked = true;
|
|
@@ -418,34 +430,33 @@ var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencyS
|
|
|
418
430
|
}
|
|
419
431
|
circularDependencySet.add(selector);
|
|
420
432
|
try {
|
|
421
|
-
const prev = data.abortControllers.get(selector);
|
|
422
433
|
let options;
|
|
423
|
-
if (
|
|
424
|
-
|
|
425
|
-
if (!cached) {
|
|
426
|
-
cached = { signal: neverAbortedSignal, storeId: data.id };
|
|
427
|
-
syncOptionsCache.set(data, cached);
|
|
428
|
-
}
|
|
429
|
-
options = cached;
|
|
434
|
+
if (selector.get.length < 2) {
|
|
435
|
+
options = getSyncOptions(data);
|
|
430
436
|
} else {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
437
|
+
const prev = data.abortControllers.get(selector);
|
|
438
|
+
if (prev === false) {
|
|
439
|
+
options = getSyncOptions(data);
|
|
440
|
+
} else {
|
|
441
|
+
if (prev)
|
|
442
|
+
prev.abort();
|
|
443
|
+
let controller;
|
|
444
|
+
const myEvalCtx = evalCtx;
|
|
445
|
+
options = {
|
|
446
|
+
storeId: data.id,
|
|
447
|
+
get signal() {
|
|
448
|
+
if (!controller) {
|
|
449
|
+
controller = new AbortController;
|
|
450
|
+
if (myEvalCtx.revoked) {
|
|
451
|
+
controller.abort();
|
|
452
|
+
} else {
|
|
453
|
+
data.abortControllers.set(selector, controller);
|
|
454
|
+
}
|
|
444
455
|
}
|
|
456
|
+
return controller.signal;
|
|
445
457
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
};
|
|
458
|
+
};
|
|
459
|
+
}
|
|
449
460
|
}
|
|
450
461
|
let allDepsThisEval;
|
|
451
462
|
let result;
|
|
@@ -470,8 +481,6 @@ var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencyS
|
|
|
470
481
|
return value;
|
|
471
482
|
}, options);
|
|
472
483
|
} catch (error) {
|
|
473
|
-
if (error instanceof NeedsInitError)
|
|
474
|
-
throw error;
|
|
475
484
|
if (error instanceof SuspendAndWaitForResolveError) {
|
|
476
485
|
result = error;
|
|
477
486
|
} else if (error instanceof SelectorEvaluationError) {
|
|
@@ -492,22 +501,28 @@ var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencyS
|
|
|
492
501
|
updatedDependencies.add(dep);
|
|
493
502
|
}
|
|
494
503
|
}
|
|
495
|
-
const
|
|
504
|
+
const prev = currentDependencies ?? new Set;
|
|
496
505
|
for (const state of updatedDependencies) {
|
|
497
|
-
if (!
|
|
506
|
+
if (!prev.has(state)) {
|
|
498
507
|
const set = getOrInitDependentsSet(state, data);
|
|
499
508
|
set.add(selector);
|
|
500
|
-
if (
|
|
501
|
-
|
|
509
|
+
if (depsChangeOut) {
|
|
510
|
+
if (!depsChangeOut.added)
|
|
511
|
+
depsChangeOut.added = new Set;
|
|
512
|
+
depsChangeOut.added.add(state);
|
|
513
|
+
}
|
|
502
514
|
}
|
|
503
515
|
}
|
|
504
516
|
if (!isAsyncResult) {
|
|
505
|
-
for (const state of
|
|
517
|
+
for (const state of prev) {
|
|
506
518
|
if (!updatedDependencies.has(state)) {
|
|
507
519
|
const set = getOrInitDependentsSet(state, data);
|
|
508
520
|
set.delete(selector);
|
|
509
|
-
if (
|
|
510
|
-
|
|
521
|
+
if (depsChangeOut) {
|
|
522
|
+
if (!depsChangeOut.removed)
|
|
523
|
+
depsChangeOut.removed = new Set;
|
|
524
|
+
depsChangeOut.removed.add(state);
|
|
525
|
+
}
|
|
511
526
|
}
|
|
512
527
|
}
|
|
513
528
|
}
|
|
@@ -534,7 +549,7 @@ var handleSelectorResult = (value, selector, data) => {
|
|
|
534
549
|
const initializedAtomsSet = new Set;
|
|
535
550
|
const res = initSelector(selector, data, initializedAtomsSet);
|
|
536
551
|
if (initializedAtomsSet.size > 0) {
|
|
537
|
-
|
|
552
|
+
propagateAtomUpdate([...initializedAtomsSet], data);
|
|
538
553
|
}
|
|
539
554
|
return res;
|
|
540
555
|
}).catch(() => {
|
|
@@ -556,12 +571,16 @@ var handleSelectorResult = (value, selector, data) => {
|
|
|
556
571
|
pendingAsyncDeps.delete(value);
|
|
557
572
|
const currentDeps = data.stateDependencies.get(selector);
|
|
558
573
|
if (currentDeps) {
|
|
574
|
+
const selectorIsLive = isLive(selector, data);
|
|
559
575
|
for (const dep of currentDeps) {
|
|
560
576
|
if (!evalDeps.has(dep)) {
|
|
561
577
|
currentDeps.delete(dep);
|
|
562
578
|
const dependents2 = data.stateDependents.get(dep);
|
|
563
579
|
if (dependents2)
|
|
564
580
|
dependents2.delete(selector);
|
|
581
|
+
if (selectorIsLive) {
|
|
582
|
+
onLiveDependencyRemoved(dep, data);
|
|
583
|
+
}
|
|
565
584
|
unmountOrphanedDeps(dep, data);
|
|
566
585
|
}
|
|
567
586
|
}
|
|
@@ -579,11 +598,13 @@ var handleSelectorResult = (value, selector, data) => {
|
|
|
579
598
|
});
|
|
580
599
|
return value;
|
|
581
600
|
} else {
|
|
582
|
-
|
|
601
|
+
if (selector.get.length >= 2) {
|
|
602
|
+
data.abortControllers.set(selector, false);
|
|
603
|
+
}
|
|
583
604
|
return value;
|
|
584
605
|
}
|
|
585
606
|
};
|
|
586
|
-
var
|
|
607
|
+
var initSelector = (selector, data, initializedAtomsSet, circularDependencySet = data.circularDepSet) => {
|
|
587
608
|
const existingValue = data.values.get(selector);
|
|
588
609
|
const updatedValue = evaluate(selector, data, initializedAtomsSet, circularDependencySet);
|
|
589
610
|
const areEqual = isPromiseLike(existingValue) || isPromiseLike(updatedValue) ? existingValue === updatedValue : selector.equal(existingValue, updatedValue);
|
|
@@ -594,56 +615,6 @@ var initSelectorDirect = (selector, data, initializedAtomsSet, circularDependenc
|
|
|
594
615
|
return true;
|
|
595
616
|
}
|
|
596
617
|
};
|
|
597
|
-
var initSelectorTrampoline = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
598
|
-
const stack = [selector];
|
|
599
|
-
const inStack = new Set([selector]);
|
|
600
|
-
while (stack.length > 0) {
|
|
601
|
-
const current = stack[stack.length - 1];
|
|
602
|
-
if (data.values.has(current)) {
|
|
603
|
-
stack.pop();
|
|
604
|
-
inStack.delete(current);
|
|
605
|
-
continue;
|
|
606
|
-
}
|
|
607
|
-
try {
|
|
608
|
-
initSelectorDirect(current, data, initializedAtomsSet, circularDependencySet);
|
|
609
|
-
stack.pop();
|
|
610
|
-
inStack.delete(current);
|
|
611
|
-
} catch (e) {
|
|
612
|
-
if (e instanceof NeedsInitError) {
|
|
613
|
-
if (inStack.has(e.selector)) {
|
|
614
|
-
throw new SelectorCircularDependencyError;
|
|
615
|
-
}
|
|
616
|
-
stack.push(e.selector);
|
|
617
|
-
inStack.add(e.selector);
|
|
618
|
-
} else {
|
|
619
|
-
throw e;
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
var initSelector = (selector, data, initializedAtomsSet, circularDependencySet = sharedCircularDepSet) => {
|
|
625
|
-
const isTopLevel = _evalDepth === 0 && !_inTrampoline;
|
|
626
|
-
_evalDepth++;
|
|
627
|
-
const existingValue = data.values.get(selector);
|
|
628
|
-
try {
|
|
629
|
-
return initSelectorDirect(selector, data, initializedAtomsSet, circularDependencySet);
|
|
630
|
-
} catch (e) {
|
|
631
|
-
if (e instanceof NeedsInitError && isTopLevel) {
|
|
632
|
-
_inTrampoline = true;
|
|
633
|
-
try {
|
|
634
|
-
initSelectorTrampoline(selector, data, initializedAtomsSet, circularDependencySet);
|
|
635
|
-
} finally {
|
|
636
|
-
_inTrampoline = false;
|
|
637
|
-
}
|
|
638
|
-
const newValue = data.values.get(selector);
|
|
639
|
-
const areEqual = isPromiseLike(existingValue) || isPromiseLike(newValue) ? existingValue === newValue : selector.equal(existingValue, newValue);
|
|
640
|
-
return !areEqual;
|
|
641
|
-
}
|
|
642
|
-
throw e;
|
|
643
|
-
} finally {
|
|
644
|
-
_evalDepth--;
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
618
|
var evaluate = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
648
619
|
let tmpValue;
|
|
649
620
|
try {
|
|
@@ -657,23 +628,18 @@ var evaluate = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
|
657
628
|
};
|
|
658
629
|
|
|
659
630
|
// src/lib/propagateUpdatedAtoms.ts
|
|
660
|
-
var
|
|
661
|
-
const existingValue = data.values.get(selector);
|
|
662
|
-
const addedDeps = new Set;
|
|
663
|
-
const removedDeps = new Set;
|
|
631
|
+
var reEvaluateSelector = (selector, data, updatedAtoms, depsChange, existingValue) => {
|
|
664
632
|
try {
|
|
665
|
-
const rawValue = evaluateSelector(selector, data, updatedAtoms, undefined,
|
|
666
|
-
const
|
|
667
|
-
const areEqual = isPromiseLike(existingValue) || isPromiseLike(
|
|
668
|
-
if (areEqual)
|
|
669
|
-
return
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
} catch (error) {
|
|
633
|
+
const rawValue = evaluateSelector(selector, data, updatedAtoms, undefined, depsChange);
|
|
634
|
+
const updatedValue = handleSelectorResult(rawValue, selector, data);
|
|
635
|
+
const areEqual = isPromiseLike(existingValue) || isPromiseLike(updatedValue) ? existingValue === updatedValue : selector.equal(existingValue, updatedValue, updatedAtoms);
|
|
636
|
+
if (areEqual)
|
|
637
|
+
return false;
|
|
638
|
+
setValueInData(selector, updatedValue, data);
|
|
639
|
+
return true;
|
|
640
|
+
} catch {
|
|
675
641
|
data.values.delete(selector);
|
|
676
|
-
return
|
|
642
|
+
return true;
|
|
677
643
|
}
|
|
678
644
|
};
|
|
679
645
|
var callSubscribers = (subscriptions, families) => {
|
|
@@ -715,7 +681,7 @@ var addSetToSet = (fromSet, toSet) => {
|
|
|
715
681
|
}
|
|
716
682
|
}
|
|
717
683
|
};
|
|
718
|
-
var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now()) => {
|
|
684
|
+
var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now(), evaluatedSelectors) => {
|
|
719
685
|
const selectors = new Set;
|
|
720
686
|
for (const atom of atoms) {
|
|
721
687
|
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
@@ -736,7 +702,7 @@ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = ne
|
|
|
736
702
|
deleteFamilyAtomsFromSet(family, familyAtoms, data, timestamp);
|
|
737
703
|
}
|
|
738
704
|
}
|
|
739
|
-
propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
|
|
705
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, false, evaluatedSelectors);
|
|
740
706
|
if (families.size > 0 && data.scopes && data.scopes.size > 0) {
|
|
741
707
|
const scopeFamilies = new Map;
|
|
742
708
|
for (const family of families.keys()) {
|
|
@@ -753,12 +719,12 @@ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = ne
|
|
|
753
719
|
}
|
|
754
720
|
}
|
|
755
721
|
for (const [scope, familiesInScope] of scopeFamilies) {
|
|
756
|
-
|
|
722
|
+
propagateInScope(familiesInScope, scope, false, evaluatedSelectors);
|
|
757
723
|
}
|
|
758
724
|
}
|
|
759
725
|
};
|
|
760
|
-
var
|
|
761
|
-
if (atoms.length === 1
|
|
726
|
+
var propagateAtomUpdate = (atoms, data, isInitOnly = false, evaluatedSelectors) => {
|
|
727
|
+
if (atoms.length === 1) {
|
|
762
728
|
const atom = atoms[0];
|
|
763
729
|
if (!isFamilyAtom(atom) && !isAtomFamily(atom)) {
|
|
764
730
|
const dependents = data.stateDependents.get(atom);
|
|
@@ -771,24 +737,21 @@ var propagateUpdatedAtoms = (atoms, data, subscriptions, families, isRecursive =
|
|
|
771
737
|
}
|
|
772
738
|
}
|
|
773
739
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
if (!families)
|
|
777
|
-
families = new Map;
|
|
740
|
+
const subscriptions = new Set;
|
|
741
|
+
const families = new Map;
|
|
778
742
|
const selectors = new Set;
|
|
779
743
|
for (const atom of atoms) {
|
|
780
744
|
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
if (
|
|
784
|
-
|
|
785
|
-
families.set(atom.family, new Set);
|
|
786
|
-
}
|
|
787
|
-
families.get(atom.family).add(atom);
|
|
745
|
+
addSetToSet(data.subscriptions.get(atom), subscriptions);
|
|
746
|
+
if (isFamilyAtom(atom)) {
|
|
747
|
+
if (!families.has(atom.family)) {
|
|
748
|
+
families.set(atom.family, new Set);
|
|
788
749
|
}
|
|
750
|
+
families.get(atom.family).add(atom);
|
|
789
751
|
}
|
|
790
752
|
}
|
|
791
753
|
if (families.size > 0) {
|
|
754
|
+
const timestamp = performance.now();
|
|
792
755
|
for (const [family, familyAtoms] of families) {
|
|
793
756
|
addSetToSet(data.stateDependents.get(family), selectors);
|
|
794
757
|
addSetToSet(data.subscriptions.get(family), subscriptions);
|
|
@@ -797,96 +760,308 @@ var propagateUpdatedAtoms = (atoms, data, subscriptions, families, isRecursive =
|
|
|
797
760
|
addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
|
|
798
761
|
}
|
|
799
762
|
}
|
|
800
|
-
if (
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
763
|
+
if (data.scopes && data.scopes.size > 0) {
|
|
764
|
+
for (const atom of atoms) {
|
|
765
|
+
if (isAtomFamily(atom) && !families.has(atom)) {
|
|
766
|
+
recursivelyUpdateIndexes(data, atom);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly, evaluatedSelectors);
|
|
771
|
+
if (data.scopes && data.scopes.size > 0) {
|
|
772
|
+
propagateToScopes(atoms, data, isInitOnly, evaluatedSelectors);
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
var propagateInScope = (atoms, data, isInitOnly = false, evaluatedSelectors) => {
|
|
776
|
+
const subscriptions = new Set;
|
|
777
|
+
const families = new Map;
|
|
778
|
+
const selectors = new Set;
|
|
779
|
+
for (const atom of atoms) {
|
|
780
|
+
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
781
|
+
}
|
|
782
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly, evaluatedSelectors);
|
|
783
|
+
if (data.scopes && data.scopes.size > 0) {
|
|
784
|
+
propagateToScopes(atoms, data, isInitOnly, evaluatedSelectors);
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
var propagateToScopes = (atoms, data, isInitOnly, evaluatedSelectors) => {
|
|
788
|
+
if (atoms.length === 1) {
|
|
789
|
+
const atom = atoms[0];
|
|
790
|
+
const shadowingScopes = isAtomFamily(atom) ? undefined : data.scopeValueIndex.get(atom);
|
|
791
|
+
for (const [, scope] of data.scopes) {
|
|
792
|
+
if (!shadowingScopes || !shadowingScopes.has(scope)) {
|
|
793
|
+
propagateInScope(atoms, scope, isInitOnly, evaluatedSelectors);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
let anyShadowed = false;
|
|
799
|
+
let atomShadows;
|
|
800
|
+
for (const atom of atoms) {
|
|
801
|
+
if (!isAtomFamily(atom)) {
|
|
802
|
+
const s = data.scopeValueIndex.get(atom);
|
|
803
|
+
if (s && s.size > 0) {
|
|
804
|
+
if (!atomShadows)
|
|
805
|
+
atomShadows = new Map;
|
|
806
|
+
atomShadows.set(atom, s);
|
|
807
|
+
anyShadowed = true;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
if (!anyShadowed) {
|
|
812
|
+
for (const [, scope] of data.scopes) {
|
|
813
|
+
propagateInScope(atoms, scope, isInitOnly, evaluatedSelectors);
|
|
814
|
+
}
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
for (const [, scope] of data.scopes) {
|
|
818
|
+
const atomsToUpdateInScope = [];
|
|
819
|
+
for (const atom of atoms) {
|
|
820
|
+
if (isAtomFamily(atom)) {
|
|
821
|
+
atomsToUpdateInScope.push(atom);
|
|
811
822
|
} else {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
if (!isAtomFamily(atom)) {
|
|
816
|
-
const s = data.scopeValueIndex.get(atom);
|
|
817
|
-
if (s && s.size > 0) {
|
|
818
|
-
if (!atomShadows)
|
|
819
|
-
atomShadows = new Map;
|
|
820
|
-
atomShadows.set(atom, s);
|
|
821
|
-
anyShadowed = true;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
if (!anyShadowed) {
|
|
826
|
-
for (const [, scope] of data.scopes) {
|
|
827
|
-
propagateUpdatedAtoms(atoms, scope, undefined, undefined, false, timestamp, true, isInitOnly);
|
|
828
|
-
}
|
|
829
|
-
} else {
|
|
830
|
-
for (const [, scope] of data.scopes) {
|
|
831
|
-
const atomsToUpdateInScope = [];
|
|
832
|
-
for (const atom of atoms) {
|
|
833
|
-
if (isAtomFamily(atom)) {
|
|
834
|
-
atomsToUpdateInScope.push(atom);
|
|
835
|
-
} else {
|
|
836
|
-
const s = atomShadows.get(atom);
|
|
837
|
-
if (!s || !s.has(scope)) {
|
|
838
|
-
atomsToUpdateInScope.push(atom);
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
if (atomsToUpdateInScope.length > 0) {
|
|
843
|
-
propagateUpdatedAtoms(atomsToUpdateInScope, scope, undefined, undefined, false, timestamp, true, isInitOnly);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
823
|
+
const s = atomShadows.get(atom);
|
|
824
|
+
if (!s || !s.has(scope)) {
|
|
825
|
+
atomsToUpdateInScope.push(atom);
|
|
846
826
|
}
|
|
847
827
|
}
|
|
848
828
|
}
|
|
829
|
+
if (atomsToUpdateInScope.length > 0) {
|
|
830
|
+
propagateInScope(atomsToUpdateInScope, scope, isInitOnly, evaluatedSelectors);
|
|
831
|
+
}
|
|
849
832
|
}
|
|
850
833
|
};
|
|
851
|
-
var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false) => {
|
|
834
|
+
var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false, evaluatedSelectors) => {
|
|
852
835
|
const updatedInitializedAtoms = new Set(updatedAtoms);
|
|
853
836
|
if (selectors.size > 0) {
|
|
854
|
-
propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly);
|
|
837
|
+
propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly, evaluatedSelectors);
|
|
855
838
|
}
|
|
856
839
|
if (subscriptions.size > 0) {
|
|
857
840
|
callSubscribers(subscriptions, families);
|
|
858
841
|
}
|
|
859
842
|
};
|
|
860
|
-
var
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
const
|
|
866
|
-
|
|
843
|
+
var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly, evaluatedSelectors) => {
|
|
844
|
+
const closure = new Set(seeds);
|
|
845
|
+
{
|
|
846
|
+
const stack = [...seeds];
|
|
847
|
+
while (stack.length > 0) {
|
|
848
|
+
const s = stack.pop();
|
|
849
|
+
const downstream = data.stateDependents.get(s);
|
|
850
|
+
if (downstream) {
|
|
851
|
+
for (const d of downstream) {
|
|
852
|
+
if (!closure.has(d)) {
|
|
853
|
+
closure.add(d);
|
|
854
|
+
stack.push(d);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
const pending = new Map;
|
|
861
|
+
const ready = [];
|
|
862
|
+
for (const s of closure) {
|
|
863
|
+
const deps = data.stateDependencies.get(s);
|
|
864
|
+
let count = 0;
|
|
865
|
+
if (deps) {
|
|
866
|
+
for (const d of deps) {
|
|
867
|
+
if (closure.has(d))
|
|
868
|
+
count++;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
pending.set(s, count);
|
|
872
|
+
if (count === 0)
|
|
873
|
+
ready.push(s);
|
|
874
|
+
}
|
|
875
|
+
const needsEval = new Set(seeds);
|
|
876
|
+
let graphMutated = false;
|
|
877
|
+
const advance = (selector, propagateChange) => {
|
|
878
|
+
const downstream = data.stateDependents.get(selector);
|
|
879
|
+
if (!downstream)
|
|
880
|
+
return;
|
|
881
|
+
for (const d of downstream) {
|
|
882
|
+
if (!closure.has(d)) {
|
|
883
|
+
if (propagateChange) {
|
|
884
|
+
graphMutated = true;
|
|
885
|
+
closure.add(d);
|
|
886
|
+
pending.set(d, 0);
|
|
887
|
+
needsEval.add(d);
|
|
888
|
+
ready.push(d);
|
|
889
|
+
}
|
|
867
890
|
continue;
|
|
868
891
|
}
|
|
892
|
+
const c = (pending.get(d) ?? 0) - 1;
|
|
893
|
+
pending.set(d, c);
|
|
894
|
+
if (propagateChange)
|
|
895
|
+
needsEval.add(d);
|
|
896
|
+
if (c <= 0)
|
|
897
|
+
ready.push(d);
|
|
898
|
+
}
|
|
899
|
+
};
|
|
900
|
+
const depsChange = {};
|
|
901
|
+
let head = 0;
|
|
902
|
+
while (head < ready.length) {
|
|
903
|
+
const selector = ready[head++];
|
|
904
|
+
if (evaluatedSelectors !== undefined && evaluatedSelectors.has(selector)) {
|
|
905
|
+
advance(selector, false);
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
const currentValue = data.values.get(selector);
|
|
909
|
+
if (isPromiseLike(currentValue) && isInitOnly) {
|
|
910
|
+
advance(selector, false);
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
if (!needsEval.has(selector)) {
|
|
914
|
+
advance(selector, false);
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
const dependents = data.stateDependents.get(selector);
|
|
918
|
+
const subscribers = data.subscriptions.get(selector);
|
|
919
|
+
if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
|
|
920
|
+
data.values.delete(selector);
|
|
921
|
+
advance(selector, false);
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
depsChange.added = undefined;
|
|
925
|
+
depsChange.removed = undefined;
|
|
926
|
+
const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
|
|
927
|
+
if (evaluatedSelectors !== undefined)
|
|
928
|
+
evaluatedSelectors.add(selector);
|
|
929
|
+
const added = depsChange.added;
|
|
930
|
+
const removed = depsChange.removed;
|
|
931
|
+
if (added || removed) {
|
|
932
|
+
graphMutated = true;
|
|
933
|
+
if (isLive(selector, data)) {
|
|
934
|
+
if (added) {
|
|
935
|
+
for (const dep of added) {
|
|
936
|
+
onLiveDependencyAdded(dep, data);
|
|
937
|
+
mountTransitiveDeps(dep, data);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (removed) {
|
|
941
|
+
for (const dep of removed) {
|
|
942
|
+
onLiveDependencyRemoved(dep, data);
|
|
943
|
+
unmountOrphanedDeps(dep, data);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
advance(selector, wasValueUpdated);
|
|
949
|
+
if (wasValueUpdated && subscribers) {
|
|
950
|
+
addSetToSet(subscribers, collectedSubscribers);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
if (!graphMutated)
|
|
954
|
+
return;
|
|
955
|
+
let stranded;
|
|
956
|
+
for (const s of closure) {
|
|
957
|
+
if (needsEval.has(s) && (pending.get(s) ?? 0) > 0) {
|
|
958
|
+
if (!stranded)
|
|
959
|
+
stranded = new Set;
|
|
960
|
+
stranded.add(s);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (!stranded)
|
|
964
|
+
return;
|
|
965
|
+
let work = stranded;
|
|
966
|
+
while (work.size > 0) {
|
|
967
|
+
const next = new Set;
|
|
968
|
+
for (const selector of work) {
|
|
969
|
+
const currentValue = data.values.get(selector);
|
|
970
|
+
if (isPromiseLike(currentValue) && isInitOnly)
|
|
971
|
+
continue;
|
|
869
972
|
const dependents = data.stateDependents.get(selector);
|
|
870
973
|
const subscribers = data.subscriptions.get(selector);
|
|
871
974
|
if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
|
|
872
975
|
data.values.delete(selector);
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
depsChange.added = undefined;
|
|
979
|
+
depsChange.removed = undefined;
|
|
980
|
+
const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
|
|
981
|
+
if (evaluatedSelectors !== undefined)
|
|
982
|
+
evaluatedSelectors.add(selector);
|
|
983
|
+
const added = depsChange.added;
|
|
984
|
+
const removed = depsChange.removed;
|
|
985
|
+
if ((added || removed) && isLive(selector, data)) {
|
|
986
|
+
if (added) {
|
|
987
|
+
for (const dep of added) {
|
|
988
|
+
onLiveDependencyAdded(dep, data);
|
|
877
989
|
mountTransitiveDeps(dep, data);
|
|
878
990
|
}
|
|
879
|
-
|
|
991
|
+
}
|
|
992
|
+
if (removed) {
|
|
993
|
+
for (const dep of removed) {
|
|
994
|
+
onLiveDependencyRemoved(dep, data);
|
|
880
995
|
unmountOrphanedDeps(dep, data);
|
|
881
996
|
}
|
|
882
997
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
998
|
+
}
|
|
999
|
+
if (wasValueUpdated) {
|
|
1000
|
+
if (subscribers)
|
|
1001
|
+
addSetToSet(subscribers, collectedSubscribers);
|
|
1002
|
+
const downstream = data.stateDependents.get(selector);
|
|
1003
|
+
if (downstream) {
|
|
1004
|
+
for (const d of downstream)
|
|
1005
|
+
next.add(d);
|
|
1006
|
+
}
|
|
887
1007
|
}
|
|
888
1008
|
}
|
|
889
|
-
|
|
1009
|
+
work = next;
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false, evaluatedSelectors) => {
|
|
1013
|
+
if (selectors.size === 0)
|
|
1014
|
+
return;
|
|
1015
|
+
let downstreamSeeds;
|
|
1016
|
+
const depsChange = {};
|
|
1017
|
+
for (const selector of selectors) {
|
|
1018
|
+
if (evaluatedSelectors !== undefined && evaluatedSelectors.has(selector)) {
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
const currentValue = data.values.get(selector);
|
|
1022
|
+
if (isPromiseLike(currentValue) && isInitOnly)
|
|
1023
|
+
continue;
|
|
1024
|
+
const dependents = data.stateDependents.get(selector);
|
|
1025
|
+
const subscribers = data.subscriptions.get(selector);
|
|
1026
|
+
if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
|
|
1027
|
+
data.values.delete(selector);
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
depsChange.added = undefined;
|
|
1031
|
+
depsChange.removed = undefined;
|
|
1032
|
+
const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
|
|
1033
|
+
if (evaluatedSelectors !== undefined)
|
|
1034
|
+
evaluatedSelectors.add(selector);
|
|
1035
|
+
const added = depsChange.added;
|
|
1036
|
+
const removed = depsChange.removed;
|
|
1037
|
+
if ((added || removed) && isLive(selector, data)) {
|
|
1038
|
+
if (added) {
|
|
1039
|
+
for (const dep of added) {
|
|
1040
|
+
onLiveDependencyAdded(dep, data);
|
|
1041
|
+
mountTransitiveDeps(dep, data);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
if (removed) {
|
|
1045
|
+
for (const dep of removed) {
|
|
1046
|
+
onLiveDependencyRemoved(dep, data);
|
|
1047
|
+
unmountOrphanedDeps(dep, data);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
if (!wasValueUpdated)
|
|
1052
|
+
continue;
|
|
1053
|
+
if (subscribers)
|
|
1054
|
+
addSetToSet(subscribers, collectedSubscribers);
|
|
1055
|
+
const downstream = data.stateDependents.get(selector);
|
|
1056
|
+
if (downstream && downstream.size > 0) {
|
|
1057
|
+
if (!downstreamSeeds)
|
|
1058
|
+
downstreamSeeds = new Set;
|
|
1059
|
+
for (const d of downstream)
|
|
1060
|
+
downstreamSeeds.add(d);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (downstreamSeeds && downstreamSeeds.size > 0) {
|
|
1064
|
+
propagateDownstreamTopo(downstreamSeeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly, evaluatedSelectors);
|
|
890
1065
|
}
|
|
891
1066
|
};
|
|
892
1067
|
|
|
@@ -894,11 +1069,19 @@ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedIn
|
|
|
894
1069
|
var isFunction = (value) => typeof value === "function";
|
|
895
1070
|
|
|
896
1071
|
// src/lib/setAtom.ts
|
|
897
|
-
var
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1072
|
+
var resolvePendingDefault = (atom, data, value) => {
|
|
1073
|
+
let cur = data;
|
|
1074
|
+
while (cur) {
|
|
1075
|
+
const entry = cur.pendingDefaults.get(atom);
|
|
1076
|
+
if (entry) {
|
|
1077
|
+
entry.resolve(value);
|
|
1078
|
+
cur.pendingDefaults.delete(atom);
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
cur = "parent" in cur ? cur.parent : undefined;
|
|
901
1082
|
}
|
|
1083
|
+
};
|
|
1084
|
+
var handlePromise = (atom, promise, currentValue, data, skipOnSet) => {
|
|
902
1085
|
setValueInData(atom, promise, data);
|
|
903
1086
|
promise.then((resolvedValue) => {
|
|
904
1087
|
if (data.values.get(atom) !== promise)
|
|
@@ -906,15 +1089,13 @@ var handlePromise = (atom, promise, currentValue, data, skipOnSet) => {
|
|
|
906
1089
|
setValueInData(atom, resolvedValue, data);
|
|
907
1090
|
if (atom.onSet && !skipOnSet)
|
|
908
1091
|
atom.onSet(resolvedValue, data);
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
}
|
|
912
|
-
propagateUpdatedAtoms([atom], data);
|
|
1092
|
+
resolvePendingDefault(atom, data, resolvedValue);
|
|
1093
|
+
propagateAtomUpdate([atom], data);
|
|
913
1094
|
}).catch(() => {
|
|
914
1095
|
if (data.values.get(atom) !== promise)
|
|
915
1096
|
return;
|
|
916
1097
|
setValueInData(atom, currentValue, data);
|
|
917
|
-
|
|
1098
|
+
propagateAtomUpdate([atom], data);
|
|
918
1099
|
});
|
|
919
1100
|
};
|
|
920
1101
|
var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
@@ -936,9 +1117,9 @@ var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
|
936
1117
|
handlePromise(atom, promise, currentValue, data, skipOnSet);
|
|
937
1118
|
if (initializedAtomsSet && initializedAtomsSet.size > 0) {
|
|
938
1119
|
initializedAtomsSet.add(atom);
|
|
939
|
-
|
|
1120
|
+
propagateAtomUpdate([...initializedAtomsSet], data);
|
|
940
1121
|
} else {
|
|
941
|
-
|
|
1122
|
+
propagateAtomUpdate([atom], data);
|
|
942
1123
|
}
|
|
943
1124
|
return promise;
|
|
944
1125
|
}
|
|
@@ -949,14 +1130,12 @@ var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
|
949
1130
|
syncValue = setValueInData(atom, syncValue, data);
|
|
950
1131
|
if (atom.onSet && !skipOnSet)
|
|
951
1132
|
atom.onSet(syncValue, data);
|
|
952
|
-
|
|
953
|
-
currentValue.__resolveEmptyAtomPromise__(syncValue);
|
|
954
|
-
}
|
|
1133
|
+
resolvePendingDefault(atom, data, syncValue);
|
|
955
1134
|
if (initializedAtomsSet && initializedAtomsSet.size > 0) {
|
|
956
1135
|
initializedAtomsSet.add(atom);
|
|
957
|
-
|
|
1136
|
+
propagateAtomUpdate([...initializedAtomsSet], data);
|
|
958
1137
|
} else {
|
|
959
|
-
|
|
1138
|
+
propagateAtomUpdate([atom], data);
|
|
960
1139
|
}
|
|
961
1140
|
return syncValue;
|
|
962
1141
|
};
|
|
@@ -964,12 +1143,11 @@ var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
|
964
1143
|
// src/lib/initAtom.ts
|
|
965
1144
|
var getAtomInitValue = (atom, data, initializedAtomsSet) => {
|
|
966
1145
|
if (atom.defaultValue === undefined) {
|
|
967
|
-
let
|
|
968
|
-
const promise = new Promise((
|
|
969
|
-
|
|
1146
|
+
let resolve;
|
|
1147
|
+
const promise = new Promise((r) => {
|
|
1148
|
+
resolve = r;
|
|
970
1149
|
});
|
|
971
|
-
|
|
972
|
-
promise.__resolveEmptyAtomPromise__ = promiseResolve;
|
|
1150
|
+
data.pendingDefaults.set(atom, { promise, resolve });
|
|
973
1151
|
return promise;
|
|
974
1152
|
} else if (typeof atom.defaultValue === "function") {
|
|
975
1153
|
const value = atom.defaultValue();
|
|
@@ -978,7 +1156,7 @@ var getAtomInitValue = (atom, data, initializedAtomsSet) => {
|
|
|
978
1156
|
if (data.values.get(atom) !== value)
|
|
979
1157
|
return;
|
|
980
1158
|
setValueInData(atom, resolvedValue, data);
|
|
981
|
-
|
|
1159
|
+
propagateAtomUpdate([atom], data);
|
|
982
1160
|
}, () => {
|
|
983
1161
|
if (data.values.get(atom) === value) {
|
|
984
1162
|
data.values.delete(atom);
|
|
@@ -1007,7 +1185,7 @@ function getState(state, data, initializedAtomsSet, circularDependencySet) {
|
|
|
1007
1185
|
if (data.values.has(state))
|
|
1008
1186
|
return data.values.get(state);
|
|
1009
1187
|
if (isAtom(state)) {
|
|
1010
|
-
if (
|
|
1188
|
+
if (data.parent)
|
|
1011
1189
|
return getState(state, data.parent, initializedAtomsSet, circularDependencySet);
|
|
1012
1190
|
if (isFamilyAtom(state)) {
|
|
1013
1191
|
const familyValue = data.values.get(state.family);
|
|
@@ -1022,14 +1200,11 @@ function getState(state, data, initializedAtomsSet, circularDependencySet) {
|
|
|
1022
1200
|
return data.values.get(state);
|
|
1023
1201
|
}
|
|
1024
1202
|
if (isSelector(state)) {
|
|
1025
|
-
if (_evalDepth >= MAX_EVAL_DEPTH) {
|
|
1026
|
-
throw new NeedsInitError(state);
|
|
1027
|
-
}
|
|
1028
1203
|
initSelector(state, data, initializedAtomsSet, circularDependencySet);
|
|
1029
1204
|
return data.values.get(state);
|
|
1030
1205
|
}
|
|
1031
1206
|
if (isAtomFamily(state)) {
|
|
1032
|
-
if (
|
|
1207
|
+
if (data.parent) {
|
|
1033
1208
|
const closestData = findClosestStoreWithAtomInitialized(state, data);
|
|
1034
1209
|
return getState(state, closestData, initializedAtomsSet, circularDependencySet);
|
|
1035
1210
|
}
|
|
@@ -1047,7 +1222,7 @@ function getState(state, data, initializedAtomsSet, circularDependencySet) {
|
|
|
1047
1222
|
throw new Error("Invalid object passed to get");
|
|
1048
1223
|
}
|
|
1049
1224
|
var findClosestStoreWithAtomInitialized = (atom, data) => {
|
|
1050
|
-
if (
|
|
1225
|
+
if (!data.parent)
|
|
1051
1226
|
return data;
|
|
1052
1227
|
if (data.values.has(atom))
|
|
1053
1228
|
return data;
|
|
@@ -1077,16 +1252,16 @@ var resolveReactive = (value, data) => {
|
|
|
1077
1252
|
// src/lib/createStoreData.ts
|
|
1078
1253
|
var nextId = 0;
|
|
1079
1254
|
var generateId = () => "__valdres_store_" + nextId++;
|
|
1080
|
-
function makeLazyGetter(key) {
|
|
1255
|
+
function makeLazyGetter(key, factory = () => new WeakMap) {
|
|
1081
1256
|
return {
|
|
1082
1257
|
get() {
|
|
1083
|
-
const
|
|
1258
|
+
const value = factory();
|
|
1084
1259
|
Object.defineProperty(this, key, {
|
|
1085
|
-
value
|
|
1260
|
+
value,
|
|
1086
1261
|
writable: true,
|
|
1087
1262
|
configurable: true
|
|
1088
1263
|
});
|
|
1089
|
-
return
|
|
1264
|
+
return value;
|
|
1090
1265
|
},
|
|
1091
1266
|
configurable: true
|
|
1092
1267
|
};
|
|
@@ -1098,8 +1273,11 @@ Object.defineProperties(lazyProto, {
|
|
|
1098
1273
|
stateDependents: makeLazyGetter("stateDependents"),
|
|
1099
1274
|
stateDependencies: makeLazyGetter("stateDependencies"),
|
|
1100
1275
|
mounts: makeLazyGetter("mounts"),
|
|
1276
|
+
liveDependentCount: makeLazyGetter("liveDependentCount"),
|
|
1101
1277
|
abortControllers: makeLazyGetter("abortControllers"),
|
|
1102
|
-
lastValueWriteAt: makeLazyGetter("lastValueWriteAt")
|
|
1278
|
+
lastValueWriteAt: makeLazyGetter("lastValueWriteAt"),
|
|
1279
|
+
circularDepSet: makeLazyGetter("circularDepSet", () => new WeakSet),
|
|
1280
|
+
latestEvalContext: makeLazyGetter("latestEvalContext")
|
|
1103
1281
|
});
|
|
1104
1282
|
function createStoreData(id, parent, options) {
|
|
1105
1283
|
const data = Object.create(lazyProto);
|
|
@@ -1107,6 +1285,7 @@ function createStoreData(id, parent, options) {
|
|
|
1107
1285
|
data.values = new WeakMap;
|
|
1108
1286
|
data.scopes = new Map;
|
|
1109
1287
|
data.scopeValueIndex = new WeakMap;
|
|
1288
|
+
data.pendingDefaults = new WeakMap;
|
|
1110
1289
|
if (options?.batchUpdates) {
|
|
1111
1290
|
data.batchUpdates = true;
|
|
1112
1291
|
}
|
|
@@ -1133,10 +1312,10 @@ var resetAtom = (atom, data) => {
|
|
|
1133
1312
|
let value = getAtomInitValue(atom, data, initializedAtomsSet);
|
|
1134
1313
|
setValueInData(atom, value, data);
|
|
1135
1314
|
if (!isPromiseLike(value)) {
|
|
1136
|
-
|
|
1315
|
+
propagateAtomUpdate([atom], data);
|
|
1137
1316
|
}
|
|
1138
1317
|
if (initializedAtomsSet.size > 0) {
|
|
1139
|
-
throw new Error("Todo -
|
|
1318
|
+
throw new Error("Todo - propagateAtomUpdate on reset");
|
|
1140
1319
|
}
|
|
1141
1320
|
return value;
|
|
1142
1321
|
};
|
|
@@ -1185,6 +1364,7 @@ var unsubscribe = (state, subscription, data) => {
|
|
|
1185
1364
|
deleteMaxAgeCleanup(data, state);
|
|
1186
1365
|
}
|
|
1187
1366
|
data.subscriptions.delete(state);
|
|
1367
|
+
onLastDirectSubscriber(state, data);
|
|
1188
1368
|
unmountOrphanedDeps(state, data);
|
|
1189
1369
|
cleanupOrphanedDeps(state, data);
|
|
1190
1370
|
}
|
|
@@ -1194,7 +1374,7 @@ var cleanupOrphanedDeps = (state, data, visited = new Set) => {
|
|
|
1194
1374
|
if (visited.has(state))
|
|
1195
1375
|
return;
|
|
1196
1376
|
visited.add(state);
|
|
1197
|
-
if (
|
|
1377
|
+
if (isLive(state, data))
|
|
1198
1378
|
return;
|
|
1199
1379
|
const deps = data.stateDependencies.get(state);
|
|
1200
1380
|
if (deps) {
|
|
@@ -1223,7 +1403,7 @@ var initSubscribers = (state, data) => {
|
|
|
1223
1403
|
return set;
|
|
1224
1404
|
};
|
|
1225
1405
|
var installMaxAgeTimer = (state, data) => {
|
|
1226
|
-
if (
|
|
1406
|
+
if (state.maxAge === undefined)
|
|
1227
1407
|
return;
|
|
1228
1408
|
const globalState = isGlobalAtom(state) ? state : undefined;
|
|
1229
1409
|
const existing = globalState?.maxAgeInterval;
|
|
@@ -1233,7 +1413,7 @@ var installMaxAgeTimer = (state, data) => {
|
|
|
1233
1413
|
for (const s of globalState.stores) {
|
|
1234
1414
|
if (s !== data && s.values.has(metaAtom2)) {
|
|
1235
1415
|
setValueInData(metaAtom2, s.values.get(metaAtom2), data);
|
|
1236
|
-
|
|
1416
|
+
propagateAtomUpdate([metaAtom2], data);
|
|
1237
1417
|
break;
|
|
1238
1418
|
}
|
|
1239
1419
|
}
|
|
@@ -1272,11 +1452,11 @@ var installMaxAgeTimer = (state, data) => {
|
|
|
1272
1452
|
if (globalState) {
|
|
1273
1453
|
for (const store of globalState.stores) {
|
|
1274
1454
|
setValueInData(metaAtom, meta, store);
|
|
1275
|
-
|
|
1455
|
+
propagateAtomUpdate([metaAtom], store);
|
|
1276
1456
|
}
|
|
1277
1457
|
} else {
|
|
1278
1458
|
setValueInData(metaAtom, meta, data);
|
|
1279
|
-
|
|
1459
|
+
propagateAtomUpdate([metaAtom], data);
|
|
1280
1460
|
}
|
|
1281
1461
|
};
|
|
1282
1462
|
const isPastStaleIfErrorWindow = () => {
|
|
@@ -1287,11 +1467,11 @@ var installMaxAgeTimer = (state, data) => {
|
|
|
1287
1467
|
if (globalState) {
|
|
1288
1468
|
for (const store of globalState.stores) {
|
|
1289
1469
|
setValueInData(atom, val, store);
|
|
1290
|
-
|
|
1470
|
+
propagateAtomUpdate([atom], store);
|
|
1291
1471
|
}
|
|
1292
1472
|
} else {
|
|
1293
1473
|
setValueInData(atom, val, data);
|
|
1294
|
-
|
|
1474
|
+
propagateAtomUpdate([atom], data);
|
|
1295
1475
|
}
|
|
1296
1476
|
};
|
|
1297
1477
|
const getValueStore = () => {
|
|
@@ -1421,14 +1601,18 @@ var installMaxAgeTimer = (state, data) => {
|
|
|
1421
1601
|
};
|
|
1422
1602
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
1423
1603
|
let parentUnsubscribe;
|
|
1424
|
-
|
|
1604
|
+
let dropDelegate;
|
|
1605
|
+
if (data.parent && (!data.values.has(state) && isAtom(state) || isAtomFamily(state))) {
|
|
1425
1606
|
const originalCallback = callback;
|
|
1426
1607
|
parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
|
|
1427
|
-
|
|
1608
|
+
dropDelegate = () => {
|
|
1428
1609
|
if (parentUnsubscribe) {
|
|
1429
1610
|
parentUnsubscribe();
|
|
1430
1611
|
parentUnsubscribe = undefined;
|
|
1431
1612
|
}
|
|
1613
|
+
};
|
|
1614
|
+
callback = (arg) => {
|
|
1615
|
+
dropDelegate();
|
|
1432
1616
|
originalCallback(arg);
|
|
1433
1617
|
};
|
|
1434
1618
|
} else if (!data.values.has(state) && isAtom(state)) {
|
|
@@ -1450,20 +1634,23 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
1450
1634
|
subscription = {
|
|
1451
1635
|
callback,
|
|
1452
1636
|
state,
|
|
1453
|
-
requireDeepEqualCheckBeforeCallback
|
|
1637
|
+
requireDeepEqualCheckBeforeCallback,
|
|
1638
|
+
reRoot: dropDelegate
|
|
1454
1639
|
};
|
|
1455
1640
|
} else {
|
|
1456
1641
|
subscription = {
|
|
1457
1642
|
callback,
|
|
1458
|
-
requireDeepEqualCheckBeforeCallback
|
|
1643
|
+
requireDeepEqualCheckBeforeCallback,
|
|
1644
|
+
reRoot: dropDelegate
|
|
1459
1645
|
};
|
|
1460
1646
|
}
|
|
1461
1647
|
subscribers.add(subscription);
|
|
1462
1648
|
if (subscribers.size === 1) {
|
|
1463
|
-
if (isAtom(state) && state.maxAge) {
|
|
1649
|
+
if (isAtom(state) && state.maxAge !== undefined && !data.parent) {
|
|
1464
1650
|
installMaxAgeTimer(state, data);
|
|
1465
1651
|
}
|
|
1466
1652
|
if (!isFamily(state)) {
|
|
1653
|
+
onFirstDirectSubscriber(state, data);
|
|
1467
1654
|
mountTransitiveDeps(state, data);
|
|
1468
1655
|
}
|
|
1469
1656
|
}
|
|
@@ -1478,8 +1665,8 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
1478
1665
|
};
|
|
1479
1666
|
};
|
|
1480
1667
|
|
|
1481
|
-
// src/lib/
|
|
1482
|
-
var
|
|
1668
|
+
// src/lib/writeAtoms.ts
|
|
1669
|
+
var writeAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false, onSetQueue) => {
|
|
1483
1670
|
const updatedAtoms = [];
|
|
1484
1671
|
for (let [atom, value] of pairs) {
|
|
1485
1672
|
const currentValue = getState(atom, data, initializedAtomsSet);
|
|
@@ -1487,8 +1674,12 @@ var setAtoms = (pairs, data, initializedAtomsSet) => {
|
|
|
1487
1674
|
if (!areEqual) {
|
|
1488
1675
|
updatedAtoms.push(atom);
|
|
1489
1676
|
value = setValueInData(atom, value, data);
|
|
1490
|
-
if (atom.onSet)
|
|
1491
|
-
|
|
1677
|
+
if (atom.onSet && !skipOnSet) {
|
|
1678
|
+
if (onSetQueue)
|
|
1679
|
+
onSetQueue.push([atom, value, data]);
|
|
1680
|
+
else
|
|
1681
|
+
atom.onSet(value, data);
|
|
1682
|
+
}
|
|
1492
1683
|
} else {
|
|
1493
1684
|
setValueInData(atom, value, data);
|
|
1494
1685
|
}
|
|
@@ -1498,8 +1689,14 @@ var setAtoms = (pairs, data, initializedAtomsSet) => {
|
|
|
1498
1689
|
updatedAtoms.push(atom);
|
|
1499
1690
|
}
|
|
1500
1691
|
}
|
|
1692
|
+
return updatedAtoms;
|
|
1693
|
+
};
|
|
1694
|
+
|
|
1695
|
+
// src/lib/setAtoms.ts
|
|
1696
|
+
var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
|
|
1697
|
+
const updatedAtoms = writeAtoms(pairs, data, initializedAtomsSet, skipOnSet);
|
|
1501
1698
|
if (updatedAtoms.length > 0) {
|
|
1502
|
-
|
|
1699
|
+
propagateAtomUpdate(updatedAtoms, data);
|
|
1503
1700
|
}
|
|
1504
1701
|
};
|
|
1505
1702
|
|
|
@@ -1587,7 +1784,7 @@ class Transaction {
|
|
|
1587
1784
|
} else {
|
|
1588
1785
|
resolved = value;
|
|
1589
1786
|
}
|
|
1590
|
-
if (!atom.mutable && !
|
|
1787
|
+
if (!atom.mutable && !IS_PROD && resolved !== null && (typeof resolved === "object" || typeof resolved === "function")) {
|
|
1591
1788
|
resolved = deepFreeze(resolved);
|
|
1592
1789
|
}
|
|
1593
1790
|
this._atomMap.set(atom, resolved);
|
|
@@ -1651,6 +1848,9 @@ class Transaction {
|
|
|
1651
1848
|
};
|
|
1652
1849
|
parentScope = (callback) => {
|
|
1653
1850
|
if (!this.parentTransaction) {
|
|
1851
|
+
if (!this.data.parent) {
|
|
1852
|
+
throw new Error("Cannot access parentScope on root store");
|
|
1853
|
+
}
|
|
1654
1854
|
this.parentTransaction = new Transaction(this.data.parent, undefined, this);
|
|
1655
1855
|
}
|
|
1656
1856
|
return this.parentTransaction.execute(callback, false);
|
|
@@ -1674,15 +1874,58 @@ class Transaction {
|
|
|
1674
1874
|
}
|
|
1675
1875
|
};
|
|
1676
1876
|
commit = () => {
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1877
|
+
if (!this._scopedTransactions) {
|
|
1878
|
+
const initializedAtomsSet = new Set;
|
|
1879
|
+
if (this._deleteSet?.size) {
|
|
1880
|
+
const evaluatedSelectors2 = new Set;
|
|
1881
|
+
const updatedAtoms = writeAtoms(this._atomMap, this.data, initializedAtomsSet);
|
|
1882
|
+
if (updatedAtoms.length > 0) {
|
|
1883
|
+
propagateAtomUpdate(updatedAtoms, this.data, false, evaluatedSelectors2);
|
|
1884
|
+
}
|
|
1885
|
+
deleteAtomFamilyAtoms(this._deleteSet, this.data);
|
|
1886
|
+
propagateDeletedAtoms([...this._deleteSet], this.data, undefined, undefined, undefined, evaluatedSelectors2);
|
|
1887
|
+
} else {
|
|
1888
|
+
setAtoms(this._atomMap, this.data, initializedAtomsSet);
|
|
1889
|
+
}
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
const plan = [];
|
|
1893
|
+
this.collectStores(plan);
|
|
1894
|
+
for (let i = plan.length - 1;i >= 0; i--) {
|
|
1895
|
+
const entry = plan[i];
|
|
1896
|
+
const txn = entry.txn;
|
|
1897
|
+
entry.updatedAtoms = writeAtoms(txn._atomMap, entry.data, new Set, false, entry.onSets);
|
|
1898
|
+
if (txn._deleteSet?.size) {
|
|
1899
|
+
deleteAtomFamilyAtoms(txn._deleteSet, entry.data);
|
|
1900
|
+
entry.deleted = [...txn._deleteSet];
|
|
1901
|
+
}
|
|
1682
1902
|
}
|
|
1903
|
+
for (const entry of plan) {
|
|
1904
|
+
for (const [atom, value, data] of entry.onSets) {
|
|
1905
|
+
atom.onSet(value, data);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
const evaluatedSelectors = new Set;
|
|
1909
|
+
for (const { data, updatedAtoms, deleted } of plan) {
|
|
1910
|
+
if (updatedAtoms.length > 0) {
|
|
1911
|
+
propagateAtomUpdate(updatedAtoms, data, false, evaluatedSelectors);
|
|
1912
|
+
}
|
|
1913
|
+
if (deleted) {
|
|
1914
|
+
propagateDeletedAtoms(deleted, data, undefined, undefined, undefined, evaluatedSelectors);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
collectStores = (plan) => {
|
|
1919
|
+
plan.push({
|
|
1920
|
+
txn: this,
|
|
1921
|
+
data: this.data,
|
|
1922
|
+
updatedAtoms: [],
|
|
1923
|
+
deleted: undefined,
|
|
1924
|
+
onSets: []
|
|
1925
|
+
});
|
|
1683
1926
|
if (this._scopedTransactions) {
|
|
1684
1927
|
for (const [, scopedTxn] of this._scopedTransactions) {
|
|
1685
|
-
scopedTxn.
|
|
1928
|
+
scopedTxn.collectStores(plan);
|
|
1686
1929
|
}
|
|
1687
1930
|
}
|
|
1688
1931
|
};
|
|
@@ -1759,6 +2002,8 @@ var isCachedValueStale = (state, data) => {
|
|
|
1759
2002
|
const maxAge = atom.maxAge;
|
|
1760
2003
|
if (maxAge === undefined)
|
|
1761
2004
|
return false;
|
|
2005
|
+
if (data.parent)
|
|
2006
|
+
return false;
|
|
1762
2007
|
if (isGlobalAtom(atom)) {
|
|
1763
2008
|
if (atom.maxAgeInterval !== undefined)
|
|
1764
2009
|
return false;
|
|
@@ -1813,7 +2058,7 @@ function storeFromStoreData(data, detach) {
|
|
|
1813
2058
|
if (_initSet.size) {
|
|
1814
2059
|
const atoms = [..._initSet];
|
|
1815
2060
|
_initSet.clear();
|
|
1816
|
-
|
|
2061
|
+
propagateAtomUpdate(atoms, data, true);
|
|
1817
2062
|
}
|
|
1818
2063
|
}
|
|
1819
2064
|
return res;
|
|
@@ -1874,11 +2119,13 @@ function storeFromStoreData(data, detach) {
|
|
|
1874
2119
|
scopedStoreData = createStoreData(scopeId, data, data.batchUpdates ? { batchUpdates: true } : undefined);
|
|
1875
2120
|
data.scopes.set(scopeId, scopedStoreData);
|
|
1876
2121
|
}
|
|
2122
|
+
const consumers = scopedStoreData.scopeConsumers;
|
|
2123
|
+
const indexKeys = scopedStoreData.scopeIndexKeys;
|
|
1877
2124
|
const detach2 = (expectedToDestroy = false) => {
|
|
1878
|
-
|
|
1879
|
-
if (
|
|
2125
|
+
consumers.delete(detach2);
|
|
2126
|
+
if (consumers.size === 0) {
|
|
1880
2127
|
data.scopes.delete(scopeId);
|
|
1881
|
-
for (const key of
|
|
2128
|
+
for (const key of indexKeys) {
|
|
1882
2129
|
const set2 = data.scopeValueIndex.get(key);
|
|
1883
2130
|
if (set2) {
|
|
1884
2131
|
set2.delete(scopedStoreData);
|
|
@@ -1886,15 +2133,15 @@ function storeFromStoreData(data, detach) {
|
|
|
1886
2133
|
data.scopeValueIndex.delete(key);
|
|
1887
2134
|
}
|
|
1888
2135
|
}
|
|
1889
|
-
|
|
2136
|
+
indexKeys.clear();
|
|
1890
2137
|
return true;
|
|
1891
2138
|
}
|
|
1892
2139
|
if (expectedToDestroy) {
|
|
1893
|
-
console.warn(`Scope ${scopeId} still has ${
|
|
2140
|
+
console.warn(`Scope ${scopeId} still has ${consumers.size} consumers, will not detach`);
|
|
1894
2141
|
}
|
|
1895
2142
|
return false;
|
|
1896
2143
|
};
|
|
1897
|
-
|
|
2144
|
+
consumers.add(detach2);
|
|
1898
2145
|
const newStore = storeFromStoreData(data.scopes.get(scopeId), detach2);
|
|
1899
2146
|
return newStore;
|
|
1900
2147
|
}
|
|
@@ -1926,25 +2173,83 @@ function storeFromStoreData(data, detach) {
|
|
|
1926
2173
|
}
|
|
1927
2174
|
|
|
1928
2175
|
// src/lib/mountAtom.ts
|
|
1929
|
-
var
|
|
1930
|
-
const
|
|
2176
|
+
var hasDirectSubscribers = (state, data) => {
|
|
2177
|
+
const subs = data.subscriptions.get(state);
|
|
2178
|
+
return !!subs && subs.size > 0;
|
|
2179
|
+
};
|
|
2180
|
+
var isLive = (state, data) => {
|
|
2181
|
+
if (hasDirectSubscribers(state, data))
|
|
2182
|
+
return true;
|
|
2183
|
+
const count = data.liveDependentCount.get(state);
|
|
2184
|
+
return !!count && count > 0;
|
|
2185
|
+
};
|
|
2186
|
+
var propagateLive = (root, data) => {
|
|
2187
|
+
const stack = [root];
|
|
1931
2188
|
while (stack.length > 0) {
|
|
1932
2189
|
const current = stack.pop();
|
|
1933
|
-
|
|
2190
|
+
const deps = data.stateDependencies.get(current);
|
|
2191
|
+
if (!deps)
|
|
1934
2192
|
continue;
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
if (dependents) {
|
|
1941
|
-
for (const dep of dependents) {
|
|
1942
|
-
if (!visited.has(dep))
|
|
1943
|
-
stack.push(dep);
|
|
2193
|
+
for (const dep of deps) {
|
|
2194
|
+
const prev = data.liveDependentCount.get(dep) ?? 0;
|
|
2195
|
+
data.liveDependentCount.set(dep, prev + 1);
|
|
2196
|
+
if (prev === 0 && !hasDirectSubscribers(dep, data)) {
|
|
2197
|
+
stack.push(dep);
|
|
1944
2198
|
}
|
|
1945
2199
|
}
|
|
1946
2200
|
}
|
|
1947
|
-
|
|
2201
|
+
};
|
|
2202
|
+
var propagateNotLive = (root, data) => {
|
|
2203
|
+
const stack = [root];
|
|
2204
|
+
while (stack.length > 0) {
|
|
2205
|
+
const current = stack.pop();
|
|
2206
|
+
const deps = data.stateDependencies.get(current);
|
|
2207
|
+
if (!deps)
|
|
2208
|
+
continue;
|
|
2209
|
+
for (const dep of deps) {
|
|
2210
|
+
const prev = data.liveDependentCount.get(dep) ?? 0;
|
|
2211
|
+
const next = prev - 1;
|
|
2212
|
+
if (next <= 0) {
|
|
2213
|
+
data.liveDependentCount.delete(dep);
|
|
2214
|
+
} else {
|
|
2215
|
+
data.liveDependentCount.set(dep, next);
|
|
2216
|
+
}
|
|
2217
|
+
if (prev === 1 && !hasDirectSubscribers(dep, data)) {
|
|
2218
|
+
stack.push(dep);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
var onFirstDirectSubscriber = (state, data) => {
|
|
2224
|
+
const liveDepCount = data.liveDependentCount.get(state) ?? 0;
|
|
2225
|
+
if (liveDepCount === 0) {
|
|
2226
|
+
propagateLive(state, data);
|
|
2227
|
+
}
|
|
2228
|
+
};
|
|
2229
|
+
var onLastDirectSubscriber = (state, data) => {
|
|
2230
|
+
const liveDepCount = data.liveDependentCount.get(state) ?? 0;
|
|
2231
|
+
if (liveDepCount === 0) {
|
|
2232
|
+
propagateNotLive(state, data);
|
|
2233
|
+
}
|
|
2234
|
+
};
|
|
2235
|
+
var onLiveDependencyAdded = (dep, data) => {
|
|
2236
|
+
const prev = data.liveDependentCount.get(dep) ?? 0;
|
|
2237
|
+
data.liveDependentCount.set(dep, prev + 1);
|
|
2238
|
+
if (prev === 0 && !hasDirectSubscribers(dep, data)) {
|
|
2239
|
+
propagateLive(dep, data);
|
|
2240
|
+
}
|
|
2241
|
+
};
|
|
2242
|
+
var onLiveDependencyRemoved = (dep, data) => {
|
|
2243
|
+
const prev = data.liveDependentCount.get(dep) ?? 0;
|
|
2244
|
+
const next = prev - 1;
|
|
2245
|
+
if (next <= 0) {
|
|
2246
|
+
data.liveDependentCount.delete(dep);
|
|
2247
|
+
} else {
|
|
2248
|
+
data.liveDependentCount.set(dep, next);
|
|
2249
|
+
}
|
|
2250
|
+
if (prev === 1 && !hasDirectSubscribers(dep, data)) {
|
|
2251
|
+
propagateNotLive(dep, data);
|
|
2252
|
+
}
|
|
1948
2253
|
};
|
|
1949
2254
|
var mountAtom = (state, data) => {
|
|
1950
2255
|
const onMountFn = state.__valdresOnMount ?? state.onMount;
|
|
@@ -1954,7 +2259,9 @@ var mountAtom = (state, data) => {
|
|
|
1954
2259
|
data.mounts.set(state, mountEntry);
|
|
1955
2260
|
const store = data.storeRef ?? storeFromStoreData(data);
|
|
1956
2261
|
try {
|
|
1957
|
-
|
|
2262
|
+
const result = onMountFn(store, state);
|
|
2263
|
+
if (typeof result === "function")
|
|
2264
|
+
mountEntry.cleanup = result;
|
|
1958
2265
|
} catch (error) {
|
|
1959
2266
|
data.mounts.delete(state);
|
|
1960
2267
|
throw error;
|
|
@@ -1969,14 +2276,20 @@ var unmountAtom = (state, data) => {
|
|
|
1969
2276
|
mount.cleanup();
|
|
1970
2277
|
}
|
|
1971
2278
|
};
|
|
1972
|
-
var mountTransitiveDeps = (state, data, visited
|
|
2279
|
+
var mountTransitiveDeps = (state, data, visited) => {
|
|
2280
|
+
if (!state.__valdresOnMount && !state.onMount) {
|
|
2281
|
+
const deps = data.stateDependencies.get(state);
|
|
2282
|
+
if (!deps || deps.size === 0)
|
|
2283
|
+
return;
|
|
2284
|
+
}
|
|
2285
|
+
const seen = visited ?? new Set;
|
|
1973
2286
|
let firstError = null;
|
|
1974
2287
|
const stack = [state];
|
|
1975
2288
|
while (stack.length > 0) {
|
|
1976
2289
|
const current = stack.pop();
|
|
1977
|
-
if (
|
|
2290
|
+
if (seen.has(current))
|
|
1978
2291
|
continue;
|
|
1979
|
-
|
|
2292
|
+
seen.add(current);
|
|
1980
2293
|
if (current.__valdresOnMount || current.onMount) {
|
|
1981
2294
|
try {
|
|
1982
2295
|
mountAtom(current, data);
|
|
@@ -1988,7 +2301,7 @@ var mountTransitiveDeps = (state, data, visited = new Set) => {
|
|
|
1988
2301
|
const deps = data.stateDependencies.get(current);
|
|
1989
2302
|
if (deps) {
|
|
1990
2303
|
for (const dep of deps) {
|
|
1991
|
-
if (!
|
|
2304
|
+
if (!seen.has(dep))
|
|
1992
2305
|
stack.push(dep);
|
|
1993
2306
|
}
|
|
1994
2307
|
}
|
|
@@ -1997,16 +2310,22 @@ var mountTransitiveDeps = (state, data, visited = new Set) => {
|
|
|
1997
2310
|
throw firstError.value;
|
|
1998
2311
|
}
|
|
1999
2312
|
};
|
|
2000
|
-
var unmountOrphanedDeps = (state, data, visited
|
|
2313
|
+
var unmountOrphanedDeps = (state, data, visited) => {
|
|
2314
|
+
if (!state.__valdresOnMount && !state.onMount) {
|
|
2315
|
+
const deps = data.stateDependencies.get(state);
|
|
2316
|
+
if (!deps || deps.size === 0)
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2319
|
+
const seen = visited ?? new Set;
|
|
2001
2320
|
let firstError = null;
|
|
2002
2321
|
const stack = [state];
|
|
2003
2322
|
while (stack.length > 0) {
|
|
2004
2323
|
const current = stack.pop();
|
|
2005
|
-
if (
|
|
2324
|
+
if (seen.has(current))
|
|
2006
2325
|
continue;
|
|
2007
|
-
|
|
2326
|
+
seen.add(current);
|
|
2008
2327
|
if ((current.__valdresOnMount || current.onMount) && data.mounts.has(current)) {
|
|
2009
|
-
if (!
|
|
2328
|
+
if (!isLive(current, data)) {
|
|
2010
2329
|
try {
|
|
2011
2330
|
unmountAtom(current, data);
|
|
2012
2331
|
} catch (error) {
|
|
@@ -2018,7 +2337,7 @@ var unmountOrphanedDeps = (state, data, visited = new Set) => {
|
|
|
2018
2337
|
const deps = data.stateDependencies.get(current);
|
|
2019
2338
|
if (deps) {
|
|
2020
2339
|
for (const dep of deps) {
|
|
2021
|
-
if (!
|
|
2340
|
+
if (!seen.has(dep))
|
|
2022
2341
|
stack.push(dep);
|
|
2023
2342
|
}
|
|
2024
2343
|
}
|
|
@@ -2045,8 +2364,7 @@ var globalStore = Object.assign(store("valdres-global-store"), {
|
|
|
2045
2364
|
// src/lib/globalAtom.ts
|
|
2046
2365
|
var globalAtom = (defaultValue, options) => {
|
|
2047
2366
|
const stores = new Set;
|
|
2048
|
-
|
|
2049
|
-
throw new Error("onSet on globalAtom is currently not supported");
|
|
2367
|
+
const userOnSet = options.onSet;
|
|
2050
2368
|
const onInit = (setSelf2, data) => {
|
|
2051
2369
|
setSelf2(globalStore.get(atom));
|
|
2052
2370
|
stores.add(data);
|
|
@@ -2059,6 +2377,7 @@ var globalAtom = (defaultValue, options) => {
|
|
|
2059
2377
|
}
|
|
2060
2378
|
}
|
|
2061
2379
|
}
|
|
2380
|
+
userOnSet?.(newValue, currentStore);
|
|
2062
2381
|
};
|
|
2063
2382
|
let mountCount = 0;
|
|
2064
2383
|
let userCleanup;
|
|
@@ -2091,7 +2410,7 @@ var globalAtom = (defaultValue, options) => {
|
|
|
2091
2410
|
const snapshot = [...stores];
|
|
2092
2411
|
const subscribedStores = [];
|
|
2093
2412
|
for (const s of snapshot) {
|
|
2094
|
-
if (
|
|
2413
|
+
if (isLive(atom, s)) {
|
|
2095
2414
|
subscribedStores.push(s);
|
|
2096
2415
|
}
|
|
2097
2416
|
}
|
|
@@ -2116,14 +2435,14 @@ var globalAtom = (defaultValue, options) => {
|
|
|
2116
2435
|
stores.delete(store2);
|
|
2117
2436
|
store2.values.delete(atom);
|
|
2118
2437
|
try {
|
|
2119
|
-
|
|
2438
|
+
propagateAtomUpdate([atom], store2);
|
|
2120
2439
|
} catch (e) {
|
|
2121
2440
|
recordError(e);
|
|
2122
2441
|
}
|
|
2123
2442
|
}
|
|
2124
2443
|
for (const s of subscribedStores) {
|
|
2125
2444
|
stores.add(s);
|
|
2126
|
-
if (atom.maxAge && (s.subscriptions.get(atom)?.size ?? 0) > 0) {
|
|
2445
|
+
if (atom.maxAge !== undefined && (s.subscriptions.get(atom)?.size ?? 0) > 0) {
|
|
2127
2446
|
installMaxAgeTimer(atom, s);
|
|
2128
2447
|
}
|
|
2129
2448
|
try {
|
|
@@ -2149,9 +2468,7 @@ var globalAtom = (defaultValue, options) => {
|
|
|
2149
2468
|
getSelf,
|
|
2150
2469
|
resetSelf,
|
|
2151
2470
|
detach,
|
|
2152
|
-
|
|
2153
|
-
return stores;
|
|
2154
|
-
},
|
|
2471
|
+
stores,
|
|
2155
2472
|
maxAgeInterval: undefined
|
|
2156
2473
|
};
|
|
2157
2474
|
return atom;
|
|
@@ -2247,11 +2564,7 @@ var createAtomFamily = (defaultValue, options) => {
|
|
|
2247
2564
|
const isFunctionDefault = !isSelectorFamilyDefault && typeof defaultValue === "function";
|
|
2248
2565
|
const hasName = !!options?.name;
|
|
2249
2566
|
const isGlobal = !!options?.global;
|
|
2250
|
-
const
|
|
2251
|
-
const key = familyKey(args);
|
|
2252
|
-
const cached = map.get(key);
|
|
2253
|
-
if (cached !== undefined)
|
|
2254
|
-
return cached;
|
|
2567
|
+
const build = (args, key) => {
|
|
2255
2568
|
let dv;
|
|
2256
2569
|
if (isSelectorFamilyDefault) {
|
|
2257
2570
|
dv = defaultValue(...args);
|
|
@@ -2281,14 +2594,34 @@ var createAtomFamily = (defaultValue, options) => {
|
|
|
2281
2594
|
map.set(key, familyAtom);
|
|
2282
2595
|
return familyAtom;
|
|
2283
2596
|
};
|
|
2597
|
+
function atomFamily(a0) {
|
|
2598
|
+
if (arguments.length === 1) {
|
|
2599
|
+
const t = typeof a0;
|
|
2600
|
+
if (t === "string" || t === "number" || t === "boolean") {
|
|
2601
|
+
const cached2 = map.get(a0);
|
|
2602
|
+
if (cached2 !== undefined)
|
|
2603
|
+
return cached2;
|
|
2604
|
+
return build([a0], a0);
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
const args = Array.prototype.slice.call(arguments);
|
|
2608
|
+
const key = familyKey(args);
|
|
2609
|
+
const cached = map.get(key);
|
|
2610
|
+
if (cached !== undefined)
|
|
2611
|
+
return cached;
|
|
2612
|
+
return build(args, key);
|
|
2613
|
+
}
|
|
2284
2614
|
if (hasName)
|
|
2285
2615
|
Object.defineProperty(atomFamily, "name", {
|
|
2286
2616
|
value: options.name,
|
|
2287
2617
|
writable: false
|
|
2288
2618
|
});
|
|
2289
|
-
|
|
2619
|
+
const callable = atomFamily;
|
|
2620
|
+
return Object.assign(callable, {
|
|
2290
2621
|
__valdresAtomFamilyMap: map,
|
|
2291
|
-
release: (...args) =>
|
|
2622
|
+
release: (...args) => {
|
|
2623
|
+
map.delete(familyKey(args));
|
|
2624
|
+
},
|
|
2292
2625
|
equal
|
|
2293
2626
|
});
|
|
2294
2627
|
};
|
|
@@ -2389,11 +2722,10 @@ var selectorFamily = (callback, options) => {
|
|
|
2389
2722
|
const cached = map.get(key);
|
|
2390
2723
|
if (cached !== undefined)
|
|
2391
2724
|
return cached;
|
|
2392
|
-
const get = (selectorArgs) => callback(...args)(selectorArgs);
|
|
2393
2725
|
const newSelector = {
|
|
2394
2726
|
equal,
|
|
2395
2727
|
...options,
|
|
2396
|
-
get,
|
|
2728
|
+
get: callback(...args),
|
|
2397
2729
|
family: selectorFamily2,
|
|
2398
2730
|
familyArgs: args,
|
|
2399
2731
|
familyArgsStringified: key,
|
|
@@ -2416,9 +2748,9 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
|
2416
2748
|
|
|
2417
2749
|
// src/index.ts
|
|
2418
2750
|
if (globalThis.__valdres__) {
|
|
2419
|
-
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.
|
|
2751
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.5"}`);
|
|
2420
2752
|
} else {
|
|
2421
|
-
globalThis.__valdres__ = "1.0.0-beta.
|
|
2753
|
+
globalThis.__valdres__ = "1.0.0-beta.5";
|
|
2422
2754
|
}
|
|
2423
2755
|
export {
|
|
2424
2756
|
store,
|