Skip to content

Commit 9390298

Browse files
committed
[DevTools] Fix crash when inspecting Components suspended on data awaited in anonymous functions
1 parent b1b4b7b commit 9390298

File tree

3 files changed

+105
-18
lines changed

3 files changed

+105
-18
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// flow-typed signature: 132e48034ef4756600e1d98681a166b5
2+
// flow-typed version: c6154227d1/error-stack-parser_v2.x.x/flow_>=v0.104.x
3+
4+
declare module 'error-stack-parser' {
5+
declare interface StackFrame {
6+
constructor(object: StackFrame): StackFrame;
7+
8+
isConstructor?: boolean;
9+
getIsConstructor(): boolean;
10+
setIsConstructor(): void;
11+
12+
isEval?: boolean;
13+
getIsEval(): boolean;
14+
setIsEval(): void;
15+
16+
isNative?: boolean;
17+
getIsNative(): boolean;
18+
setIsNative(): void;
19+
20+
isTopLevel?: boolean;
21+
getIsTopLevel(): boolean;
22+
setIsTopLevel(): void;
23+
24+
columnNumber?: number;
25+
getColumnNumber(): number;
26+
setColumnNumber(): void;
27+
28+
lineNumber?: number;
29+
getLineNumber(): number;
30+
setLineNumber(): void;
31+
32+
fileName?: string;
33+
getFileName(): string;
34+
setFileName(): void;
35+
36+
functionName?: string;
37+
getFunctionName(): string;
38+
setFunctionName(): void;
39+
40+
source?: string;
41+
getSource(): string;
42+
setSource(): void;
43+
44+
args?: any[];
45+
getArgs(): any[];
46+
setArgs(): void;
47+
48+
evalOrigin?: StackFrame;
49+
getEvalOrigin(): StackFrame;
50+
setEvalOrigin(): void;
51+
52+
toString(): string;
53+
}
54+
55+
declare class ErrorStackParser {
56+
parse(error: Error): Array<StackFrame>;
57+
}
58+
59+
declare module.exports: ErrorStackParser;
60+
}

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* @flow
88
*/
9-
9+
import type {StackFrame as ParsedStackFrame} from 'error-stack-parser';
1010
import type {
1111
Awaited,
1212
ReactContext,
@@ -844,7 +844,11 @@ export type HooksTree = Array<HooksNode>;
844844

845845
let mostLikelyAncestorIndex = 0;
846846

847-
function findSharedIndex(hookStack: any, rootStack: any, rootIndex: number) {
847+
function findSharedIndex(
848+
hookStack: ParsedStackFrame[],
849+
rootStack: ParsedStackFrame[],
850+
rootIndex: number,
851+
) {
848852
const source = rootStack[rootIndex].source;
849853
hookSearch: for (let i = 0; i < hookStack.length; i++) {
850854
if (hookStack[i].source === source) {
@@ -865,7 +869,10 @@ function findSharedIndex(hookStack: any, rootStack: any, rootIndex: number) {
865869
return -1;
866870
}
867871

868-
function findCommonAncestorIndex(rootStack: any, hookStack: any) {
872+
function findCommonAncestorIndex(
873+
rootStack: ParsedStackFrame[],
874+
hookStack: ParsedStackFrame[],
875+
) {
869876
let rootIndex = findSharedIndex(
870877
hookStack,
871878
rootStack,
@@ -886,7 +893,7 @@ function findCommonAncestorIndex(rootStack: any, hookStack: any) {
886893
return -1;
887894
}
888895

889-
function isReactWrapper(functionName: any, wrapperName: string) {
896+
function isReactWrapper(functionName: void | string, wrapperName: string) {
890897
const hookName = parseHookName(functionName);
891898
if (wrapperName === 'HostTransitionStatus') {
892899
return hookName === wrapperName || hookName === 'FormStatus';
@@ -895,7 +902,7 @@ function isReactWrapper(functionName: any, wrapperName: string) {
895902
return hookName === wrapperName;
896903
}
897904

898-
function findPrimitiveIndex(hookStack: any, hook: HookLogEntry) {
905+
function findPrimitiveIndex(hookStack: ParsedStackFrame[], hook: HookLogEntry) {
899906
const stackCache = getPrimitiveStackCache();
900907
const primitiveStack = stackCache.get(hook.primitive);
901908
if (primitiveStack === undefined) {
@@ -926,7 +933,7 @@ function findPrimitiveIndex(hookStack: any, hook: HookLogEntry) {
926933
return -1;
927934
}
928935

929-
function parseTrimmedStack(rootStack: any, hook: HookLogEntry) {
936+
function parseTrimmedStack(rootStack: ParsedStackFrame[], hook: HookLogEntry) {
930937
// Get the stack trace between the primitive hook function and
931938
// the root function call. I.e. the stack frames of custom hooks.
932939
const hookStack = ErrorStackParser.parse(hook.stackError);
@@ -987,7 +994,7 @@ function parseHookName(functionName: void | string): string {
987994
}
988995

989996
function buildTree(
990-
rootStack: any,
997+
rootStack: ParsedStackFrame[],
991998
readHookLog: Array<HookLogEntry>,
992999
): HooksTree {
9931000
const rootChildren: Array<HooksNode> = [];
@@ -1044,10 +1051,20 @@ function buildTree(
10441051
subHooks: children,
10451052
debugInfo: null,
10461053
hookSource: {
1047-
lineNumber: stackFrame.lineNumber,
1048-
columnNumber: stackFrame.columnNumber,
1049-
functionName: stackFrame.functionName,
1050-
fileName: stackFrame.fileName,
1054+
lineNumber:
1055+
stackFrame.lineNumber === undefined
1056+
? null
1057+
: stackFrame.lineNumber,
1058+
columnNumber:
1059+
stackFrame.columnNumber === undefined
1060+
? null
1061+
: stackFrame.columnNumber,
1062+
functionName:
1063+
stackFrame.functionName === undefined
1064+
? null
1065+
: stackFrame.functionName,
1066+
fileName:
1067+
stackFrame.fileName === undefined ? null : stackFrame.fileName,
10511068
},
10521069
};
10531070

@@ -1092,10 +1109,14 @@ function buildTree(
10921109
};
10931110
if (stack && stack.length >= 1) {
10941111
const stackFrame = stack[0];
1095-
hookSource.lineNumber = stackFrame.lineNumber;
1096-
hookSource.functionName = stackFrame.functionName;
1097-
hookSource.fileName = stackFrame.fileName;
1098-
hookSource.columnNumber = stackFrame.columnNumber;
1112+
hookSource.lineNumber =
1113+
stackFrame.lineNumber === undefined ? null : stackFrame.lineNumber;
1114+
hookSource.functionName =
1115+
stackFrame.functionName === undefined ? null : stackFrame.functionName;
1116+
hookSource.fileName =
1117+
stackFrame.fileName === undefined ? null : stackFrame.fileName;
1118+
hookSource.columnNumber =
1119+
stackFrame.columnNumber === undefined ? null : stackFrame.columnNumber;
10991120
}
11001121

11011122
levelChild.hookSource = hookSource;
@@ -1201,7 +1222,10 @@ export function inspectHooks<Props>(
12011222
// $FlowFixMe[incompatible-use] found when upgrading Flow
12021223
currentDispatcher.H = previousDispatcher;
12031224
}
1204-
const rootStack = ErrorStackParser.parse(ancestorStackError);
1225+
const rootStack =
1226+
ancestorStackError === undefined
1227+
? ([] as ParsedStackFrame[])
1228+
: ErrorStackParser.parse(ancestorStackError);
12051229
return buildTree(rootStack, readHookLog);
12061230
}
12071231

@@ -1249,7 +1273,10 @@ function inspectHooksOfForwardRef<Props, Ref>(
12491273
hookLog = [];
12501274
currentDispatcher.H = previousDispatcher;
12511275
}
1252-
const rootStack = ErrorStackParser.parse(ancestorStackError);
1276+
const rootStack =
1277+
ancestorStackError === undefined
1278+
? ([] as ParsedStackFrame[])
1279+
: ErrorStackParser.parse(ancestorStackError);
12531280
return buildTree(rootStack, readHookLog);
12541281
}
12551282

packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ describe('ReactHooksInspection', () => {
752752
"hookSource": {
753753
"columnNumber": 0,
754754
"fileName": "**",
755-
"functionName": undefined,
755+
"functionName": null,
756756
"lineNumber": 0,
757757
},
758758
"id": null,

0 commit comments

Comments
 (0)