From ff9511d4357e63e14366ec32c6d7f1b37a4c5602 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Sat, 17 Jan 2015 05:03:23 +0300 Subject: [PATCH] Proof of concept of how traversal would look like with `state` parameter --- .../transformation/helpers/name-method.js | 36 +++++---- lib/6to5/transformation/modules/_default.js | 70 +++++++++-------- .../transformers/_alias-functions.js | 78 ++++++++++--------- lib/6to5/util.js | 16 ++-- 4 files changed, 105 insertions(+), 95 deletions(-) diff --git a/lib/6to5/transformation/helpers/name-method.js b/lib/6to5/transformation/helpers/name-method.js index 340bf7e27d..36cdbddaea 100644 --- a/lib/6to5/transformation/helpers/name-method.js +++ b/lib/6to5/transformation/helpers/name-method.js @@ -2,6 +2,24 @@ var traverse = require("../../traverse"); var util = require("../../util"); var t = require("../../types"); +var traverser = { + enter: function (node, parent, scope, context, state) { + // check if this node is an identifier that matches the same as our function id + if (!t.isIdentifier(node, { name: state.id })) return; + + // check if this node is the one referenced + if (!t.isReferenced(node, parent)) return; + + // check that we don't have a local variable declared as that removes the need + // for the wrapper + var localDeclar = scope.get(state.id, true); + if (localDeclar !== state.outerDeclar) return; + + state.selfReference = true; + context.stop(); + } +}; + module.exports = function (node, file, scope) { var key = t.toComputedKey(node, node.key); if (!t.isLiteral(key)) return node; // we can't set a function id with this @@ -15,23 +33,7 @@ module.exports = function (node, file, scope) { outerDeclar: scope.get(id, true), }; - traverse(node, { - enter: function (node, parent, scope, context, state) { - // check if this node is an identifier that matches the same as our function id - if (!t.isIdentifier(node, { name: state.id })) return; - - // check if this node is the one referenced - if (!t.isReferenced(node, parent)) return; - - // check that we don't have a local variable declared as that removes the need - // for the wrapper - var localDeclar = scope.get(state.id, true); - if (localDeclar !== state.outerDeclar) return; - - state.selfReference = true; - context.stop(); - } - }, scope, state); + traverse(node, traverser, scope, state); if (state.selfReference) { node.value = util.template("property-method-assignment-wrapper", { diff --git a/lib/6to5/transformation/modules/_default.js b/lib/6to5/transformation/modules/_default.js index 68040ac8b8..1485d27f03 100644 --- a/lib/6to5/transformation/modules/_default.js +++ b/lib/6to5/transformation/modules/_default.js @@ -16,35 +16,51 @@ function DefaultFormatter(file) { //this.checkCollisions(); } +var exportsTraverser = { + enter: function (node, parent, scope, context, localExports) { + var declar = node && node.declaration; + if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) { + _.extend(localExports, t.getIds(declar, true)); + } + } +}; + DefaultFormatter.prototype.getLocalExports = function () { var localExports = {}; - - traverse(this.file.ast, { - enter: function (node, parent, scope, context, localExports) { - var declar = node && node.declaration; - if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) { - _.extend(localExports, t.getIds(declar, true)); - } - } - }, null, localExports); - + traverse(this.file.ast, exportsTraverser, null, localExports); return localExports; }; +var importsTraverser = { + enter: function (node, parent, scope, context, localImports) { + if (t.isImportDeclaration(node)) { + _.extend(localImports, t.getIds(node, true)); + } + } +}; + DefaultFormatter.prototype.getLocalImports = function () { var localImports = {}; - - traverse(this.file.ast, { - enter: function (node, parent, scope, context, localImports) { - if (t.isImportDeclaration(node)) { - _.extend(localImports, t.getIds(node, true)); - } - } - }, null, localImports); - + traverse(this.file.ast, importsTraverser, null, localImports); return localImports; }; +var collissionsTraverser = { + enter: function (node, parent, scope, context, check) { + if (t.isAssignmentExpression(node)) { + + var left = node.left; + if (t.isMemberExpression(left)) { + while (left.object) left = left.object; + } + + check(left); + } else if (t.isDeclaration(node)) { + _.each(t.getIds(node, true), check); + } + } +}; + DefaultFormatter.prototype.checkCollisions = function () { // todo: all check export collissions @@ -61,21 +77,7 @@ DefaultFormatter.prototype.checkCollisions = function () { } }; - traverse(file.ast, { - enter: function (node, parent, scope, context, check) { - if (t.isAssignmentExpression(node)) { - - var left = node.left; - if (t.isMemberExpression(left)) { - while (left.object) left = left.object; - } - - check(left); - } else if (t.isDeclaration(node)) { - _.each(t.getIds(node, true), check); - } - } - }, null, check); + traverse(file.ast, collissionsTraverser, null, check); }; DefaultFormatter.prototype.remapExportAssignment = function (node) { diff --git a/lib/6to5/transformation/transformers/_alias-functions.js b/lib/6to5/transformation/transformers/_alias-functions.js index bc52a45ee8..1d2bf585f6 100644 --- a/lib/6to5/transformation/transformers/_alias-functions.js +++ b/lib/6to5/transformation/transformers/_alias-functions.js @@ -1,6 +1,46 @@ var traverse = require("../../traverse"); var t = require("../../types"); +var functionChildrenTraverser = { + enter: function (node, parent, scope, context, state) { + if (t.isFunction(node) && !node._aliasFunction) { + return context.skip(); + } + + if (node._ignoreAliasFunctions) return context.skip(); + + var getId; + + if (t.isIdentifier(node) && node.name === "arguments") { + getId = state.getArgumentsId; + } else if (t.isThisExpression(node)) { + getId = state.getThisId; + } else { + return; + } + + if (t.isReferenced(node, parent)) return getId(); + } +}; + +var functionTraverser = { + enter: function (node, parent, scope, context, state) { + if (!node._aliasFunction) { + if (t.isFunction(node)) { + // stop traversal of this node as it'll be hit again by this transformer + return context.skip(); + } else { + return; + } + } + + // traverse all child nodes of this function and find `arguments` and `this` + traverse(node, functionChildrenTraverser, null, state); + + return context.skip(); + } +}; + var go = function (getBody, node, file, scope) { var argumentsId; var thisId; @@ -16,43 +56,7 @@ var go = function (getBody, node, file, scope) { // traverse the function and find all alias functions so we can alias // `arguments` and `this` if necessary - traverse(node, { - enter: function (node, parent, scope, context, state) { - if (!node._aliasFunction) { - if (t.isFunction(node)) { - // stop traversal of this node as it'll be hit again by this transformer - return context.skip(); - } else { - return; - } - } - - // traverse all child nodes of this function and find `arguments` and `this` - traverse(node, { - enter: function (node, parent, scope, context, state) { - if (t.isFunction(node) && !node._aliasFunction) { - return context.skip(); - } - - if (node._ignoreAliasFunctions) return context.skip(); - - var getId; - - if (t.isIdentifier(node) && node.name === "arguments") { - getId = state.getArgumentsId; - } else if (t.isThisExpression(node)) { - getId = state.getThisId; - } else { - return; - } - - if (t.isReferenced(node, parent)) return getId(); - } - }, null, state); - - return context.skip(); - } - }, null, state); + traverse(node, functionTraverser, null, state); var body; diff --git a/lib/6to5/util.js b/lib/6to5/util.js index 87ce7cebe5..626d06305d 100644 --- a/lib/6to5/util.js +++ b/lib/6to5/util.js @@ -129,6 +129,14 @@ exports.buildDefineProperties = function (mutatorMap) { return objExpr; }; +var templateTraverser = { + enter: function (node, parent, scope, context, nodes) { + if (t.isIdentifier(node) && _.has(nodes, node.name)) { + return nodes[node.name]; + } + } +}; + exports.template = function (name, nodes, keepExpression) { var template = exports.templates[name]; if (!template) throw new ReferenceError("unknown template " + name); @@ -141,13 +149,7 @@ exports.template = function (name, nodes, keepExpression) { template = _.cloneDeep(template); if (!_.isEmpty(nodes)) { - traverse(template, { - enter: function (node, parent, scope, context, nodes) { - if (t.isIdentifier(node) && _.has(nodes, node.name)) { - return nodes[node.name]; - } - } - }, null, nodes); + traverse(template, templateTraverser, null, nodes); } var node = template.body[0];