[compiler][ez] Option to bail out on blocklisted imports

ghstack-source-id: 540d154b25e49a83683a05fc9326dbd0ad59a6bd
Pull Request resolved: https://github.com/facebook/react/pull/30643
This commit is contained in:
Mofei Zhang
2024-08-08 15:47:40 -07:00
parent 3871fdadaa
commit 2d2cc042d7
6 changed files with 83 additions and 2 deletions

View File

@@ -8,9 +8,33 @@
import {NodePath} from '@babel/core';
import * as t from '@babel/types';
import {CompilerError} from '../CompilerError';
import {ExternalFunction, GeneratedSource} from '../HIR';
import {EnvironmentConfig, ExternalFunction, GeneratedSource} from '../HIR';
import {getOrInsertDefault} from '../Utils/utils';
export function validateRestrictedImports(
path: NodePath<t.Program>,
{validateBlocklistedImports}: EnvironmentConfig,
): void {
if (
validateBlocklistedImports == null ||
validateBlocklistedImports.length === 0
) {
return;
}
const restrictedImports = new Set(validateBlocklistedImports);
path.traverse({
ImportDeclaration(importDeclPath) {
if (restrictedImports.has(importDeclPath.node.source.value)) {
CompilerError.throwTodo({
reason: 'Bailing out due to blocklisted import',
description: `Import from module ${importDeclPath.node.source.value}`,
loc: importDeclPath.node.loc ?? null,
});
}
},
});
}
export function addImportsToProgram(
path: NodePath<t.Program>,
importList: Array<ExternalFunction>,

View File

@@ -24,7 +24,11 @@ import {isComponentDeclaration} from '../Utils/ComponentDeclaration';
import {isHookDeclaration} from '../Utils/HookDeclaration';
import {assertExhaustive} from '../Utils/utils';
import {insertGatedFunctionDeclaration} from './Gating';
import {addImportsToProgram, updateMemoCacheFunctionImport} from './Imports';
import {
addImportsToProgram,
updateMemoCacheFunctionImport,
validateRestrictedImports,
} from './Imports';
import {PluginOptions} from './Options';
import {compileFn} from './Pipeline';
import {
@@ -296,6 +300,7 @@ export function compileProgram(
});
}
const environment = environmentResult.unwrap();
validateRestrictedImports(program, environment);
const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c');
const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime';

View File

@@ -238,6 +238,7 @@ const EnvironmentConfigSchema = z.object({
* this option to the empty array.
*/
validateNoCapitalizedCalls: z.nullable(z.array(z.string())).default(null),
validateBlocklistedImports: z.nullable(z.array(z.string())).default(null),
/*
* When enabled, the compiler assumes that hooks follow the Rules of React:

View File

@@ -0,0 +1,28 @@
## Input
```javascript
// @validateBlocklistedImports(DangerousImport)
import {foo} from 'DangerousImport';
import {useIdentity} from 'shared-runtime';
function useHook() {
useIdentity(foo);
return;
}
```
## Error
```
1 | // @validateBlocklistedImports(DangerousImport)
> 2 | import {foo} from 'DangerousImport';
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Todo: Bailing out due to blocklisted import. Import from module DangerousImport (2:2)
3 | import {useIdentity} from 'shared-runtime';
4 |
5 | function useHook() {
```

View File

@@ -0,0 +1,8 @@
// @validateBlocklistedImports(DangerousImport)
import {foo} from 'DangerousImport';
import {useIdentity} from 'shared-runtime';
function useHook() {
useIdentity(foo);
return;
}

View File

@@ -47,6 +47,7 @@ function makePluginOptions(
let validatePreserveExistingMemoizationGuarantees = false;
let enableChangeDetectionForDebugging = null;
let customMacros = null;
let validateBlocklistedImports = null;
if (firstLine.indexOf('@compilationMode(annotation)') !== -1) {
assert(
@@ -155,6 +156,19 @@ function makePluginOptions(
.filter(s => s.length > 0);
}
const validateBlocklistedImportsMatch =
/@validateBlocklistedImports\(([^)]+)\)/.exec(firstLine);
if (
validateBlocklistedImportsMatch &&
validateBlocklistedImportsMatch.length > 1 &&
validateBlocklistedImportsMatch[1].trim().length > 0
) {
validateBlocklistedImports = validateBlocklistedImportsMatch[1]
.split(' ')
.map(s => s.trim())
.filter(s => s.length > 0);
}
let lowerContextAccess = null;
if (firstLine.includes('@lowerContextAccess')) {
lowerContextAccess = {
@@ -216,6 +230,7 @@ function makePluginOptions(
validatePreserveExistingMemoizationGuarantees,
enableChangeDetectionForDebugging,
lowerContextAccess,
validateBlocklistedImports,
},
compilationMode,
logger,