@samitouri / QOS-React-1 / commits / f5d99baf8e

Add config option to ignore 'use no forget' directives

This will let us test without taking into account the existing 'use no forget' directives to better understand what validations we may need to build. There are two other files that look for this directive that do not seem to take compiler options: 1. https://github.com/facebook/react-forget/blob/408617ec8a5caa815f61d4204cb3fec0775593ca/react/scripts/babel/transform-forget.js#L25 2. https://github.com/facebook/react-forget/blob/408617ec8a5caa815f61d4204cb3fec0775593ca/packages/babel-plugin-react-forget/scripts/jest/makeTransform.ts#L119 Do I need to do anything for those?

Jordan Brown committed Mar 4, 2024 at 19:00 UTC f5d99baf8e64530473fac5fe0dd2bd489f3bf8fc
5 files changed +99 -18
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Options.ts
+5
@@ -104,6 +104,10 @@ export type PluginOptions = {
104 eslintSuppressionRules?: Array<string> | null | undefined;
105
106 flowSuppressions: boolean;
107 + /*
108 + * Ignore 'use no forget' annotations. Helpful during testing but should not be used in production.
109 + */
110 + ignoreUseNoForget: boolean;
111 };
112
113 const CompilationModeSchema = z.enum([
@@ -172,6 +176,7 @@ export const defaultOptions: PluginOptions = {
176 enableUseMemoCachePolyfill: false,
177 eslintSuppressionRules: null,
178 flowSuppressions: false,
179 + ignoreUseNoForget: false,
180 } as const;
181
182 export function parsePluginOptions(obj: unknown): PluginOptions {
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts
+12 -6
@@ -51,13 +51,15 @@ function findDirectiveEnablingMemoization(
51 }
52
53 function findDirectiveDisablingMemoization(
54 - directives: t.Directive[]
54 + directives: t.Directive[],
55 + options: PluginOptions
56 ): t.Directive | null {
57 for (const directive of directives) {
58 const directiveValue = directive.value.value;
59 if (
59 - directiveValue === "use no forget" ||
60 - directiveValue === "use no memo"
60 + (directiveValue === "use no forget" ||
61 + directiveValue === "use no memo") &&
62 + !options.ignoreUseNoForget
63 ) {
64 return directive;
65 }
@@ -197,12 +199,15 @@ export function compileProgram(
199 program: NodePath<t.Program>,
200 pass: CompilerPass
201 ): void {
202 + const options = parsePluginOptions(pass.opts);
203 +
204 // Top level "use no forget", skip this file entirely
201 - if (findDirectiveDisablingMemoization(program.node.directives) != null) {
205 + if (
206 + findDirectiveDisablingMemoization(program.node.directives, options) != null
207 + ) {
208 return;
209 }
210
205 - const options = parsePluginOptions(pass.opts);
211 const environment = parseEnvironmentConfig(pass.opts.environment ?? {});
212
213 /*
@@ -400,7 +405,8 @@ function getReactFunctionType(
405 if (fn.node.body.type === "BlockStatement") {
406 // Opt-outs disable compilation regardless of mode
407 const useNoForget = findDirectiveDisablingMemoization(
403 - fn.node.body.directives
408 + fn.node.body.directives,
409 + pass.opts
410 );
411 if (useNoForget != null) {
412 pass.opts.logger?.logEvent(pass.filename, {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/ignore-use-no-forget.expect.md new
+53
@@ -0,0 +1,53 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +// @ignoreUseNoForget
6 +function Component(prop) {
7 + "use no forget";
8 + const result = prop.x.toFixed();
9 + return <div>{result}</div>;
10 +}
11 +
12 +export const FIXTURE_ENTRYPOINT = {
13 + fn: Component,
14 + params: [{ x: 1 }],
15 +};
16 +
17 +```
18 +
19 +## Code
20 +
21 +```javascript
22 +import { unstable_useMemoCache as useMemoCache } from "react"; // @ignoreUseNoForget
23 +function Component(prop) {
24 + const $ = useMemoCache(4);
25 + let t0;
26 + if ($[0] !== prop.x) {
27 + t0 = prop.x.toFixed();
28 + $[0] = prop.x;
29 + $[1] = t0;
30 + } else {
31 + t0 = $[1];
32 + }
33 + const result = t0;
34 + let t1;
35 + if ($[2] !== result) {
36 + t1 = <div>{result}</div>;
37 + $[2] = result;
38 + $[3] = t1;
39 + } else {
40 + t1 = $[3];
41 + }
42 + return t1;
43 +}
44 +
45 +export const FIXTURE_ENTRYPOINT = {
46 + fn: Component,
47 + params: [{ x: 1 }],
48 +};
49 +
50 +```
51 +
52 +### Eval output
53 +(kind: ok) <div>1</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/ignore-use-no-forget.js new
+11
@@ -0,0 +1,11 @@
1 +// @ignoreUseNoForget
2 +function Component(prop) {
3 + "use no forget";
4 + const result = prop.x.toFixed();
5 + return <div>{result}</div>;
6 +}
7 +
8 +export const FIXTURE_ENTRYPOINT = {
9 + fn: Component,
10 + params: [{ x: 1 }],
11 +};
compiler/packages/snap/src/compiler.ts
+18 -12
@@ -108,6 +108,11 @@ function makePluginOptions(
108 flowSuppressions = true;
109 }
110
111 + let ignoreUseNoForget: boolean = false;
112 + if (firstLine.includes("@ignoreUseNoForget")) {
113 + ignoreUseNoForget = true;
114 + }
115 +
116 const hookPatternMatch = /@hookPattern:"([^"]+)"/.exec(firstLine);
117 if (
118 hookPatternMatch &&
@@ -168,6 +173,7 @@ function makePluginOptions(
173 enableUseMemoCachePolyfill,
174 eslintSuppressionRules,
175 flowSuppressions,
176 + ignoreUseNoForget
177 };
178 }
179
@@ -205,18 +211,18 @@ function getEvaluatorPresets(
211 presets.push(
212 language === "typescript"
213 ? [
208 - "@babel/preset-typescript",
209 - {
210 - /**
211 - * onlyRemoveTypeImports needs to be set as fbt imports
212 - * would otherwise be removed by this pass.
213 - * https://github.com/facebook/fbt/issues/49
214 - * https://github.com/facebook/sfbt/issues/72
215 - * https://dev.to/retyui/how-to-add-support-typescript-for-fbt-an-internationalization-framework-3lo0
216 - */
217 - onlyRemoveTypeImports: true,
218 - },
219 - ]
214 + "@babel/preset-typescript",
215 + {
216 + /**
217 + * onlyRemoveTypeImports needs to be set as fbt imports
218 + * would otherwise be removed by this pass.
219 + * https://github.com/facebook/fbt/issues/49
220 + * https://github.com/facebook/sfbt/issues/72
221 + * https://dev.to/retyui/how-to-add-support-typescript-for-fbt-an-internationalization-framework-3lo0
222 + */
223 + onlyRemoveTypeImports: true,
224 + },
225 + ]
226 : "@babel/preset-flow"
227 );
228