@samitouri / QOS-React-2 / commits / d44538ad96

Stop passing NodePaths to CompilerError

This was causing issues in various places where errors would be stringified. Because the inner detail objects would contain a NodePath with circular structures this would cause a JSON.stringify error in code outside of our control. This change makes it so we always print the codeframe from the NodePath and then passing the string.

Lauren Tan committed Jan 26, 2023 at 13:58 UTC d44538ad9654e048e5cfb53e874265bbf77a4391
5 files changed +98 -87
compiler/forget/packages/playground/lib/forgetMonacoDiagnostics.ts
+6 -6
@@ -23,18 +23,18 @@ function mapForgetDiagnosticToMonacoMarker(
23 detail: CompilerErrorDetail,
24 monaco: Monaco
25 ): editor.IMarkerData | null {
26 - if (detail.nodePath == null || detail.nodePath.node?.loc == null) {
26 + if (detail.loc == null) {
27 return null;
28 }
29 const severity = mapForgetSeverityToMonaco(detail.severity, monaco);
30 - let message = detail.errorMessage;
30 + let message = detail.printErrorMessage();
31 return {
32 severity,
33 message,
34 - startLineNumber: detail.nodePath.node.loc.start.line,
35 - startColumn: detail.nodePath.node.loc.start.column + 1,
36 - endLineNumber: detail.nodePath.node.loc.end.line,
37 - endColumn: detail.nodePath.node.loc.end.column + 1,
34 + startLineNumber: detail.loc.start.line,
35 + startColumn: detail.loc.start.column + 1,
36 + endLineNumber: detail.loc.end.line,
37 + endColumn: detail.loc.end.column + 1,
38 };
39 }
40
compiler/forget/src/CompilerError.ts
+33 -28
@@ -1,4 +1,6 @@
1 -import { Node, NodePath } from "@babel/core";
1 +import { Node, NodePath } from "@babel/traverse";
2 +import { SourceLocation } from "@babel/types";
3 +import { ExtractClassProperties } from "./Utils/types";
4 import { assertExhaustive } from "./Utils/utils";
5
6 export enum ErrorSeverity {
@@ -9,10 +11,11 @@ export enum ErrorSeverity {
11 export type CompilerErrorOptions = {
12 reason: string;
13 severity: ErrorSeverity;
12 - nodePath: AnyNodePath | null;
14 + nodePath: AnyNodePath;
15 };
16 type AnyNodePath = NodePath<Node | null | undefined>;
17 type CompilerErrorKind = typeof InvalidInputError | typeof TodoError;
18 +type CompilerErrorDetailOptions = ExtractClassProperties<CompilerErrorDetail>;
19
20 function mapSeverityToErrorCtor(severity: ErrorSeverity): CompilerErrorKind {
21 switch (severity) {
@@ -37,6 +40,22 @@ class TodoError extends Error {
40 }
41 }
42
43 +export function tryPrintCodeFrame(
44 + options: CompilerErrorOptions
45 +): string | null {
46 + if (options.nodePath == null) return null;
47 + try {
48 + return options.nodePath
49 + .buildCodeFrameError(
50 + options.reason,
51 + mapSeverityToErrorCtor(options.severity)
52 + )
53 + .toString();
54 + } catch {
55 + return null;
56 + }
57 +}
58 +
59 /**
60 * Each bailout or invariant in HIR lowering creates an {@link CompilerErrorDetail}, which is then
61 * aggregated into a single {@link CompilerError} later.
@@ -44,43 +63,29 @@ class TodoError extends Error {
63 export class CompilerErrorDetail {
64 reason: string;
65 severity: ErrorSeverity;
47 - /**
48 - * If a NodePath is provided, we will prefer Babel's built in codeframe error generation which
49 - * will print error markers in the correct location.
50 - */
51 - nodePath: AnyNodePath | null;
66 + codeframe: string | null;
67 + loc: SourceLocation | null;
68
53 - constructor(options: CompilerErrorOptions) {
69 + constructor(options: CompilerErrorDetailOptions) {
70 this.reason = options.reason;
71 this.severity = options.severity;
56 - this.nodePath = options.nodePath;
72 + this.codeframe = options.codeframe;
73 + this.loc = options.loc;
74 }
75
59 - get errorMessage(): string {
76 + printErrorMessage(): string {
77 + if (this.codeframe != null) {
78 + return this.codeframe;
79 + }
80 const buffer = [`${this.severity}: ${this.reason}`];
61 - if (this.nodePath != null && this.nodePath.node?.loc != null) {
62 - buffer.push(
63 - ` (${this.nodePath.node.loc.start.line}:${this.nodePath.node.loc.end.line})`
64 - );
81 + if (this.loc != null) {
82 + buffer.push(` (${this.loc.start.line}:${this.loc.end.line})`);
83 }
84 return buffer.join("");
85 }
86
69 - get codeFrame() {
70 - if (this.nodePath == null) {
71 - return this.errorMessage;
72 - }
73 - try {
74 - return this.nodePath
75 - .buildCodeFrameError(this.reason, mapSeverityToErrorCtor(this.severity))
76 - .toString();
77 - } catch {
78 - return this.errorMessage;
79 - }
80 - }
81 -
87 toString(): string {
83 - return `[ReactForget] ${this.errorMessage}`;
88 + return `[ReactForget] ${this.printErrorMessage()}`;
89 }
90 }
91
compiler/forget/src/HIR/BuildHIR.ts
+42 -42
@@ -73,7 +73,7 @@ export function lower(
73 };
74 params.push(place);
75 } else {
76 - builder.pushError({
76 + builder.recordError({
77 reason: `(BuildHIR::lower) Handle ${param.node.type} params`,
78 severity: ErrorSeverity.Todo,
79 nodePath: param,
@@ -94,7 +94,7 @@ export function lower(
94 } else if (body.isBlockStatement()) {
95 lowerStatement(builder, body);
96 } else {
97 - builder.pushError({
97 + builder.recordError({
98 reason: `(BuildHIR::lower) Unexpected function body kind: ${body.type}}`,
99 severity: ErrorSeverity.InvalidInput,
100 nodePath: body,
@@ -341,7 +341,7 @@ function lowerStatement(
341 const initBlock = builder.enter("value", (blockId) => {
342 const init = stmt.get("init");
343 if (!init.isVariableDeclaration()) {
344 - builder.pushError({
344 + builder.recordError({
345 reason:
346 "(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement",
347 severity: ErrorSeverity.Todo,
@@ -361,7 +361,7 @@ function lowerStatement(
361 const updateBlock = builder.enter("value", (blockId) => {
362 const update = stmt.get("update");
363 if (update.node == null) {
364 - builder.pushError({
364 + builder.recordError({
365 reason: `(BuildHIR::lowerStatement) Handle empty update in ForStatement`,
366 severity: ErrorSeverity.Todo,
367 nodePath: stmt,
@@ -404,7 +404,7 @@ function lowerStatement(
404
405 const test = stmt.get("test");
406 if (test.node == null) {
407 - builder.pushError({
407 + builder.recordError({
408 reason: `(BuildHIR::lowerStatement) Handle empty test in ForStatement`,
409 severity: ErrorSeverity.Todo,
410 nodePath: stmt,
@@ -573,7 +573,7 @@ function lowerStatement(
573 const test = case_.get("test");
574 if (test.node == null) {
575 if (hasDefault) {
576 - builder.pushError({
576 + builder.recordError({
577 reason:
578 "(BuildHIR::lowerStatement) Expected at most one `default` branch in SwitchStatement, this code should have failed to parse",
579 severity: ErrorSeverity.InvalidInput,
@@ -659,7 +659,7 @@ function lowerStatement(
659 const stmt = stmtPath as NodePath<t.VariableDeclaration>;
660 const nodeKind: string = stmt.node.kind;
661 if (nodeKind === "var") {
662 - builder.pushError({
662 + builder.recordError({
663 reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`,
664 severity: ErrorSeverity.Todo,
665 nodePath: stmt,
@@ -742,7 +742,7 @@ function lowerStatement(
742 case "TSNamespaceExportDeclaration":
743 case "TSTypeAliasDeclaration":
744 case "WithStatement": {
745 - builder.pushError({
745 + builder.recordError({
746 reason: `(BuildHIR::lowerStatement) Handle ${stmtPath.type} statements`,
747 severity: ErrorSeverity.Todo,
748 nodePath: stmtPath,
@@ -814,7 +814,7 @@ function lowerExpression(
814 let hasError = false;
815 for (const propertyPath of propertyPaths) {
816 if (!propertyPath.isObjectProperty()) {
817 - builder.pushError({
817 + builder.recordError({
818 reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.type} properties in ObjectExpression`,
819 severity: ErrorSeverity.Todo,
820 nodePath: propertyPath,
@@ -824,7 +824,7 @@ function lowerExpression(
824 }
825 const key = propertyPath.node.key;
826 if (key.type !== "Identifier") {
827 - builder.pushError({
827 + builder.recordError({
828 reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
829 severity: ErrorSeverity.InvalidInput,
830 nodePath: propertyPath,
@@ -834,7 +834,7 @@ function lowerExpression(
834 }
835 const valuePath = propertyPath.get("value");
836 if (!valuePath.isExpression()) {
837 - builder.pushError({
837 + builder.recordError({
838 reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`,
839 severity: ErrorSeverity.Todo,
840 nodePath: valuePath,
@@ -859,7 +859,7 @@ function lowerExpression(
859 let elements: Place[] = [];
860 for (const element of expr.get("elements")) {
861 if (element.node == null || !element.isExpression()) {
862 - builder.pushError({
862 + builder.recordError({
863 reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`,
864 severity: ErrorSeverity.Todo,
865 nodePath: element,
@@ -883,7 +883,7 @@ function lowerExpression(
883 const expr = exprPath as NodePath<t.NewExpression>;
884 const calleePath = expr.get("callee");
885 if (!calleePath.isExpression()) {
886 - builder.pushError({
886 + builder.recordError({
887 reason: `(BuildHIR::lowerExpression) Expected Expression, got ${calleePath.type} in NewExpression (v8 intrinsics not supported): ${calleePath.type}`,
888 severity: ErrorSeverity.InvalidInput,
889 nodePath: calleePath,
@@ -895,7 +895,7 @@ function lowerExpression(
895 let hasError = false;
896 for (const argPath of expr.get("arguments")) {
897 if (!argPath.isExpression()) {
898 - builder.pushError({
898 + builder.recordError({
899 reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in NewExpression`,
900 severity: ErrorSeverity.Todo,
901 nodePath: argPath,
@@ -920,7 +920,7 @@ function lowerExpression(
920 const calleePath = expr.get("callee");
921 let hasError = false;
922 if (!calleePath.isExpression()) {
923 - builder.pushError({
923 + builder.recordError({
924 reason: `(BuildHIR::lowerExpression) Expected Expression, got ${calleePath.type} in CallExpression (v8 intrinsics not supported)`,
925 severity: ErrorSeverity.InvalidInput,
926 nodePath: calleePath,
@@ -935,7 +935,7 @@ function lowerExpression(
935 let args: Place[] = [];
936 for (const argPath of expr.get("arguments")) {
937 if (!argPath.isExpression()) {
938 - builder.pushError({
938 + builder.recordError({
939 reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`,
940 severity: ErrorSeverity.Todo,
941 nodePath: argPath,
@@ -967,7 +967,7 @@ function lowerExpression(
967 let args: Place[] = [];
968 for (const argPath of expr.get("arguments")) {
969 if (!argPath.isExpression()) {
970 - builder.pushError({
970 + builder.recordError({
971 reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`,
972 severity: ErrorSeverity.Todo,
973 nodePath: argPath,
@@ -991,7 +991,7 @@ function lowerExpression(
991 const expr = exprPath as NodePath<t.BinaryExpression>;
992 const leftPath = expr.get("left");
993 if (!leftPath.isExpression()) {
994 - builder.pushError({
994 + builder.recordError({
995 reason: `(BuildHIR::lowerExpression) Expected Expression, got ${leftPath.type} lval in BinaryExpression`,
996 severity: ErrorSeverity.InvalidInput,
997 nodePath: leftPath,
@@ -1115,7 +1115,7 @@ function lowerExpression(
1115 };
1116 const binaryOperator = operators[operator];
1117 if (binaryOperator == null) {
1118 - builder.pushError({
1118 + builder.recordError({
1119 reason: `(BuildHIR::lowerExpression) Handle ${operator} operaators in AssignmentExpression`,
1120 severity: ErrorSeverity.Todo,
1121 nodePath: expr.get("operator"),
@@ -1154,7 +1154,7 @@ function lowerExpression(
1154 // Extract the final property to be read from and re-assigned, eg 'c'
1155 const property = leftExpr.get("property");
1156 if (!property.isIdentifier()) {
1157 - builder.pushError({
1157 + builder.recordError({
1158 reason: `(BuildHIR::lowerExpression) Handle ${property.type} properties in MemberExpression`,
1159 severity: ErrorSeverity.Todo,
1160 nodePath: property,
@@ -1213,7 +1213,7 @@ function lowerExpression(
1213 };
1214 }
1215 default: {
1216 - builder.pushError({
1216 + builder.recordError({
1217 reason: `(BuildHIR::lowerExpression) Expected Identifier or MemberExpression, got ${expr.type} lval in AssignmentExpression`,
1218 severity: ErrorSeverity.InvalidInput,
1219 nodePath: expr,
@@ -1248,7 +1248,7 @@ function lowerExpression(
1248 let hasError = false;
1249 for (const attribute of opening.get("attributes")) {
1250 if (!attribute.isJSXAttribute()) {
1251 - builder.pushError({
1251 + builder.recordError({
1252 reason: `(BuildHIR::lowerExpression) Handle ${attribute.type} attributes in JSXElement`,
1253 severity: ErrorSeverity.Todo,
1254 nodePath: attribute,
@@ -1258,7 +1258,7 @@ function lowerExpression(
1258 }
1259 const name = attribute.get("name");
1260 if (!name.isJSXIdentifier()) {
1261 - builder.pushError({
1261 + builder.recordError({
1262 reason: `(BuildHIR::lowerExpression) Handle ${name.type} attribute names in JSXElement`,
1263 severity: ErrorSeverity.Todo,
1264 nodePath: name,
@@ -1272,7 +1272,7 @@ function lowerExpression(
1272 value = lowerExpressionToPlace(builder, valueExpr);
1273 } else {
1274 if (!valueExpr.isJSXExpressionContainer()) {
1275 - builder.pushError({
1275 + builder.recordError({
1276 reason: `(BuildHIR::lowerExpression) Handle ${valueExpr.type} attribute values in JSXElement`,
1277 severity: ErrorSeverity.Todo,
1278 nodePath: valueExpr,
@@ -1282,7 +1282,7 @@ function lowerExpression(
1282 }
1283 const expression = valueExpr.get("expression");
1284 if (!expression.isExpression()) {
1285 - builder.pushError({
1285 + builder.recordError({
1286 reason: `(BuildHIR::lowerExpression) Handle ${expression.type} expressions in JSXExpressionContainer within JSXElement`,
1287 severity: ErrorSeverity.Todo,
1288 nodePath: valueExpr,
@@ -1334,7 +1334,7 @@ function lowerExpression(
1334 const lowering = lower(expr);
1335 let loweredFunc: HIRFunction;
1336 if (lowering.isErr()) {
1337 - lowering.unwrapErr().forEach((e) => builder.pushError(e));
1337 + lowering.unwrapErr().forEach((e) => builder.pushErrorDetail(e));
1338 return {
1339 kind: "UnsupportedNode",
1340 node: exprNode,
@@ -1347,7 +1347,7 @@ function lowerExpression(
1347 const params: Array<string> = [];
1348 for (const p of expr.get("params")) {
1349 if (!p.isIdentifier()) {
1350 - builder.pushError({
1350 + builder.recordError({
1351 reason: `(BuildHIR::lowerExpression) Handle ${p.type} params in FunctionExpression`,
1352 severity: ErrorSeverity.Todo,
1353 nodePath: p,
@@ -1373,7 +1373,7 @@ function lowerExpression(
1373 case "TaggedTemplateExpression": {
1374 const expr = exprPath as NodePath<t.TaggedTemplateExpression>;
1375 if (expr.get("quasi").get("expressions").length !== 0) {
1376 - builder.pushError({
1376 + builder.recordError({
1377 reason: "Unhandled tagged template with interpolations",
1378 severity: ErrorSeverity.Todo,
1379 nodePath: exprPath,
@@ -1387,7 +1387,7 @@ function lowerExpression(
1387
1388 const value = expr.get("quasi").get("quasis").at(0)!.node.value;
1389 if (value.raw !== value.cooked) {
1390 - builder.pushError({
1390 + builder.recordError({
1391 reason:
1392 "Unhandled tagged template where cooked value is different from raw value",
1393 severity: ErrorSeverity.Todo,
@@ -1413,7 +1413,7 @@ function lowerExpression(
1413 };
1414 }
1415 default: {
1416 - builder.pushError({
1416 + builder.recordError({
1417 reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`,
1418 severity: ErrorSeverity.Todo,
1419 nodePath: exprPath,
@@ -1433,7 +1433,7 @@ function lowerMemberExpression(
1433 const property = expr.get("property");
1434 if (!expr.node.computed) {
1435 if (!property.isIdentifier()) {
1436 - builder.pushError({
1436 + builder.recordError({
1437 reason: `(BuildHIR::lowerExpression) Handle ${property.type} property`,
1438 severity: ErrorSeverity.Todo,
1439 nodePath: property,
@@ -1454,7 +1454,7 @@ function lowerMemberExpression(
1454 return { object, property: property.node.name, value };
1455 } else {
1456 if (!property.isExpression()) {
1457 - builder.pushError({
1457 + builder.recordError({
1458 reason: `(BuildHIR::lowerMemberExpression) Expected Expression, got ${property.type} property`,
1459 severity: ErrorSeverity.InvalidInput,
1460 nodePath: property,
@@ -1543,7 +1543,7 @@ function lowerJsxElementName(
1543 const exprNode = exprPath.node;
1544 const exprLoc = exprNode.loc ?? GeneratedSource;
1545 if (!exprPath.isJSXIdentifier()) {
1546 - builder.pushError({
1546 + builder.recordError({
1547 reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`,
1548 severity: ErrorSeverity.Todo,
1549 nodePath: exprPath,
@@ -1604,7 +1604,7 @@ function lowerJsxElement(
1604 } else if (exprPath.isJSXExpressionContainer()) {
1605 const expression = exprPath.get("expression");
1606 if (!expression.isExpression()) {
1607 - builder.pushError({
1607 + builder.recordError({
1608 reason: `(BuildHIR::lowerJsxElement) Handle ${expression.type} expressions`,
1609 severity: ErrorSeverity.Todo,
1610 nodePath: expression,
@@ -1638,7 +1638,7 @@ function lowerJsxElement(
1638 return place;
1639 } else {
1640 if (!(t.isJSXFragment(exprNode) || t.isJSXSpreadChild(exprNode))) {
1641 - builder.pushError({
1641 + builder.recordError({
1642 reason: `(BuildHIR::lowerJsxElement) Expected refinement to work, got: ${exprPath.type}`,
1643 severity: ErrorSeverity.InvalidInput,
1644 nodePath: exprPath,
@@ -1765,7 +1765,7 @@ function lowerAssignment(
1765 }
1766 if (!lvalue.node.computed) {
1767 if (!property.isIdentifier()) {
1768 - builder.pushError({
1768 + builder.recordError({
1769 reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in MemberExpression`,
1770 severity: ErrorSeverity.Todo,
1771 nodePath: property,
@@ -1781,7 +1781,7 @@ function lowerAssignment(
1781 };
1782 } else {
1783 if (!property.isExpression()) {
1784 - builder.pushError({
1784 + builder.recordError({
1785 reason:
1786 "Expected private name to appear as a non-computed property",
1787 severity: ErrorSeverity.InvalidInput,
@@ -1816,7 +1816,7 @@ function lowerAssignment(
1816 continue;
1817 }
1818 if (element.node.type === "RestElement") {
1819 - builder.pushError({
1819 + builder.recordError({
1820 reason: `(BuildHIR::lowerAssignment) Handle ${element.type} in ArrayPattern`,
1821 severity: ErrorSeverity.Todo,
1822 nodePath: element,
@@ -1864,7 +1864,7 @@ function lowerAssignment(
1864 for (let i = 0; i < properties.length; i++) {
1865 const property = properties[i];
1866 if (!property.isObjectProperty()) {
1867 - builder.pushError({
1867 + builder.recordError({
1868 reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in ObjectPattern`,
1869 severity: ErrorSeverity.Todo,
1870 nodePath: property,
@@ -1874,7 +1874,7 @@ function lowerAssignment(
1874 }
1875 const key = property.get("key");
1876 if (!key.isIdentifier()) {
1877 - builder.pushError({
1877 + builder.recordError({
1878 reason: `(BuildHIR::lowerAssignment) Handle ${key.type} keys in ObjectPattern`,
1879 severity: ErrorSeverity.Todo,
1880 nodePath: key,
@@ -1884,7 +1884,7 @@ function lowerAssignment(
1884 }
1885 const element = property.get("value");
1886 if (!element.isLVal()) {
1887 - builder.pushError({
1887 + builder.recordError({
1888 reason: `(BuildHIR::lowerAssignment) Expected object property value to be an LVal, got: ${element.type}`,
1889 severity: ErrorSeverity.InvalidInput,
1890 nodePath: element,
@@ -1906,7 +1906,7 @@ function lowerAssignment(
1906 : objectPlace;
1907 }
1908 default: {
1909 - builder.pushError({
1909 + builder.recordError({
1910 reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`,
1911 severity: ErrorSeverity.Todo,
1912 nodePath: lvaluePath,
compiler/forget/src/HIR/HIRBuilder.ts
+16 -3
@@ -8,7 +8,11 @@
8 import { NodePath } from "@babel/traverse";
9 import * as t from "@babel/types";
10 import invariant from "invariant";
11 -import { CompilerErrorDetail, CompilerErrorOptions } from "../CompilerError";
11 +import {
12 + CompilerErrorDetail,
13 + CompilerErrorOptions,
14 + tryPrintCodeFrame,
15 +} from "../CompilerError";
16 import { logHIR } from "../Utils/logger";
17 import { assertExhaustive } from "../Utils/utils";
18 import { getOrAddGlobal } from "./Globals";
@@ -415,8 +419,17 @@ export default class HIRBuilder {
419 invariant(false, "Expected a loop to be in scope");
420 }
421
418 - pushError(options: CompilerErrorOptions): CompilerErrorDetail {
419 - const detail = new CompilerErrorDetail(options);
422 + recordError(options: CompilerErrorOptions): CompilerErrorDetail {
423 + const detail = new CompilerErrorDetail({
424 + reason: options.reason,
425 + severity: options.severity,
426 + codeframe: tryPrintCodeFrame(options),
427 + loc: options.nodePath?.node?.loc ?? null,
428 + });
429 + return this.pushErrorDetail(detail);
430 + }
431 +
432 + pushErrorDetail(detail: CompilerErrorDetail): CompilerErrorDetail {
433 this.errors.push(detail);
434 return detail;
435 }
compiler/forget/src/__tests__/hir-test.ts
+1 -8
@@ -10,7 +10,6 @@
10 import { wasmFolder } from "@hpcc-js/wasm";
11 import path from "path";
12 import runReactForgetBabelPlugin from "../Babel/RunReactForgetBabelPlugin";
13 -import { CompilerError } from "../CompilerError";
13 import { toggleLogging } from "../Utils/logger";
14 import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
15
@@ -99,13 +98,7 @@ ${outputs.join("\n")}
98 });
99
100 function formatErrorOutput(error: Error): string {
102 - if (error instanceof CompilerError) {
103 - error.message = error.details
104 - .map((detail) => `[ReactForget] ${detail.codeFrame}`)
105 - .join("\n\n");
106 - } else {
107 - error.message = error.message.replace(/^\/.*?:\s/, "");
108 - }
101 + error.message = error.message.replace(/^\/.*?:\s/, "");
102 return `
103 ## Error
104