2019-10-22 07:05:47 +03:00
|
|
|
/**
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*
|
2019-12-06 02:58:55 +03:00
|
|
|
* @flow strict-local
|
2019-10-22 07:05:47 +03:00
|
|
|
* @format
|
|
|
|
*/
|
|
|
|
|
|
|
|
import UTFSequence from '../../UTFSequence';
|
|
|
|
import stringifySafe from '../../Utilities/stringifySafe';
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
import type {ExceptionData} from '../../Core/NativeExceptionsManager';
|
2019-11-13 22:30:43 +03:00
|
|
|
import type {LogBoxLogData} from './LogBoxLog';
|
2020-07-28 23:06:03 +03:00
|
|
|
import parseErrorStack from '../../Core/Devtools/parseErrorStack';
|
2019-10-22 07:05:47 +03:00
|
|
|
|
2019-11-27 19:28:01 +03:00
|
|
|
const BABEL_TRANSFORM_ERROR_FORMAT = /^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;
|
2020-03-09 15:58:55 +03:00
|
|
|
const BABEL_CODE_FRAME_ERROR_FORMAT = /^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;
|
2020-02-25 15:32:21 +03:00
|
|
|
const METRO_ERROR_FORMAT = /^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;
|
2019-11-27 19:28:01 +03:00
|
|
|
|
2019-11-21 20:38:13 +03:00
|
|
|
export type ExtendedExceptionData = ExceptionData & {
|
|
|
|
isComponentError: boolean,
|
|
|
|
...
|
|
|
|
};
|
2019-10-22 07:05:47 +03:00
|
|
|
export type Category = string;
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
export type CodeFrame = $ReadOnly<{|
|
|
|
|
content: string,
|
2019-11-27 19:28:01 +03:00
|
|
|
location: ?{
|
2019-11-07 20:10:13 +03:00
|
|
|
row: number,
|
|
|
|
column: number,
|
2019-11-21 20:38:13 +03:00
|
|
|
...
|
2019-11-07 20:10:13 +03:00
|
|
|
},
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
fileName: string,
|
2020-07-28 23:06:03 +03:00
|
|
|
|
|
|
|
// TODO: When React switched to using call stack frames,
|
|
|
|
// we gained the ability to use the collapse flag, but
|
|
|
|
// it is not integrated into the LogBox UI.
|
|
|
|
collapse?: boolean,
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
|}>;
|
2019-10-22 07:05:47 +03:00
|
|
|
export type Message = $ReadOnly<{|
|
|
|
|
content: string,
|
|
|
|
substitutions: $ReadOnlyArray<
|
|
|
|
$ReadOnly<{|
|
|
|
|
length: number,
|
|
|
|
offset: number,
|
|
|
|
|}>,
|
|
|
|
>,
|
|
|
|
|}>;
|
|
|
|
|
2019-12-10 21:06:57 +03:00
|
|
|
export type ComponentStack = $ReadOnlyArray<CodeFrame>;
|
2019-10-22 07:05:47 +03:00
|
|
|
|
|
|
|
const SUBSTITUTION = UTFSequence.BOM + '%s';
|
|
|
|
|
2020-02-21 20:30:56 +03:00
|
|
|
export function parseInterpolation(
|
2019-10-22 07:05:47 +03:00
|
|
|
args: $ReadOnlyArray<mixed>,
|
|
|
|
): $ReadOnly<{|
|
|
|
|
category: Category,
|
|
|
|
message: Message,
|
|
|
|
|}> {
|
|
|
|
const categoryParts = [];
|
|
|
|
const contentParts = [];
|
|
|
|
const substitutionOffsets = [];
|
|
|
|
|
|
|
|
const remaining = [...args];
|
|
|
|
if (typeof remaining[0] === 'string') {
|
|
|
|
const formatString = String(remaining.shift());
|
|
|
|
const formatStringParts = formatString.split('%s');
|
|
|
|
const substitutionCount = formatStringParts.length - 1;
|
|
|
|
const substitutions = remaining.splice(0, substitutionCount);
|
|
|
|
|
|
|
|
let categoryString = '';
|
|
|
|
let contentString = '';
|
|
|
|
|
|
|
|
let substitutionIndex = 0;
|
|
|
|
for (const formatStringPart of formatStringParts) {
|
|
|
|
categoryString += formatStringPart;
|
|
|
|
contentString += formatStringPart;
|
|
|
|
|
|
|
|
if (substitutionIndex < substitutionCount) {
|
|
|
|
if (substitutionIndex < substitutions.length) {
|
|
|
|
// Don't stringify a string type.
|
|
|
|
// It adds quotation mark wrappers around the string,
|
|
|
|
// which causes the LogBox to look odd.
|
|
|
|
const substitution =
|
|
|
|
typeof substitutions[substitutionIndex] === 'string'
|
|
|
|
? substitutions[substitutionIndex]
|
|
|
|
: stringifySafe(substitutions[substitutionIndex]);
|
|
|
|
substitutionOffsets.push({
|
|
|
|
length: substitution.length,
|
|
|
|
offset: contentString.length,
|
|
|
|
});
|
|
|
|
|
|
|
|
categoryString += SUBSTITUTION;
|
|
|
|
contentString += substitution;
|
|
|
|
} else {
|
|
|
|
substitutionOffsets.push({
|
|
|
|
length: 2,
|
|
|
|
offset: contentString.length,
|
|
|
|
});
|
|
|
|
|
|
|
|
categoryString += '%s';
|
|
|
|
contentString += '%s';
|
|
|
|
}
|
|
|
|
|
|
|
|
substitutionIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
categoryParts.push(categoryString);
|
|
|
|
contentParts.push(contentString);
|
|
|
|
}
|
|
|
|
|
2020-03-25 07:35:58 +03:00
|
|
|
const remainingArgs = remaining.map(arg => {
|
2019-10-22 07:05:47 +03:00
|
|
|
// Don't stringify a string type.
|
|
|
|
// It adds quotation mark wrappers around the string,
|
|
|
|
// which causes the LogBox to look odd.
|
|
|
|
return typeof arg === 'string' ? arg : stringifySafe(arg);
|
|
|
|
});
|
|
|
|
categoryParts.push(...remainingArgs);
|
|
|
|
contentParts.push(...remainingArgs);
|
|
|
|
|
|
|
|
return {
|
|
|
|
category: categoryParts.join(' '),
|
|
|
|
message: {
|
|
|
|
content: contentParts.join(' '),
|
|
|
|
substitutions: substitutionOffsets,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2019-12-10 21:06:57 +03:00
|
|
|
|
2020-07-28 23:06:03 +03:00
|
|
|
function isComponentStack(consoleArgument: string) {
|
2020-09-02 19:58:25 +03:00
|
|
|
const isOldComponentStackFormat = / {4}in/.test(consoleArgument);
|
|
|
|
const isNewComponentStackFormat = / {4}at/.test(consoleArgument);
|
2020-07-28 23:06:03 +03:00
|
|
|
const isNewJSCComponentStackFormat = /@.*\n/.test(consoleArgument);
|
|
|
|
|
|
|
|
return (
|
|
|
|
isOldComponentStackFormat ||
|
|
|
|
isNewComponentStackFormat ||
|
|
|
|
isNewJSCComponentStackFormat
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-11-01 02:22:38 +03:00
|
|
|
export function parseComponentStack(message: string): ComponentStack {
|
2020-07-28 23:06:03 +03:00
|
|
|
// In newer versions of React, the component stack is formatted as a call stack frame.
|
|
|
|
// First try to parse the component stack as a call stack frame, and if that doesn't
|
|
|
|
// work then we'll fallback to the old custom component stack format parsing.
|
|
|
|
const stack = parseErrorStack(message);
|
|
|
|
if (stack && stack.length > 0) {
|
|
|
|
return stack.map(frame => ({
|
|
|
|
content: frame.methodName,
|
|
|
|
collapse: frame.collapse || false,
|
|
|
|
fileName: frame.file == null ? 'unknown' : frame.file,
|
|
|
|
location: {
|
|
|
|
column: frame.column == null ? -1 : frame.column,
|
|
|
|
row: frame.lineNumber == null ? -1 : frame.lineNumber,
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2019-11-01 02:22:38 +03:00
|
|
|
return message
|
|
|
|
.split(/\n {4}in /g)
|
2020-03-25 07:35:58 +03:00
|
|
|
.map(s => {
|
2019-11-01 02:22:38 +03:00
|
|
|
if (!s) {
|
|
|
|
return null;
|
|
|
|
}
|
2019-12-10 21:06:57 +03:00
|
|
|
const match = s.match(/(.*) \(at (.*\.js):([\d]+)\)/);
|
|
|
|
if (!match) {
|
|
|
|
return null;
|
2019-11-01 02:22:38 +03:00
|
|
|
}
|
2019-12-10 21:06:57 +03:00
|
|
|
|
|
|
|
let [content, fileName, row] = match.slice(1);
|
|
|
|
return {
|
|
|
|
content,
|
|
|
|
fileName,
|
|
|
|
location: {column: -1, row: parseInt(row, 10)},
|
|
|
|
};
|
2019-11-01 02:22:38 +03:00
|
|
|
})
|
|
|
|
.filter(Boolean);
|
|
|
|
}
|
2019-10-22 07:05:47 +03:00
|
|
|
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
export function parseLogBoxException(
|
2019-11-13 22:30:43 +03:00
|
|
|
error: ExtendedExceptionData,
|
2019-11-13 22:30:43 +03:00
|
|
|
): LogBoxLogData {
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
const message =
|
|
|
|
error.originalMessage != null ? error.originalMessage : 'Unknown';
|
|
|
|
|
2020-02-25 15:32:21 +03:00
|
|
|
const metroInternalError = message.match(METRO_ERROR_FORMAT);
|
|
|
|
if (metroInternalError) {
|
|
|
|
const [
|
|
|
|
content,
|
|
|
|
fileName,
|
|
|
|
row,
|
|
|
|
column,
|
|
|
|
codeFrame,
|
|
|
|
] = metroInternalError.slice(1);
|
|
|
|
|
|
|
|
return {
|
|
|
|
level: 'fatal',
|
|
|
|
type: 'Metro Error',
|
|
|
|
stack: [],
|
|
|
|
isComponentError: false,
|
|
|
|
componentStack: [],
|
|
|
|
codeFrame: {
|
|
|
|
fileName,
|
|
|
|
location: {
|
|
|
|
row: parseInt(row, 10),
|
|
|
|
column: parseInt(column, 10),
|
|
|
|
},
|
|
|
|
content: codeFrame,
|
|
|
|
},
|
|
|
|
message: {
|
|
|
|
content,
|
|
|
|
substitutions: [],
|
|
|
|
},
|
|
|
|
category: `${fileName}-${row}-${column}`,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-11-27 19:28:01 +03:00
|
|
|
const babelTransformError = message.match(BABEL_TRANSFORM_ERROR_FORMAT);
|
|
|
|
if (babelTransformError) {
|
|
|
|
// Transform errors are thrown from inside the Babel transformer.
|
|
|
|
const [
|
|
|
|
fileName,
|
|
|
|
content,
|
|
|
|
row,
|
|
|
|
column,
|
|
|
|
codeFrame,
|
|
|
|
] = babelTransformError.slice(1);
|
|
|
|
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
return {
|
2019-11-27 19:28:01 +03:00
|
|
|
level: 'syntax',
|
|
|
|
stack: [],
|
|
|
|
isComponentError: false,
|
|
|
|
componentStack: [],
|
|
|
|
codeFrame: {
|
|
|
|
fileName,
|
|
|
|
location: {
|
|
|
|
row: parseInt(row, 10),
|
|
|
|
column: parseInt(column, 10),
|
|
|
|
},
|
|
|
|
content: codeFrame,
|
|
|
|
},
|
|
|
|
message: {
|
|
|
|
content,
|
|
|
|
substitutions: [],
|
|
|
|
},
|
|
|
|
category: `${fileName}-${row}-${column}`,
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-11-27 19:28:01 +03:00
|
|
|
const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
|
|
|
|
|
|
|
|
if (babelCodeFrameError) {
|
|
|
|
// Codeframe errors are thrown from any use of buildCodeFrameError.
|
|
|
|
const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
|
|
|
|
return {
|
|
|
|
level: 'syntax',
|
|
|
|
stack: [],
|
|
|
|
isComponentError: false,
|
|
|
|
componentStack: [],
|
|
|
|
codeFrame: {
|
|
|
|
fileName,
|
|
|
|
location: null, // We are not given the location.
|
|
|
|
content: codeFrame,
|
2019-11-07 20:10:13 +03:00
|
|
|
},
|
2019-11-27 19:28:01 +03:00
|
|
|
message: {
|
|
|
|
content,
|
|
|
|
substitutions: [],
|
|
|
|
},
|
|
|
|
category: `${fileName}-${1}-${1}`,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-04-02 02:40:37 +03:00
|
|
|
if (message.match(/^TransformError /)) {
|
|
|
|
return {
|
|
|
|
level: 'syntax',
|
|
|
|
stack: error.stack,
|
|
|
|
isComponentError: error.isComponentError,
|
|
|
|
componentStack: [],
|
|
|
|
message: {
|
|
|
|
content: message,
|
|
|
|
substitutions: [],
|
|
|
|
},
|
|
|
|
category: message,
|
|
|
|
};
|
|
|
|
}
|
2019-11-27 19:28:01 +03:00
|
|
|
|
2020-04-02 02:40:37 +03:00
|
|
|
const componentStack = error.componentStack;
|
|
|
|
if (error.isFatal || error.isComponentError) {
|
|
|
|
return {
|
|
|
|
level: 'fatal',
|
|
|
|
stack: error.stack,
|
|
|
|
isComponentError: error.isComponentError,
|
|
|
|
componentStack:
|
|
|
|
componentStack != null ? parseComponentStack(componentStack) : [],
|
|
|
|
...parseInterpolation([message]),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (componentStack != null) {
|
|
|
|
// It is possible that console errors have a componentStack.
|
|
|
|
return {
|
|
|
|
level: 'error',
|
|
|
|
stack: error.stack,
|
|
|
|
isComponentError: error.isComponentError,
|
|
|
|
componentStack: parseComponentStack(componentStack),
|
|
|
|
...parseInterpolation([message]),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Most `console.error` calls won't have a componentStack. We parse them like
|
|
|
|
// regular logs which have the component stack burried in the message.
|
2019-11-27 19:28:01 +03:00
|
|
|
return {
|
2020-04-02 02:40:37 +03:00
|
|
|
level: 'error',
|
2019-11-27 19:28:01 +03:00
|
|
|
stack: error.stack,
|
|
|
|
isComponentError: error.isComponentError,
|
2020-04-02 02:40:37 +03:00
|
|
|
...parseLogBoxLog([message]),
|
LogBox - Add syntax error handling
Summary:
This diff adds handling for syntax errors.
## Strategy
To do this we introduce a new log level type syntax, giving us these levels with semantics:
- `warn` - console warns, show collapsed, dismissible
- `error` - console errors, show collapsed, dismissible
- `fatal` - thrown exceptions, show expanded, not dismissible
- `syntax` - thrown exceptions for invalid syntax, show expanded, not dismissible
Syntax errors shows expanded, covers all other errors, and are only dismissible when the syntax error is fixed and updated with Fast Refresh. Once the syntax error is fixed, it reveals any previously covered fatals, errors, or warnings behind it
In many ways, this makes syntax errors the highest level error.
## Visuals
Syntax errors also have their own display formatting. Stack traces for syntax errors don't make sense, so we don't show them. Instead, we show the syntax error message and a code frame for the error.
The code frame is also updated so that is doesn't wrap and is horizontally scrollable, making it easier to read.
## Detecting syntax errors
To detect syntax errors we've updated `LogBoxData.addException` to call the parse function `parseLogBoxException`. This method will perform a regex on the error message to detect:
- file name
- location
- error message
- codeframe
If this regex fails for any reason to find all four parts, we'll fall back to a fatal. Over time we'll update this regex to be more robust and handle more cases we've missed.
Changelog: [Internal]
Reviewed By: motiz88
Differential Revision: D18278862
fbshipit-source-id: 59069aba38a27c44787e5248b2973c3a345c4a0a
2019-11-02 02:05:02 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-11-01 02:22:38 +03:00
|
|
|
export function parseLogBoxLog(
|
2019-10-22 07:05:47 +03:00
|
|
|
args: $ReadOnlyArray<mixed>,
|
2019-10-22 23:59:44 +03:00
|
|
|
): {|
|
2019-10-22 07:05:47 +03:00
|
|
|
componentStack: ComponentStack,
|
|
|
|
category: Category,
|
|
|
|
message: Message,
|
|
|
|
|} {
|
2019-11-19 00:45:59 +03:00
|
|
|
const message = args[0];
|
2019-10-22 23:59:44 +03:00
|
|
|
let argsWithoutComponentStack = [];
|
2019-11-19 00:45:59 +03:00
|
|
|
let componentStack = [];
|
|
|
|
|
|
|
|
// Extract component stack from warnings like "Some warning%s".
|
|
|
|
if (
|
|
|
|
typeof message === 'string' &&
|
|
|
|
message.slice(-2) === '%s' &&
|
|
|
|
args.length > 0
|
|
|
|
) {
|
|
|
|
const lastArg = args[args.length - 1];
|
2020-07-28 23:06:03 +03:00
|
|
|
if (typeof lastArg === 'string' && isComponentStack(lastArg)) {
|
2019-11-19 00:45:59 +03:00
|
|
|
argsWithoutComponentStack = args.slice(0, -1);
|
|
|
|
argsWithoutComponentStack[0] = message.slice(0, -2);
|
|
|
|
componentStack = parseComponentStack(lastArg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (componentStack.length === 0) {
|
|
|
|
// Try finding the component stack elsewhere.
|
|
|
|
for (const arg of args) {
|
2020-07-28 23:06:03 +03:00
|
|
|
if (typeof arg === 'string' && isComponentStack(arg)) {
|
2020-04-02 02:40:37 +03:00
|
|
|
// Strip out any messages before the component stack.
|
2020-07-28 23:06:03 +03:00
|
|
|
let messageEndIndex = arg.search(/\n {4}(in|at) /);
|
|
|
|
if (messageEndIndex < 0) {
|
|
|
|
// Handle JSC component stacks.
|
|
|
|
messageEndIndex = arg.search(/\n/);
|
|
|
|
}
|
2020-04-02 02:40:37 +03:00
|
|
|
if (messageEndIndex > 0) {
|
|
|
|
argsWithoutComponentStack.push(arg.slice(0, messageEndIndex));
|
|
|
|
}
|
|
|
|
|
2019-11-19 00:45:59 +03:00
|
|
|
componentStack = parseComponentStack(arg);
|
|
|
|
} else {
|
|
|
|
argsWithoutComponentStack.push(arg);
|
|
|
|
}
|
2019-10-22 07:05:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2020-02-21 20:30:56 +03:00
|
|
|
...parseInterpolation(argsWithoutComponentStack),
|
2019-10-22 07:05:47 +03:00
|
|
|
componentStack,
|
|
|
|
};
|
|
|
|
}
|