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,70 +1,70 @@
1
- import { AnyModel } from "../model/BaseModel"
2
- import { getModelIdPropertyName } from "../model/getModelMetadata"
3
- import { ModelConstructorOptions } from "../model/ModelConstructorOptions"
4
- import { modelTypeKey } from "../model/metadata"
5
- import { getModelOrSnapshotTypeAndId, getSnapshotModelType } from "../model/utils"
6
- import { ModelClass } from "../modelShared/BaseModelShared"
7
- import { getModelInfoForName, getModelNotRegisteredErrorMessage } from "../modelShared/modelInfo"
8
- import { withErrorModelTrailEntry } from "../utils/errorDiagnostics"
9
- import { FromSnapshotContext, registerSnapshotter } from "./fromSnapshot"
10
- import { SnapshotInOfModel } from "./SnapshotOf"
11
- import { SnapshotProcessingError } from "./SnapshotProcessingError"
12
- import { SnapshotterAndReconcilerPriority } from "./SnapshotterAndReconcilerPriority"
13
-
14
- function fromModelSnapshot(sn: SnapshotInOfModel<AnyModel>, ctx: FromSnapshotContext): AnyModel {
15
- const type = sn[modelTypeKey]
16
-
17
- if (!type) {
18
- throw new SnapshotProcessingError({
19
- message: `a model snapshot must contain a type key (${modelTypeKey}), but none was found`,
20
- actualSnapshot: sn,
21
- })
22
- }
23
-
24
- const modelInfo = getModelInfoForName(type)
25
- if (!modelInfo) {
26
- throw new SnapshotProcessingError({
27
- message: getModelNotRegisteredErrorMessage(type),
28
- actualSnapshot: sn,
29
- })
30
- }
31
-
32
- const modelIdPropertyName = getModelIdPropertyName(modelInfo.class as ModelClass<AnyModel>)
33
- if (modelIdPropertyName && sn[modelIdPropertyName] === undefined) {
34
- throw new SnapshotProcessingError({
35
- message: `a model snapshot of type '${type}' must contain an id key (${modelIdPropertyName}), but none was found`,
36
- actualSnapshot: sn,
37
- })
38
- }
39
-
40
- const modelTypeAndId = getModelOrSnapshotTypeAndId(sn)
41
- const modelId = modelTypeAndId?.modelId
42
-
43
- return withErrorModelTrailEntry(type, modelId, () => {
44
- return new (modelInfo.class as any)(undefined, {
45
- snapshotInitialData: {
46
- unprocessedSnapshot: sn,
47
- unprocessedModelType:
48
- typeof ctx.untypedSnapshot === "object" &&
49
- ctx.untypedSnapshot &&
50
- modelTypeKey in ctx.untypedSnapshot
51
- ? ctx.untypedSnapshot[modelTypeKey]
52
- : undefined,
53
- snapshotToInitialData: ctx.snapshotToInitialData,
54
- },
55
- generateNewIds: ctx.options.generateNewIds,
56
- } satisfies ModelConstructorOptions)
57
- })
58
- }
59
-
60
- /**
61
- * @internal
62
- */
63
- export function registerFromModelSnapshotter() {
64
- registerSnapshotter(SnapshotterAndReconcilerPriority.Model, (sn, ctx) => {
65
- if (getSnapshotModelType(sn) !== undefined) {
66
- return fromModelSnapshot(sn, ctx)
67
- }
68
- return undefined
69
- })
70
- }
1
+ import type { AnyModel } from "../model/BaseModel"
2
+ import { getModelIdPropertyName } from "../model/getModelMetadata"
3
+ import type { ModelConstructorOptions } from "../model/ModelConstructorOptions"
4
+ import { modelTypeKey } from "../model/metadata"
5
+ import { getModelOrSnapshotTypeAndId, getSnapshotModelType } from "../model/utils"
6
+ import type { ModelClass } from "../modelShared/BaseModelShared"
7
+ import { getModelInfoForName, getModelNotRegisteredErrorMessage } from "../modelShared/modelInfo"
8
+ import { withErrorModelTrailEntry } from "../utils/errorDiagnostics"
9
+ import { type FromSnapshotContext, registerSnapshotter } from "./fromSnapshot"
10
+ import type { SnapshotInOfModel } from "./SnapshotOf"
11
+ import { SnapshotProcessingError } from "./SnapshotProcessingError"
12
+ import { SnapshotterAndReconcilerPriority } from "./SnapshotterAndReconcilerPriority"
13
+
14
+ function fromModelSnapshot(sn: SnapshotInOfModel<AnyModel>, ctx: FromSnapshotContext): AnyModel {
15
+ const type = sn[modelTypeKey]
16
+
17
+ if (!type) {
18
+ throw new SnapshotProcessingError({
19
+ message: `a model snapshot must contain a type key (${modelTypeKey}), but none was found`,
20
+ actualSnapshot: sn,
21
+ })
22
+ }
23
+
24
+ const modelInfo = getModelInfoForName(type)
25
+ if (!modelInfo) {
26
+ throw new SnapshotProcessingError({
27
+ message: getModelNotRegisteredErrorMessage(type),
28
+ actualSnapshot: sn,
29
+ })
30
+ }
31
+
32
+ const modelIdPropertyName = getModelIdPropertyName(modelInfo.class as ModelClass<AnyModel>)
33
+ if (modelIdPropertyName && sn[modelIdPropertyName] === undefined) {
34
+ throw new SnapshotProcessingError({
35
+ message: `a model snapshot of type '${type}' must contain an id key (${modelIdPropertyName}), but none was found`,
36
+ actualSnapshot: sn,
37
+ })
38
+ }
39
+
40
+ const modelTypeAndId = getModelOrSnapshotTypeAndId(sn)
41
+ const modelId = modelTypeAndId?.modelId
42
+
43
+ return withErrorModelTrailEntry(type, modelId, () => {
44
+ return new (modelInfo.class as any)(undefined, {
45
+ snapshotInitialData: {
46
+ unprocessedSnapshot: sn,
47
+ unprocessedModelType:
48
+ typeof ctx.untypedSnapshot === "object" &&
49
+ ctx.untypedSnapshot &&
50
+ modelTypeKey in ctx.untypedSnapshot
51
+ ? ctx.untypedSnapshot[modelTypeKey]
52
+ : undefined,
53
+ snapshotToInitialData: ctx.snapshotToInitialData,
54
+ },
55
+ generateNewIds: ctx.options.generateNewIds,
56
+ } satisfies ModelConstructorOptions)
57
+ })
58
+ }
59
+
60
+ /**
61
+ * @internal
62
+ */
63
+ export function registerFromModelSnapshotter() {
64
+ registerSnapshotter(SnapshotterAndReconcilerPriority.Model, (sn, ctx) => {
65
+ if (getSnapshotModelType(sn) !== undefined) {
66
+ return fromModelSnapshot(sn, ctx)
67
+ }
68
+ return undefined
69
+ })
70
+ }
@@ -1,42 +1,47 @@
1
- import { observable, set } from "mobx"
2
- import { tweakPlainObject } from "../tweaker/tweakPlainObject"
3
- import { isPlainObject } from "../utils"
4
- import { withErrorPathSegment } from "../utils/errorDiagnostics"
5
- import {
6
- FromSnapshotContext,
7
- internalFromSnapshot,
8
- observableOptions,
9
- registerSnapshotter,
10
- } from "./fromSnapshot"
11
- import { SnapshotInOfObject } from "./SnapshotOf"
12
- import { SnapshotterAndReconcilerPriority } from "./SnapshotterAndReconcilerPriority"
13
-
14
- function fromPlainObjectSnapshot(sn: SnapshotInOfObject<any>, ctx: FromSnapshotContext): object {
15
- const plainObj = observable.object({}, undefined, observableOptions)
16
-
17
- const snKeys = Object.keys(sn)
18
- const snKeysLen = snKeys.length
19
- for (let i = 0; i < snKeysLen; i++) {
20
- const k = snKeys[i]
21
- const v = sn[k]
22
- // setIfDifferent not required
23
- set(
24
- plainObj,
25
- k,
26
- withErrorPathSegment(k, () => internalFromSnapshot(v, ctx))
27
- )
28
- }
29
- return tweakPlainObject(plainObj, undefined, undefined, true, false)
30
- }
31
-
32
- /**
33
- * @internal
34
- */
35
- export function registerFromPlainObjectSnapshotter() {
36
- registerSnapshotter(SnapshotterAndReconcilerPriority.PlainObject, (sn, ctx) => {
37
- if (isPlainObject(sn)) {
38
- return fromPlainObjectSnapshot(sn, ctx)
39
- }
40
- return undefined
41
- })
42
- }
1
+ import { observable } from "mobx"
2
+ import { tweakPlainObject } from "../tweaker/tweakPlainObject"
3
+ import { isPlainObject, setOwnProp } from "../utils"
4
+ import { withErrorPathSegment } from "../utils/errorDiagnostics"
5
+ import {
6
+ type FromSnapshotContext,
7
+ internalFromSnapshot,
8
+ observableOptions,
9
+ registerSnapshotter,
10
+ } from "./fromSnapshot"
11
+ import type { SnapshotInOfObject } from "./SnapshotOf"
12
+ import { SnapshotterAndReconcilerPriority } from "./SnapshotterAndReconcilerPriority"
13
+
14
+ function fromPlainObjectSnapshot(sn: SnapshotInOfObject<any>, ctx: FromSnapshotContext): object {
15
+ const plainObj: Record<string, unknown> = {}
16
+
17
+ const snKeys = Object.keys(sn)
18
+ const snKeysLen = snKeys.length
19
+ for (let i = 0; i < snKeysLen; i++) {
20
+ const k = snKeys[i]
21
+ const v = sn[k]
22
+ setOwnProp(
23
+ plainObj,
24
+ k,
25
+ withErrorPathSegment(k, () => internalFromSnapshot(v, ctx))
26
+ )
27
+ }
28
+ return tweakPlainObject(
29
+ observable.object(plainObj, undefined, observableOptions),
30
+ undefined,
31
+ undefined,
32
+ true,
33
+ false
34
+ )
35
+ }
36
+
37
+ /**
38
+ * @internal
39
+ */
40
+ export function registerFromPlainObjectSnapshotter() {
41
+ registerSnapshotter(SnapshotterAndReconcilerPriority.PlainObject, (sn, ctx) => {
42
+ if (isPlainObject(sn)) {
43
+ return fromPlainObjectSnapshot(sn, ctx)
44
+ }
45
+ return undefined
46
+ })
47
+ }
@@ -1,198 +1,198 @@
1
- import { action, observable, set } from "mobx"
2
- import type { AnyModel } from "../model/BaseModel"
3
- import { isReservedModelKey } from "../model/metadata"
4
- import { resolveStandardTypeNoThrow, resolveTypeChecker } from "../types/resolveTypeChecker"
5
- import type { AnyType, TypeToData, TypeToSnapshotIn } from "../types/schemas"
6
- import { isLateTypeChecker, TypeChecker } from "../types/TypeChecker"
7
- import { resolveCodecSupport } from "../types/utility/typesCodec"
8
- import { isMap, isPrimitive, isSet } from "../utils"
9
- import { runWithErrorDiagnosticsContext, withErrorPathSegment } from "../utils/errorDiagnostics"
10
- import { registerDefaultSnapshotters } from "./registerDefaultSnapshotters"
11
- import type { SnapshotInOf, SnapshotInOfModel, SnapshotOutOf } from "./SnapshotOf"
12
- import { SnapshotProcessingError } from "./SnapshotProcessingError"
13
-
14
- /**
15
- * @internal
16
- */
17
- export type Snapshotter = (sn: any, ctx: FromSnapshotContext) => any
18
-
19
- const snapshotters: { priority: number; snapshotter: Snapshotter }[] = []
20
-
21
- /**
22
- * @internal
23
- */
24
- export function registerSnapshotter(priority: number, snapshotter: Snapshotter): void {
25
- snapshotters.push({ priority, snapshotter })
26
- snapshotters.sort((a, b) => a.priority - b.priority)
27
- }
28
-
29
- /**
30
- * From snapshot options.
31
- */
32
- export interface FromSnapshotOptions {
33
- /**
34
- * Pass `true` to generate new internal ids for models rather than reusing them. (Default is `false`)
35
- */
36
- generateNewIds: boolean
37
- }
38
-
39
- /**
40
- * @internal
41
- */
42
- export interface FromSnapshotContext {
43
- options: FromSnapshotOptions
44
- snapshotToInitialData: (processedSn: SnapshotInOfModel<AnyModel>) => any
45
- untypedSnapshot: unknown
46
- }
47
-
48
- /**
49
- * Given a type deserializes a data structure from its snapshot form.
50
- *
51
- * @template TType Object type.
52
- * @param type Type.
53
- * @param snapshot Snapshot, even if a primitive.
54
- * @param options Options.
55
- * @returns The deserialized object.
56
- */
57
- export function fromSnapshot<TType extends AnyType>(
58
- type: TType,
59
- snapshot: TypeToSnapshotIn<TType>,
60
- options?: Partial<FromSnapshotOptions>
61
- ): TypeToData<TType>
62
-
63
- /**
64
- * Deserializes a data structure from its snapshot form.
65
- *
66
- * @template T Object type.
67
- * @param snapshot Snapshot, even if a primitive.
68
- * @param options Options.
69
- * @returns The deserialized object.
70
- */
71
- export function fromSnapshot<T>(
72
- snapshot: SnapshotInOf<T> | SnapshotOutOf<T>,
73
- options?: Partial<FromSnapshotOptions>
74
- ): T
75
-
76
- export function fromSnapshot<T>(arg1: any, arg2: any, arg3?: any): T {
77
- return runWithErrorDiagnosticsContext(() => {
78
- let snapshot: any
79
- let unprocessedSnapshot: unknown
80
- let options: Partial<FromSnapshotOptions> | undefined
81
- const standardType = arguments.length >= 2 ? resolveStandardTypeNoThrow(arg1) : undefined
82
-
83
- if (isLateTypeChecker(arg1) || arg1 instanceof TypeChecker || standardType) {
84
- const resolvedType = standardType ?? arg1
85
- const codecSupport = resolveCodecSupport(resolvedType)
86
-
87
- if (codecSupport.hasCodec) {
88
- unprocessedSnapshot = arg2
89
- snapshot = resolveTypeChecker(codecSupport.storedType).fromSnapshotProcessor(
90
- unprocessedSnapshot
91
- )
92
- options = arg3
93
- const storedValue = fromSnapshotAction(snapshot, unprocessedSnapshot, options)
94
- return codecSupport.adapter.toRuntime(storedValue)
95
- }
96
-
97
- const typeChecker = resolveTypeChecker(resolvedType)
98
- unprocessedSnapshot = arg2
99
- snapshot = typeChecker.fromSnapshotProcessor(unprocessedSnapshot)
100
- options = arg3
101
- } else {
102
- snapshot = arg1
103
- unprocessedSnapshot = snapshot
104
- options = arg2
105
- }
106
-
107
- return fromSnapshotAction(snapshot, unprocessedSnapshot, options)
108
- })
109
- }
110
-
111
- const fromSnapshotAction = action(
112
- "fromSnapshot",
113
- <T>(
114
- snapshot: SnapshotInOf<T>,
115
- unprocessedSnapshot: unknown,
116
- options: Partial<FromSnapshotOptions> | undefined
117
- ): T => {
118
- const opts = {
119
- generateNewIds: false,
120
- overrideRootModelId: undefined,
121
- ...options,
122
- }
123
-
124
- const ctx: Partial<FromSnapshotContext> = {
125
- options: opts,
126
- untypedSnapshot: unprocessedSnapshot,
127
- }
128
- ctx.snapshotToInitialData = snapshotToInitialData.bind(undefined, ctx as FromSnapshotContext)
129
-
130
- return internalFromSnapshot<T>(snapshot, ctx as FromSnapshotContext)
131
- }
132
- )
133
-
134
- /**
135
- * @internal
136
- */
137
- export function internalFromSnapshot<T>(
138
- sn: SnapshotInOf<T> | SnapshotOutOf<T>,
139
- ctx: FromSnapshotContext
140
- ): T {
141
- if (isPrimitive(sn)) {
142
- return sn as any
143
- }
144
-
145
- registerDefaultSnapshotters()
146
-
147
- const snapshotterLen = snapshotters.length
148
- for (let i = 0; i < snapshotterLen; i++) {
149
- const { snapshotter } = snapshotters[i]
150
- const ret = snapshotter(sn, ctx)
151
- if (ret !== undefined) {
152
- return ret
153
- }
154
- }
155
-
156
- if (isMap(sn)) {
157
- throw new SnapshotProcessingError({
158
- message: "a snapshot must not contain maps",
159
- actualSnapshot: sn,
160
- })
161
- }
162
-
163
- if (isSet(sn)) {
164
- throw new SnapshotProcessingError({
165
- message: "a snapshot must not contain sets",
166
- actualSnapshot: sn,
167
- })
168
- }
169
-
170
- throw new SnapshotProcessingError({
171
- message: "unsupported snapshot",
172
- actualSnapshot: sn,
173
- })
174
- }
175
-
176
- function snapshotToInitialData(
177
- ctx: FromSnapshotContext,
178
- processedSn: SnapshotInOfModel<AnyModel>
179
- ): any {
180
- const initialData = observable.object({}, undefined, observableOptions)
181
-
182
- const processedSnKeys = Object.keys(processedSn)
183
- const processedSnKeysLen = processedSnKeys.length
184
- for (let i = 0; i < processedSnKeysLen; i++) {
185
- const k = processedSnKeys[i]
186
- if (!isReservedModelKey(k)) {
187
- const v = processedSn[k]
188
- const snapshotValue = withErrorPathSegment(k, () => internalFromSnapshot(v, ctx))
189
- // setIfDifferent not required
190
- set(initialData, k, snapshotValue)
191
- }
192
- }
193
- return initialData
194
- }
195
-
196
- export const observableOptions = {
197
- deep: false,
198
- }
1
+ import { action, observable } from "mobx"
2
+ import type { AnyModel } from "../model/BaseModel"
3
+ import { isReservedModelKey } from "../model/metadata"
4
+ import { resolveStandardTypeNoThrow, resolveTypeChecker } from "../types/resolveTypeChecker"
5
+ import type { AnyType, TypeToData, TypeToSnapshotIn } from "../types/schemas"
6
+ import { isLateTypeChecker, TypeChecker } from "../types/TypeChecker"
7
+ import { resolveCodecSupport } from "../types/utility/typesCodec"
8
+ import { isMap, isPrimitive, isSet, setOwnProp } from "../utils"
9
+ import { runWithErrorDiagnosticsContext, withErrorPathSegment } from "../utils/errorDiagnostics"
10
+ import { registerDefaultSnapshotters } from "./registerDefaultSnapshotters"
11
+ import type { SnapshotInOf, SnapshotInOfModel, SnapshotOutOf } from "./SnapshotOf"
12
+ import { SnapshotProcessingError } from "./SnapshotProcessingError"
13
+
14
+ /**
15
+ * @internal
16
+ */
17
+ export type Snapshotter = (sn: any, ctx: FromSnapshotContext) => any
18
+
19
+ const snapshotters: { priority: number; snapshotter: Snapshotter }[] = []
20
+
21
+ /**
22
+ * @internal
23
+ */
24
+ export function registerSnapshotter(priority: number, snapshotter: Snapshotter): void {
25
+ snapshotters.push({ priority, snapshotter })
26
+ snapshotters.sort((a, b) => a.priority - b.priority)
27
+ }
28
+
29
+ /**
30
+ * From snapshot options.
31
+ */
32
+ export interface FromSnapshotOptions {
33
+ /**
34
+ * Pass `true` to generate new internal ids for models rather than reusing them. (Default is `false`)
35
+ */
36
+ generateNewIds: boolean
37
+ }
38
+
39
+ /**
40
+ * @internal
41
+ */
42
+ export interface FromSnapshotContext {
43
+ options: FromSnapshotOptions
44
+ snapshotToInitialData: (processedSn: SnapshotInOfModel<AnyModel>) => any
45
+ untypedSnapshot: unknown
46
+ }
47
+
48
+ /**
49
+ * Given a type deserializes a data structure from its snapshot form.
50
+ *
51
+ * @template TType Object type.
52
+ * @param type Type.
53
+ * @param snapshot Snapshot, even if a primitive.
54
+ * @param options Options.
55
+ * @returns The deserialized object.
56
+ */
57
+ export function fromSnapshot<TType extends AnyType>(
58
+ type: TType,
59
+ snapshot: TypeToSnapshotIn<TType>,
60
+ options?: Partial<FromSnapshotOptions>
61
+ ): TypeToData<TType>
62
+
63
+ /**
64
+ * Deserializes a data structure from its snapshot form.
65
+ *
66
+ * @template T Object type.
67
+ * @param snapshot Snapshot, even if a primitive.
68
+ * @param options Options.
69
+ * @returns The deserialized object.
70
+ */
71
+ export function fromSnapshot<T>(
72
+ snapshot: SnapshotInOf<T> | SnapshotOutOf<T>,
73
+ options?: Partial<FromSnapshotOptions>
74
+ ): T
75
+
76
+ export function fromSnapshot<T>(arg1: any, arg2: any, arg3?: any): T {
77
+ return runWithErrorDiagnosticsContext(() => {
78
+ let snapshot: any
79
+ let unprocessedSnapshot: unknown
80
+ let options: Partial<FromSnapshotOptions> | undefined
81
+ // biome-ignore lint/complexity/noArguments: overload resolution needs the real call arity to distinguish omitted snapshots from omitted type args.
82
+ const standardType = arguments.length >= 2 ? resolveStandardTypeNoThrow(arg1) : undefined
83
+
84
+ if (isLateTypeChecker(arg1) || arg1 instanceof TypeChecker || standardType) {
85
+ const resolvedType = standardType ?? arg1
86
+ const codecSupport = resolveCodecSupport(resolvedType)
87
+
88
+ if (codecSupport.hasCodec) {
89
+ unprocessedSnapshot = arg2
90
+ snapshot = resolveTypeChecker(codecSupport.storedType).fromSnapshotProcessor(
91
+ unprocessedSnapshot
92
+ )
93
+ options = arg3
94
+ const storedValue = fromSnapshotAction(snapshot, unprocessedSnapshot, options)
95
+ return codecSupport.adapter.toRuntime(storedValue)
96
+ }
97
+
98
+ const typeChecker = resolveTypeChecker(resolvedType)
99
+ unprocessedSnapshot = arg2
100
+ snapshot = typeChecker.fromSnapshotProcessor(unprocessedSnapshot)
101
+ options = arg3
102
+ } else {
103
+ snapshot = arg1
104
+ unprocessedSnapshot = snapshot
105
+ options = arg2
106
+ }
107
+
108
+ return fromSnapshotAction(snapshot, unprocessedSnapshot, options)
109
+ })
110
+ }
111
+
112
+ const fromSnapshotAction = action(
113
+ "fromSnapshot",
114
+ <T>(
115
+ snapshot: SnapshotInOf<T>,
116
+ unprocessedSnapshot: unknown,
117
+ options: Partial<FromSnapshotOptions> | undefined
118
+ ): T => {
119
+ const opts = {
120
+ generateNewIds: false,
121
+ overrideRootModelId: undefined,
122
+ ...options,
123
+ }
124
+
125
+ const ctx: Partial<FromSnapshotContext> = {
126
+ options: opts,
127
+ untypedSnapshot: unprocessedSnapshot,
128
+ }
129
+ ctx.snapshotToInitialData = snapshotToInitialData.bind(undefined, ctx as FromSnapshotContext)
130
+
131
+ return internalFromSnapshot<T>(snapshot, ctx as FromSnapshotContext)
132
+ }
133
+ )
134
+
135
+ /**
136
+ * @internal
137
+ */
138
+ export function internalFromSnapshot<T>(
139
+ sn: SnapshotInOf<T> | SnapshotOutOf<T>,
140
+ ctx: FromSnapshotContext
141
+ ): T {
142
+ if (isPrimitive(sn)) {
143
+ return sn as any
144
+ }
145
+
146
+ registerDefaultSnapshotters()
147
+
148
+ const snapshotterLen = snapshotters.length
149
+ for (let i = 0; i < snapshotterLen; i++) {
150
+ const { snapshotter } = snapshotters[i]
151
+ const ret = snapshotter(sn, ctx)
152
+ if (ret !== undefined) {
153
+ return ret
154
+ }
155
+ }
156
+
157
+ if (isMap(sn)) {
158
+ throw new SnapshotProcessingError({
159
+ message: "a snapshot must not contain maps",
160
+ actualSnapshot: sn,
161
+ })
162
+ }
163
+
164
+ if (isSet(sn)) {
165
+ throw new SnapshotProcessingError({
166
+ message: "a snapshot must not contain sets",
167
+ actualSnapshot: sn,
168
+ })
169
+ }
170
+
171
+ throw new SnapshotProcessingError({
172
+ message: "unsupported snapshot",
173
+ actualSnapshot: sn,
174
+ })
175
+ }
176
+
177
+ function snapshotToInitialData(
178
+ ctx: FromSnapshotContext,
179
+ processedSn: SnapshotInOfModel<AnyModel>
180
+ ): any {
181
+ const initialData: Record<string, unknown> = {}
182
+
183
+ const processedSnKeys = Object.keys(processedSn)
184
+ const processedSnKeysLen = processedSnKeys.length
185
+ for (let i = 0; i < processedSnKeysLen; i++) {
186
+ const k = processedSnKeys[i]
187
+ if (!isReservedModelKey(k)) {
188
+ const v = processedSn[k]
189
+ const snapshotValue = withErrorPathSegment(k, () => internalFromSnapshot(v, ctx))
190
+ setOwnProp(initialData, k, snapshotValue)
191
+ }
192
+ }
193
+ return observable.object(initialData, undefined, observableOptions)
194
+ }
195
+
196
+ export const observableOptions = {
197
+ deep: false,
198
+ }