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:
1 parent
7a29405d68
commit
075cdcec9e
96 files changed
+5104
-54
No files matched your search
@@ -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();
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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;
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -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 };
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+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) {
|
||||
File renamed without changes.
File renamed without changes.
+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 {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+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,
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+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);
|
||||
}
|
||||
File renamed without changes.
@@ -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