valdres 0.2.0-alpha.2 → 0.2.0-alpha.21

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.
Files changed (94) hide show
  1. package/dist/index.js +527 -259
  2. package/dist/types/index.d.ts +26 -0
  3. package/dist/types/src/atom.d.ts +16 -0
  4. package/dist/types/src/atomFamily.d.ts +10 -0
  5. package/dist/types/src/createStoreWithSelectorSet.d.ts +2 -0
  6. package/dist/types/src/lib/atomFamilyAtom.d.ts +8 -0
  7. package/dist/types/src/lib/createStoreData.d.ts +3 -0
  8. package/dist/types/src/lib/getState.d.ts +7 -0
  9. package/dist/types/src/lib/globalAtom.d.ts +4 -0
  10. package/dist/{src → types/src}/lib/initAtom.d.ts +2 -1
  11. package/dist/{src → types/src}/lib/initSelector.d.ts +1 -1
  12. package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +4 -0
  13. package/dist/types/src/lib/setAtom.d.ts +3 -0
  14. package/dist/types/src/lib/storeFromStoreData.d.ts +4 -0
  15. package/dist/{src → types/src}/lib/transaction.d.ts +2 -1
  16. package/dist/types/src/lib/unsubscribe.d.ts +5 -0
  17. package/dist/{src → types/src}/lib/updateStateSubscribers.d.ts +1 -1
  18. package/dist/types/src/selector.d.ts +4 -0
  19. package/dist/types/src/selectorFamily.d.ts +3 -0
  20. package/dist/types/src/store.d.ts +1 -0
  21. package/dist/types/src/types/Atom.d.ts +12 -0
  22. package/dist/types/src/types/AtomDefaultValue.d.ts +2 -0
  23. package/dist/types/src/types/AtomFamily.d.ts +12 -0
  24. package/dist/types/src/types/AtomFamilyAtom.d.ts +6 -0
  25. package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +5 -0
  26. package/dist/types/src/types/AtomFamilySelector.d.ts +6 -0
  27. package/dist/types/src/types/AtomOnInit.d.ts +2 -0
  28. package/dist/types/src/types/AtomOnSet.d.ts +2 -0
  29. package/dist/types/src/types/AtomOptions.d.ts +11 -0
  30. package/dist/{src → types/src}/types/Family.d.ts +1 -1
  31. package/dist/types/src/types/FamilyKey.d.ts +3 -0
  32. package/dist/types/src/types/GetValue.d.ts +8 -0
  33. package/dist/types/src/types/GlobalAtom.d.ts +5 -0
  34. package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +1 -0
  35. package/dist/types/src/types/ResetAtom.d.ts +2 -0
  36. package/dist/types/src/types/Selector.d.ts +9 -0
  37. package/dist/types/src/types/SelectorFamily.d.ts +5 -0
  38. package/dist/types/src/types/SelectorOptions.d.ts +3 -0
  39. package/dist/types/src/types/SetAtom.d.ts +3 -0
  40. package/dist/types/src/types/SetAtomValue.d.ts +1 -0
  41. package/dist/types/src/types/Store.d.ts +24 -0
  42. package/dist/{src → types/src}/types/StoreData.d.ts +9 -1
  43. package/dist/types/src/types/Subscription.d.ts +1 -0
  44. package/dist/types/src/utils/isAtom.d.ts +2 -0
  45. package/dist/types/src/utils/isAtomFamily.d.ts +2 -0
  46. package/dist/types/src/utils/isFamily.d.ts +1 -0
  47. package/dist/types/src/utils/isFamilyAtom.d.ts +2 -0
  48. package/dist/types/src/utils/isFamilySelector.d.ts +2 -0
  49. package/dist/types/src/utils/isFamilyState.d.ts +3 -0
  50. package/dist/types/src/utils/isSelector.d.ts +2 -0
  51. package/dist/types/src/utils/isSelectorFamily.d.ts +2 -0
  52. package/package.json +12 -7
  53. package/dist/src/atom.d.ts +0 -9
  54. package/dist/src/atom.test.d.ts +0 -1
  55. package/dist/src/atomFamily.d.ts +0 -2
  56. package/dist/src/atomFamily.test.d.ts +0 -1
  57. package/dist/src/createStore.d.ts +0 -2
  58. package/dist/src/createStore.test.d.ts +0 -1
  59. package/dist/src/getDefaultStore.d.ts +0 -2
  60. package/dist/src/lib/getState.d.ts +0 -3
  61. package/dist/src/lib/initAtom.test.d.ts +0 -1
  62. package/dist/src/lib/initSelector.test.d.ts +0 -1
  63. package/dist/src/lib/propagateUpdatedAtoms.d.ts +0 -3
  64. package/dist/src/lib/recursivlyUpdateSelectors.d.ts +0 -1
  65. package/dist/src/lib/setAtom.d.ts +0 -3
  66. package/dist/src/lib/setAtom.test.d.ts +0 -1
  67. package/dist/src/lib/subscribe.test.d.ts +0 -1
  68. package/dist/src/lib/transaction.test.d.ts +0 -1
  69. package/dist/src/lib/unsubscribe.d.ts +0 -3
  70. package/dist/src/selector.d.ts +0 -3
  71. package/dist/src/selector.test.d.ts +0 -1
  72. package/dist/src/selectorFamily.d.ts +0 -2
  73. package/dist/src/selectorFamily.test.d.ts +0 -1
  74. package/dist/src/types/Atom.d.ts +0 -9
  75. package/dist/src/types/AtomFamily.d.ts +0 -5
  76. package/dist/src/types/GetValue.d.ts +0 -2
  77. package/dist/src/types/ResetAtom.d.ts +0 -2
  78. package/dist/src/types/Selector.d.ts +0 -8
  79. package/dist/src/types/SelectorFamily.d.ts +0 -5
  80. package/dist/src/types/SetAtom.d.ts +0 -2
  81. package/dist/src/types/Store.d.ts +0 -14
  82. package/dist/src/utils/isAtom.d.ts +0 -3
  83. package/dist/src/utils/isFamily.d.ts +0 -1
  84. package/dist/src/utils/isSelector.d.ts +0 -2
  85. package/dist/test/utils/wait.d.ts +0 -2
  86. /package/dist/{src → types/src}/lib/resetAtom.d.ts +0 -0
  87. /package/dist/{src → types/src}/lib/setAtoms.d.ts +0 -0
  88. /package/dist/{src → types/src}/lib/stableStringify.d.ts +0 -0
  89. /package/dist/{src → types/src}/lib/subscribe.d.ts +0 -0
  90. /package/dist/{src → types/src}/lib/updateSelectorSubscribers.d.ts +0 -0
  91. /package/dist/{src → types/src}/types/State.d.ts +0 -0
  92. /package/dist/{src → types/src}/types/SubscribeFn.d.ts +0 -0
  93. /package/dist/{src → types/src}/types/TransactionFn.d.ts +0 -0
  94. /package/dist/{src → types/src}/utils/isPromiseLike.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,91 +1,32 @@
