mobx-keystone 2.1.0 → 2.2.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 +11 -0
- package/README.md +1 -1
- package/dist/mobx-keystone.esm.js +275 -489
- package/dist/mobx-keystone.esm.mjs +275 -489
- package/dist/mobx-keystone.umd.js +274 -492
- 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/index.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 +4 -2
- 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 +11 -5
- 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/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/objectBased/typesDataModelData.ts +7 -8
- package/src/types/objectBased/typesObject.ts +11 -15
- package/src/types/objectBased/typesRecord.ts +11 -15
- 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 +5 -0
- package/src/types/utility/typesCodecSupport.ts +3 -3
- package/src/types/utility/typesMap.ts +43 -51
- 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
|
@@ -68,6 +68,19 @@ export function typesTuple<T extends AnyType[]>(...itemTypes: T): ArrayType<T> {
|
|
|
68
68
|
// computeds cannot isolate tuple-item changes and only add allocation overhead.
|
|
69
69
|
const checkTupleItems = createWholeContainerCachedCheck(checkTupleItemsImperatively)
|
|
70
70
|
|
|
71
|
+
const processorPlan = snapshotProcessorPlan(
|
|
72
|
+
() => checkers,
|
|
73
|
+
(processors) =>
|
|
74
|
+
processors.some(Boolean)
|
|
75
|
+
? (array: unknown[]) => {
|
|
76
|
+
return array.map((item, i) => {
|
|
77
|
+
const processor = processors[i]
|
|
78
|
+
return processor ? withErrorPathSegment(i, () => processor(item)) : item
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
: undefined
|
|
82
|
+
)
|
|
83
|
+
|
|
71
84
|
const thisTc: TypeChecker = new TypeChecker(
|
|
72
85
|
TypeCheckerBaseType.Array,
|
|
73
86
|
|
|
@@ -102,31 +115,9 @@ export function typesTuple<T extends AnyType[]>(...itemTypes: T): ArrayType<T> {
|
|
|
102
115
|
return thisTc
|
|
103
116
|
},
|
|
104
117
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
processors.some(Boolean)
|
|
109
|
-
? (array: unknown[]) => {
|
|
110
|
-
return array.map((item, i) => {
|
|
111
|
-
const processor = processors[i]
|
|
112
|
-
return processor ? withErrorPathSegment(i, () => processor(item)) : item
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
: undefined
|
|
116
|
-
),
|
|
117
|
-
|
|
118
|
-
snapshotProcessorPlan(
|
|
119
|
-
() => checkers,
|
|
120
|
-
(processors) =>
|
|
121
|
-
processors.some(Boolean)
|
|
122
|
-
? (array: unknown[]) => {
|
|
123
|
-
return array.map((item, i) => {
|
|
124
|
-
const processor = processors[i]
|
|
125
|
-
return processor ? withErrorPathSegment(i, () => processor(item)) : item
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
: undefined
|
|
129
|
-
)
|
|
118
|
+
processorPlan,
|
|
119
|
+
|
|
120
|
+
processorPlan
|
|
130
121
|
)
|
|
131
122
|
|
|
132
123
|
return thisTc
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from "../tweaker/tweakedChangeListeners"
|
|
20
20
|
import { getMobxVersion } from "../utils"
|
|
21
21
|
import { ChunkedSequence, ChunkedSet, chunkSize, type SequenceChunk } from "../utils/chunks"
|
|
22
|
+
import { getOrCreate } from "../utils/mapUtils"
|
|
22
23
|
import { TypeCheckError } from "./TypeCheckError"
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -79,11 +80,7 @@ function checkUncached(
|
|
|
79
80
|
typeCheckedValue: any,
|
|
80
81
|
check: () => TypeCheckError | null
|
|
81
82
|
): TypeCheckError | null {
|
|
82
|
-
|
|
83
|
-
if (!results) {
|
|
84
|
-
results = new Map()
|
|
85
|
-
uncachedResults!.set(checker, results)
|
|
86
|
-
}
|
|
83
|
+
const results = getOrCreate(uncachedResults!, checker, () => new Map())
|
|
87
84
|
let error = results.get(value)
|
|
88
85
|
if (error === undefined) {
|
|
89
86
|
error = check()
|
|
@@ -152,11 +149,9 @@ export function createWholeContainerCachedCheck(
|
|
|
152
149
|
)
|
|
153
150
|
}
|
|
154
151
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
cache.set(value, cached)
|
|
159
|
-
}
|
|
152
|
+
const cached = getOrCreate(cache, value, () =>
|
|
153
|
+
computed(() => check(value, emptyPath, undefined), { keepAlive: true })
|
|
154
|
+
)
|
|
160
155
|
const error = cached.get()
|
|
161
156
|
return contextualizeCachedError(error, path, typeCheckedValue)
|
|
162
157
|
}
|
|
@@ -167,6 +162,10 @@ export function createWholeContainerCachedCheck(
|
|
|
167
162
|
// check new chunks twice.
|
|
168
163
|
const needsBatchToCacheChunks = getMobxVersion() < 6
|
|
169
164
|
|
|
165
|
+
function checkChunks<T>(fn: () => T): T {
|
|
166
|
+
return needsBatchToCacheChunks ? transaction(fn) : fn()
|
|
167
|
+
}
|
|
168
|
+
|
|
170
169
|
/**
|
|
171
170
|
* Checks the items of an array, starting at `firstIndex`, and returns the first
|
|
172
171
|
* error, or null.
|
|
@@ -328,14 +327,8 @@ class RecordChunks
|
|
|
328
327
|
readonly atom = createAtom("recordTypeCheckChunks")
|
|
329
328
|
private readonly record: object
|
|
330
329
|
private readonly checkKey: (key: string) => TypeCheckError | null
|
|
331
|
-
private readonly getEntry = (key: string): CachedEntry =>
|
|
332
|
-
|
|
333
|
-
if (!entry) {
|
|
334
|
-
entry = computed(() => this.checkKey(key))
|
|
335
|
-
this.entries.set(key, entry)
|
|
336
|
-
}
|
|
337
|
-
return entry
|
|
338
|
-
}
|
|
330
|
+
private readonly getEntry = (key: string): CachedEntry =>
|
|
331
|
+
getOrCreate(this.entries, key, () => computed(() => this.checkKey(key)))
|
|
339
332
|
|
|
340
333
|
constructor(record: object, checkKey: (key: string) => TypeCheckError | null) {
|
|
341
334
|
super()
|
|
@@ -458,10 +451,7 @@ export function createChunkedRecordCachedCheck(
|
|
|
458
451
|
const chunks = cached?.chunks
|
|
459
452
|
return checkUncached(cache, value, path, typeCheckedValue, () => {
|
|
460
453
|
if (chunks && typeof key === "string") {
|
|
461
|
-
|
|
462
|
-
? transaction(() => chunks.hasError(key))
|
|
463
|
-
: chunks.hasError(key)
|
|
464
|
-
if (!hasError) {
|
|
454
|
+
if (!checkChunks(() => chunks.hasError(key))) {
|
|
465
455
|
return null
|
|
466
456
|
}
|
|
467
457
|
}
|
|
@@ -475,11 +465,10 @@ export function createChunkedRecordCachedCheck(
|
|
|
475
465
|
addTweakedChangeListener<object>(value, chunks)
|
|
476
466
|
const check = computed(
|
|
477
467
|
() => {
|
|
478
|
-
const hasError = needsBatchToCacheChunks
|
|
479
|
-
? transaction(() => chunks.hasError())
|
|
480
|
-
: chunks.hasError()
|
|
481
468
|
// any added or removed key changes a chunk, so this runs again then
|
|
482
|
-
return
|
|
469
|
+
return checkChunks(() => chunks.hasError())
|
|
470
|
+
? checkAllEntries(value, emptyPath, undefined)
|
|
471
|
+
: null
|
|
483
472
|
},
|
|
484
473
|
{ keepAlive: true }
|
|
485
474
|
)
|
|
@@ -535,9 +524,7 @@ export function createChunkedArrayCachedCheck(
|
|
|
535
524
|
if (!chunks || typeof index !== "number") {
|
|
536
525
|
return checkItems(array, 0, emptyPath, undefined)
|
|
537
526
|
}
|
|
538
|
-
return
|
|
539
|
-
? transaction(() => chunks.check(index))
|
|
540
|
-
: chunks.check(index)
|
|
527
|
+
return checkChunks(() => chunks.check(index))
|
|
541
528
|
})
|
|
542
529
|
}
|
|
543
530
|
|
|
@@ -561,7 +548,7 @@ export function createChunkedArrayCachedCheck(
|
|
|
561
548
|
}
|
|
562
549
|
|
|
563
550
|
const chunks = state.chunks
|
|
564
|
-
return
|
|
551
|
+
return checkChunks(() => chunks.check())
|
|
565
552
|
},
|
|
566
553
|
{ keepAlive: true }
|
|
567
554
|
),
|
package/src/types/index.ts
CHANGED
|
@@ -90,6 +90,11 @@ export function typesDataModelData<M = never, K = M>(
|
|
|
90
90
|
|
|
91
91
|
const resolvedDataTypeChecker = resolveTypeChecker(standardDataType)
|
|
92
92
|
|
|
93
|
+
const processorPlan = snapshotProcessorPlan(
|
|
94
|
+
() => [resolvedDataTypeChecker],
|
|
95
|
+
([processor]) => processor
|
|
96
|
+
)
|
|
97
|
+
|
|
93
98
|
const thisTc: TypeChecker = new TypeChecker(
|
|
94
99
|
TypeCheckerBaseType.Object,
|
|
95
100
|
|
|
@@ -104,15 +109,9 @@ export function typesDataModelData<M = never, K = M>(
|
|
|
104
109
|
return resolvedDataTypeChecker.snapshotType(value) ? thisTc : null
|
|
105
110
|
},
|
|
106
111
|
|
|
107
|
-
|
|
108
|
-
() => [resolvedDataTypeChecker],
|
|
109
|
-
([processor]) => processor
|
|
110
|
-
),
|
|
112
|
+
processorPlan,
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
() => [resolvedDataTypeChecker],
|
|
114
|
-
([processor]) => processor
|
|
115
|
-
)
|
|
114
|
+
processorPlan
|
|
116
115
|
)
|
|
117
116
|
|
|
118
117
|
return thisTc
|
|
@@ -173,6 +173,14 @@ function typesObjectHelper<S>(objFn: S, frozen: boolean, typeInfoGen: TypeInfoGe
|
|
|
173
173
|
}
|
|
174
174
|
)
|
|
175
175
|
|
|
176
|
+
const processorPlan = snapshotProcessorPlan(
|
|
177
|
+
() => schemaEntries.map((entry) => entry.getResolvedChecker()),
|
|
178
|
+
(processors) =>
|
|
179
|
+
processors.some(Boolean)
|
|
180
|
+
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processors)
|
|
181
|
+
: undefined
|
|
182
|
+
)
|
|
183
|
+
|
|
176
184
|
const thisTc: TypeChecker = new TypeChecker(
|
|
177
185
|
TypeCheckerBaseType.Object,
|
|
178
186
|
|
|
@@ -208,21 +216,9 @@ function typesObjectHelper<S>(objFn: S, frozen: boolean, typeInfoGen: TypeInfoGe
|
|
|
208
216
|
return thisTc
|
|
209
217
|
},
|
|
210
218
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
processors.some(Boolean)
|
|
215
|
-
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processors)
|
|
216
|
-
: undefined
|
|
217
|
-
),
|
|
218
|
-
|
|
219
|
-
snapshotProcessorPlan(
|
|
220
|
-
() => schemaEntries.map((entry) => entry.getResolvedChecker()),
|
|
221
|
-
(processors) =>
|
|
222
|
-
processors.some(Boolean)
|
|
223
|
-
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processors)
|
|
224
|
-
: undefined
|
|
225
|
-
)
|
|
219
|
+
processorPlan,
|
|
220
|
+
|
|
221
|
+
processorPlan
|
|
226
222
|
)
|
|
227
223
|
|
|
228
224
|
return thisTc
|
|
@@ -83,6 +83,14 @@ export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
|
|
|
83
83
|
|
|
84
84
|
const checkRecordValues = createChunkedRecordCachedCheck(iterateRecordEntries, checkRecordEntry)
|
|
85
85
|
|
|
86
|
+
const processorPlan = snapshotProcessorPlan(
|
|
87
|
+
() => [valueChecker],
|
|
88
|
+
([processor]) =>
|
|
89
|
+
processor
|
|
90
|
+
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processor)
|
|
91
|
+
: undefined
|
|
92
|
+
)
|
|
93
|
+
|
|
86
94
|
const thisTc: TypeChecker = new TypeChecker(
|
|
87
95
|
TypeCheckerBaseType.Object,
|
|
88
96
|
|
|
@@ -126,21 +134,9 @@ export function typesRecord<T extends AnyType>(valueType: T): RecordType<T> {
|
|
|
126
134
|
return thisTc
|
|
127
135
|
},
|
|
128
136
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
processor
|
|
133
|
-
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processor)
|
|
134
|
-
: undefined
|
|
135
|
-
),
|
|
136
|
-
|
|
137
|
-
snapshotProcessorPlan(
|
|
138
|
-
() => [valueChecker],
|
|
139
|
-
([processor]) =>
|
|
140
|
-
processor
|
|
141
|
-
? (obj: Record<string, unknown>) => applySnapshotProcessor(obj, processor)
|
|
142
|
-
: undefined
|
|
143
|
-
)
|
|
137
|
+
processorPlan,
|
|
138
|
+
|
|
139
|
+
processorPlan
|
|
144
140
|
)
|
|
145
141
|
|
|
146
142
|
return thisTc
|
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>
|