valdres 0.2.0-alpha.6 → 0.2.0-alpha.61
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 +769 -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 +8 -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
|
|
441
|
+
return generateStoreData(id);
|
|
305
442
|
}
|
|
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;
|
|
337
|
-
}
|
|
338
|
-
throw new Error("Invalid object passed to get");
|
|
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,36 @@ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache)
|
|
|
454
614
|
}
|
|
455
615
|
}
|
|
456
616
|
};
|
|
457
|
-
var
|
|
458
|
-
let
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
617
|
+
var captureScopedTransaction = (scopedData, parentGetFromTxnOrData) => {
|
|
618
|
+
let txn;
|
|
619
|
+
transaction((scopedTxn) => {
|
|
620
|
+
txn = scopedTxn;
|
|
621
|
+
}, scopedData, false, parentGetFromTxnOrData);
|
|
622
|
+
return txn;
|
|
623
|
+
};
|
|
624
|
+
var transaction = (callback, data, autoCommit = true, parentGetFromTxnOrData) => {
|
|
625
|
+
const txnAtomMap = new Map;
|
|
626
|
+
const txnSelectorCache = new Map;
|
|
627
|
+
const txnSubscribers = new Map;
|
|
628
|
+
const dirtySelectors = new Set;
|
|
629
|
+
let scopedTransactions;
|
|
630
|
+
const getFromTxnOrData = (state) => {
|
|
631
|
+
if (txnAtomMap.has(state)) {
|
|
632
|
+
return txnAtomMap.get(state);
|
|
633
|
+
}
|
|
634
|
+
if (data.values.has(state)) {
|
|
635
|
+
return data.values.get(state);
|
|
636
|
+
}
|
|
637
|
+
if (parentGetFromTxnOrData) {
|
|
638
|
+
return parentGetFromTxnOrData(state);
|
|
639
|
+
}
|
|
640
|
+
};
|
|
462
641
|
const txnGet = (state) => {
|
|
463
642
|
if (isAtom(state)) {
|
|
464
|
-
|
|
643
|
+
const value = getFromTxnOrData(state);
|
|
644
|
+
if (value)
|
|
645
|
+
return value;
|
|
646
|
+
return getState(state, data);
|
|
465
647
|
} else if (isSelector(state)) {
|
|
466
648
|
if (txnSelectorCache.has(state)) {
|
|
467
649
|
return txnSelectorCache.get(state);
|
|
@@ -470,7 +652,7 @@ var transaction = (callback, data) => {
|
|
|
470
652
|
const res = state.get((s) => {
|
|
471
653
|
deps.add(s);
|
|
472
654
|
return txnGet(s);
|
|
473
|
-
});
|
|
655
|
+
}, data.id);
|
|
474
656
|
for (const dep of deps) {
|
|
475
657
|
if (!txnSubscribers.has(dep)) {
|
|
476
658
|
txnSubscribers.set(dep, new Set);
|
|
@@ -479,127 +661,435 @@ var transaction = (callback, data) => {
|
|
|
479
661
|
}
|
|
480
662
|
txnSelectorCache.set(state, res);
|
|
481
663
|
return res;
|
|
664
|
+
} else if (isAtomFamily(state)) {
|
|
665
|
+
return txnGet(state.__keysSelector);
|
|
482
666
|
} else {
|
|
483
667
|
throw new Error("Unsupported state");
|
|
484
668
|
}
|
|
485
669
|
};
|
|
486
|
-
const txnSet = (
|
|
487
|
-
if (!isAtom(
|
|
670
|
+
const txnSet = (atom, value) => {
|
|
671
|
+
if (!isAtom(atom))
|
|
488
672
|
throw new Error("Not an atom");
|
|
489
|
-
if (
|
|
490
|
-
const currentValue = txnGet(
|
|
673
|
+
if (isFunction(value)) {
|
|
674
|
+
const currentValue = txnGet(atom);
|
|
491
675
|
value = value(currentValue);
|
|
492
676
|
}
|
|
493
|
-
for (const selector of findDependencies(
|
|
677
|
+
for (const selector of findDependencies(atom, data)) {
|
|
494
678
|
dirtySelectors.add(selector);
|
|
495
679
|
txnSelectorCache.delete(selector);
|
|
496
680
|
}
|
|
497
|
-
if (txnSubscribers.get(
|
|
498
|
-
recursivlyResetTxnSelectorCache(
|
|
681
|
+
if (txnSubscribers.get(atom)?.size) {
|
|
682
|
+
recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
|
|
683
|
+
}
|
|
684
|
+
txnAtomMap.set(atom, value);
|
|
685
|
+
if (isFamilyAtom(atom)) {
|
|
686
|
+
const currentKeySet = txnGet(atom.family.__keysAtom);
|
|
687
|
+
if (!currentKeySet.has(atom.familyKey)) {
|
|
688
|
+
const newSet = new Set(currentKeySet);
|
|
689
|
+
newSet.add(atom.familyKey);
|
|
690
|
+
txnSet(atom.family.__keysAtom, newSet);
|
|
691
|
+
}
|
|
499
692
|
}
|
|
500
|
-
|
|
693
|
+
return value;
|
|
501
694
|
};
|
|
502
|
-
const txnReset = (
|
|
503
|
-
const value = getAtomInitValue(
|
|
504
|
-
txnAtomMap.set(
|
|
695
|
+
const txnReset = (atom) => {
|
|
696
|
+
const value = getAtomInitValue(atom, data);
|
|
697
|
+
txnAtomMap.set(atom, value);
|
|
505
698
|
return value;
|
|
506
699
|
};
|
|
507
700
|
const commit = () => {
|
|
508
701
|
setAtoms(txnAtomMap, data);
|
|
509
702
|
dirtySelectors.clear();
|
|
703
|
+
if (scopedTransactions) {
|
|
704
|
+
for (const scopedTxn of Object.values(scopedTransactions)) {
|
|
705
|
+
scopedTxn.commit();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
510
708
|
};
|
|
511
|
-
const result = callback(
|
|
512
|
-
|
|
709
|
+
const result = callback({
|
|
710
|
+
set: txnSet,
|
|
711
|
+
get: txnGet,
|
|
712
|
+
reset: txnReset,
|
|
713
|
+
commit,
|
|
714
|
+
scope: (scopeId, callback2) => {
|
|
715
|
+
if (scopeId in data.scopes) {
|
|
716
|
+
const scopedData = data.scopes[scopeId];
|
|
717
|
+
if (scopedTransactions === undefined) {
|
|
718
|
+
scopedTransactions = {};
|
|
719
|
+
}
|
|
720
|
+
if (scopedTransactions[scopeId] === undefined) {
|
|
721
|
+
scopedTransactions[scopeId] = captureScopedTransaction(scopedData, getFromTxnOrData);
|
|
722
|
+
}
|
|
723
|
+
return callback2(scopedTransactions[scopeId]);
|
|
724
|
+
} else {
|
|
725
|
+
throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
data
|
|
729
|
+
});
|
|
730
|
+
if (autoCommit)
|
|
731
|
+
commit();
|
|
513
732
|
return result;
|
|
514
733
|
};
|
|
515
734
|
|
|
516
735
|
// src/lib/storeFromStoreData.ts
|
|
517
|
-
var
|
|
518
|
-
|
|
736
|
+
var SelectorProvidedToSetError = `Invalid state object passed to set().
|
|
737
|
+
You provided a \`selector\`.
|
|
738
|
+
Only \`atom\` cam be set.
|
|
739
|
+
`;
|
|
740
|
+
var InvalidStateSetError = `Invalid state object passed to set().
|
|
741
|
+
Only \`atom\` can be set.
|
|
742
|
+
`;
|
|
743
|
+
function storeFromStoreData(data, detach) {
|
|
744
|
+
const get = (state) => getState(state, data);
|
|
519
745
|
const set = (state, value) => {
|
|
520
|
-
if (
|
|
521
|
-
|
|
522
|
-
|
|
746
|
+
if (isAtom(state))
|
|
747
|
+
return setAtom(state, value, data);
|
|
748
|
+
if (isSelector(state))
|
|
749
|
+
throw new Error(SelectorProvidedToSetError);
|
|
750
|
+
throw new Error(InvalidStateSetError);
|
|
523
751
|
};
|
|
524
|
-
const reset = (
|
|
752
|
+
const reset = (atom) => resetAtom(atom, data);
|
|
525
753
|
const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
|
|
526
754
|
const txn = (callback) => transaction(callback, data);
|
|
755
|
+
const scope = (scopeId) => {
|
|
756
|
+
let scopedStoreData;
|
|
757
|
+
if (scopeId in data.scopes) {
|
|
758
|
+
scopedStoreData = data.scopes[scopeId];
|
|
759
|
+
} else {
|
|
760
|
+
scopedStoreData = createStoreData(scopeId, data);
|
|
761
|
+
data.scopes[scopeId] = scopedStoreData;
|
|
762
|
+
}
|
|
763
|
+
const detach2 = () => {
|
|
764
|
+
scopedStoreData.scopeConsumers.delete(detach2);
|
|
765
|
+
if (scopedStoreData.scopeConsumers.size === 0) {
|
|
766
|
+
delete data.scopes[scopeId];
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
scopedStoreData.scopeConsumers.add(detach2);
|
|
770
|
+
const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
|
|
771
|
+
return newStore;
|
|
772
|
+
};
|
|
773
|
+
if (detach) {
|
|
774
|
+
return {
|
|
775
|
+
get,
|
|
776
|
+
set,
|
|
777
|
+
sub,
|
|
778
|
+
txn,
|
|
779
|
+
reset,
|
|
780
|
+
data,
|
|
781
|
+
scope,
|
|
782
|
+
detach
|
|
783
|
+
};
|
|
784
|
+
} else {
|
|
785
|
+
return {
|
|
786
|
+
get,
|
|
787
|
+
set,
|
|
788
|
+
sub,
|
|
789
|
+
txn,
|
|
790
|
+
reset,
|
|
791
|
+
data,
|
|
792
|
+
scope
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/store.ts
|
|
798
|
+
var store = (id) => {
|
|
799
|
+
const data = createStoreData(id);
|
|
800
|
+
return storeFromStoreData(data);
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
// src/globalStore.ts
|
|
804
|
+
var globalStore = Object.assign(store("valdres-global-store"), {
|
|
805
|
+
atoms: new Map,
|
|
806
|
+
atomFamilies: new Map
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
// src/lib/globalAtom.ts
|
|
810
|
+
var globalAtom = (defaultValue, options) => {
|
|
811
|
+
const stores = new Set;
|
|
812
|
+
let value;
|
|
813
|
+
let initialized = false;
|
|
814
|
+
let onReset;
|
|
815
|
+
if (options.onSet)
|
|
816
|
+
throw new Error("onSet on globalAtom is currently not supported");
|
|
817
|
+
const onInit = (setSelf2, data) => {
|
|
818
|
+
setSelf2(globalStore.get(atom));
|
|
819
|
+
if (!initialized && options.onInit) {
|
|
820
|
+
onReset = options.onInit((newVal) => {
|
|
821
|
+
setSelf2(newVal);
|
|
822
|
+
value = newVal;
|
|
823
|
+
}, data);
|
|
824
|
+
initialized = true;
|
|
825
|
+
}
|
|
826
|
+
stores.add(data);
|
|
827
|
+
};
|
|
828
|
+
const onSet = (newValue, currentStore) => {
|
|
829
|
+
value = newValue;
|
|
830
|
+
if (stores.size > 1) {
|
|
831
|
+
for (const store2 of stores) {
|
|
832
|
+
if (store2.id !== currentStore.id) {
|
|
833
|
+
setAtom(atom, value, store2, true);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
const getSelf = () => globalStore.get(atom);
|
|
839
|
+
const setSelf = (newValue) => globalStore.set(atom, newValue);
|
|
840
|
+
const resetSelf = () => {
|
|
841
|
+
value = undefined;
|
|
842
|
+
initialized = false;
|
|
843
|
+
for (const store2 of stores) {
|
|
844
|
+
if (store2.stateDependencies.has(atom)) {
|
|
845
|
+
throw new Error("TODO: Reset support for stateDependencies");
|
|
846
|
+
}
|
|
847
|
+
store2.values.delete(atom);
|
|
848
|
+
store2.expiredValues.delete(atom);
|
|
849
|
+
propagateUpdatedAtoms([atom], store2);
|
|
850
|
+
stores.delete(store2);
|
|
851
|
+
onReset?.();
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
const atom = {
|
|
855
|
+
equal,
|
|
856
|
+
...options,
|
|
857
|
+
defaultValue,
|
|
858
|
+
name: options?.name,
|
|
859
|
+
onInit,
|
|
860
|
+
onSet,
|
|
861
|
+
setSelf,
|
|
862
|
+
getSelf,
|
|
863
|
+
resetSelf,
|
|
864
|
+
get stores() {
|
|
865
|
+
return stores;
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
return atom;
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
// src/atom.ts
|
|
872
|
+
function atom(defaultValue, options) {
|
|
873
|
+
if (!options)
|
|
874
|
+
return { equal, defaultValue };
|
|
875
|
+
if (options.global) {
|
|
876
|
+
return globalAtom(defaultValue, options);
|
|
877
|
+
}
|
|
527
878
|
return {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
879
|
+
equal,
|
|
880
|
+
defaultValue,
|
|
881
|
+
...options
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
// src/lib/atomFamilyAtom.ts
|
|
885
|
+
function atomFamilyAtom(defaultValue, options) {
|
|
886
|
+
if (options.global) {
|
|
887
|
+
return globalAtom(defaultValue, options);
|
|
888
|
+
}
|
|
889
|
+
return {
|
|
890
|
+
...options,
|
|
891
|
+
defaultValue
|
|
534
892
|
};
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// src/lib/stableStringify.ts
|
|
896
|
+
var stableStringifyRecurse = (x, key) => {
|
|
897
|
+
if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
|
|
898
|
+
return `"${x}"`;
|
|
899
|
+
}
|
|
900
|
+
switch (typeof x) {
|
|
901
|
+
case "undefined":
|
|
902
|
+
return "";
|
|
903
|
+
case "boolean":
|
|
904
|
+
return x ? "true" : "false";
|
|
905
|
+
case "number":
|
|
906
|
+
case "symbol":
|
|
907
|
+
return String(x);
|
|
908
|
+
case "string":
|
|
909
|
+
return JSON.stringify(x);
|
|
910
|
+
case "function":
|
|
911
|
+
return `__FUNCTION(${x.toString()})__`;
|
|
912
|
+
}
|
|
913
|
+
if (x === null) {
|
|
914
|
+
return "null";
|
|
915
|
+
}
|
|
916
|
+
if (typeof x !== "object") {
|
|
917
|
+
return JSON.stringify(x) ?? "";
|
|
918
|
+
}
|
|
919
|
+
if (isPromiseLike(x)) {
|
|
920
|
+
return "__PROMISE__";
|
|
921
|
+
}
|
|
922
|
+
if (Array.isArray(x)) {
|
|
923
|
+
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
924
|
+
}
|
|
925
|
+
if (typeof x.toJSON === "function") {
|
|
926
|
+
return stableStringifyRecurse(x.toJSON(key), key);
|
|
927
|
+
}
|
|
928
|
+
if (x instanceof Map) {
|
|
929
|
+
const obj = {};
|
|
930
|
+
for (const [k, v] of x) {
|
|
931
|
+
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
932
|
+
}
|
|
933
|
+
return stableStringifyRecurse(obj, key);
|
|
934
|
+
}
|
|
935
|
+
if (x instanceof Set) {
|
|
936
|
+
return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
|
|
937
|
+
}
|
|
938
|
+
if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
|
|
939
|
+
return stableStringifyRecurse(Array.from(x), key);
|
|
940
|
+
}
|
|
941
|
+
return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
|
|
942
|
+
};
|
|
943
|
+
var stableStringify = (x) => {
|
|
944
|
+
if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
|
|
945
|
+
return x;
|
|
946
|
+
return stableStringifyRecurse(x);
|
|
535
947
|
};
|
|
536
948
|
|
|
537
|
-
// src/
|
|
538
|
-
var
|
|
539
|
-
|
|
540
|
-
|
|
949
|
+
// src/selector.ts
|
|
950
|
+
var selector = (get, options) => {
|
|
951
|
+
if (!options)
|
|
952
|
+
return { equal, get };
|
|
953
|
+
return { equal, ...options, get };
|
|
541
954
|
};
|
|
955
|
+
|
|
956
|
+
// src/lib/createAtomFamily.ts
|
|
957
|
+
var createOptions = (options = {}, family, familyKey, keyStringified) => {
|
|
958
|
+
if (options.name) {
|
|
959
|
+
return {
|
|
960
|
+
equal,
|
|
961
|
+
...options,
|
|
962
|
+
name: options?.name + "_" + keyStringified,
|
|
963
|
+
family,
|
|
964
|
+
familyKey
|
|
965
|
+
};
|
|
966
|
+
} else {
|
|
967
|
+
return { equal, ...options, family, familyKey };
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
var handleDefaultValue = (defaultValue, key) => {
|
|
971
|
+
if (isSelectorFamily(defaultValue))
|
|
972
|
+
return defaultValue(key);
|
|
973
|
+
if (typeof defaultValue === "function")
|
|
974
|
+
return () => defaultValue(key);
|
|
975
|
+
return defaultValue;
|
|
976
|
+
};
|
|
977
|
+
var createAtomFamily = (defaultValue, options) => {
|
|
978
|
+
const map = new Map;
|
|
979
|
+
const keysAtom = atom(new Set);
|
|
980
|
+
const atomFamily = Object.assign((key) => {
|
|
981
|
+
const keyStringified = stableStringify(key);
|
|
982
|
+
if (map.has(keyStringified)) {
|
|
983
|
+
return map.get(keyStringified);
|
|
984
|
+
}
|
|
985
|
+
const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily, Object.freeze(key), keyStringified));
|
|
986
|
+
map.set(keyStringified, familyAtom);
|
|
987
|
+
return familyAtom;
|
|
988
|
+
}, {
|
|
989
|
+
__valdresAtomFamilyMap: map,
|
|
990
|
+
release: (key) => map.delete(key),
|
|
991
|
+
__keysAtom: keysAtom,
|
|
992
|
+
__keysSelector: selector((get) => Array.from(get(keysAtom)))
|
|
993
|
+
});
|
|
994
|
+
if (options?.name)
|
|
995
|
+
Object.defineProperty(atomFamily, "name", {
|
|
996
|
+
value: options.name,
|
|
997
|
+
writable: false
|
|
998
|
+
});
|
|
999
|
+
return atomFamily;
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
// src/lib/createGlobalAtomFamily.ts
|
|
1003
|
+
var createGlobalAtomFamily = (defaultValue, options) => {
|
|
1004
|
+
if (!options.name)
|
|
1005
|
+
throw new Error(`Missing name for global atomFamiliy`);
|
|
1006
|
+
if (globalStore.atomFamilies.has(options.name)) {
|
|
1007
|
+
return globalStore.atomFamilies.get(options.name);
|
|
1008
|
+
}
|
|
1009
|
+
const family = createAtomFamily(defaultValue, options);
|
|
1010
|
+
globalStore.atomFamilies.set(options.name, family);
|
|
1011
|
+
return family;
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
// src/atomFamily.ts
|
|
1015
|
+
function atomFamily(defaultValue, options) {
|
|
1016
|
+
if (options?.global)
|
|
1017
|
+
return createGlobalAtomFamily(defaultValue, options);
|
|
1018
|
+
return createAtomFamily(defaultValue, options);
|
|
1019
|
+
}
|
|
542
1020
|
// src/createStoreWithSelectorSet.ts
|
|
543
|
-
var setSelector = (
|
|
544
|
-
return
|
|
1021
|
+
var setSelector = (selector2, values, store2) => {
|
|
1022
|
+
return selector2.set(store2.set, store2.get, store2.reset, ...values);
|
|
545
1023
|
};
|
|
546
1024
|
var createStoreWithSelectorSet = (id) => {
|
|
547
1025
|
const data = createStoreData(id);
|
|
548
|
-
const
|
|
549
|
-
|
|
1026
|
+
const store2 = storeFromStoreData(data);
|
|
1027
|
+
store2.set = (state, value, ...rest) => {
|
|
550
1028
|
if (isAtom(state))
|
|
551
1029
|
return setAtom(state, value, data);
|
|
552
1030
|
if (isSelector(state))
|
|
553
|
-
return setSelector(state, [value, ...rest],
|
|
1031
|
+
return setSelector(state, [value, ...rest], store2);
|
|
554
1032
|
throw new Error("Invalid state object");
|
|
555
1033
|
};
|
|
556
|
-
|
|
557
|
-
return
|
|
1034
|
+
store2.kind = "storeWithSelectorSet";
|
|
1035
|
+
return store2;
|
|
558
1036
|
};
|
|
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
1037
|
// src/selectorFamily.ts
|
|
571
|
-
var
|
|
1038
|
+
var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
|
|
1039
|
+
if (options.name) {
|
|
1040
|
+
return {
|
|
1041
|
+
equal,
|
|
1042
|
+
...options,
|
|
1043
|
+
name: options?.name + "_" + keyStringified,
|
|
1044
|
+
family,
|
|
1045
|
+
familyKey
|
|
1046
|
+
};
|
|
1047
|
+
} else {
|
|
1048
|
+
return { equal, ...options, family, familyKey };
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
var selectorFamily = (get, options) => {
|
|
572
1052
|
const map = new Map;
|
|
573
1053
|
const selectorFamily2 = (key) => {
|
|
574
|
-
|
|
575
|
-
try {
|
|
576
|
-
keyStringified = stableStringify(key);
|
|
577
|
-
} catch (e) {
|
|
578
|
-
console.log(`errro`, { key, debugLabel, e });
|
|
579
|
-
throw e;
|
|
580
|
-
}
|
|
1054
|
+
const keyStringified = stableStringify(key);
|
|
581
1055
|
if (map.has(keyStringified))
|
|
582
1056
|
return map.get(keyStringified);
|
|
583
|
-
const
|
|
584
|
-
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
|
|
585
|
-
newSelector.family = selectorFamily2;
|
|
1057
|
+
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
|
|
586
1058
|
map.set(keyStringified, newSelector);
|
|
587
1059
|
return newSelector;
|
|
588
1060
|
};
|
|
589
|
-
selectorFamily2.
|
|
1061
|
+
selectorFamily2.__valdresSelectorFamilyMap = map;
|
|
1062
|
+
if (options?.name)
|
|
1063
|
+
Object.defineProperty(selectorFamily2, "name", {
|
|
1064
|
+
value: options.name,
|
|
1065
|
+
writable: false
|
|
1066
|
+
});
|
|
590
1067
|
return selectorFamily2;
|
|
591
1068
|
};
|
|
1069
|
+
// src/utils/isFamilySelector.ts
|
|
1070
|
+
var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
1071
|
+
|
|
1072
|
+
// src/index.ts
|
|
1073
|
+
if (globalThis.__valdres__) {
|
|
1074
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${version}`);
|
|
1075
|
+
} else {
|
|
1076
|
+
globalThis.__valdres__ = version;
|
|
1077
|
+
}
|
|
592
1078
|
export {
|
|
1079
|
+
store,
|
|
593
1080
|
selectorFamily,
|
|
594
1081
|
selector,
|
|
595
|
-
|
|
1082
|
+
isSelectorFamily,
|
|
596
1083
|
isSelector,
|
|
597
1084
|
isPromiseLike,
|
|
1085
|
+
isFamilyState,
|
|
1086
|
+
isFamilySelector,
|
|
1087
|
+
isFamilyAtom,
|
|
598
1088
|
isFamily,
|
|
1089
|
+
isAtomFamily,
|
|
599
1090
|
isAtom,
|
|
600
|
-
|
|
1091
|
+
globalStore,
|
|
601
1092
|
createStoreWithSelectorSet,
|
|
602
|
-
createStore,
|
|
603
1093
|
atomFamily,
|
|
604
1094
|
atom
|
|
605
1095
|
};
|