Skip to content

Commit 50216c6

Browse files
committed
[compiler] Playground qol: shared compilation option directives with tests
- Adds @compilationMode(all|infer|syntax|annotation) and @panicMode(none) directives. This is now shared with our test infra - Playground still defaults to `infer` mode while tests default to `all` mode - See added fixture tests
1 parent f892dab commit 50216c6

File tree

7 files changed

+154
-96
lines changed

7 files changed

+154
-96
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { c as _c } from "react/compiler-runtime"; // 
2+
        @compilationMode(all)
3+
function nonReactFn() {
4+
  const $ = _c(1);
5+
  let t0;
6+
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
7+
    t0 = {};
8+
    $[0] = t0;
9+
  } else {
10+
    t0 = $[0];
11+
  }
12+
  return t0;
13+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @compilationMode(infer)
2+
function nonReactFn() {
3+
  return {};
4+
}

compiler/apps/playground/__tests__/e2e/page.spec.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,24 @@ function Foo() {
7979
// @flow
8080
function useFoo(propVal: {+baz: number}) {
8181
return <div>{(propVal.baz as number)}</div>;
82+
}
83+
`,
84+
noFormat: true,
85+
},
86+
{
87+
name: 'compilationMode-infer',
88+
input: `// @compilationMode(infer)
89+
function nonReactFn() {
90+
return {};
91+
}
92+
`,
93+
noFormat: true,
94+
},
95+
{
96+
name: 'compilationMode-all',
97+
input: `// @compilationMode(all)
98+
function nonReactFn() {
99+
return {};
82100
}
83101
`,
84102
noFormat: true,
@@ -142,7 +160,7 @@ test('reset button works', async ({page}) => {
142160
});
143161

144162
TEST_CASE_INPUTS.forEach((t, idx) =>
145-
test(`playground compiles: ${t.name}`, async ({page}) => {
163+
test.only(`playground compiles: ${t.name}`, async ({page}) => {
146164
const store: Store = {
147165
source: t.input,
148166
};

compiler/apps/playground/components/Editor/EditorImpl.tsx

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import BabelPluginReactCompiler, {
2020
CompilerPipelineValue,
2121
parsePluginOptions,
2222
} from 'babel-plugin-react-compiler/src';
23-
import {type EnvironmentConfig} from 'babel-plugin-react-compiler/src/HIR/Environment';
2423
import clsx from 'clsx';
2524
import invariant from 'invariant';
2625
import {useSnackbar} from 'notistack';
@@ -69,22 +68,14 @@ function parseInput(
6968
function invokeCompiler(
7069
source: string,
7170
language: 'flow' | 'typescript',
72-
environment: EnvironmentConfig,
73-
logIR: (pipelineValue: CompilerPipelineValue) => void,
71+
options: PluginOptions,
7472
): CompilerTransformOutput {
75-
const opts: PluginOptions = parsePluginOptions({
76-
logger: {
77-
debugLogIRs: logIR,
78-
logEvent: () => {},
79-
},
80-
environment,
81-
});
8273
const ast = parseInput(source, language);
8374
let result = transformFromAstSync(ast, source, {
8475
filename: '_playgroundFile.js',
8576
highlightCode: false,
8677
retainLines: true,
87-
plugins: [[BabelPluginReactCompiler, opts]],
78+
plugins: [[BabelPluginReactCompiler, options]],
8879
ast: true,
8980
sourceType: 'module',
9081
configFile: false,
@@ -170,51 +161,59 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
170161
try {
171162
// Extract the first line to quickly check for custom test directives
172163
const pragma = source.substring(0, source.indexOf('\n'));
173-
const config = parseConfigPragmaForTests(pragma);
174-
175-
transformOutput = invokeCompiler(
176-
source,
177-
language,
178-
{...config, customHooks: new Map([...COMMON_HOOKS])},
179-
result => {
180-
switch (result.kind) {
181-
case 'ast': {
182-
break;
183-
}
184-
case 'hir': {
185-
upsert({
186-
kind: 'hir',
187-
fnName: result.value.id,
188-
name: result.name,
189-
value: printFunctionWithOutlined(result.value),
190-
});
191-
break;
192-
}
193-
case 'reactive': {
194-
upsert({
195-
kind: 'reactive',
196-
fnName: result.value.id,
197-
name: result.name,
198-
value: printReactiveFunctionWithOutlined(result.value),
199-
});
200-
break;
201-
}
202-
case 'debug': {
203-
upsert({
204-
kind: 'debug',
205-
fnName: null,
206-
name: result.name,
207-
value: result.value,
208-
});
209-
break;
210-
}
211-
default: {
212-
const _: never = result;
213-
throw new Error(`Unhandled result ${result}`);
214-
}
164+
const logIR = (result: CompilerPipelineValue): void => {
165+
switch (result.kind) {
166+
case 'ast': {
167+
break;
168+
}
169+
case 'hir': {
170+
upsert({
171+
kind: 'hir',
172+
fnName: result.value.id,
173+
name: result.name,
174+
value: printFunctionWithOutlined(result.value),
175+
});
176+
break;
177+
}
178+
case 'reactive': {
179+
upsert({
180+
kind: 'reactive',
181+
fnName: result.value.id,
182+
name: result.name,
183+
value: printReactiveFunctionWithOutlined(result.value),
184+
});
185+
break;
215186
}
187+
case 'debug': {
188+
upsert({
189+
kind: 'debug',
190+
fnName: null,
191+
name: result.name,
192+
value: result.value,
193+
});
194+
break;
195+
}
196+
default: {
197+
const _: never = result;
198+
throw new Error(`Unhandled result ${result}`);
199+
}
200+
}
201+
};
202+
const parsedOptions = parseConfigPragmaForTests(pragma, {
203+
compilationMode: 'infer',
204+
});
205+
const opts: PluginOptions = parsePluginOptions({
206+
...parsedOptions,
207+
environment: {
208+
...parsedOptions.environment,
209+
customHooks: new Map([...COMMON_HOOKS]),
216210
},
217-
);
211+
logger: {
212+
debugLogIRs: logIR,
213+
logEvent: () => {},
214+
},
215+
});
216+
transformOutput = invokeCompiler(source, language, opts);
218217
} catch (err) {
219218
/**
220219
* error might be an invariant violation or other runtime error

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ import * as t from '@babel/types';
99
import {ZodError, z} from 'zod';
1010
import {fromZodError} from 'zod-validation-error';
1111
import {CompilerError} from '../CompilerError';
12-
import {Logger} from '../Entrypoint';
12+
import {
13+
CompilationMode,
14+
Logger,
15+
PanicThresholdOptions,
16+
parsePluginOptions,
17+
PluginOptions,
18+
} from '../Entrypoint';
1319
import {Err, Ok, Result} from '../Utils/Result';
1420
import {
1521
DEFAULT_GLOBALS,
@@ -683,7 +689,9 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
683689
/**
684690
* For snap test fixtures and playground only.
685691
*/
686-
export function parseConfigPragmaForTests(pragma: string): EnvironmentConfig {
692+
function parseConfigPragmaEnvironmentForTest(
693+
pragma: string,
694+
): EnvironmentConfig {
687695
const maybeConfig: any = {};
688696
// Get the defaults to programmatically check for boolean properties
689697
const defaultConfig = EnvironmentConfigSchema.parse({});
@@ -749,6 +757,48 @@ export function parseConfigPragmaForTests(pragma: string): EnvironmentConfig {
749757
suggestions: null,
750758
});
751759
}
760+
export function parseConfigPragmaForTests(
761+
pragma: string,
762+
defaults: {
763+
compilationMode: CompilationMode;
764+
},
765+
): PluginOptions {
766+
const environment = parseConfigPragmaEnvironmentForTest(pragma);
767+
let compilationMode: CompilationMode = defaults.compilationMode;
768+
let panicThreshold: PanicThresholdOptions = 'all_errors';
769+
for (const token of pragma.split(' ')) {
770+
if (!token.startsWith('@')) {
771+
continue;
772+
}
773+
switch (token) {
774+
case '@compilationMode(annotation)': {
775+
compilationMode = 'annotation';
776+
break;
777+
}
778+
case '@compilationMode(infer)': {
779+
compilationMode = 'infer';
780+
break;
781+
}
782+
case '@compilationMode(all)': {
783+
compilationMode = 'all';
784+
break;
785+
}
786+
case '@compilationMode(syntax)': {
787+
compilationMode = 'syntax';
788+
break;
789+
}
790+
case '@panicThreshold(none)': {
791+
panicThreshold = 'none';
792+
break;
793+
}
794+
}
795+
}
796+
return parsePluginOptions({
797+
environment,
798+
compilationMode,
799+
panicThreshold,
800+
});
801+
}
752802

753803
export type PartialEnvironmentConfig = Partial<EnvironmentConfig>;
754804

compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
import {parseConfigPragmaForTests, validateEnvironmentConfig} from '..';
9+
import {defaultOptions} from '../Entrypoint';
910

1011
describe('parseConfigPragmaForTests()', () => {
1112
it('parses flags in various forms', () => {
@@ -19,13 +20,17 @@ describe('parseConfigPragmaForTests()', () => {
1920

2021
const config = parseConfigPragmaForTests(
2122
'@enableUseTypeAnnotations @validateNoSetStateInPassiveEffects:true @validateNoSetStateInRender:false',
23+
{compilationMode: defaultOptions.compilationMode},
2224
);
2325
expect(config).toEqual({
24-
...defaultConfig,
25-
enableUseTypeAnnotations: true,
26-
validateNoSetStateInPassiveEffects: true,
27-
validateNoSetStateInRender: false,
28-
enableResetCacheOnSourceFileChanges: false,
26+
...defaultOptions,
27+
environment: {
28+
...defaultOptions.environment,
29+
enableUseTypeAnnotations: true,
30+
validateNoSetStateInPassiveEffects: true,
31+
validateNoSetStateInRender: false,
32+
enableResetCacheOnSourceFileChanges: false,
33+
},
2934
});
3035
});
3136
});

compiler/packages/snap/src/compiler.ts

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@ import {transformFromAstSync} from '@babel/core';
1111
import * as BabelParser from '@babel/parser';
1212
import {NodePath} from '@babel/traverse';
1313
import * as t from '@babel/types';
14-
import assert from 'assert';
1514
import type {
16-
CompilationMode,
1715
Logger,
1816
LoggerEvent,
19-
PanicThresholdOptions,
2017
PluginOptions,
2118
CompilerReactTarget,
2219
CompilerPipelineValue,
@@ -51,31 +48,13 @@ function makePluginOptions(
5148
ValueKindEnum: typeof ValueKind,
5249
): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
5350
let gating = null;
54-
let compilationMode: CompilationMode = 'all';
55-
let panicThreshold: PanicThresholdOptions = 'all_errors';
5651
let hookPattern: string | null = null;
5752
// TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false
5853
let validatePreserveExistingMemoizationGuarantees = false;
5954
let customMacros: null | Array<Macro> = null;
6055
let validateBlocklistedImports = null;
61-
let enableFire = false;
6256
let target: CompilerReactTarget = '19';
6357

64-
if (firstLine.indexOf('@compilationMode(annotation)') !== -1) {
65-
assert(
66-
compilationMode === 'all',
67-
'Cannot set @compilationMode(..) more than once',
68-
);
69-
compilationMode = 'annotation';
70-
}
71-
if (firstLine.indexOf('@compilationMode(infer)') !== -1) {
72-
assert(
73-
compilationMode === 'all',
74-
'Cannot set @compilationMode(..) more than once',
75-
);
76-
compilationMode = 'infer';
77-
}
78-
7958
if (firstLine.includes('@gating')) {
8059
gating = {
8160
source: 'ReactForgetFeatureFlag',
@@ -96,10 +75,6 @@ function makePluginOptions(
9675
}
9776
}
9877

99-
if (firstLine.includes('@panicThreshold(none)')) {
100-
panicThreshold = 'none';
101-
}
102-
10378
let eslintSuppressionRules: Array<string> | null = null;
10479
const eslintSuppressionMatch = /@eslintSuppressionRules\(([^)]+)\)/.exec(
10580
firstLine,
@@ -130,10 +105,6 @@ function makePluginOptions(
130105
validatePreserveExistingMemoizationGuarantees = true;
131106
}
132107

133-
if (firstLine.includes('@enableFire')) {
134-
enableFire = true;
135-
}
136-
137108
const hookPatternMatch = /@hookPattern:"([^"]+)"/.exec(firstLine);
138109
if (
139110
hookPatternMatch &&
@@ -199,10 +170,11 @@ function makePluginOptions(
199170
debugLogIRs: debugIRLogger,
200171
};
201172

202-
const config = parseConfigPragmaFn(firstLine);
173+
const config = parseConfigPragmaFn(firstLine, {compilationMode: 'all'});
203174
const options = {
175+
...config,
204176
environment: {
205-
...config,
177+
...config.environment,
206178
moduleTypeProvider: makeSharedRuntimeTypeProvider({
207179
EffectEnum,
208180
ValueKindEnum,
@@ -212,12 +184,9 @@ function makePluginOptions(
212184
hookPattern,
213185
validatePreserveExistingMemoizationGuarantees,
214186
validateBlocklistedImports,
215-
enableFire,
216187
},
217-
compilationMode,
218188
logger,
219189
gating,
220-
panicThreshold,
221190
noEmit: false,
222191
eslintSuppressionRules,
223192
flowSuppressions,

0 commit comments

Comments
 (0)