valdres 0.2.0-alpha.3 → 0.2.0-alpha.30

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