[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 {