Skip to content

Commit

Permalink
Organize component stack regexes better (#43371)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #43371

This file has a lot of regexes, let's organize and comment them all.

Changelog: [Internal]

Reviewed By: yungsters

Differential Revision: D54638520

fbshipit-source-id: eed61133758ccefd2a640f121c4da214bcad4880
  • Loading branch information
rickhanlonii authored and facebook-github-bot committed Mar 8, 2024
1 parent adaf5eb commit ed32b4b
Showing 1 changed file with 68 additions and 21 deletions.
89 changes: 68 additions & 21 deletions packages/react-native/Libraries/LogBox/Data/parseLogBoxLog.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,62 @@ import ansiRegex from 'ansi-regex';

const ANSI_REGEX = ansiRegex().source;

const BABEL_TRANSFORM_ERROR_FORMAT =
const RE_TRANSFORM_ERROR = /^TransformError /;
const RE_COMPONENT_STACK_LINE = /\n {4}(in|at) /;
const RE_COMPONENT_STACK_LINE_GLOBAL = /\n {4}(in|at) /g;
const RE_COMPONENT_STACK_LINE_OLD = / {4}in/;
const RE_COMPONENT_STACK_LINE_NEW = / {4}at/;
const RE_COMPONENT_STACK_LINE_STACK_FRAME = /@.*\n/;

// "TransformError " (Optional) and either "SyntaxError: " or "ReferenceError: "
// Capturing groups:
// 1: error message
// 2: file path
// 3: line number
// 4: column number
// \n\n
// 5: code frame
const RE_BABEL_TRANSFORM_ERROR_FORMAT =
/^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;

// Capturing groups:
// 1: component name
// "at"
// 2: file path including extension
// 3: line number
const RE_COMPONENT_STACK_WITH_SOURCE =
/(.*) \(at (.*\.(?:js|jsx|ts|tsx)):([\d]+)\)/;

// Capturing groups:
// 1: component name
// "at"
// 2: parent component name
const RE_COMPONENT_STACK_NO_SOURCE = /(.*) \(created by .*\)/;

// Capturing groups:
// - non-capturing "TransformError " (optional)
// - non-capturing Error message
// 1: file path
// 2: file name
// 3: error message
// 4: code frame, which includes code snippet indicators or terminal escape sequences for formatting.
const RE_BABEL_CODE_FRAME_ERROR_FORMAT =
// eslint-disable-next-line no-control-regex
/^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;

// Capturing groups:
// - non-capturing "InternalError Metro has encountered an error:"
// 1: error title
// 2: error message
// 3: file path
// 4: line number
// 5: column number
// 6: code frame, which includes code snippet indicators or terminal escape sequences for formatting.
const RE_METRO_ERROR_FORMAT =
/^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;

// https://github.com/babel/babel/blob/33dbb85e9e9fe36915273080ecc42aee62ed0ade/packages/babel-code-frame/src/index.ts#L183-L184
const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
const RE_BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
[
// Beginning of a line (per 'm' flag)
'^',
Expand All @@ -42,13 +93,6 @@ const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
'm',
);

const BABEL_CODE_FRAME_ERROR_FORMAT =
// eslint-disable-next-line no-control-regex
/^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;

const METRO_ERROR_FORMAT =
/^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;

export type ExtendedExceptionData = ExceptionData & {
isComponentError: boolean,
...
Expand Down Expand Up @@ -158,9 +202,12 @@ export function parseInterpolation(args: $ReadOnlyArray<mixed>): $ReadOnly<{|
}

function isComponentStack(consoleArgument: string) {
const isOldComponentStackFormat = / {4}in/.test(consoleArgument);
const isNewComponentStackFormat = / {4}at/.test(consoleArgument);
const isNewJSCComponentStackFormat = /@.*\n/.test(consoleArgument);
const isOldComponentStackFormat =
RE_COMPONENT_STACK_LINE_OLD.test(consoleArgument);
const isNewComponentStackFormat =
RE_COMPONENT_STACK_LINE_NEW.test(consoleArgument);
const isNewJSCComponentStackFormat =
RE_COMPONENT_STACK_LINE_STACK_FRAME.test(consoleArgument);

return (
isOldComponentStackFormat ||
Expand All @@ -187,12 +234,12 @@ export function parseComponentStack(message: string): ComponentStack {
}

return message
.split(/\n {4}in /g)
.split(RE_COMPONENT_STACK_LINE_GLOBAL)
.map(s => {
if (!s) {
return null;
}
const match = s.match(/(.*) \(at (.*\.(?:js|jsx|ts|tsx)):([\d]+)\)/);
const match = s.match(RE_COMPONENT_STACK_WITH_SOURCE);
if (match) {
let [content, fileName, row] = match.slice(1);
return {
Expand All @@ -203,7 +250,7 @@ export function parseComponentStack(message: string): ComponentStack {
}

// In some cases, the component stack doesn't have a source.
const matchWithoutSource = s.match(/(.*) \(created by .*\)/);
const matchWithoutSource = s.match(RE_COMPONENT_STACK_NO_SOURCE);
if (matchWithoutSource) {
return {
content: matchWithoutSource[1],
Expand All @@ -223,7 +270,7 @@ export function parseLogBoxException(
const message =
error.originalMessage != null ? error.originalMessage : 'Unknown';

const metroInternalError = message.match(METRO_ERROR_FORMAT);
const metroInternalError = message.match(RE_METRO_ERROR_FORMAT);
if (metroInternalError) {
const [content, fileName, row, column, codeFrame] =
metroInternalError.slice(1);
Expand Down Expand Up @@ -251,7 +298,7 @@ export function parseLogBoxException(
};
}

const babelTransformError = message.match(BABEL_TRANSFORM_ERROR_FORMAT);
const babelTransformError = message.match(RE_BABEL_TRANSFORM_ERROR_FORMAT);
if (babelTransformError) {
// Transform errors are thrown from inside the Babel transformer.
const [fileName, content, row, column, codeFrame] =
Expand Down Expand Up @@ -281,8 +328,8 @@ export function parseLogBoxException(

// Perform a cheap match first before trying to parse the full message, which
// can get expensive for arbitrary input.
if (BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
if (RE_BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
const babelCodeFrameError = message.match(RE_BABEL_CODE_FRAME_ERROR_FORMAT);

if (babelCodeFrameError) {
// Codeframe errors are thrown from any use of buildCodeFrameError.
Expand All @@ -307,7 +354,7 @@ export function parseLogBoxException(
}
}

if (message.match(/^TransformError /)) {
if (message.match(RE_TRANSFORM_ERROR)) {
return {
level: 'syntax',
stack: error.stack,
Expand Down Expand Up @@ -386,7 +433,7 @@ export function parseLogBoxLog(args: $ReadOnlyArray<mixed>): {|
for (const arg of args) {
if (typeof arg === 'string' && isComponentStack(arg)) {
// Strip out any messages before the component stack.
let messageEndIndex = arg.search(/\n {4}(in|at) /);
let messageEndIndex = arg.search(RE_COMPONENT_STACK_LINE);
if (messageEndIndex < 0) {
// Handle JSC component stacks.
messageEndIndex = arg.search(/\n/);
Expand Down

0 comments on commit ed32b4b

Please sign in to comment.