mobx-keystone 1.22.0 → 1.23.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 +7 -0
- package/dist/mobx-keystone.esm.js +6702 -5797
- package/dist/mobx-keystone.esm.mjs +6702 -5797
- package/dist/mobx-keystone.umd.js +6718 -5798
- package/dist/types/action/runUnprotected.d.ts +8 -4
- package/dist/types/model/Model.d.ts +5 -0
- 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/package.json +11 -10
- 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/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/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/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/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 +114 -122
- 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 +9 -7
- package/src/types/createPerEntryCachedCheck.ts +0 -166
- /package/dist/types/{types/createPerEntryCachedCheck.d.ts → action/mutationBatch.d.ts} +0 -0
package/src/modelShared/prop.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SnapshotInOf, SnapshotOutOf } from "../snapshot/SnapshotOf"
|
|
2
2
|
import type { AnyStandardType } from "../types/schemas"
|
|
3
|
+
import { lazy } from "../utils"
|
|
3
4
|
import { runWithErrorDiagnosticsContext, withErrorPathSegment } from "../utils/errorDiagnostics"
|
|
4
5
|
import { getOrCreate } from "../utils/mapUtils"
|
|
5
6
|
import type { Flatten, IsNeverType, IsOptionalValue } from "../utils/types"
|
|
@@ -13,6 +14,17 @@ type SetterMode = boolean | "assign"
|
|
|
13
14
|
|
|
14
15
|
export type ModelPropSetterValueTransform<T> = (value: T) => T
|
|
15
16
|
|
|
17
|
+
/** @internal */
|
|
18
|
+
export interface FullModelPropTransform {
|
|
19
|
+
transform: (
|
|
20
|
+
original: unknown,
|
|
21
|
+
model: object,
|
|
22
|
+
propName: PropertyKey,
|
|
23
|
+
setOriginalValue: (newOriginalValue: unknown) => void
|
|
24
|
+
) => unknown
|
|
25
|
+
untransform: (transformed: unknown, model: object, propName: PropertyKey) => unknown
|
|
26
|
+
}
|
|
27
|
+
|
|
16
28
|
/**
|
|
17
29
|
* A model property.
|
|
18
30
|
*/
|
|
@@ -42,24 +54,18 @@ export interface ModelProp<
|
|
|
42
54
|
// True when the declared default is a runtime/transformed value and must be
|
|
43
55
|
// converted before it can be stored in `$`.
|
|
44
56
|
_defaultValueIsTransformed: boolean
|
|
57
|
+
_getDefaultValueIsTransformed?: () => boolean
|
|
45
58
|
_typeChecker: AnyStandardType | undefined
|
|
46
59
|
_setter: SetterMode
|
|
47
60
|
_setterValueTransform: ((value: unknown) => unknown) | undefined
|
|
48
61
|
_isId: boolean
|
|
49
62
|
_idGenerator?: (() => string) | undefined
|
|
50
|
-
_transform:
|
|
51
|
-
|
|
52
|
-
transform: (
|
|
53
|
-
original: unknown,
|
|
54
|
-
model: object,
|
|
55
|
-
propName: PropertyKey,
|
|
56
|
-
setOriginalValue: (newOriginalValue: unknown) => void
|
|
57
|
-
) => unknown
|
|
58
|
-
untransform: (transformed: unknown, model: object, propName: PropertyKey) => unknown
|
|
59
|
-
}
|
|
60
|
-
| undefined
|
|
63
|
+
_transform: FullModelPropTransform | undefined
|
|
64
|
+
_getTransform?: () => FullModelPropTransform | undefined
|
|
61
65
|
_fromSnapshotProcessor?: (sn: unknown) => unknown
|
|
62
66
|
_toSnapshotProcessor?: (sn: unknown) => unknown
|
|
67
|
+
_getFromSnapshotProcessor?: () => ((sn: unknown) => unknown) | undefined
|
|
68
|
+
_getToSnapshotProcessor?: () => ((sn: unknown) => unknown) | undefined
|
|
63
69
|
|
|
64
70
|
/**
|
|
65
71
|
* Adds a setter to the property. The setter will be named `set${CapitalizedPropName}`
|
|
@@ -141,6 +147,9 @@ export interface ModelProp<
|
|
|
141
147
|
*
|
|
142
148
|
* `fromSnapshot` runs before assigning snapshot data into the model prop.
|
|
143
149
|
* `toSnapshot` runs when exporting model data back to snapshot form.
|
|
150
|
+
* Both processors must be pure and deterministic, and their canonical output
|
|
151
|
+
* must round-trip to the same stored value. Reconciliation and snapshot
|
|
152
|
+
* generation may skip calls when that canonical snapshot is already current.
|
|
144
153
|
*/
|
|
145
154
|
withSnapshotProcessor<
|
|
146
155
|
FS = TFromSnapshotOverride,
|
|
@@ -400,13 +409,17 @@ const baseProp: AnyModelProp = {
|
|
|
400
409
|
_defaultFn: noDefaultValue,
|
|
401
410
|
_defaultValue: noDefaultValue,
|
|
402
411
|
_defaultValueIsTransformed: false,
|
|
412
|
+
_getDefaultValueIsTransformed: undefined,
|
|
403
413
|
_typeChecker: undefined,
|
|
404
414
|
_setter: false,
|
|
405
415
|
_setterValueTransform: undefined,
|
|
406
416
|
_isId: false,
|
|
407
417
|
_transform: undefined,
|
|
418
|
+
_getTransform: undefined,
|
|
408
419
|
_fromSnapshotProcessor: undefined,
|
|
409
420
|
_toSnapshotProcessor: undefined,
|
|
421
|
+
_getFromSnapshotProcessor: undefined,
|
|
422
|
+
_getToSnapshotProcessor: undefined,
|
|
410
423
|
|
|
411
424
|
withSetter(modeOrValueTransform?: SetterMode | ModelPropSetterValueTransform<unknown>) {
|
|
412
425
|
const obj: AnyModelProp = Object.create(this)
|
|
@@ -418,43 +431,88 @@ const baseProp: AnyModelProp = {
|
|
|
418
431
|
|
|
419
432
|
withTransform(transform: ModelPropTransform<unknown, unknown>) {
|
|
420
433
|
const obj: AnyModelProp = Object.create(this)
|
|
421
|
-
|
|
434
|
+
const innerTransform = toFullModelPropTransform(transform)
|
|
435
|
+
if (this._getTransform) {
|
|
436
|
+
const oldGet = this._getTransform
|
|
437
|
+
obj._getTransform = lazy(() => composeFullTransforms(oldGet(), innerTransform))
|
|
438
|
+
obj._transform = undefined
|
|
439
|
+
} else {
|
|
440
|
+
obj._transform = composeFullTransforms(this._transform, innerTransform)
|
|
441
|
+
}
|
|
422
442
|
return obj
|
|
423
443
|
},
|
|
424
444
|
|
|
425
445
|
withSnapshotProcessor({ fromSnapshot, toSnapshot }) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
if (this._fromSnapshotProcessor && fromSnapshot) {
|
|
429
|
-
const oldFn = this._fromSnapshotProcessor
|
|
430
|
-
const newFn = fromSnapshot
|
|
431
|
-
newFromSnapshot = (sn: any) => oldFn(newFn(sn))
|
|
432
|
-
} else if (fromSnapshot) {
|
|
433
|
-
newFromSnapshot = fromSnapshot
|
|
434
|
-
} else {
|
|
435
|
-
newFromSnapshot = this._fromSnapshotProcessor
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
let newToSnapshot: ((sn: any) => any) | undefined
|
|
446
|
+
const obj: AnyModelProp = Object.create(this)
|
|
439
447
|
|
|
440
|
-
if (
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
+
if (fromSnapshot) {
|
|
449
|
+
const newProcessor = fromSnapshot as (sn: unknown) => unknown
|
|
450
|
+
if (this._getFromSnapshotProcessor) {
|
|
451
|
+
const oldGet = this._getFromSnapshotProcessor
|
|
452
|
+
obj._getFromSnapshotProcessor = lazy(() => {
|
|
453
|
+
const oldProcessor = oldGet()
|
|
454
|
+
return oldProcessor ? (sn: unknown) => oldProcessor(newProcessor(sn)) : newProcessor
|
|
455
|
+
})
|
|
456
|
+
obj._fromSnapshotProcessor = undefined
|
|
457
|
+
} else {
|
|
458
|
+
const oldProcessor = this._fromSnapshotProcessor
|
|
459
|
+
obj._fromSnapshotProcessor = oldProcessor
|
|
460
|
+
? (sn: unknown) => oldProcessor(newProcessor(sn))
|
|
461
|
+
: newProcessor
|
|
462
|
+
}
|
|
448
463
|
}
|
|
449
464
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
465
|
+
if (toSnapshot) {
|
|
466
|
+
const newProcessor = toSnapshot as (sn: unknown) => unknown
|
|
467
|
+
if (this._getToSnapshotProcessor) {
|
|
468
|
+
const oldGet = this._getToSnapshotProcessor
|
|
469
|
+
obj._getToSnapshotProcessor = lazy(() => {
|
|
470
|
+
const oldProcessor = oldGet()
|
|
471
|
+
return oldProcessor ? (sn: unknown) => newProcessor(oldProcessor(sn)) : newProcessor
|
|
472
|
+
})
|
|
473
|
+
obj._toSnapshotProcessor = undefined
|
|
474
|
+
} else {
|
|
475
|
+
const oldProcessor = this._toSnapshotProcessor
|
|
476
|
+
obj._toSnapshotProcessor = oldProcessor
|
|
477
|
+
? (sn: unknown) => newProcessor(oldProcessor(sn))
|
|
478
|
+
: newProcessor
|
|
479
|
+
}
|
|
480
|
+
}
|
|
453
481
|
|
|
454
482
|
return obj
|
|
455
483
|
},
|
|
456
484
|
}
|
|
457
485
|
|
|
486
|
+
/** @internal */
|
|
487
|
+
export function getModelPropFromSnapshotProcessor(
|
|
488
|
+
modelProp: AnyModelProp
|
|
489
|
+
): ((sn: unknown) => unknown) | undefined {
|
|
490
|
+
return modelProp._getFromSnapshotProcessor
|
|
491
|
+
? modelProp._getFromSnapshotProcessor()
|
|
492
|
+
: modelProp._fromSnapshotProcessor
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** @internal */
|
|
496
|
+
export function getModelPropToSnapshotProcessor(
|
|
497
|
+
modelProp: AnyModelProp
|
|
498
|
+
): ((sn: unknown) => unknown) | undefined {
|
|
499
|
+
return modelProp._getToSnapshotProcessor
|
|
500
|
+
? modelProp._getToSnapshotProcessor()
|
|
501
|
+
: modelProp._toSnapshotProcessor
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/** @internal */
|
|
505
|
+
export function getModelPropTransform(modelProp: AnyModelProp): FullModelPropTransform | undefined {
|
|
506
|
+
return modelProp._getTransform ? modelProp._getTransform() : modelProp._transform
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/** @internal */
|
|
510
|
+
export function getModelPropDefaultValueIsTransformed(modelProp: AnyModelProp): boolean {
|
|
511
|
+
return modelProp._getDefaultValueIsTransformed
|
|
512
|
+
? modelProp._getDefaultValueIsTransformed()
|
|
513
|
+
: modelProp._defaultValueIsTransformed
|
|
514
|
+
}
|
|
515
|
+
|
|
458
516
|
/**
|
|
459
517
|
* Defines a model property, with an optional function to generate a default value
|
|
460
518
|
* if the input snapshot / model creation data is `null` or `undefined`.
|
|
@@ -565,7 +623,10 @@ const cacheTransformedValueFn = () => {
|
|
|
565
623
|
cacheTransformResult = true
|
|
566
624
|
}
|
|
567
625
|
|
|
568
|
-
|
|
626
|
+
/** @internal */
|
|
627
|
+
export function toFullModelPropTransform(
|
|
628
|
+
transformObject: ModelPropTransform<unknown, unknown>
|
|
629
|
+
): FullModelPropTransform {
|
|
569
630
|
const cache = new WeakMap<
|
|
570
631
|
object,
|
|
571
632
|
Map<PropertyKey, { originalValue: unknown; transformedValue: unknown }>
|
|
@@ -630,27 +691,9 @@ function toFullTransform(transformObject: ModelPropTransform<unknown, unknown>)
|
|
|
630
691
|
}
|
|
631
692
|
|
|
632
693
|
function composeFullTransforms(
|
|
633
|
-
outerTransform:
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
originalValue: unknown,
|
|
637
|
-
model: object,
|
|
638
|
-
propName: PropertyKey,
|
|
639
|
-
setOriginalValue: (newOriginalValue: unknown) => void
|
|
640
|
-
): unknown
|
|
641
|
-
untransform(transformedValue: unknown, model: object, propName: PropertyKey): unknown
|
|
642
|
-
}
|
|
643
|
-
| undefined,
|
|
644
|
-
innerTransform: {
|
|
645
|
-
transform(
|
|
646
|
-
originalValue: unknown,
|
|
647
|
-
model: object,
|
|
648
|
-
propName: PropertyKey,
|
|
649
|
-
setOriginalValue: (newOriginalValue: unknown) => void
|
|
650
|
-
): unknown
|
|
651
|
-
untransform(transformedValue: unknown, model: object, propName: PropertyKey): unknown
|
|
652
|
-
}
|
|
653
|
-
) {
|
|
694
|
+
outerTransform: FullModelPropTransform | undefined,
|
|
695
|
+
innerTransform: FullModelPropTransform
|
|
696
|
+
): FullModelPropTransform {
|
|
654
697
|
if (!outerTransform) {
|
|
655
698
|
return innerTransform
|
|
656
699
|
}
|
|
@@ -699,15 +742,14 @@ export function getModelPropStoredDefaultValue(
|
|
|
699
742
|
propName: string
|
|
700
743
|
): unknown | typeof noDefaultValue {
|
|
701
744
|
const defaultValue = getModelPropDefaultValue(propData)
|
|
702
|
-
if (defaultValue === noDefaultValue || !propData
|
|
745
|
+
if (defaultValue === noDefaultValue || !getModelPropDefaultValueIsTransformed(propData)) {
|
|
703
746
|
return defaultValue
|
|
704
747
|
}
|
|
705
748
|
|
|
706
|
-
|
|
749
|
+
const transform = getModelPropTransform(propData)
|
|
750
|
+
return transform
|
|
707
751
|
? runWithErrorDiagnosticsContext(() =>
|
|
708
|
-
withErrorPathSegment(propName, () =>
|
|
709
|
-
propData._transform!.untransform(defaultValue, model, propName)
|
|
710
|
-
)
|
|
752
|
+
withErrorPathSegment(propName, () => transform.untransform(defaultValue, model, propName))
|
|
711
753
|
)
|
|
712
754
|
: defaultValue
|
|
713
755
|
}
|
|
@@ -28,7 +28,10 @@ import { getInternalModelClassPropsInfo, setInternalModelClassPropsInfo } from "
|
|
|
28
28
|
import { modelMetadataSymbol, modelUnwrappedClassSymbol } from "./modelSymbols"
|
|
29
29
|
import {
|
|
30
30
|
type AnyModelProp,
|
|
31
|
+
getModelPropFromSnapshotProcessor,
|
|
31
32
|
getModelPropStoredDefaultValue,
|
|
33
|
+
getModelPropToSnapshotProcessor,
|
|
34
|
+
getModelPropTransform,
|
|
32
35
|
type ModelProps,
|
|
33
36
|
noDefaultValue,
|
|
34
37
|
prop,
|
|
@@ -39,21 +42,36 @@ function createGetModelInstanceDataField<M extends AnyModel | AnyDataModel>(
|
|
|
39
42
|
modelProp: AnyModelProp,
|
|
40
43
|
modelPropName: string
|
|
41
44
|
): (this: M) => unknown {
|
|
42
|
-
const
|
|
45
|
+
const fixedTransform = modelProp._getTransform ? undefined : modelProp._transform
|
|
43
46
|
|
|
44
|
-
if (!
|
|
47
|
+
if (!modelProp._getTransform && !fixedTransform) {
|
|
45
48
|
// no need to use get since these vars always get on the initial $
|
|
46
49
|
return function (this) {
|
|
47
50
|
return this.$[modelPropName]
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
type TransformValue = (model: M, value: unknown) => unknown
|
|
55
|
+
const createTransformValue =
|
|
56
|
+
(transform: NonNullable<ReturnType<typeof getModelPropTransform>>): TransformValue =>
|
|
57
|
+
(model, value) =>
|
|
58
|
+
transform.transform(value, model, modelPropName, (newValue) => {
|
|
59
|
+
// use apply set instead to wrap it in an action
|
|
60
|
+
// set the $ object to set the original value directly
|
|
61
|
+
applySet(model.$, modelPropName, newValue)
|
|
62
|
+
})
|
|
63
|
+
let transformValue: TransformValue
|
|
64
|
+
if (fixedTransform) {
|
|
65
|
+
transformValue = createTransformValue(fixedTransform)
|
|
66
|
+
} else {
|
|
67
|
+
transformValue = (model, value) => {
|
|
68
|
+
const transform = getModelPropTransform(modelProp)
|
|
69
|
+
transformValue = transform
|
|
70
|
+
? createTransformValue(transform)
|
|
71
|
+
: (_model, storedValue) => storedValue
|
|
72
|
+
return transformValue(model, value)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
57
75
|
|
|
58
76
|
return function (this) {
|
|
59
77
|
// no need to use get since these vars always get on the initial $
|
|
@@ -85,10 +103,9 @@ const setModelInstanceDataField: SetModelInstanceDataFieldFn = (
|
|
|
85
103
|
value = modelProp._setterValueTransform(value)
|
|
86
104
|
}
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
)
|
|
106
|
+
const transform = modelProp._getTransform ? modelProp._getTransform() : modelProp._transform
|
|
107
|
+
let untransformedValue = transform
|
|
108
|
+
? withErrorPathSegment(modelPropName, () => transform.untransform(value, model, modelPropName))
|
|
92
109
|
: value
|
|
93
110
|
|
|
94
111
|
// apply default value if applicable
|
|
@@ -128,6 +145,27 @@ propForDefaultId._isId = true
|
|
|
128
145
|
type FromSnapshotProcessorFn = (sn: any) => any
|
|
129
146
|
type ToSnapshotProcessorFn = (sn: any, instance: any) => any
|
|
130
147
|
|
|
148
|
+
function defineLazySnapshotProcessor(
|
|
149
|
+
modelClass: object,
|
|
150
|
+
property: "fromSnapshotProcessor" | "toSnapshotProcessor",
|
|
151
|
+
compile: () => FromSnapshotProcessorFn | ToSnapshotProcessorFn | undefined
|
|
152
|
+
): void {
|
|
153
|
+
Object.defineProperty(modelClass, property, {
|
|
154
|
+
configurable: true,
|
|
155
|
+
enumerable: true,
|
|
156
|
+
get() {
|
|
157
|
+
const processor = compile()
|
|
158
|
+
Object.defineProperty(modelClass, property, {
|
|
159
|
+
configurable: true,
|
|
160
|
+
enumerable: true,
|
|
161
|
+
writable: true,
|
|
162
|
+
value: processor,
|
|
163
|
+
})
|
|
164
|
+
return processor
|
|
165
|
+
},
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
131
169
|
export function sharedInternalModel<
|
|
132
170
|
TProps extends ModelProps,
|
|
133
171
|
TBaseModel extends AnyModel | AnyDataModel,
|
|
@@ -234,13 +272,13 @@ export function sharedInternalModel<
|
|
|
234
272
|
// create type checker if needed
|
|
235
273
|
let dataTypeChecker: AnyType | undefined
|
|
236
274
|
if (needsTypeChecker) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
275
|
+
dataTypeChecker = typesObject(() => {
|
|
276
|
+
const typeCheckerObj: Record<string, AnyType> = {}
|
|
277
|
+
for (const [k, mp] of Object.entries(composedModelProps)) {
|
|
278
|
+
typeCheckerObj[k] = mp._typeChecker ? resolveStoredType(mp._typeChecker) : typesUnchecked()
|
|
279
|
+
}
|
|
280
|
+
return typeCheckerObj
|
|
281
|
+
})
|
|
244
282
|
}
|
|
245
283
|
|
|
246
284
|
const base: any = baseModel ?? (type === "class" ? BaseModel : BaseDataModel)
|
|
@@ -279,8 +317,17 @@ export function sharedInternalModel<
|
|
|
279
317
|
return baseModel
|
|
280
318
|
}
|
|
281
319
|
|
|
282
|
-
//
|
|
283
|
-
|
|
320
|
+
// Copy static props from the base without reading its lazy snapshot processor
|
|
321
|
+
// accessors. This keeps subclass declaration from compiling the parent model's
|
|
322
|
+
// processor graph before snapshot processing is actually needed.
|
|
323
|
+
for (const key of Reflect.ownKeys(base)) {
|
|
324
|
+
if (key === "fromSnapshotProcessor" || key === "toSnapshotProcessor") {
|
|
325
|
+
continue
|
|
326
|
+
}
|
|
327
|
+
if (Object.prototype.propertyIsEnumerable.call(base, key)) {
|
|
328
|
+
;(ThisModel as any)[key] = (base as any)[key]
|
|
329
|
+
}
|
|
330
|
+
}
|
|
284
331
|
delete (ThisModel as any)[modelUnwrappedClassSymbol]
|
|
285
332
|
|
|
286
333
|
const initializers: ModelClassInitializer[] = base[modelInitializersSymbol]
|
|
@@ -345,10 +392,6 @@ export function sharedInternalModel<
|
|
|
345
392
|
}
|
|
346
393
|
}
|
|
347
394
|
|
|
348
|
-
const modelPropsFromSnapshotProcessor = getModelPropsFromSnapshotProcessor(composedModelProps)
|
|
349
|
-
|
|
350
|
-
const modelPropsToSnapshotProcessor = getModelPropsToSnapshotProcessor(composedModelProps)
|
|
351
|
-
|
|
352
395
|
if (fromSnapshotProcessor) {
|
|
353
396
|
const fn = fromSnapshotProcessor
|
|
354
397
|
fromSnapshotProcessor = (sn) => {
|
|
@@ -373,54 +416,42 @@ export function sharedInternalModel<
|
|
|
373
416
|
}
|
|
374
417
|
}
|
|
375
418
|
|
|
376
|
-
ThisModel
|
|
377
|
-
|
|
419
|
+
defineLazySnapshotProcessor(ThisModel, "fromSnapshotProcessor", () =>
|
|
420
|
+
chainFns(
|
|
421
|
+
fromSnapshotProcessor,
|
|
422
|
+
getModelPropsSnapshotProcessor(composedModelProps, getModelPropFromSnapshotProcessor)
|
|
423
|
+
)
|
|
424
|
+
)
|
|
425
|
+
defineLazySnapshotProcessor(ThisModel, "toSnapshotProcessor", () =>
|
|
426
|
+
chainFns(
|
|
427
|
+
getModelPropsSnapshotProcessor(composedModelProps, getModelPropToSnapshotProcessor),
|
|
428
|
+
toSnapshotProcessor
|
|
429
|
+
)
|
|
430
|
+
)
|
|
378
431
|
|
|
379
432
|
return ThisModel
|
|
380
433
|
}
|
|
381
434
|
|
|
382
|
-
function
|
|
383
|
-
composedModelProps: ModelProps
|
|
435
|
+
function getModelPropsSnapshotProcessor(
|
|
436
|
+
composedModelProps: ModelProps,
|
|
437
|
+
getProcessor: (prop: AnyModelProp) => ((sn: unknown) => unknown) | undefined
|
|
384
438
|
): FromSnapshotProcessorFn | undefined {
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return (sn) => {
|
|
393
|
-
const newSn = { ...sn }
|
|
394
|
-
for (const [propName, propData] of propsWithFromSnapshotProcessor) {
|
|
395
|
-
if (propData._fromSnapshotProcessor) {
|
|
396
|
-
newSn[propName] = withErrorPathSegment(propName, () =>
|
|
397
|
-
propData._fromSnapshotProcessor!(sn[propName])
|
|
398
|
-
)
|
|
399
|
-
}
|
|
439
|
+
const propsWithProcessor: Array<readonly [string, (sn: unknown) => unknown]> = []
|
|
440
|
+
for (const [propName, propData] of Object.entries(composedModelProps)) {
|
|
441
|
+
const processor = getProcessor(propData)
|
|
442
|
+
if (processor) {
|
|
443
|
+
propsWithProcessor.push([propName, processor])
|
|
400
444
|
}
|
|
401
|
-
return newSn
|
|
402
445
|
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function getModelPropsToSnapshotProcessor(
|
|
406
|
-
composedModelProps: ModelProps
|
|
407
|
-
): ToSnapshotProcessorFn | undefined {
|
|
408
|
-
const propsWithToSnapshotProcessor = Object.entries(composedModelProps).filter(
|
|
409
|
-
([_propName, propData]) => propData._toSnapshotProcessor
|
|
410
|
-
)
|
|
411
446
|
|
|
412
|
-
if (
|
|
447
|
+
if (propsWithProcessor.length === 0) {
|
|
413
448
|
return undefined
|
|
414
449
|
}
|
|
415
450
|
|
|
416
451
|
return (sn) => {
|
|
417
452
|
const newSn = { ...sn }
|
|
418
|
-
for (const [propName,
|
|
419
|
-
|
|
420
|
-
newSn[propName] = withErrorPathSegment(propName, () =>
|
|
421
|
-
propData._toSnapshotProcessor!(sn[propName])
|
|
422
|
-
)
|
|
423
|
-
}
|
|
453
|
+
for (const [propName, processor] of propsWithProcessor) {
|
|
454
|
+
newSn[propName] = withErrorPathSegment(propName, () => processor(sn[propName]))
|
|
424
455
|
}
|
|
425
456
|
return newSn
|
|
426
457
|
}
|
package/src/parent/core.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { createAtom, type IAtom } from "mobx"
|
|
2
2
|
import { isModel } from "../model/utils"
|
|
3
|
+
import { treeNodeMetadata } from "../tweaker/treeNodeMetadata"
|
|
3
4
|
import { getOrCreate } from "../utils/mapUtils"
|
|
4
5
|
import type { ParentPath } from "./path"
|
|
5
6
|
|
|
6
|
-
/**
|
|
7
|
-
* @internal
|
|
8
|
-
*/
|
|
9
|
-
export const objectParents = new WeakMap<object, ParentPath<object> | undefined>()
|
|
10
|
-
|
|
11
7
|
const objectParentsAtoms = new WeakMap<object, IAtom>()
|
|
12
8
|
|
|
13
9
|
/**
|
|
@@ -44,16 +40,26 @@ export function reportParentPathChanged(node: object) {
|
|
|
44
40
|
objectParentsAtoms.get(node)?.reportChanged()
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
/** @internal */
|
|
44
|
+
export function getDataObjectParent(node: object): object | undefined {
|
|
45
|
+
return treeNodeMetadata.get(node)?.dataObjectParent
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @internal */
|
|
49
|
+
export function hasDataObjectParent(node: object): boolean {
|
|
50
|
+
return treeNodeMetadata.get(node)?.dataObjectParent !== undefined
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** @internal */
|
|
54
|
+
export function setDataObjectParent(node: object, parent: object): void {
|
|
55
|
+
treeNodeMetadata.get(node)!.dataObjectParent = parent
|
|
56
|
+
}
|
|
51
57
|
|
|
52
58
|
/**
|
|
53
59
|
* @internal
|
|
54
60
|
*/
|
|
55
61
|
export function dataToModelNode<T extends object>(node: T): T {
|
|
56
|
-
const modelNode =
|
|
62
|
+
const modelNode = getDataObjectParent(node)
|
|
57
63
|
return (modelNode as T | undefined) ?? node
|
|
58
64
|
}
|
|
59
65
|
|