From 557e5310d426c799e4a30c31635e76892c6de64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 02:11:00 +0100 Subject: [PATCH 01/21] spread operators in arrays --- .../__tests__/es6-spread-operator-test.js | 93 +++++++++++++++++++ visitors/es6-spread-operator-visitors.js | 65 +++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 visitors/__tests__/es6-spread-operator-test.js create mode 100644 visitors/es6-spread-operator-visitors.js diff --git a/visitors/__tests__/es6-spread-operator-test.js b/visitors/__tests__/es6-spread-operator-test.js new file mode 100644 index 0000000..a2dcd01 --- /dev/null +++ b/visitors/__tests__/es6-spread-operator-test.js @@ -0,0 +1,93 @@ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @emails dmitrys@fb.com javascript@lists.facebook.com + */ + +/*jshint evil:true*/ +/* global describe, beforeEach, expect, it*/ + + + +describe('es6-spread-operator-visitors', function() { + var visitors, + transformFn; + beforeEach(function() { + visitors = require('../es6-spread-operator-visitors').visitorList; + transformFn = require('../../src/jstransform').transform; + }); + + function transform(code) { + return transformFn(visitors, code).code; + } + + function expectTransform(code, result) { + expect(transform(code)).toEqual(result); + } + + function evalCode(code) { + return eval(transform(code)); + } + + describe('within array', function () { + it('should create an array concatanation of each object in array, and each parameters ', function () { + expect(evalCode('[1, 2, ...[3, 4]]')).toEqual([1, 2, 3, 4]); + }); + + it('should throws an error if spread a non object ', function () { + expect(function () { + evalCode('[1, 2, ...{ a: 5 }'); + }).toThrow(); + }); + + it('should throws an error if passing a non array', function () { + expect(function () { + evalCode('[1, 2, ...{ a: 5 }'); + }).toThrow(); + }); + + it('should accept anything that resolve to an array', function () { + expect(evalCode('[1, 2, ...(function () { return [3, 4] })()]')).toEqual([1, 2, 3, 4]); + }); + + it('should ouput the following code source', function () { + expectTransform( + '[1, 2, ...[3, 4]]', + [ + 'Array.prototype.concat.apply([],[1, 2, ', + '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])])' + ].join('')); + }); + + + it('should keep lines break', function () { + expectTransform( + ['[1, 2,', + '...[3,', + ' 4]]' + ].join('\n'), + [ + 'Array.prototype.concat.apply([],[1, 2,', + '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3,', + ' 4])])' + ].join('\n')); + }); + }); + +}); + + diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js new file mode 100644 index 0000000..d389f73 --- /dev/null +++ b/visitors/es6-spread-operator-visitors.js @@ -0,0 +1,65 @@ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*jslint node:true*/ + +/** + * Desugars ES6 rest parameters into ES3 arguments slicing. + * + * function printf(template, ...args) { + * args.forEach(...); + * }; + * + * function printf(template) { + * var args = [].slice.call(arguments, 1); + * args.forEach(...); + * }; + * + */ +var Syntax = require('esprima-fb').Syntax; +var utils = require('../src/utils'); + +var spreadTemplate = '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })('; + +function visitArrayWithSpreadElement(traverse, node, path, state){ + utils.append('Array.prototype.concat.apply([],', state); + utils.catchup(node.range[0], state); + node.elements.forEach(function (node) { + utils.catchup(node.range[0], state); + if (node.type === Syntax.SpreadElement) { + utils.append(spreadTemplate, state); + utils.move(node.range[0] + 3, state); + utils.catchup(node.range[1], state); + utils.append(')', state); + } else { + utils.catchup(node.range[1], state); + } + }); + utils.catchup(node.range[1], state); + utils.append(')', state); +} + +visitArrayWithSpreadElement.test = function (node, path, state) { + return node.type === Syntax.ArrayExpression && + node.elements && + node.elements.some(function (node) { + return node.type === Syntax.SpreadElement; + }); +}; + +exports.visitorList = [ + visitArrayWithSpreadElement +]; From 5d4165d8fc8bc60a3b20bebf3595c74f8a35a8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 18:06:26 +0100 Subject: [PATCH 02/21] spread operator in call expression --- .../__tests__/es6-spread-operator-test.js | 90 +++++++++++++++++-- visitors/es6-spread-operator-visitors.js | 64 ++++++++++--- 2 files changed, 134 insertions(+), 20 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-test.js b/visitors/__tests__/es6-spread-operator-test.js index a2dcd01..f70e972 100644 --- a/visitors/__tests__/es6-spread-operator-test.js +++ b/visitors/__tests__/es6-spread-operator-test.js @@ -18,7 +18,7 @@ * @emails dmitrys@fb.com javascript@lists.facebook.com */ -/*jshint evil:true*/ +/*jshint evil:true, unused: false*/ /* global describe, beforeEach, expect, it*/ @@ -39,29 +39,30 @@ describe('es6-spread-operator-visitors', function() { expect(transform(code)).toEqual(result); } - function evalCode(code) { - return eval(transform(code)); - } describe('within array', function () { it('should create an array concatanation of each object in array, and each parameters ', function () { - expect(evalCode('[1, 2, ...[3, 4]]')).toEqual([1, 2, 3, 4]); + expect(eval(transform('[1, 2, ...[3, 4]]'))).toEqual([1, 2, 3, 4]); + }); + + it('should works with only spread', function () { + expect(eval(transform('[...[1, 2]]'))).toEqual([1, 2]); }); it('should throws an error if spread a non object ', function () { expect(function () { - evalCode('[1, 2, ...{ a: 5 }'); + eval(transform('[1, 2, ...{ a: 5 }')); }).toThrow(); }); it('should throws an error if passing a non array', function () { expect(function () { - evalCode('[1, 2, ...{ a: 5 }'); + eval(transform('[1, 2, ...{ a: 5 }')); }).toThrow(); }); it('should accept anything that resolve to an array', function () { - expect(evalCode('[1, 2, ...(function () { return [3, 4] })()]')).toEqual([1, 2, 3, 4]); + expect(eval(transform('[1, 2, ...(function () { return [3, 4] })()]'))).toEqual([1, 2, 3, 4]); }); it('should ouput the following code source', function () { @@ -87,7 +88,78 @@ describe('es6-spread-operator-visitors', function() { ].join('\n')); }); }); - + + + describe('within call expression', function () { + + function returnArgs () { + return Array.prototype.slice.call(arguments); + } + + + it('should pass spread array as parameters ', function () { + expect(eval(transform('returnArgs(1, 2, ...[3, 4])'))).toEqual([1, 2, 3, 4]); + }); + + it('should ouput the following code source', function () { + expectTransform( + 'returnArgs(1, 2,...[3, 4])', + [ + 'returnArgs.apply(undefined, ', + 'Array.prototype.concat.apply([],[1, 2,', + '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])]))' + ].join('')); + }); + + + it('should keep lines break and comments', function () { + expectTransform( + [ + 'returnArgs /*comments*/(', + ' 1, 2,', + ' ...[3, 4]', + ')' + ].join('\n'), + [ + 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', + ' 1, 2,', + ' (function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])', + ']))' + ].join('\n')); + }); + }); + + + describe('within method call expression', function () { + + var object = { + returnArgsAndThis: function() { + return Array.prototype.slice.call(arguments).concat(this); + } + }; + + + it('should keep the \'this\' context in case of method call ', function () { + expect(eval(transform('object.returnArgsAndThis(1, 2, ...[3, 4])'))).toEqual([1, 2, 3, 4, object]); + }); + + it('should keep the \'this\' context in case of computed method call ', function () { + expect(eval(transform('object[\'return\'+\'ArgsAndThis\'](1, 2, ...[3, 4])'))).toEqual([1, 2, 3, 4, object]); + }); + + + it('should ouput the following code source', function () { + var transformedCode = transform('object.returnArgsAndThis(1, 2, ...[3, 4])'); + transformedCode = transformedCode.replace(/_this\d*/g, '_this'); + expect(transformedCode).toBe([ + '(function() { var _this = object; return _this.returnArgsAndThis', + '.apply(_this, Array.prototype.concat.apply([],[1, 2, ', + '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])]))})()' + ].join('')); + }); + + + }); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index d389f73..342850b 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -34,10 +34,16 @@ var utils = require('../src/utils'); var spreadTemplate = '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })('; -function visitArrayWithSpreadElement(traverse, node, path, state){ - utils.append('Array.prototype.concat.apply([],', state); - utils.catchup(node.range[0], state); - node.elements.forEach(function (node) { +function hasSpread(elements) { + return elements && + elements.some(function (node) { + return node.type === Syntax.SpreadElement; + }); +} + + +function insertElementsWithSpread(elements, state) { + elements.forEach(function (node) { utils.catchup(node.range[0], state); if (node.type === Syntax.SpreadElement) { utils.append(spreadTemplate, state); @@ -48,18 +54,54 @@ function visitArrayWithSpreadElement(traverse, node, path, state){ utils.catchup(node.range[1], state); } }); +} + +function visitArrayWithSpreadElement(traverse, node, path, state) { + utils.append('Array.prototype.concat.apply([],', state); + utils.catchup(node.range[0], state); + insertElementsWithSpread(node.elements, state); utils.catchup(node.range[1], state); utils.append(')', state); } -visitArrayWithSpreadElement.test = function (node, path, state) { - return node.type === Syntax.ArrayExpression && - node.elements && - node.elements.some(function (node) { - return node.type === Syntax.SpreadElement; - }); +visitArrayWithSpreadElement.test = function (node) { + return node.type === Syntax.ArrayExpression && hasSpread(node.elements); +}; + + +function visitFunctionCallWithSpreadElement(traverse, node, path, state) { + //console.log(JSON.stringify(node, null, 4)); + if (node.callee.type === Syntax.MemberExpression) { + var thisIdent = '_this' + (Math.random() * 1e9 >>> 0); + utils.append('(function() { var ' + thisIdent + ' = ', state); + utils.catchup(node.callee.object.range[1], state); + utils.append('; return '+ thisIdent , state); + utils.catchup(node.callee.range[1], state); + utils.append('.apply('+ thisIdent + ', Array.prototype.concat.apply([],', state); + } else { + utils.catchup(node.callee.range[1], state); + utils.append('.apply(undefined, Array.prototype.concat.apply([],', state); + } + utils.catchup(node.arguments[0].range[0], state, function (content) { + //todo too much simplist here we will replace all '(' in comments also + return content.replace(/\(/g, '['); + }); + insertElementsWithSpread(node.arguments, state); + utils.catchup(node.range[1], state, function (content) { + //todo too much simplist here we will replace all ')' in comments also + return content.replace(/\)/g, ']'); + }); + utils.append('))', state); + if (node.callee.type === Syntax.MemberExpression) { + utils.append('})()',state); + } +} + +visitFunctionCallWithSpreadElement.test = function (node) { + return node.type === Syntax.CallExpression && hasSpread(node.arguments); }; exports.visitorList = [ - visitArrayWithSpreadElement + visitArrayWithSpreadElement, + visitFunctionCallWithSpreadElement ]; From eea02333cfdacdbeacfdb7bb2a1abc2a1b2c68ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 20:57:04 +0100 Subject: [PATCH 03/21] renaming --- ...read-operator-test.js => es6-spread-operator-visitors-test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename visitors/__tests__/{es6-spread-operator-test.js => es6-spread-operator-visitors-test.js} (100%) diff --git a/visitors/__tests__/es6-spread-operator-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js similarity index 100% rename from visitors/__tests__/es6-spread-operator-test.js rename to visitors/__tests__/es6-spread-operator-visitors-test.js From f624afa79e726562488bc67c55a71ba7f3532ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 21:22:23 +0100 Subject: [PATCH 04/21] spread in new expression --- .../es6-spread-operator-visitors-test.js | 35 ++++++++++++++++++ visitors/es6-spread-operator-visitors.js | 36 +++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index f70e972..5c7293f 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -159,6 +159,41 @@ describe('es6-spread-operator-visitors', function() { }); + }); + + + describe('within new expression', function () { + + function MyClass(a, b) { + this.a = a; + this.b = b; + } + + + it('should pass spread array as arguments of the construtor, and produce an object instance of called function', function () { + var result = eval(transform('new MyClass(...[1, 2])')); + expect(result).toEqual({ + a: 1, + b: 2 + }); + expect(result instanceof MyClass).toBe(true); + }); + + + it('should ouput the following code source', function () { + var transformedCode = transform('new MyClass(...[1, 2])'); + transformedCode = transformedCode.replace(/_result\d*/g, '_result'); + transformedCode = transformedCode.replace(/_class\d*/g, '_class'); + expect(transformedCode).toBe([ + '(function() { var _class = MyClass, _result = Object.create(_class.prototype);', + '_class.apply(_result, Array.prototype.concat.apply([],[', + '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([1, 2])]));', + 'return _result;', + '})()' + ].join('')); + }); + + }); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 342850b..d5bda5d 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -42,6 +42,10 @@ function hasSpread(elements) { } +function randomInt() { + return Math.random() * 1e9 >>> 0; +} + function insertElementsWithSpread(elements, state) { elements.forEach(function (node) { utils.catchup(node.range[0], state); @@ -70,9 +74,8 @@ visitArrayWithSpreadElement.test = function (node) { function visitFunctionCallWithSpreadElement(traverse, node, path, state) { - //console.log(JSON.stringify(node, null, 4)); if (node.callee.type === Syntax.MemberExpression) { - var thisIdent = '_this' + (Math.random() * 1e9 >>> 0); + var thisIdent = '_this' + randomInt(); utils.append('(function() { var ' + thisIdent + ' = ', state); utils.catchup(node.callee.object.range[1], state); utils.append('; return '+ thisIdent , state); @@ -101,7 +104,34 @@ visitFunctionCallWithSpreadElement.test = function (node) { return node.type === Syntax.CallExpression && hasSpread(node.arguments); }; + +function visitNewExpressionWithSpreadElement(traverse, node, path, state) { + var classIdent = '_class' + randomInt(), + resultIdent = '_result' + randomInt(); + + utils.move(node.range[0] + 4 , state); //remove 'new ' + utils.append('(function() { var ' + classIdent + ' = ', state); + utils.catchup(node.callee.range[1], state); + utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype);', state); + utils.append( classIdent + '.apply('+ resultIdent + ', Array.prototype.concat.apply([],', state); + utils.catchup(node.arguments[0].range[0], state, function (content) { + //todo too much simplist here we will replace all '(' in comments also + return content.replace(/\(/g, '['); + }); + insertElementsWithSpread(node.arguments, state); + utils.catchup(node.range[1], state, function (content) { + //todo too much simplist here we will replace all ')' in comments also + return content.replace(/\)/g, ']'); + }); + utils.append('));return ' + resultIdent + ';})()', state); +} + +visitNewExpressionWithSpreadElement.test = function (node) { + return node.type === Syntax.NewExpression && hasSpread(node.arguments); +}; + exports.visitorList = [ visitArrayWithSpreadElement, - visitFunctionCallWithSpreadElement + visitFunctionCallWithSpreadElement, + visitNewExpressionWithSpreadElement ]; From 4f311275dd15e2933ed0752b932e32d441d5229a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 21:32:28 +0100 Subject: [PATCH 05/21] cleaning and line break respect in new expression --- .../__tests__/es6-spread-operator-visitors-test.js | 13 +++++++++++++ visitors/es6-spread-operator-visitors.js | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 5c7293f..3a915ad 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -192,6 +192,19 @@ describe('es6-spread-operator-visitors', function() { '})()' ].join('')); }); + + it('should keep new lines and comments', function () { + var transformedCode = transform('/*hello world*/ new /*hello*/\nMyClass(\n /*comments*/ ...[1//comment\n, 2])'); + transformedCode = transformedCode.replace(/_result\d*/g, '_result'); + transformedCode = transformedCode.replace(/_class\d*/g, '_class'); + expect(transformedCode).toBe([ + '/*hello world*/ /*hello*/\n(function() { var _class = MyClass, _result = Object.create(_class.prototype);', + '_class.apply(_result, Array.prototype.concat.apply([],[\n /*comments*/ ', + '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([1//comment\n, 2])]));', + 'return _result;', + '})()' + ].join('')); + }); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index d5bda5d..977ccce 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -41,7 +41,6 @@ function hasSpread(elements) { }); } - function randomInt() { return Math.random() * 1e9 >>> 0; } @@ -60,7 +59,7 @@ function insertElementsWithSpread(elements, state) { }); } -function visitArrayWithSpreadElement(traverse, node, path, state) { +function visitArrayExpressionWithSpreadElement(traverse, node, path, state) { utils.append('Array.prototype.concat.apply([],', state); utils.catchup(node.range[0], state); insertElementsWithSpread(node.elements, state); @@ -68,7 +67,7 @@ function visitArrayWithSpreadElement(traverse, node, path, state) { utils.append(')', state); } -visitArrayWithSpreadElement.test = function (node) { +visitArrayExpressionWithSpreadElement.test = function (node) { return node.type === Syntax.ArrayExpression && hasSpread(node.elements); }; @@ -110,6 +109,7 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { resultIdent = '_result' + randomInt(); utils.move(node.range[0] + 4 , state); //remove 'new ' + utils.catchup(node.callee.range[0], state); utils.append('(function() { var ' + classIdent + ' = ', state); utils.catchup(node.callee.range[1], state); utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype);', state); @@ -131,7 +131,7 @@ visitNewExpressionWithSpreadElement.test = function (node) { }; exports.visitorList = [ - visitArrayWithSpreadElement, + visitArrayExpressionWithSpreadElement, visitFunctionCallWithSpreadElement, visitNewExpressionWithSpreadElement ]; From a2491ef75de7eeaf2ca6c753dfbe731494d6e340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 22:26:07 +0100 Subject: [PATCH 06/21] replace spread template --- .../__tests__/es6-spread-operator-visitors-test.js | 14 +++++++------- visitors/es6-spread-operator-visitors.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 3a915ad..60e016d 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -70,7 +70,7 @@ describe('es6-spread-operator-visitors', function() { '[1, 2, ...[3, 4]]', [ 'Array.prototype.concat.apply([],[1, 2, ', - '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])])' + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])])' ].join('')); }); @@ -83,7 +83,7 @@ describe('es6-spread-operator-visitors', function() { ].join('\n'), [ 'Array.prototype.concat.apply([],[1, 2,', - '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3,', + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3,', ' 4])])' ].join('\n')); }); @@ -107,7 +107,7 @@ describe('es6-spread-operator-visitors', function() { [ 'returnArgs.apply(undefined, ', 'Array.prototype.concat.apply([],[1, 2,', - '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])]))' + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])]))' ].join('')); }); @@ -123,7 +123,7 @@ describe('es6-spread-operator-visitors', function() { [ 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', ' 1, 2,', - ' (function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])', + ' (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', ']))' ].join('\n')); }); @@ -154,7 +154,7 @@ describe('es6-spread-operator-visitors', function() { expect(transformedCode).toBe([ '(function() { var _this = object; return _this.returnArgsAndThis', '.apply(_this, Array.prototype.concat.apply([],[1, 2, ', - '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([3, 4])]))})()' + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])]))})()' ].join('')); }); @@ -187,7 +187,7 @@ describe('es6-spread-operator-visitors', function() { expect(transformedCode).toBe([ '(function() { var _class = MyClass, _result = Object.create(_class.prototype);', '_class.apply(_result, Array.prototype.concat.apply([],[', - '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([1, 2])]));', + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1, 2])]));', 'return _result;', '})()' ].join('')); @@ -200,7 +200,7 @@ describe('es6-spread-operator-visitors', function() { expect(transformedCode).toBe([ '/*hello world*/ /*hello*/\n(function() { var _class = MyClass, _result = Object.create(_class.prototype);', '_class.apply(_result, Array.prototype.concat.apply([],[\n /*comments*/ ', - '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })([1//comment\n, 2])]));', + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1//comment\n, 2])]));', 'return _result;', '})()' ].join('')); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 977ccce..72a7537 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -32,7 +32,7 @@ var Syntax = require('esprima-fb').Syntax; var utils = require('../src/utils'); -var spreadTemplate = '(function(v) { return Array.isArray(v)? v : !function () { throw new TypeError(v + \' is not an array\'); }() })('; +var spreadTemplate = '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })('; function hasSpread(elements) { return elements && From 366b3f4828ce0a85ac14c25de8b060dd8ae4baa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 22:35:24 +0100 Subject: [PATCH 07/21] comment with examples of how the spread operator works --- visitors/es6-spread-operator-visitors.js | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 72a7537..a19dab6 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -17,17 +17,26 @@ /*jslint node:true*/ /** - * Desugars ES6 rest parameters into ES3 arguments slicing. + * Desugars ES6 spread operator into ES5 (and ES3 with ES5-shim) equivalent expression * - * function printf(template, ...args) { - * args.forEach(...); - * }; + * [1, 2, 3, ...[4, 5]] + * is transformed into an expression equivalent to : + * [1, 2, 3, 4, 5] + * + * myFunction(...[1, 2]) + * is transformed in an expression equivalent to : + * myFunction(1, 2) * - * function printf(template) { - * var args = [].slice.call(arguments, 1); - * args.forEach(...); - * }; + * myObject.myMethod(…[1, 2]) + * is transformed in an expression equivalent to : + * myObject.myMethod(1, 2) + * + * new MyClass(...[1, 2]) + * is transformed in an expression equivalent to : + * new MyClass(1, 2) + * * + * works only with arrays (no 'iterable object') */ var Syntax = require('esprima-fb').Syntax; var utils = require('../src/utils'); From b90ed592550847bed792685f5deda51870762676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 25 Mar 2014 22:40:05 +0100 Subject: [PATCH 08/21] todo comments syntax correction --- visitors/es6-spread-operator-visitors.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index a19dab6..90e54b8 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -94,12 +94,12 @@ function visitFunctionCallWithSpreadElement(traverse, node, path, state) { utils.append('.apply(undefined, Array.prototype.concat.apply([],', state); } utils.catchup(node.arguments[0].range[0], state, function (content) { - //todo too much simplist here we will replace all '(' in comments also + // TODO: too much simplist here we will replace all '(' in comments also return content.replace(/\(/g, '['); }); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, function (content) { - //todo too much simplist here we will replace all ')' in comments also + // TODO: too much simplist here we will replace all ')' in comments also return content.replace(/\)/g, ']'); }); utils.append('))', state); @@ -124,12 +124,12 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype);', state); utils.append( classIdent + '.apply('+ resultIdent + ', Array.prototype.concat.apply([],', state); utils.catchup(node.arguments[0].range[0], state, function (content) { - //todo too much simplist here we will replace all '(' in comments also + // TODO: too much simplist here we will replace all '(' in comments also return content.replace(/\(/g, '['); }); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, function (content) { - //todo too much simplist here we will replace all ')' in comments also + // TODO: too much simplist here we will replace all ')' in comments also return content.replace(/\)/g, ']'); }); utils.append('));return ' + resultIdent + ';})()', state); From 736632628492a2244f06b40191c18a909c49ad78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 26 Mar 2014 01:07:53 +0100 Subject: [PATCH 09/21] externalize templates in a separate modules --- .../es6-spread-operator-visitors-test.js | 62 ++++++++++++------- visitors/es6-spread-operator-visitors.js | 54 +++++++++------- visitors/spread-templates.js | 37 +++++++++++ 3 files changed, 108 insertions(+), 45 deletions(-) create mode 100644 visitors/spread-templates.js diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 60e016d..932b8bc 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -26,6 +26,8 @@ describe('es6-spread-operator-visitors', function() { var visitors, transformFn; + var spreadTemplates = require('../spread-templates'); + beforeEach(function() { visitors = require('../es6-spread-operator-visitors').visitorList; transformFn = require('../../src/jstransform').transform; @@ -69,22 +71,26 @@ describe('es6-spread-operator-visitors', function() { expectTransform( '[1, 2, ...[3, 4]]', [ - 'Array.prototype.concat.apply([],[1, 2, ', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])])' + spreadTemplates.outerArrayBegin, + '[', + '1, 2, ', + spreadTemplates.spreadLiteralBegin, '[3, 4]', spreadTemplates.spreadLiteralEnd, + ']', + spreadTemplates.outerArrayEnd, ].join('')); }); - it('should keep lines break', function () { + it('should keep lines break and comments', function () { expectTransform( - ['[1, 2,', + ['[1 /*mycomments*/, 2,', '...[3,', ' 4]]' ].join('\n'), [ - 'Array.prototype.concat.apply([],[1, 2,', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3,', - ' 4])])' + spreadTemplates.outerArrayBegin + '[1 /*mycomments*/, 2,', + spreadTemplates.spreadLiteralBegin + '[3,', + ' 4]'+ spreadTemplates.spreadLiteralEnd + ']' + spreadTemplates.outerArrayEnd ].join('\n')); }); }); @@ -105,9 +111,13 @@ describe('es6-spread-operator-visitors', function() { expectTransform( 'returnArgs(1, 2,...[3, 4])', [ - 'returnArgs.apply(undefined, ', - 'Array.prototype.concat.apply([],[1, 2,', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])]))' + 'returnArgs', + spreadTemplates.callExpressionBegin(), + '[', + '1, 2,', + spreadTemplates.spreadLiteralBegin, '[3, 4]', spreadTemplates.spreadLiteralEnd, + ']', + spreadTemplates.callExpressionEnd ].join('')); }); @@ -121,10 +131,10 @@ describe('es6-spread-operator-visitors', function() { ')' ].join('\n'), [ - 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', + 'returnArgs' + spreadTemplates.callExpressionBegin() + ' /*comments*/[', ' 1, 2,', - ' (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', - ']))' + ' ' + spreadTemplates.spreadLiteralBegin + '[3, 4]' + spreadTemplates.spreadLiteralEnd, + ']'+ spreadTemplates.callExpressionEnd ].join('\n')); }); }); @@ -149,12 +159,18 @@ describe('es6-spread-operator-visitors', function() { it('should ouput the following code source', function () { - var transformedCode = transform('object.returnArgsAndThis(1, 2, ...[3, 4])'); + var transformedCode = transform('object.returnArgsAndThis(1, 2,...[3, 4])'); transformedCode = transformedCode.replace(/_this\d*/g, '_this'); expect(transformedCode).toBe([ - '(function() { var _this = object; return _this.returnArgsAndThis', - '.apply(_this, Array.prototype.concat.apply([],[1, 2, ', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])]))})()' + spreadTemplates.closureStart, + 'var _this = object; ', + 'return _this.returnArgsAndThis', spreadTemplates.callExpressionBegin('_this'), + '[', + '1, 2,', + spreadTemplates.spreadLiteralBegin, '[3, 4]', spreadTemplates.spreadLiteralEnd, + ']', + spreadTemplates.callExpressionEnd, + spreadTemplates.closureEnd ].join('')); }); @@ -185,11 +201,15 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_result\d*/g, '_result'); transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ - '(function() { var _class = MyClass, _result = Object.create(_class.prototype);', - '_class.apply(_result, Array.prototype.concat.apply([],[', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1, 2])]));', + spreadTemplates.closureStart, + 'var _class = MyClass, _result = Object.create(_class.prototype);', + '_class', spreadTemplates.callExpressionBegin('_result'), + '[', + spreadTemplates.spreadLiteralBegin, '[1, 2]', spreadTemplates.spreadLiteralEnd, + ']', + spreadTemplates.callExpressionEnd, ';', 'return _result;', - '})()' + spreadTemplates.closureEnd ].join('')); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 90e54b8..256aa40 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -40,8 +40,7 @@ */ var Syntax = require('esprima-fb').Syntax; var utils = require('../src/utils'); - -var spreadTemplate = '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })('; +var spreadTemplates = require('./spread-templates'); function hasSpread(elements) { return elements && @@ -50,18 +49,18 @@ function hasSpread(elements) { }); } -function randomInt() { - return Math.random() * 1e9 >>> 0; +function generateIdent(base) { + return base + (Math.random() * 1e9 >>> 0); } function insertElementsWithSpread(elements, state) { elements.forEach(function (node) { utils.catchup(node.range[0], state); if (node.type === Syntax.SpreadElement) { - utils.append(spreadTemplate, state); - utils.move(node.range[0] + 3, state); + utils.append(spreadTemplates.spreadLiteralBegin, state); + utils.move(node.range[0] + 3, state); // remove ... utils.catchup(node.range[1], state); - utils.append(')', state); + utils.append(spreadTemplates.spreadLiteralEnd, state); } else { utils.catchup(node.range[1], state); } @@ -69,11 +68,10 @@ function insertElementsWithSpread(elements, state) { } function visitArrayExpressionWithSpreadElement(traverse, node, path, state) { - utils.append('Array.prototype.concat.apply([],', state); - utils.catchup(node.range[0], state); + utils.append(spreadTemplates.outerArrayBegin, state); insertElementsWithSpread(node.elements, state); utils.catchup(node.range[1], state); - utils.append(')', state); + utils.append(spreadTemplates.outerArrayEnd, state); } visitArrayExpressionWithSpreadElement.test = function (node) { @@ -82,17 +80,18 @@ visitArrayExpressionWithSpreadElement.test = function (node) { function visitFunctionCallWithSpreadElement(traverse, node, path, state) { + var thisIdent; if (node.callee.type === Syntax.MemberExpression) { - var thisIdent = '_this' + randomInt(); - utils.append('(function() { var ' + thisIdent + ' = ', state); + thisIdent = generateIdent('_this'); + utils.append(spreadTemplates.closureStart, state); + utils.append('var ' + thisIdent + ' = ', state); utils.catchup(node.callee.object.range[1], state); utils.append('; return '+ thisIdent , state); - utils.catchup(node.callee.range[1], state); - utils.append('.apply('+ thisIdent + ', Array.prototype.concat.apply([],', state); - } else { - utils.catchup(node.callee.range[1], state); - utils.append('.apply(undefined, Array.prototype.concat.apply([],', state); } + + utils.catchup(node.callee.range[1], state); + utils.append(spreadTemplates.callExpressionBegin(thisIdent), state); + utils.catchup(node.arguments[0].range[0], state, function (content) { // TODO: too much simplist here we will replace all '(' in comments also return content.replace(/\(/g, '['); @@ -102,9 +101,9 @@ function visitFunctionCallWithSpreadElement(traverse, node, path, state) { // TODO: too much simplist here we will replace all ')' in comments also return content.replace(/\)/g, ']'); }); - utils.append('))', state); + utils.append(spreadTemplates.callExpressionEnd, state); if (node.callee.type === Syntax.MemberExpression) { - utils.append('})()',state); + utils.append(spreadTemplates.closureEnd, state); } } @@ -114,15 +113,16 @@ visitFunctionCallWithSpreadElement.test = function (node) { function visitNewExpressionWithSpreadElement(traverse, node, path, state) { - var classIdent = '_class' + randomInt(), - resultIdent = '_result' + randomInt(); + var classIdent = generateIdent('_class'), + resultIdent = generateIdent('_result'); utils.move(node.range[0] + 4 , state); //remove 'new ' utils.catchup(node.callee.range[0], state); - utils.append('(function() { var ' + classIdent + ' = ', state); + utils.append(spreadTemplates.closureStart, state); + utils.append('var ' + classIdent + ' = ', state); utils.catchup(node.callee.range[1], state); utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype);', state); - utils.append( classIdent + '.apply('+ resultIdent + ', Array.prototype.concat.apply([],', state); + utils.append(classIdent + spreadTemplates.callExpressionBegin(resultIdent), state); utils.catchup(node.arguments[0].range[0], state, function (content) { // TODO: too much simplist here we will replace all '(' in comments also return content.replace(/\(/g, '['); @@ -132,7 +132,13 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { // TODO: too much simplist here we will replace all ')' in comments also return content.replace(/\)/g, ']'); }); - utils.append('));return ' + resultIdent + ';})()', state); + utils.append([ + spreadTemplates.callExpressionEnd, + ';return ', + resultIdent, + ';', + spreadTemplates.closureEnd + ].join(''), state); } visitNewExpressionWithSpreadElement.test = function (node) { diff --git a/visitors/spread-templates.js b/visitors/spread-templates.js new file mode 100644 index 0000000..1ae134e --- /dev/null +++ b/visitors/spread-templates.js @@ -0,0 +1,37 @@ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*jshint node:true*/ + +/** + * just a list of string templates used for spread operator + */ + +module.exports = { + spreadLiteralBegin: '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })(', + spreadLiteralEnd: ')', + + outerArrayBegin: 'Array.prototype.concat.apply([],', + outerArrayEnd: ')', + + callExpressionBegin: function (context) { + return '.apply(context, Array.prototype.concat.apply([],'.replace('context', context); + }, + callExpressionEnd: '))', + + closureStart: '(function() { ', + closureEnd: '})()' +}; \ No newline at end of file From 7d7aeace9f5897dbf9dc83678287b2382002d4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 26 Mar 2014 01:32:42 +0100 Subject: [PATCH 10/21] fix case of '(' and ')' in comments that was replaced --- .../es6-spread-operator-visitors-test.js | 14 +++++ visitors/es6-spread-operator-visitors.js | 53 +++++++++++++------ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 932b8bc..89dc0d5 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -137,6 +137,20 @@ describe('es6-spread-operator-visitors', function() { ']'+ spreadTemplates.callExpressionEnd ].join('\n')); }); + + it('should keep intact comments with \'(\' && \')\' ', function () { + expectTransform( + [ + 'returnArgs /*comments (*/( 1, 2,', + '...[3, 4] //comments )', + ')' + ].join('\n'), + [ + 'returnArgs' + spreadTemplates.callExpressionBegin() + ' /*comments (*/[ 1, 2,', + spreadTemplates.spreadLiteralBegin + '[3, 4]' + spreadTemplates.spreadLiteralEnd + ' //comments )', + ']'+ spreadTemplates.callExpressionEnd + ].join('\n')); + }); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 256aa40..0b78812 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -53,6 +53,39 @@ function generateIdent(base) { return base + (Math.random() * 1e9 >>> 0); } +function replaceInNonComments(search, replace) { + return function (source) { + var result = '', inBlockComment = false, inLineComment = false; + while (source) { + var char = source.charAt(0); + source = source.substr(1); + if (inBlockComment) { + if (char === '*' && source.charAt(0) === '/') { + inBlockComment = false; + } + } else if (inLineComment) { + if (char === '\n') { + inLineComment = false; + } + } else if (char === '/') { + var next = source.charAt(0); + if (next === '*') { + inBlockComment = true; + } else if (next === '/') { + inLineComment = true; + } + } + + if(char === search && !inBlockComment && !inLineComment) { + result += replace; + } else { + result += char; + } + } + return result; + }; +} + function insertElementsWithSpread(elements, state) { elements.forEach(function (node) { utils.catchup(node.range[0], state); @@ -92,15 +125,9 @@ function visitFunctionCallWithSpreadElement(traverse, node, path, state) { utils.catchup(node.callee.range[1], state); utils.append(spreadTemplates.callExpressionBegin(thisIdent), state); - utils.catchup(node.arguments[0].range[0], state, function (content) { - // TODO: too much simplist here we will replace all '(' in comments also - return content.replace(/\(/g, '['); - }); + utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); - utils.catchup(node.range[1], state, function (content) { - // TODO: too much simplist here we will replace all ')' in comments also - return content.replace(/\)/g, ']'); - }); + utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); utils.append(spreadTemplates.callExpressionEnd, state); if (node.callee.type === Syntax.MemberExpression) { utils.append(spreadTemplates.closureEnd, state); @@ -123,15 +150,9 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { utils.catchup(node.callee.range[1], state); utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype);', state); utils.append(classIdent + spreadTemplates.callExpressionBegin(resultIdent), state); - utils.catchup(node.arguments[0].range[0], state, function (content) { - // TODO: too much simplist here we will replace all '(' in comments also - return content.replace(/\(/g, '['); - }); + utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); - utils.catchup(node.range[1], state, function (content) { - // TODO: too much simplist here we will replace all ')' in comments also - return content.replace(/\)/g, ']'); - }); + utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); utils.append([ spreadTemplates.callExpressionEnd, ';return ', From 7828a1253508e6da5c1f59fea3a33d6b20bf434c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 26 Mar 2014 01:59:31 +0100 Subject: [PATCH 11/21] Fix new expression with function that returns value --- .../es6-spread-operator-visitors-test.js | 30 ++++++++++++------- visitors/es6-spread-operator-visitors.js | 17 +++++------ visitors/spread-templates.js | 6 ++-- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 89dc0d5..d5af915 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -199,6 +199,9 @@ describe('es6-spread-operator-visitors', function() { this.b = b; } + function FakeClass(a) { + return a; + } it('should pass spread array as arguments of the construtor, and produce an object instance of called function', function () { var result = eval(transform('new MyClass(...[1, 2])')); @@ -209,6 +212,11 @@ describe('es6-spread-operator-visitors', function() { expect(result instanceof MyClass).toBe(true); }); + it('should return the function return value if the function has one', function () { + expect(eval(transform('new FakeClass(...[1, 2])'))).toBe(1); + expect(eval(transform('new FakeClass(...[null])'))).toBe(null); + }); + it('should ouput the following code source', function () { var transformedCode = transform('new MyClass(...[1, 2])'); @@ -216,28 +224,28 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ spreadTemplates.closureStart, - 'var _class = MyClass, _result = Object.create(_class.prototype);', - '_class', spreadTemplates.callExpressionBegin('_result'), + 'var _class = MyClass, _result = Object.create(_class.prototype)', + ', funcResult = _class', spreadTemplates.callExpressionBegin('_result'), '[', spreadTemplates.spreadLiteralBegin, '[1, 2]', spreadTemplates.spreadLiteralEnd, ']', - spreadTemplates.callExpressionEnd, ';', - 'return _result;', + spreadTemplates.callExpressionEnd, + spreadTemplates.newExpressionFuncResultCheck, + '; return _result;', spreadTemplates.closureEnd ].join('')); }); it('should keep new lines and comments', function () { - var transformedCode = transform('/*hello world*/ new /*hello*/\nMyClass(\n /*comments*/ ...[1//comment\n, 2])'); + var transformedCode = transform('/*hello world (*/ new /*hello*/\nMyClass(\n /*comments*/ ...[1//comment\n, 2])'); transformedCode = transformedCode.replace(/_result\d*/g, '_result'); transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ - '/*hello world*/ /*hello*/\n(function() { var _class = MyClass, _result = Object.create(_class.prototype);', - '_class.apply(_result, Array.prototype.concat.apply([],[\n /*comments*/ ', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1//comment\n, 2])]));', - 'return _result;', - '})()' - ].join('')); + '/*hello world (*/ /*hello*/', + '(function() { var _class = MyClass, _result = Object.create(_class.prototype), funcResult = _class.apply(_result, Array.prototype.concat.apply([],[', + ' /*comments*/ (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1//comment', + ', 2])])); if (typeof funcResult !== \'undefined\') { return funcResult }; return _result;})()' + ].join('\n')); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 0b78812..fe152e6 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -128,7 +128,9 @@ function visitFunctionCallWithSpreadElement(traverse, node, path, state) { utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); + utils.append(spreadTemplates.callExpressionEnd, state); + if (node.callee.type === Syntax.MemberExpression) { utils.append(spreadTemplates.closureEnd, state); } @@ -148,18 +150,15 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { utils.append(spreadTemplates.closureStart, state); utils.append('var ' + classIdent + ' = ', state); utils.catchup(node.callee.range[1], state); - utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype);', state); - utils.append(classIdent + spreadTemplates.callExpressionBegin(resultIdent), state); + utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype), ', state); + utils.append('funcResult = ' + classIdent + spreadTemplates.callExpressionBegin(resultIdent), state); utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); - utils.append([ - spreadTemplates.callExpressionEnd, - ';return ', - resultIdent, - ';', - spreadTemplates.closureEnd - ].join(''), state); + utils.append(spreadTemplates.callExpressionEnd, state); + utils.append(spreadTemplates.newExpressionFuncResultCheck, state); + utils.append('; return ' + resultIdent + ';', state); + utils.append(spreadTemplates.closureEnd, state); } visitNewExpressionWithSpreadElement.test = function (node) { diff --git a/visitors/spread-templates.js b/visitors/spread-templates.js index 1ae134e..ca4d087 100644 --- a/visitors/spread-templates.js +++ b/visitors/spread-templates.js @@ -33,5 +33,7 @@ module.exports = { callExpressionEnd: '))', closureStart: '(function() { ', - closureEnd: '})()' -}; \ No newline at end of file + closureEnd: '})()', + + newExpressionFuncResultCheck: '; if (typeof funcResult !== \'undefined\') { return funcResult }' +}; From 70bafa27212799c21d25ed0f5f617a19d0feeb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Thu, 27 Mar 2014 20:58:23 +0100 Subject: [PATCH 12/21] Revert templates extenalizing We agree with @jeffmo on IRC that externalizing the string in another modules resulted in less readability in visitors --- .../es6-spread-operator-visitors-test.js | 53 +++++++++---------- visitors/es6-spread-operator-visitors.js | 29 +++++----- visitors/spread-templates.js | 39 -------------- 3 files changed, 40 insertions(+), 81 deletions(-) delete mode 100644 visitors/spread-templates.js diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index d5af915..c34430d 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -26,7 +26,6 @@ describe('es6-spread-operator-visitors', function() { var visitors, transformFn; - var spreadTemplates = require('../spread-templates'); beforeEach(function() { visitors = require('../es6-spread-operator-visitors').visitorList; @@ -71,12 +70,12 @@ describe('es6-spread-operator-visitors', function() { expectTransform( '[1, 2, ...[3, 4]]', [ - spreadTemplates.outerArrayBegin, + 'Array.prototype.concat.apply([],', '[', '1, 2, ', - spreadTemplates.spreadLiteralBegin, '[3, 4]', spreadTemplates.spreadLiteralEnd, + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', ']', - spreadTemplates.outerArrayEnd, + ')', ].join('')); }); @@ -88,9 +87,9 @@ describe('es6-spread-operator-visitors', function() { ' 4]]' ].join('\n'), [ - spreadTemplates.outerArrayBegin + '[1 /*mycomments*/, 2,', - spreadTemplates.spreadLiteralBegin + '[3,', - ' 4]'+ spreadTemplates.spreadLiteralEnd + ']' + spreadTemplates.outerArrayEnd + 'Array.prototype.concat.apply([],[1 /*mycomments*/, 2,', + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3,', + ' 4])])' ].join('\n')); }); }); @@ -112,12 +111,12 @@ describe('es6-spread-operator-visitors', function() { 'returnArgs(1, 2,...[3, 4])', [ 'returnArgs', - spreadTemplates.callExpressionBegin(), + '.apply(undefined, Array.prototype.concat.apply([],', '[', '1, 2,', - spreadTemplates.spreadLiteralBegin, '[3, 4]', spreadTemplates.spreadLiteralEnd, + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', ']', - spreadTemplates.callExpressionEnd + '))' ].join('')); }); @@ -131,10 +130,10 @@ describe('es6-spread-operator-visitors', function() { ')' ].join('\n'), [ - 'returnArgs' + spreadTemplates.callExpressionBegin() + ' /*comments*/[', + 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', ' 1, 2,', - ' ' + spreadTemplates.spreadLiteralBegin + '[3, 4]' + spreadTemplates.spreadLiteralEnd, - ']'+ spreadTemplates.callExpressionEnd + ' (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', + ']'+ '))' ].join('\n')); }); @@ -146,9 +145,9 @@ describe('es6-spread-operator-visitors', function() { ')' ].join('\n'), [ - 'returnArgs' + spreadTemplates.callExpressionBegin() + ' /*comments (*/[ 1, 2,', - spreadTemplates.spreadLiteralBegin + '[3, 4]' + spreadTemplates.spreadLiteralEnd + ' //comments )', - ']'+ spreadTemplates.callExpressionEnd + 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments (*/[ 1, 2,', + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4]) //comments )', + ']'+ '))' ].join('\n')); }); }); @@ -176,15 +175,15 @@ describe('es6-spread-operator-visitors', function() { var transformedCode = transform('object.returnArgsAndThis(1, 2,...[3, 4])'); transformedCode = transformedCode.replace(/_this\d*/g, '_this'); expect(transformedCode).toBe([ - spreadTemplates.closureStart, + '(function() { ', 'var _this = object; ', - 'return _this.returnArgsAndThis', spreadTemplates.callExpressionBegin('_this'), + 'return _this.returnArgsAndThis.apply(_this, Array.prototype.concat.apply([],', '[', '1, 2,', - spreadTemplates.spreadLiteralBegin, '[3, 4]', spreadTemplates.spreadLiteralEnd, + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', ']', - spreadTemplates.callExpressionEnd, - spreadTemplates.closureEnd + '))', + '})()' ].join('')); }); @@ -223,16 +222,16 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_result\d*/g, '_result'); transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ - spreadTemplates.closureStart, + '(function() { ', 'var _class = MyClass, _result = Object.create(_class.prototype)', - ', funcResult = _class', spreadTemplates.callExpressionBegin('_result'), + ', funcResult = _class.apply(_result, Array.prototype.concat.apply([],', '[', - spreadTemplates.spreadLiteralBegin, '[1, 2]', spreadTemplates.spreadLiteralEnd, + '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1, 2])', ']', - spreadTemplates.callExpressionEnd, - spreadTemplates.newExpressionFuncResultCheck, + '))', + '; if (typeof funcResult !== \'undefined\') { return funcResult }', '; return _result;', - spreadTemplates.closureEnd + '})()' ].join('')); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index fe152e6..a718b35 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -40,7 +40,6 @@ */ var Syntax = require('esprima-fb').Syntax; var utils = require('../src/utils'); -var spreadTemplates = require('./spread-templates'); function hasSpread(elements) { return elements && @@ -90,10 +89,10 @@ function insertElementsWithSpread(elements, state) { elements.forEach(function (node) { utils.catchup(node.range[0], state); if (node.type === Syntax.SpreadElement) { - utils.append(spreadTemplates.spreadLiteralBegin, state); + utils.append('(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })(', state); utils.move(node.range[0] + 3, state); // remove ... utils.catchup(node.range[1], state); - utils.append(spreadTemplates.spreadLiteralEnd, state); + utils.append(')', state); } else { utils.catchup(node.range[1], state); } @@ -101,10 +100,10 @@ function insertElementsWithSpread(elements, state) { } function visitArrayExpressionWithSpreadElement(traverse, node, path, state) { - utils.append(spreadTemplates.outerArrayBegin, state); + utils.append('Array.prototype.concat.apply([],', state); insertElementsWithSpread(node.elements, state); utils.catchup(node.range[1], state); - utils.append(spreadTemplates.outerArrayEnd, state); + utils.append(')', state); } visitArrayExpressionWithSpreadElement.test = function (node) { @@ -113,26 +112,26 @@ visitArrayExpressionWithSpreadElement.test = function (node) { function visitFunctionCallWithSpreadElement(traverse, node, path, state) { - var thisIdent; + var thisIdent = 'undefined'; if (node.callee.type === Syntax.MemberExpression) { thisIdent = generateIdent('_this'); - utils.append(spreadTemplates.closureStart, state); + utils.append('(function() { ', state); utils.append('var ' + thisIdent + ' = ', state); utils.catchup(node.callee.object.range[1], state); utils.append('; return '+ thisIdent , state); } utils.catchup(node.callee.range[1], state); - utils.append(spreadTemplates.callExpressionBegin(thisIdent), state); + utils.append('.apply(' + thisIdent + ', Array.prototype.concat.apply([],', state); utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); - utils.append(spreadTemplates.callExpressionEnd, state); + utils.append('))', state); if (node.callee.type === Syntax.MemberExpression) { - utils.append(spreadTemplates.closureEnd, state); + utils.append('})()', state); } } @@ -147,18 +146,18 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { utils.move(node.range[0] + 4 , state); //remove 'new ' utils.catchup(node.callee.range[0], state); - utils.append(spreadTemplates.closureStart, state); + utils.append('(function() { ', state); utils.append('var ' + classIdent + ' = ', state); utils.catchup(node.callee.range[1], state); utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype), ', state); - utils.append('funcResult = ' + classIdent + spreadTemplates.callExpressionBegin(resultIdent), state); + utils.append('funcResult = ' + classIdent + '.apply(' + resultIdent + ', Array.prototype.concat.apply([],', state); utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); - utils.append(spreadTemplates.callExpressionEnd, state); - utils.append(spreadTemplates.newExpressionFuncResultCheck, state); + utils.append('))', state); + utils.append('; if (typeof funcResult !== \'undefined\') { return funcResult }', state); utils.append('; return ' + resultIdent + ';', state); - utils.append(spreadTemplates.closureEnd, state); + utils.append('})()', state); } visitNewExpressionWithSpreadElement.test = function (node) { diff --git a/visitors/spread-templates.js b/visitors/spread-templates.js deleted file mode 100644 index ca4d087..0000000 --- a/visitors/spread-templates.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright 2013 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*jshint node:true*/ - -/** - * just a list of string templates used for spread operator - */ - -module.exports = { - spreadLiteralBegin: '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })(', - spreadLiteralEnd: ')', - - outerArrayBegin: 'Array.prototype.concat.apply([],', - outerArrayEnd: ')', - - callExpressionBegin: function (context) { - return '.apply(context, Array.prototype.concat.apply([],'.replace('context', context); - }, - callExpressionEnd: '))', - - closureStart: '(function() { ', - closureEnd: '})()', - - newExpressionFuncResultCheck: '; if (typeof funcResult !== \'undefined\') { return funcResult }' -}; From ab7c4b409bf5a86c7da42553c77e84a5748b11f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Thu, 27 Mar 2014 21:00:58 +0100 Subject: [PATCH 13/21] reformat a little the code source output in tests --- .../__tests__/es6-spread-operator-visitors-test.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index c34430d..8bd9c32 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -133,7 +133,7 @@ describe('es6-spread-operator-visitors', function() { 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', ' 1, 2,', ' (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', - ']'+ '))' + ']))' ].join('\n')); }); @@ -147,7 +147,7 @@ describe('es6-spread-operator-visitors', function() { [ 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments (*/[ 1, 2,', '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4]) //comments )', - ']'+ '))' + ']))' ].join('\n')); }); }); @@ -177,12 +177,10 @@ describe('es6-spread-operator-visitors', function() { expect(transformedCode).toBe([ '(function() { ', 'var _this = object; ', - 'return _this.returnArgsAndThis.apply(_this, Array.prototype.concat.apply([],', - '[', + 'return _this.returnArgsAndThis.apply(_this, Array.prototype.concat.apply([],[', '1, 2,', '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', - ']', - '))', + ']))', '})()' ].join('')); }); From 5d4d4375332114e4384f7a31f209be9a51a3aa2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Fri, 28 Mar 2014 03:04:13 +0100 Subject: [PATCH 14/21] add runtimes inclusion logic --- .../es6-spread-operator-visitors-test.js | 21 +++++++++++++++---- visitors/es6-spread-operator-runtime.js | 1 + visitors/es6-spread-operator-visitors.js | 15 +++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 visitors/es6-spread-operator-runtime.js diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 8bd9c32..8d1873f 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -24,6 +24,9 @@ describe('es6-spread-operator-visitors', function() { + var fs = require('fs'), path = require('path'), + runtime = fs.readFileSync(path.join(__dirname, '..', 'es6-spread-operator-runtime.js'), 'utf-8'); + var visitors, transformFn; @@ -32,14 +35,24 @@ describe('es6-spread-operator-visitors', function() { transformFn = require('../../src/jstransform').transform; }); - function transform(code) { - return transformFn(visitors, code).code; + function transform(code, options) { + return transformFn(visitors, code, options).code; } - function expectTransform(code, result) { - expect(transform(code)).toEqual(result); + function expectTransform(code, result, options) { + expect(transform(code, options)).toEqual(result); } + describe('runtime', function () { + it('should be included if the options \'includeSpreadRuntime \' is set to true ', function () { + expectTransform('', runtime, { includeSpreadRuntime: true }); + }); + + it('should not be included otherwise', function () { + expectTransform('', ''); + }); + }); + describe('within array', function () { it('should create an array concatanation of each object in array, and each parameters ', function () { diff --git a/visitors/es6-spread-operator-runtime.js b/visitors/es6-spread-operator-runtime.js new file mode 100644 index 0000000..1377c02 --- /dev/null +++ b/visitors/es6-spread-operator-runtime.js @@ -0,0 +1 @@ +//fake runtime diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index a718b35..b8558cd 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -99,6 +99,20 @@ function insertElementsWithSpread(elements, state) { }); } + +var fs = require('fs'), + path = require('path'), + runtime = fs.readFileSync(path.join(__dirname, 'es6-spread-operator-runtime.js'), 'utf-8'); + +function visitProgram(traverse, node, path, state) { + if (state.g.opts.includeSpreadRuntime) { + utils.append(runtime, state); + } +} +visitProgram.test = function(node) { + return node.type === Syntax.Program; +}; + function visitArrayExpressionWithSpreadElement(traverse, node, path, state) { utils.append('Array.prototype.concat.apply([],', state); insertElementsWithSpread(node.elements, state); @@ -165,6 +179,7 @@ visitNewExpressionWithSpreadElement.test = function (node) { }; exports.visitorList = [ + visitProgram, visitArrayExpressionWithSpreadElement, visitFunctionCallWithSpreadElement, visitNewExpressionWithSpreadElement From 8615906acdb671eeb241b1373211fa18655d86bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Fri, 28 Mar 2014 03:15:54 +0100 Subject: [PATCH 15/21] fix bad tests --- visitors/__tests__/es6-spread-operator-visitors-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 8bd9c32..33fa6b4 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -52,13 +52,13 @@ describe('es6-spread-operator-visitors', function() { it('should throws an error if spread a non object ', function () { expect(function () { - eval(transform('[1, 2, ...{ a: 5 }')); + eval(transform('[1, 2, ...undefined]')); }).toThrow(); }); it('should throws an error if passing a non array', function () { expect(function () { - eval(transform('[1, 2, ...{ a: 5 }')); + eval(transform('[1, 2, ...{ a: 5 }]')); }).toThrow(); }); From 0aa0ecb4d719cc577c20d57d365ae60939aff4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Fri, 28 Mar 2014 03:37:35 +0100 Subject: [PATCH 16/21] replace spread element check by runtimes call --- .../es6-spread-operator-visitors-test.js | 40 +++++++++---------- visitors/es6-spread-operator-runtime.js | 24 ++++++++++- visitors/es6-spread-operator-visitors.js | 12 +++--- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 8d1873f..585cdb4 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -49,34 +49,34 @@ describe('es6-spread-operator-visitors', function() { }); it('should not be included otherwise', function () { - expectTransform('', ''); + expectTransform('', '', {}); }); }); describe('within array', function () { it('should create an array concatanation of each object in array, and each parameters ', function () { - expect(eval(transform('[1, 2, ...[3, 4]]'))).toEqual([1, 2, 3, 4]); + expect(eval(transform('[1, 2, ...[3, 4]]', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4]); }); it('should works with only spread', function () { - expect(eval(transform('[...[1, 2]]'))).toEqual([1, 2]); + expect(eval(transform('[...[1, 2]]', { includeSpreadRuntime: true }))).toEqual([1, 2]); }); it('should throws an error if spread a non object ', function () { expect(function () { - eval(transform('[1, 2, ...{ a: 5 }')); + eval(transform('[1, 2, ...{ a: 5 }', { includeSpreadRuntime: true })); }).toThrow(); }); it('should throws an error if passing a non array', function () { expect(function () { - eval(transform('[1, 2, ...{ a: 5 }')); + eval(transform('[1, 2, ...{ a: 5 }', { includeSpreadRuntime: true })); }).toThrow(); }); it('should accept anything that resolve to an array', function () { - expect(eval(transform('[1, 2, ...(function () { return [3, 4] })()]'))).toEqual([1, 2, 3, 4]); + expect(eval(transform('[1, 2, ...(function () { return [3, 4] })()]', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4]); }); it('should ouput the following code source', function () { @@ -86,7 +86,7 @@ describe('es6-spread-operator-visitors', function() { 'Array.prototype.concat.apply([],', '[', '1, 2, ', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', + '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', ']', ')', ].join('')); @@ -101,7 +101,7 @@ describe('es6-spread-operator-visitors', function() { ].join('\n'), [ 'Array.prototype.concat.apply([],[1 /*mycomments*/, 2,', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3,', + '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3,', ' 4])])' ].join('\n')); }); @@ -116,7 +116,7 @@ describe('es6-spread-operator-visitors', function() { it('should pass spread array as parameters ', function () { - expect(eval(transform('returnArgs(1, 2, ...[3, 4])'))).toEqual([1, 2, 3, 4]); + expect(eval(transform('returnArgs(1, 2, ...[3, 4])', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4]); }); it('should ouput the following code source', function () { @@ -127,7 +127,7 @@ describe('es6-spread-operator-visitors', function() { '.apply(undefined, Array.prototype.concat.apply([],', '[', '1, 2,', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', + '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', ']', '))' ].join('')); @@ -145,7 +145,7 @@ describe('es6-spread-operator-visitors', function() { [ 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', ' 1, 2,', - ' (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', + ' ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', ']))' ].join('\n')); }); @@ -159,7 +159,7 @@ describe('es6-spread-operator-visitors', function() { ].join('\n'), [ 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments (*/[ 1, 2,', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4]) //comments )', + '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4]) //comments )', ']))' ].join('\n')); }); @@ -176,11 +176,11 @@ describe('es6-spread-operator-visitors', function() { it('should keep the \'this\' context in case of method call ', function () { - expect(eval(transform('object.returnArgsAndThis(1, 2, ...[3, 4])'))).toEqual([1, 2, 3, 4, object]); + expect(eval(transform('object.returnArgsAndThis(1, 2, ...[3, 4])', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4, object]); }); it('should keep the \'this\' context in case of computed method call ', function () { - expect(eval(transform('object[\'return\'+\'ArgsAndThis\'](1, 2, ...[3, 4])'))).toEqual([1, 2, 3, 4, object]); + expect(eval(transform('object[\'return\'+\'ArgsAndThis\'](1, 2, ...[3, 4])', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4, object]); }); @@ -192,7 +192,7 @@ describe('es6-spread-operator-visitors', function() { 'var _this = object; ', 'return _this.returnArgsAndThis.apply(_this, Array.prototype.concat.apply([],[', '1, 2,', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([3, 4])', + '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', ']))', '})()' ].join('')); @@ -214,7 +214,7 @@ describe('es6-spread-operator-visitors', function() { } it('should pass spread array as arguments of the construtor, and produce an object instance of called function', function () { - var result = eval(transform('new MyClass(...[1, 2])')); + var result = eval(transform('new MyClass(...[1, 2])', { includeSpreadRuntime: true })); expect(result).toEqual({ a: 1, b: 2 @@ -223,8 +223,8 @@ describe('es6-spread-operator-visitors', function() { }); it('should return the function return value if the function has one', function () { - expect(eval(transform('new FakeClass(...[1, 2])'))).toBe(1); - expect(eval(transform('new FakeClass(...[null])'))).toBe(null); + expect(eval(transform('new FakeClass(...[1, 2])', { includeSpreadRuntime: true }))).toBe(1); + expect(eval(transform('new FakeClass(...[null])', { includeSpreadRuntime: true }))).toBe(null); }); @@ -237,7 +237,7 @@ describe('es6-spread-operator-visitors', function() { 'var _class = MyClass, _result = Object.create(_class.prototype)', ', funcResult = _class.apply(_result, Array.prototype.concat.apply([],', '[', - '(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1, 2])', + '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1, 2])', ']', '))', '; if (typeof funcResult !== \'undefined\') { return funcResult }', @@ -253,7 +253,7 @@ describe('es6-spread-operator-visitors', function() { expect(transformedCode).toBe([ '/*hello world (*/ /*hello*/', '(function() { var _class = MyClass, _result = Object.create(_class.prototype), funcResult = _class.apply(_result, Array.prototype.concat.apply([],[', - ' /*comments*/ (function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })([1//comment', + ' /*comments*/ ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1//comment', ', 2])])); if (typeof funcResult !== \'undefined\') { return funcResult }; return _result;})()' ].join('\n')); }); diff --git a/visitors/es6-spread-operator-runtime.js b/visitors/es6-spread-operator-runtime.js index 1377c02..ff1abca 100644 --- a/visitors/es6-spread-operator-runtime.js +++ b/visitors/es6-spread-operator-runtime.js @@ -1 +1,23 @@ -//fake runtime +/*global window, self */ +(function (global) { + + function assertSpreadElement(array) { + if (Array.isArray(array)) { + return array; + } + throw new TypeError(array + ' is not an array'); + } + + global.____JSTRANSFORM_SPREAD_RUNTIME____ = { + assertSpreadElement: assertSpreadElement + }; +})((function () { + if (typeof window !== 'undefined') { + return window; + } else if (typeof global !== 'undefined') { + return global; + } else if (typeof self !== 'undefined') { + return self; + } + return this; +})()); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index b8558cd..9db6078 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -40,6 +40,10 @@ */ var Syntax = require('esprima-fb').Syntax; var utils = require('../src/utils'); +var fs = require('fs'); +var path = require('path'); +var runtimeCode = fs.readFileSync(path.join(__dirname, 'es6-spread-operator-runtime.js'), 'utf-8'); +var runtime = '____JSTRANSFORM_SPREAD_RUNTIME____'; function hasSpread(elements) { return elements && @@ -89,7 +93,7 @@ function insertElementsWithSpread(elements, state) { elements.forEach(function (node) { utils.catchup(node.range[0], state); if (node.type === Syntax.SpreadElement) { - utils.append('(function(array) { if (Array.isArray(array)) { return array }; throw new TypeError(array + \' is not an array\'); })(', state); + utils.append(runtime + '.assertSpreadElement(', state); utils.move(node.range[0] + 3, state); // remove ... utils.catchup(node.range[1], state); utils.append(')', state); @@ -100,13 +104,9 @@ function insertElementsWithSpread(elements, state) { } -var fs = require('fs'), - path = require('path'), - runtime = fs.readFileSync(path.join(__dirname, 'es6-spread-operator-runtime.js'), 'utf-8'); - function visitProgram(traverse, node, path, state) { if (state.g.opts.includeSpreadRuntime) { - utils.append(runtime, state); + utils.append(runtimeCode, state); } } visitProgram.test = function(node) { From f15ee211aeb33dee8769d852f108c4e73cff932e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 1 Apr 2014 19:44:51 +0200 Subject: [PATCH 17/21] replace iife by runtimes call to executeNewExpression --- .../es6-spread-operator-visitors-test.js | 20 +++++++------------ visitors/es6-spread-operator-runtime.js | 9 ++++++++- visitors/es6-spread-operator-visitors.js | 12 ++--------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 585cdb4..bdc2a9d 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -215,6 +215,7 @@ describe('es6-spread-operator-visitors', function() { it('should pass spread array as arguments of the construtor, and produce an object instance of called function', function () { var result = eval(transform('new MyClass(...[1, 2])', { includeSpreadRuntime: true })); + console.log(transform('new MyClass(...[1, 2])', { includeSpreadRuntime: true })); expect(result).toEqual({ a: 1, b: 2 @@ -233,16 +234,11 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_result\d*/g, '_result'); transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ - '(function() { ', - 'var _class = MyClass, _result = Object.create(_class.prototype)', - ', funcResult = _class.apply(_result, Array.prototype.concat.apply([],', - '[', + '____JSTRANSFORM_SPREAD_RUNTIME____.executeNewExpression(MyClass, ', + 'Array.prototype.concat.apply([],[', '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1, 2])', - ']', - '))', - '; if (typeof funcResult !== \'undefined\') { return funcResult }', - '; return _result;', - '})()' + '])', + ')' ].join('')); }); @@ -252,13 +248,11 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ '/*hello world (*/ /*hello*/', - '(function() { var _class = MyClass, _result = Object.create(_class.prototype), funcResult = _class.apply(_result, Array.prototype.concat.apply([],[', + '____JSTRANSFORM_SPREAD_RUNTIME____.executeNewExpression(MyClass, Array.prototype.concat.apply([],[', ' /*comments*/ ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1//comment', - ', 2])])); if (typeof funcResult !== \'undefined\') { return funcResult }; return _result;})()' + ', 2])]))' ].join('\n')); }); - - }); }); diff --git a/visitors/es6-spread-operator-runtime.js b/visitors/es6-spread-operator-runtime.js index ff1abca..f0f198d 100644 --- a/visitors/es6-spread-operator-runtime.js +++ b/visitors/es6-spread-operator-runtime.js @@ -7,9 +7,16 @@ } throw new TypeError(array + ' is not an array'); } + + function executeNewExpression(func, args) { + var result = Object.create(func.prototype); + var funcResult = func.apply(result, args); + return typeof funcResult === 'undefined' ? result : funcResult; + } global.____JSTRANSFORM_SPREAD_RUNTIME____ = { - assertSpreadElement: assertSpreadElement + assertSpreadElement: assertSpreadElement, + executeNewExpression: executeNewExpression }; })((function () { if (typeof window !== 'undefined') { diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 9db6078..51d4add 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -155,23 +155,15 @@ visitFunctionCallWithSpreadElement.test = function (node) { function visitNewExpressionWithSpreadElement(traverse, node, path, state) { - var classIdent = generateIdent('_class'), - resultIdent = generateIdent('_result'); - utils.move(node.range[0] + 4 , state); //remove 'new ' utils.catchup(node.callee.range[0], state); - utils.append('(function() { ', state); - utils.append('var ' + classIdent + ' = ', state); + utils.append(runtime + '.executeNewExpression(', state); utils.catchup(node.callee.range[1], state); - utils.append(', ' + resultIdent + ' = Object.create(' + classIdent + '.prototype), ', state); - utils.append('funcResult = ' + classIdent + '.apply(' + resultIdent + ', Array.prototype.concat.apply([],', state); + utils.append(', Array.prototype.concat.apply([],', state); utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); insertElementsWithSpread(node.arguments, state); utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); utils.append('))', state); - utils.append('; if (typeof funcResult !== \'undefined\') { return funcResult }', state); - utils.append('; return ' + resultIdent + ';', state); - utils.append('})()', state); } visitNewExpressionWithSpreadElement.test = function (node) { From 2f16f3dae03346678881eb6db437c2b49468ad4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 2 Apr 2014 08:56:27 +0200 Subject: [PATCH 18/21] remove loging --- visitors/__tests__/es6-spread-operator-visitors-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index ef6df80..96794ab 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -215,7 +215,6 @@ describe('es6-spread-operator-visitors', function() { it('should pass spread array as arguments of the construtor, and produce an object instance of called function', function () { var result = eval(transform('new MyClass(...[1, 2])', { includeSpreadRuntime: true })); - console.log(transform('new MyClass(...[1, 2])', { includeSpreadRuntime: true })); expect(result).toEqual({ a: 1, b: 2 From 0e94da6cff4a08a526bf75ce9eb3bf2a9d1ba7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 2 Apr 2014 08:59:18 +0200 Subject: [PATCH 19/21] adding failing test case for array elements without spread operator --- visitors/__tests__/es6-spread-operator-visitors-test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index 96794ab..a48cdf4 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -79,6 +79,10 @@ describe('es6-spread-operator-visitors', function() { expect(eval(transform('[1, 2, ...(function () { return [3, 4] })()]', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4]); }); + it('it should not spread elements without spread operator', function () { + expect(eval(transform('[[1,2], ...[3, 4]]', { includeSpreadRuntime: true }))).toEqual([[1, 2], 3, 4]); + }); + it('should ouput the following code source', function () { expectTransform( '[1, 2, ...[3, 4]]', From c941ee0f6862bdb6c48fb2c8b3dd8b57b9dfb0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 2 Apr 2014 09:55:27 +0200 Subject: [PATCH 20/21] fix output code source too match the excepted transformation --- .../es6-spread-operator-visitors-test.js | 48 ++++++++----------- visitors/es6-spread-operator-visitors.js | 35 +++++++++----- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/visitors/__tests__/es6-spread-operator-visitors-test.js b/visitors/__tests__/es6-spread-operator-visitors-test.js index a48cdf4..241a40a 100644 --- a/visitors/__tests__/es6-spread-operator-visitors-test.js +++ b/visitors/__tests__/es6-spread-operator-visitors-test.js @@ -87,11 +87,8 @@ describe('es6-spread-operator-visitors', function() { expectTransform( '[1, 2, ...[3, 4]]', [ - 'Array.prototype.concat.apply([],', - '[', - '1, 2, ', - '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', - ']', + 'Array.prototype.concat.call(', + '[1, 2], ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', ')', ].join('')); }); @@ -104,9 +101,9 @@ describe('es6-spread-operator-visitors', function() { ' 4]]' ].join('\n'), [ - 'Array.prototype.concat.apply([],[1 /*mycomments*/, 2,', + 'Array.prototype.concat.call([1 /*mycomments*/, 2],', '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3,', - ' 4])])' + ' 4]))' ].join('\n')); }); }); @@ -119,20 +116,16 @@ describe('es6-spread-operator-visitors', function() { } - it('should pass spread array as parameters ', function () { + it('should pass spread array as parameters', function () { expect(eval(transform('returnArgs(1, 2, ...[3, 4])', { includeSpreadRuntime: true }))).toEqual([1, 2, 3, 4]); }); it('should ouput the following code source', function () { expectTransform( - 'returnArgs(1, 2,...[3, 4])', + 'returnArgs(1, 2, ...[3, 4])', [ - 'returnArgs', - '.apply(undefined, Array.prototype.concat.apply([],', - '[', - '1, 2,', - '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', - ']', + 'returnArgs.apply(undefined, Array.prototype.concat.call(', + '[1, 2], ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', '))' ].join('')); }); @@ -147,10 +140,10 @@ describe('es6-spread-operator-visitors', function() { ')' ].join('\n'), [ - 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments*/[', - ' 1, 2,', + 'returnArgs.apply(undefined, /*comments*/Array.prototype.concat.call(', + ' [1, 2],', ' ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', - ']))' + '))' ].join('\n')); }); @@ -162,9 +155,9 @@ describe('es6-spread-operator-visitors', function() { ')' ].join('\n'), [ - 'returnArgs.apply(undefined, Array.prototype.concat.apply([], /*comments (*/[ 1, 2,', + 'returnArgs.apply(undefined, /*comments (*/Array.prototype.concat.call( [1, 2],', '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4]) //comments )', - ']))' + '))' ].join('\n')); }); }); @@ -194,10 +187,9 @@ describe('es6-spread-operator-visitors', function() { expect(transformedCode).toBe([ '(function() { ', 'var _this = object; ', - 'return _this.returnArgsAndThis.apply(_this, Array.prototype.concat.apply([],[', - '1, 2,', - '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', - ']))', + 'return _this.returnArgsAndThis.apply(_this, Array.prototype.concat.call(', + '[1, 2],____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([3, 4])', + '))', '})()' ].join('')); }); @@ -238,9 +230,7 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ '____JSTRANSFORM_SPREAD_RUNTIME____.executeNewExpression(MyClass, ', - 'Array.prototype.concat.apply([],[', - '____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1, 2])', - '])', + 'Array.prototype.concat.call(____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1, 2]))', ')' ].join('')); }); @@ -251,9 +241,9 @@ describe('es6-spread-operator-visitors', function() { transformedCode = transformedCode.replace(/_class\d*/g, '_class'); expect(transformedCode).toBe([ '/*hello world (*/ /*hello*/', - '____JSTRANSFORM_SPREAD_RUNTIME____.executeNewExpression(MyClass, Array.prototype.concat.apply([],[', + '____JSTRANSFORM_SPREAD_RUNTIME____.executeNewExpression(MyClass, Array.prototype.concat.call(', ' /*comments*/ ____JSTRANSFORM_SPREAD_RUNTIME____.assertSpreadElement([1//comment', - ', 2])]))' + ', 2])))' ].join('\n')); }); }); diff --git a/visitors/es6-spread-operator-visitors.js b/visitors/es6-spread-operator-visitors.js index 51d4add..931c255 100644 --- a/visitors/es6-spread-operator-visitors.js +++ b/visitors/es6-spread-operator-visitors.js @@ -90,17 +90,29 @@ function replaceInNonComments(search, replace) { } function insertElementsWithSpread(elements, state) { + var insideBrackets = false; elements.forEach(function (node) { - utils.catchup(node.range[0], state); if (node.type === Syntax.SpreadElement) { + if (insideBrackets) { + utils.append(']', state); + insideBrackets = false; + } + utils.catchup(node.range[0], state); utils.append(runtime + '.assertSpreadElement(', state); utils.move(node.range[0] + 3, state); // remove ... utils.catchup(node.range[1], state); utils.append(')', state); } else { + if (!insideBrackets) { + utils.append('[', state); + insideBrackets = true; + } utils.catchup(node.range[1], state); } }); + if (insideBrackets) { + utils.append(']', state); + } } @@ -114,10 +126,10 @@ visitProgram.test = function(node) { }; function visitArrayExpressionWithSpreadElement(traverse, node, path, state) { - utils.append('Array.prototype.concat.apply([],', state); + utils.catchup(node.elements[0].range[0], state, + replaceInNonComments('[', 'Array.prototype.concat.call(')); insertElementsWithSpread(node.elements, state); - utils.catchup(node.range[1], state); - utils.append(')', state); + utils.catchup(node.range[1], state, replaceInNonComments(']', ')')); } visitArrayExpressionWithSpreadElement.test = function (node) { @@ -136,13 +148,13 @@ function visitFunctionCallWithSpreadElement(traverse, node, path, state) { } utils.catchup(node.callee.range[1], state); - utils.append('.apply(' + thisIdent + ', Array.prototype.concat.apply([],', state); + utils.append('.apply(' + thisIdent + ', ', state); - utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); + utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', 'Array.prototype.concat.call(')); insertElementsWithSpread(node.arguments, state); - utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); + utils.catchup(node.range[1], state); - utils.append('))', state); + utils.append(')', state); if (node.callee.type === Syntax.MemberExpression) { utils.append('})()', state); @@ -159,11 +171,10 @@ function visitNewExpressionWithSpreadElement(traverse, node, path, state) { utils.catchup(node.callee.range[0], state); utils.append(runtime + '.executeNewExpression(', state); utils.catchup(node.callee.range[1], state); - utils.append(', Array.prototype.concat.apply([],', state); - utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', '[')); + utils.catchup(node.arguments[0].range[0], state, replaceInNonComments('(', ', Array.prototype.concat.call(')); insertElementsWithSpread(node.arguments, state); - utils.catchup(node.range[1], state, replaceInNonComments(')', ']')); - utils.append('))', state); + utils.catchup(node.range[1], state); + utils.append(')', state); } visitNewExpressionWithSpreadElement.test = function (node) { From d12fc1ba1dc406f70141e3af8e230e54fdb26e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Wed, 2 Apr 2014 10:01:58 +0200 Subject: [PATCH 21/21] remove jshint comments in spread-operator-runtime --- visitors/es6-spread-operator-runtime.js | 1 - 1 file changed, 1 deletion(-) diff --git a/visitors/es6-spread-operator-runtime.js b/visitors/es6-spread-operator-runtime.js index f0f198d..2176fc0 100644 --- a/visitors/es6-spread-operator-runtime.js +++ b/visitors/es6-spread-operator-runtime.js @@ -1,4 +1,3 @@ -/*global window, self */ (function (global) { function assertSpreadElement(array) {