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