jotai-state-tree 1.2.0 → 1.3.0
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/{chunk-3TQNT4MR.mjs → chunk-OAXK4KFM.mjs} +46 -16
- package/dist/index.d.mts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +288 -40
- package/dist/index.mjs +245 -25
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +42 -16
- package/dist/react.mjs +1 -1
- package/dist/{tree-B2tSEN1S.d.mts → tree-BV2K9utF.d.mts} +4 -0
- package/dist/{tree-B2tSEN1S.d.ts → tree-BV2K9utF.d.ts} +4 -0
- package/package.json +1 -1
- package/src/__tests__/index.test.ts +327 -0
- package/src/__tests__/performance.test.ts +2 -2
- package/src/__tests__/snapshot-sharing.test.ts +179 -0
- package/src/array.ts +9 -0
- package/src/index.ts +1 -37
- package/src/lifecycle.ts +256 -29
- package/src/map.ts +6 -1
- package/src/model.ts +17 -4
- package/src/tree.ts +52 -22
|
@@ -77,6 +77,9 @@ var StateTreeNode = class {
|
|
|
77
77
|
this.patchListeners = /* @__PURE__ */ new Set();
|
|
78
78
|
/** Volatile state (non-serialized) */
|
|
79
79
|
this.volatileState = {};
|
|
80
|
+
/** Cached snapshot for structural sharing optimization */
|
|
81
|
+
this.cachedSnapshot = void 0;
|
|
82
|
+
this.isSnapshotDirty = true;
|
|
80
83
|
this.$id = generateNodeId();
|
|
81
84
|
this.$type = type;
|
|
82
85
|
this.$env = env ?? parent?.$env;
|
|
@@ -86,6 +89,15 @@ var StateTreeNode = class {
|
|
|
86
89
|
nodeRegistry.set(this.$id, { node: new WeakRef(this), instance: null });
|
|
87
90
|
nodeFinalizationRegistry.register(this, this.$id, this);
|
|
88
91
|
}
|
|
92
|
+
invalidateSnapshot() {
|
|
93
|
+
if (!this.isSnapshotDirty) {
|
|
94
|
+
this.isSnapshotDirty = true;
|
|
95
|
+
this.cachedSnapshot = void 0;
|
|
96
|
+
if (this.$parent) {
|
|
97
|
+
this.$parent.invalidateSnapshot();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
89
101
|
/** Set the instance reference */
|
|
90
102
|
setInstance(instance) {
|
|
91
103
|
const entry = nodeRegistry.get(this.$id);
|
|
@@ -110,6 +122,9 @@ var StateTreeNode = class {
|
|
|
110
122
|
);
|
|
111
123
|
}
|
|
112
124
|
const oldValue = this.getValue();
|
|
125
|
+
if (oldValue === value) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
113
128
|
globalStore.set(this.valueAtom, value);
|
|
114
129
|
this.notifyPatch(
|
|
115
130
|
{ op: "replace", path: this.$path, value },
|
|
@@ -127,6 +142,7 @@ var StateTreeNode = class {
|
|
|
127
142
|
child.$env = child.$env ?? this.$env;
|
|
128
143
|
this.children.set(key, child);
|
|
129
144
|
lifecycleHookHandlers.runAfterAttach?.(child);
|
|
145
|
+
this.invalidateSnapshot();
|
|
130
146
|
}
|
|
131
147
|
/** Recursively update the path of a node and all its children */
|
|
132
148
|
updatePathRecursively(node, newPath) {
|
|
@@ -142,6 +158,7 @@ var StateTreeNode = class {
|
|
|
142
158
|
if (child) {
|
|
143
159
|
child.destroy();
|
|
144
160
|
this.children.delete(key);
|
|
161
|
+
this.invalidateSnapshot();
|
|
145
162
|
}
|
|
146
163
|
}
|
|
147
164
|
/** Get a child node */
|
|
@@ -204,6 +221,7 @@ var StateTreeNode = class {
|
|
|
204
221
|
}
|
|
205
222
|
/** Notify snapshot listeners */
|
|
206
223
|
notifySnapshotChange() {
|
|
224
|
+
this.invalidateSnapshot();
|
|
207
225
|
let current = this;
|
|
208
226
|
while (current) {
|
|
209
227
|
const snapshot = getSnapshotFromNode(current);
|
|
@@ -261,6 +279,7 @@ var StateTreeNode = class {
|
|
|
261
279
|
detach() {
|
|
262
280
|
if (this.$parent) {
|
|
263
281
|
lifecycleHookHandlers.runBeforeDetach?.(this);
|
|
282
|
+
const parent = this.$parent;
|
|
264
283
|
for (const [key, child] of this.$parent.children) {
|
|
265
284
|
if (child === this) {
|
|
266
285
|
this.$parent.children.delete(key);
|
|
@@ -269,6 +288,7 @@ var StateTreeNode = class {
|
|
|
269
288
|
}
|
|
270
289
|
this.$parent = null;
|
|
271
290
|
this.$path = "";
|
|
291
|
+
parent.invalidateSnapshot();
|
|
272
292
|
}
|
|
273
293
|
}
|
|
274
294
|
};
|
|
@@ -283,38 +303,44 @@ function hasStateTreeNode(instance) {
|
|
|
283
303
|
return instance !== null && typeof instance === "object" && $treenode in instance;
|
|
284
304
|
}
|
|
285
305
|
function getSnapshotFromNode(node) {
|
|
306
|
+
if (!node.isSnapshotDirty && node.cachedSnapshot !== void 0) {
|
|
307
|
+
return node.cachedSnapshot;
|
|
308
|
+
}
|
|
286
309
|
const type = node.$type;
|
|
287
310
|
const value = node.getValue();
|
|
311
|
+
let snapshot;
|
|
288
312
|
if (type._kind === "model") {
|
|
289
|
-
const
|
|
313
|
+
const modelSnapshot = {};
|
|
290
314
|
const children = node.getChildren();
|
|
291
315
|
for (const [key, childNode] of children) {
|
|
292
|
-
|
|
316
|
+
modelSnapshot[key] = getSnapshotFromNode(childNode);
|
|
293
317
|
}
|
|
294
318
|
if (node.postProcessor) {
|
|
295
|
-
|
|
319
|
+
snapshot = node.postProcessor(modelSnapshot);
|
|
320
|
+
} else {
|
|
321
|
+
snapshot = modelSnapshot;
|
|
296
322
|
}
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
if (type._kind === "array") {
|
|
323
|
+
} else if (type._kind === "array") {
|
|
300
324
|
const arr = value;
|
|
301
|
-
|
|
325
|
+
snapshot = arr.map((_, index) => {
|
|
302
326
|
const childNode = node.getChild(String(index));
|
|
303
327
|
return childNode ? getSnapshotFromNode(childNode) : arr[index];
|
|
304
328
|
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const snapshot = {};
|
|
329
|
+
} else if (type._kind === "map") {
|
|
330
|
+
const mapSnapshot = {};
|
|
308
331
|
const children = node.getChildren();
|
|
309
332
|
for (const [key, childNode] of children) {
|
|
310
|
-
|
|
333
|
+
mapSnapshot[key] = getSnapshotFromNode(childNode);
|
|
311
334
|
}
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
335
|
+
snapshot = mapSnapshot;
|
|
336
|
+
} else if (type._kind === "reference") {
|
|
337
|
+
snapshot = node.identifierValue ?? value;
|
|
338
|
+
} else {
|
|
339
|
+
snapshot = value;
|
|
316
340
|
}
|
|
317
|
-
|
|
341
|
+
node.cachedSnapshot = snapshot;
|
|
342
|
+
node.isSnapshotDirty = false;
|
|
343
|
+
return snapshot;
|
|
318
344
|
}
|
|
319
345
|
function applySnapshotToNode(node, snapshot) {
|
|
320
346
|
if (!node.$isAlive) {
|
|
@@ -591,6 +617,9 @@ function recordPatches(target) {
|
|
|
591
617
|
};
|
|
592
618
|
}
|
|
593
619
|
var currentAction = null;
|
|
620
|
+
function getCurrentAction() {
|
|
621
|
+
return currentAction;
|
|
622
|
+
}
|
|
594
623
|
var actionListeners = /* @__PURE__ */ new Set();
|
|
595
624
|
var actionRecorderHooks = [];
|
|
596
625
|
function registerActionRecorderHook(hook) {
|
|
@@ -856,6 +885,7 @@ export {
|
|
|
856
885
|
onPatch,
|
|
857
886
|
applyPatch,
|
|
858
887
|
recordPatches,
|
|
888
|
+
getCurrentAction,
|
|
859
889
|
registerActionRecorderHook,
|
|
860
890
|
isActionRunning,
|
|
861
891
|
trackAction,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-
|
|
2
|
-
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-
|
|
1
|
+
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-BV2K9utF.mjs';
|
|
2
|
+
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-BV2K9utF.mjs';
|
|
3
3
|
import 'jotai/vanilla/internals';
|
|
4
4
|
import 'jotai';
|
|
5
5
|
|
|
@@ -362,9 +362,14 @@ interface IMiddlewareHandler {
|
|
|
362
362
|
(call: IMiddlewareEvent, next: (call: IMiddlewareEvent, callback?: (value: unknown) => unknown) => unknown, abort: (value: unknown) => unknown): unknown;
|
|
363
363
|
}
|
|
364
364
|
/**
|
|
365
|
-
* Add middleware to the
|
|
365
|
+
* Add middleware to the stack/node
|
|
366
366
|
*/
|
|
367
367
|
declare function addMiddleware(target: unknown, handler: IMiddlewareHandler, includeHooks?: boolean): IDisposer;
|
|
368
|
+
/**
|
|
369
|
+
* Creates an async action (generator function) that can be yielded.
|
|
370
|
+
* Compatible with MST's flow().
|
|
371
|
+
*/
|
|
372
|
+
declare function flow<Args extends unknown[], R>(generator: (...args: Args) => Generator<Promise<unknown>, R, unknown>): (...args: Args) => Promise<R>;
|
|
368
373
|
interface ISerializedActionCall {
|
|
369
374
|
name: string;
|
|
370
375
|
path: string;
|
|
@@ -646,11 +651,6 @@ declare const types: {
|
|
|
646
651
|
safeDynamicReference: typeof safeDynamicReference;
|
|
647
652
|
};
|
|
648
653
|
|
|
649
|
-
/**
|
|
650
|
-
* Creates an async action (generator function) that can be yielded.
|
|
651
|
-
* Compatible with MST's flow().
|
|
652
|
-
*/
|
|
653
|
-
declare function flow<Args extends unknown[], R>(generator: (...args: Args) => Generator<Promise<unknown>, R, unknown>): (...args: Args) => Promise<R>;
|
|
654
654
|
/**
|
|
655
655
|
* Cast a value to a different type.
|
|
656
656
|
* Useful for working around TypeScript limitations.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-
|
|
2
|
-
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-
|
|
1
|
+
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-BV2K9utF.js';
|
|
2
|
+
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-BV2K9utF.js';
|
|
3
3
|
import 'jotai/vanilla/internals';
|
|
4
4
|
import 'jotai';
|
|
5
5
|
|
|
@@ -362,9 +362,14 @@ interface IMiddlewareHandler {
|
|
|
362
362
|
(call: IMiddlewareEvent, next: (call: IMiddlewareEvent, callback?: (value: unknown) => unknown) => unknown, abort: (value: unknown) => unknown): unknown;
|
|
363
363
|
}
|
|
364
364
|
/**
|
|
365
|
-
* Add middleware to the
|
|
365
|
+
* Add middleware to the stack/node
|
|
366
366
|
*/
|
|
367
367
|
declare function addMiddleware(target: unknown, handler: IMiddlewareHandler, includeHooks?: boolean): IDisposer;
|
|
368
|
+
/**
|
|
369
|
+
* Creates an async action (generator function) that can be yielded.
|
|
370
|
+
* Compatible with MST's flow().
|
|
371
|
+
*/
|
|
372
|
+
declare function flow<Args extends unknown[], R>(generator: (...args: Args) => Generator<Promise<unknown>, R, unknown>): (...args: Args) => Promise<R>;
|
|
368
373
|
interface ISerializedActionCall {
|
|
369
374
|
name: string;
|
|
370
375
|
path: string;
|
|
@@ -646,11 +651,6 @@ declare const types: {
|
|
|
646
651
|
safeDynamicReference: typeof safeDynamicReference;
|
|
647
652
|
};
|
|
648
653
|
|
|
649
|
-
/**
|
|
650
|
-
* Creates an async action (generator function) that can be yielded.
|
|
651
|
-
* Compatible with MST's flow().
|
|
652
|
-
*/
|
|
653
|
-
declare function flow<Args extends unknown[], R>(generator: (...args: Args) => Generator<Promise<unknown>, R, unknown>): (...args: Args) => Promise<R>;
|
|
654
654
|
/**
|
|
655
655
|
* Cast a value to a different type.
|
|
656
656
|
* Useful for working around TypeScript limitations.
|