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,125 +1,131 @@
1
- import { getTypeInfo } from "../getTypeInfo"
2
- import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
3
- import type { AnyStandardType, AnyType, TypeToData } from "../schemas"
4
- import { TypeCheckError } from "../TypeCheckError"
5
- import { lateTypeChecker, TypeChecker, TypeInfo, TypeInfoGen } from "../TypeChecker"
6
-
7
- /**
8
- * A refinement over a given type. This allows you to do extra checks
9
- * over models, ensure numbers are integers, etc.
10
- *
11
- * Example:
12
- * ```ts
13
- * const integerType = types.refinement(types.number, (n) => {
14
- * return Number.isInteger(n)
15
- * }, "integer")
16
- *
17
- * const sumModelType = types.refinement(types.model(Sum), (sum) => {
18
- * // imagine that for some reason sum includes a number 'a', a number 'b'
19
- * // and the result
20
- *
21
- * const rightResult = sum.a + sum.b === sum.result
22
- *
23
- * // simple mode that will just return that the whole model is incorrect
24
- * return rightResult
25
- *
26
- * // this will return that the result field is wrong
27
- * return rightResult ? null : new TypeCheckError({
28
- * path: ["result"],
29
- * expectedTypeName: "a+b",
30
- * actualValue: sum.result,
31
- * })
32
- * })
33
- * ```
34
- *
35
- * @template T Base type.
36
- * @param baseType Base type.
37
- * @param checkFn Function that will receive the data (if it passes the base type
38
- * check) and return null or false if there were no errors or either a TypeCheckError instance or
39
- * true if there were.
40
- * @returns
41
- */
42
- export function typesRefinement<T extends AnyType>(
43
- baseType: T,
44
- checkFn: (data: TypeToData<T>) => TypeCheckError | null | boolean,
45
- typeName?: string
46
- ): T {
47
- const typeInfoGen: TypeInfoGen = (t) =>
48
- new RefinementTypeInfo(t, resolveStandardType(baseType), checkFn, typeName)
49
-
50
- return lateTypeChecker(() => {
51
- const baseChecker = resolveTypeChecker(baseType)
52
-
53
- const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
54
- const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
55
- const refinementName = typeName || "refinementOf"
56
- return `${refinementName}<${baseTypeName}>`
57
- }
58
-
59
- const thisTc: TypeChecker = new TypeChecker(
60
- baseChecker.baseType,
61
-
62
- (data, path, typeCheckedValue) => {
63
- const baseErr = baseChecker.check(data, path, typeCheckedValue)
64
- if (baseErr) {
65
- return baseErr
66
- }
67
-
68
- // The refinement function always runs with the full data value regardless of
69
- // the partial check scope. This is intentional: cross-property invariants
70
- // enforced by refinements must remain fully validated after every change.
71
- const refinementErr = checkFn(data)
72
-
73
- if (refinementErr === true || refinementErr == null) {
74
- return null
75
- } else if (refinementErr === false) {
76
- return new TypeCheckError({
77
- path,
78
- expectedTypeName: getTypeName(thisTc),
79
- actualValue: data,
80
- typeCheckedValue,
81
- })
82
- } else {
83
- // override typeCheckedValue
84
- return new TypeCheckError({
85
- path: refinementErr.path,
86
- expectedTypeName: refinementErr.expectedTypeName,
87
- actualValue: refinementErr.actualValue,
88
- typeCheckedValue,
89
- })
90
- }
91
- },
92
-
93
- getTypeName,
94
- typeInfoGen,
95
-
96
- // we cannot check refinement here since it checks data instances, not snapshots
97
- (sn) => baseChecker.snapshotType(sn),
98
-
99
- (sn) => baseChecker.fromSnapshotProcessor(sn),
100
- (sn) => baseChecker.toSnapshotProcessor(sn)
101
- )
102
-
103
- return thisTc
104
- }, typeInfoGen) as any
105
- }
106
-
107
- /**
108
- * `types.refinement` type info.
109
- */
110
- export class RefinementTypeInfo extends TypeInfo {
111
- readonly kind = "refinement"
112
-
113
- get baseTypeInfo(): TypeInfo {
114
- return getTypeInfo(this.baseType)
115
- }
116
-
117
- constructor(
118
- thisType: AnyStandardType,
119
- readonly baseType: AnyStandardType,
120
- readonly checkFunction: (data: any) => TypeCheckError | null | boolean,
121
- readonly typeName: string | undefined
122
- ) {
123
- super(thisType)
124
- }
125
- }
1
+ import { getTypeInfo } from "../getTypeInfo"
2
+ import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
3
+ import type { AnyStandardType, AnyType, TypeToData } from "../schemas"
4
+ import { TypeCheckError } from "../TypeCheckError"
5
+ import { lateTypeChecker, TypeChecker, TypeInfo, type TypeInfoGen } from "../TypeChecker"
6
+
7
+ /**
8
+ * A refinement over a given type. This allows you to do extra checks
9
+ * over models, ensure numbers are integers, etc.
10
+ *
11
+ * Example:
12
+ * ```ts
13
+ * const integerType = types.refinement(types.number, (n) => {
14
+ * return Number.isInteger(n)
15
+ * }, "integer")
16
+ *
17
+ * const sumModelType = types.refinement(types.model(Sum), (sum) => {
18
+ * // imagine that for some reason sum includes a number 'a', a number 'b'
19
+ * // and the result
20
+ *
21
+ * const rightResult = sum.a + sum.b === sum.result
22
+ *
23
+ * // simple mode that will just return that the whole model is incorrect
24
+ * return rightResult
25
+ *
26
+ * // this will return that the result field is wrong
27
+ * return rightResult ? null : new TypeCheckError({
28
+ * path: ["result"],
29
+ * expectedTypeName: "a+b",
30
+ * actualValue: sum.result,
31
+ * })
32
+ * })
33
+ * ```
34
+ *
35
+ * @template T Base type.
36
+ * @param baseType Base type.
37
+ * @param checkFn Function that will receive the data (if it passes the base type
38
+ * check) and return null or false if there were no errors or either a TypeCheckError instance or
39
+ * true if there were.
40
+ * @returns
41
+ */
42
+ export function typesRefinement<T extends AnyType>(
43
+ baseType: T,
44
+ checkFn: (data: TypeToData<T>) => TypeCheckError | null | boolean,
45
+ typeName?: string
46
+ ): T {
47
+ const typeInfoGen: TypeInfoGen = (t) =>
48
+ new RefinementTypeInfo(t, resolveStandardType(baseType), checkFn, typeName)
49
+
50
+ return lateTypeChecker(() => {
51
+ const baseChecker = resolveTypeChecker(baseType)
52
+
53
+ const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
54
+ const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
55
+ const refinementName = typeName || "refinementOf"
56
+ return `${refinementName}<${baseTypeName}>`
57
+ }
58
+
59
+ const thisTc: TypeChecker = new TypeChecker(
60
+ baseChecker.baseType,
61
+
62
+ (data, path, typeCheckedValue) => {
63
+ const baseErr = baseChecker.check(data, path, typeCheckedValue)
64
+ if (baseErr) {
65
+ return baseErr
66
+ }
67
+
68
+ // The refinement function always runs with the full data value regardless of
69
+ // the partial check scope. This is intentional: cross-property invariants
70
+ // enforced by refinements must remain fully validated after every change.
71
+ const refinementErr = checkFn(data)
72
+
73
+ if (refinementErr === true || refinementErr == null) {
74
+ return null
75
+ } else if (refinementErr === false) {
76
+ return new TypeCheckError({
77
+ path,
78
+ expectedTypeName: getTypeName(thisTc),
79
+ actualValue: data,
80
+ typeCheckedValue,
81
+ })
82
+ } else {
83
+ // override typeCheckedValue
84
+ return new TypeCheckError({
85
+ path: refinementErr.path,
86
+ expectedTypeName: refinementErr.expectedTypeName,
87
+ actualValue: refinementErr.actualValue,
88
+ typeCheckedValue,
89
+ })
90
+ }
91
+ },
92
+
93
+ getTypeName,
94
+ typeInfoGen,
95
+
96
+ // we cannot check refinement here since it checks data instances, not snapshots
97
+ (sn) => baseChecker.snapshotType(sn),
98
+
99
+ (sn) => baseChecker.fromSnapshotProcessor(sn),
100
+ (sn) => baseChecker.toSnapshotProcessor(sn)
101
+ )
102
+
103
+ return thisTc
104
+ }, typeInfoGen) as any
105
+ }
106
+
107
+ /**
108
+ * `types.refinement` type info.
109
+ */
110
+ export class RefinementTypeInfo extends TypeInfo {
111
+ readonly kind = "refinement"
112
+ readonly baseType: AnyStandardType
113
+ readonly checkFunction: (data: any) => TypeCheckError | null | boolean
114
+ readonly typeName: string | undefined
115
+
116
+ get baseTypeInfo(): TypeInfo {
117
+ return getTypeInfo(this.baseType)
118
+ }
119
+
120
+ constructor(
121
+ thisType: AnyStandardType,
122
+ baseType: AnyStandardType,
123
+ checkFunction: (data: any) => TypeCheckError | null | boolean,
124
+ typeName: string | undefined
125
+ ) {
126
+ super(thisType)
127
+ this.baseType = baseType
128
+ this.checkFunction = checkFunction
129
+ this.typeName = typeName
130
+ }
131
+ }
@@ -1,110 +1,110 @@
1
- import { type ObservableSet } from "mobx"
2
- import type { ModelPropTransform } from "../../modelShared/prop"
3
- import { isSet } from "../../utils"
4
- import { asSet } from "../../wrappers/asSet"
5
- import { typesArray } from "../arrayBased/typesArray"
6
- import type { AnyType, ArrayType, TypeToData } from "../schemas"
7
- import { TypeCheckerBaseType } from "../TypeChecker"
8
- import type { CodecFromEncoded, RuntimeAdapter } from "./typesCodecCore"
9
- import { createCodecType } from "./typesCodecCore"
10
- import { resolveCodecSupport } from "./typesCodecSupport"
11
-
12
- function makeArrayBackedSetTransform<TStored, TRuntime>(
13
- valueAdapter: RuntimeAdapter<TStored, TRuntime>
14
- ): ModelPropTransform<Array<TStored>, Set<TRuntime> | ObservableSet<TRuntime>> {
15
- const storedByRuntime = new WeakMap<Set<TRuntime> | ObservableSet<TRuntime>, Array<TStored>>()
16
-
17
- return {
18
- transform({ originalValue, cachedTransformedValue }) {
19
- if (cachedTransformedValue) {
20
- return cachedTransformedValue
21
- }
22
-
23
- const storedSet = asSet(originalValue)
24
-
25
- const runtimeSet: Set<TRuntime> | ObservableSet<TRuntime> = new Proxy(storedSet, {
26
- get(target, prop, receiver) {
27
- switch (prop) {
28
- case "has":
29
- return (value: TRuntime) => target.has(valueAdapter.toStored(value))
30
- case "add":
31
- return (value: TRuntime) => {
32
- target.add(valueAdapter.toStored(value))
33
- return receiver
34
- }
35
- case "delete":
36
- return (value: TRuntime) => target.delete(valueAdapter.toStored(value))
37
- case "clear":
38
- return () => target.clear()
39
- case "size":
40
- return target.size
41
- case "forEach":
42
- return (
43
- callback: (
44
- value: TRuntime,
45
- key: TRuntime,
46
- set: Set<TRuntime> | ObservableSet<TRuntime>
47
- ) => void,
48
- thisArg?: unknown
49
- ) => {
50
- target.forEach((value) => {
51
- const runtimeValue = valueAdapter.toRuntime(value)
52
- callback.call(thisArg, runtimeValue, runtimeValue, receiver)
53
- })
54
- }
55
- case "entries":
56
- return function* () {
57
- for (const value of target.values()) {
58
- const runtimeValue = valueAdapter.toRuntime(value)
59
- yield [runtimeValue, runtimeValue] as const
60
- }
61
- }
62
- case "keys":
63
- case "values":
64
- case Symbol.iterator:
65
- return function* () {
66
- for (const value of target.values()) {
67
- yield valueAdapter.toRuntime(value)
68
- }
69
- }
70
- default:
71
- return Reflect.get(target, prop, receiver)
72
- }
73
- },
74
- }) as unknown as Set<TRuntime> | ObservableSet<TRuntime>
75
-
76
- storedByRuntime.set(runtimeSet, originalValue)
77
- return runtimeSet
78
- },
79
-
80
- untransform({ transformedValue }) {
81
- const cachedStored = storedByRuntime.get(transformedValue)
82
- if (cachedStored) {
83
- return cachedStored
84
- }
85
-
86
- return Array.from(transformedValue.values()).map((value) => valueAdapter.toStored(value))
87
- },
88
- }
89
- }
90
-
91
- export function typesSetFromArray<TValueType extends AnyType>(
92
- valueType: TValueType
93
- ): CodecFromEncoded<
94
- ArrayType<TValueType[]>,
95
- Set<TypeToData<TValueType>> | ObservableSet<TypeToData<TValueType>>
96
- > {
97
- const valueSupport = resolveCodecSupport(valueType)
98
-
99
- return createCodecType(
100
- {
101
- typeName: "setFromArray",
102
- encodedType: typesArray(valueSupport.storedType),
103
- is(value): value is Set<TypeToData<TValueType>> | ObservableSet<TypeToData<TValueType>> {
104
- return isSet(value)
105
- },
106
- ...makeArrayBackedSetTransform(valueSupport.adapter),
107
- },
108
- TypeCheckerBaseType.Object
109
- )
110
- }
1
+ import type { ObservableSet } from "mobx"
2
+ import type { ModelPropTransform } from "../../modelShared/prop"
3
+ import { isSet } from "../../utils"
4
+ import { asSet } from "../../wrappers/asSet"
5
+ import { typesArray } from "../arrayBased/typesArray"
6
+ import type { AnyType, ArrayType, TypeToData } from "../schemas"
7
+ import { TypeCheckerBaseType } from "../TypeChecker"
8
+ import type { CodecFromEncoded, RuntimeAdapter } from "./typesCodecCore"
9
+ import { createCodecType } from "./typesCodecCore"
10
+ import { resolveCodecSupport } from "./typesCodecSupport"
11
+
12
+ function makeArrayBackedSetTransform<TStored, TRuntime>(
13
+ valueAdapter: RuntimeAdapter<TStored, TRuntime>
14
+ ): ModelPropTransform<Array<TStored>, Set<TRuntime> | ObservableSet<TRuntime>> {
15
+ const storedByRuntime = new WeakMap<Set<TRuntime> | ObservableSet<TRuntime>, Array<TStored>>()
16
+
17
+ return {
18
+ transform({ originalValue, cachedTransformedValue }) {
19
+ if (cachedTransformedValue) {
20
+ return cachedTransformedValue
21
+ }
22
+
23
+ const storedSet = asSet(originalValue)
24
+
25
+ const runtimeSet: Set<TRuntime> | ObservableSet<TRuntime> = new Proxy(storedSet, {
26
+ get(target, prop, receiver) {
27
+ switch (prop) {
28
+ case "has":
29
+ return (value: TRuntime) => target.has(valueAdapter.toStored(value))
30
+ case "add":
31
+ return (value: TRuntime) => {
32
+ target.add(valueAdapter.toStored(value))
33
+ return receiver
34
+ }
35
+ case "delete":
36
+ return (value: TRuntime) => target.delete(valueAdapter.toStored(value))
37
+ case "clear":
38
+ return () => target.clear()
39
+ case "size":
40
+ return target.size
41
+ case "forEach":
42
+ return (
43
+ callback: (
44
+ value: TRuntime,
45
+ key: TRuntime,
46
+ set: Set<TRuntime> | ObservableSet<TRuntime>
47
+ ) => void,
48
+ thisArg?: unknown
49
+ ) => {
50
+ target.forEach((value) => {
51
+ const runtimeValue = valueAdapter.toRuntime(value)
52
+ callback.call(thisArg, runtimeValue, runtimeValue, receiver)
53
+ })
54
+ }
55
+ case "entries":
56
+ return function* () {
57
+ for (const value of target.values()) {
58
+ const runtimeValue = valueAdapter.toRuntime(value)
59
+ yield [runtimeValue, runtimeValue] as const
60
+ }
61
+ }
62
+ case "keys":
63
+ case "values":
64
+ case Symbol.iterator:
65
+ return function* () {
66
+ for (const value of target.values()) {
67
+ yield valueAdapter.toRuntime(value)
68
+ }
69
+ }
70
+ default:
71
+ return Reflect.get(target, prop, receiver)
72
+ }
73
+ },
74
+ }) as unknown as Set<TRuntime> | ObservableSet<TRuntime>
75
+
76
+ storedByRuntime.set(runtimeSet, originalValue)
77
+ return runtimeSet
78
+ },
79
+
80
+ untransform({ transformedValue }) {
81
+ const cachedStored = storedByRuntime.get(transformedValue)
82
+ if (cachedStored) {
83
+ return cachedStored
84
+ }
85
+
86
+ return Array.from(transformedValue.values()).map((value) => valueAdapter.toStored(value))
87
+ },
88
+ }
89
+ }
90
+
91
+ export function typesSetFromArray<TValueType extends AnyType>(
92
+ valueType: TValueType
93
+ ): CodecFromEncoded<
94
+ ArrayType<TValueType[]>,
95
+ Set<TypeToData<TValueType>> | ObservableSet<TypeToData<TValueType>>
96
+ > {
97
+ const valueSupport = resolveCodecSupport(valueType)
98
+
99
+ return createCodecType(
100
+ {
101
+ typeName: "setFromArray",
102
+ encodedType: typesArray(valueSupport.storedType),
103
+ is(value): value is Set<TypeToData<TValueType>> | ObservableSet<TypeToData<TValueType>> {
104
+ return isSet(value)
105
+ },
106
+ ...makeArrayBackedSetTransform(valueSupport.adapter),
107
+ },
108
+ TypeCheckerBaseType.Object
109
+ )
110
+ }
@@ -1,70 +1,69 @@
1
- import { getTypeInfo } from "../getTypeInfo"
2
- import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
3
- import type { AnyStandardType, AnyType } from "../schemas"
4
- import { lateTypeChecker, TypeChecker, TypeInfo, TypeInfoGen } from "../TypeChecker"
5
-
6
- /**
7
- * A type that wraps another type but skips runtime validation.
8
- * Unlike `types.unchecked()`, this preserves the wrapped type's
9
- * runtime/snapshot typing and all processors/codecs/transforms.
10
- *
11
- * Use this when you want codec conversions (e.g. `types.dateAsTimestamp`,
12
- * `types.bigint`, `types.mapFromObject(...)`) without paying the cost of
13
- * runtime type checking on every change.
14
- *
15
- * Example:
16
- * ```ts
17
- * // Date codec with no runtime validation
18
- * const dateType = types.skipCheck(types.dateAsTimestamp)
19
- *
20
- * // In a model
21
- * class M extends Model({ date: tProp(types.skipCheck(types.dateAsTimestamp)) }) {}
22
- * ```
23
- *
24
- * @template T Base type.
25
- * @param baseType The type whose validation should be skipped.
26
- * @returns A type with the same runtime/snapshot behavior but no validation.
27
- */
28
- export function typesSkipCheck<T extends AnyType>(baseType: T): T {
29
- const typeInfoGen: TypeInfoGen = (t) => new SkipCheckTypeInfo(t, resolveStandardType(baseType))
30
-
31
- return lateTypeChecker(() => {
32
- const baseChecker = resolveTypeChecker(baseType)
33
-
34
- const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
35
- const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
36
- return `skipCheck<${baseTypeName}>`
37
- }
38
-
39
- const thisTc: TypeChecker = new TypeChecker(
40
- baseChecker.baseType,
41
- (_data, _path, _typeCheckedValue) => null, // always passes validation
42
- getTypeName,
43
- typeInfoGen,
44
- (sn) => baseChecker.snapshotType(sn),
45
- (sn) => baseChecker.fromSnapshotProcessor(sn),
46
- (sn) => baseChecker.toSnapshotProcessor(sn)
47
- )
48
- thisTc.skipCheck = true
49
-
50
- return thisTc
51
- }, typeInfoGen) as any
52
- }
53
-
54
- /**
55
- * `types.skipCheck` type info.
56
- */
57
- export class SkipCheckTypeInfo extends TypeInfo {
58
- readonly kind = "skipCheck"
59
-
60
- get baseTypeInfo(): TypeInfo {
61
- return getTypeInfo(this.baseType)
62
- }
63
-
64
- constructor(
65
- thisType: AnyStandardType,
66
- readonly baseType: AnyStandardType
67
- ) {
68
- super(thisType)
69
- }
70
- }
1
+ import { getTypeInfo } from "../getTypeInfo"
2
+ import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
3
+ import type { AnyStandardType, AnyType } from "../schemas"
4
+ import { lateTypeChecker, TypeChecker, TypeInfo, type TypeInfoGen } from "../TypeChecker"
5
+
6
+ /**
7
+ * A type that wraps another type but skips runtime validation.
8
+ * Unlike `types.unchecked()`, this preserves the wrapped type's
9
+ * runtime/snapshot typing and all processors/codecs/transforms.
10
+ *
11
+ * Use this when you want codec conversions (e.g. `types.dateAsTimestamp`,
12
+ * `types.bigint`, `types.mapFromObject(...)`) without paying the cost of
13
+ * runtime type checking on every change.
14
+ *
15
+ * Example:
16
+ * ```ts
17
+ * // Date codec with no runtime validation
18
+ * const dateType = types.skipCheck(types.dateAsTimestamp)
19
+ *
20
+ * // In a model
21
+ * class M extends Model({ date: tProp(types.skipCheck(types.dateAsTimestamp)) }) {}
22
+ * ```
23
+ *
24
+ * @template T Base type.
25
+ * @param baseType The type whose validation should be skipped.
26
+ * @returns A type with the same runtime/snapshot behavior but no validation.
27
+ */
28
+ export function typesSkipCheck<T extends AnyType>(baseType: T): T {
29
+ const typeInfoGen: TypeInfoGen = (t) => new SkipCheckTypeInfo(t, resolveStandardType(baseType))
30
+
31
+ return lateTypeChecker(() => {
32
+ const baseChecker = resolveTypeChecker(baseType)
33
+
34
+ const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
35
+ const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
36
+ return `skipCheck<${baseTypeName}>`
37
+ }
38
+
39
+ const thisTc: TypeChecker = new TypeChecker(
40
+ baseChecker.baseType,
41
+ (_data, _path, _typeCheckedValue) => null, // always passes validation
42
+ getTypeName,
43
+ typeInfoGen,
44
+ (sn) => baseChecker.snapshotType(sn),
45
+ (sn) => baseChecker.fromSnapshotProcessor(sn),
46
+ (sn) => baseChecker.toSnapshotProcessor(sn)
47
+ )
48
+ thisTc.skipCheck = true
49
+
50
+ return thisTc
51
+ }, typeInfoGen) as any
52
+ }
53
+
54
+ /**
55
+ * `types.skipCheck` type info.
56
+ */
57
+ export class SkipCheckTypeInfo extends TypeInfo {
58
+ readonly kind = "skipCheck"
59
+ readonly baseType: AnyStandardType
60
+
61
+ get baseTypeInfo(): TypeInfo {
62
+ return getTypeInfo(this.baseType)
63
+ }
64
+
65
+ constructor(thisType: AnyStandardType, baseType: AnyStandardType) {
66
+ super(thisType)
67
+ this.baseType = baseType
68
+ }
69
+ }