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,143 +1,142 @@
1
- import { modelTypeKey } from "../../model/metadata"
2
- import { modelInfoByClass } from "../../modelShared/modelInfo"
3
- import { isObject } from "../../utils"
4
- import { withErrorPathSegment } from "../../utils/errorDiagnostics"
5
- import { ObjectMap } from "../../wrappers/ObjectMap"
6
- import { getTypeInfo } from "../getTypeInfo"
7
- import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
8
- import type { AnyStandardType, AnyType, ModelType, TypeToData } from "../schemas"
9
- import { TypeCheckError } from "../TypeCheckError"
10
- import {
11
- lateTypeChecker,
12
- TypeChecker,
13
- TypeCheckerBaseType,
14
- TypeInfo,
15
- TypeInfoGen,
16
- } from "../TypeChecker"
17
- import { resolveCodecSupport } from "../utility/typesCodec"
18
- import { typesObject } from "./typesObject"
19
- import { typesRecord } from "./typesRecord"
20
-
21
- /**
22
- * A type that represents an object-like map ObjectMap.
23
- *
24
- * Example:
25
- * ```ts
26
- * const numberMapType = types.objectMap(types.number)
27
- * ```
28
- *
29
- * @template T Value type.
30
- * @param valueType Value type.
31
- * @returns
32
- */
33
- export function typesObjectMap<T extends AnyType>(
34
- valueType: T
35
- ): ModelType<ObjectMap<TypeToData<T>>> {
36
- const typeInfoGen: TypeInfoGen = (t) => new ObjectMapTypeInfo(t, resolveStandardType(valueType))
37
-
38
- return lateTypeChecker(() => {
39
- const modelInfo = modelInfoByClass.get(ObjectMap)!
40
-
41
- const valueChecker = resolveTypeChecker(valueType)
42
- const valueSupport = resolveCodecSupport(valueType)
43
- const storedValueChecker = resolveTypeChecker(valueSupport.storedType)
44
-
45
- const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) =>
46
- `ObjectMap<${valueChecker.getTypeName(...recursiveTypeCheckers, valueChecker)}>`
47
-
48
- const dataTypeChecker = typesObject(() => ({
49
- items: typesRecord(valueSupport.storedType as any),
50
- }))
51
- const resolvedDataTypeChecker = resolveTypeChecker(dataTypeChecker)
52
-
53
- const thisTc: TypeChecker = new TypeChecker(
54
- TypeCheckerBaseType.Object,
55
-
56
- (obj, path, typeCheckedValue) => {
57
- if (!(obj instanceof ObjectMap)) {
58
- return new TypeCheckError({
59
- path,
60
- expectedTypeName: getTypeName(thisTc),
61
- actualValue: obj,
62
- typeCheckedValue,
63
- })
64
- }
65
-
66
- return resolvedDataTypeChecker.check(obj.$, path, typeCheckedValue)
67
- },
68
-
69
- getTypeName,
70
- typeInfoGen,
71
-
72
- (obj) => {
73
- if (!isObject(obj)) {
74
- return null
75
- }
76
-
77
- if (obj[modelTypeKey] !== undefined) {
78
- // fast check
79
- return obj[modelTypeKey] === modelInfo.name ? thisTc : null
80
- }
81
-
82
- return resolvedDataTypeChecker.snapshotType(obj) ? thisTc : null
83
- },
84
-
85
- (sn: { items: Record<string, unknown> }) => {
86
- const newItems: (typeof sn)["items"] = {}
87
-
88
- withErrorPathSegment("items", () => {
89
- for (const k of Object.keys(sn.items)) {
90
- newItems[k] = withErrorPathSegment(k, () =>
91
- storedValueChecker.fromSnapshotProcessor(sn.items[k])
92
- )
93
- }
94
- })
95
-
96
- return {
97
- ...sn,
98
- [modelTypeKey]: modelInfo.name,
99
- items: newItems,
100
- }
101
- },
102
-
103
- (sn: { items: Record<string, unknown>; [modelTypeKey]?: string }) => {
104
- const newItems: (typeof sn)["items"] = {}
105
-
106
- withErrorPathSegment("items", () => {
107
- for (const k of Object.keys(sn.items)) {
108
- newItems[k] = withErrorPathSegment(k, () =>
109
- storedValueChecker.toSnapshotProcessor(sn.items[k])
110
- )
111
- }
112
- })
113
-
114
- const snCopy = {
115
- ...sn,
116
- items: newItems,
117
- }
118
-
119
- return snCopy
120
- }
121
- )
122
-
123
- return thisTc
124
- }, typeInfoGen) as any
125
- }
126
-
127
- /**
128
- * `types.objectMap` type info.
129
- */
130
- export class ObjectMapTypeInfo extends TypeInfo {
131
- readonly kind = "objectMap"
132
-
133
- get valueTypeInfo(): TypeInfo {
134
- return getTypeInfo(this.valueType)
135
- }
136
-
137
- constructor(
138
- thisType: AnyStandardType,
139
- readonly valueType: AnyStandardType
140
- ) {
141
- super(thisType)
142
- }
143
- }
1
+ import { modelTypeKey } from "../../model/metadata"
2
+ import { modelInfoByClass } from "../../modelShared/modelInfo"
3
+ import { isObject } from "../../utils"
4
+ import { withErrorPathSegment } from "../../utils/errorDiagnostics"
5
+ import { ObjectMap } from "../../wrappers/ObjectMap"
6
+ import { getTypeInfo } from "../getTypeInfo"
7
+ import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
8
+ import type { AnyStandardType, AnyType, ModelType, TypeToData } from "../schemas"
9
+ import { TypeCheckError } from "../TypeCheckError"
10
+ import {
11
+ lateTypeChecker,
12
+ TypeChecker,
13
+ TypeCheckerBaseType,
14
+ TypeInfo,
15
+ type TypeInfoGen,
16
+ } from "../TypeChecker"
17
+ import { resolveCodecSupport } from "../utility/typesCodec"
18
+ import { typesObject } from "./typesObject"
19
+ import { typesRecord } from "./typesRecord"
20
+
21
+ /**
22
+ * A type that represents an object-like map ObjectMap.
23
+ *
24
+ * Example:
25
+ * ```ts
26
+ * const numberMapType = types.objectMap(types.number)
27
+ * ```
28
+ *
29
+ * @template T Value type.
30
+ * @param valueType Value type.
31
+ * @returns
32
+ */
33
+ export function typesObjectMap<T extends AnyType>(
34
+ valueType: T
35
+ ): ModelType<ObjectMap<TypeToData<T>>> {
36
+ const typeInfoGen: TypeInfoGen = (t) => new ObjectMapTypeInfo(t, resolveStandardType(valueType))
37
+
38
+ return lateTypeChecker(() => {
39
+ const modelInfo = modelInfoByClass.get(ObjectMap)!
40
+
41
+ const valueChecker = resolveTypeChecker(valueType)
42
+ const valueSupport = resolveCodecSupport(valueType)
43
+ const storedValueChecker = resolveTypeChecker(valueSupport.storedType)
44
+
45
+ const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) =>
46
+ `ObjectMap<${valueChecker.getTypeName(...recursiveTypeCheckers, valueChecker)}>`
47
+
48
+ const dataTypeChecker = typesObject(() => ({
49
+ items: typesRecord(valueSupport.storedType as any),
50
+ }))
51
+ const resolvedDataTypeChecker = resolveTypeChecker(dataTypeChecker)
52
+
53
+ const thisTc: TypeChecker = new TypeChecker(
54
+ TypeCheckerBaseType.Object,
55
+
56
+ (obj, path, typeCheckedValue) => {
57
+ if (!(obj instanceof ObjectMap)) {
58
+ return new TypeCheckError({
59
+ path,
60
+ expectedTypeName: getTypeName(thisTc),
61
+ actualValue: obj,
62
+ typeCheckedValue,
63
+ })
64
+ }
65
+
66
+ return resolvedDataTypeChecker.check(obj.$, path, typeCheckedValue)
67
+ },
68
+
69
+ getTypeName,
70
+ typeInfoGen,
71
+
72
+ (obj) => {
73
+ if (!isObject(obj)) {
74
+ return null
75
+ }
76
+
77
+ if (obj[modelTypeKey] !== undefined) {
78
+ // fast check
79
+ return obj[modelTypeKey] === modelInfo.name ? thisTc : null
80
+ }
81
+
82
+ return resolvedDataTypeChecker.snapshotType(obj) ? thisTc : null
83
+ },
84
+
85
+ (sn: { items: Record<string, unknown> }) => {
86
+ const newItems: (typeof sn)["items"] = {}
87
+
88
+ withErrorPathSegment("items", () => {
89
+ for (const k of Object.keys(sn.items)) {
90
+ newItems[k] = withErrorPathSegment(k, () =>
91
+ storedValueChecker.fromSnapshotProcessor(sn.items[k])
92
+ )
93
+ }
94
+ })
95
+
96
+ return {
97
+ ...sn,
98
+ [modelTypeKey]: modelInfo.name,
99
+ items: newItems,
100
+ }
101
+ },
102
+
103
+ (sn: { items: Record<string, unknown>; [modelTypeKey]?: string }) => {
104
+ const newItems: (typeof sn)["items"] = {}
105
+
106
+ withErrorPathSegment("items", () => {
107
+ for (const k of Object.keys(sn.items)) {
108
+ newItems[k] = withErrorPathSegment(k, () =>
109
+ storedValueChecker.toSnapshotProcessor(sn.items[k])
110
+ )
111
+ }
112
+ })
113
+
114
+ const snCopy = {
115
+ ...sn,
116
+ items: newItems,
117
+ }
118
+
119
+ return snCopy
120
+ }
121
+ )
122
+
123
+ return thisTc
124
+ }, typeInfoGen) as any
125
+ }
126
+
127
+ /**
128
+ * `types.objectMap` type info.
129
+ */
130
+ export class ObjectMapTypeInfo extends TypeInfo {
131
+ readonly kind = "objectMap"
132
+ readonly valueType: AnyStandardType
133
+
134
+ get valueTypeInfo(): TypeInfo {
135
+ return getTypeInfo(this.valueType)
136
+ }
137
+
138
+ constructor(thisType: AnyStandardType, valueType: AnyStandardType) {
139
+ super(thisType)
140
+ this.valueType = valueType
141
+ }
142
+ }
@@ -1,157 +1,156 @@
1
- import { isObservableObject, keys } from "mobx"
2
- import type { Path } from "../../parent/pathTypes"
3
- import { failure, isObject } from "../../utils"
4
- import { withErrorPathSegment } from "../../utils/errorDiagnostics"
5
- import { createPerEntryCachedCheck, recordCachePruning } from "../createPerEntryCachedCheck"
6
- import { getTypeInfo } from "../getTypeInfo"
7
- import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
8
- import type { AnyStandardType, AnyType, RecordType } from "../schemas"
9
- import { TypeCheckError } from "../TypeCheckError"
10
- import {
11
- lateTypeChecker,
12
- TypeChecker,
13
- TypeCheckerBaseType,
14
- TypeInfo,
15
- TypeInfoGen,
16
- } from "../TypeChecker"
17
- import { prependPathElementToTypeCheckError } from "../typeCheckErrorUtils"
18
-
19
- /**
20
- * A type that represents an object-like map, an object with string keys and values all of a same given type.
21
- *
22
- * Example:
23
- * ```ts
24
- * // { [k: string]: number }
25
- * const numberMapType = types.record(types.number)
26
- * ```
27
- *
28
- * @template T Type.
29
- * @param valueType Type of the values of the object-like map.
30
- * @returns
31
- */
32
- export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
33
- const typeInfoGen: TypeInfoGen = (tc) => new RecordTypeInfo(tc, resolveStandardType(valueType))
34
-
35
- return lateTypeChecker(() => {
36
- const valueChecker = resolveTypeChecker(valueType)
37
- const emptyChildPath: Path = []
38
-
39
- const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) =>
40
- `Record<${valueChecker.getTypeName(...recursiveTypeCheckers, valueChecker)}>`
41
-
42
- const applySnapshotProcessor = (obj: Record<string, unknown>, mode: "from" | "to") => {
43
- if (valueChecker.unchecked) {
44
- return obj
45
- }
46
-
47
- const newObj: typeof obj = {}
48
-
49
- const keys = Object.keys(obj)
50
- for (let i = 0; i < keys.length; i++) {
51
- const k = keys[i]
52
- const v = withErrorPathSegment(k, () =>
53
- mode === "from"
54
- ? valueChecker.fromSnapshotProcessor(obj[k])
55
- : valueChecker.toSnapshotProcessor(obj[k])
56
- )
57
- newObj[k] = v
58
- }
59
-
60
- return newObj
61
- }
62
-
63
- const checkRecordValues = createPerEntryCachedCheck(
64
- (obj, checkEntry) => {
65
- // Use keys() from MobX for observable objects to track key additions/removals
66
- // in MobX 4 (which lacks Proxy). Object.keys() doesn't establish MobX tracking
67
- // in MobX 4, so the aggregation computed would miss newly added keys.
68
- const objKeys = isObservableObject(obj) ? keys(obj) : Object.keys(obj)
69
- for (let i = 0; i < objKeys.length; i++) {
70
- const error = checkEntry(objKeys[i])
71
- if (error) return error
72
- }
73
- return null
74
- },
75
- (obj, key, path, typeCheckedValue) => {
76
- if (typeof key !== "string") {
77
- throw failure(`record type keys must be strings, got ${typeof key}`)
78
- }
79
- const error = valueChecker.check(obj[key], emptyChildPath, typeCheckedValue)
80
- return error ? prependPathElementToTypeCheckError(error, path, key, typeCheckedValue) : null
81
- },
82
- recordCachePruning
83
- )
84
-
85
- const thisTc: TypeChecker = new TypeChecker(
86
- TypeCheckerBaseType.Object,
87
-
88
- (obj, path, typeCheckedValue) => {
89
- if (!isObject(obj)) {
90
- return new TypeCheckError({
91
- path,
92
- expectedTypeName: getTypeName(thisTc),
93
- actualValue: obj,
94
- typeCheckedValue,
95
- })
96
- }
97
-
98
- if (valueChecker.unchecked || valueChecker.skipCheck) {
99
- return null
100
- }
101
-
102
- return checkRecordValues(obj, path, typeCheckedValue)
103
- },
104
-
105
- getTypeName,
106
- typeInfoGen,
107
-
108
- (obj) => {
109
- if (!isObject(obj)) {
110
- return null
111
- }
112
-
113
- if (!valueChecker.unchecked) {
114
- const keys = Object.keys(obj)
115
- for (let i = 0; i < keys.length; i++) {
116
- const k = keys[i]
117
- const v = obj[k]
118
- const valueActualChecker = valueChecker.snapshotType(v)
119
- if (!valueActualChecker) {
120
- return null
121
- }
122
- }
123
- }
124
-
125
- return thisTc
126
- },
127
-
128
- (obj: Record<string, unknown>) => {
129
- return applySnapshotProcessor(obj, "from")
130
- },
131
-
132
- (obj: Record<string, unknown>) => {
133
- return applySnapshotProcessor(obj, "to")
134
- }
135
- )
136
-
137
- return thisTc
138
- }, typeInfoGen) as any
139
- }
140
-
141
- /**
142
- * `types.record` type info.
143
- */
144
- export class RecordTypeInfo extends TypeInfo {
145
- readonly kind = "record"
146
-
147
- get valueTypeInfo(): TypeInfo {
148
- return getTypeInfo(this.valueType)
149
- }
150
-
151
- constructor(
152
- thisType: AnyStandardType,
153
- readonly valueType: AnyStandardType
154
- ) {
155
- super(thisType)
156
- }
157
- }
1
+ import { isObservableObject, keys } from "mobx"
2
+ import type { Path } from "../../parent/pathTypes"
3
+ import { failure, isObject } from "../../utils"
4
+ import { withErrorPathSegment } from "../../utils/errorDiagnostics"
5
+ import { createPerEntryCachedCheck, recordCachePruning } from "../createPerEntryCachedCheck"
6
+ import { getTypeInfo } from "../getTypeInfo"
7
+ import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
8
+ import type { AnyStandardType, AnyType, RecordType } from "../schemas"
9
+ import { TypeCheckError } from "../TypeCheckError"
10
+ import {
11
+ lateTypeChecker,
12
+ TypeChecker,
13
+ TypeCheckerBaseType,
14
+ TypeInfo,
15
+ type TypeInfoGen,
16
+ } from "../TypeChecker"
17
+ import { prependPathElementToTypeCheckError } from "../typeCheckErrorUtils"
18
+
19
+ /**
20
+ * A type that represents an object-like map, an object with string keys and values all of a same given type.
21
+ *
22
+ * Example:
23
+ * ```ts
24
+ * // { [k: string]: number }
25
+ * const numberMapType = types.record(types.number)
26
+ * ```
27
+ *
28
+ * @template T Type.
29
+ * @param valueType Type of the values of the object-like map.
30
+ * @returns
31
+ */
32
+ export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
33
+ const typeInfoGen: TypeInfoGen = (tc) => new RecordTypeInfo(tc, resolveStandardType(valueType))
34
+
35
+ return lateTypeChecker(() => {
36
+ const valueChecker = resolveTypeChecker(valueType)
37
+ const emptyChildPath: Path = []
38
+
39
+ const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) =>
40
+ `Record<${valueChecker.getTypeName(...recursiveTypeCheckers, valueChecker)}>`
41
+
42
+ const applySnapshotProcessor = (obj: Record<string, unknown>, mode: "from" | "to") => {
43
+ if (valueChecker.unchecked) {
44
+ return obj
45
+ }
46
+
47
+ const newObj: typeof obj = {}
48
+
49
+ const keys = Object.keys(obj)
50
+ for (let i = 0; i < keys.length; i++) {
51
+ const k = keys[i]
52
+ const v = withErrorPathSegment(k, () =>
53
+ mode === "from"
54
+ ? valueChecker.fromSnapshotProcessor(obj[k])
55
+ : valueChecker.toSnapshotProcessor(obj[k])
56
+ )
57
+ newObj[k] = v
58
+ }
59
+
60
+ return newObj
61
+ }
62
+
63
+ const checkRecordValues = createPerEntryCachedCheck(
64
+ (obj, checkEntry) => {
65
+ // Use keys() from MobX for observable objects to track key additions/removals
66
+ // in MobX 4 (which lacks Proxy). Object.keys() doesn't establish MobX tracking
67
+ // in MobX 4, so the aggregation computed would miss newly added keys.
68
+ const objKeys = isObservableObject(obj) ? keys(obj) : Object.keys(obj)
69
+ for (let i = 0; i < objKeys.length; i++) {
70
+ const error = checkEntry(objKeys[i])
71
+ if (error) return error
72
+ }
73
+ return null
74
+ },
75
+ (obj, key, path, typeCheckedValue) => {
76
+ if (typeof key !== "string") {
77
+ throw failure(`record type keys must be strings, got ${typeof key}`)
78
+ }
79
+ const error = valueChecker.check(obj[key], emptyChildPath, typeCheckedValue)
80
+ return error ? prependPathElementToTypeCheckError(error, path, key, typeCheckedValue) : null
81
+ },
82
+ recordCachePruning
83
+ )
84
+
85
+ const thisTc: TypeChecker = new TypeChecker(
86
+ TypeCheckerBaseType.Object,
87
+
88
+ (obj, path, typeCheckedValue) => {
89
+ if (!isObject(obj)) {
90
+ return new TypeCheckError({
91
+ path,
92
+ expectedTypeName: getTypeName(thisTc),
93
+ actualValue: obj,
94
+ typeCheckedValue,
95
+ })
96
+ }
97
+
98
+ if (valueChecker.unchecked || valueChecker.skipCheck) {
99
+ return null
100
+ }
101
+
102
+ return checkRecordValues(obj, path, typeCheckedValue)
103
+ },
104
+
105
+ getTypeName,
106
+ typeInfoGen,
107
+
108
+ (obj) => {
109
+ if (!isObject(obj)) {
110
+ return null
111
+ }
112
+
113
+ if (!valueChecker.unchecked) {
114
+ const keys = Object.keys(obj)
115
+ for (let i = 0; i < keys.length; i++) {
116
+ const k = keys[i]
117
+ const v = obj[k]
118
+ const valueActualChecker = valueChecker.snapshotType(v)
119
+ if (!valueActualChecker) {
120
+ return null
121
+ }
122
+ }
123
+ }
124
+
125
+ return thisTc
126
+ },
127
+
128
+ (obj: Record<string, unknown>) => {
129
+ return applySnapshotProcessor(obj, "from")
130
+ },
131
+
132
+ (obj: Record<string, unknown>) => {
133
+ return applySnapshotProcessor(obj, "to")
134
+ }
135
+ )
136
+
137
+ return thisTc
138
+ }, typeInfoGen) as any
139
+ }
140
+
141
+ /**
142
+ * `types.record` type info.
143
+ */
144
+ export class RecordTypeInfo extends TypeInfo {
145
+ readonly kind = "record"
146
+ readonly valueType: AnyStandardType
147
+
148
+ get valueTypeInfo(): TypeInfo {
149
+ return getTypeInfo(this.valueType)
150
+ }
151
+
152
+ constructor(thisType: AnyStandardType, valueType: AnyStandardType) {
153
+ super(thisType)
154
+ this.valueType = valueType
155
+ }
156
+ }