mobx-keystone 1.20.0 → 1.22.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/CHANGELOG.md +864 -853
- package/README.md +61 -61
- package/dist/mobx-keystone.esm.js +11336 -11148
- package/dist/mobx-keystone.esm.mjs +11336 -11148
- package/dist/mobx-keystone.umd.js +12229 -11738
- package/dist/types/actionMiddlewares/undoMiddleware.d.ts +1 -1
- package/dist/types/modelShared/prop.d.ts +5 -0
- package/dist/types/redux/connectReduxDevTools.d.ts +17 -4
- package/dist/types/ref/Ref.d.ts +1 -1
- package/dist/types/treeUtils/sandbox.d.ts +1 -1
- package/dist/types/types/TypeChecker.d.ts +1 -1
- package/dist/types/types/arrayBased/typesArray.d.ts +1 -1
- package/dist/types/types/arrayBased/typesTuple.d.ts +1 -1
- package/dist/types/types/objectBased/typesArraySet.d.ts +1 -1
- package/dist/types/types/objectBased/typesDataModelData.d.ts +1 -1
- package/dist/types/types/objectBased/typesModel.d.ts +1 -1
- package/dist/types/types/objectBased/typesObject.d.ts +3 -3
- package/dist/types/types/objectBased/typesObjectMap.d.ts +1 -1
- package/dist/types/types/objectBased/typesRecord.d.ts +1 -1
- package/dist/types/types/primitiveBased/typesPrimitive.d.ts +1 -1
- package/dist/types/types/types.d.ts +3 -3
- package/dist/types/types/utility/typesCodec.d.ts +1 -6
- package/dist/types/types/utility/typesCodecCore.d.ts +1 -1
- package/dist/types/types/utility/typesOr.d.ts +1 -1
- package/dist/types/types/utility/typesRefinement.d.ts +1 -1
- package/dist/types/types/utility/typesSkipCheck.d.ts +1 -1
- package/dist/types/types/utility/typesTag.d.ts +1 -1
- package/dist/types/wrappers/ObjectMap.d.ts +2 -0
- package/dist/types/wrappers/asMap.d.ts +10 -6
- package/package.json +14 -12
- package/src/action/applyAction.ts +125 -114
- package/src/action/applyMethodCall.ts +37 -37
- package/src/action/isModelAction.ts +16 -16
- package/src/action/middleware.ts +137 -137
- package/src/action/modelFlow.ts +240 -240
- package/src/action/modelFlowPromiseGenerator.ts +127 -125
- package/src/action/pendingActions.ts +42 -42
- package/src/action/wrapInAction.ts +156 -156
- package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +1 -1
- package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +172 -172
- package/src/actionMiddlewares/actionSerialization/arraySerializer.ts +20 -20
- package/src/actionMiddlewares/actionSerialization/dateSerializer.ts +17 -17
- package/src/actionMiddlewares/actionSerialization/mapSerializer.ts +42 -42
- package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +50 -50
- package/src/actionMiddlewares/actionSerialization/objectSnapshotSerializer.ts +21 -21
- package/src/actionMiddlewares/actionSerialization/plainObjectSerializer.ts +24 -32
- package/src/actionMiddlewares/actionSerialization/primitiveSerializer.ts +51 -51
- package/src/actionMiddlewares/actionSerialization/setSerializer.ts +37 -37
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +3 -3
- package/src/actionMiddlewares/onActionMiddleware.ts +2 -2
- package/src/actionMiddlewares/readonlyMiddleware.ts +2 -2
- package/src/actionMiddlewares/transactionMiddleware.ts +4 -4
- package/src/actionMiddlewares/undoMiddleware.ts +804 -796
- package/src/actionMiddlewares/utils.ts +2 -2
- package/src/computedTree/computedTree.ts +143 -143
- package/src/context/context.ts +1 -1
- package/src/dataModel/BaseDataModel.ts +194 -192
- package/src/dataModel/actions.ts +1 -1
- package/src/dataModel/newDataModel.ts +57 -57
- package/src/deepChange/index.ts +1 -1
- package/src/deepChange/onDeepChange.ts +244 -244
- package/src/frozen/Frozen.ts +146 -146
- package/src/globalConfig/globalConfig.ts +107 -107
- package/src/index.ts +24 -24
- package/src/model/BaseModel.ts +275 -273
- package/src/model/ModelConstructorOptions.ts +15 -15
- package/src/model/getModelMetadata.ts +51 -51
- package/src/model/index.ts +6 -6
- package/src/model/mixins.ts +288 -288
- package/src/model/newModel.ts +301 -301
- package/src/model/utils.ts +249 -249
- package/src/modelShared/modelDecorator.ts +260 -253
- package/src/modelShared/modelInfo.ts +50 -50
- package/src/modelShared/modelSymbols.ts +3 -3
- package/src/modelShared/newModel.ts +25 -25
- package/src/modelShared/prop.ts +713 -684
- package/src/modelShared/sharedInternalModel.ts +427 -417
- package/src/modelShared/utils.ts +24 -24
- package/src/parent/core.ts +65 -65
- package/src/parent/coreObjectChildren.ts +180 -180
- package/src/parent/detach.ts +47 -47
- package/src/parent/findParent.ts +1 -1
- package/src/parent/getChildrenObjects.ts +25 -25
- package/src/parent/path.ts +386 -381
- package/src/parent/setParent.ts +149 -149
- package/src/parent/walkTree.ts +1 -1
- package/src/patch/applyPatches.ts +187 -187
- package/src/patch/jsonPatch.ts +108 -108
- package/src/patch/patchRecorder.ts +6 -1
- package/src/redux/connectReduxDevTools.ts +39 -7
- package/src/redux/redux.ts +6 -2
- package/src/ref/Ref.ts +1 -1
- package/src/ref/core.ts +339 -345
- package/src/ref/customRef.ts +3 -3
- package/src/ref/rootRef.ts +100 -100
- package/src/rootStore/attachDetach.ts +89 -89
- package/src/rootStore/rootStore.ts +1 -1
- package/src/snapshot/SnapshotOf.ts +104 -104
- package/src/snapshot/SnapshotProcessingError.ts +45 -45
- package/src/snapshot/applySnapshot.ts +177 -181
- package/src/snapshot/cloneTreeValue.ts +30 -30
- package/src/snapshot/fromArraySnapshot.ts +27 -33
- package/src/snapshot/fromModelSnapshot.ts +70 -70
- package/src/snapshot/fromPlainObjectSnapshot.ts +47 -42
- package/src/snapshot/fromSnapshot.ts +198 -198
- package/src/snapshot/getSnapshot.ts +80 -79
- package/src/snapshot/index.ts +8 -8
- package/src/snapshot/internal.ts +230 -230
- package/src/snapshot/reconcileArraySnapshot.ts +70 -70
- package/src/snapshot/reconcileModelSnapshot.ts +155 -150
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +72 -72
- package/src/snapshot/reconcileSnapshot.ts +88 -88
- package/src/standardActions/actions.ts +64 -64
- package/src/standardActions/objectActions.ts +60 -60
- package/src/transforms/ImmutableDate.ts +93 -93
- package/src/transforms/asMap.ts +50 -50
- package/src/transforms/asSet.ts +22 -22
- package/src/transforms/bigint.ts +20 -20
- package/src/transforms/date.ts +40 -40
- package/src/treeUtils/deepEquals.ts +55 -55
- package/src/treeUtils/sandbox.ts +6 -3
- package/src/tweaker/TweakerPriority.ts +9 -9
- package/src/tweaker/tweak.ts +4 -3
- package/src/tweaker/tweakArray.ts +530 -475
- package/src/tweaker/tweakFrozen.ts +42 -42
- package/src/tweaker/tweakModel.ts +1 -1
- package/src/tweaker/tweakPlainObject.ts +355 -355
- package/src/tweaker/typeChecking.ts +101 -101
- package/src/types/SnapshotTypeMismatchError.ts +46 -46
- package/src/types/TypeCheckError.ts +183 -184
- package/src/types/TypeChecker.ts +202 -185
- package/src/types/arrayBased/typesArray.ts +136 -137
- package/src/types/arrayBased/typesTuple.ts +138 -139
- package/src/types/createPerEntryCachedCheck.ts +166 -160
- package/src/types/index.ts +6 -6
- package/src/types/objectBased/typesArraySet.ts +133 -134
- package/src/types/objectBased/typesDataModelData.ts +203 -204
- package/src/types/objectBased/typesModel.ts +220 -221
- package/src/types/objectBased/typesObject.ts +308 -310
- package/src/types/objectBased/typesObjectMap.ts +142 -143
- package/src/types/objectBased/typesRecord.ts +156 -157
- package/src/types/objectBased/typesRef.ts +89 -89
- package/src/types/primitiveBased/typesEnum.ts +63 -63
- package/src/types/primitiveBased/typesPrimitive.ts +219 -220
- package/src/types/registerDefaultStandardTypeResolvers.ts +21 -21
- package/src/types/resolveTypeChecker.ts +78 -78
- package/src/types/schemas.ts +208 -208
- package/src/types/tProp.ts +277 -268
- package/src/types/typeCheck.ts +21 -21
- package/src/types/typeCheckErrorUtils.ts +23 -23
- package/src/types/types.ts +142 -142
- package/src/types/utility/typeToStoredData.ts +37 -37
- package/src/types/utility/typesBigInt.ts +15 -15
- package/src/types/utility/typesCodec.ts +41 -38
- package/src/types/utility/typesCodecCore.ts +178 -178
- package/src/types/utility/typesCodecSupport.ts +806 -806
- package/src/types/utility/typesDate.ts +27 -27
- package/src/types/utility/typesMap.ts +253 -222
- package/src/types/utility/typesOr.ts +263 -259
- package/src/types/utility/typesRefinement.ts +131 -125
- package/src/types/utility/typesSet.ts +110 -110
- package/src/types/utility/typesSkipCheck.ts +69 -70
- package/src/types/utility/typesTag.ts +88 -82
- package/src/types/utility/typesUnchecked.ts +40 -40
- package/src/utils/AnyFunction.ts +4 -4
- package/src/utils/ModelPool.ts +59 -59
- package/src/utils/chainFns.ts +18 -18
- package/src/utils/decorators.ts +274 -274
- package/src/utils/errorDiagnostics.ts +204 -204
- package/src/utils/index.ts +443 -372
- package/src/wrappers/ArraySet.ts +156 -156
- package/src/wrappers/ObjectMap.ts +155 -136
- package/src/wrappers/asMap.ts +65 -30
- package/src/wrappers/asSet.ts +3 -3
|
@@ -1,79 +1,80 @@
|
|
|
1
|
-
import { assertTweakedObject, isTweakedObject } from "../tweaker/core"
|
|
2
|
-
import { toTreeNode } from "../tweaker/tweak"
|
|
3
|
-
import { resolveTypeChecker } from "../types/resolveTypeChecker"
|
|
4
|
-
import { AnyType, TypeToData, TypeToSnapshotOut } from "../types/schemas"
|
|
5
|
-
import { resolveCodecSupport } from "../types/utility/typesCodec"
|
|
6
|
-
import { failure, identityFn, isPrimitive } from "../utils"
|
|
7
|
-
import {
|
|
8
|
-
freezeInternalSnapshot,
|
|
9
|
-
getInternalSnapshot,
|
|
10
|
-
reportInternalSnapshotObserved,
|
|
11
|
-
} from "./internal"
|
|
12
|
-
import type { SnapshotOutOf } from "./SnapshotOf"
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Retrieves an immutable snapshot for a data structure.
|
|
16
|
-
* Since returned snapshots are immutable they will respect shallow equality, this is,
|
|
17
|
-
* if no changes are made then the snapshot will be kept the same.
|
|
18
|
-
*
|
|
19
|
-
* @template T Object type.
|
|
20
|
-
* @param nodeOrPrimitive Data structure, including primtives.
|
|
21
|
-
* @returns The snapshot.
|
|
22
|
-
*/
|
|
23
|
-
export function getSnapshot<T extends AnyType>(
|
|
24
|
-
type: T,
|
|
25
|
-
nodeOrPrimitive: TypeToData<T>
|
|
26
|
-
): TypeToSnapshotOut<T>
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Retrieves an immutable snapshot for a data structure.
|
|
30
|
-
* Since returned snapshots are immutable they will respect shallow equality, this is,
|
|
31
|
-
* if no changes are made then the snapshot will be kept the same.
|
|
32
|
-
*
|
|
33
|
-
* @template T Object type.
|
|
34
|
-
* @param nodeOrPrimitive Data structure, including primtives.
|
|
35
|
-
* @returns The snapshot.
|
|
36
|
-
*/
|
|
37
|
-
export function getSnapshot<T>(nodeOrPrimitive: T): SnapshotOutOf<T>
|
|
38
|
-
|
|
39
|
-
export function getSnapshot(arg1: any, arg2
|
|
40
|
-
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
1
|
+
import { assertTweakedObject, isTweakedObject } from "../tweaker/core"
|
|
2
|
+
import { toTreeNode } from "../tweaker/tweak"
|
|
3
|
+
import { resolveTypeChecker } from "../types/resolveTypeChecker"
|
|
4
|
+
import type { AnyType, TypeToData, TypeToSnapshotOut } from "../types/schemas"
|
|
5
|
+
import { resolveCodecSupport } from "../types/utility/typesCodec"
|
|
6
|
+
import { failure, identityFn, isPrimitive } from "../utils"
|
|
7
|
+
import {
|
|
8
|
+
freezeInternalSnapshot,
|
|
9
|
+
getInternalSnapshot,
|
|
10
|
+
reportInternalSnapshotObserved,
|
|
11
|
+
} from "./internal"
|
|
12
|
+
import type { SnapshotOutOf } from "./SnapshotOf"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves an immutable snapshot for a data structure.
|
|
16
|
+
* Since returned snapshots are immutable they will respect shallow equality, this is,
|
|
17
|
+
* if no changes are made then the snapshot will be kept the same.
|
|
18
|
+
*
|
|
19
|
+
* @template T Object type.
|
|
20
|
+
* @param nodeOrPrimitive Data structure, including primtives.
|
|
21
|
+
* @returns The snapshot.
|
|
22
|
+
*/
|
|
23
|
+
export function getSnapshot<T extends AnyType>(
|
|
24
|
+
type: T,
|
|
25
|
+
nodeOrPrimitive: TypeToData<T>
|
|
26
|
+
): TypeToSnapshotOut<T>
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Retrieves an immutable snapshot for a data structure.
|
|
30
|
+
* Since returned snapshots are immutable they will respect shallow equality, this is,
|
|
31
|
+
* if no changes are made then the snapshot will be kept the same.
|
|
32
|
+
*
|
|
33
|
+
* @template T Object type.
|
|
34
|
+
* @param nodeOrPrimitive Data structure, including primtives.
|
|
35
|
+
* @returns The snapshot.
|
|
36
|
+
*/
|
|
37
|
+
export function getSnapshot<T>(nodeOrPrimitive: T): SnapshotOutOf<T>
|
|
38
|
+
|
|
39
|
+
export function getSnapshot(...args: [arg1: any] | [arg1: any, arg2: any]): any {
|
|
40
|
+
const [arg1, arg2] = args
|
|
41
|
+
let toSnapshotProcessor: (sn: unknown) => unknown = identityFn
|
|
42
|
+
let nodeOrPrimitive: any
|
|
43
|
+
|
|
44
|
+
if (args.length >= 2) {
|
|
45
|
+
const codecSupport = resolveCodecSupport(arg1)
|
|
46
|
+
if (codecSupport.hasCodec) {
|
|
47
|
+
const storedTypeChecker = resolveTypeChecker(codecSupport.storedType)
|
|
48
|
+
const storedValue = codecSupport.adapter.toStored(arg2)
|
|
49
|
+
|
|
50
|
+
if (isPrimitive(storedValue)) {
|
|
51
|
+
return storedTypeChecker.toSnapshotProcessor(storedValue)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const storedTree = isTweakedObject(storedValue, true)
|
|
55
|
+
? storedValue
|
|
56
|
+
: toTreeNode(codecSupport.storedType, storedValue)
|
|
57
|
+
return storedTypeChecker.toSnapshotProcessor(getSnapshot(storedTree))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toSnapshotProcessor = resolveTypeChecker(arg1).toSnapshotProcessor
|
|
61
|
+
nodeOrPrimitive = arg2
|
|
62
|
+
} else {
|
|
63
|
+
nodeOrPrimitive = arg1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (isPrimitive(nodeOrPrimitive)) {
|
|
67
|
+
return toSnapshotProcessor(nodeOrPrimitive)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
assertTweakedObject(nodeOrPrimitive, "nodeOrPrimitive")
|
|
71
|
+
|
|
72
|
+
const snapshot = getInternalSnapshot(nodeOrPrimitive)
|
|
73
|
+
if (!snapshot) {
|
|
74
|
+
throw failure("getSnapshot is not supported for this kind of object")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
freezeInternalSnapshot(snapshot.transformed)
|
|
78
|
+
reportInternalSnapshotObserved(snapshot)
|
|
79
|
+
return toSnapshotProcessor(snapshot.transformed)
|
|
80
|
+
}
|
package/src/snapshot/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from "./applySnapshot"
|
|
2
|
-
export * from "./clone"
|
|
3
|
-
export * from "./cloneTreeValue"
|
|
4
|
-
export * from "./fromSnapshot"
|
|
5
|
-
export * from "./getSnapshot"
|
|
6
|
-
export * from "./onSnapshot"
|
|
7
|
-
export * from "./SnapshotOf"
|
|
8
|
-
export * from "./SnapshotProcessingError"
|
|
1
|
+
export * from "./applySnapshot"
|
|
2
|
+
export * from "./clone"
|
|
3
|
+
export * from "./cloneTreeValue"
|
|
4
|
+
export * from "./fromSnapshot"
|
|
5
|
+
export * from "./getSnapshot"
|
|
6
|
+
export * from "./onSnapshot"
|
|
7
|
+
export * from "./SnapshotOf"
|
|
8
|
+
export * from "./SnapshotProcessingError"
|
package/src/snapshot/internal.ts
CHANGED
|
@@ -1,230 +1,230 @@
|
|
|
1
|
-
import { action, createAtom, IAtom } from "mobx"
|
|
2
|
-
import { fastGetParentPath, ParentPath } from "../parent/path"
|
|
3
|
-
import { invalidateCachedToSnapshotProcessorResult } from "../types/TypeChecker"
|
|
4
|
-
import { isPrimitive } from "../utils"
|
|
5
|
-
import { PrimitiveValue } from "../utils/types"
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @internal
|
|
9
|
-
*/
|
|
10
|
-
export type SnapshotTransformFn = (sn: unknown) => unknown
|
|
11
|
-
|
|
12
|
-
interface SnapshotData {
|
|
13
|
-
untransformed: any
|
|
14
|
-
readonly transformFn: SnapshotTransformFn | undefined
|
|
15
|
-
transformed: any
|
|
16
|
-
atom: IAtom | undefined
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const snapshots = new WeakMap<object, SnapshotData>()
|
|
20
|
-
|
|
21
|
-
// true if it has been accessed publicly and therefore should be cloned
|
|
22
|
-
// rather than modified in place
|
|
23
|
-
const frozenState = new WeakMap<object, boolean>()
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @internal
|
|
27
|
-
*/
|
|
28
|
-
export function getInternalSnapshot<T extends object>(
|
|
29
|
-
value: T
|
|
30
|
-
): Readonly<SnapshotData> | undefined {
|
|
31
|
-
return snapshots.get(value)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface InternalSnapshotParent {
|
|
35
|
-
parentSnapshot: SnapshotData | undefined
|
|
36
|
-
parentPath: ParentPath<any>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function getInternalSnapshotParent(
|
|
40
|
-
sn: Readonly<SnapshotData> | undefined,
|
|
41
|
-
parentPath: ParentPath<any> | undefined
|
|
42
|
-
): InternalSnapshotParent | undefined {
|
|
43
|
-
if (!(parentPath && sn)) {
|
|
44
|
-
return undefined
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const parentSn = getInternalSnapshot(parentPath.parent)
|
|
48
|
-
if (!parentSn) {
|
|
49
|
-
return undefined
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
parentSnapshot: parentSn,
|
|
54
|
-
parentPath: parentPath,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @internal
|
|
60
|
-
*/
|
|
61
|
-
export const unsetInternalSnapshot = action("unsetInternalSnapshot", (value: any) => {
|
|
62
|
-
const oldSn = getInternalSnapshot(value)
|
|
63
|
-
|
|
64
|
-
if (oldSn) {
|
|
65
|
-
snapshots.delete(value)
|
|
66
|
-
oldSn.atom?.reportChanged()
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @internal
|
|
72
|
-
*/
|
|
73
|
-
export const setNewInternalSnapshot = action(
|
|
74
|
-
"setNewInternalSnapshot",
|
|
75
|
-
<T extends object>(
|
|
76
|
-
value: any,
|
|
77
|
-
untransformed: T,
|
|
78
|
-
transformFn: SnapshotTransformFn | undefined,
|
|
79
|
-
markAsFrozen = false
|
|
80
|
-
): void => {
|
|
81
|
-
const transformed: any = transformFn ? transformFn(untransformed) : untransformed
|
|
82
|
-
|
|
83
|
-
const sn: SnapshotData = {
|
|
84
|
-
untransformed,
|
|
85
|
-
transformFn,
|
|
86
|
-
transformed,
|
|
87
|
-
atom: undefined, // will be created when first observed
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
frozenState.set(untransformed, markAsFrozen)
|
|
91
|
-
|
|
92
|
-
if (transformed !== undefined && transformed !== untransformed) {
|
|
93
|
-
frozenState.set(transformed, markAsFrozen)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
snapshots.set(value, sn)
|
|
97
|
-
|
|
98
|
-
sn.atom?.reportChanged()
|
|
99
|
-
}
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
type MutateInternalSnapshotFn<T> = (prevSn: T) => void
|
|
103
|
-
|
|
104
|
-
function updateParentSnapshots(value: any, sn: SnapshotData): void {
|
|
105
|
-
// also update parent(s) snapshot(s) if needed
|
|
106
|
-
const parent = getInternalSnapshotParent(sn, fastGetParentPath(value, false))
|
|
107
|
-
if (!parent) {
|
|
108
|
-
return
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const { parentSnapshot, parentPath } = parent
|
|
112
|
-
// might be false in the cases where the parent has not yet been created
|
|
113
|
-
if (!parentSnapshot) {
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const path = parentPath.path
|
|
118
|
-
|
|
119
|
-
// patches for parent changes should not be emitted
|
|
120
|
-
updateInternalSnapshot(parentPath.parent, (objOrArray: any) => {
|
|
121
|
-
objOrArray
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* @internal
|
|
127
|
-
*/
|
|
128
|
-
export const updateInternalSnapshot = action(
|
|
129
|
-
"updateInternalSnapshot",
|
|
130
|
-
<T extends object>(value: any, mutate: MutateInternalSnapshotFn<T>): void => {
|
|
131
|
-
const sn = getInternalSnapshot(value)! as SnapshotData
|
|
132
|
-
|
|
133
|
-
let untransformed = sn.untransformed
|
|
134
|
-
const snFrozen = frozenState.get(untransformed)!
|
|
135
|
-
if (snFrozen) {
|
|
136
|
-
if (Array.isArray(untransformed)) {
|
|
137
|
-
untransformed = untransformed.slice()
|
|
138
|
-
} else {
|
|
139
|
-
untransformed =
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
// the processor cached result is no longer valid since we will
|
|
143
|
-
// mutate the object
|
|
144
|
-
invalidateCachedToSnapshotProcessorResult(untransformed)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
mutate(untransformed)
|
|
148
|
-
|
|
149
|
-
sn.untransformed = untransformed
|
|
150
|
-
sn.transformed = sn.transformFn ? sn.transformFn(untransformed) : untransformed
|
|
151
|
-
|
|
152
|
-
frozenState.set(sn.untransformed, false)
|
|
153
|
-
if (sn.transformed !== undefined) {
|
|
154
|
-
frozenState.set(sn.transformed, false)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
sn.atom?.reportChanged()
|
|
158
|
-
updateParentSnapshots(value, sn)
|
|
159
|
-
}
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* @internal
|
|
164
|
-
*/
|
|
165
|
-
export const refreshInternalSnapshot = action("refreshInternalSnapshot", (value: any): void => {
|
|
166
|
-
const sn = getInternalSnapshot(value) as SnapshotData | undefined
|
|
167
|
-
if (!sn?.transformFn) {
|
|
168
|
-
return
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const oldTransformed = sn.transformed
|
|
172
|
-
const newTransformed: any = sn.transformFn(sn.untransformed)
|
|
173
|
-
|
|
174
|
-
if (oldTransformed === newTransformed) {
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
sn.transformed = newTransformed
|
|
179
|
-
|
|
180
|
-
// transformed snapshots created by internal transforms must be tracked as mutable
|
|
181
|
-
// until they are exposed through getSnapshot / freezeInternalSnapshot.
|
|
182
|
-
if (frozenState.get(newTransformed) === undefined) {
|
|
183
|
-
frozenState.set(newTransformed, false)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
sn.atom?.reportChanged()
|
|
187
|
-
updateParentSnapshots(value, sn)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* @internal
|
|
192
|
-
*/
|
|
193
|
-
export function reportInternalSnapshotObserved(sn: SnapshotData) {
|
|
194
|
-
if (!sn.atom) {
|
|
195
|
-
sn.atom = createAtom("snapshot")
|
|
196
|
-
}
|
|
197
|
-
sn.atom.reportObserved()
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* @internal
|
|
202
|
-
*/
|
|
203
|
-
export function freezeInternalSnapshot<T extends PrimitiveValue | object>(data: T): T {
|
|
204
|
-
if (isPrimitive(data)) {
|
|
205
|
-
return data
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// this might be undefined if the data comes from example from transforms
|
|
209
|
-
const isFrozen = frozenState.get(data)
|
|
210
|
-
|
|
211
|
-
if (isFrozen === undefined || isFrozen) {
|
|
212
|
-
// already frozen or an external data (e.g. from a transform)
|
|
213
|
-
return data
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (Array.isArray(data)) {
|
|
217
|
-
for (let i = 0; i < data.length; i++) {
|
|
218
|
-
freezeInternalSnapshot(data[i])
|
|
219
|
-
}
|
|
220
|
-
} else {
|
|
221
|
-
const keys = Object.keys(data)
|
|
222
|
-
for (let i = 0; i < keys.length; i++) {
|
|
223
|
-
freezeInternalSnapshot((data as any)[keys[i]])
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
frozenState.set(data, true)
|
|
228
|
-
|
|
229
|
-
return data
|
|
230
|
-
}
|
|
1
|
+
import { action, createAtom, type IAtom } from "mobx"
|
|
2
|
+
import { fastGetParentPath, type ParentPath } from "../parent/path"
|
|
3
|
+
import { invalidateCachedToSnapshotProcessorResult } from "../types/TypeChecker"
|
|
4
|
+
import { clonePlainObject, isPrimitive, setOwnProp } from "../utils"
|
|
5
|
+
import type { PrimitiveValue } from "../utils/types"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export type SnapshotTransformFn = (sn: unknown) => unknown
|
|
11
|
+
|
|
12
|
+
interface SnapshotData {
|
|
13
|
+
untransformed: any
|
|
14
|
+
readonly transformFn: SnapshotTransformFn | undefined
|
|
15
|
+
transformed: any
|
|
16
|
+
atom: IAtom | undefined
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const snapshots = new WeakMap<object, SnapshotData>()
|
|
20
|
+
|
|
21
|
+
// true if it has been accessed publicly and therefore should be cloned
|
|
22
|
+
// rather than modified in place
|
|
23
|
+
const frozenState = new WeakMap<object, boolean>()
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export function getInternalSnapshot<T extends object>(
|
|
29
|
+
value: T
|
|
30
|
+
): Readonly<SnapshotData> | undefined {
|
|
31
|
+
return snapshots.get(value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface InternalSnapshotParent {
|
|
35
|
+
parentSnapshot: SnapshotData | undefined
|
|
36
|
+
parentPath: ParentPath<any>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getInternalSnapshotParent(
|
|
40
|
+
sn: Readonly<SnapshotData> | undefined,
|
|
41
|
+
parentPath: ParentPath<any> | undefined
|
|
42
|
+
): InternalSnapshotParent | undefined {
|
|
43
|
+
if (!(parentPath && sn)) {
|
|
44
|
+
return undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const parentSn = getInternalSnapshot(parentPath.parent)
|
|
48
|
+
if (!parentSn) {
|
|
49
|
+
return undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
parentSnapshot: parentSn,
|
|
54
|
+
parentPath: parentPath,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export const unsetInternalSnapshot = action("unsetInternalSnapshot", (value: any) => {
|
|
62
|
+
const oldSn = getInternalSnapshot(value)
|
|
63
|
+
|
|
64
|
+
if (oldSn) {
|
|
65
|
+
snapshots.delete(value)
|
|
66
|
+
oldSn.atom?.reportChanged()
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export const setNewInternalSnapshot = action(
|
|
74
|
+
"setNewInternalSnapshot",
|
|
75
|
+
<T extends object>(
|
|
76
|
+
value: any,
|
|
77
|
+
untransformed: T,
|
|
78
|
+
transformFn: SnapshotTransformFn | undefined,
|
|
79
|
+
markAsFrozen = false
|
|
80
|
+
): void => {
|
|
81
|
+
const transformed: any = transformFn ? transformFn(untransformed) : untransformed
|
|
82
|
+
|
|
83
|
+
const sn: SnapshotData = {
|
|
84
|
+
untransformed,
|
|
85
|
+
transformFn,
|
|
86
|
+
transformed,
|
|
87
|
+
atom: undefined, // will be created when first observed
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
frozenState.set(untransformed, markAsFrozen)
|
|
91
|
+
|
|
92
|
+
if (transformed !== undefined && transformed !== untransformed) {
|
|
93
|
+
frozenState.set(transformed, markAsFrozen)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
snapshots.set(value, sn)
|
|
97
|
+
|
|
98
|
+
sn.atom?.reportChanged()
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
type MutateInternalSnapshotFn<T> = (prevSn: T) => void
|
|
103
|
+
|
|
104
|
+
function updateParentSnapshots(value: any, sn: SnapshotData): void {
|
|
105
|
+
// also update parent(s) snapshot(s) if needed
|
|
106
|
+
const parent = getInternalSnapshotParent(sn, fastGetParentPath(value, false))
|
|
107
|
+
if (!parent) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const { parentSnapshot, parentPath } = parent
|
|
112
|
+
// might be false in the cases where the parent has not yet been created
|
|
113
|
+
if (!parentSnapshot) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const path = parentPath.path
|
|
118
|
+
|
|
119
|
+
// patches for parent changes should not be emitted
|
|
120
|
+
updateInternalSnapshot(parentPath.parent, (objOrArray: any) => {
|
|
121
|
+
setOwnProp(objOrArray, path, sn.transformed)
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
128
|
+
export const updateInternalSnapshot = action(
|
|
129
|
+
"updateInternalSnapshot",
|
|
130
|
+
<T extends object>(value: any, mutate: MutateInternalSnapshotFn<T>): void => {
|
|
131
|
+
const sn = getInternalSnapshot(value)! as SnapshotData
|
|
132
|
+
|
|
133
|
+
let untransformed = sn.untransformed
|
|
134
|
+
const snFrozen = frozenState.get(untransformed)!
|
|
135
|
+
if (snFrozen) {
|
|
136
|
+
if (Array.isArray(untransformed)) {
|
|
137
|
+
untransformed = untransformed.slice()
|
|
138
|
+
} else {
|
|
139
|
+
untransformed = clonePlainObject(untransformed)
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
// the processor cached result is no longer valid since we will
|
|
143
|
+
// mutate the object
|
|
144
|
+
invalidateCachedToSnapshotProcessorResult(untransformed)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
mutate(untransformed)
|
|
148
|
+
|
|
149
|
+
sn.untransformed = untransformed
|
|
150
|
+
sn.transformed = sn.transformFn ? sn.transformFn(untransformed) : untransformed
|
|
151
|
+
|
|
152
|
+
frozenState.set(sn.untransformed, false)
|
|
153
|
+
if (sn.transformed !== undefined) {
|
|
154
|
+
frozenState.set(sn.transformed, false)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
sn.atom?.reportChanged()
|
|
158
|
+
updateParentSnapshots(value, sn)
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
export const refreshInternalSnapshot = action("refreshInternalSnapshot", (value: any): void => {
|
|
166
|
+
const sn = getInternalSnapshot(value) as SnapshotData | undefined
|
|
167
|
+
if (!sn?.transformFn) {
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const oldTransformed = sn.transformed
|
|
172
|
+
const newTransformed: any = sn.transformFn(sn.untransformed)
|
|
173
|
+
|
|
174
|
+
if (oldTransformed === newTransformed) {
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
sn.transformed = newTransformed
|
|
179
|
+
|
|
180
|
+
// transformed snapshots created by internal transforms must be tracked as mutable
|
|
181
|
+
// until they are exposed through getSnapshot / freezeInternalSnapshot.
|
|
182
|
+
if (frozenState.get(newTransformed) === undefined) {
|
|
183
|
+
frozenState.set(newTransformed, false)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
sn.atom?.reportChanged()
|
|
187
|
+
updateParentSnapshots(value, sn)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @internal
|
|
192
|
+
*/
|
|
193
|
+
export function reportInternalSnapshotObserved(sn: SnapshotData) {
|
|
194
|
+
if (!sn.atom) {
|
|
195
|
+
sn.atom = createAtom("snapshot")
|
|
196
|
+
}
|
|
197
|
+
sn.atom.reportObserved()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @internal
|
|
202
|
+
*/
|
|
203
|
+
export function freezeInternalSnapshot<T extends PrimitiveValue | object>(data: T): T {
|
|
204
|
+
if (isPrimitive(data)) {
|
|
205
|
+
return data
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// this might be undefined if the data comes from example from transforms
|
|
209
|
+
const isFrozen = frozenState.get(data)
|
|
210
|
+
|
|
211
|
+
if (isFrozen === undefined || isFrozen) {
|
|
212
|
+
// already frozen or an external data (e.g. from a transform)
|
|
213
|
+
return data
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (Array.isArray(data)) {
|
|
217
|
+
for (let i = 0; i < data.length; i++) {
|
|
218
|
+
freezeInternalSnapshot(data[i])
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
const keys = Object.keys(data)
|
|
222
|
+
for (let i = 0; i < keys.length; i++) {
|
|
223
|
+
freezeInternalSnapshot((data as any)[keys[i]])
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
frozenState.set(data, true)
|
|
228
|
+
|
|
229
|
+
return data
|
|
230
|
+
}
|