Add option to compile ReactScript

This commit is contained in:
Sathya Gunasekaran
2023-08-09 14:49:29 -04:00
parent 27f38ec321
commit 5d8587b81c
10 changed files with 80 additions and 15 deletions
@@ -5,10 +5,10 @@
* LICENSE file in the root directory of this source tree.
*/
/// <reference path="./plugin-syntax-jsx.d.ts" />
/// <reference path="./types.d.ts" />
import jsx from "@babel/plugin-syntax-jsx";
import type * as BabelCore from "@babel/core";
import jsx from "@babel/plugin-syntax-jsx";
import { compileProgram, parsePluginOptions } from "../Entrypoint";
/**
@@ -7,11 +7,12 @@
import type * as BabelCore from "@babel/core";
import { transformFromAstSync } from "@babel/core";
import * as parser from "@babel/parser";
import * as BabelParser from "@babel/parser";
import * as HermesParser from "hermes-parser";
import invariant from "invariant";
import prettier from "prettier";
import ReactForgetBabelPlugin from "./BabelPlugin";
import type { PluginOptions } from "../Entrypoint";
import ReactForgetBabelPlugin from "./BabelPlugin";
type ReactForgetBabelPluginResult = {
ast: BabelCore.BabelFileResult["ast"];
@@ -21,16 +22,26 @@ type ReactForgetBabelPluginResult = {
export function runReactForgetBabelPlugin(
text: string,
file: string,
language: "flow" | "typescript",
options: PluginOptions | null
): ReactForgetBabelPluginResult {
const ast = parser.parse(text, {
sourceFilename: file,
plugins: ["jsx", language],
sourceType: "module",
});
let ast;
if (language === "flow") {
ast = HermesParser.parse(text, {
babel: true,
flow: "all",
sourceFilename: file,
sourceType: "module",
enableExperimentalComponentSyntax: true,
});
} else {
ast = BabelParser.parse(text, {
sourceFilename: file,
plugins: ["typescript", "jsx"],
sourceType: "module",
});
}
const result = transformFromAstSync(ast, text, {
filename: file,
highlightCode: false,
@@ -6,3 +6,4 @@
*/
declare module "@babel/plugin-syntax-jsx";
declare module "hermes-parser";
@@ -87,6 +87,13 @@ export type PluginOptions = {
* Defaults to false
*/
noEmit: boolean;
/**
* Enable to make Forget only compile components written in ReactScript syntax
* and parsed by hermes-parser.
*
*/
enableOnlyOnReactScript: boolean;
};
export type Logger = {
@@ -94,6 +101,7 @@ export type Logger = {
};
export const defaultOptions: PluginOptions = {
enableOnlyOnReactScript: false,
enableOnlyOnUseForgetDirective: false,
panicOnBailout: true,
environment: null,
@@ -329,6 +329,12 @@ function shouldVisitNode(
fn: NodePath<t.FunctionDeclaration | t.ArrowFunctionExpression>,
pass: CompilerPass
): boolean {
if (pass.opts.enableOnlyOnReactScript) {
if (!fn.get("__componentDeclaration")) {
return false;
}
}
if (pass.opts.enableOnlyOnUseForgetDirective) {
const body = fn.get("body");
if (!body.isBlockStatement()) {
@@ -16,7 +16,6 @@ function Component(props) {
## Code
```javascript
// @flow
function Component(props) {
const x = foo();
return x;
@@ -0,0 +1,31 @@
## Input
```javascript
// @reactScriptDirective
export default component Foo(bar: number) {
return <Bar bar={bar} />;
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
export default function Foo(t7) {
const $ = useMemoCache(2);
const { bar } = t7;
const c_0 = $[0] !== bar;
let t0;
if (c_0) {
t0 = <Bar bar={bar} />;
$[0] = bar;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
@@ -0,0 +1,4 @@
// @reactScriptDirective
export default component Foo(bar: number) {
return <Bar bar={bar} />;
}
@@ -16,7 +16,7 @@ function Component(props) {
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @flow
import { unstable_useMemoCache as useMemoCache } from "react";
type Foo = { bar: string };
function Component(props) {
const $ = useMemoCache(2);
@@ -87,6 +87,7 @@ export async function compile(
// Extract the first line to quickly check for custom test directives
const firstLine = input.substring(0, input.indexOf("\n"));
let language = parseLanguage(firstLine);
let enableOnlyOnUseForgetDirective = false;
let gating = null;
@@ -100,6 +101,7 @@ export async function compile(
let validateNoSetStateInRender = true;
let enableEmitFreeze = null;
let enableOptimizeFunctionExpressions = true;
let enableOnlyOnReactScript = false;
if (firstLine.indexOf("@forgetDirective") !== -1) {
enableOnlyOnUseForgetDirective = true;
}
@@ -145,11 +147,12 @@ export async function compile(
importSpecifierName: "makeReadOnly",
};
}
const language = parseLanguage(firstLine);
if (firstLine.indexOf("@reactScriptDirective") !== -1) {
enableOnlyOnReactScript = true;
language = "flow";
}
code = runReactForgetBabelPlugin(input, basename, language, {
enableOnlyOnUseForgetDirective,
environment: {
customHooks: new Map([
[
@@ -174,6 +177,8 @@ export async function compile(
enableOptimizeFunctionExpressions,
assertValidMutableRanges: true,
},
enableOnlyOnUseForgetDirective,
enableOnlyOnReactScript,
logger: null,
gating,
instrumentForget,