[be] Move old compiler to separate package

This commit is contained in:
Joe Savona
2022-12-16 09:33:07 -08:00
parent 7a29405d68
commit 075cdcec9e
96 changed files with 5104 additions and 54 deletions
@@ -0,0 +1,73 @@
{
"name": "babel-plugin-react-forget-legacy",
"version": "0.0.1",
"description": "Babel plugin for React Forget.",
"main": "dist/index.js",
"license": "MIT",
"files": [
"src"
],
"scripts": {
"build": "tsc && scripts/hash-dist.sh",
"bundle:meta": "scripts/bundle-meta.sh",
"dev": "concurrently --kill-others \"tsc --watch\" \"yarn:playground\"",
"playground": "cd packages/playground && yarn && yarn dev",
"test": "yarn build && jest",
"ts:analyze-trace": "scripts/ts-analyze-trace.sh",
"test262": "yarn run --silent test262-harness --preprocessor=scripts/test262-preprocessor.js",
"test262:all": "yarn run --silent test262 'test262/test/**/*.js'",
"test262:ci": "scripts/test262.sh",
"prettier": "node ./scripts/prettier.js write-changed",
"prettier:all": "node ./scripts/prettier.js write",
"prettier:ci": "prettier --check ."
},
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react-forget.git"
},
"dependencies": {
"@babel/generator": "7.2.0",
"@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/types": "^7.19.0",
"invariant": "^2.2.4",
"prettier": "2.7.1",
"pretty-format": "^24"
},
"devDependencies": {
"@babel/core": "^7.19.1",
"@babel/parser": "^7.19.1",
"@babel/plugin-syntax-typescript": "^7.18.6",
"@babel/plugin-transform-block-scoping": "^7.18.9",
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/traverse": "^7.19.1",
"@hpcc-js/wasm": "^1.15.0",
"@testing-library/react": "^13.4.0",
"@tsconfig/node16-strictest": "^1.0.3",
"@types/eslint": "^8.4.6",
"@types/invariant": "^2.2.35",
"@types/jest": "^29.0.3",
"@types/node": "^18.7.18",
"babel-jest": "^29.0.3",
"chalk": "^3.0.0",
"concurrently": "^7.4.0",
"eslint": "^8.25.0",
"glob": "^7.1.6",
"hermes-eslint": "^0.9.0",
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"test262-harness": "^8.0.0",
"ts-jest": "^29.0.1",
"ts-node": "^10.9.1",
"typescript": "^4.8.3"
},
"resolutions": {
"./**/@babel/parser": "7.7.4",
"./**/@babel/types": "7.7.4",
"@babel/core": "7.2.0",
"@babel/traverse": "7.1.6"
}
}
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -eo pipefail
# Hashes JS files in the dist directory to create a cache-breaker
find dist -name '*.js' | sort | xargs shasum | shasum | awk '{ print $1 }' > dist/HASH
@@ -0,0 +1,42 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/// <reference path="./plugin-syntax-jsx.d.ts" />
import jsx from "@babel/plugin-syntax-jsx";
import type { PluginObj } from "@babel/core";
import type * as BabelCore from "@babel/core";
import { createCompilerDriver } from "./CompilerDriver";
import { CompilerOptions, parseCompilerOptions } from "./CompilerOptions";
/**
* The React Forget Babel Plugin
* @param {*} babel
* @returns
*/
export default function (babel: typeof BabelCore): PluginObj {
return {
name: "react-forget",
inherits: jsx,
visitor: {
Program: {
enter(program, pass) {
let compilerOptions: CompilerOptions;
try {
compilerOptions = parseCompilerOptions(pass.opts);
} catch (err) {
throw new Error(
`PluginOptions is required to be valid CompilerOptions: ${err}.`
);
}
let compiler = createCompilerDriver(compilerOptions, program);
compiler.compile();
},
},
},
};
}
@@ -0,0 +1,113 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import * as t from "@babel/types";
import generate from "@babel/generator";
/**
* Dumper.
*/
const defaultDumpNodeOption = {
// dump with location.
loc: false,
// dump with the node type.
type: false,
// dump as the entire source code instead of a shorten name.
source: false,
// instead of <anno>, fallback to source.
fallbackToSource: true,
};
type DumpNodeOption = typeof defaultDumpNodeOption;
export function dumpNodeLoc(node: t.Node): string {
return `${node.loc?.start.line ?? "?"}:${node.loc?.start.column ?? "?"}`;
}
/**
* Dump a string form of the @param node to help with debugging.
*/
export function dumpNode(
node: t.Node | null | undefined,
options: Partial<DumpNodeOption> = defaultDumpNodeOption
): string {
let str = "";
let opt = { ...defaultDumpNodeOption, ...options };
if (!node) return "";
if (opt.loc) {
str += `${dumpNodeLoc(node)} `;
}
if (opt.source) {
str += generate(node).code;
} else {
switch (node.type) {
case "Identifier":
str += node.name;
break;
case "JSXIdentifier":
str += `${node.name}`;
break;
case "VariableDeclarator":
str += `${dumpNode(node.id, { source: true })}`;
break;
case "JSXMemberExpression":
str += `${dumpNode(node.object)}.${dumpNode(node.property)}`;
break;
case "JSXNamespacedName":
str += `${dumpNode(node.namespace)}:${dumpNode(node.name)}`;
break;
case "JSXOpeningElement":
str += dumpNode(node.name);
break;
case "JSXAttribute":
str += dumpNode(node.name);
break;
case "FunctionDeclaration":
str += `function ${dumpNode(node.id)}`;
break;
case "JSXFragment":
str += `<>`;
break;
case "JSXElement":
if (node.selfClosing) {
str += `<${dumpNode(node.openingElement)} />`;
} else {
str += `<${dumpNode(node.openingElement)}>`;
}
break;
default:
if (opt.fallbackToSource) {
str += "`" + generate(node, { compact: true }).code + "`";
} else {
str += `<anno>`;
}
}
}
if (opt.type) {
str += ` : ${node.type}`;
}
return str;
}
@@ -0,0 +1,39 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { Node, NodePath } from "@babel/traverse";
/**
* A utility type to generate NodePath as a disjointed union type for better
* type refinement and exhaustiveness check.
*
* @see https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
*/
export type PathUnion<N extends Node | undefined | null> = N extends Node
? NodePath<N>
: N extends undefined
? NodePath<undefined>
: N extends null
? NodePath<null>
: never;
/**
* Cast @param path of type {@link NodePath} to {@link PathUnion}.
*
* This should only be used right before a type refinement (aka. narrowing):
*
* const path = pathUnion(rawPath)
* switch(path.kind) {
* case "A":
* // path is now refined to NodePath<A>
* }
*/
export function pathUnion<N extends Node | null | undefined>(
path: NodePath<N>
): PathUnion<N> {
return path as PathUnion<N>;
}
@@ -0,0 +1,83 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Individual util functions.
*/
export function setEq<T>(a: Set<T>, b: Set<T>): boolean {
return a.size === b.size && [...a].every((v) => b.has(v));
}
export function nullableSetEq<T>(
a: Set<T> | undefined,
b: Set<T> | undefined
): boolean {
if (a === undefined && b === undefined) return true;
if (a === undefined || b === undefined) return false;
return a.size === b.size && [...a].every((v) => b.has(v));
}
export function setSubset<T>(a: Set<T>, b: Set<T>): boolean {
return a.size <= b.size && [...a].every((v) => b.has(v));
}
export function setIntersect<T>(a: Set<T>, b: Set<T>): boolean {
return [...a].some((v) => b.has(v));
}
export function setFirst<T>(s: Set<T>): T {
return [...s][0];
}
export function setEmpty<T>(s: Set<T>): boolean {
return s.size === 0;
}
export function hasOwnProperty<T>(obj: T, key: PropertyKey): key is keyof T {
return Object.prototype.hasOwnProperty.call(obj, key);
}
/**
* Trigger an exhaustivess check in TypeScript and throw at runtime.
*
* Example:
*
* ```ts
* enum ErrorCode = {
* E0001 = "E0001",
* E0002 = "E0002"
* }
*
* switch (code) {
* case ErrorCode.E0001:
* // ...
* default:
* assertExhaustive(code, "Unhandled error code");
* }
* ```
*/
export function assertExhaustive(_: never, errorMsg: string): never {
throw new Error(errorMsg);
}
/**
* Modifies @param array in place, retaining only the items where the predicate returns true.
*/
export function retainWhere<T>(
array: Array<T>,
predicate: (item: T) => boolean
) {
let writeIndex = 0;
for (let readIndex = 0; readIndex < array.length; readIndex++) {
const item = array[readIndex];
if (predicate(item) === true) {
array[writeIndex++] = item;
}
}
array.length = writeIndex;
}
@@ -0,0 +1,27 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import invariant from "invariant";
import { getMostRecentCompilerContext } from "./CompilerContext";
// Record a bailout if there is an invariant violation and a recently created compiler context.
// Otherwise, just throws a regular invariant.
function compilerInvariant(
condition: unknown,
format: string,
...args: any[]
): asserts condition {
let context = null;
try {
context = getMostRecentCompilerContext();
} catch (_) {}
if (context != null) {
return context.invariant(condition, format, ...args);
}
return invariant(condition, format, ...args);
}
export { compilerInvariant as invariant };
@@ -7,7 +7,7 @@
import generate from "@babel/generator";
import * as t from "@babel/types";
import * as IR from "../IR";
import * as IR from ".";
import * as LIR from "../LIR";
export default function prettyPrint(irFunc: IR.Func) {
@@ -6,7 +6,7 @@
*/
import * as t from "@babel/types";
import * as IR from "../IR";
import * as IR from ".";
import { dumpNodeLoc } from "../Common/Dumper";
export class ValSnapshot {
@@ -7,6 +7,7 @@
import generate from "@babel/generator";
import * as t from "@babel/types";
import * as LIR from ".";
import { assertExhaustive } from "../Common/utils";
import { invariant } from "../CompilerError";
import * as IR from "../IR";
@@ -16,7 +17,6 @@ import {
revertAddComments,
revertRenameReactiveVal,
} from "../IR/PrettyPrinter";
import * as LIR from "../LIR";
import {
EntryKind,
isExprEntry,
@@ -0,0 +1,5 @@
## TODOs
This directory contains files that are currently crashing the compiler and
should be moved to `../transform/` as a potential new fixture once the crash
is fixed.
@@ -0,0 +1,15 @@
// @Out DumpCFG
function useForOfStatement(x) {
"use forget";
const items = [];
let item;
for (item of x) {
if (shouldBreak()) {
break;
} else if (shouldContinue()) {
continue;
}
items.push(item);
}
return items;
}
@@ -0,0 +1,206 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
"use strict";
/* global expect,test */
import fs from "fs";
import path from "path";
const EXPECT_SUFFIX = ".expect.md";
const PROJECT_ROOT = path.dirname(path.dirname(__dirname));
expect.extend({
accessSnapshotState(_anything, cb) {
cb(this["snapshotState"]._updateSnapshot);
return {
pass: true,
message: () => "",
};
},
toHaveNoUnmatchedSnapshots(unmatchedSnapshots, fixturesPath) {
return {
pass: unmatchedSnapshots.length === 0,
message: () => {
const unmatchedSnapshotsText = unmatchedSnapshots
.map((file: string) => path.join(fixturesPath, file))
.join("\n * ");
return (
`Found ${EXPECT_SUFFIX} files without corresponding inputs:\n* ${unmatchedSnapshotsText}` +
`\n\nRun 'npm test -- -u' to remove these extra ${EXPECT_SUFFIX} files`
);
},
};
},
});
export default function generateTestsFromFixtures(
fixturesPath: string,
transform: (input: string, file: any, options: { debug: boolean }) => string
) {
const files = fs.readdirSync(fixturesPath);
const fixtures = matchInputOutputFixtures(files, fixturesPath);
const relativeFixturesPath = path.relative(PROJECT_ROOT, fixturesPath);
describe(relativeFixturesPath, () => {
test("has input fixtures", () => {
expect(fixtures.size).toBeGreaterThan(0);
});
test("has a consistent extension for input fixtures", () => {
const extensions = Array.from(
new Set(
Array.from(fixtures.values())
.map((entry) =>
entry.input != null ? path.extname(entry.input) : null
)
.filter(Boolean)
)
);
expect(extensions).toEqual(extensions.slice(0, 1));
});
describe("fixtures", () => {
for (const {
basename,
input: inputFile,
output: outputFile,
} of Array.from(fixtures.values())) {
let testCommand;
switch (basename.split(".")[0]) {
case "only":
testCommand = test.only;
break;
case "skip":
testCommand = test.skip;
break;
default:
testCommand = test;
break;
}
let input: string | null = null;
let debug = false;
if (inputFile != null) {
input = fs.readFileSync(inputFile, "utf8");
const lines = input.split("\n");
if (lines[0]!.indexOf("@only") !== -1) {
testCommand = test.only;
debug = true;
}
}
testCommand(basename, () => {
let receivedOutput;
if (input !== null) {
receivedOutput = transform(input, basename, { debug });
} else {
receivedOutput = "<<input deleted>>";
}
// Use a standard snapshot for the expected output so that the snapshot fails unless the
// value matches
expect(receivedOutput).toMatchSnapshot();
// Determine whether the snapshot is in update mode or only creating snapshots for new inputs
// to update the .expect file in parallel with updating the snapshot itself.
const snapshotUpdateMode = determineSnapshotMode();
if (outputFile != null) {
const outputExists = fs.existsSync(outputFile);
if (
snapshotUpdateMode === "all" ||
(snapshotUpdateMode === "new" && !outputExists)
) {
if (inputFile != null) {
fs.writeFileSync(outputFile, receivedOutput, "utf8");
} else {
fs.unlinkSync(outputFile);
}
} else {
// As a sanity check, make sure that the current output matches the .expect file
const actualOutput = fs.readFileSync(outputFile, "utf8");
expect(receivedOutput).toEqual(actualOutput);
}
}
});
}
});
});
}
function determineSnapshotMode() {
// Determine which snapshot mode we're in: ignoring snapshots,
// updating new files only, or updating all files
let updateSnapshots = "none";
// @ts-ignore
expect(null).accessSnapshotState((_updateSnapshots) => {
updateSnapshots = _updateSnapshots;
});
const updateSnapshotEnvVariable = process.env["UPDATE_SNAPSHOTS"];
if (
updateSnapshotEnvVariable === "1" ||
updateSnapshotEnvVariable === "all"
) {
console.log(
"Updating all snapshots due to UPDATE_SNAPSHOTS environment variable being set"
);
updateSnapshots = "all";
} else {
// @ts-ignore
expect(updateSnapshotEnvVariable).toEqual();
}
expect(updateSnapshots).toEqual(expect.stringMatching(/none|new|all/));
return updateSnapshots;
}
function matchInputOutputFixtures(files: string[], fixturesPath: string) {
const fixtures: Map<
string,
{ basename: string; input: string | null; output: string | null }
> = new Map();
for (const file of files) {
const isOutput = file.endsWith(EXPECT_SUFFIX);
const basename = path.basename(
file,
isOutput ? EXPECT_SUFFIX : path.extname(file)
);
let entry = fixtures.get(basename);
if (entry === undefined) {
entry = { basename, input: null, output: null };
fixtures.set(basename, entry);
}
const resolvedPath = path.format({
dir: fixturesPath,
name: file,
});
if (isOutput) {
entry.output = resolvedPath;
} else {
if (entry.input !== null) {
throw new Error(
"Found multiple inputs with the basename '" +
basename +
"': " +
entry.input +
" and " +
resolvedPath
);
}
entry.input = resolvedPath;
const outputFile = path.format({
dir: fixturesPath,
name: basename,
ext: EXPECT_SUFFIX,
});
entry.output = outputFile;
}
}
return fixtures;
}
@@ -0,0 +1,41 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @ts-ignore-line
import { Linter } from "eslint/lib/linter";
// @ts-ignore-line
import * as HermesESLint from "hermes-eslint";
// @ts-ignore-line
import { NoUseBeforeDefineRule } from "../..";
const ESLINT_CONFIG: Linter.Config = {
parser: "hermes-eslint",
parserOptions: {
sourceType: "module",
},
rules: {
"custom-no-use-before-define": [
"error",
{ variables: false, functions: false },
],
},
};
/**
* Post-codegen pass to validate that the generated code does not introduce bugs.
* Note that the compiler currently incorrectly reorders code in some cases: this
* step detects this using ESLint's no-use-before-define rule at its strictest
* setting.
*/
export default function validateNoUseBeforeDefine(
source: string
): Array<{ line: number; column: number; message: string }> | null {
const linter = new Linter();
linter.defineParser("hermes-eslint", HermesESLint);
linter.defineRule("custom-no-use-before-define", NoUseBeforeDefineRule);
return linter.verify(source, ESLINT_CONFIG);
}
@@ -0,0 +1,53 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import BabelPlugin from "./BabelPlugin";
declare global {
var __DEV__: boolean | null | undefined;
}
// TODO: Replace the following exports with something like `export * as X from "./X";`
// so that we can make calls like `X.stringify` for better naming and DX.
export * from "./CompilerContext";
export { createCompilerFlags, parseCompilerFlags } from "./CompilerFlags";
export * from "./CompilerOptions";
export * from "./CompilerOutputs";
export * from "./Diagnostic";
export * from "./Logger";
export { NoUseBeforeDefineRule } from "./Validation";
import { parse } from "@babel/parser";
import traverse, { NodePath } from "@babel/traverse";
import * as t from "@babel/types";
function parseFunctions(
source: string
): Array<NodePath<t.FunctionDeclaration>> {
try {
const ast = parse(source, {
plugins: ["typescript", "jsx"],
});
const items: Array<NodePath<t.FunctionDeclaration>> = [];
traverse(ast, {
FunctionDeclaration: {
enter(nodePath) {
items.push(nodePath);
},
},
});
return items;
} catch (e) {
return [];
}
}
export const HIR = {
parseFunctions,
};
export default BabelPlugin;
@@ -0,0 +1 @@
declare module "@babel/plugin-syntax-jsx";
@@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node16-strictest/tsconfig.json",
"compilerOptions": {
"declaration": true,
"outDir": "dist",
"jsx": "react-jsxdev",
// weaken strictness from preset
"importsNotUsedAsValues": "remove",
"noUncheckedIndexedAccess": false,
"noUnusedParameters": false,
"useUnknownInCatchVariables": false,
"target": "ES2015",
// ideally turn off only during dev, or on a per-file basis
"noUnusedLocals": false
},
"exclude": ["node_modules"],
"include": ["src/**/*.ts"]
}
File diff suppressed because it is too large Load Diff
@@ -3,7 +3,7 @@
*/
import MonacoEditor, { type Monaco } from "@monaco-editor/react";
import type { Diagnostic } from "babel-plugin-react-forget";
import type { Diagnostic } from "babel-plugin-react-forget-legacy";
import invariant from "invariant";
import type { editor } from "monaco-editor";
import { useEffect, useState } from "react";
@@ -6,12 +6,12 @@
*/
import generate from "@babel/generator";
import MonacoEditor from "@monaco-editor/react";
import { HIR } from "babel-plugin-react-forget";
import {
Diagnostic,
HIR,
OutputKind,
stringifyCompilerOutputs,
} from "babel-plugin-react-forget";
} from "babel-plugin-react-forget-legacy";
import prettier from "prettier";
import prettierParserBabel from "prettier/parser-babel";
import { memo, useMemo } from "react";
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import type { Diagnostic } from "babel-plugin-react-forget";
import type { Diagnostic } from "babel-plugin-react-forget-legacy";
import clsx from "clsx";
import invariant from "invariant";
import { useSnackbar } from "notistack";
@@ -1,5 +1,8 @@
import { graphviz, wasmFolder } from "@hpcc-js/wasm";
import { OutputKind, type CompilerOutputs } from "babel-plugin-react-forget";
import {
OutputKind,
type CompilerOutputs,
} from "babel-plugin-react-forget-legacy";
import { memo, useEffect, useState } from "react";
import genDotProgram from "../lib/dotProgramGenerator";
@@ -14,8 +14,8 @@ import {
type CompilerOptions,
type CompilerOutputs,
type Diagnostic,
} from "babel-plugin-react-forget";
import { PassName } from "../../../dist/Pass";
} from "babel-plugin-react-forget-legacy";
import { PassName } from "../../babel-plugin-react-forget-legacy/dist/Pass";
// @ts-ignore
import ESLint from "eslint-browser";
import { getBabelPlugins } from "./utils";
@@ -2,8 +2,8 @@
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import { createCompilerFlags } from "babel-plugin-react-forget-legacy";
import type { Store } from "./stores";
import { createCompilerFlags } from "babel-plugin-react-forget";
const index = `\
function fibbonacci(n) {
@@ -4,7 +4,7 @@
// TODO: Add transform tests for these.
import { SCCGraph, ValGraph } from "babel-plugin-react-forget";
import { SCCGraph, ValGraph } from "babel-plugin-react-forget-legacy";
import invariant from "invariant";
const dotPrologue = `\
@@ -3,7 +3,7 @@
*/
import { Monaco } from "@monaco-editor/react";
import { Diagnostic, DiagnosticLevel } from "babel-plugin-react-forget";
import { Diagnostic, DiagnosticLevel } from "babel-plugin-react-forget-legacy";
import { MarkerSeverity, type editor } from "monaco-editor";
function mapForgetSeverityToMonaco(
@@ -2,12 +2,14 @@
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import { createCompilerFlags } from "babel-plugin-react-forget";
import {
createCompilerFlags,
parseCompilerFlags,
} from "babel-plugin-react-forget-legacy";
import invariant from "invariant";
import { ForgetCompilerFlags } from "../compilerDriver";
import { defaultStore } from "../defaultStore";
import { codec } from "../utils";
import { ForgetCompilerFlags } from "../compilerDriver";
import { parseCompilerFlags } from "babel-plugin-react-forget";
/**
* Global Store for Playground
@@ -1,10 +1,10 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import type { PluginItem, TransformOptions } from "@babel/core";
import type { PluginItem } from "@babel/core";
import ReactForgetBabelPlugin, {
CompilerOptions,
} from "babel-plugin-react-forget";
} from "babel-plugin-react-forget-legacy";
/**
* Unicode-Base64 Codec.
@@ -8,19 +8,29 @@
## Build Forget plugin and link it so it can be used by playground
cd ../..
echo "building forget"
yarn
yarn build
yarn link
## Build ESLint for the browser and link it so it can be used by playground
cd packages/eslint-browser
echo "building eslint-browser"
yarn
yarn build
yarn link
cd ../babel-plugin-react-forget-legacy
echo "building legacy forget"
yarn
yarn build
yarn link
## Configure the playground itself to use the above locally linked packages
cd ../playground
echo "linking playground"
yarn link babel-plugin-react-forget
yarn link babel-plugin-react-forget-legacy
yarn link eslint-browser
+19 -16
View File
@@ -7,11 +7,11 @@
/// <reference path="./plugin-syntax-jsx.d.ts" />
import jsx from "@babel/plugin-syntax-jsx";
import type { PluginObj } from "@babel/core";
import type * as BabelCore from "@babel/core";
import { createCompilerDriver } from "./CompilerDriver";
import { CompilerOptions, parseCompilerOptions } from "./CompilerOptions";
import type { PluginObj } from "@babel/core";
import jsx from "@babel/plugin-syntax-jsx";
import { invariant } from "./CompilerError";
import Pipeline from "./HIR/Pipeline";
/**
* The React Forget Babel Plugin
@@ -23,18 +23,21 @@ export default function (babel: typeof BabelCore): PluginObj {
name: "react-forget",
inherits: jsx,
visitor: {
Program: {
enter(program, pass) {
let compilerOptions: CompilerOptions;
try {
compilerOptions = parseCompilerOptions(pass.opts);
} catch (err) {
throw new Error(
`PluginOptions is required to be valid CompilerOptions: ${err}.`
);
}
let compiler = createCompilerDriver(compilerOptions, program);
compiler.compile();
FunctionDeclaration: {
enter(fn, pass) {
const { ast } = Pipeline(fn, {
eliminateRedundantPhi: true,
inferReferenceEffects: true,
inferTypes: true,
inferMutableRanges: true,
inferReactiveScopeVariables: true,
inferReactiveScopes: true,
inferReactiveScopeDependencies: true,
leaveSSA: true,
codegen: true,
});
invariant(ast !== null, "Expected ast to be present");
fn.replaceWith(ast);
},
},
},
+1 -8
View File
@@ -6,7 +6,6 @@
*/
import invariant from "invariant";
import { getMostRecentCompilerContext } from "./CompilerContext";
// Record a bailout if there is an invariant violation and a recently created compiler context.
// Otherwise, just throws a regular invariant.
@@ -15,13 +14,7 @@ function compilerInvariant(
format: string,
...args: any[]
): asserts condition {
let context = null;
try {
context = getMostRecentCompilerContext();
} catch (_) {}
if (context != null) {
return context.invariant(condition, format, ...args);
}
return invariant(condition, format, ...args);
}
export { compilerInvariant as invariant };
-1
View File
@@ -22,7 +22,6 @@ import {
ReturnTerminal,
SourceLocation,
ThrowTerminal,
makeType,
} from "./HIR";
import HIRBuilder, { Environment } from "./HIRBuilder";
import todo, { todoInvariant } from "./todo";
+1 -1
View File
@@ -6,8 +6,8 @@
*/
import { assertExhaustive } from "../Common/utils";
import { BlockId } from "../ControlFlowGraph";
import {
BlockId,
HIRFunction,
Instruction,
InstructionId,
-10
View File
@@ -11,16 +11,6 @@ declare global {
var __DEV__: boolean | null | undefined;
}
// TODO: Replace the following exports with something like `export * as X from "./X";`
// so that we can make calls like `X.stringify` for better naming and DX.
export * from "./CompilerContext";
export { createCompilerFlags, parseCompilerFlags } from "./CompilerFlags";
export * from "./CompilerOptions";
export * from "./CompilerOutputs";
export * from "./Diagnostic";
export * from "./Logger";
export { NoUseBeforeDefineRule } from "./Validation";
import { parse } from "@babel/parser";
import traverse, { NodePath } from "@babel/traverse";
import * as t from "@babel/types";