Skip to content

Commit fa4f23e

Browse files
cpojerfacebook-github-bot
authored andcommitted
Add codeFrame to each warning and error in LogBox
Summary: This diff changes the LogBox to show the code frame for the first non-collapsed stack frame. Let me know what you think about this change! Changelog: [Internal] LogBox changes Reviewed By: rickhanlonii Differential Revision: D18372456 fbshipit-source-id: ddf6d6c53ab28d11d8355f4cb1cb071a00a7366e
1 parent 5eddf1d commit fa4f23e

7 files changed

Lines changed: 67 additions & 24 deletions

File tree

Libraries/Core/Devtools/symbolicateStackTrace.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,27 @@ let fetch;
1919

2020
import type {StackFrame} from '../NativeExceptionsManager';
2121

22+
export type CodeFrame = $ReadOnly<{|
23+
content: string,
24+
location: {
25+
row: number,
26+
column: number,
27+
},
28+
fileName: string,
29+
|}>;
30+
31+
export type SymbolicatedStackTrace = $ReadOnly<{|
32+
stack: Array<StackFrame>,
33+
codeFrame: ?CodeFrame,
34+
|}>;
35+
2236
function isSourcedFromDisk(sourcePath: string): boolean {
2337
return !/^http/.test(sourcePath) && /[\\/]/.test(sourcePath);
2438
}
2539

2640
async function symbolicateStackTrace(
2741
stack: Array<StackFrame>,
28-
): Promise<Array<StackFrame>> {
42+
): Promise<SymbolicatedStackTrace> {
2943
// RN currently lazy loads whatwg-fetch using a custom fetch module, which,
3044
// when called for the first time, requires and re-exports 'whatwg-fetch'.
3145
// However, when a dependency of the project tries to require whatwg-fetch
@@ -74,8 +88,7 @@ async function symbolicateStackTrace(
7488
method: 'POST',
7589
body: JSON.stringify({stack: stackCopy}),
7690
});
77-
const json = await response.json();
78-
return json.stack;
91+
return await response.json();
7992
}
8093

8194
module.exports = symbolicateStackTrace;