1
- // src/atom.ts
2
- var atom = (defaultValue, options) => {
3
- if (!options)
4
- return { defaultValue };
5
- return {
6
- defaultValue,
7
- ...options
8
- };
9
- };
1
+ // src/lib/setAtom.ts
2
+ import equal4 from "fast-deep-equal/es6";
3
+
10
4
  // src/utils/isPromiseLike.ts
11
5
  var isPromiseLike = (object) => {
12
6
  return object && object.then && typeof object.then === "function";
13
7
  };
14
8
 
15
- // src/lib/stableStringify.ts
16
- var stableStringifyRecurse = (x, key) => {
17
- if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
18
- return `"${x}"`;
19
- }
20
- switch (typeof x) {
21
- case "undefined":
22
- return "";
23
- case "boolean":
24
- return x ? "true" : "false";
25
- case "number":
26
- case "symbol":
27
- return String(x);
28
- case "string":
29
- return JSON.stringify(x);
30
- case "function":
31
- return `__FUNCTION(${x.toString()})__`;
32
- }
33
- if (x === null) {
34
- return "null";
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;
52
- }
53
- return stableStringifyRecurse(obj, key);
54
- }
55
- if (x instanceof Set) {
56
- return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
57
- }
58
- if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
59
- return stableStringifyRecurse(Array.from(x), key);
60
- }
61
- return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
62
- };
63
- var stableStringify = (x) => {
64
- if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
65
- return x;
66
- return stableStringifyRecurse(x);
67
- };
9
+ // src/lib/getState.ts
10
+ import equal3 from "fast-deep-equal/es6";
11
+
12
+ // src/utils/isAtom.ts
13
+ var isAtom = (state) => Object.hasOwn(state, "defaultValue");
14
+
15
+ // src/utils/isAtomFamily.ts
16
+ var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
17
+
18
+ // src/utils/isSelector.ts
19
+ var isSelector = (state) => state && Object.hasOwn(state, "get");
20
+
21
+ // src/utils/isSelectorFamily.ts
22
+ var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
23
+
24
+ // src/utils/isFamilyState.ts
25
+ var isFamilyState = (state) => state && Object.hasOwn(state, "family");
26
+
27
+ // src/utils/isFamilyAtom.ts
28
+ var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
68
29
 
