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.
- package/CHANGELOG.md +864 -853
- package/README.md +61 -61
- package/dist/mobx-keystone.esm.js +11336 -11148
- package/dist/mobx-keystone.esm.mjs +11336 -11148
- package/dist/mobx-keystone.umd.js +12229 -11738
- package/dist/types/actionMiddlewares/undoMiddleware.d.ts +1 -1
- package/dist/types/modelShared/prop.d.ts +5 -0
- package/dist/types/redux/connectReduxDevTools.d.ts +17 -4
- package/dist/types/ref/Ref.d.ts +1 -1
- package/dist/types/treeUtils/sandbox.d.ts +1 -1
- package/dist/types/types/TypeChecker.d.ts +1 -1
- package/dist/types/types/arrayBased/typesArray.d.ts +1 -1
- package/dist/types/types/arrayBased/typesTuple.d.ts +1 -1
- package/dist/types/types/objectBased/typesArraySet.d.ts +1 -1
- package/dist/types/types/objectBased/typesDataModelData.d.ts +1 -1
- package/dist/types/types/objectBased/typesModel.d.ts +1 -1
- package/dist/types/types/objectBased/typesObject.d.ts +3 -3
- package/dist/types/types/objectBased/typesObjectMap.d.ts +1 -1
- package/dist/types/types/objectBased/typesRecord.d.ts +1 -1
- package/dist/types/types/primitiveBased/typesPrimitive.d.ts +1 -1
- package/dist/types/types/types.d.ts +3 -3
- package/dist/types/types/utility/typesCodec.d.ts +1 -6
- package/dist/types/types/utility/typesCodecCore.d.ts +1 -1
- package/dist/types/types/utility/typesOr.d.ts +1 -1
- package/dist/types/types/utility/typesRefinement.d.ts +1 -1
- package/dist/types/types/utility/typesSkipCheck.d.ts +1 -1
- package/dist/types/types/utility/typesTag.d.ts +1 -1
- package/dist/types/wrappers/ObjectMap.d.ts +2 -0
- package/dist/types/wrappers/asMap.d.ts +10 -6
- package/package.json +14 -12
- package/src/action/applyAction.ts +125 -114
- package/src/action/applyMethodCall.ts +37 -37
- package/src/action/isModelAction.ts +16 -16
- package/src/action/middleware.ts +137 -137
- package/src/action/modelFlow.ts +240 -240
- package/src/action/modelFlowPromiseGenerator.ts +127 -125
- package/src/action/pendingActions.ts +42 -42
- package/src/action/wrapInAction.ts +156 -156
- package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +1 -1
- package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +172 -172
- package/src/actionMiddlewares/actionSerialization/arraySerializer.ts +20 -20
- package/src/actionMiddlewares/actionSerialization/dateSerializer.ts +17 -17
- package/src/actionMiddlewares/actionSerialization/mapSerializer.ts +42 -42
- package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +50 -50
- package/src/actionMiddlewares/actionSerialization/objectSnapshotSerializer.ts +21 -21
- package/src/actionMiddlewares/actionSerialization/plainObjectSerializer.ts +24 -32
- package/src/actionMiddlewares/actionSerialization/primitiveSerializer.ts +51 -51
- package/src/actionMiddlewares/actionSerialization/setSerializer.ts +37 -37
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +3 -3
- package/src/actionMiddlewares/onActionMiddleware.ts +2 -2
- package/src/actionMiddlewares/readonlyMiddleware.ts +2 -2
- package/src/actionMiddlewares/transactionMiddleware.ts +4 -4
- package/src/actionMiddlewares/undoMiddleware.ts +804 -796
- package/src/actionMiddlewares/utils.ts +2 -2
- package/src/computedTree/computedTree.ts +143 -143
- package/src/context/context.ts +1 -1
- package/src/dataModel/BaseDataModel.ts +194 -192
- package/src/dataModel/actions.ts +1 -1
- package/src/dataModel/newDataModel.ts +57 -57
- package/src/deepChange/index.ts +1 -1
- package/src/deepChange/onDeepChange.ts +244 -244
- package/src/frozen/Frozen.ts +146 -146
- package/src/globalConfig/globalConfig.ts +107 -107
- package/src/index.ts +24 -24
- package/src/model/BaseModel.ts +275 -273
- package/src/model/ModelConstructorOptions.ts +15 -15
- package/src/model/getModelMetadata.ts +51 -51
- package/src/model/index.ts +6 -6
- package/src/model/mixins.ts +288 -288
- package/src/model/newModel.ts +301 -301
- package/src/model/utils.ts +249 -249
- package/src/modelShared/modelDecorator.ts +260 -253
- package/src/modelShared/modelInfo.ts +50 -50
- package/src/modelShared/modelSymbols.ts +3 -3
- package/src/modelShared/newModel.ts +25 -25
- package/src/modelShared/prop.ts +713 -684
- package/src/modelShared/sharedInternalModel.ts +427 -417
- package/src/modelShared/utils.ts +24 -24
- package/src/parent/core.ts +65 -65
- package/src/parent/coreObjectChildren.ts +180 -180
- package/src/parent/detach.ts +47 -47
- package/src/parent/findParent.ts +1 -1
- package/src/parent/getChildrenObjects.ts +25 -25
- package/src/parent/path.ts +386 -381
- package/src/parent/setParent.ts +149 -149
- package/src/parent/walkTree.ts +1 -1
- package/src/patch/applyPatches.ts +187 -187
- package/src/patch/jsonPatch.ts +108 -108
- package/src/patch/patchRecorder.ts +6 -1
- package/src/redux/connectReduxDevTools.ts +39 -7
- package/src/redux/redux.ts +6 -2
- package/src/ref/Ref.ts +1 -1
- package/src/ref/core.ts +339 -345
- package/src/ref/customRef.ts +3 -3
- package/src/ref/rootRef.ts +100 -100
- package/src/rootStore/attachDetach.ts +89 -89
- package/src/rootStore/rootStore.ts +1 -1
- package/src/snapshot/SnapshotOf.ts +104 -104
- package/src/snapshot/SnapshotProcessingError.ts +45 -45
- package/src/snapshot/applySnapshot.ts +177 -181
- package/src/snapshot/cloneTreeValue.ts +30 -30
- package/src/snapshot/fromArraySnapshot.ts +27 -33
- package/src/snapshot/fromModelSnapshot.ts +70 -70
- package/src/snapshot/fromPlainObjectSnapshot.ts +47 -42
- package/src/snapshot/fromSnapshot.ts +198 -198
- package/src/snapshot/getSnapshot.ts +80 -79
- package/src/snapshot/index.ts +8 -8
- package/src/snapshot/internal.ts +230 -230
- package/src/snapshot/reconcileArraySnapshot.ts +70 -70
- package/src/snapshot/reconcileModelSnapshot.ts +155 -150
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +72 -72
- package/src/snapshot/reconcileSnapshot.ts +88 -88
- package/src/standardActions/actions.ts +64 -64
- package/src/standardActions/objectActions.ts +60 -60
- package/src/transforms/ImmutableDate.ts +93 -93
- package/src/transforms/asMap.ts +50 -50
- package/src/transforms/asSet.ts +22 -22
- package/src/transforms/bigint.ts +20 -20
- package/src/transforms/date.ts +40 -40
- package/src/treeUtils/deepEquals.ts +55 -55
- package/src/treeUtils/sandbox.ts +6 -3
- package/src/tweaker/TweakerPriority.ts +9 -9
- package/src/tweaker/tweak.ts +4 -3
- package/src/tweaker/tweakArray.ts +530 -475
- package/src/tweaker/tweakFrozen.ts +42 -42
- package/src/tweaker/tweakModel.ts +1 -1
- package/src/tweaker/tweakPlainObject.ts +355 -355
- package/src/tweaker/typeChecking.ts +101 -101
- package/src/types/SnapshotTypeMismatchError.ts +46 -46
- package/src/types/TypeCheckError.ts +183 -184
- package/src/types/TypeChecker.ts +202 -185
- package/src/types/arrayBased/typesArray.ts +136 -137
- package/src/types/arrayBased/typesTuple.ts +138 -139
- package/src/types/createPerEntryCachedCheck.ts +166 -160
- package/src/types/index.ts +6 -6
- package/src/types/objectBased/typesArraySet.ts +133 -134
- package/src/types/objectBased/typesDataModelData.ts +203 -204
- package/src/types/objectBased/typesModel.ts +220 -221
- package/src/types/objectBased/typesObject.ts +308 -310
- package/src/types/objectBased/typesObjectMap.ts +142 -143
- package/src/types/objectBased/typesRecord.ts +156 -157
- package/src/types/objectBased/typesRef.ts +89 -89
- package/src/types/primitiveBased/typesEnum.ts +63 -63
- package/src/types/primitiveBased/typesPrimitive.ts +219 -220
- package/src/types/registerDefaultStandardTypeResolvers.ts +21 -21
- package/src/types/resolveTypeChecker.ts +78 -78
- package/src/types/schemas.ts +208 -208
- package/src/types/tProp.ts +277 -268
- package/src/types/typeCheck.ts +21 -21
- package/src/types/typeCheckErrorUtils.ts +23 -23
- package/src/types/types.ts +142 -142
- package/src/types/utility/typeToStoredData.ts +37 -37
- package/src/types/utility/typesBigInt.ts +15 -15
- package/src/types/utility/typesCodec.ts +41 -38
- package/src/types/utility/typesCodecCore.ts +178 -178
- package/src/types/utility/typesCodecSupport.ts +806 -806
- package/src/types/utility/typesDate.ts +27 -27
- package/src/types/utility/typesMap.ts +253 -222
- package/src/types/utility/typesOr.ts +263 -259
- package/src/types/utility/typesRefinement.ts +131 -125
- package/src/types/utility/typesSet.ts +110 -110
- package/src/types/utility/typesSkipCheck.ts +69 -70
- package/src/types/utility/typesTag.ts +88 -82
- package/src/types/utility/typesUnchecked.ts +40 -40
- package/src/utils/AnyFunction.ts +4 -4
- package/src/utils/ModelPool.ts +59 -59
- package/src/utils/chainFns.ts +18 -18
- package/src/utils/decorators.ts +274 -274
- package/src/utils/errorDiagnostics.ts +204 -204
- package/src/utils/index.ts +443 -372
- package/src/wrappers/ArraySet.ts +156 -156
- package/src/wrappers/ObjectMap.ts +155 -136
- package/src/wrappers/asMap.ts +65 -30
- 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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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 {
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
+
}
|