Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b817b78bc |
@@ -0,0 +1,13 @@
|
||||
import { c as _c } from "react/compiler-runtime"; //
|
||||
@compilationMode(all)
|
||||
function nonReactFn() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = {};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// @compilationMode(infer)
|
||||
function nonReactFn() {
|
||||
return {};
|
||||
}
|
||||
@@ -79,6 +79,24 @@ function Foo() {
|
||||
// @flow
|
||||
function useFoo(propVal: {+baz: number}) {
|
||||
return <div>{(propVal.baz as number)}</div>;
|
||||
}
|
||||
`,
|
||||
noFormat: true,
|
||||
},
|
||||
{
|
||||
name: 'compilationMode-infer',
|
||||
input: `// @compilationMode(infer)
|
||||
function nonReactFn() {
|
||||
return {};
|
||||
}
|
||||
`,
|
||||
noFormat: true,
|
||||
},
|
||||
{
|
||||
name: 'compilationMode-all',
|
||||
input: `// @compilationMode(all)
|
||||
function nonReactFn() {
|
||||
return {};
|
||||
}
|
||||
`,
|
||||
noFormat: true,
|
||||
|
||||
@@ -20,7 +20,6 @@ import BabelPluginReactCompiler, {
|
||||
CompilerPipelineValue,
|
||||
parsePluginOptions,
|
||||
} from 'babel-plugin-react-compiler/src';
|
||||
import {type EnvironmentConfig} from 'babel-plugin-react-compiler/src/HIR/Environment';
|
||||
import clsx from 'clsx';
|
||||
import invariant from 'invariant';
|
||||
import {useSnackbar} from 'notistack';
|
||||
@@ -69,23 +68,14 @@ function parseInput(
|
||||
function invokeCompiler(
|
||||
source: string,
|
||||
language: 'flow' | 'typescript',
|
||||
environment: EnvironmentConfig,
|
||||
logIR: (pipelineValue: CompilerPipelineValue) => void,
|
||||
options: PluginOptions,
|
||||
): CompilerTransformOutput {
|
||||
const opts: PluginOptions = parsePluginOptions({
|
||||
logger: {
|
||||
debugLogIRs: logIR,
|
||||
logEvent: () => {},
|
||||
},
|
||||
environment,
|
||||
panicThreshold: 'all_errors',
|
||||
});
|
||||
const ast = parseInput(source, language);
|
||||
let result = transformFromAstSync(ast, source, {
|
||||
filename: '_playgroundFile.js',
|
||||
highlightCode: false,
|
||||
retainLines: true,
|
||||
plugins: [[BabelPluginReactCompiler, opts]],
|
||||
plugins: [[BabelPluginReactCompiler, options]],
|
||||
ast: true,
|
||||
sourceType: 'module',
|
||||
configFile: false,
|
||||
@@ -171,51 +161,59 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
||||
try {
|
||||
// Extract the first line to quickly check for custom test directives
|
||||
const pragma = source.substring(0, source.indexOf('\n'));
|
||||
const config = parseConfigPragmaForTests(pragma);
|
||||
|
||||
transformOutput = invokeCompiler(
|
||||
source,
|
||||
language,
|
||||
{...config, customHooks: new Map([...COMMON_HOOKS])},
|
||||
result => {
|
||||
switch (result.kind) {
|
||||
case 'ast': {
|
||||
break;
|
||||
}
|
||||
case 'hir': {
|
||||
upsert({
|
||||
kind: 'hir',
|
||||
fnName: result.value.id,
|
||||
name: result.name,
|
||||
value: printFunctionWithOutlined(result.value),
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'reactive': {
|
||||
upsert({
|
||||
kind: 'reactive',
|
||||
fnName: result.value.id,
|
||||
name: result.name,
|
||||
value: printReactiveFunctionWithOutlined(result.value),
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'debug': {
|
||||
upsert({
|
||||
kind: 'debug',
|
||||
fnName: null,
|
||||
name: result.name,
|
||||
value: result.value,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const _: never = result;
|
||||
throw new Error(`Unhandled result ${result}`);
|
||||
}
|
||||
const logIR = (result: CompilerPipelineValue): void => {
|
||||
switch (result.kind) {
|
||||
case 'ast': {
|
||||
break;
|
||||
}
|
||||
case 'hir': {
|
||||
upsert({
|
||||
kind: 'hir',
|
||||
fnName: result.value.id,
|
||||
name: result.name,
|
||||
value: printFunctionWithOutlined(result.value),
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'reactive': {
|
||||
upsert({
|
||||
kind: 'reactive',
|
||||
fnName: result.value.id,
|
||||
name: result.name,
|
||||
value: printReactiveFunctionWithOutlined(result.value),
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'debug': {
|
||||
upsert({
|
||||
kind: 'debug',
|
||||
fnName: null,
|
||||
name: result.name,
|
||||
value: result.value,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const _: never = result;
|
||||
throw new Error(`Unhandled result ${result}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
const parsedOptions = parseConfigPragmaForTests(pragma, {
|
||||
compilationMode: 'infer',
|
||||
});
|
||||
const opts: PluginOptions = parsePluginOptions({
|
||||
...parsedOptions,
|
||||
environment: {
|
||||
...parsedOptions.environment,
|
||||
customHooks: new Map([...COMMON_HOOKS]),
|
||||
},
|
||||
);
|
||||
logger: {
|
||||
debugLogIRs: logIR,
|
||||
logEvent: () => {},
|
||||
},
|
||||
});
|
||||
transformOutput = invokeCompiler(source, language, opts);
|
||||
} catch (err) {
|
||||
/**
|
||||
* error might be an invariant violation or other runtime error
|
||||
|
||||
@@ -9,7 +9,13 @@ import * as t from '@babel/types';
|
||||
import {ZodError, z} from 'zod';
|
||||
import {fromZodError} from 'zod-validation-error';
|
||||
import {CompilerError} from '../CompilerError';
|
||||
import {Logger} from '../Entrypoint';
|
||||
import {
|
||||
CompilationMode,
|
||||
Logger,
|
||||
PanicThresholdOptions,
|
||||
parsePluginOptions,
|
||||
PluginOptions,
|
||||
} from '../Entrypoint';
|
||||
import {Err, Ok, Result} from '../Utils/Result';
|
||||
import {
|
||||
DEFAULT_GLOBALS,
|
||||
@@ -683,7 +689,9 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
|
||||
/**
|
||||
* For snap test fixtures and playground only.
|
||||
*/
|
||||
export function parseConfigPragmaForTests(pragma: string): EnvironmentConfig {
|
||||
function parseConfigPragmaEnvironmentForTest(
|
||||
pragma: string,
|
||||
): EnvironmentConfig {
|
||||
const maybeConfig: any = {};
|
||||
// Get the defaults to programmatically check for boolean properties
|
||||
const defaultConfig = EnvironmentConfigSchema.parse({});
|
||||
@@ -749,6 +757,48 @@ export function parseConfigPragmaForTests(pragma: string): EnvironmentConfig {
|
||||
suggestions: null,
|
||||
});
|
||||
}
|
||||
export function parseConfigPragmaForTests(
|
||||
pragma: string,
|
||||
defaults: {
|
||||
compilationMode: CompilationMode;
|
||||
},
|
||||
): PluginOptions {
|
||||
const environment = parseConfigPragmaEnvironmentForTest(pragma);
|
||||
let compilationMode: CompilationMode = defaults.compilationMode;
|
||||
let panicThreshold: PanicThresholdOptions = 'all_errors';
|
||||
for (const token of pragma.split(' ')) {
|
||||
if (!token.startsWith('@')) {
|
||||
continue;
|
||||
}
|
||||
switch (token) {
|
||||
case '@compilationMode(annotation)': {
|
||||
compilationMode = 'annotation';
|
||||
break;
|
||||
}
|
||||
case '@compilationMode(infer)': {
|
||||
compilationMode = 'infer';
|
||||
break;
|
||||
}
|
||||
case '@compilationMode(all)': {
|
||||
compilationMode = 'all';
|
||||
break;
|
||||
}
|
||||
case '@compilationMode(syntax)': {
|
||||
compilationMode = 'syntax';
|
||||
break;
|
||||
}
|
||||
case '@panicThreshold(none)': {
|
||||
panicThreshold = 'none';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsePluginOptions({
|
||||
environment,
|
||||
compilationMode,
|
||||
panicThreshold,
|
||||
});
|
||||
}
|
||||
|
||||
export type PartialEnvironmentConfig = Partial<EnvironmentConfig>;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
import {parseConfigPragmaForTests, validateEnvironmentConfig} from '..';
|
||||
import {defaultOptions} from '../Entrypoint';
|
||||
|
||||
describe('parseConfigPragmaForTests()', () => {
|
||||
it('parses flags in various forms', () => {
|
||||
@@ -19,13 +20,18 @@ describe('parseConfigPragmaForTests()', () => {
|
||||
|
||||
const config = parseConfigPragmaForTests(
|
||||
'@enableUseTypeAnnotations @validateNoSetStateInPassiveEffects:true @validateNoSetStateInRender:false',
|
||||
{compilationMode: defaultOptions.compilationMode},
|
||||
);
|
||||
expect(config).toEqual({
|
||||
...defaultConfig,
|
||||
enableUseTypeAnnotations: true,
|
||||
validateNoSetStateInPassiveEffects: true,
|
||||
validateNoSetStateInRender: false,
|
||||
enableResetCacheOnSourceFileChanges: false,
|
||||
...defaultOptions,
|
||||
panicThreshold: 'all_errors',
|
||||
environment: {
|
||||
...defaultOptions.environment,
|
||||
enableUseTypeAnnotations: true,
|
||||
validateNoSetStateInPassiveEffects: true,
|
||||
validateNoSetStateInRender: false,
|
||||
enableResetCacheOnSourceFileChanges: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,12 +11,9 @@ import {transformFromAstSync} from '@babel/core';
|
||||
import * as BabelParser from '@babel/parser';
|
||||
import {NodePath} from '@babel/traverse';
|
||||
import * as t from '@babel/types';
|
||||
import assert from 'assert';
|
||||
import type {
|
||||
CompilationMode,
|
||||
Logger,
|
||||
LoggerEvent,
|
||||
PanicThresholdOptions,
|
||||
PluginOptions,
|
||||
CompilerReactTarget,
|
||||
CompilerPipelineValue,
|
||||
@@ -51,31 +48,13 @@ function makePluginOptions(
|
||||
ValueKindEnum: typeof ValueKind,
|
||||
): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
|
||||
let gating = null;
|
||||
let compilationMode: CompilationMode = 'all';
|
||||
let panicThreshold: PanicThresholdOptions = 'all_errors';
|
||||
let hookPattern: string | null = null;
|
||||
// TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false
|
||||
let validatePreserveExistingMemoizationGuarantees = false;
|
||||
let customMacros: null | Array<Macro> = null;
|
||||
let validateBlocklistedImports = null;
|
||||
let enableFire = false;
|
||||
let target: CompilerReactTarget = '19';
|
||||
|
||||
if (firstLine.indexOf('@compilationMode(annotation)') !== -1) {
|
||||
assert(
|
||||
compilationMode === 'all',
|
||||
'Cannot set @compilationMode(..) more than once',
|
||||
);
|
||||
compilationMode = 'annotation';
|
||||
}
|
||||
if (firstLine.indexOf('@compilationMode(infer)') !== -1) {
|
||||
assert(
|
||||
compilationMode === 'all',
|
||||
'Cannot set @compilationMode(..) more than once',
|
||||
);
|
||||
compilationMode = 'infer';
|
||||
}
|
||||
|
||||
if (firstLine.includes('@gating')) {
|
||||
gating = {
|
||||
source: 'ReactForgetFeatureFlag',
|
||||
@@ -96,10 +75,6 @@ function makePluginOptions(
|
||||
}
|
||||
}
|
||||
|
||||
if (firstLine.includes('@panicThreshold(none)')) {
|
||||
panicThreshold = 'none';
|
||||
}
|
||||
|
||||
let eslintSuppressionRules: Array<string> | null = null;
|
||||
const eslintSuppressionMatch = /@eslintSuppressionRules\(([^)]+)\)/.exec(
|
||||
firstLine,
|
||||
@@ -130,10 +105,6 @@ function makePluginOptions(
|
||||
validatePreserveExistingMemoizationGuarantees = true;
|
||||
}
|
||||
|
||||
if (firstLine.includes('@enableFire')) {
|
||||
enableFire = true;
|
||||
}
|
||||
|
||||
const hookPatternMatch = /@hookPattern:"([^"]+)"/.exec(firstLine);
|
||||
if (
|
||||
hookPatternMatch &&
|
||||
@@ -199,10 +170,11 @@ function makePluginOptions(
|
||||
debugLogIRs: debugIRLogger,
|
||||
};
|
||||
|
||||
const config = parseConfigPragmaFn(firstLine);
|
||||
const config = parseConfigPragmaFn(firstLine, {compilationMode: 'all'});
|
||||
const options = {
|
||||
...config,
|
||||
environment: {
|
||||
...config,
|
||||
...config.environment,
|
||||
moduleTypeProvider: makeSharedRuntimeTypeProvider({
|
||||
EffectEnum,
|
||||
ValueKindEnum,
|
||||
@@ -212,12 +184,9 @@ function makePluginOptions(
|
||||
hookPattern,
|
||||
validatePreserveExistingMemoizationGuarantees,
|
||||
validateBlocklistedImports,
|
||||
enableFire,
|
||||
},
|
||||
compilationMode,
|
||||
logger,
|
||||
gating,
|
||||
panicThreshold,
|
||||
noEmit: false,
|
||||
eslintSuppressionRules,
|
||||
flowSuppressions,
|
||||
|
||||
Reference in New Issue
Block a user