mutts 1.0.10 → 1.0.12
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/README.md +3 -3
- package/dist/browser.cjs +244 -3199
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +2 -2
- package/dist/browser.dev.cjs +51 -50
- package/dist/browser.dev.cjs.map +1 -1
- package/dist/browser.dev.d.ts +2 -2
- package/dist/browser.dev.esm.js +2 -2
- package/dist/browser.esm.js +15 -13
- package/dist/browser.esm.js.map +1 -1
- package/dist/chunks/{index-CaaQQlPJ.esm.js → index-BUop6B2U.esm.js} +384 -981
- package/dist/chunks/index-BUop6B2U.esm.js.map +1 -0
- package/dist/chunks/index-yK0HVxHv.cjs +2612 -0
- package/dist/chunks/index-yK0HVxHv.cjs.map +1 -0
- package/dist/chunks/{node-nKJBk8iJ.esm.js → node-Bo7WU5S2.esm.js} +2 -2
- package/dist/chunks/{node-nKJBk8iJ.esm.js.map → node-Bo7WU5S2.esm.js.map} +1 -1
- package/dist/chunks/{async-node-3PrbVAbB.cjs → node-Dd0esp5F.cjs} +4 -4
- package/dist/chunks/node-Dd0esp5F.cjs.map +1 -0
- package/dist/chunks/{proxy-Dtg-bJ3T.cjs → proxy-BvM4yewA.cjs} +441 -342
- package/dist/chunks/proxy-BvM4yewA.cjs.map +1 -0
- package/dist/chunks/{proxy-r7lARftl.esm.js → proxy-D2C49sXH.esm.js} +401 -330
- package/dist/chunks/proxy-D2C49sXH.esm.js.map +1 -0
- package/dist/debug.cjs +17 -4
- package/dist/debug.cjs.map +1 -1
- package/dist/debug.d.ts +2 -2
- package/dist/debug.esm.js +17 -3
- package/dist/debug.esm.js.map +1 -1
- package/dist/index.d.ts +84 -209
- package/dist/mutts.umd.js +842 -1362
- package/dist/mutts.umd.js.map +1 -1
- package/dist/mutts.umd.min.js +1 -1
- package/dist/mutts.umd.min.js.map +1 -1
- package/dist/node.cjs +51 -49
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.dev.cjs +51 -49
- package/dist/node.dev.cjs.map +1 -1
- package/dist/node.dev.d.ts +2 -2
- package/dist/node.dev.esm.js +3 -3
- package/dist/node.esm.js +3 -3
- package/dist/{types-W5vD6m2n.d.ts → types-Bx2PhORg.d.ts} +38 -47
- package/docs/ai/api-reference.md +0 -14
- package/docs/ai/manual.md +2 -22
- package/docs/reactive/advanced.md +13 -14
- package/docs/reactive/attend.md +1 -2
- package/docs/reactive/collections.md +2 -149
- package/docs/reactive/core.md +218 -96
- package/docs/reactive/debugging.md +2 -2
- package/docs/reactive/resource.md +1 -1
- package/docs/reactive.md +1 -3
- package/docs/zone.md +1 -1
- package/package.json +18 -9
- package/dist/chunks/async-browser-BU_IfxYD.cjs +0 -216
- package/dist/chunks/async-browser-BU_IfxYD.cjs.map +0 -1
- package/dist/chunks/async-core-CRLKP3l-.cjs +0 -29
- package/dist/chunks/async-core-CRLKP3l-.cjs.map +0 -1
- package/dist/chunks/async-node-3PrbVAbB.cjs.map +0 -1
- package/dist/chunks/index-CaaQQlPJ.esm.js.map +0 -1
- package/dist/chunks/proxy-Dtg-bJ3T.cjs.map +0 -1
- package/dist/chunks/proxy-r7lARftl.esm.js.map +0 -1
- package/docs/reactive/scan.md +0 -324
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as decorator, B as flavored, O as isReactive, $ as reactive, x as effect, a4 as touched, S as link, G as getState, aa as dependant, a5 as touched1, ab as keysOf, ac as markWithRoot, ad as objectsWithDeepWatchers, ae as effectToDeepWatchedObjects, a7 as untracked, af as deepWatchers, a0 as options, L as isNonReactive, a8 as unwrap, ag as registerDeepWatcher, V as named, ah as rootFunctionSymbol, _ as proxyToObject, ai as getRoot, u as deepCompare, aj as optionCall, a2 as root, ak as FoolProof, z as flavorOptions, al as effectHistory, p as captured, am as unreactiveProperties, g as addUnreactiveProps, an as __runInitializers, ao as __esDecorate, n as atomic, ap as batch, aq as contentRef, ar as notifyPropertyChange, as as metaProtos, at as wrapProtos, au as objectParents, av as watchers, aw as effectToReactiveObjects, W as objectToProxy } from './proxy-D2C49sXH.esm.js';
|
|
2
2
|
|
|
3
3
|
// Integrated with `using` statement via Symbol.dispose
|
|
4
4
|
const fr = new FinalizationRegistry((f) => f());
|
|
@@ -744,211 +744,6 @@ function chainPromise(given) {
|
|
|
744
744
|
return chained;
|
|
745
745
|
}
|
|
746
746
|
|
|
747
|
-
const memoizedRegistry = new WeakMap();
|
|
748
|
-
const wrapperRegistry = new WeakMap();
|
|
749
|
-
function getBranch(tree, key) {
|
|
750
|
-
tree.branches ?? (tree.branches = new WeakMap());
|
|
751
|
-
let branch = tree.branches.get(key);
|
|
752
|
-
if (!branch) {
|
|
753
|
-
branch = {};
|
|
754
|
-
tree.branches.set(key, branch);
|
|
755
|
-
}
|
|
756
|
-
return branch;
|
|
757
|
-
}
|
|
758
|
-
function memoizeFunction(fn, opts) {
|
|
759
|
-
const fnRoot = getRoot(fn);
|
|
760
|
-
const existing = memoizedRegistry.get(fnRoot);
|
|
761
|
-
if (existing)
|
|
762
|
-
return existing;
|
|
763
|
-
const cacheRoot = {};
|
|
764
|
-
const memoized = markWithRoot(function memoized(...args) {
|
|
765
|
-
if (args.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg)))) {
|
|
766
|
-
if (opts?.lenient)
|
|
767
|
-
return fn.apply(this, args);
|
|
768
|
-
throw new Error('memoize expects non-null object arguments');
|
|
769
|
-
}
|
|
770
|
-
let node = cacheRoot;
|
|
771
|
-
// Note: decorators add `this` as first argument
|
|
772
|
-
for (const arg of args) {
|
|
773
|
-
node = getBranch(node, arg);
|
|
774
|
-
}
|
|
775
|
-
dependant(node, 'memoize');
|
|
776
|
-
if ('result' in node) {
|
|
777
|
-
if (options.onMemoizationDiscrepancy) {
|
|
778
|
-
const wasVerification = options.isVerificationRun;
|
|
779
|
-
options.isVerificationRun = true;
|
|
780
|
-
try {
|
|
781
|
-
const fresh = untracked(() => fn.apply(this, args));
|
|
782
|
-
if (!deepCompare(node.result, fresh)) {
|
|
783
|
-
optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'calculation');
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
finally {
|
|
787
|
-
options.isVerificationRun = wasVerification;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
return node.result;
|
|
791
|
-
}
|
|
792
|
-
// Create memoize internal effect to track dependencies and invalidate cache
|
|
793
|
-
// Use untracked to prevent the effect creation from being affected by parent effects
|
|
794
|
-
node.cleanup = root(() => effect.named('memoize')(() => {
|
|
795
|
-
// Execute the function and track its dependencies
|
|
796
|
-
// The function execution will automatically track dependencies on reactive objects
|
|
797
|
-
node.result = fn.apply(this, args);
|
|
798
|
-
return (reason) => {
|
|
799
|
-
// When dependencies change, clear the cache and notify consumers
|
|
800
|
-
delete node.result;
|
|
801
|
-
touched1(node, { type: 'invalidate', prop: args }, 'memoize');
|
|
802
|
-
// Lazy memoization: stop the effect so it doesn't re-run immediately.
|
|
803
|
-
// It will be re-created on next access.
|
|
804
|
-
if (node.cleanup) {
|
|
805
|
-
node.cleanup({ type: 'invalidate', cause: reason });
|
|
806
|
-
node.cleanup = undefined;
|
|
807
|
-
}
|
|
808
|
-
};
|
|
809
|
-
}, { opaque: true }));
|
|
810
|
-
if (options.onMemoizationDiscrepancy) {
|
|
811
|
-
const wasVerification = options.isVerificationRun;
|
|
812
|
-
options.isVerificationRun = true;
|
|
813
|
-
try {
|
|
814
|
-
const fresh = untracked(() => fn.apply(this, args));
|
|
815
|
-
if (!deepCompare(node.result, fresh)) {
|
|
816
|
-
optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'comparison');
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
finally {
|
|
820
|
-
options.isVerificationRun = wasVerification;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
return node.result;
|
|
824
|
-
}, fn);
|
|
825
|
-
memoizedRegistry.set(fnRoot, memoized);
|
|
826
|
-
memoizedRegistry.set(memoized, memoized);
|
|
827
|
-
return memoized;
|
|
828
|
-
}
|
|
829
|
-
function memoizeObject(target, opts) {
|
|
830
|
-
const existing = memoizedRegistry.get(target);
|
|
831
|
-
if (existing)
|
|
832
|
-
return existing;
|
|
833
|
-
const proxy = new Proxy(target, {
|
|
834
|
-
get(source, prop, receiver) {
|
|
835
|
-
// 1. Walk prototype chain to find descriptor
|
|
836
|
-
let current = source;
|
|
837
|
-
let desc;
|
|
838
|
-
while (current) {
|
|
839
|
-
desc = Object.getOwnPropertyDescriptor(current, prop);
|
|
840
|
-
if (desc)
|
|
841
|
-
break;
|
|
842
|
-
current = Object.getPrototypeOf(current);
|
|
843
|
-
}
|
|
844
|
-
if (!desc)
|
|
845
|
-
return Reflect.get(source, prop, receiver);
|
|
846
|
-
// 2. If getter, memoize
|
|
847
|
-
if (desc.get) {
|
|
848
|
-
const originalGetter = desc.get;
|
|
849
|
-
let wrapper = wrapperRegistry.get(originalGetter);
|
|
850
|
-
if (!wrapper) {
|
|
851
|
-
wrapper = markWithRoot(named(`${String(source?.constructor?.name ?? 'Object')}.${String(prop)}`, (that) => {
|
|
852
|
-
return originalGetter.call(that);
|
|
853
|
-
}), {
|
|
854
|
-
propertyKey: prop,
|
|
855
|
-
});
|
|
856
|
-
const origRoot = originalGetter[rootFunctionSymbol];
|
|
857
|
-
if (origRoot)
|
|
858
|
-
wrapper[rootFunctionSymbol] = origRoot;
|
|
859
|
-
wrapperRegistry.set(originalGetter, wrapper);
|
|
860
|
-
}
|
|
861
|
-
const memoized = memoizeFunction(wrapper, opts);
|
|
862
|
-
return memoized(receiver);
|
|
863
|
-
}
|
|
864
|
-
// 3. Otherwise forward
|
|
865
|
-
return Reflect.get(source, prop, receiver);
|
|
866
|
-
},
|
|
867
|
-
// Forward set to the target (source) to ensure it acts as the receiver for reactivity notifications
|
|
868
|
-
set(source, prop, value, _receiver) {
|
|
869
|
-
// By strictly passing `source` as receiver, we ensure that if `source` is a reactive proxy,
|
|
870
|
-
// it recognizes itself and triggers change notifications.
|
|
871
|
-
return Reflect.set(source, prop, value, source);
|
|
872
|
-
},
|
|
873
|
-
});
|
|
874
|
-
proxyToObject.set(proxy, target);
|
|
875
|
-
memoizedRegistry.set(target, proxy);
|
|
876
|
-
return proxy;
|
|
877
|
-
}
|
|
878
|
-
/**
|
|
879
|
-
* Decorator and function wrapper for memoizing computed values based on reactive dependencies.
|
|
880
|
-
*
|
|
881
|
-
* When used as a decorator on getters or methods, it caches the result and automatically
|
|
882
|
-
* invalidates the cache when reactive dependencies change.
|
|
883
|
-
*
|
|
884
|
-
* When used as a function wrapper, it memoizes based on object arguments (WeakMap-based cache).
|
|
885
|
-
*
|
|
886
|
-
* @example
|
|
887
|
-
* ```typescript
|
|
888
|
-
* class User {
|
|
889
|
-
* @memoize
|
|
890
|
-
* get fullName() {
|
|
891
|
-
* return `${this.firstName} ${this.lastName}`
|
|
892
|
-
* }
|
|
893
|
-
* }
|
|
894
|
-
*
|
|
895
|
-
* // Or as a function wrapper
|
|
896
|
-
* const expensive = memoize((obj: SomeObject) => {
|
|
897
|
-
* return heavyComputation(obj)
|
|
898
|
-
* })
|
|
899
|
-
* ```
|
|
900
|
-
*/
|
|
901
|
-
function makeMemoizeDecorator(memoizeOpts) {
|
|
902
|
-
return decorator({
|
|
903
|
-
getter(original, target, propertyKey) {
|
|
904
|
-
return function () {
|
|
905
|
-
let wrapper = wrapperRegistry.get(original);
|
|
906
|
-
if (!wrapper) {
|
|
907
|
-
wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`, (that) => {
|
|
908
|
-
return original.call(that);
|
|
909
|
-
}), {
|
|
910
|
-
method: original,
|
|
911
|
-
propertyKey,
|
|
912
|
-
});
|
|
913
|
-
const origRoot = original[rootFunctionSymbol];
|
|
914
|
-
if (origRoot)
|
|
915
|
-
wrapper[rootFunctionSymbol] = origRoot;
|
|
916
|
-
wrapperRegistry.set(original, wrapper);
|
|
917
|
-
}
|
|
918
|
-
const memoized = memoizeFunction(wrapper, memoizeOpts);
|
|
919
|
-
return memoized(this);
|
|
920
|
-
};
|
|
921
|
-
},
|
|
922
|
-
method(original, target, name) {
|
|
923
|
-
return function (...args) {
|
|
924
|
-
let wrapper = wrapperRegistry.get(original);
|
|
925
|
-
if (!wrapper) {
|
|
926
|
-
wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`, (that, ...args) => {
|
|
927
|
-
return original.call(that, ...args);
|
|
928
|
-
}), {
|
|
929
|
-
method: original,
|
|
930
|
-
propertyKey: name,
|
|
931
|
-
});
|
|
932
|
-
const origRoot = original[rootFunctionSymbol];
|
|
933
|
-
if (origRoot)
|
|
934
|
-
wrapper[rootFunctionSymbol] = origRoot;
|
|
935
|
-
wrapperRegistry.set(original, wrapper);
|
|
936
|
-
}
|
|
937
|
-
const memoized = memoizeFunction(wrapper, memoizeOpts);
|
|
938
|
-
return memoized(this, ...args);
|
|
939
|
-
};
|
|
940
|
-
},
|
|
941
|
-
default: (target) => typeof target === 'object'
|
|
942
|
-
? memoizeObject(target, memoizeOpts)
|
|
943
|
-
: memoizeFunction(target, memoizeOpts),
|
|
944
|
-
});
|
|
945
|
-
}
|
|
946
|
-
const memoize = flavored(makeMemoizeDecorator(), {
|
|
947
|
-
get lenient() {
|
|
948
|
-
return makeMemoizeDecorator({ lenient: true });
|
|
949
|
-
},
|
|
950
|
-
});
|
|
951
|
-
|
|
952
747
|
function attend(source, callback) {
|
|
953
748
|
const enumerate = typeof source === 'function'
|
|
954
749
|
? source
|
|
@@ -960,14 +755,14 @@ function attend(source, callback) {
|
|
|
960
755
|
? () => source.values()
|
|
961
756
|
: () => Object.keys(source);
|
|
962
757
|
const keyEffects = new Map();
|
|
963
|
-
const outer = effect(({ ascend }) => {
|
|
758
|
+
const outer = effect.named('attend')(({ ascend }) => {
|
|
964
759
|
const keys = new Set();
|
|
965
760
|
for (const key of enumerate())
|
|
966
761
|
keys.add(key);
|
|
967
762
|
for (const key of keys) {
|
|
968
763
|
if (keyEffects.has(key))
|
|
969
764
|
continue;
|
|
970
|
-
keyEffects.set(key, ascend(() => effect(() => callback(key))));
|
|
765
|
+
keyEffects.set(key, ascend(() => effect.named(`attend:${key}`)((access) => callback(key, access))));
|
|
971
766
|
}
|
|
972
767
|
for (const key of Array.from(keyEffects.keys())) {
|
|
973
768
|
if (!keys.has(key)) {
|
|
@@ -983,146 +778,10 @@ function attend(source, callback) {
|
|
|
983
778
|
keyEffects.clear();
|
|
984
779
|
};
|
|
985
780
|
}
|
|
986
|
-
/**
|
|
987
|
-
* Perform a reactive scan over an array of items.
|
|
988
|
-
*
|
|
989
|
-
* This implementation is highly optimized for performance and fine-grained reactivity:
|
|
990
|
-
* - **Incremental Updates**: Changes to an item only trigger re-computation from that
|
|
991
|
-
* point onwards in the result chain.
|
|
992
|
-
* - **Move Optimization**: If items are moved within the array, their accumulated
|
|
993
|
-
* values are reused as long as their predecessor remains the same.
|
|
994
|
-
* - **Duplicate Support**: Correctly handles multiple occurrences of the same object
|
|
995
|
-
* instance using an internal occurrence tracking mechanism.
|
|
996
|
-
* - **Memory Efficient**: Uses `WeakMap` for caching intermediates, which are
|
|
997
|
-
* automatically cleared when source items are garbage collected.
|
|
998
|
-
*
|
|
999
|
-
* @example
|
|
1000
|
-
* ```typescript
|
|
1001
|
-
* const source = reactive([{ val: 1 }, { val: 2 }, { val: 3 }])
|
|
1002
|
-
* const sum = scan(source, (acc, item) => acc + item.val, 0)
|
|
1003
|
-
*
|
|
1004
|
-
* expect([...sum]).toEqual([1, 3, 6])
|
|
1005
|
-
*
|
|
1006
|
-
* // Modifying an item only re-computes subsequent sums
|
|
1007
|
-
* source[1].val = 10
|
|
1008
|
-
* expect([...sum]).toEqual([1, 11, 14])
|
|
1009
|
-
* ```
|
|
1010
|
-
*
|
|
1011
|
-
* @param source The source array of objects (will be made reactive)
|
|
1012
|
-
* @param callback The accumulator function called with (accumulator, currentItem)
|
|
1013
|
-
* @param initialValue The starting value for the accumulation
|
|
1014
|
-
* @returns A reactive array of accumulated values, with a [cleanup] property to stop the tracking
|
|
1015
|
-
*/
|
|
1016
|
-
function scan(source, callback, initialValue) {
|
|
1017
|
-
const observedSource = reactive(source);
|
|
1018
|
-
const rawResult = [];
|
|
1019
|
-
const result = reactive(rawResult);
|
|
1020
|
-
// Track effects for each index to dispose them when the array shrinks
|
|
1021
|
-
const indexEffects = new Map();
|
|
1022
|
-
// Mapping from index to its current intermediate object
|
|
1023
|
-
const indexToIntermediate = reactive([]);
|
|
1024
|
-
const intermediaries = new WeakMap();
|
|
1025
|
-
let Intermediate = (() => {
|
|
1026
|
-
var _a;
|
|
1027
|
-
let _instanceExtraInitializers = [];
|
|
1028
|
-
let _get_acc_decorators;
|
|
1029
|
-
return _a = class Intermediate {
|
|
1030
|
-
constructor(val, prev) {
|
|
1031
|
-
this.val = (__runInitializers(this, _instanceExtraInitializers), val);
|
|
1032
|
-
this.prev = prev;
|
|
1033
|
-
}
|
|
1034
|
-
get acc() {
|
|
1035
|
-
const prevAcc = this.prev ? this.prev.acc : initialValue;
|
|
1036
|
-
return callback(prevAcc, this.val);
|
|
1037
|
-
}
|
|
1038
|
-
},
|
|
1039
|
-
(() => {
|
|
1040
|
-
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
1041
|
-
_get_acc_decorators = [memoize];
|
|
1042
|
-
__esDecorate(_a, null, _get_acc_decorators, { kind: "getter", name: "acc", static: false, private: false, access: { has: obj => "acc" in obj, get: obj => obj.acc }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
1043
|
-
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1044
|
-
})(),
|
|
1045
|
-
_a;
|
|
1046
|
-
})();
|
|
1047
|
-
function disposeIndex(index) {
|
|
1048
|
-
const stop = indexEffects.get(index);
|
|
1049
|
-
if (stop) {
|
|
1050
|
-
stop();
|
|
1051
|
-
indexEffects.delete(index);
|
|
1052
|
-
Reflect.deleteProperty(indexToIntermediate, index);
|
|
1053
|
-
Reflect.deleteProperty(result, index);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
const mainEffect = effect(function scanMainEffect({ ascend }) {
|
|
1057
|
-
const length = observedSource.length;
|
|
1058
|
-
const occurrenceCount = new Map();
|
|
1059
|
-
let prev;
|
|
1060
|
-
for (let i = 0; i < length; i++)
|
|
1061
|
-
if (i in observedSource) {
|
|
1062
|
-
const val = observedSource[i];
|
|
1063
|
-
if (!(val &&
|
|
1064
|
-
(typeof val === 'object' || typeof val === 'function' || typeof val === 'symbol'))) {
|
|
1065
|
-
throw new Error('scan: items must be objects (WeakKey) for intermediate caching');
|
|
1066
|
-
}
|
|
1067
|
-
const count = occurrenceCount.get(val) ?? 0;
|
|
1068
|
-
occurrenceCount.set(val, count + 1);
|
|
1069
|
-
let list = intermediaries.get(val);
|
|
1070
|
-
if (!list) {
|
|
1071
|
-
list = [];
|
|
1072
|
-
intermediaries.set(val, list);
|
|
1073
|
-
}
|
|
1074
|
-
let intermediate = list[count];
|
|
1075
|
-
if (!intermediate) {
|
|
1076
|
-
intermediate = reactive(new Intermediate(val, prev));
|
|
1077
|
-
list[count] = intermediate;
|
|
1078
|
-
}
|
|
1079
|
-
else {
|
|
1080
|
-
// Update the link.
|
|
1081
|
-
if (untracked(() => intermediate.prev) !== prev) {
|
|
1082
|
-
intermediate.prev = prev;
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
// Update the reactive mapping for this index
|
|
1086
|
-
if (indexToIntermediate[i] !== intermediate) {
|
|
1087
|
-
indexToIntermediate[i] = intermediate;
|
|
1088
|
-
}
|
|
1089
|
-
// If we don't have an effect for this index yet, create one
|
|
1090
|
-
if (!indexEffects.has(i)) {
|
|
1091
|
-
ascend(() => {
|
|
1092
|
-
const index = i;
|
|
1093
|
-
const stop = effect(function scanIndexSyncEffect() {
|
|
1094
|
-
const inter = indexToIntermediate[index];
|
|
1095
|
-
if (inter) {
|
|
1096
|
-
const accValue = inter.acc;
|
|
1097
|
-
result[index] = accValue;
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
|
-
indexEffects.set(index, stop);
|
|
1101
|
-
});
|
|
1102
|
-
}
|
|
1103
|
-
prev = intermediate;
|
|
1104
|
-
}
|
|
1105
|
-
// Cleanup trailing indices
|
|
1106
|
-
for (const index of Array.from(indexEffects.keys())) {
|
|
1107
|
-
if (index >= length)
|
|
1108
|
-
disposeIndex(index);
|
|
1109
|
-
}
|
|
1110
|
-
// Ensure result length matches source length
|
|
1111
|
-
if (rawResult.length !== length) {
|
|
1112
|
-
FoolProof.set(result, 'length', length, result);
|
|
1113
|
-
}
|
|
1114
|
-
});
|
|
1115
|
-
return cleanedBy(result, ((reason) => {
|
|
1116
|
-
mainEffect(reason);
|
|
1117
|
-
for (const stop of indexEffects.values())
|
|
1118
|
-
stop(reason);
|
|
1119
|
-
indexEffects.clear();
|
|
1120
|
-
}));
|
|
1121
|
-
}
|
|
1122
781
|
function lift(cb) {
|
|
1123
782
|
let result;
|
|
1124
783
|
let rawResult;
|
|
1125
|
-
const liftCleanup = effect.named(
|
|
784
|
+
const liftCleanup = effect.named(`lift:${cb.name}`)(markWithRoot((access) => {
|
|
1126
785
|
const source = cb(access);
|
|
1127
786
|
if (!source || typeof source !== 'object')
|
|
1128
787
|
throw new Error('lift callback must return an array or object');
|
|
@@ -1135,11 +794,8 @@ function lift(cb) {
|
|
|
1135
794
|
throw new Error('lift callback must return the same type as the previous result');
|
|
1136
795
|
if (Array.isArray(source)) {
|
|
1137
796
|
const res = result;
|
|
1138
|
-
const
|
|
1139
|
-
for (let i = patches.length - 1; i >= 0; i--) {
|
|
1140
|
-
const { indexA, sliceA, sliceB } = patches[i];
|
|
797
|
+
for (const { indexA, sliceA, sliceB } of arrayDiff(res, source).sort((a, b) => a.indexA - b.indexA))
|
|
1141
798
|
res.splice(indexA, sliceA.length, ...sliceB);
|
|
1142
|
-
}
|
|
1143
799
|
}
|
|
1144
800
|
else {
|
|
1145
801
|
for (const key of Object.keys(source)) {
|
|
@@ -1166,7 +822,7 @@ function lift(cb) {
|
|
|
1166
822
|
}
|
|
1167
823
|
}
|
|
1168
824
|
}, cb));
|
|
1169
|
-
return
|
|
825
|
+
return link(result, liftCleanup);
|
|
1170
826
|
}
|
|
1171
827
|
/**
|
|
1172
828
|
* Reactively maps an array source through `fn`, producing a lazy reactive output array.
|
|
@@ -1187,7 +843,7 @@ function lift(cb) {
|
|
|
1187
843
|
*/
|
|
1188
844
|
function morphArray(source, fn, options) {
|
|
1189
845
|
if (typeof source !== 'function' && !isReactive(source) && options?.pure === true) {
|
|
1190
|
-
return source.map(fn);
|
|
846
|
+
return source.map((i) => fn(i));
|
|
1191
847
|
}
|
|
1192
848
|
let track;
|
|
1193
849
|
const itemEffects = new Map();
|
|
@@ -1209,17 +865,14 @@ function morphArray(source, fn, options) {
|
|
|
1209
865
|
}
|
|
1210
866
|
else {
|
|
1211
867
|
const indexRef = { value: key };
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
cache[indexRef.value]
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
};
|
|
1221
|
-
});
|
|
1222
|
-
});
|
|
868
|
+
const stop = track(() => effect.named(`morph:${fn.name}:${key}`).opaque((access) => {
|
|
869
|
+
cache[indexRef.value] = fn(input, access);
|
|
870
|
+
return (reason) => {
|
|
871
|
+
delete cache[indexRef.value];
|
|
872
|
+
touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
|
|
873
|
+
stop?.({ type: 'invalidate', cause: reason });
|
|
874
|
+
};
|
|
875
|
+
}));
|
|
1223
876
|
itemEffects.set(key, { stop, index: indexRef });
|
|
1224
877
|
}
|
|
1225
878
|
}
|
|
@@ -1236,7 +889,7 @@ function morphArray(source, fn, options) {
|
|
|
1236
889
|
return Reflect.has(input, prop);
|
|
1237
890
|
},
|
|
1238
891
|
});
|
|
1239
|
-
const stopMain = effect.named(
|
|
892
|
+
const stopMain = effect.named(`morph:${fn.name}`)(({ ascend }) => {
|
|
1240
893
|
track = ascend;
|
|
1241
894
|
const newInput = [...(typeof source === 'function' ? source() : source)];
|
|
1242
895
|
const diffs = arrayDiff(input, newInput).toSorted((a, b) => b.indexA - a.indexA);
|
|
@@ -1251,7 +904,7 @@ function morphArray(source, fn, options) {
|
|
|
1251
904
|
// We need to move entries in the Map.
|
|
1252
905
|
const entries = Array.from(itemEffects.entries()).sort((a, b) => a[0] - b[0]);
|
|
1253
906
|
// Remove entries that will be shifted
|
|
1254
|
-
for (const [idx,
|
|
907
|
+
for (const [idx, _entry] of entries) {
|
|
1255
908
|
if (idx >= diff.indexA + diff.sliceA.length) {
|
|
1256
909
|
itemEffects.delete(idx);
|
|
1257
910
|
}
|
|
@@ -1283,7 +936,7 @@ function morphArray(source, fn, options) {
|
|
|
1283
936
|
}
|
|
1284
937
|
input = newInput;
|
|
1285
938
|
});
|
|
1286
|
-
return
|
|
939
|
+
return link(proxy, (reason) => {
|
|
1287
940
|
stopMain(reason);
|
|
1288
941
|
for (const entry of itemEffects.values())
|
|
1289
942
|
entry.stop(reason);
|
|
@@ -1305,7 +958,7 @@ function morphMap(source, fn, options) {
|
|
|
1305
958
|
if (!isReactive(source) && options?.pure === true) {
|
|
1306
959
|
const res = new Map();
|
|
1307
960
|
for (const [k, v] of source)
|
|
1308
|
-
res.set(k, fn(v));
|
|
961
|
+
res.set(k, fn(v, k));
|
|
1309
962
|
return res;
|
|
1310
963
|
}
|
|
1311
964
|
let track;
|
|
@@ -1322,15 +975,15 @@ function morphMap(source, fn, options) {
|
|
|
1322
975
|
function computeItem(key, val) {
|
|
1323
976
|
const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(val));
|
|
1324
977
|
if (isPure) {
|
|
1325
|
-
cache.set(key, track(() => fn(val)));
|
|
978
|
+
cache.set(key, track(() => fn(val, key)));
|
|
1326
979
|
}
|
|
1327
980
|
else {
|
|
1328
|
-
const stop = track(() => effect.opaque(() => {
|
|
1329
|
-
cache.set(key, fn(source.get(key)));
|
|
981
|
+
const stop = track(() => effect.named(`morph:${fn.name}:${key}`).opaque((access) => {
|
|
982
|
+
cache.set(key, fn(source.get(key), key, access));
|
|
1330
983
|
return (reason) => {
|
|
1331
984
|
cache.delete(key);
|
|
1332
985
|
touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
|
|
1333
|
-
stop({ type: 'invalidate', cause: reason });
|
|
986
|
+
stop?.({ type: 'invalidate', cause: reason });
|
|
1334
987
|
};
|
|
1335
988
|
}));
|
|
1336
989
|
itemEffects.set(key, stop);
|
|
@@ -1374,7 +1027,7 @@ function morphMap(source, fn, options) {
|
|
|
1374
1027
|
},
|
|
1375
1028
|
});
|
|
1376
1029
|
let stateSnapshot = getState(source);
|
|
1377
|
-
const stopMain = effect.named(
|
|
1030
|
+
const stopMain = effect.named(`morph:${fn.name}`)(({ ascend }) => {
|
|
1378
1031
|
track = ascend;
|
|
1379
1032
|
dependant(source, keysOf);
|
|
1380
1033
|
while ('evolution' in stateSnapshot) {
|
|
@@ -1390,7 +1043,7 @@ function morphMap(source, fn, options) {
|
|
|
1390
1043
|
}
|
|
1391
1044
|
}
|
|
1392
1045
|
});
|
|
1393
|
-
return
|
|
1046
|
+
return link(proxy, (reason) => {
|
|
1394
1047
|
stopMain(reason);
|
|
1395
1048
|
for (const stop of itemEffects.values())
|
|
1396
1049
|
stop(reason);
|
|
@@ -1412,7 +1065,7 @@ function morphRecord(source, fn, options) {
|
|
|
1412
1065
|
if (!isReactive(source) && options?.pure === true) {
|
|
1413
1066
|
const res = {};
|
|
1414
1067
|
for (const k of Object.keys(source))
|
|
1415
|
-
res[k] = fn(source[k]);
|
|
1068
|
+
res[k] = fn(source[k], k);
|
|
1416
1069
|
return res;
|
|
1417
1070
|
}
|
|
1418
1071
|
let track;
|
|
@@ -1428,15 +1081,15 @@ function morphRecord(source, fn, options) {
|
|
|
1428
1081
|
function computeItem(key, val) {
|
|
1429
1082
|
const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(val));
|
|
1430
1083
|
if (isPure) {
|
|
1431
|
-
cache[key] = track(() => fn(val));
|
|
1084
|
+
cache[key] = track(() => fn(val, key));
|
|
1432
1085
|
}
|
|
1433
1086
|
else {
|
|
1434
|
-
const stop = track(() => effect.opaque(() => {
|
|
1435
|
-
cache[key] = fn(source[key]);
|
|
1087
|
+
const stop = track(() => effect.named(`morph:${fn.name}:${key}`).opaque((access) => {
|
|
1088
|
+
cache[key] = fn(source[key], key, access);
|
|
1436
1089
|
return (reason) => {
|
|
1437
1090
|
delete cache[key];
|
|
1438
1091
|
touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
|
|
1439
|
-
stop({ type: 'invalidate', cause: reason });
|
|
1092
|
+
stop?.({ type: 'invalidate', cause: reason });
|
|
1440
1093
|
};
|
|
1441
1094
|
}));
|
|
1442
1095
|
itemEffects.set(key, stop);
|
|
@@ -1463,7 +1116,7 @@ function morphRecord(source, fn, options) {
|
|
|
1463
1116
|
},
|
|
1464
1117
|
});
|
|
1465
1118
|
let stateSnapshot = getState(source);
|
|
1466
|
-
const stopMain = effect.named(
|
|
1119
|
+
const stopMain = effect.named(`morph:${fn.name}`)(({ ascend }) => {
|
|
1467
1120
|
track = ascend;
|
|
1468
1121
|
// Track only structural changes on source
|
|
1469
1122
|
dependant(source, keysOf);
|
|
@@ -1480,7 +1133,7 @@ function morphRecord(source, fn, options) {
|
|
|
1480
1133
|
}
|
|
1481
1134
|
}
|
|
1482
1135
|
});
|
|
1483
|
-
return
|
|
1136
|
+
return link(proxy, (reason) => {
|
|
1484
1137
|
stopMain(reason);
|
|
1485
1138
|
for (const stop of itemEffects.values())
|
|
1486
1139
|
stop(reason);
|
|
@@ -1539,7 +1192,7 @@ function deepWatch(target, callback, { immediate = false } = {}) {
|
|
|
1539
1192
|
const wrappedCallback = markWithRoot((() => callback(target)), callback);
|
|
1540
1193
|
registerDeepWatcher();
|
|
1541
1194
|
// Use the existing effect system to register dependencies
|
|
1542
|
-
return effect(() => {
|
|
1195
|
+
return effect.named('deepWatch')(() => {
|
|
1543
1196
|
// Mark the target object as having deep watchers
|
|
1544
1197
|
objectsWithDeepWatchers.add(target);
|
|
1545
1198
|
// Track which objects this effect is watching for cleanup
|
|
@@ -1575,35 +1228,24 @@ function deepWatch(target, callback, { immediate = false } = {}) {
|
|
|
1575
1228
|
}
|
|
1576
1229
|
}
|
|
1577
1230
|
// Also handle array indices and length
|
|
1578
|
-
//
|
|
1579
|
-
if (
|
|
1580
|
-
// Access
|
|
1581
|
-
const length = obj.length;
|
|
1582
|
-
// Access all current array elements to register dependencies
|
|
1583
|
-
for (let i = 0; i < length; i++) {
|
|
1584
|
-
// Access the array element to register dependency
|
|
1585
|
-
const value = obj[i];
|
|
1586
|
-
// Make the value reactive if it's an object
|
|
1587
|
-
const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
|
|
1588
|
-
traverseAndTrack(reactiveValue, depth + 1);
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
// Handle Set values (deep watch values only, not keys since Sets don't have separate keys)
|
|
1592
|
-
else if (obj instanceof Set) {
|
|
1593
|
-
// Access all Set values to register dependencies
|
|
1231
|
+
// Handle arrays and collections using iterators to ensure proxy tracking is triggered
|
|
1232
|
+
if (typeof obj[Symbol.iterator] === 'function') {
|
|
1233
|
+
// Access the iterator to track additions/removals/collection changes
|
|
1594
1234
|
for (const value of obj) {
|
|
1595
1235
|
// Make the value reactive if it's an object
|
|
1596
1236
|
const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
|
|
1597
1237
|
traverseAndTrack(reactiveValue, depth + 1);
|
|
1598
1238
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1239
|
+
// Explicitly depend on length so array mutations changing count trigger re-evaluation
|
|
1240
|
+
if ('length' in obj) {
|
|
1241
|
+
dependant(obj, 'length');
|
|
1242
|
+
}
|
|
1243
|
+
// For Maps, also ensure we track values explicitly if the iterator yields entries
|
|
1244
|
+
if (obj instanceof Map) {
|
|
1245
|
+
for (const value of obj.values()) {
|
|
1246
|
+
const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
|
|
1247
|
+
traverseAndTrack(reactiveValue, depth + 1);
|
|
1248
|
+
}
|
|
1607
1249
|
}
|
|
1608
1250
|
}
|
|
1609
1251
|
// Note: WeakSet and WeakMap cannot be iterated, so we can't deep watch their contents
|
|
@@ -1640,12 +1282,217 @@ function deepWatch(target, callback, { immediate = false } = {}) {
|
|
|
1640
1282
|
objectsWithDeepWatchers.delete(obj);
|
|
1641
1283
|
}
|
|
1642
1284
|
}
|
|
1643
|
-
// Clean up the tracking data
|
|
1644
|
-
effectToDeepWatchedObjects.delete(wrappedCallback);
|
|
1285
|
+
// Clean up the tracking data
|
|
1286
|
+
effectToDeepWatchedObjects.delete(wrappedCallback);
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
const memoizedRegistry = new WeakMap();
|
|
1293
|
+
const wrapperRegistry = new WeakMap();
|
|
1294
|
+
function getBranch(tree, key) {
|
|
1295
|
+
tree.branches ?? (tree.branches = new WeakMap());
|
|
1296
|
+
let branch = tree.branches.get(key);
|
|
1297
|
+
if (!branch) {
|
|
1298
|
+
branch = {};
|
|
1299
|
+
tree.branches.set(key, branch);
|
|
1300
|
+
}
|
|
1301
|
+
return branch;
|
|
1302
|
+
}
|
|
1303
|
+
function memoizeFunction(fn, opts) {
|
|
1304
|
+
const fnRoot = getRoot(fn);
|
|
1305
|
+
const existing = memoizedRegistry.get(fnRoot);
|
|
1306
|
+
if (existing)
|
|
1307
|
+
return existing;
|
|
1308
|
+
const cacheRoot = {};
|
|
1309
|
+
const memoized = markWithRoot(function memoized(...args) {
|
|
1310
|
+
if (args.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg)))) {
|
|
1311
|
+
if (opts?.lenient)
|
|
1312
|
+
return fn.apply(this, args);
|
|
1313
|
+
throw new Error('memoize expects non-null object arguments');
|
|
1314
|
+
}
|
|
1315
|
+
let node = cacheRoot;
|
|
1316
|
+
// Note: decorators add `this` as first argument
|
|
1317
|
+
for (const arg of args) {
|
|
1318
|
+
node = getBranch(node, arg);
|
|
1319
|
+
}
|
|
1320
|
+
dependant(node, 'memoize');
|
|
1321
|
+
if ('result' in node) {
|
|
1322
|
+
if (options.onMemoizationDiscrepancy) {
|
|
1323
|
+
const wasVerification = options.isVerificationRun;
|
|
1324
|
+
options.isVerificationRun = true;
|
|
1325
|
+
try {
|
|
1326
|
+
const fresh = untracked(() => fn.apply(this, args));
|
|
1327
|
+
if (!deepCompare(node.result, fresh)) {
|
|
1328
|
+
optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'calculation');
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
finally {
|
|
1332
|
+
options.isVerificationRun = wasVerification;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
return node.result;
|
|
1336
|
+
}
|
|
1337
|
+
// Create memoize internal effect to track dependencies and invalidate cache
|
|
1338
|
+
// Use untracked to prevent the effect creation from being affected by parent effects
|
|
1339
|
+
node.cleanup = root(() => effect.named('memoize')(() => {
|
|
1340
|
+
// Execute the function and track its dependencies
|
|
1341
|
+
// The function execution will automatically track dependencies on reactive objects
|
|
1342
|
+
node.result = fn.apply(this, args);
|
|
1343
|
+
return (reason) => {
|
|
1344
|
+
// When dependencies change, clear the cache and notify consumers
|
|
1345
|
+
delete node.result;
|
|
1346
|
+
touched1(node, { type: 'invalidate', prop: args }, 'memoize');
|
|
1347
|
+
// Lazy memoization: stop the effect so it doesn't re-run immediately.
|
|
1348
|
+
// It will be re-created on next access.
|
|
1349
|
+
if (node.cleanup) {
|
|
1350
|
+
node.cleanup({ type: 'invalidate', cause: reason });
|
|
1351
|
+
node.cleanup = undefined;
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
}, { opaque: true }));
|
|
1355
|
+
if (options.onMemoizationDiscrepancy) {
|
|
1356
|
+
const wasVerification = options.isVerificationRun;
|
|
1357
|
+
options.isVerificationRun = true;
|
|
1358
|
+
try {
|
|
1359
|
+
const fresh = untracked(() => fn.apply(this, args));
|
|
1360
|
+
if (!deepCompare(node.result, fresh)) {
|
|
1361
|
+
optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'comparison');
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
finally {
|
|
1365
|
+
options.isVerificationRun = wasVerification;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return node.result;
|
|
1369
|
+
}, fn);
|
|
1370
|
+
memoizedRegistry.set(fnRoot, memoized);
|
|
1371
|
+
memoizedRegistry.set(memoized, memoized);
|
|
1372
|
+
return memoized;
|
|
1373
|
+
}
|
|
1374
|
+
function memoizeObject(target, opts) {
|
|
1375
|
+
const existing = memoizedRegistry.get(target);
|
|
1376
|
+
if (existing)
|
|
1377
|
+
return existing;
|
|
1378
|
+
const proxy = new Proxy(target, {
|
|
1379
|
+
get(source, prop, receiver) {
|
|
1380
|
+
// 1. Walk prototype chain to find descriptor
|
|
1381
|
+
let current = source;
|
|
1382
|
+
let desc;
|
|
1383
|
+
while (current) {
|
|
1384
|
+
desc = Object.getOwnPropertyDescriptor(current, prop);
|
|
1385
|
+
if (desc)
|
|
1386
|
+
break;
|
|
1387
|
+
current = Object.getPrototypeOf(current);
|
|
1388
|
+
}
|
|
1389
|
+
if (!desc)
|
|
1390
|
+
return Reflect.get(source, prop, receiver);
|
|
1391
|
+
// 2. If getter, memoize
|
|
1392
|
+
if (desc.get) {
|
|
1393
|
+
const originalGetter = desc.get;
|
|
1394
|
+
let wrapper = wrapperRegistry.get(originalGetter);
|
|
1395
|
+
if (!wrapper) {
|
|
1396
|
+
wrapper = markWithRoot(named(`${String(source?.constructor?.name ?? 'Object')}.${String(prop)}`, (that) => {
|
|
1397
|
+
return originalGetter.call(that);
|
|
1398
|
+
}), {
|
|
1399
|
+
propertyKey: prop,
|
|
1400
|
+
});
|
|
1401
|
+
const origRoot = originalGetter[rootFunctionSymbol];
|
|
1402
|
+
if (origRoot)
|
|
1403
|
+
wrapper[rootFunctionSymbol] = origRoot;
|
|
1404
|
+
wrapperRegistry.set(originalGetter, wrapper);
|
|
1405
|
+
}
|
|
1406
|
+
const memoized = memoizeFunction(wrapper, opts);
|
|
1407
|
+
return memoized(receiver);
|
|
1645
1408
|
}
|
|
1646
|
-
|
|
1409
|
+
// 3. Otherwise forward
|
|
1410
|
+
return Reflect.get(source, prop, receiver);
|
|
1411
|
+
},
|
|
1412
|
+
// Forward set to the target (source) to ensure it acts as the receiver for reactivity notifications
|
|
1413
|
+
set(source, prop, value, _receiver) {
|
|
1414
|
+
// By strictly passing `source` as receiver, we ensure that if `source` is a reactive proxy,
|
|
1415
|
+
// it recognizes itself and triggers change notifications.
|
|
1416
|
+
return Reflect.set(source, prop, value, source);
|
|
1417
|
+
},
|
|
1418
|
+
});
|
|
1419
|
+
proxyToObject.set(proxy, target);
|
|
1420
|
+
memoizedRegistry.set(target, proxy);
|
|
1421
|
+
return proxy;
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Decorator and function wrapper for memoizing computed values based on reactive dependencies.
|
|
1425
|
+
*
|
|
1426
|
+
* When used as a decorator on getters or methods, it caches the result and automatically
|
|
1427
|
+
* invalidates the cache when reactive dependencies change.
|
|
1428
|
+
*
|
|
1429
|
+
* When used as a function wrapper, it memoizes based on object arguments (WeakMap-based cache).
|
|
1430
|
+
*
|
|
1431
|
+
* @example
|
|
1432
|
+
* ```typescript
|
|
1433
|
+
* class User {
|
|
1434
|
+
* @memoize
|
|
1435
|
+
* get fullName() {
|
|
1436
|
+
* return `${this.firstName} ${this.lastName}`
|
|
1437
|
+
* }
|
|
1438
|
+
* }
|
|
1439
|
+
*
|
|
1440
|
+
* // Or as a function wrapper
|
|
1441
|
+
* const expensive = memoize((obj: SomeObject) => {
|
|
1442
|
+
* return heavyComputation(obj)
|
|
1443
|
+
* })
|
|
1444
|
+
* ```
|
|
1445
|
+
*/
|
|
1446
|
+
function makeMemoizeDecorator(memoizeOpts) {
|
|
1447
|
+
return decorator({
|
|
1448
|
+
getter(original, target, propertyKey) {
|
|
1449
|
+
return function () {
|
|
1450
|
+
let wrapper = wrapperRegistry.get(original);
|
|
1451
|
+
if (!wrapper) {
|
|
1452
|
+
wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`, (that) => {
|
|
1453
|
+
return original.call(that);
|
|
1454
|
+
}), {
|
|
1455
|
+
method: original,
|
|
1456
|
+
propertyKey,
|
|
1457
|
+
});
|
|
1458
|
+
const origRoot = original[rootFunctionSymbol];
|
|
1459
|
+
if (origRoot)
|
|
1460
|
+
wrapper[rootFunctionSymbol] = origRoot;
|
|
1461
|
+
wrapperRegistry.set(original, wrapper);
|
|
1462
|
+
}
|
|
1463
|
+
const memoized = memoizeFunction(wrapper, memoizeOpts);
|
|
1464
|
+
return memoized(this);
|
|
1465
|
+
};
|
|
1466
|
+
},
|
|
1467
|
+
method(original, target, name) {
|
|
1468
|
+
return function (...args) {
|
|
1469
|
+
let wrapper = wrapperRegistry.get(original);
|
|
1470
|
+
if (!wrapper) {
|
|
1471
|
+
wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`, (that, ...args) => {
|
|
1472
|
+
return original.call(that, ...args);
|
|
1473
|
+
}), {
|
|
1474
|
+
method: original,
|
|
1475
|
+
propertyKey: name,
|
|
1476
|
+
});
|
|
1477
|
+
const origRoot = original[rootFunctionSymbol];
|
|
1478
|
+
if (origRoot)
|
|
1479
|
+
wrapper[rootFunctionSymbol] = origRoot;
|
|
1480
|
+
wrapperRegistry.set(original, wrapper);
|
|
1481
|
+
}
|
|
1482
|
+
const memoized = memoizeFunction(wrapper, memoizeOpts);
|
|
1483
|
+
return memoized(this, ...args);
|
|
1484
|
+
};
|
|
1485
|
+
},
|
|
1486
|
+
default: (target) => typeof target === 'object'
|
|
1487
|
+
? memoizeObject(target, memoizeOpts)
|
|
1488
|
+
: memoizeFunction(target, memoizeOpts),
|
|
1647
1489
|
});
|
|
1648
1490
|
}
|
|
1491
|
+
const memoize = flavored(makeMemoizeDecorator(), {
|
|
1492
|
+
get lenient() {
|
|
1493
|
+
return makeMemoizeDecorator({ lenient: true });
|
|
1494
|
+
},
|
|
1495
|
+
});
|
|
1649
1496
|
|
|
1650
1497
|
/**
|
|
1651
1498
|
* Organizes a source object's properties into a target object using a callback function.
|
|
@@ -1721,7 +1568,7 @@ function organized(source, apply, baseTarget = {}) {
|
|
|
1721
1568
|
});
|
|
1722
1569
|
return apply(accessBase, target);
|
|
1723
1570
|
});
|
|
1724
|
-
return
|
|
1571
|
+
return link(target, (reason) => stop(reason));
|
|
1725
1572
|
}
|
|
1726
1573
|
/**
|
|
1727
1574
|
* Organizes a property on a target object
|
|
@@ -1764,7 +1611,7 @@ changed, options = {}) {
|
|
|
1764
1611
|
function watchObject(value, changed, { immediate = false, deep = false } = {}) {
|
|
1765
1612
|
if (deep)
|
|
1766
1613
|
return deepWatch(value, changed, { immediate });
|
|
1767
|
-
return effect(
|
|
1614
|
+
return effect.named('watch:object')(() => {
|
|
1768
1615
|
dependant(value);
|
|
1769
1616
|
if (immediate)
|
|
1770
1617
|
changed(value);
|
|
@@ -1774,7 +1621,7 @@ function watchObject(value, changed, { immediate = false, deep = false } = {}) {
|
|
|
1774
1621
|
function watchCallBack(value, changed, { immediate = false, deep = false } = {}) {
|
|
1775
1622
|
let oldValue = unsetYet;
|
|
1776
1623
|
let deepCleanup;
|
|
1777
|
-
const cbCleanup = effect(markWithRoot(
|
|
1624
|
+
const cbCleanup = effect.named('watch:callback')(markWithRoot((access) => {
|
|
1778
1625
|
const newValue = value(access);
|
|
1779
1626
|
if (oldValue !== newValue) {
|
|
1780
1627
|
const old = oldValue;
|
|
@@ -1792,12 +1639,10 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
|
|
|
1792
1639
|
deepCleanup = deepWatch(newValue, (value) => changed(value, value));
|
|
1793
1640
|
}
|
|
1794
1641
|
}, value));
|
|
1795
|
-
return
|
|
1642
|
+
return (() => {
|
|
1796
1643
|
cbCleanup();
|
|
1797
1644
|
if (deepCleanup)
|
|
1798
1645
|
deepCleanup();
|
|
1799
|
-
}, {
|
|
1800
|
-
[stopped]: { get: () => cbCleanup[stopped] },
|
|
1801
1646
|
});
|
|
1802
1647
|
}
|
|
1803
1648
|
//#endregion
|
|
@@ -1812,7 +1657,7 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
|
|
|
1812
1657
|
function when(predicate, timeout) {
|
|
1813
1658
|
return new Promise((resolve, reject) => {
|
|
1814
1659
|
let timer;
|
|
1815
|
-
const stop = effect(
|
|
1660
|
+
const stop = effect.named('watch:when')((access) => {
|
|
1816
1661
|
try {
|
|
1817
1662
|
const value = predicate(access);
|
|
1818
1663
|
if (value) {
|
|
@@ -1849,7 +1694,7 @@ function shallowNonReactive(obj) {
|
|
|
1849
1694
|
obj = unwrap(obj);
|
|
1850
1695
|
if (isNonReactive(obj))
|
|
1851
1696
|
return obj;
|
|
1852
|
-
|
|
1697
|
+
obj[unreactiveProperties] = true;
|
|
1853
1698
|
return obj;
|
|
1854
1699
|
}
|
|
1855
1700
|
function unreactiveApplication(arg1, ...args) {
|
|
@@ -1857,13 +1702,19 @@ function unreactiveApplication(arg1, ...args) {
|
|
|
1857
1702
|
? shallowNonReactive(arg1)
|
|
1858
1703
|
: ((original) => {
|
|
1859
1704
|
// Copy the parent's unreactive properties if they exist
|
|
1860
|
-
const
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1705
|
+
const parentMarker = original.prototype[unreactiveProperties];
|
|
1706
|
+
// If parent is fully unreactive, child is too
|
|
1707
|
+
if (parentMarker === true) {
|
|
1708
|
+
original.prototype[unreactiveProperties] = true;
|
|
1709
|
+
}
|
|
1710
|
+
else {
|
|
1711
|
+
const set = new Set(parentMarker || []);
|
|
1712
|
+
// Add all arguments (including the first one)
|
|
1713
|
+
set.add(arg1);
|
|
1714
|
+
for (const arg of args)
|
|
1715
|
+
set.add(arg);
|
|
1716
|
+
addUnreactiveProps(original.prototype, set);
|
|
1717
|
+
}
|
|
1867
1718
|
return original; // Return the class
|
|
1868
1719
|
});
|
|
1869
1720
|
}
|
|
@@ -1873,11 +1724,26 @@ function unreactiveApplication(arg1, ...args) {
|
|
|
1873
1724
|
*/
|
|
1874
1725
|
const unreactive = decorator({
|
|
1875
1726
|
class(original) {
|
|
1876
|
-
|
|
1877
|
-
nonReactiveClass(original);
|
|
1727
|
+
original.prototype[unreactiveProperties] = true;
|
|
1878
1728
|
},
|
|
1879
1729
|
default: unreactiveApplication,
|
|
1880
1730
|
});
|
|
1731
|
+
//#endregion
|
|
1732
|
+
//#region resource
|
|
1733
|
+
function lazyInit(resource, load) {
|
|
1734
|
+
const creation = effectHistory.active;
|
|
1735
|
+
let fresh = true;
|
|
1736
|
+
return new Proxy(resource, {
|
|
1737
|
+
[Symbol.toStringTag]: 'LazyInit',
|
|
1738
|
+
get(target, prop) {
|
|
1739
|
+
if (fresh) {
|
|
1740
|
+
captured(creation, load)();
|
|
1741
|
+
fresh = false;
|
|
1742
|
+
}
|
|
1743
|
+
return target[prop];
|
|
1744
|
+
},
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1881
1747
|
/**
|
|
1882
1748
|
* Creates a reactive resource that automatically tracks async state.
|
|
1883
1749
|
* @param fetcher - Async function that returns the value. Reactive dependencies are tracked.
|
|
@@ -1885,521 +1751,59 @@ const unreactive = decorator({
|
|
|
1885
1751
|
* @returns Reactive Resource object with value, loading, error, latest properties
|
|
1886
1752
|
*/
|
|
1887
1753
|
function resource(fetcher, options = {}) {
|
|
1888
|
-
const
|
|
1754
|
+
const resource = reactive({
|
|
1889
1755
|
value: options.initialValue,
|
|
1890
1756
|
loading: true,
|
|
1891
1757
|
error: undefined,
|
|
1892
1758
|
latest: options.initialValue,
|
|
1893
|
-
reload
|
|
1759
|
+
reload() {
|
|
1894
1760
|
reloadSignal.value++;
|
|
1895
1761
|
},
|
|
1896
1762
|
});
|
|
1897
1763
|
const reloadSignal = reactive({ value: 0 });
|
|
1764
|
+
// Solve race conditions: make sure a new fast request is not overloaded by a slow old one
|
|
1898
1765
|
let counter = 0;
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
result
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
state.latest = result;
|
|
1924
|
-
state.loading = false;
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
catch (err) {
|
|
1928
|
-
state.error = err;
|
|
1929
|
-
state.loading = false;
|
|
1930
|
-
}
|
|
1931
|
-
});
|
|
1932
|
-
state.stop = stop;
|
|
1933
|
-
return state;
|
|
1934
|
-
}
|
|
1935
|
-
//#endregion
|
|
1936
|
-
|
|
1937
|
-
// Helper to work around TypeScript limitation: base class expressions cannot reference class type parameters
|
|
1938
|
-
function getRegisterBase() {
|
|
1939
|
-
class RegisterBase extends Indexable(ArrayReadForward, {
|
|
1940
|
-
get(index) {
|
|
1941
|
-
return this[getAt](index);
|
|
1942
|
-
},
|
|
1943
|
-
set(index, value) {
|
|
1944
|
-
this[setAt](index, value);
|
|
1945
|
-
},
|
|
1946
|
-
getLength() {
|
|
1947
|
-
return this.length;
|
|
1948
|
-
},
|
|
1949
|
-
setLength(value) {
|
|
1950
|
-
this.length = value;
|
|
1951
|
-
},
|
|
1952
|
-
}) {
|
|
1953
|
-
toArray() {
|
|
1954
|
-
return Array.from(this);
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
return RegisterBase;
|
|
1958
|
-
}
|
|
1959
|
-
let RegisterClass = (() => {
|
|
1960
|
-
var _RegisterClass_instances, _RegisterClass_keyFn, _RegisterClass_keys, _RegisterClass_values, _RegisterClass_usage, _RegisterClass_valueInfo, _RegisterClass_keyEffects, _RegisterClass_ascend, _RegisterClass_events, _RegisterClass_rekeyValue;
|
|
1961
|
-
let _classDecorators = [unreactive];
|
|
1962
|
-
let _classDescriptor;
|
|
1963
|
-
let _classExtraInitializers = [];
|
|
1964
|
-
let _classThis;
|
|
1965
|
-
let _classSuper = getRegisterBase();
|
|
1966
|
-
_classThis = class extends _classSuper {
|
|
1967
|
-
get [(_RegisterClass_keyFn = new WeakMap(), _RegisterClass_keys = new WeakMap(), _RegisterClass_values = new WeakMap(), _RegisterClass_usage = new WeakMap(), _RegisterClass_valueInfo = new WeakMap(), _RegisterClass_keyEffects = new WeakMap(), _RegisterClass_ascend = new WeakMap(), _RegisterClass_events = new WeakMap(), _RegisterClass_instances = new WeakSet(), forwardArray)]() {
|
|
1968
|
-
return this.toArray();
|
|
1969
|
-
}
|
|
1970
|
-
on(eventOrEvents, cb) {
|
|
1971
|
-
// @ts-expect-error Delegate to Eventful
|
|
1972
|
-
return __classPrivateFieldGet(this, _RegisterClass_events, "f").on(eventOrEvents, cb);
|
|
1973
|
-
}
|
|
1974
|
-
off(eventOrEvents, cb) {
|
|
1975
|
-
// @ts-expect-error Delegate to Eventful
|
|
1976
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").off(eventOrEvents, cb);
|
|
1977
|
-
}
|
|
1978
|
-
/**
|
|
1979
|
-
* Register a global hook that receives all events
|
|
1980
|
-
*/
|
|
1981
|
-
hook(cb) {
|
|
1982
|
-
return __classPrivateFieldGet(this, _RegisterClass_events, "f").hook(cb);
|
|
1983
|
-
}
|
|
1984
|
-
constructor(keyFn, initial) {
|
|
1985
|
-
super();
|
|
1986
|
-
_RegisterClass_instances.add(this);
|
|
1987
|
-
_RegisterClass_keyFn.set(this, void 0);
|
|
1988
|
-
_RegisterClass_keys.set(this, void 0);
|
|
1989
|
-
_RegisterClass_values.set(this, void 0);
|
|
1990
|
-
_RegisterClass_usage.set(this, new Map());
|
|
1991
|
-
_RegisterClass_valueInfo.set(this, new Map());
|
|
1992
|
-
_RegisterClass_keyEffects.set(this, new Set());
|
|
1993
|
-
_RegisterClass_ascend.set(this, void 0);
|
|
1994
|
-
_RegisterClass_events.set(this, new Eventful()
|
|
1995
|
-
/**
|
|
1996
|
-
* Register event listeners for CRUD operations
|
|
1997
|
-
*/
|
|
1998
|
-
);
|
|
1999
|
-
/* Moved below initialization */
|
|
2000
|
-
let ascendGet;
|
|
2001
|
-
effect(({ ascend }) => {
|
|
2002
|
-
ascendGet = ascend;
|
|
2003
|
-
});
|
|
2004
|
-
__classPrivateFieldSet(this, _RegisterClass_ascend, ascendGet, "f");
|
|
2005
|
-
if (typeof keyFn !== 'function')
|
|
2006
|
-
throw new Error('Register requires a key function');
|
|
2007
|
-
__classPrivateFieldSet(this, _RegisterClass_keyFn, keyFn, "f");
|
|
2008
|
-
__classPrivateFieldSet(this, _RegisterClass_keys, reactive([]), "f");
|
|
2009
|
-
__classPrivateFieldSet(this, _RegisterClass_values, reactive(new Map()), "f");
|
|
2010
|
-
if (initial)
|
|
2011
|
-
this.push(...initial);
|
|
2012
|
-
}
|
|
2013
|
-
ensureKey(value) {
|
|
2014
|
-
let info = __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").get(value);
|
|
2015
|
-
if (info)
|
|
2016
|
-
return info.key;
|
|
2017
|
-
info = { key: undefined };
|
|
2018
|
-
__classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").set(value, info);
|
|
2019
|
-
__classPrivateFieldGet(this, _RegisterClass_ascend, "f").call(this, () => {
|
|
2020
|
-
const stop = effect(({ reaction }) => {
|
|
2021
|
-
const nextKey = __classPrivateFieldGet(this, _RegisterClass_keyFn, "f").call(this, value);
|
|
2022
|
-
this.assertValidKey(nextKey);
|
|
2023
|
-
const previousKey = info.key;
|
|
2024
|
-
if (reaction && previousKey !== undefined && !Object.is(nextKey, previousKey))
|
|
2025
|
-
__classPrivateFieldGet(this, _RegisterClass_instances, "m", _RegisterClass_rekeyValue).call(this, value, previousKey, nextKey);
|
|
2026
|
-
info.key = nextKey;
|
|
2027
|
-
});
|
|
2028
|
-
info.stop = stop;
|
|
2029
|
-
__classPrivateFieldGet(this, _RegisterClass_keyEffects, "f").add(stop);
|
|
2030
|
-
});
|
|
2031
|
-
if (info.key === undefined)
|
|
2032
|
-
throw new Error('Register key function must return a property key');
|
|
2033
|
-
return info.key;
|
|
2034
|
-
}
|
|
2035
|
-
assertValidKey(key) {
|
|
2036
|
-
const type = typeof key;
|
|
2037
|
-
if (type !== 'string' && type !== 'number' && type !== 'symbol')
|
|
2038
|
-
throw new Error('Register key function must return a property key');
|
|
2039
|
-
}
|
|
2040
|
-
setKeyValue(key, value, index) {
|
|
2041
|
-
const existing = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2042
|
-
if (existing !== undefined && existing !== value) {
|
|
2043
|
-
this.cleanupValue(existing);
|
|
2044
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").set(key, value);
|
|
2045
|
-
if (index !== undefined) {
|
|
2046
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").emit('update', existing, value, key, index);
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
else {
|
|
2050
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").set(key, value);
|
|
2051
|
-
}
|
|
2052
|
-
}
|
|
2053
|
-
cleanupValue(value) {
|
|
2054
|
-
const info = __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").get(value);
|
|
2055
|
-
if (!info)
|
|
2056
|
-
return;
|
|
2057
|
-
const stop = info.stop;
|
|
2058
|
-
if (stop) {
|
|
2059
|
-
info.stop = undefined;
|
|
2060
|
-
__classPrivateFieldGet(this, _RegisterClass_keyEffects, "f").delete(stop);
|
|
2061
|
-
stop();
|
|
2062
|
-
}
|
|
2063
|
-
__classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").delete(value);
|
|
2064
|
-
}
|
|
2065
|
-
disposeKeyEffects() {
|
|
2066
|
-
for (const value of Array.from(__classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").keys()))
|
|
2067
|
-
this.cleanupValue(value);
|
|
2068
|
-
__classPrivateFieldGet(this, _RegisterClass_keyEffects, "f").clear();
|
|
2069
|
-
}
|
|
2070
|
-
incrementUsage(key) {
|
|
2071
|
-
const count = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(key) ?? 0;
|
|
2072
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").set(key, count + 1);
|
|
2073
|
-
}
|
|
2074
|
-
decrementUsage(key, index) {
|
|
2075
|
-
const count = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(key);
|
|
2076
|
-
if (!count)
|
|
2077
|
-
return;
|
|
2078
|
-
if (count <= 1) {
|
|
2079
|
-
const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2080
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").delete(key);
|
|
2081
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").delete(key);
|
|
2082
|
-
if (value !== undefined) {
|
|
2083
|
-
this.cleanupValue(value);
|
|
2084
|
-
const idx = index ?? __classPrivateFieldGet(this, _RegisterClass_keys, "f").indexOf(key);
|
|
2085
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").emit('delete', value, key, idx);
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
else {
|
|
2089
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").set(key, count - 1);
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
normalizeIndex(index, allowEnd = false) {
|
|
2093
|
-
const length = this.length;
|
|
2094
|
-
let resolved = index;
|
|
2095
|
-
if (resolved < 0)
|
|
2096
|
-
resolved = Math.max(length + resolved, 0);
|
|
2097
|
-
if (resolved > length) {
|
|
2098
|
-
if (allowEnd)
|
|
2099
|
-
resolved = length;
|
|
2100
|
-
else
|
|
2101
|
-
throw new RangeError('Index out of bounds');
|
|
2102
|
-
}
|
|
2103
|
-
if (!allowEnd && resolved === length)
|
|
2104
|
-
throw new RangeError('Index out of bounds');
|
|
2105
|
-
return resolved;
|
|
2106
|
-
}
|
|
2107
|
-
assignAt(index, key, value) {
|
|
2108
|
-
const oldKey = __classPrivateFieldGet(this, _RegisterClass_keys, "f")[index];
|
|
2109
|
-
if (oldKey !== undefined && Object.is(oldKey, key)) {
|
|
2110
|
-
const oldValue = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2111
|
-
this.setKeyValue(key, value);
|
|
2112
|
-
if (oldValue !== undefined && oldValue !== value) {
|
|
2113
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").emit('update', oldValue, value, key, index);
|
|
2114
|
-
}
|
|
2115
|
-
return;
|
|
2116
|
-
}
|
|
2117
|
-
if (oldKey !== undefined)
|
|
2118
|
-
this.decrementUsage(oldKey);
|
|
2119
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f")[index] = key;
|
|
2120
|
-
this.incrementUsage(key);
|
|
2121
|
-
this.setKeyValue(key, value);
|
|
2122
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").emit('add', value, key, index);
|
|
2123
|
-
}
|
|
2124
|
-
insertKeyValue(index, key, value) {
|
|
2125
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(index, 0, key);
|
|
2126
|
-
this.incrementUsage(key);
|
|
2127
|
-
this.setKeyValue(key, value);
|
|
2128
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").emit('add', value, key, index);
|
|
2129
|
-
}
|
|
2130
|
-
rebuildFrom(values) {
|
|
2131
|
-
this.disposeKeyEffects();
|
|
2132
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(0, __classPrivateFieldGet(this, _RegisterClass_keys, "f").length);
|
|
2133
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").clear();
|
|
2134
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").clear();
|
|
2135
|
-
for (const value of values) {
|
|
2136
|
-
const key = this.ensureKey(value);
|
|
2137
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f").push(key);
|
|
2138
|
-
this.incrementUsage(key);
|
|
2139
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").set(key, value);
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
get length() {
|
|
2143
|
-
return __classPrivateFieldGet(this, _RegisterClass_keys, "f").length;
|
|
2144
|
-
}
|
|
2145
|
-
[(_RegisterClass_rekeyValue = function _RegisterClass_rekeyValue(value, oldKey, newKey) {
|
|
2146
|
-
if (Object.is(oldKey, newKey))
|
|
2147
|
-
return;
|
|
2148
|
-
const existingValue = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(newKey);
|
|
2149
|
-
if (existingValue !== undefined && existingValue !== value)
|
|
2150
|
-
throw new Error(`Register key collision for key ${String(newKey)}`);
|
|
2151
|
-
const count = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(oldKey);
|
|
2152
|
-
if (!count)
|
|
2153
|
-
return;
|
|
2154
|
-
const existingCount = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(newKey) ?? 0;
|
|
2155
|
-
this.setKeyValue(newKey, value);
|
|
2156
|
-
let index = -1;
|
|
2157
|
-
for (let i = 0; i < __classPrivateFieldGet(this, _RegisterClass_keys, "f").length; i++)
|
|
2158
|
-
if (Object.is(__classPrivateFieldGet(this, _RegisterClass_keys, "f")[i], oldKey)) {
|
|
2159
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f")[i] = newKey;
|
|
2160
|
-
if (index === -1)
|
|
2161
|
-
index = i;
|
|
2162
|
-
}
|
|
2163
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").set(newKey, existingCount + count);
|
|
2164
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").delete(oldKey);
|
|
2165
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").delete(oldKey);
|
|
2166
|
-
const updatedInfo = __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").get(value);
|
|
2167
|
-
if (updatedInfo)
|
|
2168
|
-
updatedInfo.key = newKey;
|
|
2169
|
-
if (index !== -1) {
|
|
2170
|
-
__classPrivateFieldGet(this, _RegisterClass_events, "f").emit('rekey', value, oldKey, newKey, index);
|
|
2171
|
-
}
|
|
2172
|
-
}, getAt)](index) {
|
|
2173
|
-
const key = __classPrivateFieldGet(this, _RegisterClass_keys, "f")[index];
|
|
2174
|
-
return key === undefined ? undefined : __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2175
|
-
}
|
|
2176
|
-
[setAt](index, value) {
|
|
2177
|
-
const key = this.ensureKey(value);
|
|
2178
|
-
if (index === this.length) {
|
|
2179
|
-
this.insertKeyValue(index, key, value);
|
|
2180
|
-
return;
|
|
2181
|
-
}
|
|
2182
|
-
const normalized = this.normalizeIndex(index);
|
|
2183
|
-
this.assignAt(normalized, key, value);
|
|
2184
|
-
}
|
|
2185
|
-
push(...items) {
|
|
2186
|
-
for (const item of items) {
|
|
2187
|
-
const key = this.ensureKey(item);
|
|
2188
|
-
this.insertKeyValue(this.length, key, item);
|
|
2189
|
-
}
|
|
2190
|
-
return this.length;
|
|
2191
|
-
}
|
|
2192
|
-
pop() {
|
|
2193
|
-
if (!this.length)
|
|
2194
|
-
return undefined;
|
|
2195
|
-
return this.removeAt(this.length - 1);
|
|
2196
|
-
}
|
|
2197
|
-
shift() {
|
|
2198
|
-
if (!this.length)
|
|
2199
|
-
return undefined;
|
|
2200
|
-
return this.removeAt(0);
|
|
2201
|
-
}
|
|
2202
|
-
unshift(...items) {
|
|
2203
|
-
let index = 0;
|
|
2204
|
-
for (const item of items) {
|
|
2205
|
-
const key = this.ensureKey(item);
|
|
2206
|
-
this.insertKeyValue(index++, key, item);
|
|
2207
|
-
}
|
|
2208
|
-
return this.length;
|
|
2209
|
-
}
|
|
2210
|
-
splice(start, deleteCount, ...items) {
|
|
2211
|
-
const normalizedStart = this.normalizeIndex(start, true);
|
|
2212
|
-
const maxDeletions = this.length - normalizedStart;
|
|
2213
|
-
const actualDelete = Math.min(deleteCount === undefined ? maxDeletions : Math.max(deleteCount, 0), maxDeletions);
|
|
2214
|
-
const keysToInsert = [];
|
|
2215
|
-
for (const item of items)
|
|
2216
|
-
keysToInsert.push(this.ensureKey(item));
|
|
2217
|
-
const removedKeys = __classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(normalizedStart, actualDelete, ...keysToInsert);
|
|
2218
|
-
const removedValues = [];
|
|
2219
|
-
for (let i = 0; i < removedKeys.length; i++) {
|
|
2220
|
-
const key = removedKeys[i];
|
|
2221
|
-
if (key === undefined)
|
|
2222
|
-
continue;
|
|
2223
|
-
const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2224
|
-
this.decrementUsage(key, normalizedStart + i);
|
|
2225
|
-
removedValues.push(value);
|
|
2226
|
-
}
|
|
2227
|
-
for (let i = 0; i < keysToInsert.length; i++) {
|
|
2228
|
-
const key = keysToInsert[i];
|
|
2229
|
-
const value = items[i];
|
|
2230
|
-
this.incrementUsage(key);
|
|
2231
|
-
this.setKeyValue(key, value);
|
|
2232
|
-
}
|
|
2233
|
-
return removedValues;
|
|
2234
|
-
}
|
|
2235
|
-
clear() {
|
|
2236
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f").length = 0;
|
|
2237
|
-
__classPrivateFieldGet(this, _RegisterClass_usage, "f").clear();
|
|
2238
|
-
__classPrivateFieldGet(this, _RegisterClass_values, "f").clear();
|
|
2239
|
-
this.disposeKeyEffects();
|
|
2240
|
-
}
|
|
2241
|
-
get(key) {
|
|
2242
|
-
return __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2243
|
-
}
|
|
2244
|
-
set(key, value) {
|
|
2245
|
-
if (__classPrivateFieldGet(this, _RegisterClass_values, "f").has(key))
|
|
2246
|
-
this.setKeyValue(key, value);
|
|
2247
|
-
}
|
|
2248
|
-
remove(key) {
|
|
2249
|
-
let index = this.indexOfKey(key);
|
|
2250
|
-
while (index !== -1) {
|
|
2251
|
-
this.removeAt(index);
|
|
2252
|
-
index = this.indexOfKey(key);
|
|
2253
|
-
}
|
|
2254
|
-
}
|
|
2255
|
-
removeAt(index) {
|
|
2256
|
-
const [key] = __classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(index, 1);
|
|
2257
|
-
if (key === undefined)
|
|
2258
|
-
return undefined;
|
|
2259
|
-
const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2260
|
-
this.decrementUsage(key, index);
|
|
2261
|
-
return value;
|
|
2262
|
-
}
|
|
2263
|
-
/**
|
|
2264
|
-
* Keep only the items for which the predicate returns true.
|
|
2265
|
-
* Items for which the predicate returns false are removed.
|
|
2266
|
-
*
|
|
2267
|
-
* The predicate is evaluated once per distinct key; duplicate keys
|
|
2268
|
-
* will follow the same keep/remove decision.
|
|
2269
|
-
*/
|
|
2270
|
-
keep(predicate) {
|
|
2271
|
-
const decisions = new Map();
|
|
2272
|
-
for (const [index, key] of __classPrivateFieldGet(this, _RegisterClass_keys, "f").entries()) {
|
|
2273
|
-
if (decisions.has(key)) {
|
|
2274
|
-
if (!decisions.get(key))
|
|
2275
|
-
this.removeAt(index);
|
|
2276
|
-
continue;
|
|
2277
|
-
}
|
|
2278
|
-
const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
|
|
2279
|
-
const shouldKeep = predicate(value);
|
|
2280
|
-
decisions.set(key, shouldKeep);
|
|
2281
|
-
if (!shouldKeep)
|
|
2282
|
-
this.removeAt(index);
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
hasKey(key) {
|
|
2286
|
-
return __classPrivateFieldGet(this, _RegisterClass_usage, "f").has(key);
|
|
2287
|
-
}
|
|
2288
|
-
indexOfKey(key) {
|
|
2289
|
-
return __classPrivateFieldGet(this, _RegisterClass_keys, "f").indexOf(key);
|
|
2290
|
-
}
|
|
2291
|
-
mapKeys() {
|
|
2292
|
-
return __classPrivateFieldGet(this, _RegisterClass_values, "f").keys();
|
|
2293
|
-
}
|
|
2294
|
-
update(...values) {
|
|
2295
|
-
for (const value of values) {
|
|
2296
|
-
const key = this.ensureKey(value);
|
|
2297
|
-
if (__classPrivateFieldGet(this, _RegisterClass_values, "f").has(key)) {
|
|
2298
|
-
const index = __classPrivateFieldGet(this, _RegisterClass_keys, "f").indexOf(key);
|
|
2299
|
-
this.setKeyValue(key, value, index);
|
|
1766
|
+
return lazyInit(resource, () => {
|
|
1767
|
+
link(resource, effect.named('watch:resource')((access) => {
|
|
1768
|
+
// Track reload signal to enable manual reloading
|
|
1769
|
+
void reloadSignal.value;
|
|
1770
|
+
const id = ++counter;
|
|
1771
|
+
resource.loading = true;
|
|
1772
|
+
resource.error = undefined;
|
|
1773
|
+
try {
|
|
1774
|
+
const result = fetcher(access);
|
|
1775
|
+
if (result instanceof Promise) {
|
|
1776
|
+
resource.promise = result
|
|
1777
|
+
.then((val) => {
|
|
1778
|
+
if (id === counter) {
|
|
1779
|
+
resource.value = val;
|
|
1780
|
+
resource.latest = val;
|
|
1781
|
+
resource.loading = false;
|
|
1782
|
+
}
|
|
1783
|
+
})
|
|
1784
|
+
.catch((err) => {
|
|
1785
|
+
if (id === counter) {
|
|
1786
|
+
resource.error = err;
|
|
1787
|
+
resource.loading = false;
|
|
1788
|
+
}
|
|
1789
|
+
});
|
|
2300
1790
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
if (__classPrivateFieldGet(this, _RegisterClass_values, "f").has(key))
|
|
2307
|
-
this.setKeyValue(key, value);
|
|
2308
|
-
else
|
|
2309
|
-
insert(value);
|
|
2310
|
-
}
|
|
2311
|
-
}
|
|
2312
|
-
entries() {
|
|
2313
|
-
const self = this;
|
|
2314
|
-
function* iterator() {
|
|
2315
|
-
for (let i = 0; i < __classPrivateFieldGet(self, _RegisterClass_keys, "f").length; i++) {
|
|
2316
|
-
const val = __classPrivateFieldGet(self, _RegisterClass_values, "f").get(__classPrivateFieldGet(self, _RegisterClass_keys, "f")[i]);
|
|
2317
|
-
if (val !== undefined)
|
|
2318
|
-
yield [i, val];
|
|
1791
|
+
else {
|
|
1792
|
+
resource.promise = Promise.resolve();
|
|
1793
|
+
resource.value = result;
|
|
1794
|
+
resource.latest = result;
|
|
1795
|
+
resource.loading = false;
|
|
2319
1796
|
}
|
|
2320
1797
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
function* iterator() {
|
|
2326
|
-
for (const key of __classPrivateFieldGet(self, _RegisterClass_keys, "f")) {
|
|
2327
|
-
const value = __classPrivateFieldGet(self, _RegisterClass_values, "f").get(key);
|
|
2328
|
-
if (value !== undefined)
|
|
2329
|
-
yield value;
|
|
2330
|
-
}
|
|
1798
|
+
catch (err) {
|
|
1799
|
+
resource.promise = Promise.reject(err);
|
|
1800
|
+
resource.error = err;
|
|
1801
|
+
resource.loading = false;
|
|
2331
1802
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
toString() {
|
|
2335
|
-
return `[Register length=${this.length}]`;
|
|
2336
|
-
}
|
|
2337
|
-
at(index) {
|
|
2338
|
-
const resolved = index < 0 ? this.length + index : index;
|
|
2339
|
-
if (resolved < 0 || resolved >= this.length)
|
|
2340
|
-
return undefined;
|
|
2341
|
-
return this[getAt](resolved);
|
|
2342
|
-
}
|
|
2343
|
-
reverse() {
|
|
2344
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f").reverse();
|
|
2345
|
-
return this;
|
|
2346
|
-
}
|
|
2347
|
-
sort(compareFn) {
|
|
2348
|
-
const fwdCompareFn = compareFn
|
|
2349
|
-
? (a, b) => compareFn(__classPrivateFieldGet(this, _RegisterClass_values, "f").get(a), __classPrivateFieldGet(this, _RegisterClass_values, "f").get(b))
|
|
2350
|
-
: undefined;
|
|
2351
|
-
__classPrivateFieldGet(this, _RegisterClass_keys, "f").sort(fwdCompareFn);
|
|
2352
|
-
return this;
|
|
2353
|
-
}
|
|
2354
|
-
fill(value, start = 0, end = this.length) {
|
|
2355
|
-
const values = this.toArray();
|
|
2356
|
-
values.fill(value, start, end);
|
|
2357
|
-
this.rebuildFrom(values);
|
|
2358
|
-
return this;
|
|
2359
|
-
}
|
|
2360
|
-
copyWithin(target, start, end) {
|
|
2361
|
-
const values = this.toArray();
|
|
2362
|
-
values.copyWithin(target, start, end);
|
|
2363
|
-
this.rebuildFrom(values);
|
|
2364
|
-
return this;
|
|
2365
|
-
}
|
|
2366
|
-
};
|
|
2367
|
-
__setFunctionName(_classThis, "RegisterClass");
|
|
2368
|
-
(() => {
|
|
2369
|
-
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
2370
|
-
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
2371
|
-
_classThis = _classDescriptor.value;
|
|
2372
|
-
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
2373
|
-
__runInitializers(_classThis, _classExtraInitializers);
|
|
2374
|
-
})();
|
|
2375
|
-
return _classThis;
|
|
2376
|
-
})();
|
|
2377
|
-
const Register = RegisterClass;
|
|
2378
|
-
/**
|
|
2379
|
-
* Creates a reactive Register - an ordered, array-like collection with stable key-based identity.
|
|
2380
|
-
*
|
|
2381
|
-
* Register combines array semantics (indexable access, ordering, iteration) with Map-like
|
|
2382
|
-
* key-based lookups. Items with the same key share the same value instance, making it ideal
|
|
2383
|
-
* for UI lists keyed by IDs or when you need to preserve identity across reorders.
|
|
2384
|
-
*
|
|
2385
|
-
* @param keyFn - Function that extracts the key from each item
|
|
2386
|
-
* @param initial - Optional initial items to populate the register
|
|
2387
|
-
* @returns A reactive Register instance
|
|
2388
|
-
*
|
|
2389
|
-
* @example
|
|
2390
|
-
* ```typescript
|
|
2391
|
-
* const users = register(
|
|
2392
|
-
* (user: User) => user.id,
|
|
2393
|
-
* [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
|
|
2394
|
-
* )
|
|
2395
|
-
*
|
|
2396
|
-
* users.push({ id: 3, name: 'Charlie' })
|
|
2397
|
-
* const bob = users.get(2) // Get by key
|
|
2398
|
-
* ```
|
|
2399
|
-
*/
|
|
2400
|
-
function register(keyFn, initial) {
|
|
2401
|
-
return new RegisterClass(keyFn, initial);
|
|
1803
|
+
}));
|
|
1804
|
+
});
|
|
2402
1805
|
}
|
|
1806
|
+
//#endregion
|
|
2403
1807
|
|
|
2404
1808
|
/**
|
|
2405
1809
|
* Converts an iterator to a generator that yields reactive values
|
|
@@ -2482,6 +1886,7 @@ let ReactiveArrayWrapper = (() => {
|
|
|
2482
1886
|
let _classSuper = Array;
|
|
2483
1887
|
let _instanceExtraInitializers = [];
|
|
2484
1888
|
let _fill_decorators;
|
|
1889
|
+
let _copyWithin_decorators;
|
|
2485
1890
|
let _pop_decorators;
|
|
2486
1891
|
let _push_decorators;
|
|
2487
1892
|
let _reverse_decorators;
|
|
@@ -2506,6 +1911,9 @@ let ReactiveArrayWrapper = (() => {
|
|
|
2506
1911
|
fill(value, start, end) {
|
|
2507
1912
|
return super.fill(unwrap(value), start, end);
|
|
2508
1913
|
}
|
|
1914
|
+
copyWithin(target, start, end) {
|
|
1915
|
+
return super.copyWithin(target, start, end);
|
|
1916
|
+
}
|
|
2509
1917
|
filter(predicate, thisArg) {
|
|
2510
1918
|
return reactive(super.filter((v, i, a) => predicate.call(thisArg, reactive(v), i, a), thisArg));
|
|
2511
1919
|
}
|
|
@@ -2607,7 +2015,7 @@ let ReactiveArrayWrapper = (() => {
|
|
|
2607
2015
|
dependant(this, keysOf);
|
|
2608
2016
|
return makeReactiveIterator(super.values());
|
|
2609
2017
|
}
|
|
2610
|
-
[(_fill_decorators = [atomic], _pop_decorators = [atomic], _push_decorators = [atomic], _reverse_decorators = [atomic], _shift_decorators = [atomic], _sort_decorators = [atomic], _splice_decorators = [atomic], _unshift_decorators = [atomic], Symbol.iterator)]() {
|
|
2018
|
+
[(_fill_decorators = [atomic], _copyWithin_decorators = [atomic], _pop_decorators = [atomic], _push_decorators = [atomic], _reverse_decorators = [atomic], _shift_decorators = [atomic], _sort_decorators = [atomic], _splice_decorators = [atomic], _unshift_decorators = [atomic], Symbol.iterator)]() {
|
|
2611
2019
|
dependant(this, keysOf);
|
|
2612
2020
|
return makeReactiveIterator(super[Symbol.iterator]());
|
|
2613
2021
|
}
|
|
@@ -2620,7 +2028,6 @@ let ReactiveArrayWrapper = (() => {
|
|
|
2620
2028
|
: undefined;
|
|
2621
2029
|
return reactive(super.toSorted(wrappedCompare));
|
|
2622
2030
|
}
|
|
2623
|
-
// biome-ignore lint/complexity/noArguments: Needed to distinguish fn() from fn(undefined)
|
|
2624
2031
|
toSpliced(start, deleteCount, ...items) {
|
|
2625
2032
|
if (arguments.length > 2)
|
|
2626
2033
|
return reactive(super.toSpliced(start, deleteCount, ...items.map(unwrap)));
|
|
@@ -2641,6 +2048,7 @@ let ReactiveArrayWrapper = (() => {
|
|
|
2641
2048
|
(() => {
|
|
2642
2049
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
2643
2050
|
__esDecorate(_a, null, _fill_decorators, { kind: "method", name: "fill", static: false, private: false, access: { has: obj => "fill" in obj, get: obj => obj.fill }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
2051
|
+
__esDecorate(_a, null, _copyWithin_decorators, { kind: "method", name: "copyWithin", static: false, private: false, access: { has: obj => "copyWithin" in obj, get: obj => obj.copyWithin }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
2644
2052
|
__esDecorate(_a, null, _pop_decorators, { kind: "method", name: "pop", static: false, private: false, access: { has: obj => "pop" in obj, get: obj => obj.pop }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
2645
2053
|
__esDecorate(_a, null, _push_decorators, { kind: "method", name: "push", static: false, private: false, access: { has: obj => "push" in obj, get: obj => obj.push }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
2646
2054
|
__esDecorate(_a, null, _reverse_decorators, { kind: "method", name: "reverse", static: false, private: false, access: { has: obj => "reverse" in obj, get: obj => obj.reverse }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -2661,18 +2069,18 @@ class ReactiveWeakMap extends WeakMap {
|
|
|
2661
2069
|
// Implement WeakMap interface methods with reactivity
|
|
2662
2070
|
delete(key) {
|
|
2663
2071
|
const hadKey = this.has(key);
|
|
2664
|
-
const result =
|
|
2072
|
+
const result = super.delete(key);
|
|
2665
2073
|
if (hadKey)
|
|
2666
2074
|
touched1(contentRef(this), { type: 'del', prop: key }, key);
|
|
2667
2075
|
return result;
|
|
2668
2076
|
}
|
|
2669
2077
|
get(key) {
|
|
2670
2078
|
dependant(contentRef(this), key);
|
|
2671
|
-
return reactive(
|
|
2079
|
+
return reactive(super.get(key));
|
|
2672
2080
|
}
|
|
2673
2081
|
has(key) {
|
|
2674
2082
|
dependant(contentRef(this), key);
|
|
2675
|
-
return
|
|
2083
|
+
return super.has(key);
|
|
2676
2084
|
}
|
|
2677
2085
|
set(key, value) {
|
|
2678
2086
|
const hadKey = this.has(key);
|
|
@@ -2693,16 +2101,18 @@ class ReactiveMap extends Map {
|
|
|
2693
2101
|
// Implement Map interface methods with reactivity
|
|
2694
2102
|
get size() {
|
|
2695
2103
|
dependant(this, 'size'); // The ReactiveMap instance still goes through proxy
|
|
2696
|
-
return
|
|
2104
|
+
return super.size;
|
|
2697
2105
|
}
|
|
2698
2106
|
clear() {
|
|
2699
2107
|
const hadEntries = this.size > 0;
|
|
2700
|
-
|
|
2108
|
+
super.clear();
|
|
2701
2109
|
if (hadEntries) {
|
|
2702
2110
|
const evolution = { type: 'bunch', method: 'clear' };
|
|
2703
2111
|
// Clear triggers all effects since all keys are affected
|
|
2704
|
-
|
|
2705
|
-
|
|
2112
|
+
batch(() => {
|
|
2113
|
+
touched1(this, evolution, 'size');
|
|
2114
|
+
touched(contentRef(this), evolution);
|
|
2115
|
+
});
|
|
2706
2116
|
}
|
|
2707
2117
|
}
|
|
2708
2118
|
entries() {
|
|
@@ -2737,32 +2147,36 @@ class ReactiveMap extends Map {
|
|
|
2737
2147
|
// Implement Map methods with reactivity
|
|
2738
2148
|
delete(key) {
|
|
2739
2149
|
const hadKey = this.has(key);
|
|
2740
|
-
const result =
|
|
2150
|
+
const result = super.delete(key);
|
|
2741
2151
|
if (hadKey) {
|
|
2742
2152
|
const evolution = { type: 'del', prop: key };
|
|
2743
|
-
|
|
2744
|
-
|
|
2153
|
+
batch(() => {
|
|
2154
|
+
touched1(contentRef(this), evolution, key);
|
|
2155
|
+
touched1(this, evolution, 'size');
|
|
2156
|
+
});
|
|
2745
2157
|
}
|
|
2746
2158
|
return result;
|
|
2747
2159
|
}
|
|
2748
2160
|
get(key) {
|
|
2749
2161
|
dependant(contentRef(this), key);
|
|
2750
|
-
return reactive(
|
|
2162
|
+
return reactive(super.get(key));
|
|
2751
2163
|
}
|
|
2752
2164
|
has(key) {
|
|
2753
2165
|
dependant(contentRef(this), key);
|
|
2754
|
-
return
|
|
2166
|
+
return super.has(key);
|
|
2755
2167
|
}
|
|
2756
2168
|
set(key, value) {
|
|
2757
2169
|
const hadKey = this.has(key);
|
|
2758
2170
|
const oldValue = this.get(key);
|
|
2759
2171
|
const reactiveValue = reactive(value);
|
|
2760
|
-
|
|
2172
|
+
super.set(key, reactiveValue);
|
|
2761
2173
|
if (!hadKey || oldValue !== reactiveValue) {
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2174
|
+
batch(() => {
|
|
2175
|
+
notifyPropertyChange(contentRef(this), key, oldValue, reactiveValue, hadKey);
|
|
2176
|
+
// Also notify size change for Map (WeakMap doesn't track size)
|
|
2177
|
+
const evolution = { type: hadKey ? 'set' : 'add', prop: key };
|
|
2178
|
+
touched1(this, evolution, 'size');
|
|
2179
|
+
});
|
|
2766
2180
|
}
|
|
2767
2181
|
return this;
|
|
2768
2182
|
}
|
|
@@ -2775,7 +2189,7 @@ class ReactiveMap extends Map {
|
|
|
2775
2189
|
class ReactiveWeakSet extends WeakSet {
|
|
2776
2190
|
add(value) {
|
|
2777
2191
|
const had = this.has(value);
|
|
2778
|
-
|
|
2192
|
+
super.add(value);
|
|
2779
2193
|
if (!had) {
|
|
2780
2194
|
// touch the specific value and the collection view
|
|
2781
2195
|
touched1(contentRef(this), { type: 'add', prop: value }, value);
|
|
@@ -2785,14 +2199,14 @@ class ReactiveWeakSet extends WeakSet {
|
|
|
2785
2199
|
}
|
|
2786
2200
|
delete(value) {
|
|
2787
2201
|
const had = this.has(value);
|
|
2788
|
-
const res =
|
|
2202
|
+
const res = super.delete(value);
|
|
2789
2203
|
if (had)
|
|
2790
2204
|
touched1(contentRef(this), { type: 'del', prop: value }, value);
|
|
2791
2205
|
return res;
|
|
2792
2206
|
}
|
|
2793
2207
|
has(value) {
|
|
2794
2208
|
dependant(contentRef(this), value);
|
|
2795
|
-
return
|
|
2209
|
+
return super.has(value);
|
|
2796
2210
|
}
|
|
2797
2211
|
}
|
|
2798
2212
|
/**
|
|
@@ -2808,31 +2222,37 @@ class ReactiveSet extends Set {
|
|
|
2808
2222
|
add(value) {
|
|
2809
2223
|
const had = this.has(value);
|
|
2810
2224
|
const reactiveValue = reactive(value);
|
|
2811
|
-
|
|
2225
|
+
super.add(reactiveValue);
|
|
2812
2226
|
if (!had) {
|
|
2813
2227
|
const evolution = { type: 'add', prop: reactiveValue };
|
|
2814
2228
|
// touch for value-specific and aggregate dependencies
|
|
2815
|
-
|
|
2816
|
-
|
|
2229
|
+
batch(() => {
|
|
2230
|
+
touched1(contentRef(this), evolution, reactiveValue);
|
|
2231
|
+
touched1(this, evolution, 'size');
|
|
2232
|
+
});
|
|
2817
2233
|
}
|
|
2818
2234
|
return this;
|
|
2819
2235
|
}
|
|
2820
2236
|
clear() {
|
|
2821
2237
|
const hadEntries = this.size > 0;
|
|
2822
|
-
|
|
2238
|
+
super.clear();
|
|
2823
2239
|
if (hadEntries) {
|
|
2824
2240
|
const evolution = { type: 'bunch', method: 'clear' };
|
|
2825
|
-
|
|
2826
|
-
|
|
2241
|
+
batch(() => {
|
|
2242
|
+
touched1(this, evolution, 'size');
|
|
2243
|
+
touched(contentRef(this), evolution);
|
|
2244
|
+
});
|
|
2827
2245
|
}
|
|
2828
2246
|
}
|
|
2829
2247
|
delete(value) {
|
|
2830
2248
|
const had = this.has(value);
|
|
2831
|
-
const res =
|
|
2249
|
+
const res = super.delete(value);
|
|
2832
2250
|
if (had) {
|
|
2833
2251
|
const evolution = { type: 'del', prop: value };
|
|
2834
|
-
|
|
2835
|
-
|
|
2252
|
+
batch(() => {
|
|
2253
|
+
touched1(contentRef(this), evolution, value);
|
|
2254
|
+
touched1(this, evolution, 'size');
|
|
2255
|
+
});
|
|
2836
2256
|
}
|
|
2837
2257
|
return res;
|
|
2838
2258
|
}
|
|
@@ -2871,14 +2291,12 @@ class ReactiveSet extends Set {
|
|
|
2871
2291
|
}
|
|
2872
2292
|
|
|
2873
2293
|
// Register native collection types to use specialized reactive wrappers
|
|
2874
|
-
console.time('mutts-reactive-init');
|
|
2875
2294
|
metaProtos.set(Array, ReactiveArray.prototype);
|
|
2876
2295
|
metaProtos.set(Set, ReactiveSet.prototype);
|
|
2877
2296
|
metaProtos.set(WeakSet, ReactiveWeakSet.prototype);
|
|
2878
2297
|
metaProtos.set(Map, ReactiveMap.prototype);
|
|
2879
2298
|
metaProtos.set(WeakMap, ReactiveWeakMap.prototype);
|
|
2880
2299
|
wrapProtos.set(Array, ReactiveArrayWrapper.prototype);
|
|
2881
|
-
console.timeEnd('mutts-reactive-init');
|
|
2882
2300
|
/**
|
|
2883
2301
|
* Object containing internal reactive system state for debugging and profiling
|
|
2884
2302
|
*/
|
|
@@ -2891,7 +2309,6 @@ const profileInfo = {
|
|
|
2891
2309
|
objectsWithDeepWatchers,
|
|
2892
2310
|
deepWatchers,
|
|
2893
2311
|
effectToDeepWatchedObjects,
|
|
2894
|
-
nonReactiveObjects,
|
|
2895
2312
|
};
|
|
2896
2313
|
|
|
2897
2314
|
// In order to avoid async re-entrance, we could use zone.js or something like that.
|
|
@@ -3057,8 +2474,7 @@ const deprecated = Object.assign(decorator({
|
|
|
3057
2474
|
},
|
|
3058
2475
|
}), {
|
|
3059
2476
|
warn: (target, propertyKey, message) => {
|
|
3060
|
-
|
|
3061
|
-
console.warn(`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`);
|
|
2477
|
+
options.warn(`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`);
|
|
3062
2478
|
},
|
|
3063
2479
|
});
|
|
3064
2480
|
/**
|
|
@@ -3121,12 +2537,11 @@ function throttle(delay) {
|
|
|
3121
2537
|
});
|
|
3122
2538
|
}
|
|
3123
2539
|
|
|
3124
|
-
var version$1 = "1.0.
|
|
2540
|
+
var version$1 = "1.0.12";
|
|
3125
2541
|
var pkg = {
|
|
3126
2542
|
version: version$1};
|
|
3127
2543
|
|
|
3128
2544
|
const { version } = pkg;
|
|
3129
|
-
// Singleton verification
|
|
3130
2545
|
const GLOBAL_MUTTS_KEY = '__MUTTS_INSTANCE__';
|
|
3131
2546
|
const globalScope = (typeof globalThis !== 'undefined'
|
|
3132
2547
|
? globalThis
|
|
@@ -3136,28 +2551,16 @@ const globalScope = (typeof globalThis !== 'undefined'
|
|
|
3136
2551
|
? global
|
|
3137
2552
|
: false);
|
|
3138
2553
|
if (globalScope) {
|
|
3139
|
-
// Detect the source of this instance safely across different environments
|
|
3140
2554
|
let source = 'mutts/index';
|
|
3141
|
-
// biome-ignore lint/security/noGlobalEval: Intentional eval for cross-env import.meta detection
|
|
3142
|
-
const viteEval = eval;
|
|
3143
2555
|
try {
|
|
3144
2556
|
if (typeof __filename !== 'undefined')
|
|
3145
2557
|
source = __filename;
|
|
3146
|
-
else {
|
|
3147
|
-
|
|
3148
|
-
const meta = viteEval('import.meta');
|
|
3149
|
-
if (meta && meta.url)
|
|
3150
|
-
source = meta.url;
|
|
2558
|
+
else if (typeof import.meta !== 'undefined' && import.meta.url) {
|
|
2559
|
+
source = import.meta.url;
|
|
3151
2560
|
}
|
|
3152
2561
|
}
|
|
3153
|
-
catch (
|
|
3154
|
-
|
|
3155
|
-
}
|
|
3156
|
-
const currentSourceInfo = {
|
|
3157
|
-
version,
|
|
3158
|
-
source,
|
|
3159
|
-
timestamp: Date.now(),
|
|
3160
|
-
};
|
|
2562
|
+
catch (_e) { }
|
|
2563
|
+
const currentSourceInfo = { version, source, timestamp: Date.now() };
|
|
3161
2564
|
if (globalScope[GLOBAL_MUTTS_KEY]) {
|
|
3162
2565
|
const existing = globalScope[GLOBAL_MUTTS_KEY];
|
|
3163
2566
|
throw new Error(`[Mutts] Multiple instances detected!\n` +
|
|
@@ -3170,5 +2573,5 @@ if (globalScope) {
|
|
|
3170
2573
|
globalScope[GLOBAL_MUTTS_KEY] = currentSourceInfo;
|
|
3171
2574
|
}
|
|
3172
2575
|
|
|
3173
|
-
export { ArrayReadForward as A,
|
|
3174
|
-
//# sourceMappingURL=index-
|
|
2576
|
+
export { ArrayReadForward as A, unreactive as B, watch as C, Destroyable as D, Eventful as E, when as F, Indexable as I, DestructionError as a, allocated as b, allocatedValues as c, arrayDiff as d, attend as e, cache as f, cached as g, callOnGC as h, chainPromise as i, debounce as j, deepWatch as k, deprecated as l, descriptor as m, destructor as n, forwardArray as o, getAt as p, isCached as q, lift as r, memoize as s, morph as t, organize as u, organized as v, profileInfo as w, resource as x, setAt as y, throttle as z };
|
|
2577
|
+
//# sourceMappingURL=index-BUop6B2U.esm.js.map
|