mobx-keystone 2.1.0 → 2.3.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 +17 -0
- package/README.md +1 -1
- package/dist/mobx-keystone.esm.js +555 -516
- package/dist/mobx-keystone.esm.mjs +555 -516
- package/dist/mobx-keystone.umd.js +558 -519
- package/dist/types/actionMiddlewares/undoMiddleware.d.ts +2 -10
- package/dist/types/modelShared/modelDecorator.d.ts +5 -2
- package/dist/types/modelShared/prop.d.ts +42 -29
- package/dist/types/ref/Ref.d.ts +1 -4
- package/dist/types/snapshot/SnapshotOf.d.ts +4 -4
- package/dist/types/snapshot/applySnapshot.d.ts +1 -1
- package/dist/types/snapshot/fromSnapshot.d.ts +2 -2
- package/dist/types/snapshot/getSnapshot.d.ts +1 -1
- package/dist/types/types/SnapshotTypeMismatchError.d.ts +3 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/modelTypeMatching.d.ts +1 -0
- package/dist/types/types/schemas.d.ts +41 -37
- package/dist/types/types/tProp.d.ts +12 -6
- package/dist/types/types/types.d.ts +6 -6
- package/dist/types/types/utility/typeToStoredData.d.ts +14 -10
- package/dist/types/types/utility/typesCodecCore.d.ts +3 -0
- package/dist/types/utils/ModelPool.d.ts +0 -1
- package/dist/types/utils/types.d.ts +6 -0
- package/dist/types/wrappers/ArraySet.d.ts +1 -0
- package/package.json +13 -11
- package/src/action/modelFlow.ts +35 -66
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +41 -71
- package/src/actionMiddlewares/transactionMiddleware.ts +1 -1
- package/src/actionMiddlewares/undoMiddleware.ts +16 -22
- package/src/context/context.ts +15 -36
- package/src/dataModel/utils.ts +5 -28
- package/src/deepChange/onDeepChange.ts +44 -126
- package/src/model/BaseModel.ts +1 -1
- package/src/model/utils.ts +5 -10
- package/src/modelShared/modelDecorator.ts +13 -10
- package/src/modelShared/modelInfo.ts +75 -0
- package/src/modelShared/prop.ts +115 -111
- package/src/modelShared/sharedInternalModel.ts +2 -2
- package/src/parent/arrayPaths.ts +1 -4
- package/src/parent/path.ts +0 -10
- package/src/patch/patchRecorder.ts +13 -28
- package/src/ref/core.ts +6 -19
- package/src/rootStore/rootStore.ts +1 -3
- package/src/snapshot/SnapshotOf.ts +24 -48
- package/src/snapshot/applySnapshot.ts +1 -1
- package/src/snapshot/fromSnapshot.ts +10 -3
- package/src/snapshot/getSnapshot.ts +1 -1
- package/src/snapshot/internal.ts +0 -2
- package/src/snapshot/reconcileModelSnapshot.ts +5 -3
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +3 -1
- package/src/treeUtils/draft.ts +6 -1
- package/src/treeUtils/sandbox.ts +10 -7
- package/src/tweaker/tweakArray.ts +20 -50
- package/src/tweaker/tweakPlainObject.ts +9 -15
- package/src/types/SnapshotTypeMismatchError.ts +3 -1
- package/src/types/arrayBased/typesArray.ts +13 -19
- package/src/types/arrayBased/typesTuple.ts +16 -25
- package/src/types/createCachedTypeCheck.ts +17 -30
- package/src/types/index.ts +1 -0
- package/src/types/modelTypeMatching.ts +276 -0
- package/src/types/objectBased/typesDataModelData.ts +7 -8
- package/src/types/objectBased/typesModel.ts +23 -6
- package/src/types/objectBased/typesObject.ts +11 -15
- package/src/types/objectBased/typesRecord.ts +11 -15
- package/src/types/objectBased/typesRef.ts +23 -4
- package/src/types/schemas.ts +59 -71
- package/src/types/tProp.ts +29 -29
- package/src/types/utility/typeToStoredData.ts +22 -21
- package/src/types/utility/typesCodecCore.ts +8 -1
- package/src/types/utility/typesCodecSupport.ts +16 -10
- package/src/types/utility/typesMap.ts +43 -51
- package/src/types/utility/typesOr.ts +38 -8
- package/src/types/utility/typesRefinement.ts +7 -8
- package/src/types/utility/typesSkipCheck.ts +7 -8
- package/src/types/utility/typesTag.ts +7 -8
- package/src/utils/ModelPool.ts +1 -18
- package/src/utils/decorators.ts +5 -5
- package/src/utils/index.ts +1 -20
- package/src/utils/types.ts +5 -0
- package/src/wrappers/ArraySet.ts +27 -14
- package/src/wrappers/ObjectMap.ts +1 -6
- package/src/wrappers/asMap.ts +1 -21
- package/src/wrappers/asSet.ts +0 -8
package/src/types/schemas.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import type { O } from "ts-toolbelt"
|
|
2
1
|
import type { AnyDataModel } from "../dataModel/BaseDataModel"
|
|
3
2
|
import type { AnyModel } from "../model/BaseModel"
|
|
4
3
|
import type { ModelClass } from "../modelShared/BaseModelShared"
|
|
5
4
|
import type { SnapshotInOf, SnapshotOutOf } from "../snapshot/SnapshotOf"
|
|
6
|
-
import type { IsOptionalValue } from "../utils/types"
|
|
5
|
+
import type { IsOptionalValue, SimplifyObject } from "../utils/types"
|
|
7
6
|
|
|
8
7
|
// type schemas
|
|
9
8
|
|
|
10
|
-
// infer is there just to cache type generation
|
|
11
|
-
|
|
12
9
|
export interface Type<Name, Data> {
|
|
13
10
|
/** @ignore */
|
|
14
11
|
$$type: Name
|
|
@@ -38,21 +35,21 @@ export interface CodecType<
|
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
type ArrayData<S extends readonly unknown[]> = number extends S["length"]
|
|
41
|
-
? Array<TypeToData<S[number]
|
|
38
|
+
? Array<TypeToData<S[number]>>
|
|
42
39
|
: {
|
|
43
|
-
[k in keyof S]: TypeToData<S[k]>
|
|
40
|
+
[k in keyof S]: TypeToData<S[k]>
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
type ArraySnapshotInData<S extends readonly unknown[]> = number extends S["length"]
|
|
47
|
-
? Array<TypeToSnapshotIn<S[number]
|
|
44
|
+
? Array<TypeToSnapshotIn<S[number]>>
|
|
48
45
|
: {
|
|
49
|
-
[k in keyof S]: TypeToSnapshotIn<S[k]>
|
|
46
|
+
[k in keyof S]: TypeToSnapshotIn<S[k]>
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
type ArraySnapshotOutData<S extends readonly unknown[]> = number extends S["length"]
|
|
53
|
-
? Array<TypeToSnapshotOut<S[number]
|
|
50
|
+
? Array<TypeToSnapshotOut<S[number]>>
|
|
54
51
|
: {
|
|
55
|
-
[k in keyof S]: TypeToSnapshotOut<S[k]>
|
|
52
|
+
[k in keyof S]: TypeToSnapshotOut<S[k]>
|
|
56
53
|
}
|
|
57
54
|
|
|
58
55
|
export interface ArrayType<S extends readonly unknown[]> extends Type<"array", ArrayData<S>> {}
|
|
@@ -74,37 +71,28 @@ export type UndefinablePropsNames<T> = {
|
|
|
74
71
|
* Computes the optional keys for an object type schema.
|
|
75
72
|
* @ignore
|
|
76
73
|
*/
|
|
77
|
-
export type ObjectOptionalKeys<S> =
|
|
78
|
-
[
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
type ObjectData<S
|
|
82
|
-
{ [k in keyof S]: TypeToData<S[k]>
|
|
83
|
-
|
|
74
|
+
export type ObjectOptionalKeys<S> = {
|
|
75
|
+
[K in keyof S]: IsOptionalValue<TypeToDataOpt<S[K]>, K, never>
|
|
76
|
+
}[keyof S]
|
|
77
|
+
|
|
78
|
+
type ObjectData<S, OK = ObjectOptionalKeys<S>> = SimplifyObject<
|
|
79
|
+
{ [k in keyof S as k extends OK ? never : k]: TypeToData<S[k]> } & {
|
|
80
|
+
[k in keyof S as k extends OK ? k : never]?: TypeToData<S[k]>
|
|
81
|
+
}
|
|
84
82
|
>
|
|
85
83
|
|
|
86
|
-
type ObjectSnapshotInData<S
|
|
87
|
-
{ [k in keyof S]: TypeToSnapshotIn<S[k]>
|
|
88
|
-
|
|
84
|
+
type ObjectSnapshotInData<S, OK = ObjectOptionalKeys<S>> = SimplifyObject<
|
|
85
|
+
{ [k in keyof S as k extends OK ? never : k]: TypeToSnapshotIn<S[k]> } & {
|
|
86
|
+
[k in keyof S as k extends OK ? k : never]?: TypeToSnapshotIn<S[k]>
|
|
87
|
+
}
|
|
89
88
|
>
|
|
90
89
|
|
|
91
|
-
type ObjectSnapshotOutData<S
|
|
92
|
-
{ [k in keyof S]: TypeToSnapshotOut<S[k]>
|
|
93
|
-
|
|
90
|
+
type ObjectSnapshotOutData<S, OK = ObjectOptionalKeys<S>> = SimplifyObject<
|
|
91
|
+
{ [k in keyof S as k extends OK ? never : k]: TypeToSnapshotOut<S[k]> } & {
|
|
92
|
+
[k in keyof S as k extends OK ? k : never]?: TypeToSnapshotOut<S[k]>
|
|
93
|
+
}
|
|
94
94
|
>
|
|
95
95
|
|
|
96
|
-
type RecordData<S> = {
|
|
97
|
-
[k: string]: TypeToData<S> extends infer R ? R : never
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
type RecordSnapshotInData<S> = {
|
|
101
|
-
[k: string]: TypeToSnapshotIn<S> extends infer D ? D : never
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
type RecordSnapshotOutData<S> = {
|
|
105
|
-
[k: string]: TypeToSnapshotOut<S> extends infer D ? D : never
|
|
106
|
-
}
|
|
107
|
-
|
|
108
96
|
export interface ObjectType<S> extends Type<"object", ObjectData<S>> {}
|
|
109
97
|
|
|
110
98
|
export interface ObjectTypeFunction {
|
|
@@ -112,7 +100,9 @@ export interface ObjectTypeFunction {
|
|
|
112
100
|
(): ObjectOfTypes
|
|
113
101
|
}
|
|
114
102
|
|
|
115
|
-
|
|
103
|
+
// the record data types are written inline (instead of through an alias) so they are displayed as
|
|
104
|
+
// plain index signatures (e.g. `{ [k: string]: number }`)
|
|
105
|
+
export interface RecordType<S> extends Type<"record", { [k: string]: TypeToData<S> }> {}
|
|
116
106
|
|
|
117
107
|
export type AnyStandardType =
|
|
118
108
|
| IdentityType<any>
|
|
@@ -162,47 +152,45 @@ type TypeToSnapshotLeaf<S, Dir extends "in" | "out"> =
|
|
|
162
152
|
? Dir extends "in"
|
|
163
153
|
? SnapshotInOf<M>
|
|
164
154
|
: SnapshotOutOf<M>
|
|
165
|
-
: S
|
|
166
|
-
? D
|
|
167
|
-
: ConstructorToSnapshotData<S>
|
|
155
|
+
: ConstructorToSnapshotData<S>
|
|
168
156
|
|
|
169
157
|
export type TypeToData<S> = S extends ObjectTypeFunction
|
|
170
|
-
? ObjectType<ReturnType<S>>["$$data"]
|
|
171
|
-
? R
|
|
172
|
-
: never
|
|
158
|
+
? ObjectType<ReturnType<S>>["$$data"]
|
|
173
159
|
: TypeToDataLeaf<S>
|
|
174
160
|
|
|
161
|
+
// standard types are dispatched through their `$$type` discriminant (and codec / identity types
|
|
162
|
+
// through indexed accesses), which is cheaper than checking them against each type interface
|
|
175
163
|
export type TypeToSnapshotIn<S> = S extends ObjectTypeFunction
|
|
176
|
-
? ObjectSnapshotInData<ReturnType<S>>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
164
|
+
? ObjectSnapshotInData<ReturnType<S>>
|
|
165
|
+
: S extends { $$type: infer K }
|
|
166
|
+
? K extends "codec"
|
|
167
|
+
? S["$$snapshotIn" & keyof S]
|
|
168
|
+
: S extends ArrayType<infer A>
|
|
169
|
+
? ArraySnapshotInData<A>
|
|
170
|
+
: S extends ObjectType<infer O>
|
|
171
|
+
? ObjectSnapshotInData<O>
|
|
172
|
+
: S extends RecordType<infer R>
|
|
173
|
+
? { [k: string]: TypeToSnapshotIn<R> }
|
|
174
|
+
: S extends ModelType<infer M>
|
|
175
|
+
? SnapshotInOf<M>
|
|
176
|
+
: S["$$data" & keyof S]
|
|
177
|
+
: TypeToSnapshotLeaf<S, "in">
|
|
190
178
|
|
|
191
179
|
export type TypeToSnapshotOut<S> = S extends ObjectTypeFunction
|
|
192
|
-
? ObjectSnapshotOutData<ReturnType<S>>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
180
|
+
? ObjectSnapshotOutData<ReturnType<S>>
|
|
181
|
+
: S extends { $$type: infer K }
|
|
182
|
+
? K extends "codec"
|
|
183
|
+
? S["$$snapshotOut" & keyof S]
|
|
184
|
+
: S extends ArrayType<infer A>
|
|
185
|
+
? ArraySnapshotOutData<A>
|
|
186
|
+
: S extends ObjectType<infer O>
|
|
187
|
+
? ObjectSnapshotOutData<O>
|
|
188
|
+
: S extends RecordType<infer R>
|
|
189
|
+
? { [k: string]: TypeToSnapshotOut<R> }
|
|
190
|
+
: S extends ModelType<infer M>
|
|
191
|
+
? SnapshotOutOf<M>
|
|
192
|
+
: S["$$data" & keyof S]
|
|
193
|
+
: TypeToSnapshotLeaf<S, "out">
|
|
206
194
|
|
|
207
195
|
/** @ignore */
|
|
208
|
-
export type TypeToDataOpt<S> = S extends { $$data:
|
|
196
|
+
export type TypeToDataOpt<S> = S extends { $$data: unknown } ? S["$$data"] & undefined : never
|
package/src/types/tProp.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
toFullModelPropTransform,
|
|
7
7
|
} from "../modelShared/prop"
|
|
8
8
|
import { lazy } from "../utils"
|
|
9
|
+
import { getOrCreate } from "../utils/mapUtils"
|
|
9
10
|
import {
|
|
10
11
|
typesBoolean,
|
|
11
12
|
typesNull,
|
|
@@ -24,26 +25,16 @@ const noDefaultValueSymbol = Symbol("noDefaultValue")
|
|
|
24
25
|
|
|
25
26
|
const tPropCache = new WeakMap<AnyStandardType, Map<unknown, AnyModelProp>>()
|
|
26
27
|
|
|
27
|
-
function
|
|
28
|
+
function createSnapshotProcessorGetter(
|
|
28
29
|
getType: () => AnyStandardType,
|
|
29
|
-
eagerType: AnyStandardType | undefined
|
|
30
|
+
eagerType: AnyStandardType | undefined,
|
|
31
|
+
getProcessor: (typeChecker: TypeChecker) => SnapshotProcessor | undefined
|
|
30
32
|
): (() => SnapshotProcessor | undefined) | undefined {
|
|
31
33
|
if (eagerType instanceof TypeChecker) {
|
|
32
|
-
const processor = eagerType
|
|
34
|
+
const processor = getProcessor(eagerType)
|
|
33
35
|
return processor ? () => processor : undefined
|
|
34
36
|
}
|
|
35
|
-
return lazy(() => resolveTypeChecker(getType())
|
|
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())
|
|
37
|
+
return lazy(() => getProcessor(resolveTypeChecker(getType())))
|
|
47
38
|
}
|
|
48
39
|
|
|
49
40
|
type AnyTypeOrArray = AnyType | ReadonlyArray<AnyType>
|
|
@@ -53,12 +44,22 @@ type StoredRequiredPropMetadata<TType extends AnyType> = {
|
|
|
53
44
|
$storedCreationValueType: TypeToStoredData<TType>
|
|
54
45
|
}
|
|
55
46
|
|
|
56
|
-
|
|
47
|
+
// exported (and publicly re-exported) so emitted declaration files can reference it by name
|
|
48
|
+
// instead of expanding it inline in every exported model class, which is much slower and larger
|
|
49
|
+
/**
|
|
50
|
+
* A model property created by `tProp` without a default value.
|
|
51
|
+
*/
|
|
52
|
+
export type TypedMaybeOptionalModelProp<TType extends AnyType> = MaybeOptionalModelProp<
|
|
57
53
|
TypeToData<TType>
|
|
58
54
|
> &
|
|
59
55
|
StoredRequiredPropMetadata<TType>
|
|
60
56
|
|
|
61
|
-
|
|
57
|
+
// exported (and publicly re-exported) so emitted declaration files can reference it by name
|
|
58
|
+
// instead of expanding it inline in every exported model class, which is much slower and larger
|
|
59
|
+
/**
|
|
60
|
+
* A model property created by `tProp` with a default value.
|
|
61
|
+
*/
|
|
62
|
+
export type TypedOptionalModelProp<TType extends AnyType> = OptionalModelProp<TypeToData<TType>> & {
|
|
62
63
|
$storedValueType: TypeToStoredData<TType>
|
|
63
64
|
$storedCreationValueType: TypeToStoredData<TType> | null | undefined
|
|
64
65
|
$typedFromSnapshotOverride: TypeToSnapshotIn<TType> | null | undefined
|
|
@@ -124,7 +125,7 @@ export function tProp(defaultValue: boolean): TypedOptionalModelProp<typeof type
|
|
|
124
125
|
*/
|
|
125
126
|
export function tProp<TType extends AnyType>(
|
|
126
127
|
type: TType,
|
|
127
|
-
defaultFn: () => TypeToData<TType
|
|
128
|
+
defaultFn: () => NoInfer<TypeToData<TType>>
|
|
128
129
|
): TypedOptionalModelProp<TType>
|
|
129
130
|
|
|
130
131
|
/**
|
|
@@ -145,7 +146,7 @@ export function tProp<TType extends AnyType>(
|
|
|
145
146
|
*/
|
|
146
147
|
export function tProp<TType extends ReadonlyArray<AnyType>>(
|
|
147
148
|
type: TType,
|
|
148
|
-
defaultFn: () => TypeToData<TType[number]
|
|
149
|
+
defaultFn: () => NoInfer<TypeToData<TType[number]>>
|
|
149
150
|
): TypedOptionalModelProp<TType[number]>
|
|
150
151
|
|
|
151
152
|
/**
|
|
@@ -167,7 +168,7 @@ export function tProp<TType extends ReadonlyArray<AnyType>>(
|
|
|
167
168
|
*/
|
|
168
169
|
export function tProp<TType extends AnyType>(
|
|
169
170
|
type: TType,
|
|
170
|
-
defaultValue: TypeToData<TType
|
|
171
|
+
defaultValue: NoInfer<TypeToData<TType>>
|
|
171
172
|
): TypedOptionalModelProp<TType>
|
|
172
173
|
|
|
173
174
|
/**
|
|
@@ -188,7 +189,7 @@ export function tProp<TType extends AnyType>(
|
|
|
188
189
|
*/
|
|
189
190
|
export function tProp<TType extends ReadonlyArray<AnyType>>(
|
|
190
191
|
type: TType,
|
|
191
|
-
defaultValue: TypeToData<TType[number]
|
|
192
|
+
defaultValue: NoInfer<TypeToData<TType[number]>>
|
|
192
193
|
): TypedOptionalModelProp<TType[number]>
|
|
193
194
|
|
|
194
195
|
/**
|
|
@@ -250,11 +251,7 @@ export function tProp(
|
|
|
250
251
|
const typeChecker = resolveStandardType(resolvedType)
|
|
251
252
|
const defKey = hasDefaultValue ? def : noDefaultValueSymbol
|
|
252
253
|
|
|
253
|
-
|
|
254
|
-
if (!defValueCache) {
|
|
255
|
-
defValueCache = new Map()
|
|
256
|
-
tPropCache.set(typeChecker, defValueCache)
|
|
257
|
-
}
|
|
254
|
+
const defValueCache = getOrCreate(tPropCache, typeChecker, () => new Map())
|
|
258
255
|
|
|
259
256
|
const cachedProp = defValueCache.get(defKey)
|
|
260
257
|
if (cachedProp) {
|
|
@@ -301,11 +298,14 @@ export function tProp(
|
|
|
301
298
|
? toFullModelPropTransform(createCodecPropTransform(typeChecker))
|
|
302
299
|
: undefined
|
|
303
300
|
),
|
|
304
|
-
_getFromSnapshotProcessor:
|
|
301
|
+
_getFromSnapshotProcessor: createSnapshotProcessorGetter(
|
|
305
302
|
getFromSnapshotType,
|
|
306
|
-
eagerFromSnapshotType
|
|
303
|
+
eagerFromSnapshotType,
|
|
304
|
+
(tc) => tc.getFromSnapshotProcessor()
|
|
305
|
+
),
|
|
306
|
+
_getToSnapshotProcessor: createSnapshotProcessorGetter(getStoredType, eagerStoredType, (tc) =>
|
|
307
|
+
tc.getToSnapshotProcessor()
|
|
307
308
|
),
|
|
308
|
-
_getToSnapshotProcessor: createToSnapshotProcessorGetter(getStoredType, eagerStoredType),
|
|
309
309
|
} satisfies Partial<AnyModelProp>)
|
|
310
310
|
|
|
311
311
|
defValueCache.set(defKey, newProp)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SimplifyObject } from "../../utils/types"
|
|
2
2
|
import type {
|
|
3
3
|
ArrayType,
|
|
4
|
-
CodecType,
|
|
5
4
|
ObjectOptionalKeys,
|
|
6
5
|
ObjectType,
|
|
7
6
|
ObjectTypeFunction,
|
|
@@ -10,28 +9,30 @@ import type {
|
|
|
10
9
|
} from "../schemas"
|
|
11
10
|
|
|
12
11
|
type ArrayStoredData<S extends readonly unknown[]> = number extends S["length"]
|
|
13
|
-
? Array<TypeToStoredData<S[number]
|
|
12
|
+
? Array<TypeToStoredData<S[number]>>
|
|
14
13
|
: {
|
|
15
|
-
[k in keyof S]: TypeToStoredData<S[k]>
|
|
14
|
+
[k in keyof S]: TypeToStoredData<S[k]>
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
type ObjectStoredData<S
|
|
19
|
-
{ [k in keyof S]: TypeToStoredData<S[k]>
|
|
20
|
-
|
|
17
|
+
type ObjectStoredData<S, OK = ObjectOptionalKeys<S>> = SimplifyObject<
|
|
18
|
+
{ [k in keyof S as k extends OK ? never : k]: TypeToStoredData<S[k]> } & {
|
|
19
|
+
[k in keyof S as k extends OK ? k : never]?: TypeToStoredData<S[k]>
|
|
20
|
+
}
|
|
21
21
|
>
|
|
22
22
|
|
|
23
|
+
// standard types are dispatched through their `$$type` discriminant (see TypeToSnapshotIn)
|
|
23
24
|
export type TypeToStoredData<S> = S extends ObjectTypeFunction
|
|
24
|
-
? ObjectStoredData<ReturnType<S>>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
? ObjectStoredData<ReturnType<S>>
|
|
26
|
+
: S extends { $$type: infer K }
|
|
27
|
+
? K extends "codec"
|
|
28
|
+
? S["$$storedData" & keyof S]
|
|
29
|
+
: S extends ArrayType<infer A>
|
|
30
|
+
? ArrayStoredData<A>
|
|
31
|
+
: S extends ObjectType<infer O>
|
|
32
|
+
? ObjectStoredData<O>
|
|
33
|
+
: S extends RecordType<infer R>
|
|
34
|
+
? {
|
|
35
|
+
[k: string]: TypeToStoredData<R>
|
|
36
|
+
}
|
|
37
|
+
: TypeToData<S>
|
|
38
|
+
: TypeToData<S>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ModelPropTransform } from "../../modelShared/prop"
|
|
2
2
|
import { lazy } from "../../utils"
|
|
3
3
|
import { getTypeInfo } from "../getTypeInfo"
|
|
4
|
+
import { runInModelTypeMatchingPass } from "../modelTypeMatching"
|
|
4
5
|
import { resolveStandardType, resolveTypeChecker } from "../resolveTypeChecker"
|
|
5
6
|
import type {
|
|
6
7
|
AnyStandardType,
|
|
@@ -45,6 +46,11 @@ type CodecConfig<TEncodedType extends AnyType, TRuntime> = {
|
|
|
45
46
|
is(value: unknown): value is TRuntime
|
|
46
47
|
} & ModelPropTransform<TypeToData<TEncodedType>, TRuntime>
|
|
47
48
|
|
|
49
|
+
// exported (and publicly re-exported) so emitted declaration files can reference it by name
|
|
50
|
+
// instead of expanding it inline in every exported model class, which is much slower and larger
|
|
51
|
+
/**
|
|
52
|
+
* A codec type whose snapshot and stored forms are those of its encoded type.
|
|
53
|
+
*/
|
|
48
54
|
export type CodecFromEncoded<TEncodedType extends AnyType, TRuntime> = CodecType<
|
|
49
55
|
TRuntime,
|
|
50
56
|
TypeToSnapshotIn<TEncodedType>,
|
|
@@ -140,7 +146,8 @@ export function createCodecType<TEncodedType extends AnyType, TRuntime>(
|
|
|
140
146
|
() => typeName,
|
|
141
147
|
typeInfoGen,
|
|
142
148
|
|
|
143
|
-
|
|
149
|
+
// user code, so it must not see the model type matching pass of an outer union
|
|
150
|
+
(value) => (runInModelTypeMatchingPass("none", is, value, undefined) ? thisTc : null),
|
|
144
151
|
|
|
145
152
|
(snapshot) => {
|
|
146
153
|
const processedSnapshot = encodedTypeChecker.fromSnapshotProcessor(snapshot)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isObservableArray, isObservableObject, remove } from "mobx"
|
|
2
2
|
import type { ModelPropTransform } from "../../modelShared/prop"
|
|
3
|
-
import { copyOwnEnumerableProps, isArray, isObject, lazy } from "../../utils"
|
|
3
|
+
import { copyOwnEnumerableProps, hasOwnProp, isArray, isObject, lazy } from "../../utils"
|
|
4
4
|
import { setIfDifferent } from "../../utils/setIfDifferent"
|
|
5
5
|
import { ArrayTypeInfo, typesArray } from "../arrayBased/typesArray"
|
|
6
6
|
import { TupleTypeInfo, typesTuple } from "../arrayBased/typesTuple"
|
|
7
7
|
import { getTypeInfo } from "../getTypeInfo"
|
|
8
|
+
import { findClosestModelTypeMatch, findFirstMatch } from "../modelTypeMatching"
|
|
8
9
|
import { isDataModelDataStandardType } from "../objectBased/typesDataModelData"
|
|
9
10
|
import { isModelStandardType } from "../objectBased/typesModel"
|
|
10
11
|
import { ObjectTypeInfo, typesObject } from "../objectBased/typesObject"
|
|
@@ -136,7 +137,7 @@ function createObjectRuntimeAdapter(
|
|
|
136
137
|
get(target, prop, receiver) {
|
|
137
138
|
if (typeof prop === "string") {
|
|
138
139
|
const childSupport = getChildSupports()[prop]
|
|
139
|
-
if (childSupport &&
|
|
140
|
+
if (childSupport && hasOwnProp(target, prop)) {
|
|
140
141
|
return childSupport.adapter.toRuntime(target[prop], (newStoredValue) => {
|
|
141
142
|
target[prop] = newStoredValue
|
|
142
143
|
})
|
|
@@ -200,7 +201,7 @@ function createRecordRuntimeAdapter(
|
|
|
200
201
|
|
|
201
202
|
const proxy = new Proxy(stored, {
|
|
202
203
|
get(target, prop, receiver) {
|
|
203
|
-
if (typeof prop === "string" &&
|
|
204
|
+
if (typeof prop === "string" && hasOwnProp(target, prop)) {
|
|
204
205
|
const valueSupport = getValueSupport()
|
|
205
206
|
return valueSupport.adapter.toRuntime(target[prop], (newStoredValue) => {
|
|
206
207
|
target[prop] = newStoredValue
|
|
@@ -577,6 +578,13 @@ function createCodecLeafRuntimeAdapter(
|
|
|
577
578
|
}
|
|
578
579
|
}
|
|
579
580
|
|
|
581
|
+
function matchCodecSupport(
|
|
582
|
+
support: ResolvedCodecSupport,
|
|
583
|
+
value: unknown
|
|
584
|
+
): ResolvedCodecSupport | undefined {
|
|
585
|
+
return resolveTypeChecker(support.storedType).snapshotType(value) ? support : undefined
|
|
586
|
+
}
|
|
587
|
+
|
|
580
588
|
function createOrRuntimeAdapter(
|
|
581
589
|
childTypes: ReadonlyArray<AnyStandardType>,
|
|
582
590
|
getChildSupports: () => ReadonlyArray<ResolvedCodecSupport>,
|
|
@@ -607,14 +615,12 @@ function createOrRuntimeAdapter(
|
|
|
607
615
|
}
|
|
608
616
|
|
|
609
617
|
const supports = getChildSupports()
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
}
|
|
618
|
+
// prefer branches whose (possibly nested) models are the closest to the snapshot ones
|
|
619
|
+
const matchingSupport = isObject(value)
|
|
620
|
+
? findClosestModelTypeMatch(supports, matchCodecSupport, value)
|
|
621
|
+
: findFirstMatch(supports, matchCodecSupport, value)
|
|
616
622
|
|
|
617
|
-
return supports[0]
|
|
623
|
+
return matchingSupport ?? supports[0]
|
|
618
624
|
}
|
|
619
625
|
|
|
620
626
|
return {
|
|
@@ -41,18 +41,14 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
41
41
|
return getValue(storedKey)
|
|
42
42
|
}
|
|
43
43
|
case "getOrInsert":
|
|
44
|
-
return (key: TKeyRuntime, defaultValue: TValueRuntime) => {
|
|
45
|
-
const storedKey = keyAdapter.toStored(key)
|
|
46
|
-
if (!target.has(storedKey)) {
|
|
47
|
-
target.set(storedKey, valueAdapter.toStored(defaultValue))
|
|
48
|
-
}
|
|
49
|
-
return getValue(storedKey)
|
|
50
|
-
}
|
|
51
44
|
case "getOrInsertComputed":
|
|
52
|
-
return (key: TKeyRuntime,
|
|
45
|
+
return (key: TKeyRuntime, valueOrCallback: unknown) => {
|
|
53
46
|
const storedKey = keyAdapter.toStored(key)
|
|
54
47
|
if (!target.has(storedKey)) {
|
|
55
|
-
const value =
|
|
48
|
+
const value =
|
|
49
|
+
prop === "getOrInsert"
|
|
50
|
+
? (valueOrCallback as TValueRuntime)
|
|
51
|
+
: (valueOrCallback as (key: TKeyRuntime) => TValueRuntime)(key)
|
|
56
52
|
target.set(storedKey, valueAdapter.toStored(value))
|
|
57
53
|
}
|
|
58
54
|
return getValue(storedKey)
|
|
@@ -114,10 +110,18 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
114
110
|
}) as unknown as Map<TKeyRuntime, TValueRuntime>
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
function makeMapTransform<
|
|
114
|
+
TStored extends object,
|
|
115
|
+
TKeyStored,
|
|
116
|
+
TKeyRuntime,
|
|
117
|
+
TValueStored,
|
|
118
|
+
TValueRuntime,
|
|
119
|
+
>(
|
|
120
|
+
keyAdapter: RuntimeAdapter<TKeyStored, TKeyRuntime>,
|
|
121
|
+
valueAdapter: RuntimeAdapter<TValueStored, TValueRuntime>,
|
|
122
|
+
toStored: (runtimeMap: Map<TKeyRuntime, TValueRuntime>) => TStored
|
|
123
|
+
): ModelPropTransform<TStored, Map<TKeyRuntime, TValueRuntime>> {
|
|
124
|
+
const storedByRuntime = new WeakMap<Map<TKeyRuntime, TValueRuntime>, TStored>()
|
|
121
125
|
|
|
122
126
|
return {
|
|
123
127
|
transform({ originalValue, cachedTransformedValue }) {
|
|
@@ -125,63 +129,51 @@ function makeObjectBackedMapTransform<TStoredValue, TRuntimeValue>(
|
|
|
125
129
|
return cachedTransformedValue
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
const runtimeMap = makeMapProxy(
|
|
132
|
+
const runtimeMap = makeMapProxy(
|
|
133
|
+
asMap(originalValue as any) as Map<TKeyStored, TValueStored>,
|
|
134
|
+
keyAdapter,
|
|
135
|
+
valueAdapter
|
|
136
|
+
)
|
|
129
137
|
|
|
130
138
|
storedByRuntime.set(runtimeMap, originalValue)
|
|
131
139
|
return runtimeMap
|
|
132
140
|
},
|
|
133
141
|
|
|
134
142
|
untransform({ transformedValue }) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
return storedByRuntime.get(transformedValue) ?? toStored(transformedValue)
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
}
|
|
139
147
|
|
|
148
|
+
function makeObjectBackedMapTransform<TStoredValue, TRuntimeValue>(
|
|
149
|
+
valueAdapter: RuntimeAdapter<TStoredValue, TRuntimeValue>
|
|
150
|
+
): ModelPropTransform<Record<string, TStoredValue>, Map<string, TRuntimeValue>> {
|
|
151
|
+
return makeMapTransform(
|
|
152
|
+
identityRuntimeAdapter as RuntimeAdapter<string, string>,
|
|
153
|
+
valueAdapter,
|
|
154
|
+
(runtimeMap) => {
|
|
140
155
|
const result: Record<string, TStoredValue> = {}
|
|
141
|
-
|
|
156
|
+
runtimeMap.forEach((value, key) => {
|
|
142
157
|
const storedValue = valueAdapter.toStored(value)
|
|
143
158
|
if (key === "__proto__") setProtoProp(result, storedValue)
|
|
144
159
|
else result[key] = storedValue
|
|
145
160
|
})
|
|
146
161
|
return result
|
|
147
|
-
}
|
|
148
|
-
|
|
162
|
+
}
|
|
163
|
+
)
|
|
149
164
|
}
|
|
150
165
|
|
|
151
166
|
function makeArrayBackedMapTransform<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
152
167
|
keyAdapter: RuntimeAdapter<TKeyStored, TKeyRuntime>,
|
|
153
168
|
valueAdapter: RuntimeAdapter<TValueStored, TValueRuntime>
|
|
154
169
|
): ModelPropTransform<Array<[TKeyStored, TValueStored]>, Map<TKeyRuntime, TValueRuntime>> {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (cachedTransformedValue) {
|
|
163
|
-
return cachedTransformedValue
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const runtimeMap = makeMapProxy(asMap(originalValue), keyAdapter, valueAdapter)
|
|
167
|
-
|
|
168
|
-
storedByRuntime.set(runtimeMap, originalValue)
|
|
169
|
-
return runtimeMap
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
untransform({ transformedValue }) {
|
|
173
|
-
const cachedStored = storedByRuntime.get(transformedValue)
|
|
174
|
-
if (cachedStored) {
|
|
175
|
-
return cachedStored
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const result: Array<[TKeyStored, TValueStored]> = []
|
|
179
|
-
transformedValue.forEach((value, key) => {
|
|
180
|
-
result.push([keyAdapter.toStored(key), valueAdapter.toStored(value)])
|
|
181
|
-
})
|
|
182
|
-
return result
|
|
183
|
-
},
|
|
184
|
-
}
|
|
170
|
+
return makeMapTransform(keyAdapter, valueAdapter, (runtimeMap) => {
|
|
171
|
+
const result: Array<[TKeyStored, TValueStored]> = []
|
|
172
|
+
runtimeMap.forEach((value, key) => {
|
|
173
|
+
result.push([keyAdapter.toStored(key), valueAdapter.toStored(value)])
|
|
174
|
+
})
|
|
175
|
+
return result
|
|
176
|
+
})
|
|
185
177
|
}
|
|
186
178
|
|
|
187
179
|
export function typesMapFromObject<TValueType extends AnyType>(
|