mobx-keystone 1.22.0 → 1.24.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 +12 -0
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/dist/mobx-keystone.esm.js +7198 -6242
- package/dist/mobx-keystone.esm.mjs +7198 -6242
- package/dist/mobx-keystone.umd.js +7217 -6243
- package/dist/types/action/runUnprotected.d.ts +8 -4
- package/dist/types/model/Model.d.ts +5 -0
- package/dist/types/modelShared/modelDecorator.d.ts +1 -1
- package/dist/types/modelShared/prop.d.ts +8 -4
- package/dist/types/snapshot/modelInitialData.d.ts +1 -0
- package/dist/types/tweaker/treeNodeMetadata.d.ts +1 -0
- package/dist/types/types/createCachedTypeCheck.d.ts +1 -0
- package/dist/types/utils/index.d.ts +24 -0
- package/package.json +15 -11
- package/src/action/middleware.ts +5 -18
- package/src/action/mutationBatch.ts +72 -0
- package/src/action/runUnprotected.ts +21 -8
- package/src/action/wrapInAction.ts +45 -15
- package/src/actionMiddlewares/undoMiddleware.ts +19 -13
- package/src/dataModel/BaseDataModel.ts +4 -8
- package/src/deepChange/onDeepChange.ts +246 -16
- package/src/model/BaseModel.ts +4 -12
- package/src/model/Model.ts +5 -0
- package/src/model/newModel.ts +68 -36
- package/src/modelShared/modelDecorator.ts +64 -53
- package/src/modelShared/prop.ts +105 -63
- package/src/modelShared/sharedInternalModel.ts +91 -60
- package/src/parent/core.ts +16 -10
- package/src/parent/coreObjectChildren.ts +219 -21
- package/src/parent/path.ts +6 -5
- package/src/parent/setParent.ts +5 -5
- package/src/patch/emitPatch.ts +102 -20
- package/src/ref/Ref.ts +4 -5
- package/src/ref/core.ts +2 -2
- package/src/snapshot/fromArraySnapshot.ts +11 -2
- package/src/snapshot/fromModelSnapshot.ts +10 -3
- package/src/snapshot/fromPlainObjectSnapshot.ts +18 -7
- package/src/snapshot/fromSnapshot.ts +31 -9
- package/src/snapshot/getSnapshot.ts +8 -3
- package/src/snapshot/internal.ts +243 -82
- package/src/snapshot/modelInitialData.ts +41 -0
- package/src/snapshot/reconcileArraySnapshot.ts +9 -3
- package/src/snapshot/reconcileModelSnapshot.ts +97 -17
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +9 -3
- package/src/treeUtils/draft.ts +7 -8
- package/src/tweaker/core.ts +30 -5
- package/src/tweaker/treeNodeMetadata.ts +38 -0
- package/src/tweaker/tweak.ts +15 -4
- package/src/tweaker/tweakArray.ts +159 -121
- package/src/tweaker/tweakFrozen.ts +2 -2
- package/src/tweaker/tweakModel.ts +2 -2
- package/src/tweaker/tweakPlainObject.ts +117 -124
- package/src/tweaker/typeChecking.ts +10 -1
- package/src/types/TypeChecker.ts +261 -15
- package/src/types/arrayBased/typesArray.ts +38 -40
- package/src/types/arrayBased/typesTuple.ts +51 -34
- package/src/types/createCachedTypeCheck.ts +181 -0
- package/src/types/objectBased/typesArraySet.ts +42 -32
- package/src/types/objectBased/typesDataModelData.ts +18 -11
- package/src/types/objectBased/typesModel.ts +1 -1
- package/src/types/objectBased/typesObject.ts +57 -28
- package/src/types/objectBased/typesObjectMap.ts +51 -40
- package/src/types/objectBased/typesRecord.ts +59 -39
- package/src/types/objectBased/typesRef.ts +1 -1
- package/src/types/primitiveBased/typesPrimitive.ts +9 -9
- package/src/types/tProp.ts +80 -44
- package/src/types/utility/typesOr.ts +35 -24
- package/src/types/utility/typesRefinement.ts +21 -8
- package/src/types/utility/typesSkipCheck.ts +21 -8
- package/src/types/utility/typesTag.ts +21 -9
- package/src/types/utility/typesUnchecked.ts +2 -3
- package/src/utils/ModelPool.ts +34 -19
- package/src/utils/errorDiagnostics.ts +60 -18
- package/src/utils/index.ts +142 -9
- package/src/types/createPerEntryCachedCheck.ts +0 -166
- /package/dist/types/{types/createPerEntryCachedCheck.d.ts → action/mutationBatch.d.ts} +0 -0
|
@@ -2,13 +2,14 @@ import { isObservableObject, keys } from "mobx"
|
|
|
2
2
|
import type { Path } from "../../parent/pathTypes"
|
|
3
3
|
import { failure, isObject } from "../../utils"
|
|
4
4
|
import { withErrorPathSegment } from "../../utils/errorDiagnostics"
|
|
5
|
-
import {
|
|
5
|
+
import { createAdaptiveRecordCachedCheck } from "../createCachedTypeCheck"
|
|
6
6
|
import { getTypeInfo } from "../getTypeInfo"
|
|
7
7
|
import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
|
|
8
8
|
import type { AnyStandardType, AnyType, RecordType } from "../schemas"
|
|
9
9
|
import { TypeCheckError } from "../TypeCheckError"
|
|
10
10
|
import {
|
|
11
11
|
lateTypeChecker,
|
|
12
|
+
snapshotProcessorPlan,
|
|
12
13
|
TypeChecker,
|
|
13
14
|
TypeCheckerBaseType,
|
|
14
15
|
TypeInfo,
|
|
@@ -30,16 +31,19 @@ import { prependPathElementToTypeCheckError } from "../typeCheckErrorUtils"
|
|
|
30
31
|
* @returns
|
|
31
32
|
*/
|
|
32
33
|
export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const valueChecker = resolveTypeChecker(
|
|
34
|
+
const resolvedValueType = resolveStandardType(valueType)
|
|
35
|
+
const typeInfoGen: TypeInfoGen = (tc) => new RecordTypeInfo(tc, resolvedValueType)
|
|
36
|
+
const typeChecker = lateTypeChecker(() => {
|
|
37
|
+
const valueChecker = resolveTypeChecker(resolvedValueType)
|
|
37
38
|
const emptyChildPath: Path = []
|
|
38
39
|
|
|
39
40
|
const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) =>
|
|
40
41
|
`Record<${valueChecker.getTypeName(...recursiveTypeCheckers, valueChecker)}>`
|
|
41
42
|
|
|
42
|
-
const applySnapshotProcessor = (
|
|
43
|
+
const applySnapshotProcessor = (
|
|
44
|
+
obj: Record<string, unknown>,
|
|
45
|
+
processor: (snapshot: any) => unknown
|
|
46
|
+
) => {
|
|
43
47
|
if (valueChecker.unchecked) {
|
|
44
48
|
return obj
|
|
45
49
|
}
|
|
@@ -49,37 +53,44 @@ export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
|
|
|
49
53
|
const keys = Object.keys(obj)
|
|
50
54
|
for (let i = 0; i < keys.length; i++) {
|
|
51
55
|
const k = keys[i]
|
|
52
|
-
const v = withErrorPathSegment(k, () =>
|
|
53
|
-
mode === "from"
|
|
54
|
-
? valueChecker.fromSnapshotProcessor(obj[k])
|
|
55
|
-
: valueChecker.toSnapshotProcessor(obj[k])
|
|
56
|
-
)
|
|
56
|
+
const v = withErrorPathSegment(k, () => processor(obj[k]))
|
|
57
57
|
newObj[k] = v
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
return newObj
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
63
|
+
const iterateRecordEntries = (
|
|
64
|
+
obj: Record<string, unknown>,
|
|
65
|
+
checkEntry: (key: PropertyKey) => TypeCheckError | null
|
|
66
|
+
): TypeCheckError | null => {
|
|
67
|
+
// Use keys() from MobX for observable objects to track key additions/removals
|
|
68
|
+
// in MobX 4 (which lacks Proxy). Object.keys() doesn't establish MobX tracking
|
|
69
|
+
// in MobX 4, so the aggregation computed would miss newly added keys.
|
|
70
|
+
const objKeys = isObservableObject(obj) ? keys(obj) : Object.keys(obj)
|
|
71
|
+
for (let i = 0; i < objKeys.length; i++) {
|
|
72
|
+
const error = checkEntry(objKeys[i])
|
|
73
|
+
if (error) return error
|
|
74
|
+
}
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const checkRecordEntry = (
|
|
79
|
+
obj: Record<string, unknown>,
|
|
80
|
+
key: PropertyKey,
|
|
81
|
+
path: Path,
|
|
82
|
+
typeCheckedValue: any
|
|
83
|
+
): TypeCheckError | null => {
|
|
84
|
+
if (typeof key !== "string") {
|
|
85
|
+
throw failure(`record type keys must be strings, got ${typeof key}`)
|
|
86
|
+
}
|
|
87
|
+
const error = valueChecker.check(obj[key], emptyChildPath, typeCheckedValue)
|
|
88
|
+
return error ? prependPathElementToTypeCheckError(error, path, key, typeCheckedValue) : null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const checkRecordValues = createAdaptiveRecordCachedCheck(
|
|
92
|
+
iterateRecordEntries,
|
|
93
|
+
checkRecordEntry
|
|
83
94
|
)
|
|
84
95
|
|
|
85
96
|
const thisTc: TypeChecker = new TypeChecker(
|
|
@@ -125,17 +136,26 @@ export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
|
|
|
125
136
|
return thisTc
|
|
126
137
|
},
|
|
127
138
|
|
|
128
|
-
(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
snapshotProcessorPlan(
|
|
140
|
+
() => [valueChecker],
|
|
141
|
+
([processor]) =>
|
|
142
|
+
processor
|
|
143
|
+
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processor)
|
|
144
|
+
: undefined
|
|
145
|
+
),
|
|
146
|
+
|
|
147
|
+
snapshotProcessorPlan(
|
|
148
|
+
() => [valueChecker],
|
|
149
|
+
([processor]) =>
|
|
150
|
+
processor
|
|
151
|
+
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processor)
|
|
152
|
+
: undefined
|
|
153
|
+
)
|
|
135
154
|
)
|
|
136
155
|
|
|
137
156
|
return thisTc
|
|
138
|
-
}, typeInfoGen)
|
|
157
|
+
}, typeInfoGen)
|
|
158
|
+
return typeChecker as any
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertIsPrimitive
|
|
1
|
+
import { assertIsPrimitive } from "../../utils"
|
|
2
2
|
import type { PrimitiveValue } from "../../utils/types"
|
|
3
3
|
import { registerStandardTypeResolver, type StandardTypeResolverFn } from "../resolveTypeChecker"
|
|
4
4
|
import type { AnyStandardType, IdentityType } from "../schemas"
|
|
@@ -54,8 +54,8 @@ export function typesLiteral<T extends PrimitiveValue>(literal: T): IdentityType
|
|
|
54
54
|
typeInfoGen,
|
|
55
55
|
|
|
56
56
|
(value) => (value === literal ? thisTc : null),
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
undefined,
|
|
58
|
+
undefined
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
return thisTc as any
|
|
@@ -122,8 +122,8 @@ export const typesBoolean: IdentityType<boolean> = new TypeChecker(
|
|
|
122
122
|
(t) => new BooleanTypeInfo(t),
|
|
123
123
|
|
|
124
124
|
(value) => (typeof value === "boolean" ? (typesBoolean as any) : null),
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
undefined,
|
|
126
|
+
undefined
|
|
127
127
|
) as any
|
|
128
128
|
|
|
129
129
|
standardTypeResolvers.push((v) => (v === Boolean ? typesBoolean : undefined))
|
|
@@ -159,8 +159,8 @@ export const typesNumber: IdentityType<number> = new TypeChecker(
|
|
|
159
159
|
(t) => new NumberTypeInfo(t),
|
|
160
160
|
|
|
161
161
|
(value) => (typeof value === "number" ? (typesNumber as any) : null),
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
undefined,
|
|
163
|
+
undefined
|
|
164
164
|
) as any
|
|
165
165
|
|
|
166
166
|
standardTypeResolvers.push((v) => (v === Number ? typesNumber : undefined))
|
|
@@ -196,8 +196,8 @@ export const typesString: IdentityType<string> = new TypeChecker(
|
|
|
196
196
|
(t) => new StringTypeInfo(t),
|
|
197
197
|
|
|
198
198
|
(value) => (typeof value === "string" ? (typesString as any) : null),
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
undefined,
|
|
200
|
+
undefined
|
|
201
201
|
) as any
|
|
202
202
|
|
|
203
203
|
standardTypeResolvers.push((v) => (v === String ? typesString : undefined))
|
package/src/types/tProp.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type MaybeOptionalModelProp,
|
|
4
4
|
type OptionalModelProp,
|
|
5
5
|
prop,
|
|
6
|
+
toFullModelPropTransform,
|
|
6
7
|
} from "../modelShared/prop"
|
|
7
8
|
import { lazy } from "../utils"
|
|
8
9
|
import {
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
} from "./primitiveBased/typesPrimitive"
|
|
15
16
|
import { resolveStandardType, resolveTypeChecker } from "./resolveTypeChecker"
|
|
16
17
|
import type { AnyStandardType, AnyType, TypeToData, TypeToSnapshotIn } from "./schemas"
|
|
18
|
+
import { type SnapshotProcessor, TypeChecker } from "./TypeChecker"
|
|
17
19
|
import { createCodecPropTransform, resolveCodecSupport } from "./utility/typesCodec"
|
|
18
20
|
import { typesOr } from "./utility/typesOr"
|
|
19
21
|
import type { TypeToStoredData } from "./utility/typeToStoredData"
|
|
@@ -22,6 +24,28 @@ const noDefaultValueSymbol = Symbol("noDefaultValue")
|
|
|
22
24
|
|
|
23
25
|
const tPropCache = new WeakMap<AnyStandardType, Map<unknown, AnyModelProp>>()
|
|
24
26
|
|
|
27
|
+
function createFromSnapshotProcessorGetter(
|
|
28
|
+
getType: () => AnyStandardType,
|
|
29
|
+
eagerType: AnyStandardType | undefined
|
|
30
|
+
): (() => SnapshotProcessor | undefined) | undefined {
|
|
31
|
+
if (eagerType instanceof TypeChecker) {
|
|
32
|
+
const processor = eagerType.getFromSnapshotProcessor()
|
|
33
|
+
return processor ? () => processor : undefined
|
|
34
|
+
}
|
|
35
|
+
return lazy(() => resolveTypeChecker(getType()).getFromSnapshotProcessor())
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createToSnapshotProcessorGetter(
|
|
39
|
+
getType: () => AnyStandardType,
|
|
40
|
+
eagerType: AnyStandardType | undefined
|
|
41
|
+
): (() => SnapshotProcessor | undefined) | undefined {
|
|
42
|
+
if (eagerType instanceof TypeChecker) {
|
|
43
|
+
const processor = eagerType.getToSnapshotProcessor()
|
|
44
|
+
return processor ? () => processor : undefined
|
|
45
|
+
}
|
|
46
|
+
return lazy(() => resolveTypeChecker(getType()).getToSnapshotProcessor())
|
|
47
|
+
}
|
|
48
|
+
|
|
25
49
|
type AnyTypeOrArray = AnyType | ReadonlyArray<AnyType>
|
|
26
50
|
|
|
27
51
|
type StoredRequiredPropMetadata<TType extends AnyType> = {
|
|
@@ -40,26 +64,6 @@ type TypedOptionalModelProp<TType extends AnyType> = OptionalModelProp<TypeToDat
|
|
|
40
64
|
$typedFromSnapshotOverride: TypeToSnapshotIn<TType> | null | undefined
|
|
41
65
|
}
|
|
42
66
|
|
|
43
|
-
function getOrCreateTProp(
|
|
44
|
-
type: AnyStandardType,
|
|
45
|
-
defKey: unknown,
|
|
46
|
-
createTProp: () => AnyModelProp
|
|
47
|
-
): AnyModelProp {
|
|
48
|
-
let defValueCache = tPropCache.get(type)
|
|
49
|
-
if (!defValueCache) {
|
|
50
|
-
defValueCache = new Map()
|
|
51
|
-
tPropCache.set(type, defValueCache)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let prop = defValueCache.get(defKey)
|
|
55
|
-
if (!prop) {
|
|
56
|
-
prop = createTProp()
|
|
57
|
-
defValueCache.set(defKey, prop)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return prop
|
|
61
|
-
}
|
|
62
|
-
|
|
63
67
|
/**
|
|
64
68
|
* Defines a string model property with a default value.
|
|
65
69
|
* Equivalent to `tProp(types.string, defaultValue)`.
|
|
@@ -244,34 +248,66 @@ export function tProp(
|
|
|
244
248
|
: (typeOrArray as AnyType)
|
|
245
249
|
|
|
246
250
|
const typeChecker = resolveStandardType(resolvedType)
|
|
247
|
-
const
|
|
251
|
+
const defKey = hasDefaultValue ? def : noDefaultValueSymbol
|
|
248
252
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
() => resolveTypeChecker(fromSnapshotTypeChecker).fromSnapshotProcessor
|
|
255
|
-
)
|
|
256
|
-
const getToSnapshotProcessor = lazy(
|
|
257
|
-
() => resolveTypeChecker(codecSupport.storedType).toSnapshotProcessor
|
|
258
|
-
)
|
|
253
|
+
let defValueCache = tPropCache.get(typeChecker)
|
|
254
|
+
if (!defValueCache) {
|
|
255
|
+
defValueCache = new Map()
|
|
256
|
+
tPropCache.set(typeChecker, defValueCache)
|
|
257
|
+
}
|
|
259
258
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
: Object.create(baseProp)
|
|
259
|
+
const cachedProp = defValueCache.get(defKey)
|
|
260
|
+
if (cachedProp) {
|
|
261
|
+
return cachedProp
|
|
262
|
+
}
|
|
265
263
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
const eagerCodecSupport =
|
|
265
|
+
typeChecker instanceof TypeChecker ? resolveCodecSupport(typeChecker) : undefined
|
|
266
|
+
const getCodecSupport = eagerCodecSupport
|
|
267
|
+
? () => eagerCodecSupport
|
|
268
|
+
: lazy(() => resolveCodecSupport(typeChecker))
|
|
269
|
+
const eagerStoredType = eagerCodecSupport?.storedType
|
|
270
|
+
const getStoredType = eagerStoredType
|
|
271
|
+
? () => eagerStoredType
|
|
272
|
+
: lazy(() => getCodecSupport().storedType)
|
|
273
|
+
const eagerFromSnapshotType = eagerStoredType
|
|
274
|
+
? hasDefaultValue
|
|
275
|
+
? typesOr(eagerStoredType, typesUndefined, typesNull)
|
|
276
|
+
: eagerStoredType
|
|
277
|
+
: undefined
|
|
278
|
+
const getFromSnapshotType = eagerFromSnapshotType
|
|
279
|
+
? () => eagerFromSnapshotType
|
|
280
|
+
: lazy(() => {
|
|
281
|
+
const storedType = getStoredType()
|
|
282
|
+
return hasDefaultValue ? typesOr(storedType, typesUndefined, typesNull) : storedType
|
|
283
|
+
})
|
|
269
284
|
|
|
270
|
-
|
|
285
|
+
// we use Object.create to avoid messing up with the prop cache
|
|
286
|
+
const baseProp = hasDefaultValue ? prop(def) : prop()
|
|
287
|
+
const newProp = eagerCodecSupport?.hasCodec
|
|
288
|
+
? baseProp.withTransform(createCodecPropTransform(typeChecker))
|
|
289
|
+
: Object.create(baseProp)
|
|
271
290
|
|
|
272
|
-
|
|
273
|
-
|
|
291
|
+
Object.assign(newProp, {
|
|
292
|
+
_defaultValueIsTransformed: eagerCodecSupport?.hasCodec ?? false,
|
|
293
|
+
_getDefaultValueIsTransformed: eagerCodecSupport
|
|
294
|
+
? undefined
|
|
295
|
+
: lazy(() => getCodecSupport().hasCodec),
|
|
296
|
+
_typeChecker: typeChecker,
|
|
297
|
+
_getTransform: eagerCodecSupport
|
|
298
|
+
? undefined
|
|
299
|
+
: lazy(() =>
|
|
300
|
+
getCodecSupport().hasCodec
|
|
301
|
+
? toFullModelPropTransform(createCodecPropTransform(typeChecker))
|
|
302
|
+
: undefined
|
|
303
|
+
),
|
|
304
|
+
_getFromSnapshotProcessor: createFromSnapshotProcessorGetter(
|
|
305
|
+
getFromSnapshotType,
|
|
306
|
+
eagerFromSnapshotType
|
|
307
|
+
),
|
|
308
|
+
_getToSnapshotProcessor: createToSnapshotProcessorGetter(getStoredType, eagerStoredType),
|
|
309
|
+
} satisfies Partial<AnyModelProp>)
|
|
274
310
|
|
|
275
|
-
|
|
276
|
-
|
|
311
|
+
defValueCache.set(defKey, newProp)
|
|
312
|
+
return newProp
|
|
277
313
|
}
|
|
@@ -11,6 +11,7 @@ import { TypeCheckError } from "../TypeCheckError"
|
|
|
11
11
|
import {
|
|
12
12
|
getTypeCheckerBaseTypeFromValue,
|
|
13
13
|
lateTypeChecker,
|
|
14
|
+
snapshotProcessorPlan,
|
|
14
15
|
TypeChecker,
|
|
15
16
|
TypeCheckerBaseType,
|
|
16
17
|
TypeInfo,
|
|
@@ -74,11 +75,11 @@ export function typesOr(
|
|
|
74
75
|
const originalDispatcher = firstTypeChecker
|
|
75
76
|
? undefined
|
|
76
77
|
: (dispatcherOrType as (sn: any) => AnyType)
|
|
77
|
-
const
|
|
78
|
-
|
|
78
|
+
const resolvedOrTypes = orTypes.map(resolveStandardType)
|
|
79
|
+
const typeInfoGen: TypeInfoGen = (t) => new OrTypeInfo(t, resolvedOrTypes, originalDispatcher)
|
|
79
80
|
|
|
80
81
|
return lateTypeChecker(() => {
|
|
81
|
-
const checkers =
|
|
82
|
+
const checkers = resolvedOrTypes.map(resolveTypeChecker)
|
|
82
83
|
|
|
83
84
|
// if the or includes unchecked then it is unchecked
|
|
84
85
|
if (checkers.some((tc) => tc.unchecked)) {
|
|
@@ -207,29 +208,39 @@ export function typesOr(
|
|
|
207
208
|
return null
|
|
208
209
|
},
|
|
209
210
|
|
|
210
|
-
(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
},
|
|
211
|
+
snapshotProcessorPlan(
|
|
212
|
+
() => checkers,
|
|
213
|
+
() => (sn) => {
|
|
214
|
+
const type = finalDispatcher ? finalDispatcher(sn) : thisTc.snapshotType(sn)
|
|
215
|
+
if (!type) {
|
|
216
|
+
throw new SnapshotTypeMismatchError({
|
|
217
|
+
expectedTypeName: getTypeName(thisTc),
|
|
218
|
+
actualValue: sn,
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
222
|
+
const processor = type.getFromSnapshotProcessor()
|
|
223
|
+
return processor ? processor(sn) : sn
|
|
224
|
+
},
|
|
225
|
+
true
|
|
226
|
+
),
|
|
227
|
+
|
|
228
|
+
snapshotProcessorPlan(
|
|
229
|
+
() => checkers,
|
|
230
|
+
() => (sn) => {
|
|
231
|
+
const type = finalDispatcher ? finalDispatcher(sn) : thisTc.snapshotType(sn)
|
|
232
|
+
if (!type) {
|
|
233
|
+
throw new SnapshotTypeMismatchError({
|
|
234
|
+
expectedTypeName: getTypeName(thisTc),
|
|
235
|
+
actualValue: sn,
|
|
236
|
+
})
|
|
237
|
+
}
|
|
230
238
|
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
const processor = type.getToSnapshotProcessor()
|
|
240
|
+
return processor ? processor(sn) : sn
|
|
241
|
+
},
|
|
242
|
+
true
|
|
243
|
+
)
|
|
233
244
|
)
|
|
234
245
|
|
|
235
246
|
return thisTc
|
|
@@ -2,7 +2,13 @@ import { getTypeInfo } from "../getTypeInfo"
|
|
|
2
2
|
import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
|
|
3
3
|
import type { AnyStandardType, AnyType, TypeToData } from "../schemas"
|
|
4
4
|
import { TypeCheckError } from "../TypeCheckError"
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
lateTypeChecker,
|
|
7
|
+
snapshotProcessorPlan,
|
|
8
|
+
TypeChecker,
|
|
9
|
+
TypeInfo,
|
|
10
|
+
type TypeInfoGen,
|
|
11
|
+
} from "../TypeChecker"
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
14
|
* A refinement over a given type. This allows you to do extra checks
|
|
@@ -44,11 +50,11 @@ export function typesRefinement<T extends AnyType>(
|
|
|
44
50
|
checkFn: (data: TypeToData<T>) => TypeCheckError | null | boolean,
|
|
45
51
|
typeName?: string
|
|
46
52
|
): T {
|
|
53
|
+
const resolvedBaseType = resolveStandardType(baseType)
|
|
47
54
|
const typeInfoGen: TypeInfoGen = (t) =>
|
|
48
|
-
new RefinementTypeInfo(t,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const baseChecker = resolveTypeChecker(baseType)
|
|
55
|
+
new RefinementTypeInfo(t, resolvedBaseType, checkFn, typeName)
|
|
56
|
+
const typeChecker = lateTypeChecker(() => {
|
|
57
|
+
const baseChecker = resolveTypeChecker(resolvedBaseType)
|
|
52
58
|
|
|
53
59
|
const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
|
|
54
60
|
const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
|
|
@@ -96,12 +102,19 @@ export function typesRefinement<T extends AnyType>(
|
|
|
96
102
|
// we cannot check refinement here since it checks data instances, not snapshots
|
|
97
103
|
(sn) => baseChecker.snapshotType(sn),
|
|
98
104
|
|
|
99
|
-
(
|
|
100
|
-
|
|
105
|
+
snapshotProcessorPlan(
|
|
106
|
+
() => [baseChecker],
|
|
107
|
+
([processor]) => processor
|
|
108
|
+
),
|
|
109
|
+
snapshotProcessorPlan(
|
|
110
|
+
() => [baseChecker],
|
|
111
|
+
([processor]) => processor
|
|
112
|
+
)
|
|
101
113
|
)
|
|
102
114
|
|
|
103
115
|
return thisTc
|
|
104
|
-
}, typeInfoGen)
|
|
116
|
+
}, typeInfoGen)
|
|
117
|
+
return typeChecker as any
|
|
105
118
|
}
|
|
106
119
|
|
|
107
120
|
/**
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { getTypeInfo } from "../getTypeInfo"
|
|
2
2
|
import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
|
|
3
3
|
import type { AnyStandardType, AnyType } from "../schemas"
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
lateTypeChecker,
|
|
6
|
+
snapshotProcessorPlan,
|
|
7
|
+
TypeChecker,
|
|
8
|
+
TypeInfo,
|
|
9
|
+
type TypeInfoGen,
|
|
10
|
+
} from "../TypeChecker"
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* A type that wraps another type but skips runtime validation.
|
|
@@ -26,10 +32,10 @@ import { lateTypeChecker, TypeChecker, TypeInfo, type TypeInfoGen } from "../Typ
|
|
|
26
32
|
* @returns A type with the same runtime/snapshot behavior but no validation.
|
|
27
33
|
*/
|
|
28
34
|
export function typesSkipCheck<T extends AnyType>(baseType: T): T {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const baseChecker = resolveTypeChecker(
|
|
35
|
+
const resolvedBaseType = resolveStandardType(baseType)
|
|
36
|
+
const typeInfoGen: TypeInfoGen = (t) => new SkipCheckTypeInfo(t, resolvedBaseType)
|
|
37
|
+
const typeChecker = lateTypeChecker(() => {
|
|
38
|
+
const baseChecker = resolveTypeChecker(resolvedBaseType)
|
|
33
39
|
|
|
34
40
|
const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
|
|
35
41
|
const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
|
|
@@ -42,13 +48,20 @@ export function typesSkipCheck<T extends AnyType>(baseType: T): T {
|
|
|
42
48
|
getTypeName,
|
|
43
49
|
typeInfoGen,
|
|
44
50
|
(sn) => baseChecker.snapshotType(sn),
|
|
45
|
-
(
|
|
46
|
-
|
|
51
|
+
snapshotProcessorPlan(
|
|
52
|
+
() => [baseChecker],
|
|
53
|
+
([processor]) => processor
|
|
54
|
+
),
|
|
55
|
+
snapshotProcessorPlan(
|
|
56
|
+
() => [baseChecker],
|
|
57
|
+
([processor]) => processor
|
|
58
|
+
)
|
|
47
59
|
)
|
|
48
60
|
thisTc.skipCheck = true
|
|
49
61
|
|
|
50
62
|
return thisTc
|
|
51
|
-
}, typeInfoGen)
|
|
63
|
+
}, typeInfoGen)
|
|
64
|
+
return typeChecker as any
|
|
52
65
|
}
|
|
53
66
|
|
|
54
67
|
/**
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { getTypeInfo } from "../getTypeInfo"
|
|
2
2
|
import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
|
|
3
3
|
import type { AnyStandardType, AnyType } from "../schemas"
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
lateTypeChecker,
|
|
6
|
+
snapshotProcessorPlan,
|
|
7
|
+
TypeChecker,
|
|
8
|
+
TypeInfo,
|
|
9
|
+
type TypeInfoGen,
|
|
10
|
+
} from "../TypeChecker"
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Wrap a given type with tag information.
|
|
@@ -35,11 +41,10 @@ import { lateTypeChecker, TypeChecker, TypeInfo, type TypeInfoGen } from "../Typ
|
|
|
35
41
|
* @returns
|
|
36
42
|
*/
|
|
37
43
|
export function typesTag<T extends AnyType, A>(baseType: T, tag: A, typeName?: string): T {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const baseChecker = resolveTypeChecker(baseType)
|
|
44
|
+
const resolvedBaseType = resolveStandardType(baseType)
|
|
45
|
+
const typeInfoGen: TypeInfoGen = (t) => new TagTypeInfo(t, resolvedBaseType, tag, typeName)
|
|
46
|
+
const typeChecker = lateTypeChecker(() => {
|
|
47
|
+
const baseChecker = resolveTypeChecker(resolvedBaseType)
|
|
43
48
|
|
|
44
49
|
const getTypeName = (...recursiveTypeCheckers: TypeChecker[]) => {
|
|
45
50
|
const baseTypeName = baseChecker.getTypeName(...recursiveTypeCheckers, baseChecker)
|
|
@@ -53,12 +58,19 @@ export function typesTag<T extends AnyType, A>(baseType: T, tag: A, typeName?: s
|
|
|
53
58
|
getTypeName,
|
|
54
59
|
typeInfoGen,
|
|
55
60
|
(sn) => baseChecker.snapshotType(sn),
|
|
56
|
-
(
|
|
57
|
-
|
|
61
|
+
snapshotProcessorPlan(
|
|
62
|
+
() => [baseChecker],
|
|
63
|
+
([processor]) => processor
|
|
64
|
+
),
|
|
65
|
+
snapshotProcessorPlan(
|
|
66
|
+
() => [baseChecker],
|
|
67
|
+
([processor]) => processor
|
|
68
|
+
)
|
|
58
69
|
)
|
|
59
70
|
|
|
60
71
|
return thisTc
|
|
61
|
-
}, typeInfoGen)
|
|
72
|
+
}, typeInfoGen)
|
|
73
|
+
return typeChecker as any
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
/**
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { identityFn } from "../../utils"
|
|
2
1
|
import type { IdentityType } from "../schemas"
|
|
3
2
|
import { TypeChecker, TypeCheckerBaseType, TypeInfo } from "../TypeChecker"
|
|
4
3
|
|
|
@@ -10,8 +9,8 @@ const unchecked: IdentityType<any> = new TypeChecker(
|
|
|
10
9
|
|
|
11
10
|
() => unchecked as any,
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
undefined,
|
|
13
|
+
undefined
|
|
15
14
|
) as any
|
|
16
15
|
|
|
17
16
|
/**
|