Skip to content

Commit 2d2cc04

Browse files
committed
[compiler][ez] Option to bail out on blocklisted imports
ghstack-source-id: 540d154 Pull Request resolved: facebook#30643
1 parent 3871fda commit 2d2cc04

File tree

6 files changed

+83
-2
lines changed

6 files changed

+83
-2
lines changed

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,33 @@
88
import {NodePath} from '@babel/core';
99
import * as t from '@babel/types';
1010
import {CompilerError} from '../CompilerError';
11-
import {ExternalFunction, GeneratedSource} from '../HIR';
11+
import {EnvironmentConfig, ExternalFunction, GeneratedSource} from '../HIR';
1212
import {getOrInsertDefault} from '../Utils/utils';
1313

14+
export function validateRestrictedImports(
15+
path: NodePath<t.Program>,
16+
{validateBlocklistedImports}: EnvironmentConfig,
17+
): void {
18+
if (
19+
validateBlocklistedImports == null ||
20+
validateBlocklistedImports.length === 0
21+
) {
22+
return;
23+
}
24+
const restrictedImports = new Set(validateBlocklistedImports);
25+
path.traverse({
26+
ImportDeclaration(importDeclPath) {
27+
if (restrictedImports.has(importDeclPath.node.source.value)) {
28+
CompilerError.throwTodo({
29+
reason: 'Bailing out due to blocklisted import',
30+
description: `Import from module ${importDeclPath.node.source.value}`,
31+
loc: importDeclPath.node.loc ?? null,
32+
});
33+
}
34+
},
35+
});
36+
}
37+
1438
export function addImportsToProgram(
1539
path: NodePath<t.Program>,
1640
importList: Array<ExternalFunction>,

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ import {isComponentDeclaration} from '../Utils/ComponentDeclaration';
2424
import {isHookDeclaration} from '../Utils/HookDeclaration';
2525
import {assertExhaustive} from '../Utils/utils';
2626
import {insertGatedFunctionDeclaration} from './Gating';
27-
import {addImportsToProgram, updateMemoCacheFunctionImport} from './Imports';
27+
import {
28+
addImportsToProgram,
29+
updateMemoCacheFunctionImport,
30+
validateRestrictedImports,
31+
} from './Imports';
2832
import {PluginOptions} from './Options';
2933
import {compileFn} from './Pipeline';
3034
import {
@@ -296,6 +300,7 @@ export function compileProgram(
296300
});
297301
}
298302
const environment = environmentResult.unwrap();
303+
validateRestrictedImports(program, environment);
299304
const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c');
300305
const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';
301306

compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ const EnvironmentConfigSchema = z.object({
238238
* this option to the empty array.
239239
*/
240240
validateNoCapitalizedCalls: z.nullable(z.array(z.string())).default(null),
241+
validateBlocklistedImports: z.nullable(z.array(z.string())).default(null),
241242

242243
/*
243244
* When enabled, the compiler assumes that hooks follow the Rules of React:
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validateBlocklistedImports(DangerousImport)
6+
import {foo} from 'DangerousImport';
7+
import {useIdentity} from 'shared-runtime';
8+
9+
function useHook() {
10+
useIdentity(foo);
11+
return;
12+
}
13+
14+
```
15+
16+
17+
## Error
18+
19+
```
20+
1 | // @validateBlocklistedImports(DangerousImport)
21+
> 2 | import {foo} from 'DangerousImport';
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Todo: Bailing out due to blocklisted import. Import from module DangerousImport (2:2)
23+
3 | import {useIdentity} from 'shared-runtime';
24+
4 |
25+
5 | function useHook() {
26+
```
27+
28+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @validateBlocklistedImports(DangerousImport)
2+
import {foo} from 'DangerousImport';
3+
import {useIdentity} from 'shared-runtime';
4+
5+
function useHook() {
6+
useIdentity(foo);
7+
return;
8+
}

compiler/packages/snap/src/compiler.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ function makePluginOptions(
4747
let validatePreserveExistingMemoizationGuarantees = false;
4848
let enableChangeDetectionForDebugging = null;
4949
let customMacros = null;
50+
let validateBlocklistedImports = null;
5051

5152
if (firstLine.indexOf('@compilationMode(annotation)') !== -1) {
5253
assert(
@@ -155,6 +156,19 @@ function makePluginOptions(
155156
.filter(s => s.length > 0);
156157
}
157158

159+
const validateBlocklistedImportsMatch =
160+
/@validateBlocklistedImports\(([^)]+)\)/.exec(firstLine);
161+
if (
162+
validateBlocklistedImportsMatch &&
163+
validateBlocklistedImportsMatch.length > 1 &&
164+
validateBlocklistedImportsMatch[1].trim().length > 0
165+
) {
166+
validateBlocklistedImports = validateBlocklistedImportsMatch[1]
167+
.split(' ')
168+
.map(s => s.trim())
169+
.filter(s => s.length > 0);
170+
}
171+
158172
let lowerContextAccess = null;
159173
if (firstLine.includes('@lowerContextAccess')) {
160174
lowerContextAccess = {
@@ -216,6 +230,7 @@ function makePluginOptions(
216230
validatePreserveExistingMemoizationGuarantees,
217231
enableChangeDetectionForDebugging,
218232
lowerContextAccess,
233+
validateBlocklistedImports,
219234
},
220235
compilationMode,
221236
logger,

0 commit comments

Comments
 (0)