Skip to content

Commit 5a97093

Browse files
authored
fix[devtools]: feature-check structure stack trace methods (#35293)
`Error.prepareStackTrace` is non-standard feature and not all JavaScript runtimes implement the methods that we are using in React DevTools backend. This PR adds additional checks for the presence of the methods that we are using.
1 parent 5d80124 commit 5a97093

File tree

1 file changed

+47
-13
lines changed

1 file changed

+47
-13
lines changed

packages/react-devtools-shared/src/backend/utils/parseStackTrace.js

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,41 +154,73 @@ function collectStackTrace(
154154
// We mirror how V8 serializes stack frames and how we later parse them.
155155
for (let i = framesToSkip; i < structuredStackTrace.length; i++) {
156156
const callSite = structuredStackTrace[i];
157-
let name = callSite.getFunctionName() || '<anonymous>';
157+
let name =
158+
// $FlowFixMe[method-unbinding]
159+
typeof callSite.getFunctionName === 'function'
160+
? callSite.getFunctionName() || '<anonymous>'
161+
: '';
158162
if (
159163
name.includes('react_stack_bottom_frame') ||
160164
name.includes('react-stack-bottom-frame')
161165
) {
162166
// Skip everything after the bottom frame since it'll be internals.
163167
break;
164-
} else if (callSite.isNative()) {
165-
// $FlowFixMe[prop-missing]
166-
const isAsync = callSite.isAsync();
168+
// $FlowFixMe[method-unbinding]
169+
} else if (typeof callSite.isNative === 'function' && callSite.isNative()) {
170+
const isAsync =
171+
// $FlowFixMe[prop-missing]
172+
// $FlowFixMe[incompatible-use]
173+
typeof callSite.isAsync === 'function' && callSite.isAsync();
167174
result.push([name, '', 0, 0, 0, 0, isAsync]);
168175
} else {
169176
// We encode complex function calls as if they're part of the function
170177
// name since we cannot simulate the complex ones and they look the same
171178
// as function names in UIs on the client as well as stacks.
172-
if (callSite.isConstructor()) {
179+
if (
180+
// $FlowFixMe[method-unbinding]
181+
typeof callSite.isConstructor === 'function' &&
182+
callSite.isConstructor()
183+
) {
173184
name = 'new ' + name;
174-
} else if (!callSite.isToplevel()) {
185+
} else if (
186+
// $FlowFixMe[method-unbinding]
187+
typeof callSite.isToplevel === 'function' &&
188+
!callSite.isToplevel()
189+
) {
175190
name = getMethodCallName(callSite);
176191
}
177192
if (name === '<anonymous>') {
178193
name = '';
179194
}
180-
let filename = callSite.getScriptNameOrSourceURL() || '<anonymous>';
195+
let filename =
196+
// $FlowFixMe[method-unbinding]
197+
typeof callSite.getScriptNameOrSourceURL === 'function'
198+
? callSite.getScriptNameOrSourceURL() || '<anonymous>'
199+
: '';
181200
if (filename === '<anonymous>') {
182201
filename = '';
183-
if (callSite.isEval()) {
184-
const origin = callSite.getEvalOrigin();
202+
// $FlowFixMe[method-unbinding]
203+
if (typeof callSite.isEval === 'function' && callSite.isEval()) {
204+
const origin =
205+
// $FlowFixMe[method-unbinding]
206+
typeof callSite.getEvalOrigin === 'function'
207+
? callSite.getEvalOrigin()
208+
: null;
185209
if (origin) {
186210
filename = origin.toString() + ', <anonymous>';
187211
}
188212
}
189213
}
190-
const line = callSite.getLineNumber() || 0;
191-
const col = callSite.getColumnNumber() || 0;
214+
const line =
215+
// $FlowFixMe[method-unbinding]
216+
(typeof callSite.getLineNumber === 'function' &&
217+
callSite.getLineNumber()) ||
218+
0;
219+
const col =
220+
// $FlowFixMe[method-unbinding]
221+
(typeof callSite.getColumnNumber === 'function' &&
222+
callSite.getColumnNumber()) ||
223+
0;
192224
const enclosingLine: number =
193225
// $FlowFixMe[prop-missing]
194226
typeof callSite.getEnclosingLineNumber === 'function'
@@ -199,8 +231,10 @@ function collectStackTrace(
199231
typeof callSite.getEnclosingColumnNumber === 'function'
200232
? (callSite: any).getEnclosingColumnNumber() || 0
201233
: 0;
202-
// $FlowFixMe[prop-missing]
203-
const isAsync = callSite.isAsync();
234+
const isAsync =
235+
// $FlowFixMe[prop-missing]
236+
// $FlowFixMe[incompatible-use]
237+
typeof callSite.isAsync === 'function' && callSite.isAsync();
204238
result.push([
205239
name,
206240
filename,

0 commit comments

Comments
 (0)