From 4b0179bbecf0ccbcc28e4acc5de03bc7a26c1d14 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Wed, 3 Apr 2024 20:51:17 +0200 Subject: [PATCH] Fix parsing for minified prod bundles --- .../react-debug-tools/src/ReactDebugHooks.js | 119 +++++++++--------- ...ReactHooksInspectionIntegrationDOM-test.js | 2 - 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 47873829380d3..82619fc1be890 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -48,7 +48,7 @@ type HookLogEntry = { stackError: Error, value: mixed, debugInfo: ReactDebugInfo | null, - dispatcherMethodName: string, + dispatcherHookName: string, wrapperNames: Array, }; @@ -217,8 +217,8 @@ function use(usable: Usable): T { value: fulfilledValue, debugInfo: thenable._debugInfo === undefined ? null : thenable._debugInfo, - dispatcherMethodName: 'use', - wrapperNames: ['use'], + dispatcherHookName: 'Use', + wrapperNames: ['Use'], }); return fulfilledValue; } @@ -236,8 +236,8 @@ function use(usable: Usable): T { value: thenable, debugInfo: thenable._debugInfo === undefined ? null : thenable._debugInfo, - dispatcherMethodName: 'use', - wrapperNames: ['use'], + dispatcherHookName: 'Use', + wrapperNames: ['Use'], }); throw SuspenseException; } else if (usable.$$typeof === REACT_CONTEXT_TYPE) { @@ -250,8 +250,8 @@ function use(usable: Usable): T { stackError: new Error(), value, debugInfo: null, - dispatcherMethodName: 'use', - wrapperNames: ['use'], + dispatcherHookName: 'Use', + wrapperNames: ['Use'], }); return value; @@ -270,8 +270,8 @@ function useContext(context: ReactContext): T { stackError: new Error(), value: value, debugInfo: null, - dispatcherMethodName: 'useContext', - wrapperNames: ['useContext'], + dispatcherHookName: 'Context', + wrapperNames: ['Context'], }); return value; } @@ -293,8 +293,8 @@ function useState( stackError: new Error(), value: state, debugInfo: null, - dispatcherMethodName: 'useState', - wrapperNames: ['useState'], + dispatcherHookName: 'State', + wrapperNames: ['State'], }); return [state, (action: BasicStateAction) => {}]; } @@ -317,8 +317,8 @@ function useReducer( stackError: new Error(), value: state, debugInfo: null, - dispatcherMethodName: 'useReducer', - wrapperNames: ['useReducer'], + dispatcherHookName: 'Reducer', + wrapperNames: ['Reducer'], }); return [state, (action: A) => {}]; } @@ -332,8 +332,8 @@ function useRef(initialValue: T): {current: T} { stackError: new Error(), value: ref.current, debugInfo: null, - dispatcherMethodName: 'useRef', - wrapperNames: ['useRef'], + dispatcherHookName: 'Ref', + wrapperNames: ['Ref'], }); return ref; } @@ -346,8 +346,8 @@ function useCacheRefresh(): () => void { stackError: new Error(), value: hook !== null ? hook.memoizedState : function refresh() {}, debugInfo: null, - dispatcherMethodName: 'useCacheRefresh', - wrapperNames: ['useCacheRefresh'], + dispatcherHookName: 'CacheRefresh', + wrapperNames: ['CacheRefresh'], }); return () => {}; } @@ -363,8 +363,8 @@ function useLayoutEffect( stackError: new Error(), value: create, debugInfo: null, - dispatcherMethodName: 'useLayoutEffect', - wrapperNames: ['useLayoutEffect'], + dispatcherHookName: 'LayoutEffect', + wrapperNames: ['LayoutEffect'], }); } @@ -379,8 +379,8 @@ function useInsertionEffect( stackError: new Error(), value: create, debugInfo: null, - dispatcherMethodName: 'useInsertionEffect', - wrapperNames: ['useInsertionEffect'], + dispatcherHookName: 'InsertionEffect', + wrapperNames: ['InsertionEffect'], }); } @@ -395,8 +395,8 @@ function useEffect( stackError: new Error(), value: create, debugInfo: null, - dispatcherMethodName: 'useEffect', - wrapperNames: ['useEffect'], + dispatcherHookName: 'Effect', + wrapperNames: ['Effect'], }); } @@ -420,8 +420,8 @@ function useImperativeHandle( stackError: new Error(), value: instance, debugInfo: null, - dispatcherMethodName: 'useImperativeHandle', - wrapperNames: ['useImperativeHandle'], + dispatcherHookName: 'ImperativeHandle', + wrapperNames: ['ImperativeHandle'], }); } @@ -432,8 +432,8 @@ function useDebugValue(value: any, formatterFn: ?(value: any) => any) { stackError: new Error(), value: typeof formatterFn === 'function' ? formatterFn(value) : value, debugInfo: null, - dispatcherMethodName: 'useDebugValue', - wrapperNames: ['useDebugValue'], + dispatcherHookName: 'DebugValue', + wrapperNames: ['DebugValue'], }); } @@ -445,8 +445,8 @@ function useCallback(callback: T, inputs: Array | void | null): T { stackError: new Error(), value: hook !== null ? hook.memoizedState[0] : callback, debugInfo: null, - dispatcherMethodName: 'useCallback', - wrapperNames: ['useCallback'], + dispatcherHookName: 'Callback', + wrapperNames: ['Callback'], }); return callback; } @@ -463,8 +463,8 @@ function useMemo( stackError: new Error(), value, debugInfo: null, - dispatcherMethodName: 'useMemo', - wrapperNames: ['useMemo'], + dispatcherHookName: 'Memo', + wrapperNames: ['Memo'], }); return value; } @@ -486,8 +486,8 @@ function useSyncExternalStore( stackError: new Error(), value, debugInfo: null, - dispatcherMethodName: 'useSyncExternalStore', - wrapperNames: ['useSyncExternalStore'], + dispatcherHookName: 'SyncExternalStore', + wrapperNames: ['SyncExternalStore'], }); return value; } @@ -510,8 +510,8 @@ function useTransition(): [ stackError: new Error(), value: isPending, debugInfo: null, - dispatcherMethodName: 'useTransition', - wrapperNames: ['useTransition'], + dispatcherHookName: 'Transition', + wrapperNames: ['Transition'], }); return [isPending, () => {}]; } @@ -525,8 +525,8 @@ function useDeferredValue(value: T, initialValue?: T): T { stackError: new Error(), value: prevValue, debugInfo: null, - dispatcherMethodName: 'useDeferredValue', - wrapperNames: ['useDeferredValue'], + dispatcherHookName: 'DeferredValue', + wrapperNames: ['DeferredValue'], }); return prevValue; } @@ -540,8 +540,8 @@ function useId(): string { stackError: new Error(), value: id, debugInfo: null, - dispatcherMethodName: 'useId', - wrapperNames: ['useId'], + dispatcherHookName: 'Id', + wrapperNames: ['Id'], }); return id; } @@ -592,8 +592,8 @@ function useOptimistic( stackError: new Error(), value: state, debugInfo: null, - dispatcherMethodName: 'useOptimistic', - wrapperNames: ['useOptimistic'], + dispatcherHookName: 'Optimistic', + wrapperNames: ['Optimistic'], }); return [state, (action: A) => {}]; } @@ -653,8 +653,8 @@ function useFormState( stackError: stackError, value: value, debugInfo: debugInfo, - dispatcherMethodName: 'useFormState', - wrapperNames: ['useFormState'], + dispatcherHookName: 'FormState', + wrapperNames: ['FormState'], }); if (error !== null) { @@ -724,8 +724,8 @@ function useActionState( stackError: stackError, value: value, debugInfo: debugInfo, - dispatcherMethodName: 'useActionState', - wrapperNames: ['useActionState'], + dispatcherHookName: 'ActionState', + wrapperNames: ['ActionState'], }); if (error !== null) { @@ -755,10 +755,10 @@ function useHostTransitionStatus(): TransitionStatus { stackError: new Error(), value: status, debugInfo: null, - dispatcherMethodName: 'useHostTransitionStatus', + dispatcherHookName: 'HostTransitionStatus', wrapperNames: [ // react-dom - 'useFormStatus', + 'FormStatus', ], }); @@ -890,16 +890,7 @@ function findCommonAncestorIndex(rootStack: any, hookStack: any) { } function isReactWrapper(functionName: any, wrapperName: string) { - if (!functionName) { - return false; - } - if (functionName.length < wrapperName.length) { - return false; - } - return ( - functionName.lastIndexOf(wrapperName) === - functionName.length - wrapperName.length - ); + return parseHookName(functionName) === wrapperName; } function findPrimitiveIndex(hookStack: any, hook: HookLogEntry) { @@ -915,7 +906,7 @@ function findPrimitiveIndex(hookStack: any, hook: HookLogEntry) { // This prohibits nesting dispatcher calls in hooks. if ( i < hookStack.length - 1 && - isReactWrapper(hookStack[i].functionName, hook.dispatcherMethodName) + isReactWrapper(hookStack[i].functionName, hook.dispatcherHookName) ) { i++; } @@ -962,7 +953,15 @@ function parseHookName(functionName: void | string): string { if (!functionName) { return ''; } - let startIndex = functionName.lastIndexOf('.'); + let startIndex = functionName.lastIndexOf('[as '); + + if (startIndex !== -1) { + // Workaround for sourcemaps in Jest and Chrome. + // In `node --enable-source-maps`, we don't see "Object.useHostTransitionStatus [as useFormStatus]" but "Object.useFormStatus" + // "Object.useHostTransitionStatus [as useFormStatus]" -> "useFormStatus" + return parseHookName(functionName.slice(startIndex + '[as '.length, -1)); + } + startIndex = functionName.lastIndexOf('.'); if (startIndex === -1) { startIndex = 0; } else { @@ -997,7 +996,7 @@ function buildTree( parseHookName(primitiveFrame.functionName) || // Older versions of React do not have sourcemaps. // In those versions there was always a 1:1 mapping between wrapper and dispatcher method. - parseHookName(hook.dispatcherMethodName); + parseHookName(hook.dispatcherHookName); } if (stack !== null) { // Note: The indices 0 <= n < length-1 will contain the names. diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js index 19511eb36adc1..752d93fa30ab8 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js @@ -38,8 +38,6 @@ describe('ReactHooksInspectionIntegration', () => { ReactDebugTools = require('react-debug-tools'); }); - // Gating production, non-source builds only for Jest. - // @gate source || build === "development" it('should support useFormStatus hook', async () => { function FormStatus() { const status = ReactDOM.useFormStatus();