diff --git a/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt
new file mode 100644
index 0000000000000..5633cf0b0f75a
--- /dev/null
+++ b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-all-output.txt
@@ -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;
+}
\ No newline at end of file
diff --git a/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-infer-output.txt b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-infer-output.txt
new file mode 100644
index 0000000000000..b50c37fc4e48f
--- /dev/null
+++ b/compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/compilationMode-infer-output.txt
@@ -0,0 +1,4 @@
+// @compilationMode(infer)
+function nonReactFn() {
+ return {};
+}
\ No newline at end of file
diff --git a/compiler/apps/playground/__tests__/e2e/page.spec.ts b/compiler/apps/playground/__tests__/e2e/page.spec.ts
index 05fe96d4b9048..3ba082cf62972 100644
--- a/compiler/apps/playground/__tests__/e2e/page.spec.ts
+++ b/compiler/apps/playground/__tests__/e2e/page.spec.ts
@@ -79,6 +79,24 @@ function Foo() {
// @flow
function useFoo(propVal: {+baz: number}) {
return
{(propVal.baz as number)}
;
+}
+ `,
+ noFormat: true,
+ },
+ {
+ name: 'compilationMode-infer',
+ input: `// @compilationMode(infer)
+function nonReactFn() {
+ return {};
+}
+ `,
+ noFormat: true,
+ },
+ {
+ name: 'compilationMode-all',
+ input: `// @compilationMode(all)
+function nonReactFn() {
+ return {};
}
`,
noFormat: true,
diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx
index 8c782efe54d4e..8c386116865af 100644
--- a/compiler/apps/playground/components/Editor/EditorImpl.tsx
+++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx
@@ -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
diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
index f3f426df56e44..f1db567660ec9 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
@@ -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;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts
index dc4d5d25a47e2..903afe4c20b9f 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts
@@ -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,
+ },
});
});
});
diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts
index a95c61450d840..6e59276c1cbb2 100644
--- a/compiler/packages/snap/src/compiler.ts
+++ b/compiler/packages/snap/src/compiler.ts
@@ -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 = 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 | 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,