From 334a026f53ec137e42b07c2375df2751f92793af Mon Sep 17 00:00:00 2001 From: Julian Rosse Date: Thu, 31 Aug 2017 08:32:34 -0400 Subject: [PATCH 1/4] _extends utility instead of Object.assign() --- lib/coffeescript/nodes.js | 8 ++++++-- src/nodes.coffee | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/coffeescript/nodes.js b/lib/coffeescript/nodes.js index dc58f77515..a6aa1d0289 100644 --- a/lib/coffeescript/nodes.js +++ b/lib/coffeescript/nodes.js @@ -2242,7 +2242,7 @@ // Object spread properties. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md // `obj2 = {a: 1, obj..., c: 3, d: 4}` → `obj2 = Object.assign({}, {a: 1}, obj, {c: 3, d: 4})` compileSpread(o) { - var addSlice, j, len1, prop, propSlices, props, slices, splatSlice; + var _extends, addSlice, j, len1, prop, propSlices, props, slices, splatSlice; props = this.properties; // Store object spreads. splatSlice = []; @@ -2271,7 +2271,8 @@ if (!(slices[0] instanceof Obj)) { slices.unshift(new Obj); } - return (new Call(new Literal('Object.assign'), slices)).compileToFragments(o); + _extends = new Value(new Literal(utility('_extends', o))); + return (new Call(_extends, slices)).compileToFragments(o); } compileCSXAttributes(o) { @@ -5525,6 +5526,9 @@ boundMethodCheck: function() { return "function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } }"; }, + _extends: function() { + return "Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }"; + }, // Shortcuts to speed up the lookup time for native functions. hasProp: function() { return '{}.hasOwnProperty'; diff --git a/src/nodes.coffee b/src/nodes.coffee index f7bea75855..c18b368006 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1530,7 +1530,8 @@ exports.Obj = class Obj extends Base propSlices.push prop addSlice() slices.unshift new Obj unless slices[0] instanceof Obj - (new Call new Literal('Object.assign'), slices).compileToFragments o + _extends = new Value new Literal utility '_extends', o + (new Call _extends, slices).compileToFragments o compileCSXAttributes: (o) -> props = @properties @@ -3717,6 +3718,19 @@ UTILITIES = } } " + _extends: -> " + Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + } + " # Shortcuts to speed up the lookup time for native functions. hasProp: -> '{}.hasOwnProperty' From fe1c4f68c68844eb2cf5cd3275e8f053126d0cee Mon Sep 17 00:00:00 2001 From: Julian Rosse Date: Thu, 31 Aug 2017 08:42:53 -0400 Subject: [PATCH 2/4] eqJS test for _extends --- test/assignment.coffee | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/assignment.coffee b/test/assignment.coffee index 7b5ea8409f..7e7e1c93bf 100644 --- a/test/assignment.coffee +++ b/test/assignment.coffee @@ -874,3 +874,13 @@ test "#4566: destructuring with nested default values", -> {e: {f = 5} = {}} = {} eq 5, f + +test "#4674: _extends utility for object spreads", -> + eqJS( + "{a, b..., c..., d}" + """ + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + + _extends({a}, b, c, {d}); + """ + ) From e93ef044963a5121ff7cf176fc27926f92c1b9eb Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Thu, 31 Aug 2017 20:28:01 -0700 Subject: [PATCH 3/4] =?UTF-8?q?Test=20that=20a=20user-defined=20function?= =?UTF-8?q?=20named=20`=5Fextends`=20doesn=E2=80=99t=20conflict=20with=20o?= =?UTF-8?q?ur=20utility=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/assignment.coffee | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/assignment.coffee b/test/assignment.coffee index 7e7e1c93bf..ff4ba4f347 100644 --- a/test/assignment.coffee +++ b/test/assignment.coffee @@ -875,7 +875,7 @@ test "#4566: destructuring with nested default values", -> {e: {f = 5} = {}} = {} eq 5, f -test "#4674: _extends utility for object spreads", -> +test "#4674: _extends utility for object spreads 1", -> eqJS( "{a, b..., c..., d}" """ @@ -884,3 +884,11 @@ test "#4674: _extends utility for object spreads", -> _extends({a}, b, c, {d}); """ ) + +test "#4674: _extends utility for object spreads 2", -> + _extends = -> 3 + a = b: 1 + c = d: 2 + e = {a..., c...} + eq e.b, 1 + eq e.d, 2 From 5d81728eb4be507b436e9ca63d57b578ef99328f Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Thu, 31 Aug 2017 20:47:53 -0700 Subject: [PATCH 4/4] IE8 polyfill note in docs --- documentation/sections/es2015plus_output.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation/sections/es2015plus_output.md b/documentation/sections/es2015plus_output.md index b1d3d83f22..29a003f6ab 100644 --- a/documentation/sections/es2015plus_output.md +++ b/documentation/sections/es2015plus_output.md @@ -11,3 +11,5 @@ npm install --global coffeescript@next npm install --save-dev coffeescript@next babel-cli babel-preset-env coffee --print *.coffee | babel --presets env > app.js ``` + +Note that [babel-preset-env](https://babeljs.io/docs/plugins/preset-env/) doesn’t automatically supply polyfills for your code. CoffeeScript itself will output [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) if you use the `in` operator, or destructuring or spread/rest syntax; and [`Function.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) if you use a bound (`=>`) method in a class. Both are supported in Internet Explorer 9+ and all more recent browsers, but you will need to supply polyfills if you need to support Internet Explorer 8 or below and are using features that would cause these methods to be output, or in your own code are using similarly modern methods. One option is [`babel-polyfill`](https://babeljs.io/docs/usage/polyfill/), though there are many [other](https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423) [strategies](https://philipwalton.com/articles/loading-polyfills-only-when-needed/).