diff --git a/lib/6to5/transformation/modules/_default.js b/lib/6to5/transformation/modules/_default.js index 3959abec4a..95b7a97b85 100644 --- a/lib/6to5/transformation/modules/_default.js +++ b/lib/6to5/transformation/modules/_default.js @@ -51,7 +51,7 @@ DefaultFormatter.prototype.remapAssignments = function () { traverse(this.file.ast, { enter: function (node, parent, scope) { if (t.isUpdateExpression(node) && isLocalReference(node.argument, scope)) { - this.stop(); + this.skip(); // expand to long file assignment expression var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1)); @@ -79,7 +79,7 @@ DefaultFormatter.prototype.remapAssignments = function () { } if (t.isAssignmentExpression(node) && isLocalReference(node.left, scope)) { - this.stop(); + this.skip(); return self.remapExportAssignment(node); } } diff --git a/lib/6to5/transformation/modules/system.js b/lib/6to5/transformation/modules/system.js index 9d14b5cfcc..b4f72c6d5b 100644 --- a/lib/6to5/transformation/modules/system.js +++ b/lib/6to5/transformation/modules/system.js @@ -114,7 +114,7 @@ SystemFormatter.prototype.transform = function (ast) { enter: function (node, parent, scope) { if (t.isFunction(node)) { // nothing inside is accessible - return this.stop(); + return this.skip(); } if (t.isVariableDeclaration(node)) { @@ -159,7 +159,7 @@ SystemFormatter.prototype.transform = function (ast) { // hoist up function declarations for circular references traverse(block, { enter: function (node) { - if (t.isFunction(node)) this.stop(); + if (t.isFunction(node)) this.skip(); if (t.isFunctionDeclaration(node) || node._blockHoist) { handlerBody.push(node); diff --git a/lib/6to5/transformation/transformers/_alias-functions.js b/lib/6to5/transformation/transformers/_alias-functions.js index 7dbabf3710..2230a44e9a 100644 --- a/lib/6to5/transformation/transformers/_alias-functions.js +++ b/lib/6to5/transformation/transformers/_alias-functions.js @@ -20,7 +20,7 @@ var go = function (getBody, node, file, scope) { if (!node._aliasFunction) { if (t.isFunction(node)) { // stop traversal of this node as it'll be hit again by this transformer - return this.stop(); + return this.skip(); } else { return; } @@ -30,10 +30,10 @@ var go = function (getBody, node, file, scope) { traverse(node, { enter: function (node, parent) { if (t.isFunction(node) && !node._aliasFunction) { - return this.stop(); + return this.skip(); } - if (node._ignoreAliasFunctions) return this.stop(); + if (node._ignoreAliasFunctions) return this.skip(); var getId; @@ -49,7 +49,7 @@ var go = function (getBody, node, file, scope) { } }); - return this.stop(); + return this.skip(); } }); diff --git a/lib/6to5/transformation/transformers/es6-let-scoping.js b/lib/6to5/transformation/transformers/es6-let-scoping.js index 3abc6c6c90..3da1800688 100644 --- a/lib/6to5/transformation/transformers/es6-let-scoping.js +++ b/lib/6to5/transformation/transformers/es6-let-scoping.js @@ -280,7 +280,7 @@ LetScoping.prototype.checkLoop = function () { var replace; if (t.isFunction(node) || t.isLoop(node)) { - return this.stop(); + return this.skip(); } if (node && !node.label) { @@ -329,7 +329,7 @@ LetScoping.prototype.hoistVarDeclarations = function () { } else if (isVar(node, parent)) { return self.pushDeclar(node).map(t.expressionStatement); } else if (t.isFunction(node)) { - return this.stop(); + return this.skip(); } } }); @@ -388,9 +388,9 @@ LetScoping.prototype.getLetReferences = function () { } }); - return this.stop(); + return this.skip(); } else if (t.isLoop(node)) { - return this.stop(); + return this.skip(); } } }); diff --git a/lib/6to5/transformation/transformers/es6-property-method-assignment.js b/lib/6to5/transformation/transformers/es6-property-method-assignment.js new file mode 100644 index 0000000000..487441a4fd --- /dev/null +++ b/lib/6to5/transformation/transformers/es6-property-method-assignment.js @@ -0,0 +1,82 @@ +var traverse = require("../../traverse"); +var util = require("../../util"); +var t = require("../../types"); + +exports.Property = function (node, parent, file, scope) { + if (!node.method) return; + + node.method = false; + + var key = t.toComputedPropertyKey(node); + if (!t.isLiteral(key)) return; // we can't set a function id with this + + var id = t.toIdentifier(key.value); + key = t.identifier(id); + + var selfReference = false; + var outerDeclar = scope.get(id, true); + + traverse(node, { + enter: function (node, parent, scope) { + // check if this node is an identifier that matches the same as our function id + if (!t.isIdentifier(node, { name: 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(id, true); + if (localDeclar !== outerDeclar) return; + + selfReference = true; + this.stop(); + } + }, scope); + + if (selfReference) { + node.value = util.template("property-method-assignment-wrapper", { + FUNCTION: node.value, + FUNCTION_ID: key, + FUNCTION_KEY: file.generateUidIdentifier(id, scope), + WRAPPER_KEY: file.generateUidIdentifier(id + "Wrapper", scope) + }); + } else { + node.value.id = key; + } +}; + +exports.ObjectExpression = function (node, parent, file) { + var mutatorMap = {}; + var hasAny = false; + + node.properties = node.properties.filter(function (prop) { + if (prop.kind === "get" || prop.kind === "set") { + hasAny = true; + util.pushMutatorMap(mutatorMap, prop.key, prop.kind, prop.value); + return false; + } else { + return true; + } + }); + + if (!hasAny) return; + + if (node.properties.length) { + var objId = t.getUid(parent, file); + + return util.template("object-define-properties-closure", { + KEY: objId, + OBJECT: node, + CONTENT: util.template("object-define-properties", { + OBJECT: objId, + PROPS: util.buildDefineProperties(mutatorMap) + }) + }); + } else { + return util.template("object-define-properties", { + OBJECT: node, + PROPS: util.buildDefineProperties(mutatorMap) + }); + } +}; diff --git a/lib/6to5/transformation/transformers/optional-core-aliasing.js b/lib/6to5/transformation/transformers/optional-core-aliasing.js index a23602d736..bd2fb2f572 100644 --- a/lib/6to5/transformation/transformers/optional-core-aliasing.js +++ b/lib/6to5/transformation/transformers/optional-core-aliasing.js @@ -29,7 +29,7 @@ exports.ast = { if (!t.isReferenced(obj, node)) return; if (!node.computed && coreHas(obj) && _.has(core[obj.name], prop.name)) { - this.stop(); + this.skip(); return t.prependToMemberExpression(node, file._coreId); } } else if (t.isIdentifier(node) && !t.isMemberExpression(parent) && t.isReferenced(node, parent) && coreHas(node)) { diff --git a/lib/6to5/traverse/index.js b/lib/6to5/traverse/index.js index 22cd2b00ba..7e3488f4cb 100644 --- a/lib/6to5/traverse/index.js +++ b/lib/6to5/traverse/index.js @@ -22,12 +22,14 @@ function traverse(parent, opts, scope) { opts = opts || {}; + var stopped = false; + for (var i in keys) { var key = keys[i]; var nodes = parent[key]; if (!nodes) continue; - var updated = false; + var flatten = false; var handle = function (obj, key) { var node = obj[key]; @@ -50,7 +52,8 @@ function traverse(parent, opts, scope) { // replace the node node = obj[key] = result; - updated = true; + + if (isArray) flatten = true; // we're replacing a statement or block node with an array of statements so we better // ensure that it's a block @@ -59,16 +62,20 @@ function traverse(parent, opts, scope) { } }; - var stopped = false; + var skipped = false; var removed = false; var context = { stop: function () { - stopped = true; + skipped = stopped = true; + }, + + skip: function () { + skipped = true; }, remove: function () { - this.stop(); + this.skip(); removed = true; } }; @@ -84,11 +91,11 @@ function traverse(parent, opts, scope) { if (removed) { obj[key] = null; - updated = true; + flatten = true; } // stop iteration - if (stopped) return; + if (skipped) return; } // traverse node @@ -103,9 +110,10 @@ function traverse(parent, opts, scope) { if (_.isArray(nodes)) { for (i in nodes) { handle(nodes, i); + if (stopped) return; } - if (updated) { + if (flatten) { parent[key] = _.flatten(parent[key]); if (key === "body") { @@ -115,6 +123,7 @@ function traverse(parent, opts, scope) { } } else { handle(parent, key); + if (stopped) return; } } } @@ -161,7 +170,7 @@ traverse.hasType = function (tree, type, blacklistTypes) { enter: function (node) { if (node.type === type) { has = true; - this.stop(); + this.skip(); } } }); diff --git a/lib/6to5/traverse/scope.js b/lib/6to5/traverse/scope.js index 0f6b1cf976..7ec5f645af 100644 --- a/lib/6to5/traverse/scope.js +++ b/lib/6to5/traverse/scope.js @@ -93,7 +93,7 @@ Scope.prototype.getInfo = function () { // this block is a function so we'll stop since none of the variables // declared within are accessible - if (t.isFunction(node)) return this.stop(); + if (t.isFunction(node)) return this.skip(); // function identifier doesn't belong to this scope if (block.id && node === block.id) return;