diff --git a/lib/6to5/declarations.js b/lib/6to5/declarations.js new file mode 100644 index 0000000000..e86033bce4 --- /dev/null +++ b/lib/6to5/declarations.js @@ -0,0 +1,3 @@ +var b = require("recast").types.builders; + +exports.slice = b.memberExpression(b.identifier("Array"), b.memberExpression(b.identifier("prototype"), b.identifier("slice"), false), false) diff --git a/lib/6to5/file.js b/lib/6to5/file.js index dabcf7adb8..72f6378797 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -2,14 +2,17 @@ module.exports = File; var SHEBANG_REGEX = /^\#\!.*/; -var transform = require("./transform"); -var util = require("./util"); -var _ = require("lodash"); +var declarations = require("./declarations"); +var transform = require("./transform"); +var util = require("./util"); +var b = require("recast").types.builders; +var _ = require("lodash"); function File(opts) { - this.uids = {}; - this.opts = File.normaliseOptions(opts); - this.ast = {}; + this.declarations = {}; + this.uids = {}; + this.opts = File.normaliseOptions(opts); + this.ast = {}; } File.normaliseOptions = function (opts) { @@ -46,6 +49,18 @@ File.prototype.parseShebang = function (code) { return code; }; +File.prototype.addDeclaration = function (name) { + var declar = this.declarations[name]; + if (declar) return declar.uid; + + var uid = b.identifier(this.generateUid(name)); + this.declarations[name] = { + uid: uid, + node: declarations[name] + }; + return uid; +}; + File.prototype.parse = function (code) { var self = this; @@ -66,6 +81,14 @@ File.prototype.transform = function (ast) { transformer.transform(self); }); + var body = ast.program.body; + + _.each(this.declarations, function (declar) { + body.unshift(b.variableDeclaration("var", [ + b.variableDeclarator(declar.uid, declar.node) + ])); + }); + var result = util.generate(ast, opts); if (this.shebang) { diff --git a/lib/6to5/templates/arguments-slice-assign-arg.js b/lib/6to5/templates/arguments-slice-assign-arg.js index 63fb4b7bd8..544c56192d 100644 --- a/lib/6to5/templates/arguments-slice-assign-arg.js +++ b/lib/6to5/templates/arguments-slice-assign-arg.js @@ -1 +1 @@ -var VARIABLE_NAME = Array.prototype.slice.call(arguments, SLICE_ARG); +var VARIABLE_NAME = SLICE_KEY.call(arguments, SLICE_ARG); diff --git a/lib/6to5/templates/arguments-slice-assign.js b/lib/6to5/templates/arguments-slice-assign.js index c6c31475d1..90d412107e 100644 --- a/lib/6to5/templates/arguments-slice-assign.js +++ b/lib/6to5/templates/arguments-slice-assign.js @@ -1 +1 @@ -var VARIABLE_NAME = Array.prototype.slice.call(arguments); +var VARIABLE_NAME = SLICE_KEY.call(arguments); diff --git a/lib/6to5/templates/arguments-slice.js b/lib/6to5/templates/arguments-slice.js index 46653b4d59..139d78556f 100644 --- a/lib/6to5/templates/arguments-slice.js +++ b/lib/6to5/templates/arguments-slice.js @@ -1 +1 @@ -Array.prototype.slice.call(arguments); +SLICE_KEY.call(arguments); diff --git a/lib/6to5/transformers/rest-parameters.js b/lib/6to5/transformers/rest-parameters.js index bf8b50932b..4e146b41c5 100644 --- a/lib/6to5/transformers/rest-parameters.js +++ b/lib/6to5/transformers/rest-parameters.js @@ -1,7 +1,7 @@ var util = require("../util"); var b = require("recast").types.builders; -exports.Function = function (node) { +exports.Function = function (node, parent, file) { if (!node.rest) return; var rest = node.rest; @@ -12,6 +12,7 @@ exports.Function = function (node) { util.ensureBlock(node); node.body.body.unshift(util.template(templateName, { + SLICE_KEY: file.addDeclaration("slice"), VARIABLE_NAME: rest, SLICE_ARG: b.literal(node.params.length) })); diff --git a/lib/6to5/transformers/spread.js b/lib/6to5/transformers/spread.js index 7001467d06..c30f94cd57 100644 --- a/lib/6to5/transformers/spread.js +++ b/lib/6to5/transformers/spread.js @@ -21,7 +21,7 @@ exports.ArrayExpression = function (node) { return concat; }; -exports.CallExpression = function (node) { +exports.CallExpression = function (node, parent, file) { var args = node.arguments; if (args.length && _.last(args).type === "SpreadElement") { @@ -34,7 +34,9 @@ exports.CallExpression = function (node) { if (args.length) { if (spreadLiteral.name === "arguments") { - spreadLiteral = util.template("arguments-slice"); + spreadLiteral = util.template("arguments-slice", { + SLICE_KEY: file.addDeclaration("slice") + }); } var concat = util.template("array-concat"); diff --git a/test/fixtures/syntax/rest-parameters/multiple/expected.js b/test/fixtures/syntax/rest-parameters/multiple/expected.js index 4d8d7d6b68..ee9222ed51 100644 --- a/test/fixtures/syntax/rest-parameters/multiple/expected.js +++ b/test/fixtures/syntax/rest-parameters/multiple/expected.js @@ -1,7 +1,9 @@ +var _slice = Array.prototype.slice; + var t = function (f) { - var items = Array.prototype.slice.call(arguments, 1); + var items = _slice.call(arguments, 1); }; function t(f) { - var items = Array.prototype.slice.call(arguments, 1); + var items = _slice.call(arguments, 1); } diff --git a/test/fixtures/syntax/rest-parameters/single/expected.js b/test/fixtures/syntax/rest-parameters/single/expected.js index 11ce45caaa..18d648f026 100644 --- a/test/fixtures/syntax/rest-parameters/single/expected.js +++ b/test/fixtures/syntax/rest-parameters/single/expected.js @@ -1,7 +1,9 @@ +var _slice = Array.prototype.slice; + var t = function () { - var items = Array.prototype.slice.call(arguments); + var items = _slice.call(arguments); }; function t() { - var items = Array.prototype.slice.call(arguments); + var items = _slice.call(arguments); } diff --git a/test/fixtures/syntax/spread/arguments/expected.js b/test/fixtures/syntax/spread/arguments/expected.js index 6cf3de65ef..5817411dfd 100644 --- a/test/fixtures/syntax/spread/arguments/expected.js +++ b/test/fixtures/syntax/spread/arguments/expected.js @@ -1,5 +1,7 @@ +var _slice = Array.prototype.slice; + function foo() { - return bar.apply(null, ["test"].concat(Array.prototype.slice.call(arguments))); + return bar.apply(null, ["test"].concat(_slice.call(arguments))); } function bar(one, two, three) { return [