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,172 +1,172 @@
|
|
|
1
|
-
import { runInAction } from "mobx"
|
|
2
|
-
import { applyAction } from "../../action/applyAction"
|
|
3
|
-
import { frozenKey } from "../../frozen/Frozen"
|
|
4
|
-
import { getModelIdPropertyName } from "../../model/getModelMetadata"
|
|
5
|
-
import { isModel } from "../../model/utils"
|
|
6
|
-
import { resolvePath } from "../../parent/path"
|
|
7
|
-
import type { WritablePath } from "../../parent/pathTypes"
|
|
8
|
-
import { applyPatches } from "../../patch/applyPatches"
|
|
9
|
-
import { onPatches } from "../../patch/emitPatch"
|
|
10
|
-
import type { Patch } from "../../patch/Patch"
|
|
11
|
-
import { assertTweakedObject } from "../../tweaker/core"
|
|
12
|
-
import { failure, isObject } from "../../utils"
|
|
13
|
-
import { deserializeActionCall, SerializedActionCall } from "./actionSerialization"
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Serialized action call with model ID overrides.
|
|
17
|
-
* Can be generated with `applySerializedActionAndTrackNewModelIds`.
|
|
18
|
-
* To be applied with `applySerializedActionAndSyncNewModelIds`.
|
|
19
|
-
*/
|
|
20
|
-
export interface SerializedActionCallWithModelIdOverrides extends SerializedActionCall {
|
|
21
|
-
/**
|
|
22
|
-
* Model Id overrides to be applied at the end of applying the action.
|
|
23
|
-
*/
|
|
24
|
-
readonly modelIdOverrides: ReadonlyArray<Patch>
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Applies (runs) a serialized action over a target object.
|
|
29
|
-
* In this mode newly generated / modified model IDs will be tracked
|
|
30
|
-
* so they can be later synchronized when applying it on another machine
|
|
31
|
-
* via `applySerializedActionAndSyncNewModelIds`.
|
|
32
|
-
* This means this method is usually used on the server side.
|
|
33
|
-
*
|
|
34
|
-
* If you intend to apply non-serialized actions check `applyAction` instead.
|
|
35
|
-
*
|
|
36
|
-
* @param subtreeRoot Subtree root target object to run the action over.
|
|
37
|
-
* @param call The serialized action, usually as coming from the server/client.
|
|
38
|
-
* @returns The return value of the action, if any, plus a new serialized action
|
|
39
|
-
* with model overrides.
|
|
40
|
-
*/
|
|
41
|
-
export function applySerializedActionAndTrackNewModelIds<TRet = any>(
|
|
42
|
-
subtreeRoot: object,
|
|
43
|
-
call: SerializedActionCall
|
|
44
|
-
): {
|
|
45
|
-
returnValue: TRet
|
|
46
|
-
serializedActionCall: SerializedActionCallWithModelIdOverrides
|
|
47
|
-
} {
|
|
48
|
-
if (!call.serialized) {
|
|
49
|
-
throw failure("cannot apply a non-serialized action call, use 'applyAction' instead")
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
assertTweakedObject(subtreeRoot, "subtreeRoot")
|
|
53
|
-
|
|
54
|
-
const deserializedCall = deserializeActionCall(call, subtreeRoot)
|
|
55
|
-
|
|
56
|
-
const modelIdOverrides: Patch[] = []
|
|
57
|
-
|
|
58
|
-
// set a patch listener to track changes to model ids
|
|
59
|
-
const patchDisposer = onPatches(subtreeRoot, (patches) => {
|
|
60
|
-
scanPatchesForModelIdChanges(subtreeRoot, modelIdOverrides, patches)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
const returnValue = applyAction(subtreeRoot, deserializedCall)
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
returnValue,
|
|
68
|
-
serializedActionCall: {
|
|
69
|
-
...call,
|
|
70
|
-
modelIdOverrides,
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
} finally {
|
|
74
|
-
patchDisposer()
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function scanPatchesForModelIdChanges(root: object, modelIdOverrides: Patch[], patches: Patch[]) {
|
|
79
|
-
const len = patches.length
|
|
80
|
-
for (let i = 0; i < len; i++) {
|
|
81
|
-
const patch = patches[i]
|
|
82
|
-
if (patch.op === "replace" || patch.op === "add") {
|
|
83
|
-
deepScanValueForModelIdChanges(
|
|
84
|
-
root,
|
|
85
|
-
modelIdOverrides,
|
|
86
|
-
patch.value,
|
|
87
|
-
patch.path as WritablePath
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function deepScanValueForModelIdChanges(
|
|
94
|
-
root: object,
|
|
95
|
-
modelIdOverrides: Patch[],
|
|
96
|
-
value: any,
|
|
97
|
-
path: WritablePath
|
|
98
|
-
) {
|
|
99
|
-
if (path.length > 0 && typeof value === "string") {
|
|
100
|
-
// ensure the parent is an actual model
|
|
101
|
-
const parent = resolvePath(root, path.slice(0, path.length - 1)).value
|
|
102
|
-
|
|
103
|
-
if (isModel(parent)) {
|
|
104
|
-
const propertyName = path[path.length - 1]
|
|
105
|
-
if (propertyName === getModelIdPropertyName(parent.constructor as any)) {
|
|
106
|
-
// found one
|
|
107
|
-
modelIdOverrides.push({
|
|
108
|
-
op: "replace",
|
|
109
|
-
path: path.slice(),
|
|
110
|
-
value: value,
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} else if (Array.isArray(value)) {
|
|
115
|
-
const len = value.length
|
|
116
|
-
for (let i = 0; i < len; i++) {
|
|
117
|
-
path.push(i)
|
|
118
|
-
deepScanValueForModelIdChanges(root, modelIdOverrides, value[i], path)
|
|
119
|
-
path.pop()
|
|
120
|
-
}
|
|
121
|
-
} else if (isObject(value)) {
|
|
122
|
-
// skip frozen values
|
|
123
|
-
if (!value[frozenKey]) {
|
|
124
|
-
const keys = Object.keys(value)
|
|
125
|
-
const len = keys.length
|
|
126
|
-
for (let i = 0; i < len; i++) {
|
|
127
|
-
const propName = keys[i]
|
|
128
|
-
const propValue = value[propName]
|
|
129
|
-
|
|
130
|
-
path.push(propName)
|
|
131
|
-
deepScanValueForModelIdChanges(root, modelIdOverrides, propValue, path)
|
|
132
|
-
path.pop()
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Applies (runs) a serialized action over a target object.
|
|
140
|
-
* In this mode newly generated / modified model IDs previously tracked
|
|
141
|
-
* by `applySerializedActionAndTrackNewModelIds` will be synchronized after
|
|
142
|
-
* the action is applied.
|
|
143
|
-
* This means this method is usually used on the client side.
|
|
144
|
-
*
|
|
145
|
-
* If you intend to apply non-serialized actions check `applyAction` instead.
|
|
146
|
-
*
|
|
147
|
-
* @param subtreeRoot Subtree root target object to run the action over.
|
|
148
|
-
* @param call The serialized action, usually as coming from the server/client.
|
|
149
|
-
* @returns The return value of the action, if any.
|
|
150
|
-
*/
|
|
151
|
-
export function applySerializedActionAndSyncNewModelIds<TRet = any>(
|
|
152
|
-
subtreeRoot: object,
|
|
153
|
-
call: SerializedActionCallWithModelIdOverrides
|
|
154
|
-
): TRet {
|
|
155
|
-
if (!call.serialized) {
|
|
156
|
-
throw failure("cannot apply a non-serialized action call, use 'applyAction' instead")
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
assertTweakedObject(subtreeRoot, "subtreeRoot")
|
|
160
|
-
|
|
161
|
-
const deserializedCall = deserializeActionCall(call, subtreeRoot)
|
|
162
|
-
|
|
163
|
-
let returnValue: any
|
|
164
|
-
runInAction(() => {
|
|
165
|
-
returnValue = applyAction(subtreeRoot, deserializedCall)
|
|
166
|
-
|
|
167
|
-
// apply model id overrides
|
|
168
|
-
applyPatches(subtreeRoot, call.modelIdOverrides)
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
return returnValue
|
|
172
|
-
}
|
|
1
|
+
import { runInAction } from "mobx"
|
|
2
|
+
import { applyAction } from "../../action/applyAction"
|
|
3
|
+
import { frozenKey } from "../../frozen/Frozen"
|
|
4
|
+
import { getModelIdPropertyName } from "../../model/getModelMetadata"
|
|
5
|
+
import { isModel } from "../../model/utils"
|
|
6
|
+
import { resolvePath } from "../../parent/path"
|
|
7
|
+
import type { WritablePath } from "../../parent/pathTypes"
|
|
8
|
+
import { applyPatches } from "../../patch/applyPatches"
|
|
9
|
+
import { onPatches } from "../../patch/emitPatch"
|
|
10
|
+
import type { Patch } from "../../patch/Patch"
|
|
11
|
+
import { assertTweakedObject } from "../../tweaker/core"
|
|
12
|
+
import { failure, isObject } from "../../utils"
|
|
13
|
+
import { deserializeActionCall, type SerializedActionCall } from "./actionSerialization"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Serialized action call with model ID overrides.
|
|
17
|
+
* Can be generated with `applySerializedActionAndTrackNewModelIds`.
|
|
18
|
+
* To be applied with `applySerializedActionAndSyncNewModelIds`.
|
|
19
|
+
*/
|
|
20
|
+
export interface SerializedActionCallWithModelIdOverrides extends SerializedActionCall {
|
|
21
|
+
/**
|
|
22
|
+
* Model Id overrides to be applied at the end of applying the action.
|
|
23
|
+
*/
|
|
24
|
+
readonly modelIdOverrides: ReadonlyArray<Patch>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Applies (runs) a serialized action over a target object.
|
|
29
|
+
* In this mode newly generated / modified model IDs will be tracked
|
|
30
|
+
* so they can be later synchronized when applying it on another machine
|
|
31
|
+
* via `applySerializedActionAndSyncNewModelIds`.
|
|
32
|
+
* This means this method is usually used on the server side.
|
|
33
|
+
*
|
|
34
|
+
* If you intend to apply non-serialized actions check `applyAction` instead.
|
|
35
|
+
*
|
|
36
|
+
* @param subtreeRoot Subtree root target object to run the action over.
|
|
37
|
+
* @param call The serialized action, usually as coming from the server/client.
|
|
38
|
+
* @returns The return value of the action, if any, plus a new serialized action
|
|
39
|
+
* with model overrides.
|
|
40
|
+
*/
|
|
41
|
+
export function applySerializedActionAndTrackNewModelIds<TRet = any>(
|
|
42
|
+
subtreeRoot: object,
|
|
43
|
+
call: SerializedActionCall
|
|
44
|
+
): {
|
|
45
|
+
returnValue: TRet
|
|
46
|
+
serializedActionCall: SerializedActionCallWithModelIdOverrides
|
|
47
|
+
} {
|
|
48
|
+
if (!call.serialized) {
|
|
49
|
+
throw failure("cannot apply a non-serialized action call, use 'applyAction' instead")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
assertTweakedObject(subtreeRoot, "subtreeRoot")
|
|
53
|
+
|
|
54
|
+
const deserializedCall = deserializeActionCall(call, subtreeRoot)
|
|
55
|
+
|
|
56
|
+
const modelIdOverrides: Patch[] = []
|
|
57
|
+
|
|
58
|
+
// set a patch listener to track changes to model ids
|
|
59
|
+
const patchDisposer = onPatches(subtreeRoot, (patches) => {
|
|
60
|
+
scanPatchesForModelIdChanges(subtreeRoot, modelIdOverrides, patches)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const returnValue = applyAction(subtreeRoot, deserializedCall)
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
returnValue,
|
|
68
|
+
serializedActionCall: {
|
|
69
|
+
...call,
|
|
70
|
+
modelIdOverrides,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
patchDisposer()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function scanPatchesForModelIdChanges(root: object, modelIdOverrides: Patch[], patches: Patch[]) {
|
|
79
|
+
const len = patches.length
|
|
80
|
+
for (let i = 0; i < len; i++) {
|
|
81
|
+
const patch = patches[i]
|
|
82
|
+
if (patch.op === "replace" || patch.op === "add") {
|
|
83
|
+
deepScanValueForModelIdChanges(
|
|
84
|
+
root,
|
|
85
|
+
modelIdOverrides,
|
|
86
|
+
patch.value,
|
|
87
|
+
patch.path as WritablePath
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function deepScanValueForModelIdChanges(
|
|
94
|
+
root: object,
|
|
95
|
+
modelIdOverrides: Patch[],
|
|
96
|
+
value: any,
|
|
97
|
+
path: WritablePath
|
|
98
|
+
) {
|
|
99
|
+
if (path.length > 0 && typeof value === "string") {
|
|
100
|
+
// ensure the parent is an actual model
|
|
101
|
+
const parent = resolvePath(root, path.slice(0, path.length - 1)).value
|
|
102
|
+
|
|
103
|
+
if (isModel(parent)) {
|
|
104
|
+
const propertyName = path[path.length - 1]
|
|
105
|
+
if (propertyName === getModelIdPropertyName(parent.constructor as any)) {
|
|
106
|
+
// found one
|
|
107
|
+
modelIdOverrides.push({
|
|
108
|
+
op: "replace",
|
|
109
|
+
path: path.slice(),
|
|
110
|
+
value: value,
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} else if (Array.isArray(value)) {
|
|
115
|
+
const len = value.length
|
|
116
|
+
for (let i = 0; i < len; i++) {
|
|
117
|
+
path.push(i)
|
|
118
|
+
deepScanValueForModelIdChanges(root, modelIdOverrides, value[i], path)
|
|
119
|
+
path.pop()
|
|
120
|
+
}
|
|
121
|
+
} else if (isObject(value)) {
|
|
122
|
+
// skip frozen values
|
|
123
|
+
if (!value[frozenKey]) {
|
|
124
|
+
const keys = Object.keys(value)
|
|
125
|
+
const len = keys.length
|
|
126
|
+
for (let i = 0; i < len; i++) {
|
|
127
|
+
const propName = keys[i]
|
|
128
|
+
const propValue = value[propName]
|
|
129
|
+
|
|
130
|
+
path.push(propName)
|
|
131
|
+
deepScanValueForModelIdChanges(root, modelIdOverrides, propValue, path)
|
|
132
|
+
path.pop()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Applies (runs) a serialized action over a target object.
|
|
140
|
+
* In this mode newly generated / modified model IDs previously tracked
|
|
141
|
+
* by `applySerializedActionAndTrackNewModelIds` will be synchronized after
|
|
142
|
+
* the action is applied.
|
|
143
|
+
* This means this method is usually used on the client side.
|
|
144
|
+
*
|
|
145
|
+
* If you intend to apply non-serialized actions check `applyAction` instead.
|
|
146
|
+
*
|
|
147
|
+
* @param subtreeRoot Subtree root target object to run the action over.
|
|
148
|
+
* @param call The serialized action, usually as coming from the server/client.
|
|
149
|
+
* @returns The return value of the action, if any.
|
|
150
|
+
*/
|
|
151
|
+
export function applySerializedActionAndSyncNewModelIds<TRet = any>(
|
|
152
|
+
subtreeRoot: object,
|
|
153
|
+
call: SerializedActionCallWithModelIdOverrides
|
|
154
|
+
): TRet {
|
|
155
|
+
if (!call.serialized) {
|
|
156
|
+
throw failure("cannot apply a non-serialized action call, use 'applyAction' instead")
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
assertTweakedObject(subtreeRoot, "subtreeRoot")
|
|
160
|
+
|
|
161
|
+
const deserializedCall = deserializeActionCall(call, subtreeRoot)
|
|
162
|
+
|
|
163
|
+
let returnValue: any
|
|
164
|
+
runInAction(() => {
|
|
165
|
+
returnValue = applyAction(subtreeRoot, deserializedCall)
|
|
166
|
+
|
|
167
|
+
// apply model id overrides
|
|
168
|
+
applyPatches(subtreeRoot, call.modelIdOverrides)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return returnValue
|
|
172
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import type { IObservableArray } from "mobx"
|
|
2
|
-
import { isArray, namespace } from "../../utils"
|
|
3
|
-
import { ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
4
|
-
|
|
5
|
-
export const arraySerializer: ActionCallArgumentSerializer<any[] | IObservableArray<any>, any[]> = {
|
|
6
|
-
id: `${namespace}/array`,
|
|
7
|
-
|
|
8
|
-
serialize(value, serialize) {
|
|
9
|
-
if (!isArray(value)) {
|
|
10
|
-
return cannotSerialize
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// this will also transform observable arrays into non-observable ones
|
|
14
|
-
return value.map(serialize)
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
deserialize(arr, deserialize) {
|
|
18
|
-
return arr.map(deserialize)
|
|
19
|
-
},
|
|
20
|
-
}
|
|
1
|
+
import type { IObservableArray } from "mobx"
|
|
2
|
+
import { isArray, namespace } from "../../utils"
|
|
3
|
+
import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
4
|
+
|
|
5
|
+
export const arraySerializer: ActionCallArgumentSerializer<any[] | IObservableArray<any>, any[]> = {
|
|
6
|
+
id: `${namespace}/array`,
|
|
7
|
+
|
|
8
|
+
serialize(value, serialize) {
|
|
9
|
+
if (!isArray(value)) {
|
|
10
|
+
return cannotSerialize
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// this will also transform observable arrays into non-observable ones
|
|
14
|
+
return value.map(serialize)
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
deserialize(arr, deserialize) {
|
|
18
|
+
return arr.map(deserialize)
|
|
19
|
+
},
|
|
20
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { namespace } from "../../utils"
|
|
2
|
-
import { ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
3
|
-
|
|
4
|
-
export const dateSerializer: ActionCallArgumentSerializer<Date, number> = {
|
|
5
|
-
id: `${namespace}/dateAsTimestamp`,
|
|
6
|
-
|
|
7
|
-
serialize(date) {
|
|
8
|
-
if (!(date instanceof Date)) {
|
|
9
|
-
return cannotSerialize
|
|
10
|
-
}
|
|
11
|
-
return +date
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
deserialize(timestamp) {
|
|
15
|
-
return new Date(timestamp)
|
|
16
|
-
},
|
|
17
|
-
}
|
|
1
|
+
import { namespace } from "../../utils"
|
|
2
|
+
import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
3
|
+
|
|
4
|
+
export const dateSerializer: ActionCallArgumentSerializer<Date, number> = {
|
|
5
|
+
id: `${namespace}/dateAsTimestamp`,
|
|
6
|
+
|
|
7
|
+
serialize(date) {
|
|
8
|
+
if (!(date instanceof Date)) {
|
|
9
|
+
return cannotSerialize
|
|
10
|
+
}
|
|
11
|
+
return +date
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
deserialize(timestamp) {
|
|
15
|
+
return new Date(timestamp)
|
|
16
|
+
},
|
|
17
|
+
}
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { isObservableMap, ObservableMap } from "mobx"
|
|
2
|
-
import { namespace } from "../../utils"
|
|
3
|
-
import { ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
4
|
-
|
|
5
|
-
export const mapSerializer: ActionCallArgumentSerializer<
|
|
6
|
-
Map<any, any> | ObservableMap<any, any>,
|
|
7
|
-
[any, any][]
|
|
8
|
-
> = {
|
|
9
|
-
id: `${namespace}/mapAsArray`,
|
|
10
|
-
|
|
11
|
-
serialize(map, serialize) {
|
|
12
|
-
if (!(map instanceof Map || isObservableMap(map))) {
|
|
13
|
-
return cannotSerialize
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const arr: [any, any][] = []
|
|
17
|
-
|
|
18
|
-
const iter = map.keys()
|
|
19
|
-
let cur = iter.next()
|
|
20
|
-
while (!cur.done) {
|
|
21
|
-
const k = cur.value
|
|
22
|
-
const v = map.get(k)
|
|
23
|
-
arr.push([serialize(k), serialize(v)])
|
|
24
|
-
cur = iter.next()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return arr
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
deserialize(arr, deserialize) {
|
|
31
|
-
const map = new Map()
|
|
32
|
-
|
|
33
|
-
const len = arr.length
|
|
34
|
-
for (let i = 0; i < len; i++) {
|
|
35
|
-
const k = arr[i][0]
|
|
36
|
-
const v = arr[i][1]
|
|
37
|
-
map.set(deserialize(k), deserialize(v))
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return map
|
|
41
|
-
},
|
|
42
|
-
}
|
|
1
|
+
import { isObservableMap, type ObservableMap } from "mobx"
|
|
2
|
+
import { namespace } from "../../utils"
|
|
3
|
+
import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
4
|
+
|
|
5
|
+
export const mapSerializer: ActionCallArgumentSerializer<
|
|
6
|
+
Map<any, any> | ObservableMap<any, any>,
|
|
7
|
+
[any, any][]
|
|
8
|
+
> = {
|
|
9
|
+
id: `${namespace}/mapAsArray`,
|
|
10
|
+
|
|
11
|
+
serialize(map, serialize) {
|
|
12
|
+
if (!(map instanceof Map || isObservableMap(map))) {
|
|
13
|
+
return cannotSerialize
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const arr: [any, any][] = []
|
|
17
|
+
|
|
18
|
+
const iter = map.keys()
|
|
19
|
+
let cur = iter.next()
|
|
20
|
+
while (!cur.done) {
|
|
21
|
+
const k = cur.value
|
|
22
|
+
const v = map.get(k)
|
|
23
|
+
arr.push([serialize(k), serialize(v)])
|
|
24
|
+
cur = iter.next()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return arr
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
deserialize(arr, deserialize) {
|
|
31
|
+
const map = new Map()
|
|
32
|
+
|
|
33
|
+
const len = arr.length
|
|
34
|
+
for (let i = 0; i < len; i++) {
|
|
35
|
+
const k = arr[i][0]
|
|
36
|
+
const v = arr[i][1]
|
|
37
|
+
map.set(deserialize(k), deserialize(v))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return map
|
|
41
|
+
},
|
|
42
|
+
}
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { fastGetRootPath, resolvePathCheckingIds } from "../../parent/path"
|
|
2
|
-
import { Path } from "../../parent/pathTypes"
|
|
3
|
-
import { isTweakedObject } from "../../tweaker/core"
|
|
4
|
-
import { failure, namespace } from "../../utils"
|
|
5
|
-
import { rootPathToTargetPathIds } from "../utils"
|
|
6
|
-
import { ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
7
|
-
|
|
8
|
-
interface ObjectPath {
|
|
9
|
-
targetPath: Path
|
|
10
|
-
targetPathIds: (string | null)[]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const objectPathSerializer: ActionCallArgumentSerializer<object, ObjectPath> = {
|
|
14
|
-
id: `${namespace}/objectPath`,
|
|
15
|
-
|
|
16
|
-
serialize(value, _, targetRoot) {
|
|
17
|
-
if (typeof value !== "object" || value === null || !isTweakedObject(value, false)) {
|
|
18
|
-
return cannotSerialize
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// try to serialize a ref to its path if possible instead
|
|
22
|
-
if (targetRoot) {
|
|
23
|
-
const rootPath = fastGetRootPath(value, false)
|
|
24
|
-
if (rootPath.root === targetRoot) {
|
|
25
|
-
return {
|
|
26
|
-
targetPath: rootPath.path,
|
|
27
|
-
targetPathIds: rootPathToTargetPathIds(rootPath),
|
|
28
|
-
} as ObjectPath
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return cannotSerialize
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
deserialize(ref, _, targetRoot) {
|
|
36
|
-
// try to resolve the node back
|
|
37
|
-
if (targetRoot) {
|
|
38
|
-
const result = resolvePathCheckingIds(targetRoot, ref.targetPath, ref.targetPathIds)
|
|
39
|
-
if (result.resolved) {
|
|
40
|
-
return result.value
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
throw failure(
|
|
45
|
-
`object at path ${JSON.stringify(ref.targetPath)} with ids ${JSON.stringify(
|
|
46
|
-
ref.targetPathIds
|
|
47
|
-
)} could not be resolved`
|
|
48
|
-
)
|
|
49
|
-
},
|
|
50
|
-
}
|
|
1
|
+
import { fastGetRootPath, resolvePathCheckingIds } from "../../parent/path"
|
|
2
|
+
import type { Path } from "../../parent/pathTypes"
|
|
3
|
+
import { isTweakedObject } from "../../tweaker/core"
|
|
4
|
+
import { failure, namespace } from "../../utils"
|
|
5
|
+
import { rootPathToTargetPathIds } from "../utils"
|
|
6
|
+
import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
7
|
+
|
|
8
|
+
interface ObjectPath {
|
|
9
|
+
targetPath: Path
|
|
10
|
+
targetPathIds: (string | null)[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const objectPathSerializer: ActionCallArgumentSerializer<object, ObjectPath> = {
|
|
14
|
+
id: `${namespace}/objectPath`,
|
|
15
|
+
|
|
16
|
+
serialize(value, _, targetRoot) {
|
|
17
|
+
if (typeof value !== "object" || value === null || !isTweakedObject(value, false)) {
|
|
18
|
+
return cannotSerialize
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// try to serialize a ref to its path if possible instead
|
|
22
|
+
if (targetRoot) {
|
|
23
|
+
const rootPath = fastGetRootPath(value, false)
|
|
24
|
+
if (rootPath.root === targetRoot) {
|
|
25
|
+
return {
|
|
26
|
+
targetPath: rootPath.path,
|
|
27
|
+
targetPathIds: rootPathToTargetPathIds(rootPath),
|
|
28
|
+
} as ObjectPath
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return cannotSerialize
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
deserialize(ref, _, targetRoot) {
|
|
36
|
+
// try to resolve the node back
|
|
37
|
+
if (targetRoot) {
|
|
38
|
+
const result = resolvePathCheckingIds(targetRoot, ref.targetPath, ref.targetPathIds)
|
|
39
|
+
if (result.resolved) {
|
|
40
|
+
return result.value
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw failure(
|
|
45
|
+
`object at path ${JSON.stringify(ref.targetPath)} with ids ${JSON.stringify(
|
|
46
|
+
ref.targetPathIds
|
|
47
|
+
)} could not be resolved`
|
|
48
|
+
)
|
|
49
|
+
},
|
|
50
|
+
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { fromSnapshot } from "../../snapshot/fromSnapshot"
|
|
2
|
-
import { getSnapshot } from "../../snapshot/getSnapshot"
|
|
3
|
-
import { isTweakedObject } from "../../tweaker/core"
|
|
4
|
-
import { namespace } from "../../utils"
|
|
5
|
-
import { ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
6
|
-
|
|
7
|
-
export const objectSnapshotSerializer: ActionCallArgumentSerializer<object, object> = {
|
|
8
|
-
id: `${namespace}/objectSnapshot`,
|
|
9
|
-
|
|
10
|
-
serialize(value) {
|
|
11
|
-
if (typeof value !== "object" || value === null || !isTweakedObject(value, false)) {
|
|
12
|
-
return cannotSerialize
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return getSnapshot(value)
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
deserialize(snapshot) {
|
|
19
|
-
return fromSnapshot(snapshot)
|
|
20
|
-
},
|
|
21
|
-
}
|
|
1
|
+
import { fromSnapshot } from "../../snapshot/fromSnapshot"
|
|
2
|
+
import { getSnapshot } from "../../snapshot/getSnapshot"
|
|
3
|
+
import { isTweakedObject } from "../../tweaker/core"
|
|
4
|
+
import { namespace } from "../../utils"
|
|
5
|
+
import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
6
|
+
|
|
7
|
+
export const objectSnapshotSerializer: ActionCallArgumentSerializer<object, object> = {
|
|
8
|
+
id: `${namespace}/objectSnapshot`,
|
|
9
|
+
|
|
10
|
+
serialize(value) {
|
|
11
|
+
if (typeof value !== "object" || value === null || !isTweakedObject(value, false)) {
|
|
12
|
+
return cannotSerialize
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return getSnapshot(value)
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
deserialize(snapshot) {
|
|
19
|
+
return fromSnapshot(snapshot)
|
|
20
|
+
},
|
|
21
|
+
}
|