69
- // src/atomFamily.ts
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);
76
- }
77
- const atomDebugLabel = debugLabel && debugLabel + "_" + keyStringified;
78
- const newAtom = atom(typeof defaultValue === "function" ? () => defaultValue(key) : defaultValue, {
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;
88
- };
89
30
  // src/lib/updateStateSubscribers.ts
90
31
  var updateStateSubscribers = (state, data) => {
91
32
  const subscribtions = data.subscriptions.get(state);
@@ -94,7 +35,7 @@ var updateStateSubscribers = (state, data) => {
94
35
  subscribtion.callback();
95
36
  }
96
37
  }
97
- if (state.family) {
38
+ if (isFamilyState(state)) {
98
39
  const familySubscriptions = data.subscriptions.get(state.family);
99
40
  if (familySubscriptions?.size) {
100
41
  for (const subscribtion of familySubscriptions) {
@@ -105,10 +46,10 @@ var updateStateSubscribers = (state, data) => {
105
46
  };
106
47
 
107
48
  // src/lib/updateSelectorSubscribers.ts
108
- import equal2 from "fast-deep-equal";
49
+ import equal2 from "fast-deep-equal/es6";
109
50
 
110
51
  // src/lib/initSelector.ts
111
- import equal from "fast-deep-equal";
52
+ import equal from "fast-deep-equal/es6";
112
53
  class SuspendAndWaitForResolveError extends Error {
113
54
  promise;
114
55
  constructor(promise) {
@@ -125,17 +66,16 @@ var getOrInitConsumersSet = (state, data) => {
125
66
  return newSet;
126
67
  };
127
68
  var evaluateSelector = (selector, data) => {
128
- const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
129
69
  const updatedDependencies = new Set;
130
70
  let result;
131
71
  try {
132
72
  result = selector.get((state) => {
133
- const value = getState2(state, data);
73
+ const value = getState(state, data);
134
74
  updatedDependencies.add(state);
135
75
  if (isPromiseLike(value))
136
76
  throw new SuspendAndWaitForResolveError(value);
137
77
  return value;
138
- });
78
+ }, data.id);
139
79
  } catch (error) {
140
80
  if (error instanceof SuspendAndWaitForResolveError) {
141
81
  result = error;
@@ -143,6 +83,7 @@ var evaluateSelector = (selector, data) => {
143
83
  throw error;
144
84
  }
145
85
  }
86
+ const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
146
87
  const added = updatedDependencies?.difference(currentDependencies);
147
88
  const removed = currentDependencies?.difference(updatedDependencies);
148
89
  for (const state of added) {
@@ -164,7 +105,7 @@ var handleSelectorResult = (value, selector, data) => {
164
105
  value.then((resolved) => {
165
106
  data.values.set(selector, resolved);
166
107
  updateStateSubscribers(selector, data);
167
- console.log(`TODO: Should we check if other selectors are using this?`);
108
+ console.log("Should we reEvaluate?");
168
109
  });
169
110
  return value;
170
111
  } else {
@@ -191,7 +132,7 @@ var updateSelectorSubscribers = (selector, data) => {
191
132
  const familySubscriptions = selector.family && data.subscriptions.get(selector.family);
192
133
  if (!subscribtions?.size && !familySubscriptions?.size)
193
134
  return;
194
- if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && data.subscriptionsRequireEqualCheck.get(selector.family)) {
135
+ if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && selector.family && data.subscriptionsRequireEqualCheck.get(selector.family)) {
195
136
  try {
196
137
  const oldValue = data.expiredValues.get(selector);
197
138
  const newValue = initSelector(selector, data);
@@ -228,13 +169,13 @@ var recursivlyResetSelectorTree = (selectors, data, clearedSelectors) => {
228
169
  };
229
170
  var propagateUpdatedAtoms = (atoms, data) => {
230
171
  const clearedSelectors = new Set;
231
- for (const atom3 of atoms) {
232
- const consumers = data.stateConsumers.get(atom3);
172
+ for (const atom of atoms) {
173
+ const consumers = data.stateConsumers.get(atom);
233
174
  if (consumers && consumers.size) {
234
175
  recursivlyResetSelectorTree(consumers, data, clearedSelectors);
235
176
  }
236
- if (atom3.family) {
237
- const consumersFamily = data.stateConsumers.get(atom3.family);
177
+ if (isFamilyAtom(atom)) {
178
+ const consumersFamily = data.stateConsumers.get(atom.family);
238
179
  if (consumersFamily?.size) {
239
180
  recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
240
181
  }
@@ -243,32 +184,14 @@ var propagateUpdatedAtoms = (atoms, data) => {
243
184
  for (const selector of clearedSelectors) {
244
185
  updateSelectorSubscribers(selector, data);
245
186
  }
246
- for (const atom3 of atoms) {
247
- updateStateSubscribers(atom3, data);
248
- }
249
- };
250
-
251
- // src/lib/setAtom.ts
252
- import equal3 from "fast-deep-equal";
253
- var setAtom = (atom3, newValue, data) => {
254
- const currentValue = getState2(atom3, data);
255
- if (typeof newValue === "function") {
256
- newValue = newValue(currentValue);
257
- if (isPromiseLike(newValue) || isPromiseLike(currentValue))
258
- throw new Error("Todo, how should we handle this?");
259
- }
260
- if (equal3(currentValue, newValue))
261
- return;
262
- data.values.set(atom3, newValue);
263
- if (currentValue?.__isEmptyAtomPromise__) {
264
- currentValue.__resolveEmptyAtomPromise__(newValue);
187
+ for (const atom of atoms) {
188
+ updateStateSubscribers(atom, data);
265
189
  }
266
- propagateUpdatedAtoms([atom3], data);
267
190
  };
268
191
 
269
192
  // src/lib/initAtom.ts
270
- var getAtomInitValue = (atom3, data) => {
271
- if (atom3.defaultValue === undefined) {
193
+ var getAtomInitValue = (atom, data) => {
194
+ if (atom.defaultValue === undefined) {
272
195
  let promiseResolve;
273
196
  const promise = new Promise((resolve) => {
274
197
  promiseResolve = resolve;
@@ -276,58 +199,309 @@ var getAtomInitValue = (atom3, data) => {
276
199
  promise.__isEmptyAtomPromise__ = true;
277
200
  promise.__resolveEmptyAtomPromise__ = promiseResolve;
278
201
  return promise;
279
- } else if (typeof atom3.defaultValue === "function") {
280
- const value = atom3.defaultValue();
202
+ } else if (typeof atom.defaultValue === "function") {
203
+ const value = atom.defaultValue();
281
204
  if (isPromiseLike(value)) {
282
205
  value.then((resolvedValue) => {
283
- data.values.set(atom3, resolvedValue);
284
- propagateUpdatedAtoms([atom3], data);
206
+ data.values.set(atom, resolvedValue);
207
+ propagateUpdatedAtoms([atom], data);
285
208
  });
286
209
  }
287
210
  return value;
211
+ } else if (isSelector(atom.defaultValue)) {
212
+ return getState(atom.defaultValue, data);
288
213
  } else {
289
- return atom3.defaultValue;
214
+ return atom.defaultValue;
290
215
  }
291
216
  };
292
- var initAtom = (atom3, data) => {
293
- const value = getAtomInitValue(atom3, data);
294
- data.values.set(atom3, value);
295
- if (atom3.onInit)
296
- atom3.onInit((newVal) => {
297
- setAtom(atom3, newVal, data);
298
- });
217
+ var initAtom = (atom, data) => {
218
+ let value = getAtomInitValue(atom, data);
219
+ data.values.set(atom, value);
220
+ if (isFamilyAtom(atom)) {
221
+ const currentKeySet = getState(atom.family.__keysAtom, data);
222
+ if (!currentKeySet.has(atom.familyKey)) {
223
+ const newSet = new Set(currentKeySet);
224
+ newSet.add(atom.familyKey);
225
+ setAtom(atom.family.__keysAtom, newSet, data);
226
+ }
227
+ }
228
+ if (atom.onInit)
229
+ atom.onInit((newVal) => {
230
+ value = newVal;
231
+ setAtom(atom, newVal, data, true);
232
+ }, data);
299
233
  return value;
300
234
  };
301
235
 
302
- // src/utils/isAtom.ts
303
- var isAtom = (state) => Object.hasOwn(state, "defaultValue");
304
-
305
- // src/utils/isSelector.ts
306
- var isSelector = (state) => Object.hasOwn(state, "get");
307
-
308
- // src/utils/isFamily.ts
309
- var isFamily = (state) => Object.hasOwn(state, "_map");
310
-
311
236
  // src/lib/getState.ts
312
- var getState2 = (state, data) => {
237
+ function getState(state, data) {
313
238
  if (data.values.has(state))
314
239
  return data.values.get(state);
315
- if (isAtom(state))
240
+ if (isAtom(state)) {
241
+ if ("parent" in data)
242
+ return getState(state, data.parent);
316
243
  return initAtom(state, data);
244
+ }
317
245
  if (isSelector(state))
318
246
  return initSelector(state, data);
319
- if (isFamily(state)) {
320
- const res = [];
321
- for (const atom3 of state._map.values()) {
322
- res.push([atom3.familyKey, getState2(atom3, data)]);
247
+ if (isAtomFamily(state)) {
248
+ if ("parent" in data) {
249
+ const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
250
+ return getState(state.__keysSelector, closestData);
323
251
  }
324
- return res;
252
+ return getState(state.__keysSelector, data);
253
+ }
254
+ if (isSelectorFamily(state)) {
255
+ const array = Array.from(state.__valdresSelectorFamilyMap.keys());
256
+ if (equal3(array, state._keyArray))
257
+ return state._keyArray;
258
+ state._keyArray = array;
259
+ return array;
325
260
  }
326
261
  throw new Error("Invalid object passed to get");
262
+ }
263
+ var findClosestStoreWithAtomInitialized = (atom, data) => {
264
+ if ("parent" in data === false)
265
+ return data;
266
+ if (data.values.has(atom))
267
+ return data;
268
+ return findClosestStoreWithAtomInitialized(atom, data.parent);
269
+ };
270
+
271
+ // src/lib/setAtom.ts
272
+ var setAtom = (atom, newValue, data, skipOnSet = false) => {
273
+ const currentValue = getState(atom, data);
274
+ if (typeof newValue === "function") {
275
+ newValue = newValue(currentValue);
276
+ if (isPromiseLike(newValue) || isPromiseLike(currentValue))
277
+ throw new Error("Todo, how should we handle this?");
278
+ }
279
+ if (equal4(currentValue, newValue))
280
+ return;
281
+ data.values.set(atom, newValue);
282
+ if (atom.onSet && !skipOnSet)
283
+ atom.onSet(newValue, data);
284
+ if (currentValue?.__isEmptyAtomPromise__) {
285
+ currentValue.__resolveEmptyAtomPromise__(newValue);
286
+ }
287
+ propagateUpdatedAtoms([atom], data);
288
+ };
289
+
290
+ // src/lib/globalAtom.ts
291
+ var getFirstItemInSet = (set) => {
292
+ for (let item of set) {
293
+ return item;
294
+ }
295
+ throw new Error("Non Empty Set");
296
+ };
297
+ var globalAtom = (defaultValue, options) => {
298
+ const stores = new Set;
299
+ let value = defaultValue;
300
+ if (options.onSet)
301
+ throw new Error("onSet on globalAtom is currently not supported");
302
+ if (options.onInit)
303
+ throw new Error("onInit on globalAtom is currently not supported");
304
+ const onInit = (setSelf2, store) => {
305
+ setSelf2(value);
306
+ stores.add(store);
307
+ };
308
+ const onSet = (newValue, currentStore) => {
309
+ value = newValue;
310
+ if (stores.size > 1) {
311
+ for (const store of stores) {
312
+ if (store.id !== currentStore.id) {
313
+ setAtom(atom, value, store, true);
314
+ }
315
+ }
316
+ }
317
+ };
318
+ const setSelf = (newValue) => {
319
+ value = newValue;
320
+ if (stores.size > 0) {
321
+ getFirstItemInSet(stores);
322
+ const store = getFirstItemInSet(stores);
323
+ setAtom(atom, newValue, store);
324
+ }
325
+ };
326
+ const atom = {
327
+ ...options,
328
+ defaultValue,
329
+ label: options?.label,
330
+ onInit,
331
+ onSet,
332
+ setSelf
333
+ };
334
+ return atom;
335
+ };
336
+
337
+ // src/atom.ts
338
+ function atom(defaultValue, options) {
339
+ if (!options)
340
+ return { defaultValue };
341
+ if (options.global) {
342
+ return globalAtom(defaultValue, options);
343
+ }
344
+ return {
345
+ defaultValue,
346
+ ...options
347
+ };
348
+ }
349
+ // src/lib/atomFamilyAtom.ts
350
+ function atomFamilyAtom(defaultValue, options) {
351
+ if (options.global) {
352
+ return {
353
+ ...options,
354
+ defaultValue
355
+ };
356
+ }
357
+ return {
358
+ ...options,
359
+ defaultValue
360
+ };
361
+ }
362
+
363
+ // src/lib/stableStringify.ts
364
+ var stableStringifyRecurse = (x, key) => {
365
+ if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
366
+ return `"${x}"`;
367
+ }
368
+ switch (typeof x) {
369
+ case "undefined":
370
+ return "";
371
+ case "boolean":
372
+ return x ? "true" : "false";
373
+ case "number":
374
+ case "symbol":
375
+ return String(x);
376
+ case "string":
377
+ return JSON.stringify(x);
378
+ case "function":
379
+ return `__FUNCTION(${x.toString()})__`;
380
+ }
381
+ if (x === null) {
382
+ return "null";
383
+ }
384
+ if (typeof x !== "object") {
385
+ return JSON.stringify(x) ?? "";
386
+ }
387
+ if (isPromiseLike(x)) {
388
+ return "__PROMISE__";
389
+ }
390
+ if (Array.isArray(x)) {
391
+ return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
392
+ }
393
+ if (typeof x.toJSON === "function") {
394
+ return stableStringifyRecurse(x.toJSON(key), key);
395
+ }
396
+ if (x instanceof Map) {
397
+ const obj = {};
398
+ for (const [k, v] of x) {
399
+ obj[typeof k === "string" ? k : stringify(k, opt)] = v;
400
+ }
401
+ return stableStringifyRecurse(obj, key);
402
+ }
403
+ if (x instanceof Set) {
404
+ return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
405
+ }
406
+ if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
407
+ return stableStringifyRecurse(Array.from(x), key);
408
+ }
409
+ return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
410
+ };
411
+ var stableStringify = (x) => {
412
+ if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
413
+ return x;
414
+ return stableStringifyRecurse(x);
415
+ };
416
+
417
+ // src/selector.ts
418
+ var selector = (get, options) => {
419
+ if (!options)
420
+ return { get };
421
+ return { ...options, get };
327
422
  };
328
423
 
424
+ // src/atomFamily.ts
425
+ var createOptions = (options = {}, family, familyKey, keyStringified) => {
426
+ if (options.label) {
427
+ return {
428
+ ...options,
429
+ label: options?.label + "_" + keyStringified,
430
+ family,
431
+ familyKey
432
+ };
433
+ } else {
434
+ return { ...options, family, familyKey };
435
+ }
436
+ };
437
+ var handleDefaultValue = (defaultValue, key) => {
438
+ if (isSelectorFamily(defaultValue))
439
+ return defaultValue(key);
440
+ if (typeof defaultValue === "function")
441
+ return () => defaultValue(key);
442
+ return defaultValue;
443
+ };
444
+ function atomFamily(defaultValue, options) {
445
+ const map = new Map;
446
+ const atomFamily2 = (key) => {
447
+ const keyStringified = stableStringify(key);
448
+ if (map.has(keyStringified)) {
449
+ return map.get(keyStringified);
450
+ }
451
+ const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily2, Object.freeze(key), keyStringified));
452
+ map.set(keyStringified, familyAtom);
453
+ return familyAtom;
454
+ };
455
+ atomFamily2.__valdresAtomFamilyMap = map;
456
+ atomFamily2.release = (key) => map.delete(key);
457
+ const keysAtom = atom(new Set);
458
+ atomFamily2.__keysAtom = keysAtom;
459
+ atomFamily2.__keysSelector = selector((get) => Array.from(get(keysAtom)));
460
+ if (options?.label)
461
+ atomFamily2.label = options.label;
462
+ return atomFamily2;
463
+ }
464
+ // src/lib/createStoreData.ts
465
+ var generateId = () => (Math.random() + 1).toString(36).substring(7);
466
+ var generateStoreData = (id = generateId()) => {
467
+ return {
468
+ id,
469
+ values: new WeakMap,
470
+ expiredValues: new WeakMap,
471
+ subscriptions: new WeakMap,
472
+ subscriptionsRequireEqualCheck: new WeakMap,
473
+ stateConsumers: new WeakMap,
474
+ stateDependencies: new WeakMap,
475
+ scopes: {}
476
+ };
477
+ };
478
+ function createStoreData(id, parent) {
479
+ if (parent) {
480
+ return {
481
+ ...generateStoreData(id),
482
+ parent,
483
+ scopeConsumers: parent ? new Set : undefined
484
+ };
485
+ } else {
486
+ return generateStoreData(id);
487
+ }
488
+ }
489
+
490
+ // src/lib/resetAtom.ts
491
+ var resetAtom = (atom2, data) => {
492
+ let value = getAtomInitValue(atom2, data);
493
+ data.values.set(atom2, value);
494
+ if (!isPromiseLike(value)) {
495
+ propagateUpdatedAtoms([atom2], data);
496
+ }
497
+ return value;
498
+ };
499
+
500
+ // src/utils/isFamily.ts
501
+ var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
502
+
329
503
  // src/lib/unsubscribe.ts
330
- var unsubscribe = (state, subscription, data, mountRes) => {
504
+ var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
331
505
  const subscribers = data.subscriptions.get(state);
332
506
  if (subscribers) {
333
507
  subscribers.delete(subscription);
@@ -344,8 +518,15 @@ var unsubscribe = (state, subscription, data, mountRes) => {
344
518
  }
345
519
  }
346
520
  if (subscribers.size === 0) {
347
- if (state.onUnmount) {
348
- state.onUnmount(mountRes);
521
+ if (maxAgeCleanup)
522
+ maxAgeCleanup();
523
+ data.subscriptions.delete(state);
524
+ }
525
+ if (mount) {
526
+ if (subscribers.size === mount.mountSubscriptions.size) {
527
+ if (typeof mount.onUnmount === "function") {
528
+ mount.onUnmount();
529
+ }
349
530
  }
350
531
  }
351
532
  }
@@ -358,6 +539,14 @@ var initSubscribers = (state, data) => {
358
539
  return set;
359
540
  };
360
541
  var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
542
+ if ("parent" in data && !data.values.has(state) && isAtom(state)) {
543
+ const parentUnsubscribe = subscribe(state, callback, requireDeepEqualCheckBeforeCallback, data.parent);
544
+ let originalCallback = callback;
545
+ callback = () => {
546
+ parentUnsubscribe();
547
+ originalCallback();
548
+ };
549
+ }
361
550
  const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
362
551
  if (isSelector(state) && !data.values.has(state)) {
363
552
  initSelector(state, data);
@@ -375,28 +564,65 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
375
564
  requireDeepEqualCheckBeforeCallback
376
565
  };
377
566
  }
378
- let mountRes;
379
- if (subscribers.size === 0 && state.onMount) {
380
- mountRes = state.onMount((value) => {
381
- setAtom(state, value, data);
382
- });
383
- }
384
567
  subscribers.add(subscription);
568
+ let mount;
569
+ let maxAgeCleanup;
570
+ if (subscribers.size === 1) {
571
+ if (isAtom(state) && state.maxAge) {
572
+ let timeout;
573
+ const interval = setInterval(() => {
574
+ let value = getAtomInitValue(state, data);
575
+ if (isPromiseLike(value)) {
576
+ if (state.staleWhileRevalidate) {
577
+ const oldValue = data.values.get(state);
578
+ timeout = setTimeout(() => {
579
+ const nowValue = data.values.get(state);
580
+ console.log("todo", oldValue);
581
+ }, state.staleWhileRevalidate);
582
+ value.then((res) => clearTimeout(timeout));
583
+ }
584
+ } else {
585
+ data.values.set(state, value);
586
+ propagateUpdatedAtoms([state], data);
587
+ }
588
+ }, state.maxAge);
589
+ maxAgeCleanup = () => {
590
+ clearInterval(interval);
591
+ if (timeout)
592
+ clearTimeout(timeout);
593
+ };
594
+ }
595
+ if (state.onMount) {
596
+ const store = storeFromStoreData(data);
597
+ const mountSubscriptions = new Set;
598
+ const originalSub = store.sub;
599
+ store.sub = (state2, callback2) => {
600
+ mountSubscriptions.add(callback2);
601
+ return originalSub(state2, callback2);
602
+ };
603
+ mount = {
604
+ onUnmount: state.onMount(store, state),
605
+ mountSubscriptions
606
+ };
607
+ }
608
+ }
385
609
  if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
386
610
  data.subscriptionsRequireEqualCheck.set(state, true);
387
611
  }
388
- return () => unsubscribe(state, subscription, data, mountRes);
612
+ return () => unsubscribe(state, subscription, data, mount, maxAgeCleanup);
389
613
  };
390
614
 
391
615
  // src/lib/setAtoms.ts
392
- import equal4 from "fast-deep-equal";
616
+ import equal5 from "fast-deep-equal/es6";
393
617
  var setAtoms = (pairs, data) => {
394
618
  const updatedAtoms = [];
395
- for (let [atom3, value] of pairs) {
396
- const currentValue = getState2(atom3, data);
397
- if (!equal4(currentValue, value)) {
398
- updatedAtoms.push(atom3);
399
- data.values.set(atom3, value);
619
+ for (let [atom2, value] of pairs) {
620
+ const currentValue = getState(atom2, data);
621
+ if (!equal5(currentValue, value)) {
622
+ updatedAtoms.push(atom2);
623
+ if (atom2.onSet)
624
+ atom2.onSet(value, data);
625
+ data.values.set(atom2, value);
400
626
  }
401
627
  }
402
628
  propagateUpdatedAtoms(updatedAtoms, data);
@@ -415,41 +641,62 @@ var findDependencies = (state, data, result = new Set) => {
415
641
  }
416
642
  return result;
417
643
  };
644
+ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache) => {
645
+ for (const dep of txnSubscribers.get(state)) {
646
+ txnSelectorCache.delete(dep);
647
+ if (txnSubscribers.get(dep)?.size) {
648
+ recursivlyResetTxnSelectorCache(dep, txnSubscribers, txnSelectorCache);
649
+ }
650
+ }
651
+ };
418
652
  var transaction = (callback, data) => {
419
653
  let txnAtomMap = new Map;
420
654
  let txnSelectorCache = new Map;
655
+ let txnSubscribers = new Map;
421
656
  let dirtySelectors = new Set;
422
657
  const txnGet = (state) => {
423
658
  if (isAtom(state)) {
424
- return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState2(state, data);
425
- } else {
659
+ return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state, data);
660
+ } else if (isSelector(state)) {
426
661
  if (txnSelectorCache.has(state)) {
427
662
  return txnSelectorCache.get(state);
428
- } else if (dirtySelectors.has(state)) {
429
- const res = state.get(txnGet);
430
- txnSelectorCache.set(state, res);
431
- return res;
432
- } else {
433
- return getState2(state, data);
434
663
  }
664
+ const deps = new Set;
665
+ const res = state.get((s) => {
666
+ deps.add(s);
667
+ return txnGet(s);
668
+ }, data.id);
669
+ for (const dep of deps) {
670
+ if (!txnSubscribers.has(dep)) {
671
+ txnSubscribers.set(dep, new Set);
672
+ }
673
+ txnSubscribers.get(dep).add(state);
674
+ }
675
+ txnSelectorCache.set(state, res);
676
+ return res;
677
+ } else {
678
+ throw new Error("Unsupported state");
435
679
  }
436
680
  };
437
- const txnSet = (atom3, value) => {
438
- if (!isAtom(atom3))
681
+ const txnSet = (atom2, value) => {
682
+ if (!isAtom(atom2))
439
683
  throw new Error("Not an atom");
440
684
  if (typeof value === "function") {
441
- const currentValue = txnGet(atom3);
685
+ const currentValue = txnGet(atom2);
442
686
  value = value(currentValue);
443
687
  }
444
- for (const selector of findDependencies(atom3, data)) {
445
- dirtySelectors.add(selector);
446
- txnSelectorCache.delete(selector);
688
+ for (const selector2 of findDependencies(atom2, data)) {
689
+ dirtySelectors.add(selector2);
690
+ txnSelectorCache.delete(selector2);
447
691
  }
448
- txnAtomMap.set(atom3, value);
692
+ if (txnSubscribers.get(atom2)?.size) {
693
+ recursivlyResetTxnSelectorCache(atom2, txnSubscribers, txnSelectorCache);
694
+ }
695
+ txnAtomMap.set(atom2, value);
449
696
  };
450
- const txnReset = (atom3) => {
451
- const value = getAtomInitValue(atom3, data);
452
- txnAtomMap.set(atom3, value);
697
+ const txnReset = (atom2) => {
698
+ const value = getAtomInitValue(atom2, data);
699
+ txnAtomMap.set(atom2, value);
453
700
  return value;
454
701
  };
455
702
  const commit = () => {
@@ -461,112 +708,133 @@ var transaction = (callback, data) => {
461
708
  return result;
462
709
  };
463
710
 
464
- // src/lib/resetAtom.ts
465
- var resetAtom = (atom3, data) => {
466
- const res = initAtom(atom3, data);
467
- if (!isPromiseLike(res)) {
468
- propagateUpdatedAtoms([atom3], data);
469
- }
470
- return res;
471
- };
472
-
473
- // src/createStore.ts
474
- var generateId = () => (Math.random() + 1).toString(36).substring(7);
475
- var createStore = (id) => {
476
- const data = {
477
- id: id ?? generateId(),
478
- values: new WeakMap,
479
- expiredValues: new WeakMap,
480
- subscriptions: new WeakMap,
481
- subscriptionsRequireEqualCheck: new WeakMap,
482
- stateConsumers: new WeakMap,
483
- stateDependencies: new WeakMap
484
- };
485
- const get = (state) => getState2(state, data);
486
- const getWithDefault = (atom3, defaultValue) => {
487
- if (!isAtom(atom3))
488
- throw new Error("Only atom allowed");
489
- if (data.values.has(atom3)) {
490
- return data.values.get(atom3);
491
- } else {
492
- if (typeof defaultValue === "function") {
493
- defaultValue = defaultValue((state) => getState2(state, data));
494
- }
495
- data.values.set(atom3, defaultValue);
496
- return defaultValue;
497
- }
498
- };
711
+ // src/lib/storeFromStoreData.ts
712
+ var SelectorProvidedToSetError = `Invalid state object passed to set().
713
+ You provided a \`selector\`.
714
+ Only \`atom\` cam be set.
715
+ `;
716
+ var InvalidStateSetError = `Invalid state object passed to set().
717
+ Only \`atom\` can be set.
718
+ `;
719
+ function storeFromStoreData(data, detach) {
720
+ const get = (state) => getState(state, data);
499
721
  const set = (state, value) => {
500
- if (isAtom(state)) {
722
+ if (isAtom(state))
501
723
  return setAtom(state, value, data);
502
- } else {
503
- if (isSelector(state)) {
504
- if (state.set) {
505
- txn((set2, get2) => state.set({ get: get2, set: set2 }, value));
506
- return;
507
- } else {
508
- throw new Error("set on selector is not supported");
509
- }
510
- }
511
- throw new Error("Invalid state object passed to set");
512
- }
724
+ if (isSelector(state))
725
+ throw new Error(SelectorProvidedToSetError);
726
+ throw new Error(InvalidStateSetError);
513
727
  };
514
- const reset = (atom3) => resetAtom(atom3, data);
728
+ const reset = (atom2) => resetAtom(atom2, data);
515
729
  const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
516
730
  const txn = (callback) => transaction(callback, data);
517
- return {
518
- get,
519
- getWithDefault,
520
- set,
521
- sub,
522
- txn,
523
- reset,
524
- data
731
+ const scope = (scopeId) => {
732
+ let scopedStoreData;
733
+ if (scopeId in data.scopes) {
734
+ scopedStoreData = data.scopes[scopeId];
735
+ } else {
736
+ scopedStoreData = createStoreData(scopeId, data);
737
+ data.scopes[scopeId] = scopedStoreData;
738
+ }
739
+ const detach2 = () => {
740
+ scopedStoreData.scopeConsumers.delete(detach2);
741
+ if (scopedStoreData.scopeConsumers.size === 0) {
742
+ delete data.scopes[scopeId];
743
+ }
744
+ };
745
+ scopedStoreData.scopeConsumers.add(detach2);
746
+ const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
747
+ return newStore;
525
748
  };
526
- };
527
- // src/getDefaultStore.ts
528
- if (!globalThis._valdresStore) {
529
- globalThis._valdresStore = createStore("default");
749
+ if (detach) {
750
+ return {
751
+ get,
752
+ set,
753
+ sub,
754
+ txn,
755
+ reset,
756
+ data,
757
+ scope,
758
+ detach
759
+ };
760
+ } else {
761
+ return {
762
+ get,
763
+ set,
764
+ sub,
765
+ txn,
766
+ reset,
767
+ data,
768
+ scope
769
+ };
770
+ }
530
771
  }
531
- var getDefaultStore = () => globalThis._valdresStore;
532
- var resetDefaultStore = () => globalThis._valdresStore = createStore();
533
- // src/selector.ts
534
- var selector = (get, debugLabel) => ({
535
- get,
536
- debugLabel
537
- });
772
+
773
+ // src/createStoreWithSelectorSet.ts
774
+ var setSelector = (selector2, values, store) => {
775
+ return selector2.set(store.set, store.get, store.reset, ...values);
776
+ };
777
+ var createStoreWithSelectorSet = (id) => {
778
+ const data = createStoreData(id);
779
+ const store = storeFromStoreData(data);
780
+ store.set = (state, value, ...rest) => {
781
+ if (isAtom(state))
782
+ return setAtom(state, value, data);
783
+ if (isSelector(state))
784
+ return setSelector(state, [value, ...rest], store);
785
+ throw new Error("Invalid state object");
786
+ };
787
+ store.kind = "storeWithSelectorSet";
788
+ return store;
789
+ };
538
790
  // src/selectorFamily.ts
539
- var selectorFamily = (get, debugLabel) => {
791
+ var createOptions2 = (options, key) => {
792
+ if (options.label) {
793
+ return {
794
+ ...options,
795
+ label: options?.label + "_" + key
796
+ };
797
+ } else {
798
+ return options;
799
+ }
800
+ };
801
+ var selectorFamily = (get, options) => {
540
802
  const map = new Map;
541
803
  const selectorFamily2 = (key) => {
542
- let keyStringified;
543
- try {
544
- keyStringified = stableStringify(key);
545
- } catch (e) {
546
- console.log(`errro`, { key, debugLabel, e });
547
- throw e;
548
- }
804
+ const keyStringified = stableStringify(key);
549
805
  if (map.has(keyStringified))
550
806
  return map.get(keyStringified);
551
- const selectorDebugLabel = debugLabel ? debugLabel + "_" + keyStringified : undefined;
552
- const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
807
+ const newSelector = selector((selectorArgs) => get(key)(selectorArgs), options ? createOptions2(options, keyStringified) : undefined);
553
808
  newSelector.family = selectorFamily2;
554
809
  map.set(keyStringified, newSelector);
555
810
  return newSelector;
556
811
  };
557
- selectorFamily2._map = map;
812
+ selectorFamily2.__valdresSelectorFamilyMap = map;
813
+ if (options?.label)
814
+ selectorFamily2.label = options.label;
558
815
  return selectorFamily2;
559
816
  };
817
+ // src/store.ts
818
+ var store = (id) => {
819
+ const data = createStoreData(id);
820
+ return storeFromStoreData(data);
821
+ };
822
+ // src/utils/isFamilySelector.ts
823
+ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
560
824
  export {
825
+ store,
561
826
  selectorFamily,
562
827
  selector,
563
- resetDefaultStore,
828
+ isSelectorFamily,
564
829
  isSelector,
565
830
  isPromiseLike,
831
+ isFamilyState,
832
+ isFamilySelector,
833
+ isFamilyAtom,
566
834
  isFamily,
835
+ isAtomFamily,
567
836
  isAtom,
568
- getDefaultStore,
569
- createStore,
837
+ createStoreWithSelectorSet,
570
838
  atomFamily,
571
839
  atom
572
840
  };