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.
Files changed (174) hide show
  1. package/CHANGELOG.md +864 -853
  2. package/README.md +61 -61
  3. package/dist/mobx-keystone.esm.js +11336 -11148
  4. package/dist/mobx-keystone.esm.mjs +11336 -11148
  5. package/dist/mobx-keystone.umd.js +12229 -11738
  6. package/dist/types/actionMiddlewares/undoMiddleware.d.ts +1 -1
  7. package/dist/types/modelShared/prop.d.ts +5 -0
  8. package/dist/types/redux/connectReduxDevTools.d.ts +17 -4
  9. package/dist/types/ref/Ref.d.ts +1 -1
  10. package/dist/types/treeUtils/sandbox.d.ts +1 -1
  11. package/dist/types/types/TypeChecker.d.ts +1 -1
  12. package/dist/types/types/arrayBased/typesArray.d.ts +1 -1
  13. package/dist/types/types/arrayBased/typesTuple.d.ts +1 -1
  14. package/dist/types/types/objectBased/typesArraySet.d.ts +1 -1
  15. package/dist/types/types/objectBased/typesDataModelData.d.ts +1 -1
  16. package/dist/types/types/objectBased/typesModel.d.ts +1 -1
  17. package/dist/types/types/objectBased/typesObject.d.ts +3 -3
  18. package/dist/types/types/objectBased/typesObjectMap.d.ts +1 -1
  19. package/dist/types/types/objectBased/typesRecord.d.ts +1 -1
  20. package/dist/types/types/primitiveBased/typesPrimitive.d.ts +1 -1
  21. package/dist/types/types/types.d.ts +3 -3
  22. package/dist/types/types/utility/typesCodec.d.ts +1 -6
  23. package/dist/types/types/utility/typesCodecCore.d.ts +1 -1
  24. package/dist/types/types/utility/typesOr.d.ts +1 -1
  25. package/dist/types/types/utility/typesRefinement.d.ts +1 -1
  26. package/dist/types/types/utility/typesSkipCheck.d.ts +1 -1
  27. package/dist/types/types/utility/typesTag.d.ts +1 -1
  28. package/dist/types/wrappers/ObjectMap.d.ts +2 -0
  29. package/dist/types/wrappers/asMap.d.ts +10 -6
  30. package/package.json +14 -12
  31. package/src/action/applyAction.ts +125 -114
  32. package/src/action/applyMethodCall.ts +37 -37
  33. package/src/action/isModelAction.ts +16 -16
  34. package/src/action/middleware.ts +137 -137
  35. package/src/action/modelFlow.ts +240 -240
  36. package/src/action/modelFlowPromiseGenerator.ts +127 -125
  37. package/src/action/pendingActions.ts +42 -42
  38. package/src/action/wrapInAction.ts +156 -156
  39. package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +1 -1
  40. package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +172 -172
  41. package/src/actionMiddlewares/actionSerialization/arraySerializer.ts +20 -20
  42. package/src/actionMiddlewares/actionSerialization/dateSerializer.ts +17 -17
  43. package/src/actionMiddlewares/actionSerialization/mapSerializer.ts +42 -42
  44. package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +50 -50
  45. package/src/actionMiddlewares/actionSerialization/objectSnapshotSerializer.ts +21 -21
  46. package/src/actionMiddlewares/actionSerialization/plainObjectSerializer.ts +24 -32
  47. package/src/actionMiddlewares/actionSerialization/primitiveSerializer.ts +51 -51
  48. package/src/actionMiddlewares/actionSerialization/setSerializer.ts +37 -37
  49. package/src/actionMiddlewares/actionTrackingMiddleware.ts +3 -3
  50. package/src/actionMiddlewares/onActionMiddleware.ts +2 -2
  51. package/src/actionMiddlewares/readonlyMiddleware.ts +2 -2
  52. package/src/actionMiddlewares/transactionMiddleware.ts +4 -4
  53. package/src/actionMiddlewares/undoMiddleware.ts +804 -796
  54. package/src/actionMiddlewares/utils.ts +2 -2
  55. package/src/computedTree/computedTree.ts +143 -143
  56. package/src/context/context.ts +1 -1
  57. package/src/dataModel/BaseDataModel.ts +194 -192
  58. package/src/dataModel/actions.ts +1 -1
  59. package/src/dataModel/newDataModel.ts +57 -57
  60. package/src/deepChange/index.ts +1 -1
  61. package/src/deepChange/onDeepChange.ts +244 -244
  62. package/src/frozen/Frozen.ts +146 -146
  63. package/src/globalConfig/globalConfig.ts +107 -107
  64. package/src/index.ts +24 -24
  65. package/src/model/BaseModel.ts +275 -273
  66. package/src/model/ModelConstructorOptions.ts +15 -15
  67. package/src/model/getModelMetadata.ts +51 -51
  68. package/src/model/index.ts +6 -6
  69. package/src/model/mixins.ts +288 -288
  70. package/src/model/newModel.ts +301 -301
  71. package/src/model/utils.ts +249 -249
  72. package/src/modelShared/modelDecorator.ts +260 -253
  73. package/src/modelShared/modelInfo.ts +50 -50
  74. package/src/modelShared/modelSymbols.ts +3 -3
  75. package/src/modelShared/newModel.ts +25 -25
  76. package/src/modelShared/prop.ts +713 -684
  77. package/src/modelShared/sharedInternalModel.ts +427 -417
  78. package/src/modelShared/utils.ts +24 -24
  79. package/src/parent/core.ts +65 -65
  80. package/src/parent/coreObjectChildren.ts +180 -180
  81. package/src/parent/detach.ts +47 -47
  82. package/src/parent/findParent.ts +1 -1
  83. package/src/parent/getChildrenObjects.ts +25 -25
  84. package/src/parent/path.ts +386 -381
  85. package/src/parent/setParent.ts +149 -149
  86. package/src/parent/walkTree.ts +1 -1
  87. package/src/patch/applyPatches.ts +187 -187
  88. package/src/patch/jsonPatch.ts +108 -108
  89. package/src/patch/patchRecorder.ts +6 -1
  90. package/src/redux/connectReduxDevTools.ts +39 -7
  91. package/src/redux/redux.ts +6 -2
  92. package/src/ref/Ref.ts +1 -1
  93. package/src/ref/core.ts +339 -345
  94. package/src/ref/customRef.ts +3 -3
  95. package/src/ref/rootRef.ts +100 -100
  96. package/src/rootStore/attachDetach.ts +89 -89
  97. package/src/rootStore/rootStore.ts +1 -1
  98. package/src/snapshot/SnapshotOf.ts +104 -104
  99. package/src/snapshot/SnapshotProcessingError.ts +45 -45
  100. package/src/snapshot/applySnapshot.ts +177 -181
  101. package/src/snapshot/cloneTreeValue.ts +30 -30
  102. package/src/snapshot/fromArraySnapshot.ts +27 -33
  103. package/src/snapshot/fromModelSnapshot.ts +70 -70
  104. package/src/snapshot/fromPlainObjectSnapshot.ts +47 -42
  105. package/src/snapshot/fromSnapshot.ts +198 -198
  106. package/src/snapshot/getSnapshot.ts +80 -79
  107. package/src/snapshot/index.ts +8 -8
  108. package/src/snapshot/internal.ts +230 -230
  109. package/src/snapshot/reconcileArraySnapshot.ts +70 -70
  110. package/src/snapshot/reconcileModelSnapshot.ts +155 -150
  111. package/src/snapshot/reconcilePlainObjectSnapshot.ts +72 -72
  112. package/src/snapshot/reconcileSnapshot.ts +88 -88
  113. package/src/standardActions/actions.ts +64 -64
  114. package/src/standardActions/objectActions.ts +60 -60
  115. package/src/transforms/ImmutableDate.ts +93 -93
  116. package/src/transforms/asMap.ts +50 -50
  117. package/src/transforms/asSet.ts +22 -22
  118. package/src/transforms/bigint.ts +20 -20
  119. package/src/transforms/date.ts +40 -40
  120. package/src/treeUtils/deepEquals.ts +55 -55
  121. package/src/treeUtils/sandbox.ts +6 -3
  122. package/src/tweaker/TweakerPriority.ts +9 -9
  123. package/src/tweaker/tweak.ts +4 -3
  124. package/src/tweaker/tweakArray.ts +530 -475
  125. package/src/tweaker/tweakFrozen.ts +42 -42
  126. package/src/tweaker/tweakModel.ts +1 -1
  127. package/src/tweaker/tweakPlainObject.ts +355 -355
  128. package/src/tweaker/typeChecking.ts +101 -101
  129. package/src/types/SnapshotTypeMismatchError.ts +46 -46
  130. package/src/types/TypeCheckError.ts +183 -184
  131. package/src/types/TypeChecker.ts +202 -185
  132. package/src/types/arrayBased/typesArray.ts +136 -137
  133. package/src/types/arrayBased/typesTuple.ts +138 -139
  134. package/src/types/createPerEntryCachedCheck.ts +166 -160
  135. package/src/types/index.ts +6 -6
  136. package/src/types/objectBased/typesArraySet.ts +133 -134
  137. package/src/types/objectBased/typesDataModelData.ts +203 -204
  138. package/src/types/objectBased/typesModel.ts +220 -221
  139. package/src/types/objectBased/typesObject.ts +308 -310
  140. package/src/types/objectBased/typesObjectMap.ts +142 -143
  141. package/src/types/objectBased/typesRecord.ts +156 -157
  142. package/src/types/objectBased/typesRef.ts +89 -89
  143. package/src/types/primitiveBased/typesEnum.ts +63 -63
  144. package/src/types/primitiveBased/typesPrimitive.ts +219 -220
  145. package/src/types/registerDefaultStandardTypeResolvers.ts +21 -21
  146. package/src/types/resolveTypeChecker.ts +78 -78
  147. package/src/types/schemas.ts +208 -208
  148. package/src/types/tProp.ts +277 -268
  149. package/src/types/typeCheck.ts +21 -21
  150. package/src/types/typeCheckErrorUtils.ts +23 -23
  151. package/src/types/types.ts +142 -142
  152. package/src/types/utility/typeToStoredData.ts +37 -37
  153. package/src/types/utility/typesBigInt.ts +15 -15
  154. package/src/types/utility/typesCodec.ts +41 -38
  155. package/src/types/utility/typesCodecCore.ts +178 -178
  156. package/src/types/utility/typesCodecSupport.ts +806 -806
  157. package/src/types/utility/typesDate.ts +27 -27
  158. package/src/types/utility/typesMap.ts +253 -222
  159. package/src/types/utility/typesOr.ts +263 -259
  160. package/src/types/utility/typesRefinement.ts +131 -125
  161. package/src/types/utility/typesSet.ts +110 -110
  162. package/src/types/utility/typesSkipCheck.ts +69 -70
  163. package/src/types/utility/typesTag.ts +88 -82
  164. package/src/types/utility/typesUnchecked.ts +40 -40
  165. package/src/utils/AnyFunction.ts +4 -4
  166. package/src/utils/ModelPool.ts +59 -59
  167. package/src/utils/chainFns.ts +18 -18
  168. package/src/utils/decorators.ts +274 -274
  169. package/src/utils/errorDiagnostics.ts +204 -204
  170. package/src/utils/index.ts +443 -372
  171. package/src/wrappers/ArraySet.ts +156 -156
  172. package/src/wrappers/ObjectMap.ts +155 -136
  173. package/src/wrappers/asMap.ts +65 -30
  174. package/src/wrappers/asSet.ts +3 -3
