|
|
|
|
@@ -3,38 +3,48 @@ var b = require("./builders");
|
|
|
|
|
var n = require("acorn-ast-types").namedTypes;
|
|
|
|
|
var _ = require("lodash");
|
|
|
|
|
|
|
|
|
|
exports.FUNCTION_TYPES = ["ArrowFunctionExpression", "FunctionDeclaration", "FunctionExpression"];
|
|
|
|
|
exports.PATTERN_TYPES = ["ArrayPattern", "ObjectPattern"];
|
|
|
|
|
exports.BINARY_TYPES = ["BinaryExpression", "LogicalExpression"];
|
|
|
|
|
exports.UNARY_TYPES = ["UnaryExpression", "SpreadElement", "SpreadProperty"];
|
|
|
|
|
var t = exports;
|
|
|
|
|
|
|
|
|
|
exports.aliases = {
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
_.each(traverse.VISITOR_KEYS, function (keys, type) {
|
|
|
|
|
t["is" + type] = function (node) {
|
|
|
|
|
return node && node.type === type;
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var buildIs = function (isKey, typeKey, types) {
|
|
|
|
|
t[typeKey] = types;
|
|
|
|
|
|
|
|
|
|
t["is" + isKey] = function (node) {
|
|
|
|
|
return node && _.contains(types, node.type);
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
buildIs("Function", "FUNCTION", ["ArrowFunctionExpression", "FunctionDeclaration", "FunctionExpression"]);
|
|
|
|
|
buildIs("Class", "CALSS", ["ClassDeclaration", "ClassExpression"]);
|
|
|
|
|
buildIs("Pattern", "PATTERN", ["ArrayPattern", "ObjectPattern"]);
|
|
|
|
|
buildIs("Binary", "BINARY", ["BinaryExpression", "LogicalExpression"]);
|
|
|
|
|
buildIs("UnaryLike", "UNARY", ["UnaryExpression", "SpreadElement", "SpreadProperty"]);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
t.aliases = {
|
|
|
|
|
ArrowFunctionExpression: ["Function"],
|
|
|
|
|
FunctionDeclaration: ["Function"],
|
|
|
|
|
FunctionExpression: ["Function"]
|
|
|
|
|
FunctionExpression: ["Function"],
|
|
|
|
|
|
|
|
|
|
ClassDeclaration: ["Class"],
|
|
|
|
|
ClassExpression: ["Class"]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.isUnaryLike = function (node) {
|
|
|
|
|
return _.contains(exports.UNARY_TYPES, node.type);
|
|
|
|
|
};
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
exports.isBinary = function (node) {
|
|
|
|
|
return _.contains(exports.BINARY_TYPES, node.type);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.isFunction = function (node) {
|
|
|
|
|
return _.contains(exports.FUNCTION_TYPES, node.type);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.isPattern = function (node) {
|
|
|
|
|
return _.contains(exports.PATTERN_TYPES, node.type);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.isReferenced = function (node, parent) {
|
|
|
|
|
t.isReferenced = function (node, parent) {
|
|
|
|
|
// we're a property key so we aren't referenced
|
|
|
|
|
if (parent.type === "Property" && parent.key === node) return false;
|
|
|
|
|
if (t.isProperty(parent) && parent.key === node) return false;
|
|
|
|
|
|
|
|
|
|
var isMemberExpression = parent.type === "MemberExpression";
|
|
|
|
|
var isMemberExpression = t.isMemberExpression(parent);
|
|
|
|
|
|
|
|
|
|
// we're in a member expression and we're the computed property so we're referenced
|
|
|
|
|
var isComputedProperty = isMemberExpression && parent.property === node && parent.computed;
|
|
|
|
|
@@ -48,18 +58,18 @@ exports.isReferenced = function (node, parent) {
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.ensureBlock = function (node) {
|
|
|
|
|
node.body = exports.toBlock(node.body, node);
|
|
|
|
|
t.ensureBlock = function (node) {
|
|
|
|
|
node.body = t.toBlock(node.body, node);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.toBlock = function (node, parent) {
|
|
|
|
|
if (node.type === "BlockStatement") {
|
|
|
|
|
t.toBlock = function (node, parent) {
|
|
|
|
|
if (t.isBlockStatement(node)) {
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!_.isArray(node)) {
|
|
|
|
|
if (!n.Statement.check(node)) {
|
|
|
|
|
if (exports.isFunction(parent)) {
|
|
|
|
|
if (t.isFunction(parent)) {
|
|
|
|
|
node = b.returnStatement(node);
|
|
|
|
|
} else {
|
|
|
|
|
node = b.expressionStatement(node);
|
|
|
|
|
@@ -72,43 +82,74 @@ exports.toBlock = function (node, parent) {
|
|
|
|
|
return b.blockStatement(node);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.getSpecifierName = function (specifier) {
|
|
|
|
|
t.getSpecifierName = function (specifier) {
|
|
|
|
|
return specifier.name || specifier.id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.ensureExpressionType = function (node) {
|
|
|
|
|
node.type = {
|
|
|
|
|
FunctionDeclaration: "FunctionExpression",
|
|
|
|
|
ClassDeclaration: "ClassExpression"
|
|
|
|
|
}[node.type] || node.type;
|
|
|
|
|
return node;
|
|
|
|
|
t.needsWhitespace = function (node, expression) {
|
|
|
|
|
if (t.isExpressionStatement(node)) {
|
|
|
|
|
node = node.expression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (t.isFunction(node) || t.isClass(node)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (expression) return false;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (_.contains([
|
|
|
|
|
"Literal",
|
|
|
|
|
"CallExpression"
|
|
|
|
|
], node.type)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
var exprs = [];
|
|
|
|
|
|
|
|
|
|
if (t.isVariableDeclaration(node)) {
|
|
|
|
|
exprs = _.map(node.declarations, "init");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t.isArrayExpression(node)) {
|
|
|
|
|
exprs = node.elements;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return exprs.some(function (expr) {
|
|
|
|
|
return t.needsWhitespace(expr, true);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
exports.needsParans = function (node, parent) {
|
|
|
|
|
t.needsParans = function (node, parent) {
|
|
|
|
|
if (!parent) return false;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (exports.isUnaryLike(node)) {
|
|
|
|
|
return parent.type === "MemberExpression" && parent.object === node;
|
|
|
|
|
if (t.isUnaryLike(node)) {
|
|
|
|
|
return t.isMemberExpression(parent) && parent.object === node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exports.isBinary(node)) {
|
|
|
|
|
if (t.isBinary(node)) {
|
|
|
|
|
//
|
|
|
|
|
if (parent.type === "CallExpression" && parent.callee === node) {
|
|
|
|
|
if (t.isCallExpression(parent) && parent.callee === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (exports.isUnaryLike(parent)) {
|
|
|
|
|
if (t.isUnaryLike(parent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (parent.type === "MemberExpression" && parent.object === node) {
|
|
|
|
|
if (t.isMemberExpression(parent) && parent.object === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exports.isBinary(parent)) {
|
|
|
|
|
if (t.isBinary(parent)) {
|
|
|
|
|
var parentOp = parent.operator;
|
|
|
|
|
var parentPos = PRECEDENCE[parentOp];
|
|
|
|
|
|
|
|
|
|
@@ -125,8 +166,8 @@ exports.needsParans = function (node, parent) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.type === "SequenceExpression") {
|
|
|
|
|
if (parent.type === "ForStatement") {
|
|
|
|
|
if (t.isSequenceExpression(node)) {
|
|
|
|
|
if (t.isForStatement(parent)) {
|
|
|
|
|
// Although parentheses wouldn't hurt around sequence
|
|
|
|
|
// expressions in the head of for loops, traditional style
|
|
|
|
|
// dictates that e.g. i++, j++ should not be wrapped with
|
|
|
|
|
@@ -134,7 +175,7 @@ exports.needsParans = function (node, parent) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parent.type === "ExpressionStatement" && parent.expression === node) {
|
|
|
|
|
if (t.isExpressionStatement(parent) && parent.expression === node) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -144,9 +185,9 @@ exports.needsParans = function (node, parent) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (node.type === "YieldExpression") {
|
|
|
|
|
return exports.isBinary(parent)
|
|
|
|
|
|| exports.isUnaryLike(parent)
|
|
|
|
|
if (t.isYieldExpression(node)) {
|
|
|
|
|
return t.isBinary(parent)
|
|
|
|
|
|| t.isUnaryLike(parent)
|
|
|
|
|
|| parent.type === "CallExpression"
|
|
|
|
|
|| parent.type === "MemberExpression"
|
|
|
|
|
|| parent.type === "NewExpression"
|
|
|
|
|
@@ -154,61 +195,61 @@ exports.needsParans = function (node, parent) {
|
|
|
|
|
|| parent.type === "YieldExpression";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parent.type === "NewExpression" && parent.callee === node) {
|
|
|
|
|
if (t.isNewExpression(parent) && parent.callee === node) {
|
|
|
|
|
return traverse.hasType(node, "CallExpression");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (1).valueOf()
|
|
|
|
|
if (node.type === "Literal" && _.isNumber(node.value) && parent.type === "MemberExpression" && parent.object === node) {
|
|
|
|
|
if (t.isLiteral(node) && _.isNumber(node.value) && t.isMemberExpression(parent) && parent.object === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.type === "AssignmentExpression" || node.type === "ConditionalExpression") {
|
|
|
|
|
if (t.isAssignmentExpression(node) || t.isConditionalExpression(node)) {
|
|
|
|
|
//
|
|
|
|
|
if (exports.isUnaryLike(parent)) {
|
|
|
|
|
if (t.isUnaryLike(parent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (exports.isBinary(parent)) {
|
|
|
|
|
if (t.isBinary(parent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (parent.type === "CallExpression" && parent.callee === node) {
|
|
|
|
|
if (t.isCallExpression(parent) && parent.callee === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (parent.type === "ConditionalExpression" && parent.test === node) {
|
|
|
|
|
if (t.isConditionalExpression(parent) && parent.test === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (parent.type === "MemberExpression" && parent.object === node) {
|
|
|
|
|
if (t.isMemberExpression(parent) && parent.object === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.type === "FunctionExpression") {
|
|
|
|
|
if (t.isFunctionExpression(node)) {
|
|
|
|
|
// function () {};
|
|
|
|
|
if (parent.type === "ExpressionStatement") {
|
|
|
|
|
if (t.isExpressionStatement(parent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (function test() {}).name;
|
|
|
|
|
if (parent.type === "MemberExpression" && parent.object === node) {
|
|
|
|
|
if (t.isMemberExpression(parent) && parent.object === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (function () {})();
|
|
|
|
|
if (parent.type === "CallExpression" && parent.callee === node) {
|
|
|
|
|
if (t.isCallExpression(parent) && parent.callee === node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ({ x, y }) = { x: 5, y: 6 };
|
|
|
|
|
if (node.type === "ObjectPattern" && parent.type === "AssignmentExpression" && parent.left == node) {
|
|
|
|
|
if (t.isObjectPattern(node) && t.isAssignmentExpression(parent) && parent.left == node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|