start migration of core from nodes to paths
This commit is contained in:
parent
41a8257005
commit
c906bd3edc
@ -464,7 +464,7 @@ export default class File {
|
||||
this.scope = this.path.scope;
|
||||
this.ast = ast;
|
||||
|
||||
traverse(ast, {
|
||||
this.path.traverse({
|
||||
enter(node, parent, scope) {
|
||||
if (this.isScope()) {
|
||||
for (var key in scope.bindings) {
|
||||
@ -472,7 +472,7 @@ export default class File {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, this.scope);
|
||||
});
|
||||
}
|
||||
|
||||
transform(ast) {
|
||||
|
||||
@ -27,7 +27,7 @@ export default function (exports, opts) {
|
||||
};
|
||||
|
||||
exports.JSXNamespacedName = function (node, parent, scope, file) {
|
||||
throw file.errorWithNode(node, messages.get("JSXNamespacedTags"));
|
||||
throw this.errorWithNode(messages.get("JSXNamespacedTags"));
|
||||
};
|
||||
|
||||
exports.JSXMemberExpression = {
|
||||
|
||||
@ -219,7 +219,7 @@ export default class ReplaceSupers {
|
||||
var thisReference;
|
||||
|
||||
if (isIllegalBareSuper(node, parent)) {
|
||||
throw this.file.errorWithNode(node, messages.get("classesIllegalBareSuper"));
|
||||
throw this.errorWithNode(messages.get("classesIllegalBareSuper"));
|
||||
}
|
||||
|
||||
if (t.isCallExpression(node)) {
|
||||
|
||||
@ -45,7 +45,7 @@ var importsVisitor = {
|
||||
ImportDeclaration: {
|
||||
enter(node, parent, scope, formatter) {
|
||||
formatter.hasLocalImports = true;
|
||||
extend(formatter.localImports, t.getBindingIdentifiers(node));
|
||||
extend(formatter.localImports, this.getBindingIdentifiers());
|
||||
formatter.bumpImportOccurences(node);
|
||||
}
|
||||
}
|
||||
@ -54,11 +54,11 @@ var importsVisitor = {
|
||||
var exportsVisitor = {
|
||||
ExportDeclaration: {
|
||||
enter(node, parent, scope, formatter) {
|
||||
var declar = node.declaration;
|
||||
var declar = this.get("declaration");
|
||||
formatter.hasLocalImports = true;
|
||||
|
||||
if (declar && t.isStatement(declar)) {
|
||||
extend(formatter.localExports, t.getBindingIdentifiers(declar));
|
||||
if (declar.isStatement()) {
|
||||
extend(formatter.localExports, declar.getBindingIdentifiers());
|
||||
}
|
||||
|
||||
if (!node.default) {
|
||||
@ -105,16 +105,16 @@ export default class DefaultFormatter {
|
||||
}
|
||||
|
||||
getLocalExports() {
|
||||
this.file.scope.traverse(this.file.ast, exportsVisitor, this);
|
||||
this.file.path.traverse(exportsVisitor, this);
|
||||
}
|
||||
|
||||
getLocalImports() {
|
||||
this.file.scope.traverse(this.file.ast, importsVisitor, this);
|
||||
this.file.path.traverse(importsVisitor, this);
|
||||
}
|
||||
|
||||
remapAssignments() {
|
||||
if (this.hasLocalImports) {
|
||||
this.file.scope.traverse(this.file.ast, remapVisitor, this);
|
||||
this.file.path.traverse(remapVisitor, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import includes from "lodash/collection/includes";
|
||||
import traverse from "../traversal";
|
||||
|
||||
/**
|
||||
* This class is responsible for traversing over the provided `File`s
|
||||
@ -59,7 +60,7 @@ export default class TransformerPass {
|
||||
|
||||
file.log.debug(`Running transformer ${this.transformer.key}`);
|
||||
|
||||
file.scope.traverse(file.ast, this.handlers, file);
|
||||
traverse(file.ast, this.handlers, file.scope, file);
|
||||
|
||||
this.ran = true;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ export function BlockStatement(node, parent, scope, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
|
||||
scope.traverse(node, visitor, {
|
||||
this.traverse(visitor, {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
});
|
||||
|
||||
@ -111,7 +111,7 @@ function traverseReplace(node, parent, scope, remaps) {
|
||||
var letReferenceBlockVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isFunction()) {
|
||||
scope.traverse(node, letReferenceFunctionVisitor, state);
|
||||
this.traverse(letReferenceFunctionVisitor, state);
|
||||
return this.skip();
|
||||
}
|
||||
}
|
||||
@ -173,7 +173,7 @@ var loopVisitor = {
|
||||
|
||||
if (this.isLoop()) {
|
||||
state.ignoreLabeless = true;
|
||||
scope.traverse(node, loopVisitor, state);
|
||||
this.traverse(loopVisitor, state);
|
||||
state.ignoreLabeless = false;
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export function ClassDeclaration(node, parent, scope, file) {
|
||||
}
|
||||
|
||||
export function ClassExpression(node, parent, scope, file) {
|
||||
return new ClassTransformer(node, parent, scope, file).run();
|
||||
return new ClassTransformer(this, file).run();
|
||||
}
|
||||
|
||||
var verifyConstructorVisitor = traverse.explode({
|
||||
@ -37,7 +37,7 @@ var verifyConstructorVisitor = traverse.explode({
|
||||
state.hasBareSuper = true;
|
||||
|
||||
if (!state.hasSuper) {
|
||||
throw state.file.errorWithNode(node, "super call is only allowed in derived constructor");
|
||||
throw this.errorWithNode("super call is only allowed in derived constructor");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ var verifyConstructorVisitor = traverse.explode({
|
||||
ThisExpression: {
|
||||
enter(node, parent, scope, state) {
|
||||
if (state.hasSuper && !state.hasBareSuper) {
|
||||
throw state.file.errorWithNode(node, "'this' is not allowed before super()");
|
||||
throw this.errorWithNode("'this' is not allowed before super()");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,10 +58,11 @@ class ClassTransformer {
|
||||
* Description
|
||||
*/
|
||||
|
||||
constructor(node: Object, parent: Object, scope: Scope, file: File) {
|
||||
this.parent = parent;
|
||||
this.scope = scope;
|
||||
this.node = node;
|
||||
constructor(path: TraversalPath, file: File) {
|
||||
this.parent = path.parent;
|
||||
this.scope = path.scope;
|
||||
this.node = path.node;
|
||||
this.path = path;
|
||||
this.file = file;
|
||||
|
||||
this.hasInstanceMutators = false;
|
||||
@ -71,11 +72,11 @@ class ClassTransformer {
|
||||
this.staticMutatorMap = {};
|
||||
|
||||
this.hasConstructor = false;
|
||||
this.className = node.id;
|
||||
this.classRef = node.id || scope.generateUidIdentifier("class");
|
||||
this.className = this.node.id;
|
||||
this.classRef = this.node.id || this.scope.generateUidIdentifier("class");
|
||||
|
||||
this.superName = node.superClass || t.identifier("Function");
|
||||
this.hasSuper = !!node.superClass;
|
||||
this.superName = this.node.superClass || t.identifier("Function");
|
||||
this.hasSuper = !!this.node.superClass;
|
||||
|
||||
this.isLoose = file.isLoose("es6.classes");
|
||||
}
|
||||
@ -174,11 +175,13 @@ class ClassTransformer {
|
||||
var classBody = this.node.body.body;
|
||||
var body = this.body;
|
||||
|
||||
var classBodyPaths = this.path.get("body").get("body");
|
||||
|
||||
for (var i = 0; i < classBody.length; i++) {
|
||||
var node = classBody[i];
|
||||
if (t.isMethodDefinition(node)) {
|
||||
var isConstructor = (!node.computed && t.isIdentifier(node.key, { name: "constructor" })) || t.isLiteral(node.key, { value: "constructor" });
|
||||
if (isConstructor) this.verifyConstructor(node);
|
||||
if (isConstructor) this.verifyConstructor(classBodyPaths[i]);
|
||||
|
||||
var replaceSupers = new ReplaceSupers({
|
||||
methodNode: node,
|
||||
@ -206,7 +209,7 @@ class ClassTransformer {
|
||||
}
|
||||
|
||||
// we have no constructor, we have a super, and the super doesn't appear to be falsy
|
||||
if (!this.hasConstructor && this.hasSuper && t.evaluateTruthy(superName, this.scope) !== false) {
|
||||
if (!this.hasConstructor && this.hasSuper) { // todo: t.evaluateTruthy(superName, this.scope) !== false
|
||||
var helperName = "class-super-constructor-call";
|
||||
if (this.isLoose) helperName += "-loose";
|
||||
constructor.body.body.push(util.template(helperName, {
|
||||
@ -249,17 +252,17 @@ class ClassTransformer {
|
||||
* Description
|
||||
*/
|
||||
|
||||
verifyConstructor(node: Object) {
|
||||
verifyConstructor(path: TraversalPath) {
|
||||
var state = {
|
||||
hasBareSuper: false,
|
||||
hasSuper: this.hasSuper,
|
||||
file: this.file
|
||||
};
|
||||
|
||||
traverse(node, verifyConstructorVisitor, this.scope, state);
|
||||
path.traverse(verifyConstructorVisitor, state);
|
||||
|
||||
if (!state.hasBareSuper && this.hasSuper) {
|
||||
throw this.file.errorWithNode(node, "Derived constructor must call super()");
|
||||
throw path.errorWithNode("Derived constructor must call super()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ var visitor = {
|
||||
};
|
||||
|
||||
export function Scopable(node, parent, scope, file) {
|
||||
scope.traverse(node, visitor, {
|
||||
this.traverse(visitor, {
|
||||
constants: scope.getAllBindingsOfKind("const"),
|
||||
file: file
|
||||
});
|
||||
|
||||
@ -5,12 +5,10 @@ import * as t from "../../../types";
|
||||
export var check = t.isForOfStatement;
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isTypeGeneric("Array")) {
|
||||
return array(node, scope, file);
|
||||
if (this.get("right").isArrayExpression()) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.forOf")) callback = loose;
|
||||
|
||||
@ -42,7 +40,7 @@ export function ForOfStatement(node, parent, scope, file) {
|
||||
}
|
||||
}
|
||||
|
||||
var array = function (node, scope, file) {
|
||||
export function _ForOfStatementArray(node, scope, file) {
|
||||
var nodes = [];
|
||||
var right = node.right;
|
||||
|
||||
@ -78,7 +76,7 @@ var array = function (node, scope, file) {
|
||||
nodes.push(loop);
|
||||
|
||||
return nodes;
|
||||
};
|
||||
}
|
||||
|
||||
var loose = function (node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
|
||||
@ -26,7 +26,7 @@ export function ImportDeclaration(node, parent, scope, file) {
|
||||
|
||||
export function ExportDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (t.isTypeAlias(node.declaration)) return;
|
||||
if (this.get("declaration").isTypeAlias()) return;
|
||||
|
||||
var nodes = [];
|
||||
var i;
|
||||
|
||||
@ -49,41 +49,42 @@ exports.Function = function (node, parent, scope, file) {
|
||||
body.push(defNode);
|
||||
};
|
||||
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
var param = node.params[i];
|
||||
var params = this.get("params");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
|
||||
if (!t.isAssignmentPattern(param)) {
|
||||
if (!t.isRestElement(param)) {
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!param.isRestElement()) {
|
||||
lastNonDefaultParam = i + 1;
|
||||
}
|
||||
|
||||
if (!t.isIdentifier(param)) {
|
||||
scope.traverse(param, iifeVisitor, state);
|
||||
if (!param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
if (file.transformers["es6.blockScopingTDZ"].canRun() && t.isIdentifier(param)) {
|
||||
pushDefNode(param, t.identifier("undefined"), i);
|
||||
if (file.transformers["es6.blockScopingTDZ"].canRun() && param.isIdentifier()) {
|
||||
pushDefNode(param.node, t.identifier("undefined"), i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.left;
|
||||
var right = param.right;
|
||||
var left = param.get("left");
|
||||
var right = param.get("right");
|
||||
|
||||
var placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
|
||||
if (!state.iife) {
|
||||
if (t.isIdentifier(right) && scope.hasOwnBinding(right.name)) {
|
||||
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {
|
||||
state.iife = true;
|
||||
} else {
|
||||
scope.traverse(right, iifeVisitor, state);
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
pushDefNode(left, right, i);
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
|
||||
@ -15,7 +15,7 @@ var memberExpressionOptimisationVisitor = {
|
||||
// to the wrong function
|
||||
if (this.isFunctionDeclaration() || this.isFunctionExpression()) {
|
||||
state.noOptimise = true;
|
||||
scope.traverse(node, memberExpressionOptimisationVisitor, state);
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
state.noOptimise = false;
|
||||
return this.skip();
|
||||
}
|
||||
@ -88,7 +88,7 @@ exports.Function = function (node, parent, scope, file) {
|
||||
name: rest.name
|
||||
};
|
||||
|
||||
scope.traverse(node, memberExpressionOptimisationVisitor, state);
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
// we only have shorthands and there's no other references
|
||||
if (state.canOptimise && state.candidates.length) {
|
||||
|
||||
@ -81,7 +81,7 @@ export function CallExpression(node, parent, scope) {
|
||||
|
||||
var callee = node.callee;
|
||||
|
||||
if (t.isMemberExpression(callee)) {
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.generateTempBasedOnNode(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
@ -101,7 +101,7 @@ export function NewExpression(node, parent, scope, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nativeType = t.isIdentifier(node.callee) && includes(t.NATIVE_TYPE_NAMES, node.callee.name);
|
||||
var nativeType = this.get("callee").isIdentifier() && includes(t.NATIVE_TYPE_NAMES, node.callee.name);
|
||||
|
||||
var nodes = build(args, scope);
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ export function UnaryExpression(node, parent, scope, file) {
|
||||
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
if (t.isIdentifier(node.argument)) {
|
||||
if (this.get("argument").isIdentifier()) {
|
||||
var undefLiteral = t.literal("undefined");
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression("===", t.unaryExpression("typeof", node.argument), undefLiteral),
|
||||
|
||||
@ -6,7 +6,7 @@ import map from "lodash/collection/map";
|
||||
import * as t from "../../../types";
|
||||
|
||||
exports.Function = function (node, parent, scope, file) {
|
||||
var tailCall = new TailCallTransformer(node, scope, file);
|
||||
var tailCall = new TailCallTransformer(this, scope, file);
|
||||
tailCall.run();
|
||||
};
|
||||
|
||||
@ -18,11 +18,11 @@ function returnBlock(expr) {
|
||||
var firstPass = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isIfStatement()) {
|
||||
if (t.isReturnStatement(node.alternate)) {
|
||||
if (this.get("alternate").isReturnStatement()) {
|
||||
t.ensureBlock(node, "alternate");
|
||||
}
|
||||
|
||||
if (t.isReturnStatement(node.consequent)) {
|
||||
if (this.get("consequent").isReturnStatement()) {
|
||||
t.ensureBlock(node, "consequent");
|
||||
}
|
||||
} else if (this.isReturnStatement()) {
|
||||
@ -85,17 +85,18 @@ var thirdPass = {
|
||||
};
|
||||
|
||||
class TailCallTransformer {
|
||||
constructor(node, scope, file) {
|
||||
constructor(path, scope, file) {
|
||||
this.hasTailRecursion = false;
|
||||
this.needsArguments = false;
|
||||
this.setsArguments = false;
|
||||
this.needsThis = false;
|
||||
this.ownerId = node.id;
|
||||
this.ownerId = path.node.id;
|
||||
this.vars = [];
|
||||
|
||||
this.scope = scope;
|
||||
this.path = path;
|
||||
this.file = file;
|
||||
this.node = node;
|
||||
this.node = path.node;
|
||||
}
|
||||
|
||||
getArgumentsId() {
|
||||
@ -156,7 +157,7 @@ class TailCallTransformer {
|
||||
if (!ownerId) return;
|
||||
|
||||
// traverse the function and look for tail recursion
|
||||
scope.traverse(node, firstPass, this);
|
||||
this.path.traverse(firstPass, this);
|
||||
|
||||
if (!this.hasTailRecursion) return;
|
||||
|
||||
@ -167,10 +168,10 @@ class TailCallTransformer {
|
||||
|
||||
//
|
||||
|
||||
scope.traverse(node, secondPass, this);
|
||||
this.path.traverse(secondPass, this);
|
||||
|
||||
if (!this.needsThis || !this.needsArguments) {
|
||||
scope.traverse(node, thirdPass, this);
|
||||
this.path.traverse(thirdPass, this);
|
||||
}
|
||||
|
||||
var body = t.ensureBlock(node).body;
|
||||
|
||||
@ -44,6 +44,7 @@ export default {
|
||||
// needs to be before `_aliasFunction` due to define property closure
|
||||
"es6.properties.computed": require("./es6/properties.computed"),
|
||||
|
||||
"optimisation.es6.forOf": require("./optimisation/flow.for-of"),
|
||||
"es6.forOf": require("./es6/for-of"),
|
||||
|
||||
"es6.regex.sticky": require("./es6/regex.sticky"),
|
||||
|
||||
@ -34,13 +34,13 @@ var functionVisitor = {
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
scope.traverse(node, functionChildrenVisitor, state);
|
||||
this.traverse(functionChildrenVisitor, state);
|
||||
|
||||
return this.skip();
|
||||
}
|
||||
};
|
||||
|
||||
var go = function (getBody, node, scope) {
|
||||
function aliasFunction(getBody, path, scope) {
|
||||
var argumentsId;
|
||||
var thisId;
|
||||
|
||||
@ -56,7 +56,7 @@ var go = function (getBody, node, scope) {
|
||||
|
||||
// traverse the function and find all alias functions so we can alias
|
||||
// `arguments` and `this` if necessary
|
||||
scope.traverse(node, functionVisitor, state);
|
||||
path.traverse(functionVisitor, state);
|
||||
|
||||
var body;
|
||||
|
||||
@ -77,16 +77,16 @@ var go = function (getBody, node, scope) {
|
||||
};
|
||||
|
||||
export function Program(node, parent, scope) {
|
||||
go(function () {
|
||||
aliasFunction(function () {
|
||||
return node.body;
|
||||
}, node, scope);
|
||||
}, this, scope);
|
||||
};
|
||||
|
||||
export function FunctionDeclaration(node, parent, scope) {
|
||||
go(function () {
|
||||
aliasFunction(function () {
|
||||
t.ensureBlock(node);
|
||||
return node.body.body;
|
||||
}, node, scope);
|
||||
}, this, scope);
|
||||
}
|
||||
|
||||
export { FunctionDeclaration as FunctionExpression };
|
||||
|
||||
@ -59,7 +59,7 @@ export function ExportDeclaration(node, parent, scope) {
|
||||
} else if (t.isVariableDeclaration(declar)) {
|
||||
// export var foo = "bar";
|
||||
var specifiers = [];
|
||||
var bindings = t.getBindingIdentifiers(declar);
|
||||
var bindings = this.get("declaration").getBindingIdentifiers();
|
||||
for (var key in bindings) {
|
||||
var id = bindings[key];
|
||||
specifiers.push(t.exportSpecifier(id, id));
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { _ForOfStatementArray } from "../es6/for-of";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var check = t.isForOfStatement;
|
||||
export var optional = true;
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isTypeGeneric("Array")) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
}
|
||||
@ -29,5 +29,5 @@ export function ImportDeclaration(node) {
|
||||
}
|
||||
|
||||
export function ExportDeclaration(node) {
|
||||
if (t.isTypeAlias(node.declaration)) this.remove();
|
||||
if (this.get("declaration").isTypeAlias()) this.remove();
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import core from "core-js/library";
|
||||
import has from "lodash/object/has";
|
||||
import * as t from "../../../types";
|
||||
|
||||
var isSymboliterator = t.buildMatchMemberExpression("Symbol.iterator");
|
||||
var isSymbolIterator = t.buildMatchMemberExpression("Symbol.iterator");
|
||||
|
||||
var coreHas = function (node) {
|
||||
return node.name !== "_" && has(core, node.name);
|
||||
@ -47,7 +47,7 @@ var astVisitor = {
|
||||
if (!callee.computed) return false;
|
||||
|
||||
prop = callee.property;
|
||||
if (!isSymboliterator(prop)) return false;
|
||||
if (!isSymbolIterator(prop)) return false;
|
||||
|
||||
return util.template("corejs-iterator", {
|
||||
CORE_ID: file.get("coreIdentifier"),
|
||||
@ -59,7 +59,7 @@ var astVisitor = {
|
||||
if (node.operator !== "in") return;
|
||||
|
||||
var left = node.left;
|
||||
if (!isSymboliterator(left)) return;
|
||||
if (!isSymbolIterator(left)) return;
|
||||
|
||||
return util.template("corejs-is-iterator", {
|
||||
CORE_ID: file.get("coreIdentifier"),
|
||||
@ -76,7 +76,7 @@ export function manipulateOptions(opts) {
|
||||
}
|
||||
|
||||
export function Program(node, parent, scope, file) {
|
||||
scope.traverse(node, astVisitor, file);
|
||||
this.traverse(astVisitor, file);
|
||||
}
|
||||
|
||||
export function pre(file) {
|
||||
|
||||
@ -20,8 +20,7 @@ export function MethodDefinition(node, parent, scope, file) {
|
||||
if (node.kind !== "memo") return;
|
||||
node.kind = "get";
|
||||
|
||||
var value = node.value;
|
||||
t.ensureBlock(value);
|
||||
t.ensureBlock(node.value);
|
||||
|
||||
var key = node.key;
|
||||
|
||||
@ -34,7 +33,7 @@ export function MethodDefinition(node, parent, scope, file) {
|
||||
file: file
|
||||
};
|
||||
|
||||
scope.traverse(value, visitor, state);
|
||||
this.get("value").traverse(visitor, state);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ function toStatements(node) {
|
||||
export var optional = true;
|
||||
|
||||
export function ConditionalExpression(node, parent, scope) {
|
||||
var evaluateTest = t.evaluateTruthy(node.test, scope);
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
if (evaluateTest === true) {
|
||||
return node.consequent;
|
||||
} else if (evaluateTest === false) {
|
||||
@ -32,9 +32,8 @@ export var IfStatement = {
|
||||
exit(node, parent, scope) {
|
||||
var consequent = node.consequent;
|
||||
var alternate = node.alternate;
|
||||
var test = node.test;
|
||||
|
||||
var evaluateTest = t.evaluateTruthy(test, scope);
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
|
||||
// we can check if a test will be truthy 100% and if so then we can inline
|
||||
// the consequent and completely ignore the alternate
|
||||
|
||||
@ -3,7 +3,7 @@ import * as t from "../../../types";
|
||||
export var optional = true;
|
||||
|
||||
export function Expression(node, parent, scope) {
|
||||
var res = t.evaluate(node, scope);
|
||||
var res = this.evaluate();
|
||||
if (res.confident) return t.valueToNode(res.value);
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
var isConsole = t.buildMatchMemberExpression("console", true);
|
||||
|
||||
export var optional = true;
|
||||
|
||||
export function CallExpression(node, parent) {
|
||||
if (isConsole(node.callee)) {
|
||||
if (this.get("callee").matchesPattern("console", true)) {
|
||||
if (t.isExpressionStatement(parent)) {
|
||||
this.parentPath.remove();
|
||||
} else {
|
||||
|
||||
@ -14,7 +14,7 @@ function check(source, file) {
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope, file) {
|
||||
if (t.isIdentifier(node.callee, { name: "require" }) && node.arguments.length === 1) {
|
||||
if (this.get("callee").isIdentifier({ name: "require" }) && node.arguments.length === 1) {
|
||||
check(node.arguments[0], file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,30 +58,6 @@ export default class Binding {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
getValueIfImmutable() {
|
||||
// can't guarantee this value is the same
|
||||
if (this.reassigned) return;
|
||||
|
||||
var node = this.path.node;
|
||||
if (t.isVariableDeclarator(node)) {
|
||||
if (t.isIdentifier(node.id)) {
|
||||
node = node.init;
|
||||
} else {
|
||||
// otherwise it's probably a destructuring like:
|
||||
// var { foo } = "foo";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isImmutable(node)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
module.exports = traverse;
|
||||
|
||||
import TraversalContext from "./context";
|
||||
import includes from "lodash/collection/includes";
|
||||
import * as t from "../types";
|
||||
|
||||
function traverse(parent, opts, scope, state) {
|
||||
export default function traverse(parent, opts, scope, state, parentPath) {
|
||||
if (!parent) return;
|
||||
|
||||
if (!opts.noScope && !scope) {
|
||||
@ -20,10 +18,10 @@ function traverse(parent, opts, scope, state) {
|
||||
// array of nodes
|
||||
if (Array.isArray(parent)) {
|
||||
for (var i = 0; i < parent.length; i++) {
|
||||
traverse.node(parent[i], opts, scope, state);
|
||||
traverse.node(parent[i], opts, scope, state, parentPath);
|
||||
}
|
||||
} else {
|
||||
traverse.node(parent, opts, scope, state);
|
||||
traverse.node(parent, opts, scope, state, parentPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import * as t from "./index";
|
||||
|
||||
/**
|
||||
* Walk the input `node` and statically evaluate if it's truthy.
|
||||
*
|
||||
@ -18,15 +16,15 @@ import * as t from "./index";
|
||||
*
|
||||
*/
|
||||
|
||||
export function evaluateTruthy(node: Object, scope: Scope): boolean {
|
||||
var res = evaluate(node, scope);
|
||||
export function evaluateTruthy(): boolean {
|
||||
var res = this.evaluate();
|
||||
if (res.confident) return !!res.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the input `node` and statically evaluate it.
|
||||
*
|
||||
* Returns an pbject in the form `{ confident, value }`. `confident` indicates
|
||||
* Returns an object in the form `{ confident, value }`. `confident` indicates
|
||||
* whether or not we had to drop out of evaluating the expression because of
|
||||
* hitting an unknown node that we couldn't confidently find the value of.
|
||||
*
|
||||
@ -38,24 +36,27 @@ export function evaluateTruthy(node: Object, scope: Scope): boolean {
|
||||
*
|
||||
*/
|
||||
|
||||
export function evaluate(node: Object, scope: Scope): { confident: boolean; value: any } {
|
||||
export function evaluate(): { confident: boolean; value: any } {
|
||||
var confident = true;
|
||||
|
||||
var value = evaluate(node);
|
||||
var value = evaluate(this);
|
||||
if (!confident) value = undefined;
|
||||
return {
|
||||
confident: confident,
|
||||
value: value
|
||||
};
|
||||
|
||||
function evaluate(node) {
|
||||
function evaluate(path) {
|
||||
if (!confident) return;
|
||||
|
||||
if (t.isSequenceExpression(node)) {
|
||||
return evaluate(node.expressions[node.expressions.length - 1]);
|
||||
var node = path.node;
|
||||
|
||||
if (path.isSequenceExpression()) {
|
||||
var exprs = path.get("expressions");
|
||||
return evaluate(exprs[exprs.length - 1]);
|
||||
}
|
||||
|
||||
if (t.isLiteral(node)) {
|
||||
if (path.isLiteral()) {
|
||||
if (node.regex && node.value === null) {
|
||||
// we have a regex and we can't represent it natively
|
||||
} else {
|
||||
@ -63,24 +64,29 @@ export function evaluate(node: Object, scope: Scope): { confident: boolean; valu
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isConditionalExpression(node)) {
|
||||
if (evaluate(node.test)) {
|
||||
return evaluate(node.consequent);
|
||||
if (path.isConditionalExpression()) {
|
||||
if (evaluate(path.get("test"))) {
|
||||
return evaluate(path.get("consequent"));
|
||||
} else {
|
||||
return evaluate(node.alternate);
|
||||
return evaluate(path.get("alternate"));
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
if (node.name === "undefined") {
|
||||
if (path.isIdentifier({ name: "undefined" })) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (path.isIdentifier() || path.isMemberExpression()) {
|
||||
path = path.resolve();
|
||||
if (path) {
|
||||
return evaluate(path);
|
||||
} else {
|
||||
return evaluate(scope.getImmutableBindingValue(node.name));
|
||||
return confident = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isUnaryExpression(node, { prefix: true })) {
|
||||
var arg = evaluate(node.argument);
|
||||
if (path.isUnaryExpression({ prefix: true })) {
|
||||
var arg = evaluate(path.get("argument"));
|
||||
switch (node.operator) {
|
||||
case "void": return undefined;
|
||||
case "!": return !arg;
|
||||
@ -89,13 +95,13 @@ export function evaluate(node: Object, scope: Scope): { confident: boolean; valu
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(node) || t.isObjectExpression(node)) {
|
||||
if (path.isArrayExpression() || path.isObjectExpression()) {
|
||||
// we could evaluate these but it's probably impractical and not very useful
|
||||
}
|
||||
|
||||
if (t.isLogicalExpression(node)) {
|
||||
let left = evaluate(node.left);
|
||||
let right = evaluate(node.right);
|
||||
if (path.isLogicalExpression()) {
|
||||
let left = evaluate(path.get("left"));
|
||||
let right = evaluate(path.get("right"));
|
||||
|
||||
switch (node.operator) {
|
||||
case "||": return left || right;
|
||||
@ -103,9 +109,9 @@ export function evaluate(node: Object, scope: Scope): { confident: boolean; valu
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isBinaryExpression(node)) {
|
||||
let left = evaluate(node.left);
|
||||
let right = evaluate(node.right);
|
||||
if (path.isBinaryExpression()) {
|
||||
let left = evaluate(path.get("left"));
|
||||
let right = evaluate(path.get("right"));
|
||||
|
||||
switch (node.operator) {
|
||||
case "-": return left - right;
|
||||
@ -2,10 +2,11 @@ import isBoolean from "lodash/lang/isBoolean";
|
||||
import isNumber from "lodash/lang/isNumber";
|
||||
import isRegExp from "lodash/lang/isRegExp";
|
||||
import isString from "lodash/lang/isString";
|
||||
import traverse from "./index";
|
||||
import traverse from "../index";
|
||||
import includes from "lodash/collection/includes";
|
||||
import Scope from "./scope";
|
||||
import * as t from "../types";
|
||||
import assign from "lodash/object/assign";
|
||||
import Scope from "../scope";
|
||||
import * as t from "../../types";
|
||||
|
||||
export default class TraversalPath {
|
||||
constructor(parent, container) {
|
||||
@ -112,6 +113,13 @@ export default class TraversalPath {
|
||||
this._refresh(node, [node]);
|
||||
}
|
||||
|
||||
errorWithNode(msg, Error = SyntaxError) {
|
||||
var loc = this.node.loc.start;
|
||||
var err = new Error(`Line ${loc.line}: ${msg}`);
|
||||
err.loc = loc;
|
||||
return err;
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.container[this.key];
|
||||
}
|
||||
@ -133,9 +141,6 @@ export default class TraversalPath {
|
||||
// potentially create new scope
|
||||
this.setScope();
|
||||
|
||||
// refresh scope with new/removed bindings
|
||||
this._refresh(oldNode, replacements);
|
||||
|
||||
var file = this.scope && this.scope.file;
|
||||
if (file) {
|
||||
for (var i = 0; i < replacements.length; i++) {
|
||||
@ -170,12 +175,12 @@ export default class TraversalPath {
|
||||
}
|
||||
}
|
||||
|
||||
isBlacklisted() {
|
||||
isBlacklisted(): boolean {
|
||||
var blacklist = this.opts.blacklist;
|
||||
return blacklist && blacklist.indexOf(this.node.type) > -1;
|
||||
}
|
||||
|
||||
visit() {
|
||||
visit(): boolean {
|
||||
if (this.isBlacklisted()) return false;
|
||||
|
||||
this.call("enter");
|
||||
@ -215,11 +220,22 @@ export default class TraversalPath {
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
has(key): boolean {
|
||||
return !!this.node[key];
|
||||
}
|
||||
|
||||
getTypeAnnotation(): Object {
|
||||
is(key): boolean {
|
||||
return this.has(key);
|
||||
}
|
||||
|
||||
isnt(key): boolean {
|
||||
return !this.has(key);
|
||||
}
|
||||
|
||||
getTypeAnnotation(): {
|
||||
inferred: boolean;
|
||||
annotation: ?Object;
|
||||
} {
|
||||
if (this.typeInfo) {
|
||||
return this.typeInfo;
|
||||
}
|
||||
@ -246,10 +262,15 @@ export default class TraversalPath {
|
||||
|
||||
resolve(): ?TraversalPath {
|
||||
if (this.isVariableDeclarator()) {
|
||||
if (this.get("id").isIdentifier()) {
|
||||
return this.get("init").resolve();
|
||||
} else {
|
||||
// otherwise it's a request for a destructuring declarator and i'm not
|
||||
// ready to resolve those just yet
|
||||
}
|
||||
} else if (this.isIdentifier()) {
|
||||
var binding = this.scope.getBinding(this.node.name);
|
||||
if (!binding) return;
|
||||
if (!binding || binding.reassigned) return;
|
||||
|
||||
if (binding.path === this) {
|
||||
return this;
|
||||
@ -270,27 +291,44 @@ export default class TraversalPath {
|
||||
if (!prop.isProperty()) continue;
|
||||
|
||||
var key = prop.get("key");
|
||||
if (key.isIdentifier({ name: targetName }) || key.isLiteral({ value: targetName })) {
|
||||
return prop.get("value");
|
||||
}
|
||||
|
||||
// { foo: obj }
|
||||
var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });
|
||||
|
||||
// { "foo": "obj" } or { ["foo"]: "obj" }
|
||||
match ||= key.isLiteral({ value: targetName });
|
||||
|
||||
if (match) return prop.get("value");
|
||||
}
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
inferType(path: TraversalPath) {
|
||||
inferType(path: TraversalPath): ?Object {
|
||||
path = path.resolve();
|
||||
if (!path) return;
|
||||
|
||||
if (path.isRestElement() || path.isArrayExpression()) {
|
||||
if (path.isRestElement() || path.parentPath.isRestElement() || path.isArrayExpression()) {
|
||||
return t.genericTypeAnnotation(t.identifier("Array"));
|
||||
}
|
||||
|
||||
if (path.parentPath.isTypeCastExpression()) {
|
||||
return path.parentPath.node.typeAnnotation;
|
||||
}
|
||||
|
||||
if (path.isTypeCastExpression()) {
|
||||
return path.node.typeAnnotation;
|
||||
}
|
||||
|
||||
if (path.isObjectExpression()) {
|
||||
return t.genericTypeAnnotation(t.identifier("Object"));
|
||||
}
|
||||
|
||||
if (path.isFunction()) {
|
||||
return t.identifier("Function");
|
||||
}
|
||||
|
||||
if (path.isLiteral()) {
|
||||
var value = path.node.value;
|
||||
if (isString(value)) return t.stringTypeAnnotation();
|
||||
@ -304,39 +342,44 @@ export default class TraversalPath {
|
||||
}
|
||||
}
|
||||
|
||||
isScope() {
|
||||
isScope(): boolean {
|
||||
return t.isScope(this.node, this.parent);
|
||||
}
|
||||
|
||||
isReferencedIdentifier(opts) {
|
||||
isReferencedIdentifier(opts): boolean {
|
||||
return t.isReferencedIdentifier(this.node, this.parent, opts);
|
||||
}
|
||||
|
||||
isReferenced() {
|
||||
isReferenced(): boolean {
|
||||
return t.isReferenced(this.node, this.parent);
|
||||
}
|
||||
|
||||
isBlockScoped() {
|
||||
isBlockScoped(): boolean {
|
||||
return t.isBlockScoped(this.node);
|
||||
}
|
||||
|
||||
isVar() {
|
||||
isVar(): boolean {
|
||||
return t.isVar(this.node);
|
||||
}
|
||||
|
||||
isScope() {
|
||||
isScope(): boolean {
|
||||
return t.isScope(this.node, this.parent);
|
||||
}
|
||||
|
||||
isTypeGeneric(genericName: string, hasTypeParameters?): boolean {
|
||||
var type = this.getTypeAnnotation().annotation;
|
||||
isTypeGeneric(genericName: string, opts = {}): boolean {
|
||||
var typeInfo = this.getTypeAnnotation();
|
||||
var type = typeInfo.annotation;
|
||||
if (!type) return false;
|
||||
|
||||
if (type.inferred && opts.inference === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!t.isGenericTypeAnnotation(type) || !t.isIdentifier(type.id, { name: genericName })) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasTypeParameters && !type.typeParameters) {
|
||||
if (opts.requireTypeParameters && !type.typeParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -348,10 +391,64 @@ export default class TraversalPath {
|
||||
}
|
||||
|
||||
traverse(opts, state) {
|
||||
traverse(this.node, opts, this.scope, state);
|
||||
traverse(this.node, opts, this.scope, state, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the current node if it matches the provided `pattern`.
|
||||
*
|
||||
* For example, given the match `React.createClass` it would match the
|
||||
* parsed nodes of `React.createClass` and `React["createClass"]`.
|
||||
*/
|
||||
|
||||
matchesPattern(pattern: string, allowPartial?: boolean): boolean {
|
||||
var parts = pattern.split(".");
|
||||
|
||||
// not a member expression
|
||||
if (!this.isMemberExpression()) return false;
|
||||
|
||||
var search = [this.node];
|
||||
var i = 0;
|
||||
|
||||
while (search.length) {
|
||||
var node = search.shift();
|
||||
|
||||
if (allowPartial && i === parts.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
// this part doesn't match
|
||||
if (parts[i] !== node.name) return false;
|
||||
} else if (t.isLiteral(node)) {
|
||||
// this part doesn't match
|
||||
if (parts[i] !== node.value) return false;
|
||||
} else if (t.isMemberExpression(node)) {
|
||||
if (node.computed && !t.isLiteral(node.property)) {
|
||||
// we can't deal with this
|
||||
return false;
|
||||
} else {
|
||||
search.push(node.object);
|
||||
search.push(node.property);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// we can't deal with this
|
||||
return false;
|
||||
}
|
||||
|
||||
// too many parts
|
||||
if (++i > parts.length) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
assign(TraversalPath.prototype, require("./evaluation"));
|
||||
|
||||
for (var i = 0; i < t.TYPES.length; i++) {
|
||||
let type = t.TYPES[i];
|
||||
let typeKey = `is${type}`;
|
||||
@ -75,7 +75,7 @@ export default class Scope {
|
||||
if (cached) {
|
||||
return cached;
|
||||
} else {
|
||||
path.setData("scope", this);
|
||||
//path.setData("scope", this);
|
||||
}
|
||||
|
||||
this.parent = parent;
|
||||
@ -245,7 +245,7 @@ export default class Scope {
|
||||
if (t.isReferencedIdentifier(node, parent) && node.name === oldName) {
|
||||
node.name = newName;
|
||||
} else if (t.isDeclaration(node)) {
|
||||
var ids = t.getBindingIdentifiers(node);
|
||||
var ids = this.getBindingIdentifiers();
|
||||
for (var name in ids) {
|
||||
if (name === oldName) ids[name].name = newName;
|
||||
}
|
||||
@ -272,7 +272,7 @@ export default class Scope {
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
var binding = this.getBinding(node.name);
|
||||
if (binding && binding.isTypeGeneric("Array")) return node;
|
||||
if (binding && binding.isTypeGeneric("Array", { inference: false })) return node;
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(node)) {
|
||||
@ -613,26 +613,6 @@ export default class Scope {
|
||||
return binding && binding.identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
getOwnImmutableBindingValue(name: string) {
|
||||
return this._immutableBindingInfoToValue(this.getOwnBindingInfo(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
getImmutableBindingValue(name: string) {
|
||||
return this._immutableBindingInfoToValue(this.getBinding(name));
|
||||
}
|
||||
|
||||
_immutableBindingInfoToValue(binding) {
|
||||
if (binding) return binding.getValueIfImmutable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
@ -297,7 +297,6 @@ toFastProperties(t);
|
||||
toFastProperties(t.VISITOR_KEYS);
|
||||
|
||||
exports.__esModule = true;
|
||||
assign(t, require("./evaluators"));
|
||||
assign(t, require("./retrievers"));
|
||||
assign(t, require("./validators"));
|
||||
assign(t, require("./converters"));
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
"TypeofTypeAnnotation": ["argument"],
|
||||
"TypeAlias": ["id", "typeParameters", "right"],
|
||||
"TypeAnnotation": ["typeAnnotation"],
|
||||
"TypeCastExpression": ["expression"],
|
||||
"TypeCastExpression": ["expression", "typeAnnotation"],
|
||||
"TypeParameterDeclaration": ["params"],
|
||||
"TypeParameterInstantiation": ["params"],
|
||||
"ObjectTypeAnnotation": ["key", "value"],
|
||||
|
||||
@ -1 +1 @@
|
||||
var arr = [for (i of [1, 2, 3]) i * i];
|
||||
var arr = [for (i of nums) i * i];
|
||||
|
||||
@ -7,7 +7,7 @@ var arr = (function () {
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var i = _step.value;
|
||||
|
||||
_arr.push(i * i);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
function add() {
|
||||
return [for (i of [1, 2, 3]) i * this.multiplier];
|
||||
return [for (i of nums) i * this.multiplier];
|
||||
}
|
||||
|
||||
add.call({ multiplier: 5 });
|
||||
|
||||
@ -10,7 +10,7 @@ function add() {
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var i = _step.value;
|
||||
|
||||
_ref.push(i * _this.multiplier);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user