valdres 0.2.0-alpha.6 → 0.2.0-alpha.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +760 -279
- package/dist/types/src/atom.d.ts +16 -0
- package/dist/types/src/atomFamily.d.ts +4 -0
- package/dist/types/src/globalStore.d.ts +4 -0
- package/dist/types/src/index.d.ts +34 -0
- package/dist/types/src/lib/atomFamilyAtom.d.ts +8 -0
- package/dist/types/src/lib/createAtomFamily.d.ts +4 -0
- package/dist/types/src/lib/createGlobalAtomFamily.d.ts +5 -0
- package/dist/types/src/lib/createStoreData.d.ts +3 -0
- package/dist/types/src/lib/equal.d.ts +1 -0
- package/dist/types/src/lib/getState.d.ts +7 -0
- package/dist/types/src/lib/globalAtom.d.ts +4 -0
- package/dist/{src → types/src}/lib/initAtom.d.ts +2 -1
- package/dist/{src → types/src}/lib/initSelector.d.ts +1 -2
- package/dist/types/src/lib/isFunction.d.ts +1 -0
- package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +4 -0
- package/dist/types/src/lib/setAtom.d.ts +3 -0
- package/dist/types/src/lib/storeFromStoreData.d.ts +4 -0
- package/dist/{src → types/src}/lib/subscribe.d.ts +1 -1
- package/dist/types/src/lib/transaction.d.ts +4 -0
- package/dist/{src → types/src}/lib/unsubscribe.d.ts +1 -1
- package/dist/{src → types/src}/lib/updateStateSubscribers.d.ts +1 -1
- package/dist/types/src/selector.d.ts +4 -0
- package/dist/types/src/selectorFamily.d.ts +4 -0
- package/dist/types/src/store.d.ts +1 -0
- package/dist/types/src/types/Atom.d.ts +14 -0
- package/dist/types/src/types/AtomDefaultValue.d.ts +2 -0
- package/dist/types/src/types/AtomFamily.d.ts +12 -0
- package/dist/types/src/types/AtomFamilyAtom.d.ts +6 -0
- package/dist/types/src/types/AtomFamilyDefaultValue.d.ts +5 -0
- package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +3 -0
- package/dist/types/src/types/AtomFamilySelector.d.ts +6 -0
- package/dist/types/src/types/AtomOnInit.d.ts +2 -0
- package/dist/types/src/types/AtomOnSet.d.ts +2 -0
- package/dist/types/src/types/AtomOptions.d.ts +13 -0
- package/dist/types/src/types/EqualFunc.d.ts +1 -0
- package/dist/{src → types/src}/types/Family.d.ts +1 -1
- package/dist/types/src/types/FamilyKey.d.ts +3 -0
- package/dist/types/src/types/GetValue.d.ts +8 -0
- package/dist/types/src/types/GlobalAtom.d.ts +11 -0
- package/dist/types/src/types/GlobalAtomGetSelfFunc.d.ts +1 -0
- package/dist/types/src/types/GlobalAtomResetSelfFunc.d.ts +1 -0
- package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +1 -0
- package/dist/types/src/types/Selector.d.ts +11 -0
- package/dist/types/src/types/SelectorFamily.d.ts +6 -0
- package/dist/types/src/types/SelectorOptions.d.ts +5 -0
- package/dist/{src → types/src}/types/SetAtom.d.ts +3 -1
- package/dist/types/src/types/SetAtomValue.d.ts +1 -0
- package/dist/types/src/types/State.d.ts +4 -0
- package/dist/types/src/types/Store.d.ts +24 -0
- package/dist/{src → types/src}/types/StoreData.d.ts +9 -1
- package/dist/types/src/types/SubscribeFn.d.ts +9 -0
- package/dist/types/src/types/TransactionFn.d.ts +2 -0
- package/dist/{src/types/Store.d.ts → types/src/types/TransactionInterface.d.ts} +9 -6
- package/dist/types/src/utils/isAtom.d.ts +2 -0
- package/dist/types/src/utils/isAtomFamily.d.ts +2 -0
- package/dist/types/src/utils/isFamily.d.ts +1 -0
- package/dist/types/src/utils/isFamilyAtom.d.ts +2 -0
- package/dist/types/src/utils/isFamilySelector.d.ts +2 -0
- package/dist/types/src/utils/isFamilyState.d.ts +3 -0
- package/dist/types/src/utils/isSelector.d.ts +2 -0
- package/dist/types/src/utils/isSelectorFamily.d.ts +2 -0
- package/package.json +12 -10
- package/dist/index.d.ts +0 -21
- package/dist/src/atom.d.ts +0 -9
- package/dist/src/atomFamily.d.ts +0 -4
- package/dist/src/createStore.d.ts +0 -2
- package/dist/src/getDefaultStore.d.ts +0 -2
- package/dist/src/lib/createStoreData.d.ts +0 -2
- package/dist/src/lib/getState.d.ts +0 -3
- package/dist/src/lib/propagateUpdatedAtoms.d.ts +0 -3
- package/dist/src/lib/setAtom.d.ts +0 -3
- package/dist/src/lib/storeFromStoreData.d.ts +0 -3
- package/dist/src/lib/transaction.d.ts +0 -9
- package/dist/src/selector.d.ts +0 -3
- package/dist/src/selectorFamily.d.ts +0 -2
- package/dist/src/types/Atom.d.ts +0 -10
- package/dist/src/types/AtomFamily.d.ts +0 -5
- package/dist/src/types/GetValue.d.ts +0 -2
- package/dist/src/types/Selector.d.ts +0 -9
- package/dist/src/types/SelectorFamily.d.ts +0 -5
- package/dist/src/types/SetAtomValue.d.ts +0 -1
- package/dist/src/types/State.d.ts +0 -3
- package/dist/src/types/SubscribeFn.d.ts +0 -2
- package/dist/src/types/TransactionFn.d.ts +0 -4
- package/dist/src/utils/isAtom.d.ts +0 -2
- package/dist/src/utils/isFamily.d.ts +0 -1
- package/dist/src/utils/isSelector.d.ts +0 -2
- /package/dist/{src → types/src}/createStoreWithSelectorSet.d.ts +0 -0
- /package/dist/{src → types/src}/lib/resetAtom.d.ts +0 -0
- /package/dist/{src → types/src}/lib/setAtoms.d.ts +0 -0
- /package/dist/{src → types/src}/lib/stableStringify.d.ts +0 -0
- /package/dist/{src → types/src}/lib/updateSelectorSubscribers.d.ts +0 -0
- /package/dist/{src → types/src}/types/ResetAtom.d.ts +0 -0
- /package/dist/{src → types/src}/types/Subscription.d.ts +0 -0
- /package/dist/{src → types/src}/utils/isPromiseLike.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
if (!options)
|
|
4
|
-
return { defaultValue };
|
|
5
|
-
return {
|
|
6
|
-
defaultValue,
|
|
7
|
-
...options
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
// src/utils/isPromiseLike.ts
|
|
11
|
-
var isPromiseLike = (object) => {
|
|
12
|
-
return object && object.then && typeof object.then === "function";
|
|
13
|
-
};
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { version } from "../package.json";
|
|
14
3
|
|
|
15
|
-
// src/lib/
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
if (typeof x !== "object") {
|
|
37
|
-
return JSON.stringify(x) ?? "";
|
|
38
|
-
}
|
|
39
|
-
if (isPromiseLike(x)) {
|
|
40
|
-
return "__PROMISE__";
|
|
41
|
-
}
|
|
42
|
-
if (Array.isArray(x)) {
|
|
43
|
-
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
44
|
-
}
|
|
45
|
-
if (typeof x.toJSON === "function") {
|
|
46
|
-
return stableStringifyRecurse(x.toJSON(key), key);
|
|
47
|
-
}
|
|
48
|
-
if (x instanceof Map) {
|
|
49
|
-
const obj = {};
|
|
50
|
-
for (const [k, v] of x) {
|
|
51
|
-
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
4
|
+
// src/lib/equal.ts
|
|
5
|
+
var hasElementType = typeof Element !== "undefined";
|
|
6
|
+
var hasMap = typeof Map === "function";
|
|
7
|
+
var hasSet = typeof Set === "function";
|
|
8
|
+
var hasArrayBuffer = typeof ArrayBuffer === "function" && !!ArrayBuffer.isView;
|
|
9
|
+
var deepEqualFn = (a, b) => {
|
|
10
|
+
if (a === b)
|
|
11
|
+
return true;
|
|
12
|
+
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
13
|
+
if (a.constructor !== b.constructor)
|
|
14
|
+
return false;
|
|
15
|
+
var length, i, keys;
|
|
16
|
+
if (Array.isArray(a)) {
|
|
17
|
+
length = a.length;
|
|
18
|
+
if (length != b.length)
|
|
19
|
+
return false;
|
|
20
|
+
for (i = length;i-- !== 0; )
|
|
21
|
+
if (!deepEqualFn(a[i], b[i]))
|
|
22
|
+
return false;
|
|
23
|
+
return true;
|
|
52
24
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
25
|
+
var it;
|
|
26
|
+
if (hasMap && a instanceof Map && b instanceof Map) {
|
|
27
|
+
if (a.size !== b.size)
|
|
28
|
+
return false;
|
|
29
|
+
it = a.entries();
|
|
30
|
+
while (!(i = it.next()).done)
|
|
31
|
+
if (!b.has(i.value[0]))
|
|
32
|
+
return false;
|
|
33
|
+
it = a.entries();
|
|
34
|
+
while (!(i = it.next()).done)
|
|
35
|
+
if (!deepEqualFn(i.value[1], b.get(i.value[0])))
|
|
36
|
+
return false;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (hasSet && a instanceof Set && b instanceof Set) {
|
|
40
|
+
if (a.size !== b.size)
|
|
41
|
+
return false;
|
|
42
|
+
it = a.entries();
|
|
43
|
+
while (!(i = it.next()).done)
|
|
44
|
+
if (!b.has(i.value[0]))
|
|
45
|
+
return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
49
|
+
length = a.length;
|
|
50
|
+
if (length != b.length)
|
|
51
|
+
return false;
|
|
52
|
+
for (i = length;i-- !== 0; )
|
|
53
|
+
if (a[i] !== b[i])
|
|
54
|
+
return false;
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (a.constructor === RegExp)
|
|
58
|
+
return a.source === b.source && a.flags === b.flags;
|
|
59
|
+
if (a.valueOf !== Object.prototype.valueOf && typeof a.valueOf === "function" && typeof b.valueOf === "function")
|
|
60
|
+
return a.valueOf() === b.valueOf();
|
|
61
|
+
if (a.toString !== Object.prototype.toString && typeof a.toString === "function" && typeof b.toString === "function")
|
|
62
|
+
return a.toString() === b.toString();
|
|
63
|
+
keys = Object.keys(a);
|
|
64
|
+
length = keys.length;
|
|
65
|
+
if (length !== Object.keys(b).length)
|
|
66
|
+
return false;
|
|
67
|
+
for (i = length;i-- !== 0; )
|
|
68
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i]))
|
|
69
|
+
return false;
|
|
70
|
+
if (hasElementType && a instanceof Element)
|
|
71
|
+
return false;
|
|
72
|
+
for (i = length;i-- !== 0; ) {
|
|
73
|
+
if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (!deepEqualFn(a[keys[i]], b[keys[i]]))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
60
80
|
}
|
|
61
|
-
return
|
|
81
|
+
return a !== a && b !== b;
|
|
62
82
|
};
|
|
63
|
-
var
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
var atomFamily = (defaultValue, debugLabel) => {
|
|
71
|
-
const map = new Map;
|
|
72
|
-
const atomFamily2 = (key, defaultOverride) => {
|
|
73
|
-
const keyStringified = stableStringify(key);
|
|
74
|
-
if (map.has(keyStringified)) {
|
|
75
|
-
return map.get(keyStringified);
|
|
83
|
+
var equal = (a, b) => {
|
|
84
|
+
try {
|
|
85
|
+
return deepEqualFn(a, b);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if ((error.message || "").match(/stack|recursion/i)) {
|
|
88
|
+
console.warn("react-fast-compare cannot handle circular refs");
|
|
89
|
+
return false;
|
|
76
90
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
label: atomDebugLabel
|
|
80
|
-
});
|
|
81
|
-
newAtom.family = atomFamily2;
|
|
82
|
-
newAtom.familyKey = Object.freeze(key);
|
|
83
|
-
map.set(keyStringified, newAtom);
|
|
84
|
-
return newAtom;
|
|
85
|
-
};
|
|
86
|
-
atomFamily2._map = map;
|
|
87
|
-
return atomFamily2;
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
88
93
|
};
|
|
89
|
-
// src/lib/createStoreData.ts
|
|
90
|
-
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
91
|
-
var createStoreData = (id = generateId()) => ({
|
|
92
|
-
id,
|
|
93
|
-
values: new WeakMap,
|
|
94
|
-
expiredValues: new WeakMap,
|
|
95
|
-
subscriptions: new WeakMap,
|
|
96
|
-
subscriptionsRequireEqualCheck: new WeakMap,
|
|
97
|
-
stateConsumers: new WeakMap,
|
|
98
|
-
stateDependencies: new WeakMap
|
|
99
|
-
});
|
|
100
94
|
|
|
101
95
|
// src/utils/isAtom.ts
|
|
102
96
|
var isAtom = (state) => Object.hasOwn(state, "defaultValue");
|
|
103
97
|
|
|
98
|
+
// src/utils/isFamilyState.ts
|
|
99
|
+
var isFamilyState = (state) => state && Object.hasOwn(state, "family");
|
|
100
|
+
|
|
101
|
+
// src/utils/isFamilyAtom.ts
|
|
102
|
+
var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
|
|
103
|
+
|
|
104
104
|
// src/lib/updateStateSubscribers.ts
|
|
105
105
|
var updateStateSubscribers = (state, data) => {
|
|
106
106
|
const subscribtions = data.subscriptions.get(state);
|
|
@@ -109,7 +109,7 @@ var updateStateSubscribers = (state, data) => {
|
|
|
109
109
|
subscribtion.callback();
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
if (state
|
|
112
|
+
if (isFamilyState(state)) {
|
|
113
113
|
const familySubscriptions = data.subscriptions.get(state.family);
|
|
114
114
|
if (familySubscriptions?.size) {
|
|
115
115
|
for (const subscribtion of familySubscriptions) {
|
|
@@ -119,11 +119,123 @@ var updateStateSubscribers = (state, data) => {
|
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
// src/
|
|
123
|
-
|
|
122
|
+
// src/utils/isPromiseLike.ts
|
|
123
|
+
var isPromiseLike = (object) => {
|
|
124
|
+
return object && object.then && typeof object.then === "function";
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/utils/isAtomFamily.ts
|
|
128
|
+
var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
|
|
129
|
+
|
|
130
|
+
// src/utils/isSelector.ts
|
|
131
|
+
var isSelector = (state) => state && Object.hasOwn(state, "get");
|
|
132
|
+
|
|
133
|
+
// src/utils/isSelectorFamily.ts
|
|
134
|
+
var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
|
|
135
|
+
|
|
136
|
+
// src/lib/isFunction.ts
|
|
137
|
+
var isFunction = (value) => typeof value === "function";
|
|
138
|
+
|
|
139
|
+
// src/lib/setAtom.ts
|
|
140
|
+
var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
141
|
+
const currentValue = getState(atom, data);
|
|
142
|
+
if (isFunction(newValue)) {
|
|
143
|
+
newValue = newValue(currentValue);
|
|
144
|
+
if (isPromiseLike(newValue) || isPromiseLike(currentValue))
|
|
145
|
+
throw new Error("Todo, how should we handle this?");
|
|
146
|
+
}
|
|
147
|
+
if (atom.equal(currentValue, newValue))
|
|
148
|
+
return newValue;
|
|
149
|
+
data.values.set(atom, newValue);
|
|
150
|
+
if (atom.onSet && !skipOnSet)
|
|
151
|
+
atom.onSet(newValue, data);
|
|
152
|
+
if (currentValue?.__isEmptyAtomPromise__) {
|
|
153
|
+
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
154
|
+
}
|
|
155
|
+
propagateUpdatedAtoms([atom], data);
|
|
156
|
+
return newValue;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/lib/initAtom.ts
|
|
160
|
+
var getAtomInitValue = (atom, data) => {
|
|
161
|
+
if (atom.defaultValue === undefined) {
|
|
162
|
+
let promiseResolve;
|
|
163
|
+
const promise = new Promise((resolve) => {
|
|
164
|
+
promiseResolve = resolve;
|
|
165
|
+
});
|
|
166
|
+
promise.__isEmptyAtomPromise__ = true;
|
|
167
|
+
promise.__resolveEmptyAtomPromise__ = promiseResolve;
|
|
168
|
+
return promise;
|
|
169
|
+
} else if (typeof atom.defaultValue === "function") {
|
|
170
|
+
const value = atom.defaultValue();
|
|
171
|
+
if (isPromiseLike(value)) {
|
|
172
|
+
value.then((resolvedValue) => {
|
|
173
|
+
data.values.set(atom, resolvedValue);
|
|
174
|
+
propagateUpdatedAtoms([atom], data);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return value;
|
|
178
|
+
} else if (isSelector(atom.defaultValue)) {
|
|
179
|
+
return getState(atom.defaultValue, data);
|
|
180
|
+
} else {
|
|
181
|
+
return atom.defaultValue;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
var initAtom = (atom, data) => {
|
|
185
|
+
let value = getAtomInitValue(atom, data);
|
|
186
|
+
data.values.set(atom, value);
|
|
187
|
+
if (isFamilyAtom(atom)) {
|
|
188
|
+
const currentKeySet = getState(atom.family.__keysAtom, data);
|
|
189
|
+
if (!currentKeySet.has(atom.familyKey)) {
|
|
190
|
+
const newSet = new Set(currentKeySet);
|
|
191
|
+
newSet.add(atom.familyKey);
|
|
192
|
+
setAtom(atom.family.__keysAtom, newSet, data);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (atom.onInit)
|
|
196
|
+
atom.onInit((newVal) => {
|
|
197
|
+
value = newVal;
|
|
198
|
+
setAtom(atom, newVal, data, true);
|
|
199
|
+
}, data);
|
|
200
|
+
return value;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// src/lib/getState.ts
|
|
204
|
+
function getState(state, data, circularDependencySet) {
|
|
205
|
+
if (data.values.has(state))
|
|
206
|
+
return data.values.get(state);
|
|
207
|
+
if (isAtom(state)) {
|
|
208
|
+
if ("parent" in data)
|
|
209
|
+
return getState(state, data.parent, circularDependencySet);
|
|
210
|
+
return initAtom(state, data);
|
|
211
|
+
}
|
|
212
|
+
if (isSelector(state))
|
|
213
|
+
return initSelector(state, data, circularDependencySet);
|
|
214
|
+
if (isAtomFamily(state)) {
|
|
215
|
+
if ("parent" in data) {
|
|
216
|
+
const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
|
|
217
|
+
return getState(state.__keysSelector, closestData, circularDependencySet);
|
|
218
|
+
}
|
|
219
|
+
return getState(state.__keysSelector, data, circularDependencySet);
|
|
220
|
+
}
|
|
221
|
+
if (isSelectorFamily(state)) {
|
|
222
|
+
const array = Array.from(state.__valdresSelectorFamilyMap.keys());
|
|
223
|
+
if (equal(array, state._keyArray))
|
|
224
|
+
return state._keyArray;
|
|
225
|
+
state._keyArray = array;
|
|
226
|
+
return array;
|
|
227
|
+
}
|
|
228
|
+
throw new Error("Invalid object passed to get");
|
|
229
|
+
}
|
|
230
|
+
var findClosestStoreWithAtomInitialized = (atom, data) => {
|
|
231
|
+
if ("parent" in data === false)
|
|
232
|
+
return data;
|
|
233
|
+
if (data.values.has(atom))
|
|
234
|
+
return data;
|
|
235
|
+
return findClosestStoreWithAtomInitialized(atom, data.parent);
|
|
236
|
+
};
|
|
124
237
|
|
|
125
238
|
// src/lib/initSelector.ts
|
|
126
|
-
import equal from "fast-deep-equal";
|
|
127
239
|
class SuspendAndWaitForResolveError extends Error {
|
|
128
240
|
promise;
|
|
129
241
|
constructor(promise) {
|
|
@@ -131,6 +243,36 @@ class SuspendAndWaitForResolveError extends Error {
|
|
|
131
243
|
this.promise = promise;
|
|
132
244
|
}
|
|
133
245
|
}
|
|
246
|
+
var generateSelectorTrace = (selectors) => {
|
|
247
|
+
const lastIndex = selectors.length - 1;
|
|
248
|
+
return [...selectors].reverse().map((selector, index) => {
|
|
249
|
+
const name = selector.name ?? "Anonymous Selector";
|
|
250
|
+
if (index === 0) {
|
|
251
|
+
return `[START] ${name}`;
|
|
252
|
+
} else if (index === lastIndex) {
|
|
253
|
+
return `[CRASH] ${name}`;
|
|
254
|
+
} else {
|
|
255
|
+
return ` ${" ".repeat(index)}${name}`;
|
|
256
|
+
}
|
|
257
|
+
}).join(`
|
|
258
|
+
`);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
class CircularDependencyError extends Error {
|
|
262
|
+
selectors;
|
|
263
|
+
constructor() {
|
|
264
|
+
super();
|
|
265
|
+
this.selectors = [];
|
|
266
|
+
}
|
|
267
|
+
track(selector) {
|
|
268
|
+
this.selectors.push(selector);
|
|
269
|
+
}
|
|
270
|
+
get message() {
|
|
271
|
+
const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
|
|
272
|
+
return `Circular dependency detected in '${firstSelectorName}'
|
|
273
|
+
${generateSelectorTrace(this.selectors)}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
134
276
|
var getOrInitConsumersSet = (state, data) => {
|
|
135
277
|
const set = data.stateConsumers.get(state);
|
|
136
278
|
if (set)
|
|
@@ -139,18 +281,21 @@ var getOrInitConsumersSet = (state, data) => {
|
|
|
139
281
|
data.stateConsumers.set(state, newSet);
|
|
140
282
|
return newSet;
|
|
141
283
|
};
|
|
142
|
-
var evaluateSelector = (selector, data) => {
|
|
143
|
-
const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
|
|
284
|
+
var evaluateSelector = (selector, data, circularDependencyMap = new WeakSet) => {
|
|
144
285
|
const updatedDependencies = new Set;
|
|
286
|
+
if (circularDependencyMap.has(selector)) {
|
|
287
|
+
throw new CircularDependencyError;
|
|
288
|
+
}
|
|
289
|
+
circularDependencyMap.add(selector);
|
|
145
290
|
let result;
|
|
146
291
|
try {
|
|
147
292
|
result = selector.get((state) => {
|
|
148
|
-
const value =
|
|
293
|
+
const value = getState(state, data, circularDependencyMap);
|
|
149
294
|
updatedDependencies.add(state);
|
|
150
295
|
if (isPromiseLike(value))
|
|
151
296
|
throw new SuspendAndWaitForResolveError(value);
|
|
152
297
|
return value;
|
|
153
|
-
});
|
|
298
|
+
}, data.id);
|
|
154
299
|
} catch (error) {
|
|
155
300
|
if (error instanceof SuspendAndWaitForResolveError) {
|
|
156
301
|
result = error;
|
|
@@ -158,6 +303,7 @@ var evaluateSelector = (selector, data) => {
|
|
|
158
303
|
throw error;
|
|
159
304
|
}
|
|
160
305
|
}
|
|
306
|
+
const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
|
|
161
307
|
const added = updatedDependencies?.difference(currentDependencies);
|
|
162
308
|
const removed = currentDependencies?.difference(updatedDependencies);
|
|
163
309
|
for (const state of added) {
|
|
@@ -186,12 +332,19 @@ var handleSelectorResult = (value, selector, data) => {
|
|
|
186
332
|
return value;
|
|
187
333
|
}
|
|
188
334
|
};
|
|
189
|
-
var initSelector = (selector, data) => {
|
|
190
|
-
|
|
335
|
+
var initSelector = (selector, data, circularDependencySet = new WeakSet) => {
|
|
336
|
+
let tmpValue;
|
|
337
|
+
try {
|
|
338
|
+
tmpValue = evaluateSelector(selector, data, circularDependencySet);
|
|
339
|
+
} catch (e) {
|
|
340
|
+
if (e instanceof CircularDependencyError)
|
|
341
|
+
e.track(selector);
|
|
342
|
+
throw e;
|
|
343
|
+
}
|
|
191
344
|
const value = handleSelectorResult(tmpValue, selector, data);
|
|
192
345
|
if (data.expiredValues.has(selector)) {
|
|
193
346
|
const expiredValue = data.expiredValues.get(selector);
|
|
194
|
-
if (equal(expiredValue, value)) {
|
|
347
|
+
if (selector.equal(expiredValue, value)) {
|
|
195
348
|
data.values.set(selector, expiredValue);
|
|
196
349
|
return expiredValue;
|
|
197
350
|
}
|
|
@@ -210,7 +363,7 @@ var updateSelectorSubscribers = (selector, data) => {
|
|
|
210
363
|
try {
|
|
211
364
|
const oldValue = data.expiredValues.get(selector);
|
|
212
365
|
const newValue = initSelector(selector, data);
|
|
213
|
-
if (
|
|
366
|
+
if (selector.equal(newValue, oldValue))
|
|
214
367
|
return;
|
|
215
368
|
} catch (e) {
|
|
216
369
|
}
|
|
@@ -243,13 +396,13 @@ var recursivlyResetSelectorTree = (selectors, data, clearedSelectors) => {
|
|
|
243
396
|
};
|
|
244
397
|
var propagateUpdatedAtoms = (atoms, data) => {
|
|
245
398
|
const clearedSelectors = new Set;
|
|
246
|
-
for (const
|
|
247
|
-
const consumers = data.stateConsumers.get(
|
|
399
|
+
for (const atom of atoms) {
|
|
400
|
+
const consumers = data.stateConsumers.get(atom);
|
|
248
401
|
if (consumers && consumers.size) {
|
|
249
402
|
recursivlyResetSelectorTree(consumers, data, clearedSelectors);
|
|
250
403
|
}
|
|
251
|
-
if (
|
|
252
|
-
const consumersFamily = data.stateConsumers.get(
|
|
404
|
+
if (isFamilyAtom(atom)) {
|
|
405
|
+
const consumersFamily = data.stateConsumers.get(atom.family);
|
|
253
406
|
if (consumersFamily?.size) {
|
|
254
407
|
recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
|
|
255
408
|
}
|
|
@@ -258,97 +411,52 @@ var propagateUpdatedAtoms = (atoms, data) => {
|
|
|
258
411
|
for (const selector of clearedSelectors) {
|
|
259
412
|
updateSelectorSubscribers(selector, data);
|
|
260
413
|
}
|
|
261
|
-
for (const
|
|
262
|
-
updateStateSubscribers(
|
|
414
|
+
for (const atom of atoms) {
|
|
415
|
+
updateStateSubscribers(atom, data);
|
|
263
416
|
}
|
|
264
417
|
};
|
|
265
418
|
|
|
266
|
-
// src/lib/
|
|
267
|
-
|
|
268
|
-
var
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
280
|
-
}
|
|
281
|
-
propagateUpdatedAtoms([atom3], data);
|
|
419
|
+
// src/lib/createStoreData.ts
|
|
420
|
+
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
421
|
+
var generateStoreData = (id = generateId()) => {
|
|
422
|
+
return {
|
|
423
|
+
id,
|
|
424
|
+
values: new WeakMap,
|
|
425
|
+
expiredValues: new WeakMap,
|
|
426
|
+
subscriptions: new WeakMap,
|
|
427
|
+
subscriptionsRequireEqualCheck: new WeakMap,
|
|
428
|
+
stateConsumers: new WeakMap,
|
|
429
|
+
stateDependencies: new WeakMap,
|
|
430
|
+
scopes: {}
|
|
431
|
+
};
|
|
282
432
|
};
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
});
|
|
291
|
-
promise.__isEmptyAtomPromise__ = true;
|
|
292
|
-
promise.__resolveEmptyAtomPromise__ = promiseResolve;
|
|
293
|
-
return promise;
|
|
294
|
-
} else if (typeof atom3.defaultValue === "function") {
|
|
295
|
-
const value = atom3.defaultValue();
|
|
296
|
-
if (isPromiseLike(value)) {
|
|
297
|
-
value.then((resolvedValue) => {
|
|
298
|
-
data.values.set(atom3, resolvedValue);
|
|
299
|
-
propagateUpdatedAtoms([atom3], data);
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
return value;
|
|
433
|
+
function createStoreData(id, parent) {
|
|
434
|
+
if (parent) {
|
|
435
|
+
return {
|
|
436
|
+
...generateStoreData(id),
|
|
437
|
+
parent,
|
|
438
|
+
scopeConsumers: parent ? new Set : undefined
|
|
439
|
+
};
|
|
303
440
|
} else {
|
|
304
|
-
return
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
var initAtom = (atom3, data) => {
|
|
308
|
-
const value = getAtomInitValue(atom3, data);
|
|
309
|
-
data.values.set(atom3, value);
|
|
310
|
-
if (atom3.onInit)
|
|
311
|
-
atom3.onInit((newVal) => {
|
|
312
|
-
setAtom(atom3, newVal, data);
|
|
313
|
-
});
|
|
314
|
-
return value;
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
// src/utils/isSelector.ts
|
|
318
|
-
var isSelector = (state) => Object.hasOwn(state, "get");
|
|
319
|
-
|
|
320
|
-
// src/utils/isFamily.ts
|
|
321
|
-
var isFamily = (state) => Object.hasOwn(state, "_map");
|
|
322
|
-
|
|
323
|
-
// src/lib/getState.ts
|
|
324
|
-
var getState2 = (state, data) => {
|
|
325
|
-
if (data.values.has(state))
|
|
326
|
-
return data.values.get(state);
|
|
327
|
-
if (isAtom(state))
|
|
328
|
-
return initAtom(state, data);
|
|
329
|
-
if (isSelector(state))
|
|
330
|
-
return initSelector(state, data);
|
|
331
|
-
if (isFamily(state)) {
|
|
332
|
-
const res = [];
|
|
333
|
-
for (const atom3 of state._map.values()) {
|
|
334
|
-
res.push([atom3.familyKey, getState2(atom3, data)]);
|
|
335
|
-
}
|
|
336
|
-
return res;
|
|
441
|
+
return generateStoreData(id);
|
|
337
442
|
}
|
|
338
|
-
|
|
339
|
-
};
|
|
443
|
+
}
|
|
340
444
|
|
|
341
445
|
// src/lib/resetAtom.ts
|
|
342
|
-
var resetAtom = (
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
446
|
+
var resetAtom = (atom, data) => {
|
|
447
|
+
let value = getAtomInitValue(atom, data);
|
|
448
|
+
data.values.set(atom, value);
|
|
449
|
+
if (!isPromiseLike(value)) {
|
|
450
|
+
propagateUpdatedAtoms([atom], data);
|
|
346
451
|
}
|
|
347
|
-
return
|
|
452
|
+
return value;
|
|
348
453
|
};
|
|
349
454
|
|
|
455
|
+
// src/utils/isFamily.ts
|
|
456
|
+
var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
|
|
457
|
+
|
|
350
458
|
// src/lib/unsubscribe.ts
|
|
351
|
-
var unsubscribe = (state, subscription, data, mount) => {
|
|
459
|
+
var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
|
|
352
460
|
const subscribers = data.subscriptions.get(state);
|
|
353
461
|
if (subscribers) {
|
|
354
462
|
subscribers.delete(subscription);
|
|
@@ -364,10 +472,15 @@ var unsubscribe = (state, subscription, data, mount) => {
|
|
|
364
472
|
data.subscriptionsRequireEqualCheck.delete(state);
|
|
365
473
|
}
|
|
366
474
|
}
|
|
475
|
+
if (subscribers.size === 0) {
|
|
476
|
+
if (maxAgeCleanup)
|
|
477
|
+
maxAgeCleanup();
|
|
478
|
+
data.subscriptions.delete(state);
|
|
479
|
+
}
|
|
367
480
|
if (mount) {
|
|
368
481
|
if (subscribers.size === mount.mountSubscriptions.size) {
|
|
369
|
-
if (
|
|
370
|
-
|
|
482
|
+
if (typeof mount.onUnmount === "function") {
|
|
483
|
+
mount.onUnmount();
|
|
371
484
|
}
|
|
372
485
|
}
|
|
373
486
|
}
|
|
@@ -381,10 +494,24 @@ var initSubscribers = (state, data) => {
|
|
|
381
494
|
return set;
|
|
382
495
|
};
|
|
383
496
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
384
|
-
|
|
497
|
+
let parentUnsubscribe;
|
|
498
|
+
if ("parent" in data && (!data.values.has(state) && isAtom(state) || isAtomFamily(state))) {
|
|
499
|
+
const originalCallback = callback;
|
|
500
|
+
parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
|
|
501
|
+
callback = (arg) => {
|
|
502
|
+
if (parentUnsubscribe) {
|
|
503
|
+
parentUnsubscribe();
|
|
504
|
+
parentUnsubscribe = undefined;
|
|
505
|
+
}
|
|
506
|
+
originalCallback(arg);
|
|
507
|
+
};
|
|
508
|
+
} else if (!data.values.has(state) && isAtom(state)) {
|
|
509
|
+
initAtom(state, data);
|
|
510
|
+
}
|
|
385
511
|
if (isSelector(state) && !data.values.has(state)) {
|
|
386
512
|
initSelector(state, data);
|
|
387
513
|
}
|
|
514
|
+
const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
|
|
388
515
|
let subscription;
|
|
389
516
|
if (isFamily(state)) {
|
|
390
517
|
subscription = {
|
|
@@ -400,34 +527,67 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
400
527
|
}
|
|
401
528
|
subscribers.add(subscription);
|
|
402
529
|
let mount;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
530
|
+
let maxAgeCleanup;
|
|
531
|
+
if (subscribers.size === 1) {
|
|
532
|
+
if (isAtom(state) && state.maxAge) {
|
|
533
|
+
let timeout;
|
|
534
|
+
const interval = setInterval(() => {
|
|
535
|
+
let value = getAtomInitValue(state, data);
|
|
536
|
+
if (isPromiseLike(value)) {
|
|
537
|
+
if (state.staleWhileRevalidate) {
|
|
538
|
+
const oldValue = data.values.get(state);
|
|
539
|
+
timeout = setTimeout(() => {
|
|
540
|
+
const nowValue = data.values.get(state);
|
|
541
|
+
console.log("todo", oldValue);
|
|
542
|
+
}, state.staleWhileRevalidate);
|
|
543
|
+
value.then((res) => clearTimeout(timeout));
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
data.values.set(state, value);
|
|
547
|
+
propagateUpdatedAtoms([state], data);
|
|
548
|
+
}
|
|
549
|
+
}, state.maxAge);
|
|
550
|
+
maxAgeCleanup = () => {
|
|
551
|
+
clearInterval(interval);
|
|
552
|
+
if (timeout)
|
|
553
|
+
clearTimeout(timeout);
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (state.onMount) {
|
|
557
|
+
const store = storeFromStoreData(data);
|
|
558
|
+
const mountSubscriptions = new Set;
|
|
559
|
+
const originalSub = store.sub;
|
|
560
|
+
store.sub = (state2, callback2) => {
|
|
561
|
+
mountSubscriptions.add(callback2);
|
|
562
|
+
return originalSub(state2, callback2);
|
|
563
|
+
};
|
|
564
|
+
mount = {
|
|
565
|
+
onUnmount: state.onMount(store, state),
|
|
566
|
+
mountSubscriptions
|
|
567
|
+
};
|
|
568
|
+
}
|
|
415
569
|
}
|
|
416
570
|
if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
|
|
417
571
|
data.subscriptionsRequireEqualCheck.set(state, true);
|
|
418
572
|
}
|
|
419
|
-
return () =>
|
|
573
|
+
return () => {
|
|
574
|
+
if (parentUnsubscribe) {
|
|
575
|
+
parentUnsubscribe();
|
|
576
|
+
}
|
|
577
|
+
unsubscribe(state, subscription, data, mount, maxAgeCleanup);
|
|
578
|
+
};
|
|
420
579
|
};
|
|
421
580
|
|
|
422
581
|
// src/lib/setAtoms.ts
|
|
423
|
-
import equal4 from "fast-deep-equal";
|
|
424
582
|
var setAtoms = (pairs, data) => {
|
|
425
583
|
const updatedAtoms = [];
|
|
426
|
-
for (let [
|
|
427
|
-
const currentValue =
|
|
428
|
-
if (!
|
|
429
|
-
updatedAtoms.push(
|
|
430
|
-
|
|
584
|
+
for (let [atom, value] of pairs) {
|
|
585
|
+
const currentValue = getState(atom, data);
|
|
586
|
+
if (!atom.equal(currentValue, value)) {
|
|
587
|
+
updatedAtoms.push(atom);
|
|
588
|
+
if (atom.onSet)
|
|
589
|
+
atom.onSet(value, data);
|
|
590
|
+
data.values.set(atom, value);
|
|
431
591
|
}
|
|
432
592
|
}
|
|
433
593
|
propagateUpdatedAtoms(updatedAtoms, data);
|
|
@@ -454,14 +614,27 @@ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache)
|
|
|
454
614
|
}
|
|
455
615
|
}
|
|
456
616
|
};
|
|
457
|
-
var
|
|
458
|
-
let
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
617
|
+
var captureScopedTransaction = (scopedData, parentGet) => {
|
|
618
|
+
let txn;
|
|
619
|
+
transaction((scopedTxn) => {
|
|
620
|
+
txn = scopedTxn;
|
|
621
|
+
}, scopedData, false, parentGet);
|
|
622
|
+
return txn;
|
|
623
|
+
};
|
|
624
|
+
var transaction = (callback, data, autoCommit = true, parentScopeGet) => {
|
|
625
|
+
const txnAtomMap = new Map;
|
|
626
|
+
const txnSelectorCache = new Map;
|
|
627
|
+
const txnSubscribers = new Map;
|
|
628
|
+
const dirtySelectors = new Set;
|
|
629
|
+
let scopedTransactions;
|
|
462
630
|
const txnGet = (state) => {
|
|
463
631
|
if (isAtom(state)) {
|
|
464
|
-
|
|
632
|
+
if (txnAtomMap.has(state)) {
|
|
633
|
+
return txnAtomMap.get(state);
|
|
634
|
+
} else if (parentScopeGet) {
|
|
635
|
+
return parentScopeGet(state);
|
|
636
|
+
}
|
|
637
|
+
return getState(state, data);
|
|
465
638
|
} else if (isSelector(state)) {
|
|
466
639
|
if (txnSelectorCache.has(state)) {
|
|
467
640
|
return txnSelectorCache.get(state);
|
|
@@ -470,7 +643,7 @@ var transaction = (callback, data) => {
|
|
|
470
643
|
const res = state.get((s) => {
|
|
471
644
|
deps.add(s);
|
|
472
645
|
return txnGet(s);
|
|
473
|
-
});
|
|
646
|
+
}, data.id);
|
|
474
647
|
for (const dep of deps) {
|
|
475
648
|
if (!txnSubscribers.has(dep)) {
|
|
476
649
|
txnSubscribers.set(dep, new Set);
|
|
@@ -479,127 +652,435 @@ var transaction = (callback, data) => {
|
|
|
479
652
|
}
|
|
480
653
|
txnSelectorCache.set(state, res);
|
|
481
654
|
return res;
|
|
655
|
+
} else if (isAtomFamily(state)) {
|
|
656
|
+
return txnGet(state.__keysSelector);
|
|
482
657
|
} else {
|
|
483
658
|
throw new Error("Unsupported state");
|
|
484
659
|
}
|
|
485
660
|
};
|
|
486
|
-
const txnSet = (
|
|
487
|
-
if (!isAtom(
|
|
661
|
+
const txnSet = (atom, value) => {
|
|
662
|
+
if (!isAtom(atom))
|
|
488
663
|
throw new Error("Not an atom");
|
|
489
|
-
if (
|
|
490
|
-
const currentValue = txnGet(
|
|
664
|
+
if (isFunction(value)) {
|
|
665
|
+
const currentValue = txnGet(atom);
|
|
491
666
|
value = value(currentValue);
|
|
492
667
|
}
|
|
493
|
-
for (const selector of findDependencies(
|
|
668
|
+
for (const selector of findDependencies(atom, data)) {
|
|
494
669
|
dirtySelectors.add(selector);
|
|
495
670
|
txnSelectorCache.delete(selector);
|
|
496
671
|
}
|
|
497
|
-
if (txnSubscribers.get(
|
|
498
|
-
recursivlyResetTxnSelectorCache(
|
|
672
|
+
if (txnSubscribers.get(atom)?.size) {
|
|
673
|
+
recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
|
|
674
|
+
}
|
|
675
|
+
txnAtomMap.set(atom, value);
|
|
676
|
+
if (isFamilyAtom(atom)) {
|
|
677
|
+
const currentKeySet = txnGet(atom.family.__keysAtom);
|
|
678
|
+
if (!currentKeySet.has(atom.familyKey)) {
|
|
679
|
+
const newSet = new Set(currentKeySet);
|
|
680
|
+
newSet.add(atom.familyKey);
|
|
681
|
+
txnSet(atom.family.__keysAtom, newSet);
|
|
682
|
+
}
|
|
499
683
|
}
|
|
500
|
-
|
|
684
|
+
return value;
|
|
501
685
|
};
|
|
502
|
-
const txnReset = (
|
|
503
|
-
const value = getAtomInitValue(
|
|
504
|
-
txnAtomMap.set(
|
|
686
|
+
const txnReset = (atom) => {
|
|
687
|
+
const value = getAtomInitValue(atom, data);
|
|
688
|
+
txnAtomMap.set(atom, value);
|
|
505
689
|
return value;
|
|
506
690
|
};
|
|
507
691
|
const commit = () => {
|
|
508
692
|
setAtoms(txnAtomMap, data);
|
|
509
693
|
dirtySelectors.clear();
|
|
694
|
+
if (scopedTransactions) {
|
|
695
|
+
for (const scopedTxn of Object.values(scopedTransactions)) {
|
|
696
|
+
scopedTxn.commit();
|
|
697
|
+
}
|
|
698
|
+
}
|
|
510
699
|
};
|
|
511
|
-
const result = callback(
|
|
512
|
-
|
|
700
|
+
const result = callback({
|
|
701
|
+
set: txnSet,
|
|
702
|
+
get: txnGet,
|
|
703
|
+
reset: txnReset,
|
|
704
|
+
commit,
|
|
705
|
+
scope: (scopeId, callback2) => {
|
|
706
|
+
if (scopeId in data.scopes) {
|
|
707
|
+
const scopedData = data.scopes[scopeId];
|
|
708
|
+
if (scopedTransactions === undefined) {
|
|
709
|
+
scopedTransactions = {};
|
|
710
|
+
}
|
|
711
|
+
if (scopedTransactions[scopeId] === undefined) {
|
|
712
|
+
scopedTransactions[scopeId] = captureScopedTransaction(scopedData, txnGet);
|
|
713
|
+
}
|
|
714
|
+
return callback2(scopedTransactions[scopeId]);
|
|
715
|
+
} else {
|
|
716
|
+
throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
data
|
|
720
|
+
});
|
|
721
|
+
if (autoCommit)
|
|
722
|
+
commit();
|
|
513
723
|
return result;
|
|
514
724
|
};
|
|
515
725
|
|
|
516
726
|
// src/lib/storeFromStoreData.ts
|
|
517
|
-
var
|
|
518
|
-
|
|
727
|
+
var SelectorProvidedToSetError = `Invalid state object passed to set().
|
|
728
|
+
You provided a \`selector\`.
|
|
729
|
+
Only \`atom\` cam be set.
|
|
730
|
+
`;
|
|
731
|
+
var InvalidStateSetError = `Invalid state object passed to set().
|
|
732
|
+
Only \`atom\` can be set.
|
|
733
|
+
`;
|
|
734
|
+
function storeFromStoreData(data, detach) {
|
|
735
|
+
const get = (state) => getState(state, data);
|
|
519
736
|
const set = (state, value) => {
|
|
520
|
-
if (
|
|
521
|
-
|
|
522
|
-
|
|
737
|
+
if (isAtom(state))
|
|
738
|
+
return setAtom(state, value, data);
|
|
739
|
+
if (isSelector(state))
|
|
740
|
+
throw new Error(SelectorProvidedToSetError);
|
|
741
|
+
throw new Error(InvalidStateSetError);
|
|
523
742
|
};
|
|
524
|
-
const reset = (
|
|
743
|
+
const reset = (atom) => resetAtom(atom, data);
|
|
525
744
|
const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
|
|
526
745
|
const txn = (callback) => transaction(callback, data);
|
|
746
|
+
const scope = (scopeId) => {
|
|
747
|
+
let scopedStoreData;
|
|
748
|
+
if (scopeId in data.scopes) {
|
|
749
|
+
scopedStoreData = data.scopes[scopeId];
|
|
750
|
+
} else {
|
|
751
|
+
scopedStoreData = createStoreData(scopeId, data);
|
|
752
|
+
data.scopes[scopeId] = scopedStoreData;
|
|
753
|
+
}
|
|
754
|
+
const detach2 = () => {
|
|
755
|
+
scopedStoreData.scopeConsumers.delete(detach2);
|
|
756
|
+
if (scopedStoreData.scopeConsumers.size === 0) {
|
|
757
|
+
delete data.scopes[scopeId];
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
scopedStoreData.scopeConsumers.add(detach2);
|
|
761
|
+
const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
|
|
762
|
+
return newStore;
|
|
763
|
+
};
|
|
764
|
+
if (detach) {
|
|
765
|
+
return {
|
|
766
|
+
get,
|
|
767
|
+
set,
|
|
768
|
+
sub,
|
|
769
|
+
txn,
|
|
770
|
+
reset,
|
|
771
|
+
data,
|
|
772
|
+
scope,
|
|
773
|
+
detach
|
|
774
|
+
};
|
|
775
|
+
} else {
|
|
776
|
+
return {
|
|
777
|
+
get,
|
|
778
|
+
set,
|
|
779
|
+
sub,
|
|
780
|
+
txn,
|
|
781
|
+
reset,
|
|
782
|
+
data,
|
|
783
|
+
scope
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// src/store.ts
|
|
789
|
+
var store = (id) => {
|
|
790
|
+
const data = createStoreData(id);
|
|
791
|
+
return storeFromStoreData(data);
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
// src/globalStore.ts
|
|
795
|
+
var globalStore = Object.assign(store("valdres-global-store"), {
|
|
796
|
+
atoms: new Map,
|
|
797
|
+
atomFamilies: new Map
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// src/lib/globalAtom.ts
|
|
801
|
+
var globalAtom = (defaultValue, options) => {
|
|
802
|
+
const stores = new Set;
|
|
803
|
+
let value;
|
|
804
|
+
let initialized = false;
|
|
805
|
+
let onReset;
|
|
806
|
+
if (options.onSet)
|
|
807
|
+
throw new Error("onSet on globalAtom is currently not supported");
|
|
808
|
+
const onInit = (setSelf2, data) => {
|
|
809
|
+
setSelf2(globalStore.get(atom));
|
|
810
|
+
if (!initialized && options.onInit) {
|
|
811
|
+
onReset = options.onInit((newVal) => {
|
|
812
|
+
setSelf2(newVal);
|
|
813
|
+
value = newVal;
|
|
814
|
+
}, data);
|
|
815
|
+
initialized = true;
|
|
816
|
+
}
|
|
817
|
+
stores.add(data);
|
|
818
|
+
};
|
|
819
|
+
const onSet = (newValue, currentStore) => {
|
|
820
|
+
value = newValue;
|
|
821
|
+
if (stores.size > 1) {
|
|
822
|
+
for (const store2 of stores) {
|
|
823
|
+
if (store2.id !== currentStore.id) {
|
|
824
|
+
setAtom(atom, value, store2, true);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
const getSelf = () => globalStore.get(atom);
|
|
830
|
+
const setSelf = (newValue) => globalStore.set(atom, newValue);
|
|
831
|
+
const resetSelf = () => {
|
|
832
|
+
value = undefined;
|
|
833
|
+
initialized = false;
|
|
834
|
+
for (const store2 of stores) {
|
|
835
|
+
if (store2.stateDependencies.has(atom)) {
|
|
836
|
+
throw new Error("TODO: Reset support for stateDependencies");
|
|
837
|
+
}
|
|
838
|
+
store2.values.delete(atom);
|
|
839
|
+
store2.expiredValues.delete(atom);
|
|
840
|
+
propagateUpdatedAtoms([atom], store2);
|
|
841
|
+
stores.delete(store2);
|
|
842
|
+
onReset?.();
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
const atom = {
|
|
846
|
+
equal,
|
|
847
|
+
...options,
|
|
848
|
+
defaultValue,
|
|
849
|
+
name: options?.name,
|
|
850
|
+
onInit,
|
|
851
|
+
onSet,
|
|
852
|
+
setSelf,
|
|
853
|
+
getSelf,
|
|
854
|
+
resetSelf,
|
|
855
|
+
get stores() {
|
|
856
|
+
return stores;
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
return atom;
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
// src/atom.ts
|
|
863
|
+
function atom(defaultValue, options) {
|
|
864
|
+
if (!options)
|
|
865
|
+
return { equal, defaultValue };
|
|
866
|
+
if (options.global) {
|
|
867
|
+
return globalAtom(defaultValue, options);
|
|
868
|
+
}
|
|
527
869
|
return {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
870
|
+
equal,
|
|
871
|
+
defaultValue,
|
|
872
|
+
...options
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
// src/lib/atomFamilyAtom.ts
|
|
876
|
+
function atomFamilyAtom(defaultValue, options) {
|
|
877
|
+
if (options.global) {
|
|
878
|
+
return globalAtom(defaultValue, options);
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
...options,
|
|
882
|
+
defaultValue
|
|
534
883
|
};
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// src/lib/stableStringify.ts
|
|
887
|
+
var stableStringifyRecurse = (x, key) => {
|
|
888
|
+
if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
|
|
889
|
+
return `"${x}"`;
|
|
890
|
+
}
|
|
891
|
+
switch (typeof x) {
|
|
892
|
+
case "undefined":
|
|
893
|
+
return "";
|
|
894
|
+
case "boolean":
|
|
895
|
+
return x ? "true" : "false";
|
|
896
|
+
case "number":
|
|
897
|
+
case "symbol":
|
|
898
|
+
return String(x);
|
|
899
|
+
case "string":
|
|
900
|
+
return JSON.stringify(x);
|
|
901
|
+
case "function":
|
|
902
|
+
return `__FUNCTION(${x.toString()})__`;
|
|
903
|
+
}
|
|
904
|
+
if (x === null) {
|
|
905
|
+
return "null";
|
|
906
|
+
}
|
|
907
|
+
if (typeof x !== "object") {
|
|
908
|
+
return JSON.stringify(x) ?? "";
|
|
909
|
+
}
|
|
910
|
+
if (isPromiseLike(x)) {
|
|
911
|
+
return "__PROMISE__";
|
|
912
|
+
}
|
|
913
|
+
if (Array.isArray(x)) {
|
|
914
|
+
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
915
|
+
}
|
|
916
|
+
if (typeof x.toJSON === "function") {
|
|
917
|
+
return stableStringifyRecurse(x.toJSON(key), key);
|
|
918
|
+
}
|
|
919
|
+
if (x instanceof Map) {
|
|
920
|
+
const obj = {};
|
|
921
|
+
for (const [k, v] of x) {
|
|
922
|
+
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
923
|
+
}
|
|
924
|
+
return stableStringifyRecurse(obj, key);
|
|
925
|
+
}
|
|
926
|
+
if (x instanceof Set) {
|
|
927
|
+
return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
|
|
928
|
+
}
|
|
929
|
+
if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
|
|
930
|
+
return stableStringifyRecurse(Array.from(x), key);
|
|
931
|
+
}
|
|
932
|
+
return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
|
|
933
|
+
};
|
|
934
|
+
var stableStringify = (x) => {
|
|
935
|
+
if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
|
|
936
|
+
return x;
|
|
937
|
+
return stableStringifyRecurse(x);
|
|
535
938
|
};
|
|
536
939
|
|
|
537
|
-
// src/
|
|
538
|
-
var
|
|
539
|
-
|
|
540
|
-
|
|
940
|
+
// src/selector.ts
|
|
941
|
+
var selector = (get, options) => {
|
|
942
|
+
if (!options)
|
|
943
|
+
return { equal, get };
|
|
944
|
+
return { equal, ...options, get };
|
|
541
945
|
};
|
|
946
|
+
|
|
947
|
+
// src/lib/createAtomFamily.ts
|
|
948
|
+
var createOptions = (options = {}, family, familyKey, keyStringified) => {
|
|
949
|
+
if (options.name) {
|
|
950
|
+
return {
|
|
951
|
+
equal,
|
|
952
|
+
...options,
|
|
953
|
+
name: options?.name + "_" + keyStringified,
|
|
954
|
+
family,
|
|
955
|
+
familyKey
|
|
956
|
+
};
|
|
957
|
+
} else {
|
|
958
|
+
return { equal, ...options, family, familyKey };
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
var handleDefaultValue = (defaultValue, key) => {
|
|
962
|
+
if (isSelectorFamily(defaultValue))
|
|
963
|
+
return defaultValue(key);
|
|
964
|
+
if (typeof defaultValue === "function")
|
|
965
|
+
return () => defaultValue(key);
|
|
966
|
+
return defaultValue;
|
|
967
|
+
};
|
|
968
|
+
var createAtomFamily = (defaultValue, options) => {
|
|
969
|
+
const map = new Map;
|
|
970
|
+
const keysAtom = atom(new Set);
|
|
971
|
+
const atomFamily = Object.assign((key) => {
|
|
972
|
+
const keyStringified = stableStringify(key);
|
|
973
|
+
if (map.has(keyStringified)) {
|
|
974
|
+
return map.get(keyStringified);
|
|
975
|
+
}
|
|
976
|
+
const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily, Object.freeze(key), keyStringified));
|
|
977
|
+
map.set(keyStringified, familyAtom);
|
|
978
|
+
return familyAtom;
|
|
979
|
+
}, {
|
|
980
|
+
__valdresAtomFamilyMap: map,
|
|
981
|
+
release: (key) => map.delete(key),
|
|
982
|
+
__keysAtom: keysAtom,
|
|
983
|
+
__keysSelector: selector((get) => Array.from(get(keysAtom)))
|
|
984
|
+
});
|
|
985
|
+
if (options?.name)
|
|
986
|
+
Object.defineProperty(atomFamily, "name", {
|
|
987
|
+
value: options.name,
|
|
988
|
+
writable: false
|
|
989
|
+
});
|
|
990
|
+
return atomFamily;
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
// src/lib/createGlobalAtomFamily.ts
|
|
994
|
+
var createGlobalAtomFamily = (defaultValue, options) => {
|
|
995
|
+
if (!options.name)
|
|
996
|
+
throw new Error(`Missing name for global atomFamiliy`);
|
|
997
|
+
if (globalStore.atomFamilies.has(options.name)) {
|
|
998
|
+
return globalStore.atomFamilies.get(options.name);
|
|
999
|
+
}
|
|
1000
|
+
const family = createAtomFamily(defaultValue, options);
|
|
1001
|
+
globalStore.atomFamilies.set(options.name, family);
|
|
1002
|
+
return family;
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
// src/atomFamily.ts
|
|
1006
|
+
function atomFamily(defaultValue, options) {
|
|
1007
|
+
if (options?.global)
|
|
1008
|
+
return createGlobalAtomFamily(defaultValue, options);
|
|
1009
|
+
return createAtomFamily(defaultValue, options);
|
|
1010
|
+
}
|
|
542
1011
|
// src/createStoreWithSelectorSet.ts
|
|
543
|
-
var setSelector = (
|
|
544
|
-
return
|
|
1012
|
+
var setSelector = (selector2, values, store2) => {
|
|
1013
|
+
return selector2.set(store2.set, store2.get, store2.reset, ...values);
|
|
545
1014
|
};
|
|
546
1015
|
var createStoreWithSelectorSet = (id) => {
|
|
547
1016
|
const data = createStoreData(id);
|
|
548
|
-
const
|
|
549
|
-
|
|
1017
|
+
const store2 = storeFromStoreData(data);
|
|
1018
|
+
store2.set = (state, value, ...rest) => {
|
|
550
1019
|
if (isAtom(state))
|
|
551
1020
|
return setAtom(state, value, data);
|
|
552
1021
|
if (isSelector(state))
|
|
553
|
-
return setSelector(state, [value, ...rest],
|
|
1022
|
+
return setSelector(state, [value, ...rest], store2);
|
|
554
1023
|
throw new Error("Invalid state object");
|
|
555
1024
|
};
|
|
556
|
-
|
|
557
|
-
return
|
|
1025
|
+
store2.kind = "storeWithSelectorSet";
|
|
1026
|
+
return store2;
|
|
558
1027
|
};
|
|
559
|
-
// src/getDefaultStore.ts
|
|
560
|
-
if (!globalThis._valdresStore) {
|
|
561
|
-
globalThis._valdresStore = createStore("default");
|
|
562
|
-
}
|
|
563
|
-
var getDefaultStore = () => globalThis._valdresStore;
|
|
564
|
-
var resetDefaultStore = () => globalThis._valdresStore = createStore();
|
|
565
|
-
// src/selector.ts
|
|
566
|
-
var selector = (get, debugLabel) => ({
|
|
567
|
-
get,
|
|
568
|
-
debugLabel
|
|
569
|
-
});
|
|
570
1028
|
// src/selectorFamily.ts
|
|
571
|
-
var
|
|
1029
|
+
var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
|
|
1030
|
+
if (options.name) {
|
|
1031
|
+
return {
|
|
1032
|
+
equal,
|
|
1033
|
+
...options,
|
|
1034
|
+
name: options?.name + "_" + keyStringified,
|
|
1035
|
+
family,
|
|
1036
|
+
familyKey
|
|
1037
|
+
};
|
|
1038
|
+
} else {
|
|
1039
|
+
return { equal, ...options, family, familyKey };
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
var selectorFamily = (get, options) => {
|
|
572
1043
|
const map = new Map;
|
|
573
1044
|
const selectorFamily2 = (key) => {
|
|
574
|
-
|
|
575
|
-
try {
|
|
576
|
-
keyStringified = stableStringify(key);
|
|
577
|
-
} catch (e) {
|
|
578
|
-
console.log(`errro`, { key, debugLabel, e });
|
|
579
|
-
throw e;
|
|
580
|
-
}
|
|
1045
|
+
const keyStringified = stableStringify(key);
|
|
581
1046
|
if (map.has(keyStringified))
|
|
582
1047
|
return map.get(keyStringified);
|
|
583
|
-
const
|
|
584
|
-
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
|
|
585
|
-
newSelector.family = selectorFamily2;
|
|
1048
|
+
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
|
|
586
1049
|
map.set(keyStringified, newSelector);
|
|
587
1050
|
return newSelector;
|
|
588
1051
|
};
|
|
589
|
-
selectorFamily2.
|
|
1052
|
+
selectorFamily2.__valdresSelectorFamilyMap = map;
|
|
1053
|
+
if (options?.name)
|
|
1054
|
+
Object.defineProperty(selectorFamily2, "name", {
|
|
1055
|
+
value: options.name,
|
|
1056
|
+
writable: false
|
|
1057
|
+
});
|
|
590
1058
|
return selectorFamily2;
|
|
591
1059
|
};
|
|
1060
|
+
// src/utils/isFamilySelector.ts
|
|
1061
|
+
var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
1062
|
+
|
|
1063
|
+
// src/index.ts
|
|
1064
|
+
if (globalThis.__valdres__) {
|
|
1065
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${version}`);
|
|
1066
|
+
} else {
|
|
1067
|
+
globalThis.__valdres__ = version;
|
|
1068
|
+
}
|
|
592
1069
|
export {
|
|
1070
|
+
store,
|
|
593
1071
|
selectorFamily,
|
|
594
1072
|
selector,
|
|
595
|
-
|
|
1073
|
+
isSelectorFamily,
|
|
596
1074
|
isSelector,
|
|
597
1075
|
isPromiseLike,
|
|
1076
|
+
isFamilyState,
|
|
1077
|
+
isFamilySelector,
|
|
1078
|
+
isFamilyAtom,
|
|
598
1079
|
isFamily,
|
|
1080
|
+
isAtomFamily,
|
|
599
1081
|
isAtom,
|
|
600
|
-
|
|
1082
|
+
globalStore,
|
|
601
1083
|
createStoreWithSelectorSet,
|
|
602
|
-
createStore,
|
|
603
1084
|
atomFamily,
|
|
604
1085
|
atom
|
|
605
1086
|
};
|