diff --git a/compiler/forget/src/Babel/BabelPlugin.ts b/compiler/forget/src/Babel/BabelPlugin.ts
index f98d1a9969..180cde0fc3 100644
--- a/compiler/forget/src/Babel/BabelPlugin.ts
+++ b/compiler/forget/src/Babel/BabelPlugin.ts
@@ -10,7 +10,11 @@
import type * as BabelCore from "@babel/core";
import jsx from "@babel/plugin-syntax-jsx";
import * as t from "@babel/types";
-import { CompilerError } from "../CompilerError";
+import {
+ CompilerError,
+ CompilerErrorDetail,
+ ErrorSeverity,
+} from "../CompilerError";
import { compile } from "../CompilerPipeline";
import { GeneratedSource } from "../HIR";
import {
@@ -23,9 +27,13 @@ type BabelPluginPass = {
opts: PluginOptions;
};
-function hasUseForgetDirective(directives: t.Directive[]): boolean {
+function hasUseForgetDirective(directive: t.Directive): boolean {
+ return directive.value.value === "use forget";
+}
+
+function hasAnyUseForgetDirectives(directives: t.Directive[]): boolean {
for (const directive of directives) {
- if (directive.value.value === "use forget") {
+ if (hasUseForgetDirective(directive)) {
return true;
}
}
@@ -122,6 +130,61 @@ export default function ReactForgetBabelPlugin(
// want Forget to run true to source as possible.
Program(path, pass): void {
const options = parsePluginOptions(pass.opts);
+
+ const violations = [];
+ const fileComments = pass.file.ast.comments;
+ let fileHasUseForgetDirective = false;
+ if (Array.isArray(fileComments)) {
+ for (const comment of fileComments) {
+ if (
+ /eslint-disable(-next-line)? react-hooks\/(exhaustive-deps|rules-of-hooks)/.test(
+ comment.value
+ )
+ ) {
+ violations.push(comment);
+ }
+ }
+ }
+
+ if (violations.length > 0) {
+ path.traverse({
+ Directive(path) {
+ if (hasUseForgetDirective(path.node)) {
+ fileHasUseForgetDirective = true;
+ path.stop();
+ }
+ },
+ });
+
+ const reason = `Skipped compilation as it disables one or more React eslint rules`;
+ const error = new CompilerError();
+ for (const violation of violations) {
+ if (options.logger != null) {
+ options.logger.logEvent("err", {
+ reason,
+ filename: pass.filename,
+ violation,
+ });
+ }
+
+ error.pushErrorDetail(
+ new CompilerErrorDetail({
+ reason,
+ description: violation.value.trim(),
+ severity: ErrorSeverity.InvalidInput,
+ codeframe: null,
+ loc: violation.loc ?? null,
+ })
+ );
+ }
+
+ if (fileHasUseForgetDirective) {
+ throw error;
+ }
+
+ return;
+ }
+
try {
path.traverse(visitor, {
...pass,
@@ -154,7 +217,7 @@ function shouldCompile(
if (!body.isBlockStatement()) {
return false;
}
- if (!hasUseForgetDirective(body.node.directives)) {
+ if (!hasAnyUseForgetDirectives(body.node.directives)) {
return false;
}
}
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.sketchy-code-use-forget.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/error.sketchy-code-use-forget.expect.md
new file mode 100644
index 0000000000..ed9b3e6c7a
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/error.sketchy-code-use-forget.expect.md
@@ -0,0 +1,22 @@
+
+## Input
+
+```javascript
+/* eslint-disable react-hooks/rules-of-hooks */
+function lowercasecomponent() {
+ "use forget";
+ const x = [];
+ return
{x}
;
+}
+/* eslint-enable react-hooks/rules-of-hooks */
+
+```
+
+
+## Error
+
+```
+[ReactForget] InvalidInput: Skipped compilation as it disables one or more React eslint rules. eslint-disable react-hooks/rules-of-hooks (1:1)
+```
+
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/error.sketchy-code-use-forget.js b/compiler/forget/src/__tests__/fixtures/compiler/error.sketchy-code-use-forget.js
new file mode 100644
index 0000000000..08f080632c
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/error.sketchy-code-use-forget.js
@@ -0,0 +1,7 @@
+/* eslint-disable react-hooks/rules-of-hooks */
+function lowercasecomponent() {
+ "use forget";
+ const x = [];
+ return {x}
;
+}
+/* eslint-enable react-hooks/rules-of-hooks */
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-exhaustive-deps.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-exhaustive-deps.expect.md
new file mode 100644
index 0000000000..bb10d0f524
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-exhaustive-deps.expect.md
@@ -0,0 +1,35 @@
+
+## Input
+
+```javascript
+function Component() {
+ const item = [];
+ const foo = useCallback(
+ () => {
+ item.push(1);
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps
+ []
+ );
+
+ return ;
+}
+
+```
+
+## Code
+
+```javascript
+function Component() {
+ const item = [];
+ const foo = useCallback(
+ () => {
+ item.push(1);
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps
+ []
+ );
+
+ return ;
+}
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-exhaustive-deps.js b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-exhaustive-deps.js
new file mode 100644
index 0000000000..ebfb84375e
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-exhaustive-deps.js
@@ -0,0 +1,11 @@
+function Component() {
+ const item = [];
+ const foo = useCallback(
+ () => {
+ item.push(1);
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps
+ []
+ );
+
+ return ;
+}
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-rules-of-hooks.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-rules-of-hooks.expect.md
new file mode 100644
index 0000000000..95a5040378
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-rules-of-hooks.expect.md
@@ -0,0 +1,25 @@
+
+## Input
+
+```javascript
+/* eslint-disable react-hooks/rules-of-hooks */
+function lowercasecomponent() {
+ const x = [];
+ return {x}
;
+}
+/* eslint-enable react-hooks/rules-of-hooks */
+
+```
+
+## Code
+
+```javascript
+/* eslint-disable react-hooks/rules-of-hooks */
+function lowercasecomponent() {
+ const x = [];
+ return {x}
;
+}
+/* eslint-enable react-hooks/rules-of-hooks */
+
+```
+
\ No newline at end of file
diff --git a/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-rules-of-hooks.js b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-rules-of-hooks.js
new file mode 100644
index 0000000000..365284b7b8
--- /dev/null
+++ b/compiler/forget/src/__tests__/fixtures/compiler/sketchy-code-rules-of-hooks.js
@@ -0,0 +1,6 @@
+/* eslint-disable react-hooks/rules-of-hooks */
+function lowercasecomponent() {
+ const x = [];
+ return {x}
;
+}
+/* eslint-enable react-hooks/rules-of-hooks */