63
}
64
}
65
66
+// We add a suffix to some frames that older versions of React didn't do.
67
+// To compare if it's equivalent we strip out the suffix to see if they're
68
+// still equivalent. Similarly, we sometimes use [] and sometimes () so we
69
+// strip them to for the comparison.
70
+const frameDiffs = / \(\<anonymous\>\)$|\@unknown\:0\:0$|\(|\)|\[|\]/gm;
71
+function areStackTracesEqual(a: string, b: string): boolean {
72
+ return a.replace(frameDiffs, '') === b.replace(frameDiffs, '');
73
+}
74
+
75
function restorePotentiallyModifiedArgs(args: Array<any>): Array<any> {
76
// If the arguments don't have any styles applied, then just copy
77
if (!isStrictModeOverride(args)) {
213
214
// $FlowFixMe[missing-local-annot]
215
const overrideMethod = (...args) => {
207
- let shouldAppendWarningStack = false;
208
- if (method !== 'log') {
209
- if (consoleSettingsRef.appendComponentStack) {
210
- const lastArg = args.length > 0 ? args[args.length - 1] : null;
211
- const alreadyHasComponentStack =
212
- typeof lastArg === 'string' && isStringComponentStack(lastArg);
213
-
214
- // If we are ever called with a string that already has a component stack,
215
- // e.g. a React error/warning, don't append a second stack.
216
- shouldAppendWarningStack = !alreadyHasComponentStack;
217
- }
216
+ let alreadyHasComponentStack = false;
217
+ if (method !== 'log' && consoleSettingsRef.appendComponentStack) {
218
+ const lastArg = args.length > 0 ? args[args.length - 1] : null;
219
+ alreadyHasComponentStack =
220
+ typeof lastArg === 'string' && isStringComponentStack(lastArg); // The last argument should be a component stack.
221
}
222
223
const shouldShowInlineWarningsAndErrors =
247
}
248
249
if (
247
- shouldAppendWarningStack &&
250
+ consoleSettingsRef.appendComponentStack &&
251
!supportsNativeConsoleTasks(current)
252
) {
253
const componentStack = getStackByFiberInDevAndProd(
256
(currentDispatcherRef: any),
257
);
258
if (componentStack !== '') {
256
- if (isStrictModeOverride(args)) {
257
- if (__IS_FIREFOX__) {
258
- args[0] = `${args[0]} %s`;
259
- args.push(componentStack);
260
- } else {
261
- args[0] =
262
- ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK;
263
- args.push(componentStack);
259
+ // Create a fake Error so that when we print it we get native source maps. Every
260
+ // browser will print the .stack property of the error and then parse it back for source
261
+ // mapping. Rather than print the internal slot. So it doesn't matter that the internal
262
+ // slot doesn't line up.
263
+ const fakeError = new Error('');
264
+ // In Chromium, only the stack property is printed but in Firefox the <name>:<message>
265
+ // gets printed so to make the colon make sense, we name it so we print Component Stack:
266
+ // and similarly Safari leave an expandable slot.
267
+ fakeError.name = 'Component Stack'; // This gets printed
268
+ // In Chromium, the stack property needs to start with ^[\w.]*Error\b to trigger stack
269
+ // formatting. Otherwise it is left alone. So we prefix it. Otherwise we just override it
270
+ // to our own stack.
271
+ fakeError.stack =
272
+ __IS_CHROME__ || __IS_EDGE__
273
+ ? 'Error Component Stack:' + componentStack
274
+ : componentStack;
275
+ if (alreadyHasComponentStack) {
276
+ // Only modify the component stack if it matches what we would've added anyway.
277
+ // Otherwise we assume it was a non-React stack.
278
+ if (isStrictModeOverride(args)) {
279
+ // We do nothing to Strict Mode overrides that already has a stack
280
+ // because we have already lost some context for how to format it
281
+ // since we've already merged the stack into the log at this point.
282
+ } else if (
283
+ areStackTracesEqual(
284
+ args[args.length - 1],
285
+ componentStack,
286
+ )
287
+ ) {
288
+ const firstArg = args[0];
289
+ if (
290
+ args.length > 1 &&
291
+ typeof firstArg === 'string' &&
292
+ firstArg.endsWith('%s')
293
+ ) {
294
+ args[0] = firstArg.slice(0, firstArg.length - 2); // Strip the %s param
295
+ }
296
+ args[args.length - 1] = fakeError;
297
}
298
} else {
266
- args.push(componentStack);
299
+ args.push(fakeError);
300
+ if (isStrictModeOverride(args)) {
301
+ if (__IS_FIREFOX__) {
302
+ args[0] = `${args[0]} %o`;
303
+ } else {
304
+ args[0] =
305
+ ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK;
306
+ }
307
+ }
308
}
309
}
310
}