@samitouri / QOS-React-2 / commits / b19555573f

[babel] Make gating option a pair of module and project

There are some internal restrictions in Metro that only allow us to specify one gating module as an injected dependency. To allow multiple projects, this PR updates the Babel plugin to take a gating options config specifiying a project name. The project name is used as a suffix for the generated import; for example: ```js const options = { // ... gating: { module: "ReactForgetFeatureFlag", importSpecifierName: "isForgetEnabled_Secret", }; // generates import {isForgetEnabled_Secret} from "ReactForgetFeatureFlag"; // a module that exports multiple flags // ... ```

Lauren Tan committed Apr 3, 2023 at 12:33 UTC b19555573f6ec233013e73111ffe3f05f44faa5e
21 files changed +137 -100
compiler/forget/src/Babel/BabelPlugin.ts
+54 -44
@@ -12,14 +12,16 @@ import jsx from "@babel/plugin-syntax-jsx";
12 import * as t from "@babel/types";
13 import invariant from "invariant";
14 import { compile } from "../CompilerPipeline";
15 -import { parsePluginOptions, PluginOptions } from "./PluginOptions";
15 +import {
16 + GatingOptions,
17 + parsePluginOptions,
18 + PluginOptions,
19 +} from "./PluginOptions";
20
21 type BabelPluginPass = {
22 opts: PluginOptions;
23 };
24
21 -const testId = t.identifier("isForgetEnabled");
22 -
25 function hasUseForgetDirective(directives: t.Directive[]): boolean {
26 for (const directive of directives) {
27 if (directive.value.value === "use forget") {
@@ -46,7 +48,7 @@ export default function ReactForgetBabelPlugin(
48 hasForgetCompiledCode = true;
49 const compiled = compile(fn, pass.opts.environment);
50
49 - if (pass.opts.gatingModule) {
51 + if (pass.opts.gating != null) {
52 // Rename existing function
53 invariant(fn.node.id, "FunctionDeclaration must have a name");
54 const original = fn.node.id;
@@ -59,7 +61,14 @@ export default function ReactForgetBabelPlugin(
61 compiledFn.skip();
62
63 // Build and append gating test
62 - compiledFn.insertAfter(buildGatingTest(fn, compiled.id, original));
64 + compiledFn.insertAfter(
65 + buildGatingTest({
66 + originalFnDecl: fn,
67 + compiledIdent: compiled.id,
68 + originalIdent: original,
69 + gating: pass.opts.gating,
70 + })
71 + );
72 } else {
73 fn.replaceWith(compiled);
74 }
@@ -108,10 +117,10 @@ export default function ReactForgetBabelPlugin(
117 opts: { ...pass.opts, ...options },
118 });
119
111 - if (options.gatingModule && hasForgetCompiledCode) {
120 + if (options.gating != null && hasForgetCompiledCode) {
121 path.unshiftContainer(
122 "body",
114 - buildImportForGatingModule(options.gatingModule)
123 + buildImportForGatingModule(options.gating)
124 );
125 }
126 } catch (err) {
@@ -194,62 +203,63 @@ function buildBlockStatement(
203 return body.node;
204 }
205
197 -function buildGatingTest(
198 - uncompiled: BabelCore.NodePath<t.FunctionDeclaration>,
199 - compiled: t.Identifier,
200 - original: t.Identifier
201 -): t.Node | t.Node[] {
202 - const test = buildTest({
203 - uncompiled: uncompiled.node.id!,
204 - compiled,
205 - original,
206 - });
206 +type GatingTestOptions = {
207 + originalFnDecl: BabelCore.NodePath<t.FunctionDeclaration>;
208 + compiledIdent: t.Identifier;
209 + originalIdent: t.Identifier;
210 + gating: GatingOptions;
211 +};
212 +function buildGatingTest({
213 + originalFnDecl,
214 + compiledIdent,
215 + originalIdent,
216 + gating,
217 +}: GatingTestOptions): t.Node | t.Node[] {
218 + const testVarDecl = t.variableDeclaration("const", [
219 + t.variableDeclarator(
220 + originalIdent,
221 + t.conditionalExpression(
222 + t.callExpression(buildSpecifierIdent(gating), []),
223 + compiledIdent,
224 + originalFnDecl.node.id!
225 + )
226 + ),
227 + ]);
228
229 // Re-export new declaration
209 - const parent = uncompiled.parentPath;
230 + const parent = originalFnDecl.parentPath;
231 if (t.isExportDefaultDeclaration(parent)) {
232 // Re-add uncompiled function
212 - parent.replaceWith(uncompiled)[0].skip();
233 + parent.replaceWith(originalFnDecl)[0].skip();
234
235 // Add test and synthesize new export
215 - return [test, t.exportDefaultDeclaration(original)];
236 + return [testVarDecl, t.exportDefaultDeclaration(originalIdent)];
237 } else if (t.isExportNamedDeclaration(parent)) {
238 // Re-add uncompiled function
218 - parent.replaceWith(uncompiled)[0].skip();
239 + parent.replaceWith(originalFnDecl)[0].skip();
240
241 // Add and export test
221 - return t.exportNamedDeclaration(test);
242 + return t.exportNamedDeclaration(testVarDecl);
243 }
244
245 // Just add the test, no need for re-export
225 - return test;
246 + return testVarDecl;
247 }
248
249 function addSuffix(id: t.Identifier, suffix: string): t.Identifier {
250 return t.identifier(`${id.name}${suffix}`);
251 }
252
232 -function buildTest(ids: {
233 - uncompiled: t.Identifier;
234 - compiled: t.Identifier;
235 - original: t.Identifier;
236 -}): t.VariableDeclaration {
237 - return t.variableDeclaration("const", [
238 - t.variableDeclarator(
239 - ids.original,
240 - t.conditionalExpression(
241 - t.callExpression(testId, []),
242 - ids.compiled,
243 - ids.uncompiled
244 - )
245 - ),
246 - ]);
247 -}
248 -
249 -function buildImportForGatingModule(gatingModule: string): t.ImportDeclaration {
250 - const importDefaultSpecifier = t.importDefaultSpecifier(testId);
253 +function buildImportForGatingModule(
254 + gating: GatingOptions
255 +): t.ImportDeclaration {
256 + const specifierIdent = buildSpecifierIdent(gating);
257 return t.importDeclaration(
252 - [importDefaultSpecifier],
253 - t.stringLiteral(gatingModule)
258 + [t.importSpecifier(specifierIdent, specifierIdent)],
259 + t.stringLiteral(gating.source)
260 );
261 }
262 +
263 +function buildSpecifierIdent(gating: GatingOptions): t.Identifier {
264 + return t.identifier(gating.importSpecifierName);
265 +}
compiler/forget/src/Babel/PluginOptions.ts
+22 -8
@@ -7,6 +7,17 @@
7
8 import { EnvironmentConfig } from "../HIR/Environment";
9
10 +export type GatingOptions = {
11 + /**
12 + * Source for the imported module that exports the `importSpecifierName` functions
13 + */
14 + source: string;
15 + /**
16 + * Unique name for the feature flag test condition, eg `isForgetEnabled_ProjectName`
17 + */
18 + importSpecifierName: string;
19 +};
20 +
21 export type PluginOptions = {
22 /**
23 * Enable to make Forget only compile functions containing the 'use forget' directive.
@@ -18,23 +29,26 @@ export type PluginOptions = {
29 logger: Logger | null;
30
31 /**
21 - * Specifying a `gatingModule`, makes Forget compile and emit a separate
22 - * version of the function gated by importing an `isForgetEnabled` from the
23 - * specified `gatingModule`.
32 + * Specifying a `gating` config, makes Forget compile and emit a separate
33 + * version of the function gated by importing the `gating.importSpecifierName` from the
34 + * specified `gating.source`.
35 *
36 * For example:
26 - * gatingModule: 'ReactForgetFeatureFlag'
37 + * gating: {
38 + * source: 'ReactForgetFeatureFlag',
39 + * importSpecifierName: 'isForgetEnabled_Pokes',
40 + * }
41 *
42 * produces:
29 - * import isForgetEnabled from ReactForgetFeatureFlag
43 + * import {isForgetEnabled_Pokes} from 'ReactForgetFeatureFlag';
44 *
45 * Foo_forget() {}
46 *
47 * Foo_uncompiled() {}
48 *
35 - * var Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
49 + * var Foo = isForgetEnabled_Pokes() ? Foo_forget : Foo_uncompiled;
50 */
37 - gatingModule: string | null;
51 + gating: GatingOptions | null;
52 };
53
54 export type Logger = {
@@ -45,7 +59,7 @@ export const defaultOptions: PluginOptions = {
59 enableOnlyOnUseForgetDirective: false,
60 environment: null,
61 logger: null,
48 - gatingModule: null,
62 + gating: null,
63 } as const;
64
65 export function parsePluginOptions(obj: unknown): PluginOptions {
compiler/forget/src/__tests__/compiler-test.ts
+1 -1
@@ -56,7 +56,7 @@ describe("React Forget", () => {
56 ]),
57 },
58 logger: null,
59 - gatingModule: options.gatingModule,
59 + gating: options.gating,
60 }).code,
61 });
62 } catch (e) {
compiler/forget/src/__tests__/disableMemoizeJsxElements-test.ts
+1 -1
@@ -52,7 +52,7 @@ describe("React Forget (Disable memoization of JSX elements)", () => {
52 ]),
53 },
54 logger: null,
55 - gatingModule: options.gatingModule,
55 + gating: options.gating,
56 }).code,
57 });
58 } catch (e) {
compiler/forget/src/__tests__/fixtures/compiler/arrow-function-expr-gating-test.expect.md
+5 -3
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule
5 +// @gating
6 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
7
8 export default ErrorView;
@@ -12,7 +12,7 @@ export default ErrorView;
12 ## Code
13
14 ```javascript
15 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule
15 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating
16 function ErrorView_uncompiled(error, _retry) {
17 return <MessageBox error={error}></MessageBox>;
18 }
@@ -29,7 +29,9 @@ function ErrorView_forget(error, _retry) {
29 }
30 return t0;
31 }
32 -const ErrorView = isForgetEnabled() ? ErrorView_forget : ErrorView_uncompiled;
32 +const ErrorView = isForgetEnabled_Fixtures()
33 + ? ErrorView_forget
34 + : ErrorView_uncompiled;
35
36 export default ErrorView;
37
compiler/forget/src/__tests__/fixtures/compiler/arrow-function-expr-gating-test.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule
1 +// @gating
2 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
3
4 export default ErrorView;
compiler/forget/src/__tests__/fixtures/compiler/error._todo.multi-arrow-expr-export-default-gating-test.expect.md
+1 -1
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule
5 +// @gating
6 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
7
8 export default Renderer = (props) => (
compiler/forget/src/__tests__/fixtures/compiler/error._todo.multi-arrow-expr-export-default-gating-test.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule
1 +// @gating
2 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
3
4 export default Renderer = (props) => (
compiler/forget/src/__tests__/fixtures/compiler/gating-test-export-default-function.expect.md
+4 -4
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule @forgetDirective
5 +// @gating @forgetDirective
6 export default function Bar(props) {
7 "use forget";
8 return <div>{props.bar}</div>;
@@ -22,7 +22,7 @@ function Foo(props) {
22 ## Code
23
24 ```javascript
25 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
25 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating @forgetDirective
26 function Bar_uncompiled(props) {
27 "use forget";
28 return <div>{props.bar}</div>;
@@ -40,7 +40,7 @@ function Bar_forget(props) {
40 }
41 return t0;
42 }
43 -const Bar = isForgetEnabled() ? Bar_forget : Bar_uncompiled;
43 +const Bar = isForgetEnabled_Fixtures() ? Bar_forget : Bar_uncompiled;
44 export default Bar;
45
46 function NoForget(props) {
@@ -64,7 +64,7 @@ function Foo_forget(props) {
64 }
65 return t0;
66 }
67 -const Foo = isForgetEnabled() ? Foo_forget : Foo_uncompiled;
67 +const Foo = isForgetEnabled_Fixtures() ? Foo_forget : Foo_uncompiled;
68
69 ```
70
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/gating-test-export-default-function.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule @forgetDirective
1 +// @gating @forgetDirective
2 export default function Bar(props) {
3 "use forget";
4 return <div>{props.bar}</div>;
compiler/forget/src/__tests__/fixtures/compiler/gating-test-export-function-and-default.expect.md
+4 -4
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule @forgetDirective
5 +// @gating @forgetDirective
6 export default function Bar(props) {
7 "use forget";
8 return <div>{props.bar}</div>;
@@ -22,7 +22,7 @@ export function Foo(props) {
22 ## Code
23
24 ```javascript
25 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
25 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating @forgetDirective
26 function Bar_uncompiled(props) {
27 "use forget";
28 return <div>{props.bar}</div>;
@@ -40,7 +40,7 @@ function Bar_forget(props) {
40 }
41 return t0;
42 }
43 -const Bar = isForgetEnabled() ? Bar_forget : Bar_uncompiled;
43 +const Bar = isForgetEnabled_Fixtures() ? Bar_forget : Bar_uncompiled;
44 export default Bar;
45
46 function NoForget(props) {
@@ -64,7 +64,7 @@ function Foo_forget(props) {
64 }
65 return t0;
66 }
67 -export const Foo = isForgetEnabled() ? Foo_forget : Foo_uncompiled;
67 +export const Foo = isForgetEnabled_Fixtures() ? Foo_forget : Foo_uncompiled;
68
69 ```
70
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/gating-test-export-function-and-default.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule @forgetDirective
1 +// @gating @forgetDirective
2 export default function Bar(props) {
3 "use forget";
4 return <div>{props.bar}</div>;
compiler/forget/src/__tests__/fixtures/compiler/gating-test-export-function.expect.md
+4 -4
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule @forgetDirective
5 +// @gating @forgetDirective
6 export function Bar(props) {
7 "use forget";
8 return <div>{props.bar}</div>;
@@ -22,7 +22,7 @@ export function Foo(props) {
22 ## Code
23
24 ```javascript
25 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
25 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating @forgetDirective
26 function Bar_uncompiled(props) {
27 "use forget";
28 return <div>{props.bar}</div>;
@@ -40,7 +40,7 @@ function Bar_forget(props) {
40 }
41 return t0;
42 }
43 -export const Bar = isForgetEnabled() ? Bar_forget : Bar_uncompiled;
43 +export const Bar = isForgetEnabled_Fixtures() ? Bar_forget : Bar_uncompiled;
44
45 export function NoForget(props) {
46 return <Bar>{props.noForget}</Bar>;
@@ -63,7 +63,7 @@ function Foo_forget(props) {
63 }
64 return t0;
65 }
66 -export const Foo = isForgetEnabled() ? Foo_forget : Foo_uncompiled;
66 +export const Foo = isForgetEnabled_Fixtures() ? Foo_forget : Foo_uncompiled;
67
68 ```
69
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/gating-test-export-function.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule @forgetDirective
1 +// @gating @forgetDirective
2 export function Bar(props) {
3 "use forget";
4 return <div>{props.bar}</div>;
compiler/forget/src/__tests__/fixtures/compiler/gating-test.expect.md
+4 -4
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule @forgetDirective
5 +// @gating @forgetDirective
6 function Bar(props) {
7 "use forget";
8 return <div>{props.bar}</div>;
@@ -22,7 +22,7 @@ function Foo(props) {
22 ## Code
23
24 ```javascript
25 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
25 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating @forgetDirective
26 function Bar_uncompiled(props) {
27 "use forget";
28 return <div>{props.bar}</div>;
@@ -40,7 +40,7 @@ function Bar_forget(props) {
40 }
41 return t0;
42 }
43 -const Bar = isForgetEnabled() ? Bar_forget : Bar_uncompiled;
43 +const Bar = isForgetEnabled_Fixtures() ? Bar_forget : Bar_uncompiled;
44
45 function NoForget(props) {
46 return <Bar>{props.noForget}</Bar>;
@@ -63,7 +63,7 @@ function Foo_forget(props) {
63 }
64 return t0;
65 }
66 -const Foo = isForgetEnabled() ? Foo_forget : Foo_uncompiled;
66 +const Foo = isForgetEnabled_Fixtures() ? Foo_forget : Foo_uncompiled;
67
68 ```
69
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/gating-test.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule @forgetDirective
1 +// @gating @forgetDirective
2 function Bar(props) {
3 "use forget";
4 return <div>{props.bar}</div>;
compiler/forget/src/__tests__/fixtures/compiler/multi-arrow-expr-export-gating-test.expect.md
+6 -4
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule
5 +// @gating
6 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
7
8 export const Renderer = (props) => (
@@ -17,7 +17,7 @@ export const Renderer = (props) => (
17 ## Code
18
19 ```javascript
20 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule
20 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating
21 function ErrorView_uncompiled(error, _retry) {
22 return <MessageBox error={error}></MessageBox>;
23 }
@@ -34,7 +34,9 @@ function ErrorView_forget(error, _retry) {
34 }
35 return t0;
36 }
37 -const ErrorView = isForgetEnabled() ? ErrorView_forget : ErrorView_uncompiled;
37 +const ErrorView = isForgetEnabled_Fixtures()
38 + ? ErrorView_forget
39 + : ErrorView_uncompiled;
40 function Renderer_uncompiled(props) {
41 return (
42 <Foo>
@@ -73,7 +75,7 @@ function Renderer_forget(props) {
75 }
76 return t2;
77 }
76 -export const Renderer = isForgetEnabled()
78 +export const Renderer = isForgetEnabled_Fixtures()
79 ? Renderer_forget
80 : Renderer_uncompiled;
81
compiler/forget/src/__tests__/fixtures/compiler/multi-arrow-expr-export-gating-test.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule
1 +// @gating
2 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
3
4 export const Renderer = (props) => (
compiler/forget/src/__tests__/fixtures/compiler/multi-arrow-expr-gating-test.expect.md
+8 -4
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @gatingModule
5 +// @gating
6 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
7
8 const Renderer = (props) => (
@@ -19,7 +19,7 @@ export default Renderer;
19 ## Code
20
21 ```javascript
22 -import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule
22 +import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; // @gating
23 function ErrorView_uncompiled(error, _retry) {
24 return <MessageBox error={error}></MessageBox>;
25 }
@@ -36,7 +36,9 @@ function ErrorView_forget(error, _retry) {
36 }
37 return t0;
38 }
39 -const ErrorView = isForgetEnabled() ? ErrorView_forget : ErrorView_uncompiled;
39 +const ErrorView = isForgetEnabled_Fixtures()
40 + ? ErrorView_forget
41 + : ErrorView_uncompiled;
42 function Renderer_uncompiled(props) {
43 return (
44 <Foo>
@@ -75,7 +77,9 @@ function Renderer_forget(props) {
77 }
78 return t2;
79 }
78 -const Renderer = isForgetEnabled() ? Renderer_forget : Renderer_uncompiled;
80 +const Renderer = isForgetEnabled_Fixtures()
81 + ? Renderer_forget
82 + : Renderer_uncompiled;
83 export default Renderer;
84
85 ```
compiler/forget/src/__tests__/fixtures/compiler/multi-arrow-expr-gating-test.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @gatingModule
1 +// @gating
2 const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
3
4 const Renderer = (props) => (
compiler/forget/src/__tests__/test-utils/generateTestsFromFixtures.ts
+15 -10
@@ -11,6 +11,7 @@
11
12 import fs from "fs";
13 import path from "path";
14 +import { GatingOptions, PluginOptions } from "../../Babel/PluginOptions";
15
16 const EXPECT_SUFFIX = ".expect.md";
17
@@ -40,17 +41,16 @@ expect.extend({
41 },
42 });
43
44 +type FixtureTestOptions = {
45 + debug: boolean;
46 + language: "flow" | "typescript";
47 +};
48 export default function generateTestsFromFixtures(
49 fixturesPath: string,
50 transform: (
51 input: string,
52 file: any,
48 - options: {
49 - debug: boolean;
50 - enableOnlyOnUseForgetDirective: boolean;
51 - gatingModule: string | null;
52 - language: "flow" | "typescript";
53 - }
53 + options: FixtureTestOptions & PluginOptions
54 ) => string
55 ) {
56 let files: Array<string>;
@@ -90,7 +90,7 @@ export default function generateTestsFromFixtures(
90 let input: string | null = null;
91 let debug = false;
92 let enableOnlyOnUseForgetDirective = false;
93 - let gatingModule: string | null = null;
93 + let gating: GatingOptions | null = null;
94
95 if (inputFile != null) {
96 input = fs.readFileSync(inputFile, "utf8");
@@ -105,8 +105,11 @@ export default function generateTestsFromFixtures(
105 if (lines[0]!.indexOf("@forgetDirective") !== -1) {
106 enableOnlyOnUseForgetDirective = true;
107 }
108 - if (lines[0]!.indexOf("@gatingModule") !== -1) {
109 - gatingModule = "ReactForgetFeatureFlag";
108 + if (lines[0]!.indexOf("@gating") !== -1) {
109 + gating = {
110 + source: "ReactForgetFeatureFlag",
111 + importSpecifierName: "isForgetEnabled_Fixtures",
112 + };
113 }
114 }
115
@@ -114,9 +117,11 @@ export default function generateTestsFromFixtures(
117 let receivedOutput;
118 if (input !== null) {
119 receivedOutput = transform(input, basename, {
120 + environment: null,
121 + logger: null,
122 debug,
123 enableOnlyOnUseForgetDirective,
119 - gatingModule,
124 + gating,
125 language: parseLanguage(input),
126 });
127 } else {