mobx-keystone-mindreframer
Version:
A MobX powered state management solution based on data trees with first class support for Typescript, snapshots, patches and much more
59 lines (53 loc) • 2.01 kB
text/typescript
import { isModelAutoTypeCheckingEnabled } from "../globalConfig/globalConfig"
import type { AnyModel } from "../model/BaseModel"
import { getModelMetadata } from "../model/getModelMetadata"
import { isModel } from "../model/utils"
import { dataToModelNode } from "../parent/core"
import { findParent } from "../parent/findParent"
import { internalApplyPatches } from "../patch/applyPatches"
import { InternalPatchRecorder } from "../patch/emitPatch"
import { invalidateCachedTypeCheckerResult } from "../typeChecking/TypeChecker"
import { runWithoutSnapshotOrPatches } from "./core"
/**
* @ignore
* @internal
*/
export function runTypeCheckingAfterChange(obj: object, patchRecorder: InternalPatchRecorder) {
// invalidate type check cached result
invalidateCachedTypeCheckerResult(obj)
if (isModelAutoTypeCheckingEnabled()) {
const parentModelWithTypeChecker = findNearestParentModelWithTypeChecker(obj)
if (parentModelWithTypeChecker) {
const err = parentModelWithTypeChecker.typeCheck()
if (err) {
// quietly apply inverse patches (do not generate patches, snapshots, actions, etc)
runWithoutSnapshotOrPatches(() => {
internalApplyPatches.call(obj, patchRecorder.invPatches, true)
})
// at the end of apply patches it will be type checked again and its result cached once more
err.throw(parentModelWithTypeChecker)
}
}
}
}
/**
* @ignore
*
* Finds the closest parent model that has a type checker defined.
*
* @param child
* @returns
*/
function findNearestParentModelWithTypeChecker(child: object): AnyModel | undefined {
// child might be .$, so we need to check the parent model in that case
const actualChild = dataToModelNode(child)
if (child !== actualChild) {
child = actualChild
if (isModel(child) && !!getModelMetadata(child).dataType) {
return child
}
}
return findParent(child, (parent) => {
return isModel(parent) && !!getModelMetadata(parent).dataType
})
}