@pumped-fn/lite 2.1.0 → 2.1.2
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/CHANGELOG.md +41 -0
- package/dist/index.cjs +198 -108
- package/dist/index.d.cts +22 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +22 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +198 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -87,7 +87,7 @@ function getAtomsForTag(tag$1) {
|
|
|
87
87
|
return live;
|
|
88
88
|
}
|
|
89
89
|
function tag(options) {
|
|
90
|
-
const key = Symbol
|
|
90
|
+
const key = Symbol(`@pumped-fn/lite/tag/${options.label}`);
|
|
91
91
|
const hasDefault = "default" in options;
|
|
92
92
|
const defaultValue = hasDefault ? options.default : void 0;
|
|
93
93
|
const parse = options.parse;
|
|
@@ -424,12 +424,14 @@ function isResource(value) {
|
|
|
424
424
|
//#endregion
|
|
425
425
|
//#region src/service.ts
|
|
426
426
|
function service(config) {
|
|
427
|
-
|
|
427
|
+
const atomInstance = {
|
|
428
428
|
[atomSymbol]: true,
|
|
429
429
|
factory: config.factory,
|
|
430
430
|
deps: config.deps,
|
|
431
431
|
tags: config.tags
|
|
432
432
|
};
|
|
433
|
+
if (config.tags?.length) registerAtomToTags(atomInstance, config.tags);
|
|
434
|
+
return atomInstance;
|
|
433
435
|
}
|
|
434
436
|
|
|
435
437
|
//#endregion
|
|
@@ -445,7 +447,7 @@ function getResourceKey(resource$1) {
|
|
|
445
447
|
return key;
|
|
446
448
|
}
|
|
447
449
|
const inflightResources = /* @__PURE__ */ new WeakMap();
|
|
448
|
-
const
|
|
450
|
+
const resolvingResourcesMap = /* @__PURE__ */ new WeakMap();
|
|
449
451
|
var ContextDataImpl = class {
|
|
450
452
|
map = /* @__PURE__ */ new Map();
|
|
451
453
|
constructor(parentData) {
|
|
@@ -470,6 +472,10 @@ var ContextDataImpl = class {
|
|
|
470
472
|
if (this.map.has(key)) return this.map.get(key);
|
|
471
473
|
return this.parentData?.seek(key);
|
|
472
474
|
}
|
|
475
|
+
seekHas(key) {
|
|
476
|
+
if (this.map.has(key)) return true;
|
|
477
|
+
return this.parentData?.seekHas(key) ?? false;
|
|
478
|
+
}
|
|
473
479
|
getTag(tag$1) {
|
|
474
480
|
return this.map.get(tag$1.key);
|
|
475
481
|
}
|
|
@@ -515,6 +521,16 @@ var SelectHandleImpl = class {
|
|
|
515
521
|
return this.currentValue;
|
|
516
522
|
}
|
|
517
523
|
subscribe(listener) {
|
|
524
|
+
if (!this.ctrlUnsub) {
|
|
525
|
+
this.currentValue = this.selector(this.ctrl.get());
|
|
526
|
+
this.ctrlUnsub = this.ctrl.on("resolved", () => {
|
|
527
|
+
const nextValue = this.selector(this.ctrl.get());
|
|
528
|
+
if (!this.eq(this.currentValue, nextValue)) {
|
|
529
|
+
this.currentValue = nextValue;
|
|
530
|
+
this.notifyListeners();
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
518
534
|
this.listeners.add(listener);
|
|
519
535
|
return () => {
|
|
520
536
|
this.listeners.delete(listener);
|
|
@@ -522,12 +538,15 @@ var SelectHandleImpl = class {
|
|
|
522
538
|
};
|
|
523
539
|
}
|
|
524
540
|
notifyListeners() {
|
|
525
|
-
for (const listener of this.listeners) listener();
|
|
541
|
+
for (const listener of [...this.listeners]) listener();
|
|
542
|
+
}
|
|
543
|
+
dispose() {
|
|
544
|
+
this.listeners.clear();
|
|
545
|
+
this.cleanup();
|
|
526
546
|
}
|
|
527
547
|
cleanup() {
|
|
528
548
|
this.ctrlUnsub?.();
|
|
529
549
|
this.ctrlUnsub = null;
|
|
530
|
-
this.listeners.clear();
|
|
531
550
|
}
|
|
532
551
|
};
|
|
533
552
|
var ControllerImpl = class {
|
|
@@ -576,11 +595,15 @@ var ScopeImpl = class {
|
|
|
576
595
|
invalidationScheduled = false;
|
|
577
596
|
invalidationChain = null;
|
|
578
597
|
chainPromise = null;
|
|
598
|
+
chainError = null;
|
|
579
599
|
initialized = false;
|
|
600
|
+
disposed = false;
|
|
580
601
|
controllers = /* @__PURE__ */ new Map();
|
|
581
602
|
gcOptions;
|
|
582
603
|
extensions;
|
|
583
604
|
tags;
|
|
605
|
+
resolveExts;
|
|
606
|
+
execExts;
|
|
584
607
|
ready;
|
|
585
608
|
scheduleInvalidation(atom$1) {
|
|
586
609
|
const entry = this.cache.get(atom$1);
|
|
@@ -593,16 +616,22 @@ var ScopeImpl = class {
|
|
|
593
616
|
if (!this.chainPromise) {
|
|
594
617
|
this.invalidationChain = /* @__PURE__ */ new Set();
|
|
595
618
|
this.invalidationScheduled = true;
|
|
596
|
-
this.
|
|
597
|
-
|
|
598
|
-
|
|
619
|
+
this.chainError = null;
|
|
620
|
+
this.chainPromise = (async () => {
|
|
621
|
+
await new Promise((resolve) => {
|
|
622
|
+
queueMicrotask(resolve);
|
|
599
623
|
});
|
|
600
|
-
|
|
624
|
+
try {
|
|
625
|
+
await this.processInvalidationChain();
|
|
626
|
+
} catch (error) {
|
|
627
|
+
if (this.chainError === null) this.chainError = error;
|
|
628
|
+
}
|
|
629
|
+
})();
|
|
601
630
|
}
|
|
602
631
|
}
|
|
603
632
|
async processInvalidationChain() {
|
|
604
633
|
try {
|
|
605
|
-
while (this.invalidationQueue.size > 0) {
|
|
634
|
+
while (this.invalidationQueue.size > 0 && !this.disposed) {
|
|
606
635
|
const atom$1 = this.invalidationQueue.values().next().value;
|
|
607
636
|
this.invalidationQueue.delete(atom$1);
|
|
608
637
|
if (this.invalidationChain.has(atom$1)) {
|
|
@@ -623,6 +652,8 @@ var ScopeImpl = class {
|
|
|
623
652
|
constructor(options) {
|
|
624
653
|
this.extensions = options?.extensions ?? [];
|
|
625
654
|
this.tags = options?.tags ?? [];
|
|
655
|
+
this.resolveExts = this.extensions.filter((e) => e.wrapResolve);
|
|
656
|
+
this.execExts = this.extensions.filter((e) => e.wrapExec);
|
|
626
657
|
for (const p of options?.presets ?? []) this.presets.set(p.target, p.value);
|
|
627
658
|
this.gcOptions = {
|
|
628
659
|
enabled: options?.gc?.enabled ?? true,
|
|
@@ -715,21 +746,21 @@ var ScopeImpl = class {
|
|
|
715
746
|
const entry = this.cache.get(atom$1);
|
|
716
747
|
if (!entry) return;
|
|
717
748
|
const eventListeners = entry.listeners.get(event);
|
|
718
|
-
if (eventListeners) for (const listener of eventListeners) listener();
|
|
749
|
+
if (eventListeners?.size) for (const listener of [...eventListeners]) listener();
|
|
719
750
|
const allListeners = entry.listeners.get("*");
|
|
720
|
-
if (allListeners) for (const listener of allListeners) listener();
|
|
751
|
+
if (allListeners?.size) for (const listener of [...allListeners]) listener();
|
|
721
752
|
}
|
|
722
753
|
notifyAllListeners(atom$1) {
|
|
723
754
|
const entry = this.cache.get(atom$1);
|
|
724
755
|
if (!entry) return;
|
|
725
756
|
const allListeners = entry.listeners.get("*");
|
|
726
|
-
if (allListeners) for (const listener of allListeners) listener();
|
|
757
|
+
if (allListeners?.size) for (const listener of [...allListeners]) listener();
|
|
727
758
|
}
|
|
728
759
|
emitStateChange(state, atom$1) {
|
|
729
760
|
const stateMap = this.stateListeners.get(state);
|
|
730
761
|
if (stateMap) {
|
|
731
762
|
const listeners = stateMap.get(atom$1);
|
|
732
|
-
if (listeners) for (const listener of listeners) listener();
|
|
763
|
+
if (listeners?.size) for (const listener of [...listeners]) listener();
|
|
733
764
|
}
|
|
734
765
|
}
|
|
735
766
|
on(event, atom$1, listener) {
|
|
@@ -755,14 +786,15 @@ var ScopeImpl = class {
|
|
|
755
786
|
};
|
|
756
787
|
}
|
|
757
788
|
async resolve(atom$1) {
|
|
789
|
+
if (this.disposed) throw new Error("Scope is disposed");
|
|
758
790
|
if (!this.initialized) await this.ready;
|
|
759
791
|
const entry = this.cache.get(atom$1);
|
|
760
792
|
if (entry?.state === "resolved") return entry.value;
|
|
761
793
|
const pendingPromise = this.pending.get(atom$1);
|
|
762
794
|
if (pendingPromise) return pendingPromise;
|
|
763
795
|
if (this.resolving.has(atom$1)) throw new Error("Circular dependency detected");
|
|
764
|
-
|
|
765
|
-
|
|
796
|
+
if (this.presets.has(atom$1)) {
|
|
797
|
+
const presetValue = this.presets.get(atom$1);
|
|
766
798
|
if (isAtom(presetValue)) return this.resolve(presetValue);
|
|
767
799
|
const newEntry = this.getOrCreateEntry(atom$1);
|
|
768
800
|
newEntry.state = "resolved";
|
|
@@ -785,7 +817,9 @@ var ScopeImpl = class {
|
|
|
785
817
|
async doResolve(atom$1) {
|
|
786
818
|
const entry = this.getOrCreateEntry(atom$1);
|
|
787
819
|
if (!(entry.state === "resolving")) {
|
|
788
|
-
for (let i = entry.cleanups.length - 1; i >= 0; i--)
|
|
820
|
+
for (let i = entry.cleanups.length - 1; i >= 0; i--) try {
|
|
821
|
+
await entry.cleanups[i]?.();
|
|
822
|
+
} catch {}
|
|
789
823
|
entry.cleanups = [];
|
|
790
824
|
entry.state = "resolving";
|
|
791
825
|
this.emitStateChange("resolving", atom$1);
|
|
@@ -805,7 +839,7 @@ var ScopeImpl = class {
|
|
|
805
839
|
};
|
|
806
840
|
const factory = atom$1.factory;
|
|
807
841
|
const doResolve = async () => {
|
|
808
|
-
if (atom$1.deps
|
|
842
|
+
if (atom$1.deps) return factory(ctx, resolvedDeps);
|
|
809
843
|
else return factory(ctx);
|
|
810
844
|
};
|
|
811
845
|
try {
|
|
@@ -841,88 +875,103 @@ var ScopeImpl = class {
|
|
|
841
875
|
entry.pendingInvalidate = false;
|
|
842
876
|
this.invalidationChain?.delete(atom$1);
|
|
843
877
|
this.scheduleInvalidation(atom$1);
|
|
844
|
-
}
|
|
878
|
+
} else if (entry.pendingSet && "value" in entry.pendingSet) {
|
|
879
|
+
this.invalidationChain?.delete(atom$1);
|
|
880
|
+
this.scheduleInvalidation(atom$1);
|
|
881
|
+
} else entry.pendingSet = void 0;
|
|
845
882
|
throw entry.error;
|
|
846
883
|
}
|
|
847
884
|
}
|
|
848
885
|
async applyResolveExtensions(event, doResolve) {
|
|
849
886
|
let next = doResolve;
|
|
850
|
-
for (let i = this.
|
|
851
|
-
const ext = this.
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
next = ext.wrapResolve.bind(ext, currentNext, event);
|
|
855
|
-
}
|
|
887
|
+
for (let i = this.resolveExts.length - 1; i >= 0; i--) {
|
|
888
|
+
const ext = this.resolveExts[i];
|
|
889
|
+
const currentNext = next;
|
|
890
|
+
next = ext.wrapResolve.bind(ext, currentNext, event);
|
|
856
891
|
}
|
|
857
892
|
return next();
|
|
858
893
|
}
|
|
859
894
|
async resolveDeps(deps, ctx, dependentAtom) {
|
|
860
895
|
if (!deps) return {};
|
|
861
896
|
const result = {};
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (
|
|
886
|
-
|
|
887
|
-
|
|
897
|
+
const parallel = [];
|
|
898
|
+
const deferredResources = [];
|
|
899
|
+
for (const key in deps) {
|
|
900
|
+
const dep = deps[key];
|
|
901
|
+
if (isAtom(dep)) parallel.push(this.resolve(dep).then((value) => {
|
|
902
|
+
result[key] = value;
|
|
903
|
+
if (dependentAtom) {
|
|
904
|
+
const depEntry = this.getEntry(dep);
|
|
905
|
+
if (depEntry) depEntry.dependents.add(dependentAtom);
|
|
906
|
+
}
|
|
907
|
+
}));
|
|
908
|
+
else if (isControllerDep(dep)) {
|
|
909
|
+
if (dep.watch) {
|
|
910
|
+
if (!dependentAtom) throw new Error("controller({ watch: true }) is only supported in atom dependencies");
|
|
911
|
+
if (!dep.resolve) throw new Error("controller({ watch: true }) requires resolve: true");
|
|
912
|
+
}
|
|
913
|
+
const ctrl = this.controller(dep.atom);
|
|
914
|
+
if (dep.resolve) parallel.push(ctrl.resolve().then(() => {
|
|
915
|
+
result[key] = ctrl;
|
|
916
|
+
if (dependentAtom) {
|
|
917
|
+
const depEntry = this.getEntry(dep.atom);
|
|
918
|
+
if (depEntry) depEntry.dependents.add(dependentAtom);
|
|
919
|
+
}
|
|
920
|
+
if (dep.watch) {
|
|
921
|
+
const eq = dep.eq ?? Object.is;
|
|
922
|
+
let prev = ctrl.get();
|
|
923
|
+
const unsub = this.on("resolved", dep.atom, () => {
|
|
924
|
+
const next = ctrl.get();
|
|
925
|
+
if (!eq(prev, next)) {
|
|
926
|
+
prev = next;
|
|
927
|
+
this.scheduleInvalidation(dependentAtom);
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
const depEntry = this.getEntry(dependentAtom);
|
|
931
|
+
if (depEntry) depEntry.cleanups.push(unsub);
|
|
932
|
+
else unsub();
|
|
933
|
+
}
|
|
934
|
+
}));
|
|
935
|
+
else {
|
|
936
|
+
result[key] = ctrl;
|
|
937
|
+
if (dependentAtom) {
|
|
938
|
+
const depEntry = this.getEntry(dep.atom);
|
|
939
|
+
if (depEntry) depEntry.dependents.add(dependentAtom);
|
|
888
940
|
}
|
|
889
|
-
});
|
|
890
|
-
const depEntry = this.getEntry(dependentAtom);
|
|
891
|
-
if (depEntry) depEntry.cleanups.push(unsub);
|
|
892
|
-
else unsub();
|
|
893
|
-
}
|
|
894
|
-
} else if (tagExecutorSymbol in dep) {
|
|
895
|
-
const tagExecutor = dep;
|
|
896
|
-
switch (tagExecutor.mode) {
|
|
897
|
-
case "required": {
|
|
898
|
-
const value = ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags);
|
|
899
|
-
if (value !== void 0) result[key] = value;
|
|
900
|
-
else if (tagExecutor.tag.hasDefault) result[key] = tagExecutor.tag.defaultValue;
|
|
901
|
-
else throw new Error(`Tag "${tagExecutor.tag.label}" not found`);
|
|
902
|
-
break;
|
|
903
941
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
942
|
+
} else if (tagExecutorSymbol in dep) {
|
|
943
|
+
const tagExecutor = dep;
|
|
944
|
+
switch (tagExecutor.mode) {
|
|
945
|
+
case "required": {
|
|
946
|
+
const value = ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags);
|
|
947
|
+
if (value !== void 0) result[key] = value;
|
|
948
|
+
else if (tagExecutor.tag.hasDefault) result[key] = tagExecutor.tag.defaultValue;
|
|
949
|
+
else throw new Error(`Tag "${tagExecutor.tag.label}" not found`);
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
case "optional":
|
|
953
|
+
result[key] = (ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags)) ?? tagExecutor.tag.defaultValue;
|
|
954
|
+
break;
|
|
955
|
+
case "all":
|
|
956
|
+
result[key] = ctx ? this.collectFromHierarchy(ctx, tagExecutor.tag) : tagExecutor.tag.collect(this.tags);
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
959
|
+
} else if (isResource(dep)) deferredResources.push([key, dep]);
|
|
960
|
+
}
|
|
961
|
+
if (parallel.length === 1) await parallel[0];
|
|
962
|
+
else if (parallel.length > 1) await Promise.all(parallel);
|
|
963
|
+
for (const [key, resource$1] of deferredResources) {
|
|
912
964
|
if (!ctx) throw new Error("Resource deps require an ExecutionContext");
|
|
913
|
-
const resource$1 = dep;
|
|
914
965
|
const resourceKey = getResourceKey(resource$1);
|
|
915
966
|
const storeCtx = ctx.parent ?? ctx;
|
|
916
967
|
if (storeCtx.data.has(resourceKey)) {
|
|
917
968
|
result[key] = storeCtx.data.get(resourceKey);
|
|
918
969
|
continue;
|
|
919
970
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
result[key] = existingSeek;
|
|
971
|
+
if (ctx.data.seekHas(resourceKey)) {
|
|
972
|
+
result[key] = ctx.data.seek(resourceKey);
|
|
923
973
|
continue;
|
|
924
974
|
}
|
|
925
|
-
if (resolvingResources.has(resourceKey)) throw new Error(`Circular resource dependency detected: ${resource$1.name ?? "anonymous"}`);
|
|
926
975
|
let flights = inflightResources.get(storeCtx.data);
|
|
927
976
|
if (!flights) {
|
|
928
977
|
flights = /* @__PURE__ */ new Map();
|
|
@@ -933,8 +982,14 @@ var ScopeImpl = class {
|
|
|
933
982
|
result[key] = await inflight;
|
|
934
983
|
continue;
|
|
935
984
|
}
|
|
985
|
+
let localResolvingResources = resolvingResourcesMap.get(storeCtx.data);
|
|
986
|
+
if (!localResolvingResources) {
|
|
987
|
+
localResolvingResources = /* @__PURE__ */ new Set();
|
|
988
|
+
resolvingResourcesMap.set(storeCtx.data, localResolvingResources);
|
|
989
|
+
}
|
|
990
|
+
if (localResolvingResources.has(resourceKey)) throw new Error(`Circular resource dependency detected: ${resource$1.name ?? "anonymous"}`);
|
|
936
991
|
const resolve = async () => {
|
|
937
|
-
|
|
992
|
+
localResolvingResources.add(resourceKey);
|
|
938
993
|
try {
|
|
939
994
|
const resourceDeps = await this.resolveDeps(resource$1.deps, ctx);
|
|
940
995
|
const event = {
|
|
@@ -944,14 +999,14 @@ var ScopeImpl = class {
|
|
|
944
999
|
};
|
|
945
1000
|
const doResolve = async () => {
|
|
946
1001
|
const factory = resource$1.factory;
|
|
947
|
-
if (resource$1.deps
|
|
1002
|
+
if (resource$1.deps) return factory(storeCtx, resourceDeps);
|
|
948
1003
|
return factory(storeCtx);
|
|
949
1004
|
};
|
|
950
1005
|
const value = await this.applyResolveExtensions(event, doResolve);
|
|
951
1006
|
storeCtx.data.set(resourceKey, value);
|
|
952
1007
|
return value;
|
|
953
1008
|
} finally {
|
|
954
|
-
|
|
1009
|
+
localResolvingResources.delete(resourceKey);
|
|
955
1010
|
}
|
|
956
1011
|
};
|
|
957
1012
|
const promise = resolve();
|
|
@@ -975,6 +1030,7 @@ var ScopeImpl = class {
|
|
|
975
1030
|
return results;
|
|
976
1031
|
}
|
|
977
1032
|
controller(atom$1, options) {
|
|
1033
|
+
if (this.disposed) throw new Error("Scope is disposed");
|
|
978
1034
|
let ctrl = this.controllers.get(atom$1);
|
|
979
1035
|
if (!ctrl) {
|
|
980
1036
|
ctrl = new ControllerImpl(atom$1, this);
|
|
@@ -984,7 +1040,7 @@ var ScopeImpl = class {
|
|
|
984
1040
|
return ctrl;
|
|
985
1041
|
}
|
|
986
1042
|
select(atom$1, selector, options) {
|
|
987
|
-
return new SelectHandleImpl(this.controller(atom$1), selector, options?.eq ??
|
|
1043
|
+
return new SelectHandleImpl(this.controller(atom$1), selector, options?.eq ?? Object.is);
|
|
988
1044
|
}
|
|
989
1045
|
getFlowPreset(flow$1) {
|
|
990
1046
|
return this.presets.get(flow$1);
|
|
@@ -1028,10 +1084,27 @@ var ScopeImpl = class {
|
|
|
1028
1084
|
const previousValue = entry.value;
|
|
1029
1085
|
const pendingSet = entry.pendingSet;
|
|
1030
1086
|
entry.pendingSet = void 0;
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1087
|
+
if (pendingSet) {
|
|
1088
|
+
entry.state = "resolving";
|
|
1089
|
+
entry.value = previousValue;
|
|
1090
|
+
entry.error = void 0;
|
|
1091
|
+
entry.pendingInvalidate = false;
|
|
1092
|
+
this.pending.delete(atom$1);
|
|
1093
|
+
this.resolving.delete(atom$1);
|
|
1094
|
+
this.emitStateChange("resolving", atom$1);
|
|
1095
|
+
this.notifyListeners(atom$1, "resolving");
|
|
1096
|
+
if ("value" in pendingSet) entry.value = pendingSet.value;
|
|
1097
|
+
else entry.value = pendingSet.fn(previousValue);
|
|
1098
|
+
entry.state = "resolved";
|
|
1099
|
+
entry.hasValue = true;
|
|
1100
|
+
this.emitStateChange("resolved", atom$1);
|
|
1101
|
+
this.notifyListeners(atom$1, "resolved");
|
|
1102
|
+
this.invalidationChain?.delete(atom$1);
|
|
1103
|
+
return;
|
|
1034
1104
|
}
|
|
1105
|
+
for (let i = entry.cleanups.length - 1; i >= 0; i--) try {
|
|
1106
|
+
await entry.cleanups[i]?.();
|
|
1107
|
+
} catch {}
|
|
1035
1108
|
entry.cleanups = [];
|
|
1036
1109
|
entry.state = "resolving";
|
|
1037
1110
|
entry.value = previousValue;
|
|
@@ -1041,16 +1114,11 @@ var ScopeImpl = class {
|
|
|
1041
1114
|
this.resolving.delete(atom$1);
|
|
1042
1115
|
this.emitStateChange("resolving", atom$1);
|
|
1043
1116
|
this.notifyListeners(atom$1, "resolving");
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
entry.
|
|
1048
|
-
entry.hasValue = true;
|
|
1049
|
-
this.emitStateChange("resolved", atom$1);
|
|
1050
|
-
this.notifyListeners(atom$1, "resolved");
|
|
1051
|
-
return;
|
|
1117
|
+
try {
|
|
1118
|
+
await this.resolve(atom$1);
|
|
1119
|
+
} catch (e) {
|
|
1120
|
+
if (!entry.pendingSet && !entry.pendingInvalidate) throw e;
|
|
1052
1121
|
}
|
|
1053
|
-
await this.resolve(atom$1);
|
|
1054
1122
|
}
|
|
1055
1123
|
async release(atom$1) {
|
|
1056
1124
|
const entry = this.cache.get(atom$1);
|
|
@@ -1059,14 +1127,33 @@ var ScopeImpl = class {
|
|
|
1059
1127
|
clearTimeout(entry.gcScheduled);
|
|
1060
1128
|
entry.gcScheduled = null;
|
|
1061
1129
|
}
|
|
1062
|
-
for (let i = entry.cleanups.length - 1; i >= 0; i--) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1130
|
+
for (let i = entry.cleanups.length - 1; i >= 0; i--) try {
|
|
1131
|
+
await entry.cleanups[i]?.();
|
|
1132
|
+
} catch {}
|
|
1133
|
+
if (atom$1.deps) for (const dep of Object.values(atom$1.deps)) {
|
|
1134
|
+
const depAtom = isAtom(dep) ? dep : isControllerDep(dep) ? dep.atom : null;
|
|
1135
|
+
if (!depAtom) continue;
|
|
1136
|
+
const depEntry = this.cache.get(depAtom);
|
|
1137
|
+
if (depEntry) {
|
|
1138
|
+
depEntry.dependents.delete(atom$1);
|
|
1139
|
+
this.maybeScheduleGC(depAtom);
|
|
1140
|
+
}
|
|
1065
1141
|
}
|
|
1066
1142
|
this.cache.delete(atom$1);
|
|
1067
1143
|
this.controllers.delete(atom$1);
|
|
1144
|
+
for (const [state, stateMap] of this.stateListeners) {
|
|
1145
|
+
stateMap.delete(atom$1);
|
|
1146
|
+
if (stateMap.size === 0) this.stateListeners.delete(state);
|
|
1147
|
+
}
|
|
1068
1148
|
}
|
|
1069
1149
|
async dispose() {
|
|
1150
|
+
if (this.chainPromise) try {
|
|
1151
|
+
await this.chainPromise;
|
|
1152
|
+
} catch {}
|
|
1153
|
+
this.disposed = true;
|
|
1154
|
+
this.invalidationQueue.clear();
|
|
1155
|
+
this.invalidationChain = null;
|
|
1156
|
+
this.chainPromise = null;
|
|
1070
1157
|
for (const ext of this.extensions) if (ext.dispose) await ext.dispose(this);
|
|
1071
1158
|
for (const entry of this.cache.values()) if (entry.gcScheduled) {
|
|
1072
1159
|
clearTimeout(entry.gcScheduled);
|
|
@@ -1077,8 +1164,14 @@ var ScopeImpl = class {
|
|
|
1077
1164
|
}
|
|
1078
1165
|
async flush() {
|
|
1079
1166
|
if (this.chainPromise) await this.chainPromise;
|
|
1167
|
+
if (this.chainError !== null) {
|
|
1168
|
+
const error = this.chainError;
|
|
1169
|
+
this.chainError = null;
|
|
1170
|
+
throw error;
|
|
1171
|
+
}
|
|
1080
1172
|
}
|
|
1081
1173
|
createContext(options) {
|
|
1174
|
+
if (this.disposed) throw new Error("Scope is disposed");
|
|
1082
1175
|
const ctx = new ExecutionContextImpl(this, options);
|
|
1083
1176
|
for (const tagged of options?.tags ?? []) ctx.data.set(tagged.key, tagged.value);
|
|
1084
1177
|
for (const tagged of this.tags) if (!ctx.data.has(tagged.key)) ctx.data.set(tagged.key, tagged.value);
|
|
@@ -1172,7 +1265,7 @@ var ExecutionContextImpl = class ExecutionContextImpl {
|
|
|
1172
1265
|
const resolvedDeps = await this.scope.resolveDeps(flow$1.deps, this);
|
|
1173
1266
|
const factory = flow$1.factory;
|
|
1174
1267
|
const doExec = async () => {
|
|
1175
|
-
if (flow$1.deps
|
|
1268
|
+
if (flow$1.deps) return factory(this, resolvedDeps);
|
|
1176
1269
|
else return factory(this);
|
|
1177
1270
|
};
|
|
1178
1271
|
return this.applyExecExtensions(flow$1, doExec);
|
|
@@ -1188,12 +1281,10 @@ var ExecutionContextImpl = class ExecutionContextImpl {
|
|
|
1188
1281
|
}
|
|
1189
1282
|
async applyExecExtensions(target, doExec) {
|
|
1190
1283
|
let next = doExec;
|
|
1191
|
-
for (let i = this.scope.
|
|
1192
|
-
const ext = this.scope.
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
next = ext.wrapExec.bind(ext, currentNext, target, this);
|
|
1196
|
-
}
|
|
1284
|
+
for (let i = this.scope.execExts.length - 1; i >= 0; i--) {
|
|
1285
|
+
const ext = this.scope.execExts[i];
|
|
1286
|
+
const currentNext = next;
|
|
1287
|
+
next = ext.wrapExec.bind(ext, currentNext, target, this);
|
|
1197
1288
|
}
|
|
1198
1289
|
return next();
|
|
1199
1290
|
}
|
|
@@ -1203,10 +1294,9 @@ var ExecutionContextImpl = class ExecutionContextImpl {
|
|
|
1203
1294
|
async close(result = { ok: true }) {
|
|
1204
1295
|
if (this.closed) return;
|
|
1205
1296
|
this.closed = true;
|
|
1206
|
-
for (let i = this.cleanups.length - 1; i >= 0; i--) {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
}
|
|
1297
|
+
for (let i = this.cleanups.length - 1; i >= 0; i--) try {
|
|
1298
|
+
await this.cleanups[i]?.(result);
|
|
1299
|
+
} catch {}
|
|
1210
1300
|
}
|
|
1211
1301
|
};
|
|
1212
1302
|
/**
|