mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-08-16 18:10:33 +03:00
Re-adds Flow parsing and stripping when option is enabled
Summary: Release notes: adds option to parse and strip Flow annotations In a [tweet I made at the end of last year](https://twitter.com/trueadm/status/944908776896978946) I linked to a REPL example that contained Flow type annotations. The example is now broken as we removed Flow type annotation parsing. :( This PR adds this back behind the option `stripFlow` which is now enabled by default on the REPL and for React tests. I've also added a test to match the REPL for regression checking so this doesn't happen. Closes https://github.com/facebook/prepack/pull/1439 Differential Revision: D6976663 Pulled By: trueadm fbshipit-source-id: 47e28bc0986f1a1a252180f26200ce32314a4e5b
This commit is contained in:
parent
d8908e31e6
commit
414cc67b93
@ -329,6 +329,13 @@ ReactStatistics {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test React (JSX) fb-www mocks repl example 1`] = `
|
||||
ReactStatistics {
|
||||
"inlinedComponents": 6,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test React (create-element) Class component folding Classes with state 1`] = `
|
||||
ReactStatistics {
|
||||
"inlinedComponents": 0,
|
||||
@ -657,3 +664,10 @@ ReactStatistics {
|
||||
"optimizedTrees": 2,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test React (create-element) fb-www mocks repl example 1`] = `
|
||||
ReactStatistics {
|
||||
"inlinedComponents": 6,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
@ -53,6 +53,7 @@ function runTestSuite(outputJsx) {
|
||||
inlineExpressions: true,
|
||||
omitInvariants: true,
|
||||
abstractEffectsInAdditionalFunctions: true,
|
||||
stripFlow: true,
|
||||
};
|
||||
|
||||
function compileSourceWithPrepack(source) {
|
||||
@ -374,6 +375,10 @@ function runTestSuite(outputJsx) {
|
||||
it("fb-www 8", async () => {
|
||||
await runTest(directory, "fb8.js");
|
||||
});
|
||||
|
||||
it("repl example", async () => {
|
||||
await runTest(directory, "repl-example.js");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ export type RealmOptions = {
|
||||
maxStackDepth?: number,
|
||||
reactEnabled?: boolean,
|
||||
reactOutput?: ReactOutputTypes,
|
||||
stripFlow?: boolean,
|
||||
abstractEffectsInAdditionalFunctions?: boolean,
|
||||
};
|
||||
|
||||
|
@ -47,6 +47,7 @@ export type PrepackOptions = {|
|
||||
initializeMoreModules?: boolean,
|
||||
statsFile?: string,
|
||||
strictlyMonotonicDateNow?: boolean,
|
||||
stripFlow?: boolean,
|
||||
timeout?: number,
|
||||
trace?: boolean,
|
||||
uniqueSuffix?: string,
|
||||
@ -70,6 +71,7 @@ export function getRealmOptions({
|
||||
serialize = !residual,
|
||||
check,
|
||||
strictlyMonotonicDateNow,
|
||||
stripFlow,
|
||||
timeout,
|
||||
maxStackDepth,
|
||||
}: PrepackOptions): RealmOptions {
|
||||
@ -88,6 +90,7 @@ export function getRealmOptions({
|
||||
serialize,
|
||||
check,
|
||||
strictlyMonotonicDateNow,
|
||||
stripFlow,
|
||||
timeout,
|
||||
maxStackDepth,
|
||||
};
|
||||
|
@ -191,6 +191,8 @@ export class Realm {
|
||||
hoistableFunctions: new WeakMap(),
|
||||
};
|
||||
|
||||
this.stripFlow = opts.stripFlow || false;
|
||||
|
||||
this.fbLibraries = {
|
||||
other: new Map(),
|
||||
react: undefined,
|
||||
@ -255,6 +257,7 @@ export class Realm {
|
||||
output?: ReactOutputTypes,
|
||||
symbols: Map<ReactSymbolTypes, SymbolValue>,
|
||||
};
|
||||
stripFlow: boolean;
|
||||
|
||||
fbLibraries: {
|
||||
other: Map<string, AbstractValue>,
|
||||
|
@ -23,6 +23,7 @@ import type { ReactSerializerState, SerializedResult } from "./types.js";
|
||||
import { Functions } from "./functions.js";
|
||||
import { Logger } from "../utils/logger.js";
|
||||
import { Modules } from "../utils/modules.js";
|
||||
import { stripFlowTypeAnnotations } from "../utils/flow.js";
|
||||
import { LoggingTracer } from "./LoggingTracer.js";
|
||||
import { ResidualHeapVisitor } from "./ResidualHeapVisitor.js";
|
||||
import { ResidualHeapSerializer } from "./ResidualHeapSerializer.js";
|
||||
@ -224,6 +225,9 @@ export class Serializer {
|
||||
);
|
||||
|
||||
let ast = residualHeapSerializer.serialize();
|
||||
if (this.realm.stripFlow) {
|
||||
stripFlowTypeAnnotations(ast);
|
||||
}
|
||||
|
||||
// the signature for generate is not complete, hence the any
|
||||
let generated = generate(ast, { sourceMaps: sourceMaps }, (code: any));
|
||||
|
78
src/utils/flow.js
Normal file
78
src/utils/flow.js
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
|
||||
import traverse from "babel-traverse";
|
||||
import { BabelNode } from "babel-types";
|
||||
import * as t from "babel-types";
|
||||
|
||||
// Taken directly from Babel:
|
||||
// https://github.com/babel/babel/blob/cde005422701a69ff21044c138c29a5ad23b6d0a/packages/babel-plugin-transform-flow-strip-types/src/index.js#L32-L107
|
||||
// Copyright 2015-present Sebastian McKenzie / Babel project (https://github.com/babel)
|
||||
// only the lines reflected in the above were used
|
||||
export function stripFlowTypeAnnotations(ast: BabelNode): void {
|
||||
traverse(
|
||||
ast,
|
||||
{
|
||||
ImportDeclaration(path) {
|
||||
if (!path.node.specifiers.length) return;
|
||||
let typeCount = 0;
|
||||
path.node.specifiers.forEach(({ importKind }) => {
|
||||
if (importKind === "type" || importKind === "typeof") {
|
||||
typeCount++;
|
||||
}
|
||||
});
|
||||
if (typeCount === path.node.specifiers.length) {
|
||||
path.remove();
|
||||
}
|
||||
},
|
||||
Flow(path) {
|
||||
path.remove();
|
||||
},
|
||||
ClassProperty(path) {
|
||||
path.node.variance = null;
|
||||
path.node.typeAnnotation = null;
|
||||
if (!path.node.value) path.remove();
|
||||
},
|
||||
Class(path) {
|
||||
path.node.implements = null;
|
||||
path.get("body.body").forEach(child => {
|
||||
if (child.isClassProperty()) {
|
||||
child.node.typeAnnotation = null;
|
||||
if (!child.node.value) child.remove();
|
||||
}
|
||||
});
|
||||
},
|
||||
AssignmentPattern({ node }) {
|
||||
node.left.optional = false;
|
||||
},
|
||||
Function({ node }) {
|
||||
for (let i = 0; i < node.params.length; i++) {
|
||||
const param = node.params[i];
|
||||
param.optional = false;
|
||||
if (param.type === "AssignmentPattern") {
|
||||
param.left.optional = false;
|
||||
}
|
||||
}
|
||||
node.predicate = null;
|
||||
},
|
||||
TypeCastExpression(path) {
|
||||
let { node } = path;
|
||||
do {
|
||||
node = node.expression;
|
||||
} while (t.isTypeCastExpression(node));
|
||||
path.replaceWith(node);
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
(undefined: any),
|
||||
undefined
|
||||
);
|
||||
}
|
@ -31,6 +31,9 @@ export default function(
|
||||
if (realm.react.enabled) {
|
||||
plugins.push("jsx");
|
||||
}
|
||||
if (realm.stripFlow) {
|
||||
plugins.push("flow");
|
||||
}
|
||||
let ast = parse(code, { filename, sourceType, startLine, plugins });
|
||||
traverseFast(ast, node => {
|
||||
invariant(node.loc);
|
||||
|
35
test/react/mocks/repl-example.js
Normal file
35
test/react/mocks/repl-example.js
Normal file
@ -0,0 +1,35 @@
|
||||
var React = require('React');
|
||||
// the JSX transform converts to React, so we need to add it back in
|
||||
this['React'] = React;
|
||||
|
||||
function Yar(props) {
|
||||
return <a href={props.href}><em>{props.name}</em></a>
|
||||
}
|
||||
|
||||
function Bar(props) {
|
||||
return <div><span style={{color: "red"}}>Here's a link</span>: <Yar {...props} /></div>;
|
||||
}
|
||||
|
||||
// for now, we require inline Flow type annotations on the root component
|
||||
// for its props (if it has any)
|
||||
function Foo(props: {href: string}) {
|
||||
var collection = [
|
||||
{ href: props.href, name: "First Item" },
|
||||
{ href: props.href, name: "Second Item" },
|
||||
{ href: props.href, name: "Third Item" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
{collection.map(item => <Bar {...item} /> )}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// this is a special Prepack function hook
|
||||
// that tells Prepack the root of a React component tree
|
||||
if (this.__registerReactComponentRoot) {
|
||||
__registerReactComponentRoot(Foo);
|
||||
}
|
||||
|
||||
window.Foo = Foo;
|
@ -63,6 +63,12 @@ var optionsConfig = [
|
||||
defaultVal: "jsx",
|
||||
description: "Specifies the serialization output of JSX nodes when React mode is enabled."
|
||||
},
|
||||
{
|
||||
type: "boolean",
|
||||
name: "stripFlow",
|
||||
defaultVal: true,
|
||||
description: "Removes Flow type annotations from the output."
|
||||
},
|
||||
];
|
||||
|
||||
var demos = [];
|
||||
|
Loading…
Reference in New Issue
Block a user