Add option to compile ReactScript
Sathya Gunasekaran committed
Aug 9, 2023 at 14:49 UTC
5d8587b81ce59b7aa709cd22f235f62dfb3bb6a0
10 files changed
+80
-15
compiler/forget/packages/babel-plugin-react-forget/src/Babel/BabelPlugin.ts
+2
-2
@@ -5,10 +5,10 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-/// <reference path="./plugin-syntax-jsx.d.ts" />
8
+/// <reference path="./types.d.ts" />
9
10
-import jsx from "@babel/plugin-syntax-jsx";
10
import type * as BabelCore from "@babel/core";
11
+import jsx from "@babel/plugin-syntax-jsx";
12
import { compileProgram, parsePluginOptions } from "../Entrypoint";
13
14
/**
compiler/forget/packages/babel-plugin-react-forget/src/Babel/RunReactForgetBabelPlugin.ts
+19
-8
@@ -7,11 +7,12 @@
7
8
import type * as BabelCore from "@babel/core";
9
import { transformFromAstSync } from "@babel/core";
10
-import * as parser from "@babel/parser";
10
+import * as BabelParser from "@babel/parser";
11
+import * as HermesParser from "hermes-parser";
12
import invariant from "invariant";
13
import prettier from "prettier";
13
-import ReactForgetBabelPlugin from "./BabelPlugin";
14
import type { PluginOptions } from "../Entrypoint";
15
+import ReactForgetBabelPlugin from "./BabelPlugin";
16
17
type ReactForgetBabelPluginResult = {
18
ast: BabelCore.BabelFileResult["ast"];
@@ -21,16 +22,26 @@ type ReactForgetBabelPluginResult = {
22
23
export function runReactForgetBabelPlugin(
24
text: string,
24
-
25
file: string,
26
language: "flow" | "typescript",
27
options: PluginOptions | null
28
): ReactForgetBabelPluginResult {
29
- const ast = parser.parse(text, {
30
- sourceFilename: file,
31
- plugins: ["jsx", language],
32
- sourceType: "module",
33
- });
29
+ let ast;
30
+ if (language === "flow") {
31
+ ast = HermesParser.parse(text, {
32
+ babel: true,
33
+ flow: "all",
34
+ sourceFilename: file,
35
+ sourceType: "module",
36
+ enableExperimentalComponentSyntax: true,
37
+ });
38
+ } else {
39
+ ast = BabelParser.parse(text, {
40
+ sourceFilename: file,
41
+ plugins: ["typescript", "jsx"],
42
+ sourceType: "module",
43
+ });
44
+ }
45
const result = transformFromAstSync(ast, text, {
46
filename: file,
47
highlightCode: false,
compiler/forget/packages/babel-plugin-react-forget/src/Babel/types.d.ts
renamed
+1
@@ -6,3 +6,4 @@
6
*/
7
8
declare module "@babel/plugin-syntax-jsx";
9
+declare module "hermes-parser";
compiler/forget/packages/babel-plugin-react-forget/src/Entrypoint/Options.ts
+8
@@ -87,6 +87,13 @@ export type PluginOptions = {
87
* Defaults to false
88
*/
89
noEmit: boolean;
90
+
91
+ /**
92
+ * Enable to make Forget only compile components written in ReactScript syntax
93
+ * and parsed by hermes-parser.
94
+ *
95
+ */
96
+ enableOnlyOnReactScript: boolean;
97
};
98
99
export type Logger = {
@@ -94,6 +101,7 @@ export type Logger = {
101
};
102
103
export const defaultOptions: PluginOptions = {
104
+ enableOnlyOnReactScript: false,
105
enableOnlyOnUseForgetDirective: false,
106
panicOnBailout: true,
107
environment: null,
compiler/forget/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts
+6
@@ -329,6 +329,12 @@ function shouldVisitNode(
329
fn: NodePath<t.FunctionDeclaration | t.ArrowFunctionExpression>,
330
pass: CompilerPass
331
): boolean {
332
+ if (pass.opts.enableOnlyOnReactScript) {
333
+ if (!fn.get("__componentDeclaration")) {
334
+ return false;
335
+ }
336
+ }
337
+
338
if (pass.opts.enableOnlyOnUseForgetDirective) {
339
const body = fn.get("body");
340
if (!body.isBlockStatement()) {
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.expect.md
-1
@@ -16,7 +16,6 @@ function Component(props) {
16
## Code
17
18
```javascript
19
-// @flow
19
function Component(props) {
20
const x = foo();
21
return x;
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactscript-basic.flow.expect.md
new
+31
@@ -0,0 +1,31 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @reactScriptDirective
6
+export default component Foo(bar: number) {
7
+ return <Bar bar={bar} />;
8
+}
9
+```
10
+
11
+## Code
12
+
13
+```javascript
14
+import { unstable_useMemoCache as useMemoCache } from "react";
15
+export default function Foo(t7) {
16
+ const $ = useMemoCache(2);
17
+ const { bar } = t7;
18
+ const c_0 = $[0] !== bar;
19
+ let t0;
20
+ if (c_0) {
21
+ t0 = <Bar bar={bar} />;
22
+ $[0] = bar;
23
+ $[1] = t0;
24
+ } else {
25
+ t0 = $[1];
26
+ }
27
+ return t0;
28
+}
29
+
30
+```
31
+
\ No newline at end of file
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/reactscript-basic.flow.js
new
+4
@@ -0,0 +1,4 @@
1
+// @reactScriptDirective
2
+export default component Foo(bar: number) {
3
+ return <Bar bar={bar} />;
4
+}
\ No newline at end of file
compiler/forget/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/type-cast-expression.flow.expect.md
+1
-1
@@ -16,7 +16,7 @@ function Component(props) {
16
## Code
17
18
```javascript
19
-import { unstable_useMemoCache as useMemoCache } from "react"; // @flow
19
+import { unstable_useMemoCache as useMemoCache } from "react";
20
type Foo = { bar: string };
21
function Component(props) {
22
const $ = useMemoCache(2);
compiler/forget/packages/snap/src/compiler-worker.ts
+8
-3
@@ -87,6 +87,7 @@ export async function compile(
87
88
// Extract the first line to quickly check for custom test directives
89
const firstLine = input.substring(0, input.indexOf("\n"));
90
+ let language = parseLanguage(firstLine);
91
92
let enableOnlyOnUseForgetDirective = false;
93
let gating = null;
@@ -100,6 +101,7 @@ export async function compile(
101
let validateNoSetStateInRender = true;
102
let enableEmitFreeze = null;
103
let enableOptimizeFunctionExpressions = true;
104
+ let enableOnlyOnReactScript = false;
105
if (firstLine.indexOf("@forgetDirective") !== -1) {
106
enableOnlyOnUseForgetDirective = true;
107
}
@@ -145,11 +147,12 @@ export async function compile(
147
importSpecifierName: "makeReadOnly",
148
};
149
}
148
-
149
- const language = parseLanguage(firstLine);
150
+ if (firstLine.indexOf("@reactScriptDirective") !== -1) {
151
+ enableOnlyOnReactScript = true;
152
+ language = "flow";
153
+ }
154
155
code = runReactForgetBabelPlugin(input, basename, language, {
152
- enableOnlyOnUseForgetDirective,
156
environment: {
157
customHooks: new Map([
158
[
@@ -174,6 +177,8 @@ export async function compile(
177
enableOptimizeFunctionExpressions,
178
assertValidMutableRanges: true,
179
},
180
+ enableOnlyOnUseForgetDirective,
181
+ enableOnlyOnReactScript,
182
logger: null,
183
gating,
184
instrumentForget,