diff --git a/lib/6to5/traverse/index.js b/lib/6to5/traverse.js similarity index 77% rename from lib/6to5/traverse/index.js rename to lib/6to5/traverse.js index 67633d20ef..0938c4d301 100644 --- a/lib/6to5/traverse/index.js +++ b/lib/6to5/traverse.js @@ -1,23 +1,30 @@ -var _ = require("lodash"); +module.exports = traverse; -var traverse = module.exports = function (parent, callbacks, blacklistTypes) { +var Scope = require("./scope"); +var t = require("./types"); +var _ = require("lodash"); + +function traverse(parent, callbacks, opts) { // falsy node if (!parent) return; // array of nodes if (_.isArray(parent)) { _.each(parent, function (node) { - traverse(node, callbacks, blacklistTypes); + traverse(node, callbacks, opts); }); return; } // unknown node type to traverse - var keys = traverse.VISITOR_KEYS[parent.type]; + var keys = t.VISITOR_KEYS[parent.type]; if (!keys) return; + opts = opts || {}; + if (_.isArray(opts)) opts = { blacklist: opts }; + // blacklist these node types from being traversed - blacklistTypes = blacklistTypes || []; + var blacklistTypes = opts.blacklist || []; // normalise callbacks if (_.isFunction(callbacks)) callbacks = { enter: callbacks }; @@ -37,12 +44,13 @@ var traverse = module.exports = function (parent, callbacks, blacklistTypes) { // replace node var maybeReplace = function (result) { + if (result === false) return; if (result != null) node = obj[key] = result; }; // enter if (callbacks.enter) { - result = callbacks.enter(node, parent, obj, key); + result = callbacks.enter(node, parent, opts); // stop iteration if (result === false) return; @@ -51,11 +59,13 @@ var traverse = module.exports = function (parent, callbacks, blacklistTypes) { } // traverse node - traverse(node, callbacks, blacklistTypes); + var opts2 = _.clone(opts); + if (t.isScope(node)) opts2.scope = new Scope(opts.scope, node); + traverse(node, callbacks, opts2); // exit if (callbacks.exit) { - maybeReplace(callbacks.exit(node, parent, obj, key)); + maybeReplace(callbacks.exit(node, parent, opts)); } }; @@ -71,8 +81,6 @@ var traverse = module.exports = function (parent, callbacks, blacklistTypes) { }); }; -traverse.VISITOR_KEYS = require("./visitor-keys"); - traverse.removeProperties = function (tree) { var clear = function (node) { delete node.tokens; @@ -121,7 +129,7 @@ traverse.hasType = function (tree, type, blacklistTypes) { has = true; return false; } - }, blacklistTypes); + }, { blacklist: blacklistTypes }); } return has; diff --git a/lib/6to5/types/index.js b/lib/6to5/types/index.js index 8fdd0e2f01..31533075e7 100644 --- a/lib/6to5/types/index.js +++ b/lib/6to5/types/index.js @@ -6,7 +6,9 @@ var t = exports; // -_.each(traverse.VISITOR_KEYS, function (keys, type) { +t.VISITOR_KEYS = require("./visitor-keys"); + +_.each(t.VISITOR_KEYS, function (keys, type) { t["is" + type] = function (node) { return node && node.type === type; }; @@ -14,7 +16,7 @@ _.each(traverse.VISITOR_KEYS, function (keys, type) { // -t.BUILDER_KEYS = _.defaults(require("./builder-keys"), traverse.VISITOR_KEYS); +t.BUILDER_KEYS = _.defaults(require("./builder-keys"), t.VISITOR_KEYS); _.each(t.BUILDER_KEYS, function (keys, type) { t[type[0].toLowerCase() + type.slice(1)] = function () { @@ -92,6 +94,37 @@ t.toBlock = function (node, parent) { return t.blockStatement(node); }; +t.getIds = function (node) { + var search = [node]; + var ids = []; + + while (search.length) { + var id = search.shift(); + + if (t.isIdentifier(id)) { + ids.push(id.name); + } else if (t.isArrayPattern(id)) { + _.each(id.elements, function (elem) { + search.push(elem); + }); + } else if (t.isAssignmentExpression(id)) { + search.push(id.left); + } else if (t.isObjectPattern(id)) { + _.each(id.properties, function (prop) { + search.push(prop.value); + }); + } else if (t.isVariableDeclaration(id)) { + search = search.concat(id.declarations); + } else if (t.isVariableDeclarator(id)) { + search.push(id.id); + } else { + throw new Error("unknown node " + id.type); + } + } + + return ids; +}; + t.inherits = function (child, parent) { child.loc = parent.loc; child.end = parent.end; @@ -119,6 +152,10 @@ t.needsWhitespace = function (node, expression) { return true; } + if (t.isCallExpression(node) && t.isFunction(node.callee)) { + return true; + } + if (expression) return false; // @@ -192,6 +229,11 @@ t.needsParans = function (node, parent) { } } + // (class {}); + if (t.isClassExpression(node) && t.isExpressionStatement(parent)) { + return true; + } + if (t.isSequenceExpression(node)) { if (t.isForStatement(parent)) { // Although parentheses wouldn't hurt around sequence diff --git a/lib/6to5/traverse/visitor-keys.json b/lib/6to5/types/visitor-keys.json similarity index 100% rename from lib/6to5/traverse/visitor-keys.json rename to lib/6to5/types/visitor-keys.json