From eee01b444bed58c34d8cfb9dc5125b803f3dcf91 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Fri, 6 Mar 2026 08:49:50 +0100 Subject: [PATCH 1/2] fix: preserve component stack on repeated element grabs --- src/react-native/get-rendered-by.ts | 44 +++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/react-native/get-rendered-by.ts b/src/react-native/get-rendered-by.ts index f7874c8..c37cf02 100644 --- a/src/react-native/get-rendered-by.ts +++ b/src/react-native/get-rendered-by.ts @@ -32,17 +32,37 @@ type V8CallSite = { getColumnNumber(): number | null; }; +const restoreStackDescriptor = ( + error: Error, + descriptor: PropertyDescriptor | undefined, +) => { + try { + if (descriptor) { + Object.defineProperty(error, "stack", descriptor); + } else { + delete (error as Error & { stack?: unknown }).stack; + } + } catch { + // Best effort only. Some runtimes may prevent restoring non-configurable properties. + } +}; + const firstUserFrameFromError = ( error: Error, ): { file: string | null; line: number | null; column: number | null } | null => { + const stackDescriptorBeforeCallSites = Object.getOwnPropertyDescriptor(error, "stack"); let callSites: V8CallSite[] | null = null; const prev = (Error as any).prepareStackTrace; - (Error as any).prepareStackTrace = (_: unknown, sites: V8CallSite[]) => { - callSites = sites; - return ""; - }; - void error.stack; - (Error as any).prepareStackTrace = prev; + try { + (Error as any).prepareStackTrace = (_: unknown, sites: V8CallSite[]) => { + callSites = sites; + return ""; + }; + void error.stack; + } finally { + (Error as any).prepareStackTrace = prev; + restoreStackDescriptor(error, stackDescriptorBeforeCallSites); + } if (callSites && (callSites as V8CallSite[]).length > 0) { const sites = callSites as V8CallSite[]; @@ -77,10 +97,16 @@ const firstUserFrameFromError = ( return null; } + const stackDescriptorBeforeString = Object.getOwnPropertyDescriptor(error, "stack"); const prevStr = (Error as any).prepareStackTrace; - (Error as any).prepareStackTrace = undefined; - let stack = error.stack ?? ""; - (Error as any).prepareStackTrace = prevStr; + let stack = ""; + try { + (Error as any).prepareStackTrace = undefined; + stack = error.stack ?? ""; + } finally { + (Error as any).prepareStackTrace = prevStr; + restoreStackDescriptor(error, stackDescriptorBeforeString); + } if (stack.startsWith("Error: react-stack-top-frame\n")) { stack = stack.slice("Error: react-stack-top-frame\n".length); From f7f44590ce28ca571cd64182168b55c8ce928363 Mon Sep 17 00:00:00 2001 From: Szymon Chmal Date: Fri, 6 Mar 2026 08:53:36 +0100 Subject: [PATCH 2/2] style: format --- src/react-native/get-rendered-by.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/react-native/get-rendered-by.ts b/src/react-native/get-rendered-by.ts index c37cf02..1feffed 100644 --- a/src/react-native/get-rendered-by.ts +++ b/src/react-native/get-rendered-by.ts @@ -32,10 +32,7 @@ type V8CallSite = { getColumnNumber(): number | null; }; -const restoreStackDescriptor = ( - error: Error, - descriptor: PropertyDescriptor | undefined, -) => { +const restoreStackDescriptor = (error: Error, descriptor: PropertyDescriptor | undefined) => { try { if (descriptor) { Object.defineProperty(error, "stack", descriptor);