diff --git a/doc/caveats.md b/doc/caveats.md index 04de894183..d50db7d371 100644 --- a/doc/caveats.md +++ b/doc/caveats.md @@ -37,7 +37,7 @@ A polyfill is required for for-of functionality that implements `Symbol` and adds `prototype[Symbol.iterator]` behaviour to built-ins. Using the polyfills specified in [polyfill](polyfill.md) suffices. -## Spread +### Array destructuring / Spread -An [ES6 polyfill](polyfill.md) is required in order for spread to work. More -specifically a polyfill for `Array.from`. +An [ES6 polyfill](polyfill.md) is required for spread and array destructuring. +More specifically a polyfill for `Array.from`. diff --git a/lib/6to5/templates/array-from.js b/lib/6to5/templates/array-from.js new file mode 100644 index 0000000000..6e8f155aeb --- /dev/null +++ b/lib/6to5/templates/array-from.js @@ -0,0 +1 @@ +Array.from(VALUE); diff --git a/lib/6to5/transformation/transformers/destructuring.js b/lib/6to5/transformation/transformers/destructuring.js index bdb695d2b3..7034b196f0 100644 --- a/lib/6to5/transformation/transformers/destructuring.js +++ b/lib/6to5/transformation/transformers/destructuring.js @@ -1,5 +1,6 @@ -var t = require("../../types"); -var _ = require("lodash"); +var util = require("../../util"); +var t = require("../../types"); +var _ = require("lodash"); var buildVariableAssign = function (kind, id, init) { if (kind === false) { @@ -11,45 +12,60 @@ var buildVariableAssign = function (kind, id, init) { } }; -var push = function (kind, nodes, elem, parentId) { +var push = function (opts, nodes, elem, parentId) { if (t.isObjectPattern(elem)) { - pushObjectPattern(kind, nodes, elem, parentId); + pushObjectPattern(opts, nodes, elem, parentId); } else if (t.isArrayPattern(elem)) { - pushArrayPattern(kind, nodes, elem, parentId); + pushArrayPattern(opts, nodes, elem, parentId); } else if (t.isMemberExpression(elem)) { nodes.push(buildVariableAssign(false, elem, parentId)); } else { - nodes.push(buildVariableAssign(kind, elem, parentId)); + nodes.push(buildVariableAssign(opts.kind, elem, parentId)); } }; -var pushObjectPattern = function (kind, nodes, pattern, parentId) { +var pushObjectPattern = function (opts, nodes, pattern, parentId) { _.each(pattern.properties, function (prop) { var pattern2 = prop.value; var patternId2 = t.memberExpression(parentId, prop.key); if (t.isPattern(pattern2)) { - push(kind, nodes, pattern2, patternId2); + push(opts, nodes, pattern2, patternId2); } else { - nodes.push(buildVariableAssign(kind, pattern2, patternId2)); + nodes.push(buildVariableAssign(opts.kind, pattern2, patternId2)); } }); }; -var pushArrayPattern = function (kind, nodes, pattern, parentId) { +var pushArrayPattern = function (opts, nodes, pattern, parentId) { + var _parentId = t.identifier(opts.file.generateUid("ref", opts.scope)); + nodes.push(t.variableDeclaration("var", [ + t.variableDeclarator(_parentId, util.template("array-from", { + VALUE: parentId + })) + ])); + parentId = _parentId; + _.each(pattern.elements, function (elem, i) { if (!elem) return; var newPatternId; if (t.isSpreadElement(elem)) { - newPatternId = t.callExpression(t.memberExpression(parentId, t.identifier("slice")), [t.literal(i)]); + newPatternId = util.template("array-from", { + VALUE: parentId + }); + + if (+i > 0) { + newPatternId = t.callExpression(t.memberExpression(newPatternId, t.identifier("slice")), [t.literal(i)]); + } + elem = elem.argument; } else { newPatternId = t.memberExpression(parentId, t.literal(i), true); } - push(kind, nodes, elem, newPatternId); + push(opts, nodes, elem, newPatternId); }); }; @@ -71,7 +87,7 @@ var pushPattern = function (opts) { parentId = key; } - push(kind, nodes, pattern, parentId); + push(opts, nodes, pattern, parentId); }; exports.ForInStatement = @@ -89,7 +105,11 @@ exports.ForOfStatement = function (node, parent, file, scope) { var nodes = []; - push(declar.kind, nodes, pattern, key); + push({ + kind: declar.kind, + file: file, + scope: scope + }, nodes, pattern, key); t.ensureBlock(node); @@ -141,7 +161,11 @@ exports.ExpressionStatement = function (node, parent, file, scope) { t.variableDeclarator(ref, expr.right) ])); - push(false, nodes, expr.left, ref); + push({ + kind: false, + file: file, + scope: scope + }, nodes, expr.left, ref); return nodes; }; diff --git a/lib/6to5/transformation/transformers/spread.js b/lib/6to5/transformation/transformers/spread.js index fdb246b618..69ce714daa 100644 --- a/lib/6to5/transformation/transformers/spread.js +++ b/lib/6to5/transformation/transformers/spread.js @@ -1,13 +1,13 @@ -var t = require("../../types"); -var _ = require("lodash"); +var util = require("../../util"); +var t = require("../../types"); +var _ = require("lodash"); var getSpreadLiteral = function (spread) { var literal = spread.argument; if (!t.isArrayExpression(literal)) { - literal = t.callExpression( - t.memberExpression(t.identifier("Array"), t.identifier("from")), - [literal] - ); + literal = util.template("array-from", { + VALUE: literal + }); } return literal; }; diff --git a/test/fixtures/transformation/destructuring/array/expected.js b/test/fixtures/transformation/destructuring/array/expected.js index 88726d5ab7..08dca5a629 100644 --- a/test/fixtures/transformation/destructuring/array/expected.js +++ b/test/fixtures/transformation/destructuring/array/expected.js @@ -2,7 +2,13 @@ var _ref = ["hello", [", ", "junk"], ["world"]]; -var a = _ref[0]; -var b = _ref[1][0]; -var c = _ref[2][0]; -var d = _ref[3]; +var _ref2 = Array.from(_ref); + +var a = _ref2[0]; +var _ref3 = Array.from(_ref2[1]); + +var b = _ref3[0]; +var _ref4 = Array.from(_ref2[2]); + +var c = _ref4[0]; +var d = _ref2[3]; diff --git a/test/fixtures/transformation/destructuring/assignment-statement/expected.js b/test/fixtures/transformation/destructuring/assignment-statement/expected.js index 792c6693a2..35fc2af043 100644 --- a/test/fixtures/transformation/destructuring/assignment-statement/expected.js +++ b/test/fixtures/transformation/destructuring/assignment-statement/expected.js @@ -2,5 +2,7 @@ var _ref = f(); -a = _ref[0]; -b = _ref[1]; +var _ref2 = Array.from(_ref); + +a = _ref2[0]; +b = _ref2[1]; diff --git a/test/fixtures/transformation/destructuring/empty/expected.js b/test/fixtures/transformation/destructuring/empty/expected.js index 63ea350455..451f7ce094 100644 --- a/test/fixtures/transformation/destructuring/empty/expected.js +++ b/test/fixtures/transformation/destructuring/empty/expected.js @@ -2,7 +2,13 @@ var _ref = ["foo", "hello", [", ", "junk"], ["world"]]; -var a = _ref[1]; -var b = _ref[2][0]; -var c = _ref[3][0]; -var d = _ref[4]; +var _ref2 = Array.from(_ref); + +var a = _ref2[1]; +var _ref3 = Array.from(_ref2[2]); + +var b = _ref3[0]; +var _ref4 = Array.from(_ref2[3]); + +var c = _ref4[0]; +var d = _ref2[4]; diff --git a/test/fixtures/transformation/destructuring/for-in/expected.js b/test/fixtures/transformation/destructuring/for-in/expected.js index aeef27f30c..8b6d099ac0 100644 --- a/test/fixtures/transformation/destructuring/for-in/expected.js +++ b/test/fixtures/transformation/destructuring/for-in/expected.js @@ -1,7 +1,9 @@ "use strict"; for (var _ref in obj) { - var name = _ref[0]; - var value = _ref[1]; + var _ref2 = Array.from(_ref); + + var name = _ref2[0]; + var value = _ref2[1]; print("Name: " + name + ", Value: " + value); } diff --git a/test/fixtures/transformation/destructuring/for-of/expected.js b/test/fixtures/transformation/destructuring/for-of/expected.js index 92e6b21ed3..07794c6a75 100644 --- a/test/fixtures/transformation/destructuring/for-of/expected.js +++ b/test/fixtures/transformation/destructuring/for-of/expected.js @@ -2,7 +2,9 @@ for (var _iterator = this.test.expectation.registers[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) { var _ref = _step.value; - var name = _ref[0]; - var before = _ref[1]; - var after = _ref[2]; -} \ No newline at end of file + var _ref2 = Array.from(_ref); + + var name = _ref2[0]; + var before = _ref2[1]; + var after = _ref2[2]; +} diff --git a/test/fixtures/transformation/destructuring/member-expression/expected.js b/test/fixtures/transformation/destructuring/member-expression/expected.js index 10fe8bde68..54f4e6a4d9 100644 --- a/test/fixtures/transformation/destructuring/member-expression/expected.js +++ b/test/fixtures/transformation/destructuring/member-expression/expected.js @@ -2,5 +2,7 @@ var _ref = [1, 2]; -this.foo = _ref[0]; -this.bar = _ref[1]; +var _ref2 = Array.from(_ref); + +this.foo = _ref2[0]; +this.bar = _ref2[1]; diff --git a/test/fixtures/transformation/destructuring/mixed/expected.js b/test/fixtures/transformation/destructuring/mixed/expected.js index 3a7cae0ef3..595e61e0f6 100644 --- a/test/fixtures/transformation/destructuring/mixed/expected.js +++ b/test/fixtures/transformation/destructuring/mixed/expected.js @@ -1,6 +1,10 @@ "use strict"; -var x1 = rect.topLeft[0]; -var y1 = rect.topLeft[1]; -var x2 = rect.bottomRight[0]; -var y2 = rect.bottomRight[1]; \ No newline at end of file +var _ref = Array.from(rect.topLeft); + +var x1 = _ref[0]; +var y1 = _ref[1]; +var _ref2 = Array.from(rect.bottomRight); + +var x2 = _ref2[0]; +var y2 = _ref2[1]; diff --git a/test/fixtures/transformation/destructuring/multiple/expected.js b/test/fixtures/transformation/destructuring/multiple/expected.js index 039184fd2c..c782335937 100644 --- a/test/fixtures/transformation/destructuring/multiple/expected.js +++ b/test/fixtures/transformation/destructuring/multiple/expected.js @@ -2,4 +2,4 @@ var x = coords.x; var y = coords.y; -var foo = "bar"; \ No newline at end of file +var foo = "bar"; diff --git a/test/fixtures/transformation/destructuring/object-advanced/expected.js b/test/fixtures/transformation/destructuring/object-advanced/expected.js index 00af4c96da..d3ee04ea05 100644 --- a/test/fixtures/transformation/destructuring/object-advanced/expected.js +++ b/test/fixtures/transformation/destructuring/object-advanced/expected.js @@ -3,4 +3,4 @@ var x1 = rect.topLeft.x; var y1 = rect.topLeft.y; var x2 = rect.bottomRight.x; -var y2 = rect.bottomRight.y; \ No newline at end of file +var y2 = rect.bottomRight.y; diff --git a/test/fixtures/transformation/destructuring/object-basic/expected.js b/test/fixtures/transformation/destructuring/object-basic/expected.js index 2794ae6038..97601e8b4e 100644 --- a/test/fixtures/transformation/destructuring/object-basic/expected.js +++ b/test/fixtures/transformation/destructuring/object-basic/expected.js @@ -1,4 +1,4 @@ "use strict"; var x = coords.x; -var y = coords.y; \ No newline at end of file +var y = coords.y; diff --git a/test/fixtures/transformation/destructuring/parameters/expected.js b/test/fixtures/transformation/destructuring/parameters/expected.js index df43c193f7..3a428e0c3b 100644 --- a/test/fixtures/transformation/destructuring/parameters/expected.js +++ b/test/fixtures/transformation/destructuring/parameters/expected.js @@ -15,13 +15,17 @@ function unpackObject(_ref2) { console.log(unpackObject({ title: "title", author: "author" })); -var unpackArray = function (_ref3, _ref4) { - var a = _ref3[0]; - var b = _ref3[1]; - var c = _ref3[2]; - var x = _ref4[0]; - var y = _ref4[1]; - var z = _ref4[2]; +var unpackArray = function (_ref3, _ref5) { + var _ref4 = Array.from(_ref3); + + var a = _ref4[0]; + var b = _ref4[1]; + var c = _ref4[2]; + var _ref6 = Array.from(_ref5); + + var x = _ref6[0]; + var y = _ref6[1]; + var z = _ref6[2]; return a + b + c; }; diff --git a/test/fixtures/transformation/destructuring/spread-generator/exec.js b/test/fixtures/transformation/destructuring/spread-generator/exec.js new file mode 100644 index 0000000000..32c9aec57b --- /dev/null +++ b/test/fixtures/transformation/destructuring/spread-generator/exec.js @@ -0,0 +1,7 @@ +function* f() { + for (var i = 0; i < 3; i++) { + yield i; + } +} +var [...xs] = f(); +assert.deepEqual(xs, [0, 1, 2]); diff --git a/test/fixtures/transformation/destructuring/spread/expected.js b/test/fixtures/transformation/destructuring/spread/expected.js index 8802adf2b1..dcee4ce9b4 100644 --- a/test/fixtures/transformation/destructuring/spread/expected.js +++ b/test/fixtures/transformation/destructuring/spread/expected.js @@ -1,9 +1,11 @@ "use strict"; var isSorted = function (_ref) { - var x = _ref[0]; - var y = _ref[1]; - var wow = _ref.slice(2); + var _ref2 = Array.from(_ref); + + var x = _ref2[0]; + var y = _ref2[1]; + var wow = Array.from(_ref2).slice(2); if (!zs.length) return true; if (y > x) return isSorted(zs);