diff --git a/packages/lib/src/action/middleware.ts b/packages/lib/src/action/middleware.ts index e90cd19e..11edbe25 100644 --- a/packages/lib/src/action/middleware.ts +++ b/packages/lib/src/action/middleware.ts @@ -70,7 +70,7 @@ export function getActionMiddlewares(obj: object): ActionMiddlewaresIterator { function findNextIterator() { let nextIter while (current && !nextIter) { - current = fastGetParent(current) + current = fastGetParent(current, false) nextIter = getCurrentIterator() } return nextIter diff --git a/packages/lib/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts b/packages/lib/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts index ae090e3a..41dc031b 100644 --- a/packages/lib/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +++ b/packages/lib/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts @@ -19,7 +19,7 @@ export const objectPathSerializer: ActionCallArgumentSerializer( const event = { type: UndoEventType.Single, - targetPath: fastGetRootPath(ctx.target).path, + targetPath: fastGetRootPath(ctx.target, false).path, actionName: ctx.actionName, patches, inversePatches, diff --git a/packages/lib/src/context/context.ts b/packages/lib/src/context/context.ts index dec11eb2..a2e0bc2a 100644 --- a/packages/lib/src/context/context.ts +++ b/packages/lib/src/context/context.ts @@ -120,15 +120,17 @@ class ContextClass implements Context { this.nodeAtom.get(node)?.reportChanged() } - private fastGet(node: object): T { - this.reportNodeAtomObserved(node) + private fastGet(node: object, useAtom: boolean): T { + if (useAtom) { + this.reportNodeAtomObserved(node) + } const obsForNode = this.nodeContextValue.get(node) if (obsForNode) { return resolveContextValue(obsForNode) } - const parent = fastGetParent(node) + const parent = fastGetParent(node, useAtom) if (!parent) { const overrideValue = this.overrideContextValue.get() if (overrideValue) { @@ -137,35 +139,37 @@ class ContextClass implements Context { return this.getDefault() } - return this.fastGet(parent) + return this.fastGet(parent, useAtom) } get(node: object) { assertTweakedObject(node, "node") - return this.fastGet(node) + return this.fastGet(node, true) } - private fastGetProviderNode(node: object): object | undefined { - this.reportNodeAtomObserved(node) + private fastGetProviderNode(node: object, useAtom: boolean): object | undefined { + if (useAtom) { + this.reportNodeAtomObserved(node) + } const obsForNode = this.nodeContextValue.get(node) if (obsForNode) { return node } - const parent = fastGetParent(node) + const parent = fastGetParent(node, useAtom) if (!parent) { return undefined } - return this.fastGetProviderNode(parent) + return this.fastGetProviderNode(parent, useAtom) } getProviderNode(node: object): object | undefined { assertTweakedObject(node, "node") - return this.fastGetProviderNode(node) + return this.fastGetProviderNode(node, true) } getDefault(): T { diff --git a/packages/lib/src/parent/coreObjectChildren.ts b/packages/lib/src/parent/coreObjectChildren.ts index 0eeba7c4..91ad5cda 100644 --- a/packages/lib/src/parent/coreObjectChildren.ts +++ b/packages/lib/src/parent/coreObjectChildren.ts @@ -135,7 +135,7 @@ function invalidateDeepChildren(node: object, obj: ObjectChildrenData) { currentObj.deepDirty = true currentObj.deepAtom?.reportChanged() - currentNode = fastGetParent(currentNode) + currentNode = fastGetParent(currentNode, false) if (currentNode) { currentObj = getObjectChildrenObject(currentNode) } diff --git a/packages/lib/src/parent/detach.ts b/packages/lib/src/parent/detach.ts index f4c4c60c..09b9af39 100644 --- a/packages/lib/src/parent/detach.ts +++ b/packages/lib/src/parent/detach.ts @@ -31,7 +31,7 @@ const wrappedInternalDetach = lazy(() => function internalDetach(this: object): void { const node = this - const parentPath = fastGetParentPathIncludingDataObjects(node) + const parentPath = fastGetParentPathIncludingDataObjects(node, false) if (!parentPath) return const { parent, path } = parentPath diff --git a/packages/lib/src/parent/findParent.ts b/packages/lib/src/parent/findParent.ts index 17c7ff24..e67b564f 100644 --- a/packages/lib/src/parent/findParent.ts +++ b/packages/lib/src/parent/findParent.ts @@ -64,7 +64,7 @@ export function findParentPath( let depth = 0 let parentPath: ParentPath | undefined - while ((parentPath = fastGetParentPath(current))) { + while ((parentPath = fastGetParentPath(current, true))) { path.unshift(parentPath.path) current = parentPath.parent if (predicate(current)) { diff --git a/packages/lib/src/parent/path.ts b/packages/lib/src/parent/path.ts index 8fae2c6b..0700e346 100644 --- a/packages/lib/src/parent/path.ts +++ b/packages/lib/src/parent/path.ts @@ -60,16 +60,19 @@ export interface RootPath { export function getParentPath(value: object): ParentPath | undefined { assertTweakedObject(value, "value") - return fastGetParentPath(value) + return fastGetParentPath(value, true) } /** * @internal */ export function fastGetParentPath( - value: object + value: object, + useAtom: boolean ): ParentPath | undefined { - reportParentPathObserved(value) + if (useAtom) { + reportParentPathObserved(value) + } return objectParents.get(value) as ParentPath | undefined } @@ -77,14 +80,15 @@ export function fastGetParentPath( * @internal */ export function fastGetParentPathIncludingDataObjects( - value: object + value: object, + useAtom: boolean ): ParentPath | undefined { const parentModel = dataObjectParent.get(value) if (parentModel) { return { parent: parentModel as T, path: "$" } } - const parentPath = fastGetParentPath(value) + const parentPath = fastGetParentPath(value, useAtom) if (parentPath && isModel(parentPath.parent)) { return { parent: parentPath.parent.$ as T, path: parentPath.path } } @@ -101,23 +105,27 @@ export function fastGetParentPathIncludingDataObjects( export function getParent(value: object): T | undefined { assertTweakedObject(value, "value") - return fastGetParent(value) + return fastGetParent(value, true) } /** * @internal */ -export function fastGetParent(value: object): T | undefined { - return fastGetParentPath(value)?.parent +export function fastGetParent( + value: object, + useAtom: boolean +): T | undefined { + return fastGetParentPath(value, useAtom)?.parent } /** * @internal */ export function fastGetParentIncludingDataObjects( - value: object + value: object, + useAtom: boolean ): T | undefined { - return fastGetParentPathIncludingDataObjects(value)?.parent + return fastGetParentPathIncludingDataObjects(value, useAtom)?.parent } /** @@ -149,19 +157,22 @@ export function fastIsModelDataObject(value: object): boolean { export function getRootPath(value: object): RootPath { assertTweakedObject(value, "value") - return fastGetRootPath(value) + return fastGetRootPath(value, true) } /** * @internal */ -export function fastGetRootPath(value: object): RootPath { +export function fastGetRootPath( + value: object, + useAtom: boolean +): RootPath { let root = value const path = [] as WritablePath const pathObjects = [value] as unknown[] let parentPath: ParentPath | undefined - while ((parentPath = fastGetParentPath(root))) { + while ((parentPath = fastGetParentPath(root, useAtom))) { root = parentPath.parent path.unshift(parentPath.path) pathObjects.unshift(parentPath.parent) @@ -180,17 +191,17 @@ export function fastGetRootPath(value: object): RootPath export function getRoot(value: object): T { assertTweakedObject(value, "value") - return fastGetRoot(value) + return fastGetRoot(value, true) } /** * @internal */ -export function fastGetRoot(value: object): T { +export function fastGetRoot(value: object, useAtom: boolean): T { let root = value let parentPath: ParentPath | undefined - while ((parentPath = fastGetParentPath(root))) { + while ((parentPath = fastGetParentPath(root, useAtom))) { root = parentPath.parent } @@ -206,7 +217,7 @@ export function fastGetRoot(value: object): T { export function isRoot(value: object): boolean { assertTweakedObject(value, "value") - return !fastGetParent(value) + return !fastGetParent(value, true) } const unresolved = { resolved: false } as const @@ -347,7 +358,7 @@ export function getParentToChildPath(fromParent: object, toChild: object): Path let current = toChild let parentPath - while ((parentPath = fastGetParentPath(current))) { + while ((parentPath = fastGetParentPath(current, true))) { path.unshift(parentPath.path) current = parentPath.parent diff --git a/packages/lib/src/parent/path2.ts b/packages/lib/src/parent/path2.ts index 2d55d973..d6327fb1 100644 --- a/packages/lib/src/parent/path2.ts +++ b/packages/lib/src/parent/path2.ts @@ -12,13 +12,13 @@ export function isChildOfParent(child: object, parent: object): boolean { assertTweakedObject(child, "child") assertTweakedObject(parent, "parent") - let currentParent = fastGetParent(child) + let currentParent = fastGetParent(child, true) while (currentParent) { if (currentParent === parent) { return true } - currentParent = fastGetParent(currentParent) + currentParent = fastGetParent(currentParent, true) } return false diff --git a/packages/lib/src/parent/setParent.ts b/packages/lib/src/parent/setParent.ts index f079d2ae..457e7c8c 100644 --- a/packages/lib/src/parent/setParent.ts +++ b/packages/lib/src/parent/setParent.ts @@ -52,7 +52,7 @@ export const setParent = action( } } - let oldParentPath = fastGetParentPath(value) + let oldParentPath = fastGetParentPath(value, false) if (parentPathEquals(oldParentPath, parentPath)) { return value } @@ -88,7 +88,7 @@ export const setParent = action( getModelMetadata(value).valueType ) { value = clone(value, { generateNewIds: true }) - oldParentPath = fastGetParentPath(value) + oldParentPath = fastGetParentPath(value, false) } if (oldParentPath && parentPath) { @@ -109,7 +109,7 @@ export const setParent = action( let oldRoot: any let oldRootStore: any if (valueIsModel) { - oldRoot = fastGetRoot(value) + oldRoot = fastGetRoot(value, false) oldRootStore = fastIsRootStoreNoAtom(oldRoot) ? oldRoot : undefined } @@ -126,7 +126,7 @@ export const setParent = action( reportParentPathChanged(value) if (valueIsModel) { - const newRoot = fastGetRoot(value) + const newRoot = fastGetRoot(value, false) const newRootStore = fastIsRootStoreNoAtom(newRoot) ? newRoot : undefined // invoke model root store events diff --git a/packages/lib/src/patch/emitPatch.ts b/packages/lib/src/patch/emitPatch.ts index 9db79a0e..ac90d729 100644 --- a/packages/lib/src/patch/emitPatch.ts +++ b/packages/lib/src/patch/emitPatch.ts @@ -1,10 +1,10 @@ import { action, isAction } from "mobx" import { fastGetParentPath } from "../parent/path" import type { PathElement } from "../parent/pathTypes" +import { freezeInternalSnapshot, getInternalSnapshot } from "../snapshot/internal" import { assertTweakedObject } from "../tweaker/core" import { assertIsFunction, deleteFromArray, isPrimitive } from "../utils" import type { Patch } from "./Patch" -import { freezeInternalSnapshot, getInternalSnapshot } from "../snapshot/internal" const emptyPatchArray: Patch[] = [] @@ -147,12 +147,12 @@ function emitPatch(obj: object, patches: Patch[], inversePatches: Patch[]): void emitPatchForTarget(obj, patches, inversePatches, pathPrefix) // and also emit subtree listeners all the way to the root - let parentPath = fastGetParentPath(obj) + let parentPath = fastGetParentPath(obj, false) while (parentPath) { pathPrefix.unshift(parentPath.path) emitPatchForTarget(parentPath.parent, patches, inversePatches, pathPrefix) - parentPath = fastGetParentPath(parentPath.parent) + parentPath = fastGetParentPath(parentPath.parent, false) } } diff --git a/packages/lib/src/redux/connectReduxDevTools.ts b/packages/lib/src/redux/connectReduxDevTools.ts index ed956b4c..a461007b 100644 --- a/packages/lib/src/redux/connectReduxDevTools.ts +++ b/packages/lib/src/redux/connectReduxDevTools.ts @@ -117,7 +117,7 @@ export function connectReduxDevTools( } lastLoggedSnapshot = sn - const rootPath = fastGetRootPath(ctx.target) + const rootPath = fastGetRootPath(ctx.target, false) const name = getActionContextNameAndTypePath(ctx, rootPath, result) const copy = { @@ -170,7 +170,7 @@ export function connectReduxDevTools( if (ctx.parentContext) { const parentName = getActionContextNameAndTypePath( ctx.parentContext, - fastGetRootPath(ctx.parentContext.target), + fastGetRootPath(ctx.parentContext.target, false), undefined ) if (parentName) { diff --git a/packages/lib/src/ref/core.ts b/packages/lib/src/ref/core.ts index b0ad0dc4..a29eb245 100644 --- a/packages/lib/src/ref/core.ts +++ b/packages/lib/src/ref/core.ts @@ -239,7 +239,7 @@ export function getRefsResolvingTo( const oldBackRefs = getBackRefs(target, refType) oldBackRefs.forEach(updateRef) - const refsChildrenOfRoot = getDeepChildrenRefs(getDeepObjectChildren(fastGetRoot(target))) + const refsChildrenOfRoot = getDeepChildrenRefs(getDeepObjectChildren(fastGetRoot(target, true))) let refs: Set> | undefined if (refType) { refs = refsChildrenOfRoot.byType.get(refType.refClass) diff --git a/packages/lib/src/ref/rootRef.ts b/packages/lib/src/ref/rootRef.ts index eb54554f..5483b2da 100644 --- a/packages/lib/src/ref/rootRef.ts +++ b/packages/lib/src/ref/rootRef.ts @@ -55,7 +55,7 @@ export const rootRef: ( let cachedTarget: T | undefined return () => { - const refRoot = fastGetRoot(ref) + const refRoot = fastGetRoot(ref, true) if (isRefRootCachedTargetOk(ref, refRoot, cachedTarget, getId)) { return cachedTarget @@ -83,6 +83,6 @@ function isRefRootCachedTargetOk( ): cachedTarget is T { if (!cachedTarget) return false if (ref.id !== getId(cachedTarget)) return false - if (refRoot !== fastGetRoot(cachedTarget)) return false + if (refRoot !== fastGetRoot(cachedTarget, true)) return false return true } diff --git a/packages/lib/src/rootStore/rootStore.ts b/packages/lib/src/rootStore/rootStore.ts index 9dddc13a..f16bff41 100644 --- a/packages/lib/src/rootStore/rootStore.ts +++ b/packages/lib/src/rootStore/rootStore.ts @@ -104,6 +104,6 @@ export function fastIsRootStoreNoAtom(node: object): boolean { export function getRootStore(node: object): T | undefined { assertTweakedObject(node, "node") - const root = fastGetRoot(node) + const root = fastGetRoot(node, true) return isRootStore(root) ? root : undefined } diff --git a/packages/lib/src/snapshot/internal.ts b/packages/lib/src/snapshot/internal.ts index 5c85d62b..c224429e 100644 --- a/packages/lib/src/snapshot/internal.ts +++ b/packages/lib/src/snapshot/internal.ts @@ -136,7 +136,7 @@ export const updateInternalSnapshot = action( sn.atom?.reportChanged() // also update parent(s) snapshot(s) if needed - const parent = getInternalSnapshotParent(sn, fastGetParentPath(value)) + const parent = getInternalSnapshotParent(sn, fastGetParentPath(value, false)) if (parent) { const { parentSnapshot, parentPath } = parent // might be false in the cases where the parent has not yet been created diff --git a/packages/lib/src/snapshot/reconcileSnapshot.ts b/packages/lib/src/snapshot/reconcileSnapshot.ts index 774db02f..cf8998c5 100644 --- a/packages/lib/src/snapshot/reconcileSnapshot.ts +++ b/packages/lib/src/snapshot/reconcileSnapshot.ts @@ -70,7 +70,7 @@ export function detachIfNeeded(newValue: any, oldValue: any, modelPool: ModelPoo isModel(newValue) && modelPool.findModelByTypeAndId(newValue[modelTypeKey], newValue[modelIdKey]) ) { - const parentPath = fastGetParentPathIncludingDataObjects(newValue) + const parentPath = fastGetParentPathIncludingDataObjects(newValue, false) if (parentPath) { set(parentPath.parent, parentPath.path, null) } diff --git a/packages/lib/src/tweaker/tweak.ts b/packages/lib/src/tweaker/tweak.ts index d1db374f..c510ced0 100644 --- a/packages/lib/src/tweaker/tweak.ts +++ b/packages/lib/src/tweaker/tweak.ts @@ -146,7 +146,7 @@ export function tryUntweak(value: any): (() => void) | undefined { } if (inDevMode) { - if (!fastGetParent(value)) { + if (!fastGetParent(value, false)) { throw failure("assertion failed: object cannot be untweaked if it does not have a parent") } } diff --git a/packages/lib/src/types/TypeCheckError.ts b/packages/lib/src/types/TypeCheckError.ts index 0f67805a..1167180f 100644 --- a/packages/lib/src/types/TypeCheckError.ts +++ b/packages/lib/src/types/TypeCheckError.ts @@ -28,7 +28,7 @@ export class TypeCheckError { ) { let rootPath: Path = [] if (this.typeCheckedValue && isTweakedObject(this.typeCheckedValue, true)) { - rootPath = fastGetRootPath(this.typeCheckedValue).path + rootPath = fastGetRootPath(this.typeCheckedValue, false).path } const actualValueSnapshot = isTweakedObject(this.actualValue, true) diff --git a/packages/lib/src/types/TypeChecker.ts b/packages/lib/src/types/TypeChecker.ts index a749077b..d7481bec 100644 --- a/packages/lib/src/types/TypeChecker.ts +++ b/packages/lib/src/types/TypeChecker.ts @@ -50,7 +50,7 @@ export function invalidateCachedTypeCheckerResult(obj: object) { set.forEach((typeChecker) => typeChecker.invalidateCachedResult(current)) } - current = fastGetParentIncludingDataObjects(current) + current = fastGetParentIncludingDataObjects(current, false) } }