@@ -1,149 +1,149 @@
1
- import { action } from "mobx"
2
- import { enqueuePendingAction } from "../action/pendingActions"
3
- import { BaseModel } from "../model/BaseModel"
4
- import { getModelMetadata } from "../model/getModelMetadata"
5
- import { isModel } from "../model/utils"
6
- import { attachToRootStore, detachFromRootStore } from "../rootStore/attachDetach"
7
- import { fastIsRootStoreNoAtom } from "../rootStore/rootStore"
8
- import { clone } from "../snapshot/clone"
9
- import { isTweakedObject } from "../tweaker/core"
10
- import { tryUntweak } from "../tweaker/tweak"
11
- import { failure, inDevMode, isPrimitive } from "../utils"
12
- import {
13
- dataObjectParent,
14
- dataToModelNode,
15
- objectParents,
16
- parentPathEquals,
17
- reportParentPathChanged,
18
- } from "./core"
19
- import { addObjectChild, removeObjectChild } from "./coreObjectChildren"
20
- import { ParentPath, fastGetParentPath, fastGetRoot } from "./path"
21
-
22
- /**
23
- * @internal
24
- */
25
- export const setParent = action(
26
- "setParent",
27
- (
28
- value: any,
29
- parentPath: ParentPath<any> | undefined,
30
- indexChangeAllowed: boolean,
31
- isDataObject: boolean,
32
- cloneIfApplicable: boolean
33
- ): any => {
34
- if (isPrimitive(value)) {
35
- return value
36
- }
37
-
38
- if (inDevMode) {
39
- if (indexChangeAllowed && cloneIfApplicable) {
40
- throw failure(
41
- "assertion failed: 'indexChangeAllowed' and 'cloneIfApplicable' cannot be set at the same time"
42
- )
43
- }
44
- if (typeof value === "function" || typeof value === "symbol") {
45
- throw failure(`assertion failed: value cannot be a function or a symbol`)
46
- }
47
- if (!isTweakedObject(value, true)) {
48
- throw failure(`assertion failed: value is not ready to take a parent`)
49
- }
50
- if (parentPath && !isTweakedObject(parentPath.parent, true)) {
51
- throw failure(`assertion failed: parent is not ready to take children`)
52
- }
53
- }
54
-
55
- let oldParentPath = fastGetParentPath(value, false)
56
- if (parentPathEquals(oldParentPath, parentPath)) {
57
- return value
58
- }
59
-
60
- if (fastIsRootStoreNoAtom(value)) {
61
- throw failure("root stores cannot be attached to any parents")
62
- }
63
-
64
- if (isDataObject) {
65
- dataObjectParent.set(value, parentPath!.parent)
66
- // data object will proxy to use the actual parent model for child/parent stuff
67
- return value
68
- }
69
-
70
- // make sure the new parent actually points to models when we give model data objs
71
- if (parentPath) {
72
- const actualParent = dataToModelNode(parentPath.parent)
73
- if (parentPath.parent !== actualParent) {
74
- parentPath = {
75
- parent: actualParent,
76
- path: parentPath.path,
77
- }
78
- }
79
- }
80
-
81
- // value type models should be cloned when they are about to be assigned to a new parent
82
- // and they had one previously
83
- if (
84
- cloneIfApplicable &&
85
- parentPath?.parent &&
86
- oldParentPath?.parent &&
87
- isModel(value) &&
88
- getModelMetadata(value).valueType
89
- ) {
90
- value = clone(value, { generateNewIds: true })
91
- oldParentPath = fastGetParentPath(value, false)
92
- }
93
-
94
- if (oldParentPath && parentPath) {
95
- if (oldParentPath.parent === parentPath.parent && indexChangeAllowed) {
96
- // just changing the index
97
- objectParents.set(value, parentPath)
98
- reportParentPathChanged(value)
99
- return value
100
- } else {
101
- throw failure("an object cannot be assigned a new parent when it already has one")
102
- }
103
- }
104
-
105
- const postUntweaker = parentPath ? undefined : tryUntweak(value)
106
-
107
- const valueIsModel = value instanceof BaseModel
108
-
109
- let oldRoot: any
110
- let oldRootStore: any
111
- if (valueIsModel) {
112
- oldRoot = fastGetRoot(value, false)
113
- oldRootStore = fastIsRootStoreNoAtom(oldRoot) ? oldRoot : undefined
114
- }
115
-
116
- // detach from old
117
- if (oldParentPath?.parent) {
118
- removeObjectChild(oldParentPath.parent, value)
119
- }
120
-
121
- // attach to new
122
- objectParents.set(value, parentPath)
123
- if (parentPath?.parent) {
124
- addObjectChild(parentPath.parent, value)
125
- }
126
- reportParentPathChanged(value)
127
-
128
- if (valueIsModel) {
129
- const newRoot = fastGetRoot(value, false)
130
- const newRootStore = fastIsRootStoreNoAtom(newRoot) ? newRoot : undefined
131
-
132
- // invoke model root store events
133
- if (oldRootStore !== newRootStore && (oldRootStore || newRootStore)) {
134
- enqueuePendingAction(() => {
135
- if (oldRootStore) {
136
- detachFromRootStore(value)
137
- }
138
- if (newRootStore) {
139
- attachToRootStore(newRootStore, value)
140
- }
141
- })
142
- }
143
- }
144
-
145
- postUntweaker?.()
146
-
147
- return value
148
- }
149
- )
1
+ import { action } from "mobx"
2
+ import { enqueuePendingAction } from "../action/pendingActions"
3
+ import { BaseModel } from "../model/BaseModel"
4
+ import { getModelMetadata } from "../model/getModelMetadata"
5
+ import { isModel } from "../model/utils"
6
+ import { attachToRootStore, detachFromRootStore } from "../rootStore/attachDetach"
7
+ import { fastIsRootStoreNoAtom } from "../rootStore/rootStore"
8
+ import { clone } from "../snapshot/clone"
9
+ import { isTweakedObject } from "../tweaker/core"
10
+ import { tryUntweak } from "../tweaker/tweak"
11
+ import { failure, inDevMode, isPrimitive } from "../utils"
12
+ import {
13
+ dataObjectParent,
14
+ dataToModelNode,
15
+ objectParents,
16
+ parentPathEquals,
17
+ reportParentPathChanged,
18
+ } from "./core"
19
+ import { addObjectChild, removeObjectChild } from "./coreObjectChildren"
20
+ import { fastGetParentPath, fastGetRoot, type ParentPath } from "./path"
21
+
22
+ /**
23
+ * @internal
24
+ */
25
+ export const setParent = action(
26
+ "setParent",
27
+ (
28
+ value: any,
29
+ parentPath: ParentPath<any> | undefined,
30
+ indexChangeAllowed: boolean,
31
+ isDataObject: boolean,
32
+ cloneIfApplicable: boolean
33
+ ): any => {
34
+ if (isPrimitive(value)) {
35
+ return value
36
+ }
37
+
38
+ if (inDevMode) {
39
+ if (indexChangeAllowed && cloneIfApplicable) {
40
+ throw failure(
41
+ "assertion failed: 'indexChangeAllowed' and 'cloneIfApplicable' cannot be set at the same time"
42
+ )
43
+ }
44
+ if (typeof value === "function" || typeof value === "symbol") {
45
+ throw failure(`assertion failed: value cannot be a function or a symbol`)
46
+ }
47
+ if (!isTweakedObject(value, true)) {
48
+ throw failure(`assertion failed: value is not ready to take a parent`)
49
+ }
50
+ if (parentPath && !isTweakedObject(parentPath.parent, true)) {
51
+ throw failure(`assertion failed: parent is not ready to take children`)
52
+ }
53
+ }
54
+
55
+ let oldParentPath = fastGetParentPath(value, false)
56
+ if (parentPathEquals(oldParentPath, parentPath)) {
57
+ return value
58
+ }
59
+
60
+ if (fastIsRootStoreNoAtom(value)) {
61
+ throw failure("root stores cannot be attached to any parents")
62
+ }
63
+
64
+ if (isDataObject) {
65
+ dataObjectParent.set(value, parentPath!.parent)
66
+ // data object will proxy to use the actual parent model for child/parent stuff
67
+ return value
68
+ }
69
+
70
+ // make sure the new parent actually points to models when we give model data objs
71
+ if (parentPath) {
72
+ const actualParent = dataToModelNode(parentPath.parent)
73
+ if (parentPath.parent !== actualParent) {
74
+ parentPath = {
75
+ parent: actualParent,
76
+ path: parentPath.path,
77
+ }
78
+ }
79
+ }
80
+
81
+ // value type models should be cloned when they are about to be assigned to a new parent
82
+ // and they had one previously
83
+ if (
84
+ cloneIfApplicable &&
85
+ parentPath?.parent &&
86
+ oldParentPath?.parent &&
87
+ isModel(value) &&
88
+ getModelMetadata(value).valueType
89
+ ) {
90
+ value = clone(value, { generateNewIds: true })
91
+ oldParentPath = fastGetParentPath(value, false)
92
+ }
93
+
94
+ if (oldParentPath && parentPath) {
95
+ if (oldParentPath.parent === parentPath.parent && indexChangeAllowed) {
96
+ // just changing the index
97
+ objectParents.set(value, parentPath)
98
+ reportParentPathChanged(value)
99
+ return value
100
+ } else {
101
+ throw failure("an object cannot be assigned a new parent when it already has one")
102
+ }
103
+ }
104
+
105
+ const postUntweaker = parentPath ? undefined : tryUntweak(value)
106
+
107
+ const valueIsModel = value instanceof BaseModel
108
+
109
+ let oldRoot: any
110
+ let oldRootStore: any
111
+ if (valueIsModel) {
112
+ oldRoot = fastGetRoot(value, false)
113
+ oldRootStore = fastIsRootStoreNoAtom(oldRoot) ? oldRoot : undefined
114
+ }
115
+
116
+ // detach from old
117
+ if (oldParentPath?.parent) {
118
+ removeObjectChild(oldParentPath.parent, value)
119
+ }
120
+
121
+ // attach to new
122
+ objectParents.set(value, parentPath)
123
+ if (parentPath?.parent) {
124
+ addObjectChild(parentPath.parent, value)
125
+ }
126
+ reportParentPathChanged(value)
127
+
128
+ if (valueIsModel) {
129
+ const newRoot = fastGetRoot(value, false)
130
+ const newRootStore = fastIsRootStoreNoAtom(newRoot) ? newRoot : undefined
131
+
132
+ // invoke model root store events
133
+ if (oldRootStore !== newRootStore && (oldRootStore || newRootStore)) {
134
+ enqueuePendingAction(() => {
135
+ if (oldRootStore) {
136
+ detachFromRootStore(value)
137
+ }
138
+ if (newRootStore) {
139
+ attachToRootStore(newRootStore, value)
140
+ }
141
+ })
142
+ }
143
+ }
144
+
145
+ postUntweaker?.()
146
+
147
+ return value
148
+ }
149
+ )
@@ -1,4 +1,4 @@
1
- import { computed, IComputedValue } from "mobx"
1
+ import { computed, type IComputedValue } from "mobx"
2
2
  import { assertTweakedObject } from "../tweaker/core"
