@samitouri / QOS-React-2 / commits / 9c033a481d

[eslint-plugin] Only report on InvalidInput errors

Invariants aren't actionable by users, so we can omit reporting them in eslint as errors (while continuing to throw in the compiler itself)

Lauren Tan committed Jun 22, 2023 at 10:18 UTC 9c033a481d41252d88f05668723f7e061d37f562
4 files changed +47 -28
compiler/forget/packages/babel-plugin-react-forget/src/index.ts
+1 -1
@@ -19,7 +19,7 @@ export {
19 parsePluginOptions,
20 run,
21 } from "./Entrypoint";
22 -export { Effect, Hook, ValueKind, printHIR } from "./HIR";
22 +export { Effect, Hook, SourceLocation, ValueKind, printHIR } from "./HIR";
23 export { printReactiveFunction } from "./ReactiveScopes";
24
25 declare global {
compiler/forget/packages/eslint-plugin-react-forget/__tests__/ReactForgetDiagnostics-test.ts
+16 -25
@@ -41,6 +41,22 @@ const tests: ForgetTestCases = {
41 }
42 `,
43 },
44 + {
45 + // OK because invariants are only meant for the compiler team's consumption
46 + name: "[Invariant] Defined after use",
47 + code: normalizeIndent`
48 + function Component(props) {
49 + 'use forget';
50 + let y = function () {
51 + m(x);
52 + };
53 +
54 + let x = { a };
55 + m(x);
56 + return y;
57 + }
58 + `,
59 + },
60 ],
61 invalid: [
62 {
@@ -64,31 +80,6 @@ const tests: ForgetTestCases = {
80 },
81 ],
82 },
67 - {
68 - name: "[Invariant] Defined after use",
69 - code: normalizeIndent`
70 - function Component(props) {
71 - 'use forget';
72 - let y = function () {
73 - m(x);
74 - };
75 -
76 - let x = { a };
77 - m(x);
78 - return y;
79 - }
80 - `,
81 - errors: [
82 - {
83 - message:
84 - "[ReactForget] Invariant: EnterSSA: Expected identifier to be defined before being used. Identifier x$1 is undefined (8:8)",
85 - line: 8,
86 - column: 3,
87 - endColumn: 17,
88 - endLine: 8,
89 - },
90 - ],
91 - },
83 ],
84 };
85
compiler/forget/packages/eslint-plugin-react-forget/package.json
+1
@@ -30,6 +30,7 @@
30 "@babel/eslint-parser": "^7.19.1",
31 "@babel/preset-env": "^7.22.4",
32 "@babel/preset-typescript": "^7.18.6",
33 + "@babel/types": "^7.19.0",
34 "@types/node": "^20.2.5",
35 "babel-jest": "^29.0.3",
36 "eslint": "^8.19.0",
compiler/forget/packages/eslint-plugin-react-forget/src/rules/ReactForgetDiagnostics.ts
+29 -2
@@ -6,17 +6,44 @@
6 */
7
8 import { transformFromAstSync } from "@babel/core";
9 +import type { SourceLocation as BabelSourceLocation } from "@babel/types";
10 import ReactForgetBabelPlugin, {
10 - CompilerError,
11 + ErrorSeverity,
12 + type CompilerError,
13 + type CompilerErrorDetail,
14 type PluginOptions,
15 } from "babel-plugin-react-forget";
16 import type { Rule } from "eslint";
17 import * as HermesParser from "hermes-parser";
18
19 +type CompilerErrorDetailWithLoc = Omit<CompilerErrorDetail, "loc"> & {
20 + loc: BabelSourceLocation;
21 +};
22 +
23 function isReactForgetCompilerError(err: Error): err is CompilerError {
24 return err.name === "ReactForgetCompilerError";
25 }
26
27 +function isReportableDiagnostic(
28 + detail: CompilerErrorDetail
29 +): detail is CompilerErrorDetailWithLoc {
30 + let isCorrectSeverity = false;
31 + switch (detail.severity) {
32 + case ErrorSeverity.InvalidInput:
33 + isCorrectSeverity = true;
34 + break;
35 + case ErrorSeverity.Invariant:
36 + case ErrorSeverity.Todo:
37 + break;
38 + }
39 +
40 + return (
41 + isCorrectSeverity === true &&
42 + detail.loc != null &&
43 + typeof detail.loc !== "symbol"
44 + );
45 +}
46 +
47 const rule: Rule.RuleModule = {
48 meta: {
49 type: "problem",
@@ -61,7 +88,7 @@ const rule: Rule.RuleModule = {
88 } catch (err) {
89 if (isReactForgetCompilerError(err) && Array.isArray(err.details)) {
90 for (const detail of err.details) {
64 - if (detail.loc != null && typeof detail.loc !== "symbol") {
91 + if (isReportableDiagnostic(detail)) {
92 context.report({
93 message: detail.toString(),
94 loc: detail.loc,