mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[be] Move old compiler to separate package
This commit is contained in:
@@ -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"
|
||||
}
|
||||
}
|
||||
+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 };
|
||||
+1
-1
@@ -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) {
|
||||
+1
-1
@@ -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 {
|
||||
+1
-1
@@ -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,
|
||||
+5
@@ -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.
|
||||
+15
@@ -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;
|
||||
}
|
||||
+206
@@ -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;
|
||||
}
|
||||
+41
@@ -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;
|
||||
+1
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
ReturnTerminal,
|
||||
SourceLocation,
|
||||
ThrowTerminal,
|
||||
makeType,
|
||||
} from "./HIR";
|
||||
import HIRBuilder, { Environment } from "./HIRBuilder";
|
||||
import todo, { todoInvariant } from "./todo";
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
import { assertExhaustive } from "../Common/utils";
|
||||
import { BlockId } from "../ControlFlowGraph";
|
||||
import {
|
||||
BlockId,
|
||||
HIRFunction,
|
||||
Instruction,
|
||||
InstructionId,
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user