valdres 1.0.0-beta.7 → 1.0.0-beta.8

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 CHANGED
@@ -122,40 +122,7 @@ var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
122
122
  // src/utils/isSelectorFamily.ts
123
123
  var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
124
124
 
125
- // src/utils/deepFreeze.ts
126
- var deepFreeze = (obj, seen) => {
127
- if (obj === null || obj === undefined)
128
- return obj;
129
- if (typeof obj !== "object" && typeof obj !== "function")
130
- return obj;
131
- if (Object.isFrozen(obj) || seen?.has(obj))
132
- return obj;
133
- if (Array.isArray(obj)) {
134
- for (const item of obj) {
135
- if (item && typeof item === "object") {
136
- seen ??= new WeakSet;
137
- seen.add(obj);
138
- deepFreeze(item, seen);
139
- }
140
- }
141
- } else {
142
- const propNames = Object.getOwnPropertyNames(obj);
143
- for (const name of propNames) {
144
- const value = obj[name];
145
- if (value && typeof value === "object") {
146
- seen ??= new WeakSet;
147
- seen.add(obj);
148
- deepFreeze(value, seen);
149
- }
150
- }
151
- }
152
- return Object.freeze(obj);
153
- };
154
-
155
- // src/lib/IS_PROD.ts
156
- var IS_PROD = typeof process !== "undefined" && process.env != null && process.env.NODE_ENV === "production";
157
-
158
- // src/lib/setValueInData.ts
125
+ // src/lib/trackScopeValue.ts
159
126
  var trackScopeValue = (key, data) => {
160
127
  const parent = data.parent;
161
128
  const indexKeys = data.scopeIndexKeys;
@@ -170,30 +137,6 @@ var trackScopeValue = (key, data) => {
170
137
  set.add(data);
171
138
  indexKeys.add(key);
172
139
  };
173
- var setValueInData = (atom, value, data) => {
174
- const isNewAtomInScope = data.parent && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
175
- let written;
176
- if (atom.mutable || IS_PROD) {
177
- data.values.set(atom, value);
178
- written = value;
179
- } else {
180
- const frozenValue = value !== null && (typeof value === "object" || typeof value === "function") ? deepFreeze(value) : value;
181
- data.values.set(atom, frozenValue);
182
- written = frozenValue;
183
- }
184
- if (isNewAtomInScope) {
185
- trackScopeValue(atom, data);
186
- const subs = data.subscriptions.get(atom);
187
- if (subs) {
188
- for (const sub of subs)
189
- sub.reRoot?.();
190
- }
191
- }
192
- if (atom.maxAge !== undefined) {
193
- data.lastValueWriteAt.set(atom, Date.now());
194
- }
195
- return written;
196
- };
197
140
 
198
141
  // src/lib/atomFamilyIndex.ts
199
142
  var getAtomFamilyRenderedMap = (index) => {
@@ -292,13 +235,29 @@ var recursivelyUpdateIndexes = (data, family) => {
292
235
  recursivelyUpdateIndexes(scopedData, family);
293
236
  }
294
237
  };
238
+ var ensureFamilyAncestorChain = (family, data) => {
239
+ if (!data.parent)
240
+ return;
241
+ const parentIndex = initFamilyIndex(family, data.parent);
242
+ const own = data.values.get(family).__index;
243
+ if (own.parentIndex !== parentIndex) {
244
+ own.parentIndex = parentIndex;
245
+ own.rendered = null;
246
+ own.renderedArray = null;
247
+ data.values.set(family, renderAtomFamilyIndex(own));
248
+ recursivelyUpdateIndexes(data, family);
249
+ }
250
+ };
295
251
  var addFamilyAtomsToSet = (family, familyAtoms, data, timestamp) => {
296
252
  if (familyAtoms.size === 0)
297
- return;
253
+ return false;
298
254
  const index = findFamilyIndex(family, data);
299
255
  if (!index)
300
256
  throw new Error("index not found");
257
+ let membershipChanged = false;
301
258
  for (const atom of familyAtoms) {
259
+ if (!(index.created.has(atom) && !index.deleted.has(atom)))
260
+ membershipChanged = true;
302
261
  index.created.set(atom, timestamp);
303
262
  index.deleted.delete(atom);
304
263
  }
@@ -306,6 +265,7 @@ var addFamilyAtomsToSet = (family, familyAtoms, data, timestamp) => {
306
265
  index.renderedArray = null;
307
266
  data.values.set(family, renderAtomFamilyIndex(index));
308
267
  recursivelyUpdateIndexes(data, family);
268
+ return membershipChanged;
309
269
  };
310
270
 
311
271
  // src/errors/lib/generateSelectorTrace.ts
@@ -610,6 +570,69 @@ var flushChangeSink = (sink) => {
610
570
  }
611
571
  };
612
572
 
573
+ // src/utils/deepFreeze.ts
574
+ var deepFreeze = (obj, seen) => {
575
+ if (obj === null || obj === undefined)
576
+ return obj;
577
+ if (typeof obj !== "object" && typeof obj !== "function")
578
+ return obj;
579
+ if (Object.isFrozen(obj) || seen?.has(obj))
580
+ return obj;
581
+ if (Array.isArray(obj)) {
582
+ for (const item of obj) {
583
+ if (item && typeof item === "object") {
584
+ seen ??= new WeakSet;
585
+ seen.add(obj);
586
+ deepFreeze(item, seen);
587
+ }
588
+ }
589
+ } else {
590
+ const propNames = Object.getOwnPropertyNames(obj);
591
+ for (const name of propNames) {
592
+ const value = obj[name];
593
+ if (value && typeof value === "object") {
594
+ seen ??= new WeakSet;
595
+ seen.add(obj);
596
+ deepFreeze(value, seen);
597
+ }
598
+ }
599
+ }
600
+ return Object.freeze(obj);
601
+ };
602
+
603
+ // src/lib/IS_PROD.ts
604
+ var IS_PROD = typeof process !== "undefined" && process.env != null && process.env.NODE_ENV === "production";
605
+
606
+ // src/lib/setValueInData.ts
607
+ var setValueInData = (atom, value, data) => {
608
+ const isNewAtomInScope = data.parent && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
609
+ const isNewFamilyInScope = !!data.parent && !data.values.has(atom) && isAtomFamily(atom);
610
+ let written;
611
+ if (atom.mutable || IS_PROD) {
612
+ data.values.set(atom, value);
613
+ written = value;
614
+ } else {
615
+ const frozenValue = value !== null && (typeof value === "object" || typeof value === "function") ? deepFreeze(value) : value;
616
+ data.values.set(atom, frozenValue);
617
+ written = frozenValue;
618
+ }
619
+ if (isNewAtomInScope) {
620
+ trackScopeValue(atom, data);
621
+ const subs = data.subscriptions.get(atom);
622
+ if (subs) {
623
+ for (const sub of subs)
624
+ sub.reRoot?.();
625
+ }
626
+ } else if (isNewFamilyInScope) {
627
+ trackScopeValue(atom, data);
628
+ ensureFamilyAncestorChain(atom, data);
629
+ }
630
+ if (atom.maxAge !== undefined) {
631
+ data.lastValueWriteAt.set(atom, Date.now());
632
+ }
633
+ return written;
634
+ };
635
+
613
636
  // src/lib/initSelector.ts
614
637
  var neverAbortedSignal = new AbortController().signal;
615
638
  var syncOptionsCache = new WeakMap;
@@ -1017,6 +1040,7 @@ var propagateAtomUpdate = (atoms, data, isInitOnly = false, notify, report, skip
1017
1040
  updatedFamilyAtoms.get(atom.family).add(atom);
1018
1041
  }
1019
1042
  }
