diff --git a/lib/6to5/transformers/arrow-functions.js b/lib/6to5/transformers/arrow-functions.js index baa488ac4a..8fc1443172 100644 --- a/lib/6to5/transformers/arrow-functions.js +++ b/lib/6to5/transformers/arrow-functions.js @@ -19,8 +19,7 @@ exports.ArrowFunctionExpression = function (node) { exports.FunctionDeclaration = exports.FunctionExpression = function (node, parent, opts, generateUid) { - var hasArguments = false; - var id; + var argumentsId; // traverse the function and find all arrow functions traverse(node, function (node) { @@ -28,22 +27,15 @@ exports.FunctionExpression = function (node, parent, opts, generateUid) { // traverse all child nodes of this arrow function and find a sole arguments // identifier - traverse(node, function (node, parent) { - if (node.type === "Identifier" && node.name === "arguments" && - parent.type !== "MemberExpression") { - hasArguments = true; - id = id || b.identifier(generateUid("arguments")); - return id; - } - }, traverse.FUNCTION_TYPES); + argumentsId = util.aliasArguments(generateUid, node, argumentsId); return false; }, ["FunctionDeclaration", "FunctionExpression"]); - if (hasArguments) { + if (argumentsId) { util.ensureBlock(node); node.body.body.unshift(b.variableDeclaration("var", [ - b.variableDeclarator(id, b.identifier("arguments")) + b.variableDeclarator(argumentsId, b.identifier("arguments")) ])); } }; diff --git a/lib/6to5/transformers/block-binding.js b/lib/6to5/transformers/block-binding.js index 7a62878d82..4467cca308 100644 --- a/lib/6to5/transformers/block-binding.js +++ b/lib/6to5/transformers/block-binding.js @@ -23,8 +23,8 @@ var hasLet = function (nodes) { return has; }; -exports.Program = function (node) { - if (hasLet(node.body)) node.body = buildNode(node.body).node; +exports.Program = function (node, parent, opts, generateUid) { + if (hasLet(node.body)) node.body = buildNode(node.body, generateUid).node; }; exports.BlockStatement = function (node, parent, opts, generateUid) { @@ -35,7 +35,7 @@ exports.BlockStatement = function (node, parent, opts, generateUid) { var body = node.body; - var built = buildNode(node.body, true); + var built = buildNode(node.body, generateUid); node.body = built.node; traverse(built.body, function (node) { @@ -62,13 +62,13 @@ exports.BlockStatement = function (node, parent, opts, generateUid) { }; var buildForStatement = function (key) { - return function (node, parent) { + return function (node, parent, opts, generateUid) { if (isLet(node[key])) { if (parent.type === "LabeledStatement") { throw util.errorWithNode(parent, "Label statements not supported with block binding yet."); } - return buildNode(node).node; + return buildNode(node, generateUid).node; } }; }; @@ -76,7 +76,7 @@ var buildForStatement = function (key) { exports.ForOfStatement = exports.ForInStatement = buildForStatement("left"); exports.ForStatement = buildForStatement("init"); -var buildNode = function (node) { +var buildNode = function (node, generateUid) { var nodes = []; // hoist normal variable declarations @@ -113,17 +113,27 @@ var buildNode = function (node) { // + var argumentsId = util.aliasArguments(generateUid, node); + + if (argumentsId) { + nodes.push(b.variableDeclaration("var", [ + b.variableDeclarator(argumentsId, b.identifier("arguments")) + ])); + } + + // + var block = b.blockStatement([]); block.body = node; var func = b.functionExpression(null, [], block, false); + // + var templateName = "function-call"; if (traverse.hasType(node, "ThisExpression")) templateName += "-this"; if (traverse.hasType(node, "ReturnStatement", traverse.FUNCTION_TYPES)) templateName += "-return"; - // - nodes.push(util.template(templateName, { FUNCTION: func }, true)); diff --git a/lib/6to5/util.js b/lib/6to5/util.js index babf072a50..4bd471c250 100644 --- a/lib/6to5/util.js +++ b/lib/6to5/util.js @@ -212,6 +212,28 @@ exports.parse = function (opts, code, callback) { } }; +exports.aliasArguments = function (generateUid, node, id) { + var isArgumentIdentifier = function (node) { + return node.type === "Identifier" && node.name === "arguments"; + }; + + var getId = function () { + return id = id || b.identifier(generateUid("arguments")); + }; + + traverse(node, function (node, parent) { + if (isArgumentIdentifier(node) && parent.type !== "MemberExpression") { + return getId(); + } else if (node.type === "MemberExpression" && isArgumentIdentifier(node.object)) { + node.object = getId(); + } else { + return; + } + }, traverse.FUNCTION_TYPES); + + return id; +}; + try { exports.templates = require("../../templates.json"); } catch (err) { diff --git a/test/fixtures/syntax/arrow-functions/arguments/actual.js b/test/fixtures/syntax/arrow-functions/arguments/actual.js index 223df8f4fc..c9b59181c4 100644 --- a/test/fixtures/syntax/arrow-functions/arguments/actual.js +++ b/test/fixtures/syntax/arrow-functions/arguments/actual.js @@ -1,10 +1,10 @@ -function outer() { +function one() { var inner = () => arguments; return [].slice.call(inner()); } -console.log(outer(1, 2)); +one(1, 2); -function outer() { +function two() { var inner = () => arguments; var another = function () { @@ -13,4 +13,22 @@ function outer() { return [].slice.call(inner()); } -console.log(outer(1, 2)); +two(1, 2); + +function three() { + var fn = () => arguments[0] + "bar"; + return fn(); +} +three("foo"); + +function four() { + var fn = () => arguments[0].foo + "bar"; + return fn(); +} +four({ foo: "foo" }); + +function five(obj) { + var fn = () => obj.arguments[0].foo + "bar"; + return fn(); +} +five({ arguments: ["foo"] }); diff --git a/test/fixtures/syntax/arrow-functions/arguments/expected.js b/test/fixtures/syntax/arrow-functions/arguments/expected.js index 57f74d5478..304a3d2694 100644 --- a/test/fixtures/syntax/arrow-functions/arguments/expected.js +++ b/test/fixtures/syntax/arrow-functions/arguments/expected.js @@ -1,11 +1,11 @@ -function outer() { +function one() { var _arguments = arguments; var inner = function () { return _arguments; }; return [].slice.call(inner()); } -console.log(outer(1, 2)); +one(1, 2); -function outer() { +function two() { var _arguments2 = arguments; var inner = function () { return _arguments2; }; @@ -16,4 +16,30 @@ function outer() { return [].slice.call(inner()); } -console.log(outer(1, 2)); +two(1, 2); + +function three() { + var _arguments4 = arguments; + var fn = function () { + return _arguments4[0] + "bar"; + }; + return fn(); +} +three("foo"); + +function four() { + var _arguments5 = arguments; + var fn = function () { + return _arguments5[0].foo + "bar"; + }; + return fn(); +} +four({ foo: "foo" }); + +function five(obj) { + var fn = function () { + return obj.arguments[0].foo + "bar"; + }; + return fn(); +} +five({ arguments: ["foo"] }); diff --git a/test/fixtures/syntax/block-binding/arguments/actual.js b/test/fixtures/syntax/block-binding/arguments/actual.js new file mode 100644 index 0000000000..0661a55078 --- /dev/null +++ b/test/fixtures/syntax/block-binding/arguments/actual.js @@ -0,0 +1,6 @@ +(function () { + if (true) { + let a = arguments[0]; + console.log(a); + } +})(1); diff --git a/test/fixtures/syntax/block-binding/arguments/expected.js b/test/fixtures/syntax/block-binding/arguments/expected.js new file mode 100644 index 0000000000..826ea547e3 --- /dev/null +++ b/test/fixtures/syntax/block-binding/arguments/expected.js @@ -0,0 +1,9 @@ +(function () { + if (true) { + var _arguments = arguments; + (function () { + var a = _arguments[0]; + console.log(a); + })(); + } +})(1);