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,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?: any): any {
40
- let toSnapshotProcessor: (sn: unknown) => unknown = identityFn
41
- let nodeOrPrimitive: any
42
-
43
- if (arguments.length >= 2) {
44
- const codecSupport = resolveCodecSupport(arg1)
45
- if (codecSupport.hasCodec) {
46
- const storedTypeChecker = resolveTypeChecker(codecSupport.storedType)
47
- const storedValue = codecSupport.adapter.toStored(arg2)
48
-
49
- if (isPrimitive(storedValue)) {
50
- return storedTypeChecker.toSnapshotProcessor(storedValue)
51
- }
52
-
53
- const storedTree = isTweakedObject(storedValue, true)
54
- ? storedValue
55
- : toTreeNode(codecSupport.storedType, storedValue)
56
- return storedTypeChecker.toSnapshotProcessor(getSnapshot(storedTree))
57
- }
58
-
59
- toSnapshotProcessor = resolveTypeChecker(arg1).toSnapshotProcessor
60
- nodeOrPrimitive = arg2
61
- } else {
62
- nodeOrPrimitive = arg1
63
- }
64
-
65
- if (isPrimitive(nodeOrPrimitive)) {
66
- return toSnapshotProcessor(nodeOrPrimitive)
67
- }
68
-
69
- assertTweakedObject(nodeOrPrimitive, "nodeOrPrimitive")
70
-
71
- const snapshot = getInternalSnapshot(nodeOrPrimitive)
72
- if (!snapshot) {
73
- throw failure("getSnapshot is not supported for this kind of object")
74
- }
75
-
76
- freezeInternalSnapshot(snapshot.transformed)
77
- reportInternalSnapshotObserved(snapshot)
78
- return toSnapshotProcessor(snapshot.transformed)
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
+ }
@@ -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"
@@ -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[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 = Object.assign({}, 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
+ }