3
3
  import { getObjectChildren } from "./coreObjectChildren"
4
4
 
@@ -1,187 +1,187 @@
1
- import { remove } from "mobx"
2
- import { BuiltInAction } from "../action/builtInActions"
3
- import { ActionContextActionType } from "../action/context"
4
- import { wrapInAction } from "../action/wrapInAction"
5
- import { modelToDataNode } from "../parent/core"
6
- import type { PathElement } from "../parent/pathTypes"
7
- import type { Patch } from "../patch/Patch"
8
- import { reconcileSnapshot } from "../snapshot/reconcileSnapshot"
9
- import { assertTweakedObject } from "../tweaker/core"
10
- import { failure, inDevMode, isArray, lazy } from "../utils"
11
- import { runWithErrorDiagnosticsContext, withErrorPathSegments } from "../utils/errorDiagnostics"
12
- import { ModelPool } from "../utils/ModelPool"
13
- import { setIfDifferent } from "../utils/setIfDifferent"
14
-
15
- /**
16
- * Applies the given patches to the given target object.
17
- *
18
- * @param node Target object.
19
- * @param patches List of patches to apply.
20
- * @param reverse Whether patches are applied in reverse order.
21
- */
22
- export function applyPatches(
23
- node: object,
24
- patches: ReadonlyArray<Patch> | ReadonlyArray<ReadonlyArray<Patch>>,
25
- reverse = false
26
- ): void {
27
- assertTweakedObject(node, "node")
28
-
29
- if (patches.length <= 0) {
30
- return
31
- }
32
-
33
- wrappedInternalApplyPatches().call(node, patches, reverse)
34
- }
35
-
36
- /**
37
- * @internal
38
- */
39
- export function internalApplyPatches(
40
- this: object,
41
- patches: ReadonlyArray<Patch> | ReadonlyArray<ReadonlyArray<Patch>>,
42
- reverse = false
43
- ): void {
44
- runWithErrorDiagnosticsContext(() => {
45
- const obj = this
46
- const modelPool = new ModelPool(obj)
47
-
48
- if (reverse) {
49
- let i = patches.length
50
- while (i--) {
51
- const p = patches[i]
52
- if (isArray(p)) {
53
- let j = p.length
54
- while (j--) {
55
- applySinglePatchWithPath(obj, p[j], modelPool)
56
- }
57
- } else {
58
- applySinglePatchWithPath(obj, p as Patch, modelPool)
59
- }
60
- }
61
- } else {
62
- const len = patches.length
63
- for (let i = 0; i < len; i++) {
64
- const p = patches[i]
65
- if (isArray(p)) {
66
- const len2 = p.length
67
- for (let j = 0; j < len2; j++) {
68
- applySinglePatchWithPath(obj, p[j], modelPool)
69
- }
70
- } else {
71
- applySinglePatchWithPath(obj, p as Patch, modelPool)
72
- }
73
- }
74
- }
75
- })
76
- }
77
-
78
- const wrappedInternalApplyPatches = lazy(() =>
79
- wrapInAction({
80
- nameOrNameFn: BuiltInAction.ApplyPatches,
81
- fn: internalApplyPatches,
82
- actionType: ActionContextActionType.Sync,
83
- })
84
- )
85
-
86
- function applySinglePatch(obj: object, patch: Patch, modelPool: ModelPool): void {
87
- const { target, prop } = pathArrayToObjectAndProp(obj, patch.path)
88
-
89
- if (isArray(target)) {
90
- switch (patch.op) {
91
- case "add": {
92
- const index = +prop!
93
- // reconcile from the pool if possible
94
- const newValue = reconcileSnapshot(undefined, patch.value, modelPool, target)
95
- if (index < 0) {
96
- // extension needed by mobx-keystone-yjs
97
- target.push(newValue)
98
- } else {
99
- target.splice(index, 0, newValue)
100
- }
101
- break
102
- }
103
-
104
- case "remove": {
105
- const index = +prop!
106
- // no reconciliation, removing
107
- target.splice(index, 1)
108
- break
109
- }
110
-
111
- case "replace": {
112
- if (prop === "length") {
113
- target.length = patch.value
114
- } else {
115
- const index = +prop!
116
- // try to reconcile
117
- const newValue = reconcileSnapshot(target[index], patch.value, modelPool, target)
118
- setIfDifferent(target, index as any, newValue)
119
- }
120
- break
121
- }
122
-
123
- default:
124
- throw failure(`unsupported patch operation: ${(patch as any).op}`)
125
- }
126
- } else {
127
- switch (patch.op) {
128
- case "add": {
129
- // reconcile from the pool if possible
130
- const newValue = reconcileSnapshot(undefined, patch.value, modelPool, target)
131
- setIfDifferent(target, prop!, newValue)
132
- break
133
- }
134
-
135
- case "remove": {
136
- // no reconciliation, removing
137
- remove(target, prop)
138
- break
139
- }
140
-
141
- case "replace": {
142
- // try to reconcile
143
- // we don't need to tweak the pool since reconcileSnapshot will do that for us
144
- const newValue = reconcileSnapshot(target[prop!], patch.value, modelPool, target)
145
- setIfDifferent(target, prop!, newValue)
146
- break
147
- }
148
-
149
- default:
150
- throw failure(`unsupported patch operation: ${(patch as any).op}`)
151
- }
152
- }
153
- }
154
-
155
- function applySinglePatchWithPath(obj: object, patch: Patch, modelPool: ModelPool): void {
156
- withErrorPathSegments(patch.path, () => {
157
- applySinglePatch(obj, patch, modelPool)
158
- })
159
- }
160
-
161
- function pathArrayToObjectAndProp(
162
- obj: object,
163
- path: Patch["path"]
164
- ): { target: any; prop?: PathElement } {
165
- if (inDevMode) {
166
- if (!isArray(path)) {
167
- throw failure(`invalid path: ${path}`)
168
- }
169
- }
170
-
171
- let target: any = modelToDataNode(obj)
172
-
173
- if (path.length === 0) {
174
- return {
175
- target,
176
- }
177
- }
178
-
179
- for (let i = 0; i <= path.length - 2; i++) {
180
- target = modelToDataNode(target[path[i]])
181
- }
182
-
183
- return {
184
- target,
185
- prop: path[path.length - 1],
186
- }
187
- }
1
+ import { remove } from "mobx"
2
+ import { BuiltInAction } from "../action/builtInActions"
3
+ import { ActionContextActionType } from "../action/context"
4
+ import { wrapInAction } from "../action/wrapInAction"
5
+ import { modelToDataNode } from "../parent/core"
6
+ import type { PathElement } from "../parent/pathTypes"
7
+ import type { Patch } from "../patch/Patch"
8
+ import { reconcileSnapshot } from "../snapshot/reconcileSnapshot"
9
+ import { assertTweakedObject } from "../tweaker/core"
10
+ import { failure, inDevMode, isArray, lazy } from "../utils"
11
+ import { runWithErrorDiagnosticsContext, withErrorPathSegments } from "../utils/errorDiagnostics"
12
+ import { ModelPool } from "../utils/ModelPool"
13
+ import { setIfDifferent } from "../utils/setIfDifferent"
14
+
15
+ /**
16
+ * Applies the given patches to the given target object.
17
+ *
18
+ * @param node Target object.
19
+ * @param patches List of patches to apply.
20
+ * @param reverse Whether patches are applied in reverse order.
21
+ */
22
+ export function applyPatches(
23
+ node: object,
24
+ patches: ReadonlyArray<Patch> | ReadonlyArray<ReadonlyArray<Patch>>,
25
+ reverse = false
26
+ ): void {
27
+ assertTweakedObject(node, "node")
28
+
29
+ if (patches.length <= 0) {
30
+ return
31
+ }
32
+
33
+ wrappedInternalApplyPatches().call(node, patches, reverse)
34
+ }
35
+
36
+ /**
37
+ * @internal
38
+ */
39
+ export function internalApplyPatches(
40
+ this: object,
41
+ patches: ReadonlyArray<Patch> | ReadonlyArray<ReadonlyArray<Patch>>,
42
+ reverse = false
43
+ ): void {
44
+ runWithErrorDiagnosticsContext(() => {
45
+ const obj = this
46
+ const modelPool = new ModelPool(obj)
47
+
48
+ if (reverse) {
49
+ let i = patches.length
50
+ while (i--) {
51
+ const p = patches[i]
52
+ if (isArray(p)) {
53
+ let j = p.length
54
+ while (j--) {
55
+ applySinglePatchWithPath(obj, p[j], modelPool)
56
+ }
57
+ } else {
58
+ applySinglePatchWithPath(obj, p as Patch, modelPool)
59
+ }
60
+ }
61
+ } else {
62
+ const len = patches.length
63
+ for (let i = 0; i < len; i++) {
64
+ const p = patches[i]
65
+ if (isArray(p)) {
66
+ const len2 = p.length
67
+ for (let j = 0; j < len2; j++) {
68
+ applySinglePatchWithPath(obj, p[j], modelPool)
69
+ }
70
+ } else {
71
+ applySinglePatchWithPath(obj, p as Patch, modelPool)
72
+ }
73
+ }
74
+ }
75
+ })
76
+ }
77
+
78
+ const wrappedInternalApplyPatches = lazy(() =>
79
+ wrapInAction({
80
+ nameOrNameFn: BuiltInAction.ApplyPatches,
81
+ fn: internalApplyPatches,
82
+ actionType: ActionContextActionType.Sync,
83
+ })
84
+ )
85
+
86
+ function applySinglePatch(obj: object, patch: Patch, modelPool: ModelPool): void {
87
+ const { target, prop } = pathArrayToObjectAndProp(obj, patch.path)
88
+
89
+ if (isArray(target)) {
90
+ switch (patch.op) {
91
+ case "add": {
92
+ const index = +prop!
93
+ // reconcile from the pool if possible
94
+ const newValue = reconcileSnapshot(undefined, patch.value, modelPool, target)
95
+ if (index < 0) {
96
+ // extension needed by mobx-keystone-yjs
97
+ target.push(newValue)
98
+ } else {
99
+ target.splice(index, 0, newValue)
100
+ }
101
+ break
102
+ }
103
+
104
+ case "remove": {
105
+ const index = +prop!
106
+ // no reconciliation, removing
107
+ target.splice(index, 1)
108
+ break
109
+ }
110
+
111
+ case "replace": {
112
+ if (prop === "length") {
113
+ target.length = patch.value
114
+ } else {
115
+ const index = +prop!
116
+ // try to reconcile
117
+ const newValue = reconcileSnapshot(target[index], patch.value, modelPool, target)
118
+ setIfDifferent(target, index as any, newValue)
119
+ }
120
+ break
121
+ }
122
+
123
+ default:
124
+ throw failure(`unsupported patch operation: ${(patch as any).op}`)
125
+ }
126
+ } else {
127
+ switch (patch.op) {
128
+ case "add": {
129
+ // reconcile from the pool if possible
130
+ const newValue = reconcileSnapshot(undefined, patch.value, modelPool, target)
131
+ setIfDifferent(target, prop!, newValue)
132
+ break
133
+ }
134
+
135
+ case "remove": {
136
+ // no reconciliation, removing
137
+ remove(target, prop)
138
+ break
139
+ }
140
+
141
+ case "replace": {
142
+ // try to reconcile
143
+ // we don't need to tweak the pool since reconcileSnapshot will do that for us
144
+ const newValue = reconcileSnapshot(target[prop!], patch.value, modelPool, target)
145
+ setIfDifferent(target, prop!, newValue)
146
+ break
147
+ }
148
+
149
+ default:
150
+ throw failure(`unsupported patch operation: ${(patch as any).op}`)
151
+ }
152
+ }
153
+ }
154
+
155
+ function applySinglePatchWithPath(obj: object, patch: Patch, modelPool: ModelPool): void {
156
+ withErrorPathSegments(patch.path, () => {
157
+ applySinglePatch(obj, patch, modelPool)
158
+ })
159
+ }
160
+
161
+ function pathArrayToObjectAndProp(
162
+ obj: object,
163
+ path: Patch["path"]
164
+ ): { target: any; prop?: PathElement } {
165
+ if (inDevMode) {
166
+ if (!isArray(path)) {
167
+ throw failure(`invalid path: ${path}`)
168
+ }
169
+ }
170
+
171
+ let target: any = modelToDataNode(obj)
172
+
173
+ if (path.length === 0) {
174
+ return {
175
+ target,
176
+ }
177
+ }
178
+
179
+ for (let i = 0; i <= path.length - 2; i++) {
180
+ target = modelToDataNode(target[path[i]])
181
+ }
182
+
183
+ return {
184
+ target,
185
+ prop: path[path.length - 1],
186
+ }
187
+ }