Add InvalidJS error severity
Lauren Tan committed
Jun 28, 2023 at 11:43 UTC
dda59d093a9dae733f674ba91557a2ac7c1cb61b
4 files changed
+56
-37
compiler/forget/apps/playground/lib/forgetMonacoDiagnostics.ts
+2
-3
@@ -19,10 +19,9 @@ function mapForgetSeverityToMonaco(
19
): MarkerSeverity {
20
switch (level) {
21
case ErrorSeverity.Todo:
22
- case ErrorSeverity.InvalidInput:
23
- return monaco.MarkerSeverity.Error;
24
- default:
22
return monaco.MarkerSeverity.Warning;
23
+ default:
24
+ return monaco.MarkerSeverity.Error;
25
}
26
}
27
compiler/forget/packages/babel-plugin-react-forget/src/CompilerError.ts
+5
-5
@@ -10,9 +10,9 @@ import { assertExhaustive } from "./Utils/utils";
10
11
export enum ErrorSeverity {
12
/**
13
- * Unexpected syntax or input that may not be safe to compile.
13
+ * Invalid JS syntax, or valid syntax that is semantically invalid which may indicate some misunderstanding on the user’s part.
14
*/
15
- InvalidInput = "InvalidInput",
15
+ InvalidJS = "InvalidJS",
16
/**
17
* Code that breaks the rules of React.
18
*/
@@ -132,14 +132,14 @@ export class CompilerError extends Error {
132
throw errors;
133
}
134
135
- static invalidInput(
135
+ static invalidJS(
136
options: Omit<CompilerErrorDetailOptions, "severity">
137
): never {
138
const errors = new CompilerError();
139
errors.pushErrorDetail(
140
new CompilerErrorDetail({
141
...options,
142
- severity: ErrorSeverity.InvalidInput,
142
+ severity: ErrorSeverity.InvalidJS,
143
})
144
);
145
throw errors;
@@ -215,7 +215,7 @@ export class CompilerError extends Error {
215
return this.details.some((detail) => {
216
switch (detail.severity) {
217
case ErrorSeverity.Invariant:
218
- case ErrorSeverity.InvalidInput:
218
+ case ErrorSeverity.InvalidJS:
219
case ErrorSeverity.InvalidReact:
220
case ErrorSeverity.InvalidConfig:
221
return true;
compiler/forget/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts
+42
-25
@@ -8,7 +8,11 @@
8
import { NodePath, Scope } from "@babel/traverse";
9
import * as t from "@babel/types";
10
import { Expression } from "@babel/types";
11
-import { CompilerError, ErrorSeverity } from "../CompilerError";
11
+import {
12
+ CompilerError,
13
+ CompilerSuggestionOperation,
14
+ ErrorSeverity,
15
+} from "../CompilerError";
16
import { Err, Ok, Result } from "../Utils/Result";
17
import { assertExhaustive } from "../Utils/utils";
18
import { Environment } from "./Environment";
@@ -142,8 +146,8 @@ export function lower(
146
lowerStatement(builder, body);
147
} else {
148
builder.errors.push({
145
- reason: `(BuildHIR::lower) Unexpected function body kind: ${body.type}}`,
146
- severity: ErrorSeverity.InvalidInput,
149
+ reason: `Unexpected function body kind: ${body.type}}. This error is likely caused by a bug in React Forget. Please file an issue`,
150
+ severity: ErrorSeverity.InvalidJS,
151
loc: body.node.loc ?? null,
152
suggestions: null,
153
});
@@ -541,9 +545,8 @@ function lowerStatement(
545
if (testExpr.node == null) {
546
if (hasDefault) {
547
builder.errors.push({
544
- reason:
545
- "(BuildHIR::lowerStatement) Expected at most one `default` branch in SwitchStatement, this code should have failed to parse",
546
- severity: ErrorSeverity.InvalidInput,
548
+ reason: `Expected at most one \`default\` branch in SwitchStatement, this code should have failed to parse. This error is likely caused by a bug in React Forget. Please file an issue`,
549
+ severity: ErrorSeverity.InvalidJS,
550
loc: case_.node.loc ?? null,
551
suggestions: null,
552
});
@@ -659,11 +662,19 @@ function lowerStatement(
662
};
663
if (builder.isContextIdentifier(id)) {
664
if (kind === InstructionKind.Const) {
665
+ const declRangeStart = declaration.parentPath.node.start!;
666
builder.errors.push({
663
- reason: `(BuildHIR::lowerAssignment) Invalid declaration kind (const) for variable later reassigned.`,
664
- severity: ErrorSeverity.InvalidInput,
667
+ reason: `Invalid declaration kind (const), this variable is reassigned later`,
668
+ severity: ErrorSeverity.InvalidJS,
669
loc: id.node.loc ?? null,
666
- suggestions: null,
670
+ suggestions: [
671
+ {
672
+ description: "Change to let",
673
+ op: CompilerSuggestionOperation.Replace,
674
+ range: [declRangeStart, declRangeStart + 5], // "const".length
675
+ text: "let",
676
+ },
677
+ ],
678
});
679
}
680
lowerValueToTemporary(builder, {
@@ -687,8 +698,8 @@ function lowerStatement(
698
}
699
} else {
700
builder.errors.push({
690
- reason: `(BuildHIR::lowerStatement) Expected variable declaration to be an identifier if no initializer was provided.`,
691
- severity: ErrorSeverity.InvalidInput,
701
+ reason: `Expected variable declaration to be an identifier if no initializer was provided. This error is likely caused by a bug in React Forget. Please file an issue`,
702
+ severity: ErrorSeverity.InvalidJS,
703
loc: stmt.node.loc ?? null,
704
suggestions: null,
705
});
@@ -1109,8 +1120,8 @@ function lowerExpression(
1120
const calleePath = expr.get("callee");
1121
if (!calleePath.isExpression()) {
1122
builder.errors.push({
1112
- reason: `(BuildHIR::lowerExpression) Expected Expression, got ${calleePath.type} in NewExpression (v8 intrinsics not supported): ${calleePath.type}`,
1113
- severity: ErrorSeverity.Todo,
1123
+ reason: `Expected Expression, got ${calleePath.type} in NewExpression (v8 intrinsics not supported): ${calleePath.type}. This error is likely caused by a bug in React Forget. Please file an issue`,
1124
+ severity: ErrorSeverity.InvalidJS,
1125
loc: calleePath.node.loc ?? null,
1126
suggestions: null,
1127
});
@@ -1135,7 +1146,7 @@ function lowerExpression(
1146
const calleePath = expr.get("callee");
1147
if (!calleePath.isExpression()) {
1148
builder.errors.push({
1138
- reason: `(BuildHIR::lowerExpression) Expected Expression, got ${calleePath.type} in CallExpression (v8 intrinsics not supported)`,
1149
+ reason: `Expected Expression, got ${calleePath.type} in CallExpression (v8 intrinsics not supported). This error is likely caused by a bug in React Forget. Please file an issue`,
1150
severity: ErrorSeverity.Todo,
1151
loc: calleePath.node.loc ?? null,
1152
suggestions: null,
@@ -1201,8 +1212,8 @@ function lowerExpression(
1212
}
1213
if (last === null) {
1214
builder.errors.push({
1204
- reason: `(BuildHIR::lowerExpression) Expected SequenceExpression to have at least one expression`,
1205
- severity: ErrorSeverity.InvalidInput,
1215
+ reason: `Expected SequenceExpression to have at least one expression. This error is likely caused by a bug in React Forget. Please file an issue`,
1216
+ severity: ErrorSeverity.InvalidJS,
1217
loc: expr.node.loc ?? null,
1218
suggestions: null,
1219
});
@@ -1658,8 +1669,8 @@ function lowerExpression(
1669
1670
if (subexprs.length !== quasis.length - 1) {
1671
builder.errors.push({
1661
- reason: `(BuildHIR::lowerExpression) Unexpected quasi and subexpression lengths in TemplateLiteral.`,
1662
- severity: ErrorSeverity.InvalidInput,
1672
+ reason: `Unexpected quasi and subexpression lengths in TemplateLiteral. This error is likely caused by a bug in React Forget. Please file an issue`,
1673
+ severity: ErrorSeverity.InvalidJS,
1674
loc: exprPath.node.loc ?? null,
1675
suggestions: null,
1676
});
@@ -1710,10 +1721,16 @@ function lowerExpression(
1721
}
1722
} else {
1723
builder.errors.push({
1713
- reason: `(BuildHIR::lowerExpression) delete on a non-member expression has no semantic meaning`,
1714
- severity: ErrorSeverity.InvalidInput,
1724
+ reason: `Deleting a non-member expression has no semantic meaning`,
1725
+ severity: ErrorSeverity.InvalidJS,
1726
loc: expr.node.loc ?? null,
1716
- suggestions: null,
1727
+ suggestions: [
1728
+ {
1729
+ description: "Remove this line",
1730
+ range: [expr.node.start!, expr.node.end!],
1731
+ op: CompilerSuggestionOperation.Remove,
1732
+ },
1733
+ ],
1734
});
1735
return { kind: "UnsupportedNode", node: expr.node, loc: exprLoc };
1736
}
@@ -2291,8 +2308,8 @@ function lowerJsxElementName(
2308
const tag = `${namespace}:${name}`;
2309
if (namespace.indexOf(":") !== -1 || name.indexOf(":") !== -1) {
2310
builder.errors.push({
2294
- reason: `(BuildHIR::lowerJsxElementName) Expected JSXNamespacedName to have no colons in the namespace or name, got '${namespace}' : '${name}'`,
2295
- severity: ErrorSeverity.InvalidInput,
2311
+ reason: `Expected JSXNamespacedName to have no colons in the namespace or name, got '${namespace}' : '${name}'. This error is likely caused by a bug in React Forget. Please file an issue`,
2312
+ severity: ErrorSeverity.InvalidJS,
2313
loc: exprPath.node.loc ?? null,
2314
suggestions: null,
2315
});
@@ -2585,8 +2602,8 @@ function lowerAssignment(
2602
if (kind !== InstructionKind.Reassign) {
2603
if (kind === InstructionKind.Const) {
2604
builder.errors.push({
2588
- reason: `(BuildHIR::lowerAssignment) Invalid declaration kind (const) for variable later reassigned.`,
2589
- severity: ErrorSeverity.InvalidInput,
2605
+ reason: `Invalid declaration kind (const), this variable is reassigned later`,
2606
+ severity: ErrorSeverity.InvalidJS,
2607
loc: lvalue.node.loc ?? null,
2608
suggestions: null,
2609
});
compiler/forget/packages/eslint-plugin-react-forget/src/rules/ReactForgetDiagnostics.ts
+7
-4
@@ -32,19 +32,22 @@ function isReactForgetCompilerError(err: Error): err is CompilerError {
32
function isReportableDiagnostic(
33
detail: CompilerErrorDetail
34
): detail is CompilerErrorDetailWithLoc {
35
- let isCorrectSeverity = false;
35
+ let isReportable = false;
36
switch (detail.severity) {
37
case ErrorSeverity.InvalidReact:
38
- case ErrorSeverity.InvalidInput:
39
- isCorrectSeverity = true;
38
+ case ErrorSeverity.InvalidJS:
39
+ isReportable = true;
40
break;
41
+ case ErrorSeverity.InvalidConfig:
42
case ErrorSeverity.Invariant:
43
case ErrorSeverity.Todo:
44
break;
45
+ default:
46
+ assertExhaustive(detail.severity, "Unhandled error severity");
47
}
48
49
return (
47
- isCorrectSeverity === true &&
50
+ isReportable === true &&
51
detail.loc != null &&
52
typeof detail.loc !== "symbol"
53
);