1043
+ let membershipChanged;
1020
1044
  if (updatedFamilyAtoms.size > 0) {
1021
1045
  const timestamp = performance.now();
1022
1046
  for (const [family, familyAtoms] of updatedFamilyAtoms) {
@@ -1024,7 +1048,11 @@ var propagateAtomUpdate = (atoms, data, isInitOnly = false, notify, report, skip
1024
1048
  addSetToSet(data.subscriptions.get(family), subscriptions);
1025
1049
  if (familyAtoms.size === 0)
1026
1050
  throw new Error("Should not be possible");
1027
- addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
1051
+ if (addFamilyAtomsToSet(family, familyAtoms, data, timestamp)) {
1052
+ if (!membershipChanged)
1053
+ membershipChanged = new Set;
1054
+ membershipChanged.add(family);
1055
+ }
1028
1056
  }
1029
1057
  }
1030
1058
  if (data.scopes && data.scopes.size > 0) {
@@ -1058,7 +1086,15 @@ var propagateAtomUpdate = (atoms, data, isInitOnly = false, notify, report, skip
1058
1086
  if (watching && reportIsSink)
1059
1087
  emitOrigin(effectiveReport);
1060
1088
  if (hasScopes) {
1061
- propagateToScopes(atoms, data, isInitOnly, notify, effectiveReport);
1089
+ let scopeAtoms = atoms;
1090
+ if (membershipChanged) {
1091
+ scopeAtoms = atoms.slice();
1092
+ for (const family of membershipChanged) {
1093
+ if (!scopeAtoms.includes(family))
1094
+ scopeAtoms.push(family);
1095
+ }
1096
+ }
1097
+ propagateToScopes(scopeAtoms, data, isInitOnly, notify, effectiveReport);
1062
1098
  }
1063
1099
  if (watching && !reportIsSink)
1064
1100
  emitOrigin(effectiveReport);
@@ -2520,7 +2556,13 @@ class Transaction {
2520
2556
  if (moveUpIfParent && this.parentTransaction)
2521
2557
  return this.parentTransaction.cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent);
2522
2558
  const currentFamilyList = this.get(family);
2523
- const clonedIndex = cloneAtomFamilyIndex(currentFamilyList.__index, parentIndex);
2559
+ const scopeFirstMaterialization = this.data.parent && !this._atomMap.has(family) && !this.data.values.has(family);
2560
+ let clonedIndex;
2561
+ if (scopeFirstMaterialization) {
2562
+ clonedIndex = createAtomFamilyIndex(parentIndex ?? currentFamilyList.__index);
2563
+ } else {
2564
+ clonedIndex = cloneAtomFamilyIndex(currentFamilyList.__index, parentIndex);
2565
+ }
2524
2566
  if (this._scopedTransactions?.size) {
2525
2567
  for (const [, scopedTxn] of this._scopedTransactions) {
2526
2568
  scopedTxn.cloneFamilyIntoTxn(family, clonedIndex, false);
@@ -3310,9 +3352,9 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
3310
3352
 
3311
3353
  // src/index.ts
3312
3354
  if (globalThis.__valdres__) {
3313
- throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.7"}`);
3355
+ throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.8"}`);
3314
3356
  } else {
3315
- globalThis.__valdres__ = "1.0.0-beta.7";
3357
+ globalThis.__valdres__ = "1.0.0-beta.8";
3316
3358
  }
3317
3359
  export {
3318
3360
  store,
@@ -14,5 +14,7 @@ export type AtomFamilyIndex = {
14
14
  export declare const cloneAtomFamilyIndex: (index: AtomFamilyIndex, parentIndexOverride?: AtomFamilyIndex) => AtomFamilyIndex;
15
15
  export declare const createAtomFamilyIndex: (parentIndex?: AtomFamilyIndex) => AtomFamilyIndex;
16
16
  export declare const deleteFamilyAtomsFromSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
17
+ export declare const initFamilyIndex: (family: Family<any>, data: StoreData) => any;
17
18
  export declare const recursivelyUpdateIndexes: (data: StoreData, family: Family<any>) => void;
18
- export declare const addFamilyAtomsToSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
19
+ export declare const ensureFamilyAncestorChain: (family: Family<any>, data: StoreData) => void;
20
+ export declare const addFamilyAtomsToSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => boolean;
@@ -1,8 +1,6 @@
1
1
  import type { Atom } from "../types/Atom";
2
2
  import type { AtomFamily } from "../types/AtomFamily";
3
3
  import type { StoreData } from "../types/StoreData";
4
- /** Register `key` in the parent's scopeValueIndex. Throws if called on
5
- * a root store — `parent` and `scopeIndexKeys` are only populated for
6
- * scoped stores (see createStoreData). */
7
- export declare const trackScopeValue: (key: WeakKey, data: StoreData) => void;
4
+ import { trackScopeValue } from "./trackScopeValue";
5
+ export { trackScopeValue };
8
6
  export declare const setValueInData: <Value extends unknown>(atom: Atom<Value> | AtomFamily<any, any>, value: Value, data: StoreData) => Value;
@@ -0,0 +1,10 @@
1
+ import type { StoreData } from "../types/StoreData";
2
+ /** Register `key` (an atom or family) in the parent's scopeValueIndex, recording
3
+ * it in this scope's scopeIndexKeys for cleanup on detach. Throws if called on
4
+ * a root store — `parent` and `scopeIndexKeys` are only populated for scoped
5
+ * stores (see createStoreData).
6
+ *
7
+ * Lives in its own module (rather than setValueInData) so both the scope-value
8
+ * write path (setValueInData) and the family-index path (atomFamilyIndex) can
9
+ * depend on it without an import cycle. */
10
+ export declare const trackScopeValue: (key: WeakKey, data: StoreData) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valdres",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.8",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Eigil Sagafos"