Libraries/Core/ExceptionsManager.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ function reportException(e: ExtendedError, isFatal: boolean) {
116116
}
117117
const symbolicateStackTrace = require('./Devtools/symbolicateStackTrace');
118118
symbolicateStackTrace(stack)
119-
.then(prettyStack => {
119+
.then(({stack: prettyStack}) => {
120120
if (prettyStack) {
121121
NativeExceptionsManager.updateExceptionMessage(
122122
data.message,

Libraries/Core/__tests__/ExceptionsManager-test.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ describe('ExceptionsManager', () => {
3939
};
4040
});
4141
// Make symbolication a no-op.
42-
jest.mock('../Devtools/symbolicateStackTrace', () => {
43-
return async function symbolicateStackTrace(stack) {
44-
return stack;
45-
};
46-
});
42+
jest.mock(
43+
'../Devtools/symbolicateStackTrace',
44+
() =>
45+
async function symbolicateStackTrace(stack) {
46+
return {stack};
47+
},
48+
);
4749
jest.spyOn(console, 'error').mockImplementation(() => {});
4850
ReactFiberErrorDialog = require('../ReactFiberErrorDialog');
4951
NativeExceptionsManager = require('../NativeExceptionsManager').default;

Libraries/LogBox/Data/LogBoxLog.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,33 @@ class LogBoxLog {
8282
let aborted = false;
8383

8484
if (this.symbolicated.status !== 'COMPLETE') {
85-
const updateStatus = (error: ?Error, stack: ?Stack): void => {
85+
const updateStatus = (
86+
error: ?Error,
87+
stack: ?Stack,
88+
codeFrame: ?CodeFrame,
89+
): void => {
8690
if (error != null) {
87-
this.symbolicated = {error, stack: null, status: 'FAILED'};
91+
this.symbolicated = {
92+
error,
93+
stack: null,
94+
status: 'FAILED',
95+
};
8896
} else if (stack != null) {
89-
this.symbolicated = {error: null, stack, status: 'COMPLETE'};
97+
if (codeFrame) {
98+
this.codeFrame = codeFrame;
99+
}
100+
101+
this.symbolicated = {
102+
error: null,
103+
stack,
104+
status: 'COMPLETE',
105+
};
90106
} else {
91-
this.symbolicated = {error: null, stack: null, status: 'PENDING'};
107+
this.symbolicated = {
108+
error: null,
109+
stack: null,
110+
status: 'PENDING',
111+
};
92112
}
93113
if (!aborted) {
94114
if (callback != null) {
@@ -99,8 +119,8 @@ class LogBoxLog {
99119

100120
updateStatus(null, null);
101121
LogBoxSymbolication.symbolicate(this.stack).then(
102-
stack => {
103-
updateStatus(null, stack);
122+
data => {
123+
updateStatus(null, data?.stack, data?.codeFrame);
104124
},
105125
error => {
106126
updateStatus(error, null);

Libraries/LogBox/Data/LogBoxSymbolication.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@
1313
import symbolicateStackTrace from '../../Core/Devtools/symbolicateStackTrace';
1414

1515
import type {StackFrame} from '../../Core/NativeExceptionsManager';
16+
import type {SymbolicatedStackTrace} from '../../Core/Devtools/symbolicateStackTrace';
1617

1718
export type Stack = Array<StackFrame>;
1819

19-
const cache: Map<Stack, Promise<Stack>> = new Map();
20+
const cache: Map<Stack, Promise<SymbolicatedStackTrace>> = new Map();
2021

2122
/**
2223
* Sanitize because sometimes, `symbolicateStackTrace` gives us invalid values.
2324
*/
24-
const sanitize = (maybeStack: mixed): Stack => {
25+
const sanitize = ({
26+
stack: maybeStack,
27+
codeFrame,
28+
}: SymbolicatedStackTrace): SymbolicatedStackTrace => {
2529
if (!Array.isArray(maybeStack)) {
2630
throw new Error('Expected stack to be an array.');
2731
}
@@ -58,14 +62,14 @@ const sanitize = (maybeStack: mixed): Stack => {
5862
collapse,
5963
});
6064
}
61-
return stack;
65+
return {stack, codeFrame};
6266
};
6367

6468
export function deleteStack(stack: Stack): void {
6569
cache.delete(stack);
6670
}
6771

68-
export function symbolicate(stack: Stack): Promise<Stack> {
72+
export function symbolicate(stack: Stack): Promise<SymbolicatedStackTrace> {
6973
let promise = cache.get(stack);
7074
if (promise == null) {
7175
promise = symbolicateStackTrace(stack).then(sanitize);

Libraries/LogBox/Data/__tests__/LogBoxLog-test.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'use strict';
1313

1414
import type {StackFrame} from '../../../Core/NativeExceptionsManager';
15+
import type {SymbolicatedStackTrace} from '../../../Core/Devtools/symbolicateStackTrace';
1516

1617
jest.mock('../LogBoxSymbolication', () => {
1718
return {__esModule: true, symbolicate: jest.fn(), deleteStack: jest.fn()};
@@ -35,7 +36,7 @@ function getLogBoxLog() {
3536
function getLogBoxSymbolication(): {|
3637
symbolicate: JestMockFn<
3738
$ReadOnlyArray<Array<StackFrame>>,
38-
Promise<Array<StackFrame>>,
39+
Promise<SymbolicatedStackTrace>,
3940
>,
4041
|} {
4142
return (require('../LogBoxSymbolication'): any);
@@ -53,9 +54,10 @@ describe('LogBoxLog', () => {
5354
beforeEach(() => {
5455
jest.resetModules();
5556

56-
getLogBoxSymbolication().symbolicate.mockImplementation(async stack =>
57-
createStack(stack.map(frame => `S(${frame.methodName})`)),
58-
);
57+
getLogBoxSymbolication().symbolicate.mockImplementation(async stack => ({
58+
stack: createStack(stack.map(frame => `S(${frame.methodName})`)),
59+
codeFrame: null,
60+
}));
5961
});
6062

6163
it('creates a LogBoxLog object', () => {

Libraries/YellowBox/Data/YellowBoxSymbolication.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
const symbolicateStackTrace = require('../../Core/Devtools/symbolicateStackTrace');
1414

1515
import type {StackFrame} from '../../Core/NativeExceptionsManager';
16+
import type {SymbolicatedStackTrace} from '../../Core/Devtools/symbolicateStackTrace';
1617

1718
type CacheKey = string;
1819

@@ -45,7 +46,8 @@ const getCacheKey = (stack: Stack): CacheKey => {
4546
/**
4647
* Sanitize because sometimes, `symbolicateStackTrace` gives us invalid values.
4748
*/
48-
const sanitize = (maybeStack: mixed): Stack => {
49+
const sanitize = (data: SymbolicatedStackTrace): Stack => {
50+
const maybeStack = data?.stack;
4951
if (!Array.isArray(maybeStack)) {
5052
throw new Error('Expected stack to be an array.');
5153
}

0 commit comments

Comments
 (0)