From d17adf40dff114b0441511e2c1f37a7ef673e68c Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 6 Apr 2018 10:40:38 +0100 Subject: [PATCH] Use construct helper in New Spread (#7677) * Use construct helper in New Spread * CircleCI --- packages/babel-helpers/src/helpers.js | 12 +++-- .../fixtures/extend-builtins/loose/output.js | 2 +- .../fixtures/extend-builtins/spec/output.js | 2 +- .../src/index.js | 46 ++++++++----------- .../fixtures/spread/new-expression/output.js | 4 +- .../plugins-integration/issue-7527/output.js | 2 +- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index e15a0ec8f3..7cb3a88675 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -474,13 +474,17 @@ helpers.construct = () => template.program.ast` _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { - var Constructor, a = [null]; + var a = [null]; a.push.apply(a, args); - Constructor = Parent.bind.apply(Parent, a); - return setPrototypeOf(new Constructor, Class.prototype); + var Constructor = Parent.bind.apply(Parent, a); + var instance = new Constructor(); + if (Class) setPrototypeOf(instance, Class.prototype); + return instance; }; } - return _construct(Parent, args, Class); + // Avoid issues with Class being present but undefined when it wasn't + // present in the original call. + return _construct.apply(null, arguments); } `; diff --git a/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/loose/output.js b/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/loose/output.js index 21903aba61..409e1211ac 100644 --- a/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/loose/output.js +++ b/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/loose/output.js @@ -2,7 +2,7 @@ function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.crea function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() {} Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, _setPrototypeOf(function Super() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); }, Class)); }; return _wrapNativeSuper(Class); } -function _construct(Parent, args, Class) { if (typeof Reflect === "object" && Reflect.construct) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var Constructor, a = [null]; a.push.apply(a, args); Constructor = Parent.bind.apply(Parent, a); return _setPrototypeOf(new Constructor(), Class.prototype); }; } return _construct(Parent, args, Class); } +function _construct(Parent, args, Class) { if (typeof Reflect === "object" && Reflect.construct) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Parent.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } diff --git a/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/spec/output.js b/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/spec/output.js index bf7d7d16bd..df62b55860 100644 --- a/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/spec/output.js +++ b/packages/babel-plugin-transform-classes/test/fixtures/extend-builtins/spec/output.js @@ -8,7 +8,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() {} Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, _setPrototypeOf(function Super() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); }, Class)); }; return _wrapNativeSuper(Class); } -function _construct(Parent, args, Class) { if (typeof Reflect === "object" && Reflect.construct) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var Constructor, a = [null]; a.push.apply(a, args); Constructor = Parent.bind.apply(Parent, a); return _setPrototypeOf(new Constructor(), Class.prototype); }; } return _construct(Parent, args, Class); } +function _construct(Parent, args, Class) { if (typeof Reflect === "object" && Reflect.construct) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Parent.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } diff --git a/packages/babel-plugin-transform-spread/src/index.js b/packages/babel-plugin-transform-spread/src/index.js index 18f274474a..0a65a25016 100644 --- a/packages/babel-plugin-transform-spread/src/index.js +++ b/packages/babel-plugin-transform-spread/src/index.js @@ -49,12 +49,12 @@ export default declare((api, options) => { return { visitor: { - ArrayExpression(path, state) { + ArrayExpression(path) { const { node, scope } = path; const elements = node.elements; if (!hasSpread(elements)) return; - const nodes = build(elements, scope, state); + const nodes = build(elements, scope); const first = nodes.shift(); if (nodes.length === 0 && first !== elements[0].argument) { @@ -70,7 +70,7 @@ export default declare((api, options) => { ); }, - CallExpression(path, state) { + CallExpression(path) { const { node, scope } = path; const args = node.arguments; @@ -87,7 +87,7 @@ export default declare((api, options) => { if (args.length === 1 && args[0].argument.name === "arguments") { nodes = [args[0].argument]; } else { - nodes = build(args, scope, state); + nodes = build(args, scope); } const first = nodes.shift(); @@ -124,37 +124,29 @@ export default declare((api, options) => { node.arguments.unshift(t.cloneNode(contextLiteral)); }, - NewExpression(path, state) { + NewExpression(path) { const { node, scope } = path; let args = node.arguments; if (!hasSpread(args)) return; - const nodes = build(args, scope, state); + const nodes = build(args, scope); - const context = t.arrayExpression([t.nullLiteral()]); + const first = nodes.shift(); - args = t.callExpression( - t.memberExpression(context, t.identifier("concat")), - nodes, - ); + if (nodes.length) { + args = t.callExpression( + t.memberExpression(first, t.identifier("concat")), + nodes, + ); + } else { + args = first; + } path.replaceWith( - t.newExpression( - t.callExpression( - t.memberExpression( - t.memberExpression( - t.memberExpression( - t.identifier("Function"), - t.identifier("prototype"), - ), - t.identifier("bind"), - ), - t.identifier("apply"), - ), - [node.callee, args], - ), - [], - ), + t.callExpression(path.hub.file.addHelper("construct"), [ + node.callee, + args, + ]), ); }, }, diff --git a/packages/babel-plugin-transform-spread/test/fixtures/spread/new-expression/output.js b/packages/babel-plugin-transform-spread/test/fixtures/spread/new-expression/output.js index a1abd3d74d..34d55c27f0 100644 --- a/packages/babel-plugin-transform-spread/test/fixtures/spread/new-expression/output.js +++ b/packages/babel-plugin-transform-spread/test/fixtures/spread/new-expression/output.js @@ -1,2 +1,2 @@ -new (Function.prototype.bind.apply(Numbers, [null].concat(babelHelpers.toConsumableArray(nums))))(); -new (Function.prototype.bind.apply(Numbers, [null].concat([1], babelHelpers.toConsumableArray(nums))))(); +babelHelpers.construct(Numbers, babelHelpers.toConsumableArray(nums)); +babelHelpers.construct(Numbers, [1].concat(babelHelpers.toConsumableArray(nums))); diff --git a/packages/babel-preset-env/test/fixtures/plugins-integration/issue-7527/output.js b/packages/babel-preset-env/test/fixtures/plugins-integration/issue-7527/output.js index 3fe1fee5cc..7ef653ee76 100644 --- a/packages/babel-preset-env/test/fixtures/plugins-integration/issue-7527/output.js +++ b/packages/babel-preset-env/test/fixtures/plugins-integration/issue-7527/output.js @@ -12,7 +12,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() {} Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, _setPrototypeOf(function Super() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); }, Class)); }; return _wrapNativeSuper(Class); } -function _construct(Parent, args, Class) { if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && Reflect.construct) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var Constructor, a = [null]; a.push.apply(a, args); Constructor = Parent.bind.apply(Parent, a); return _setPrototypeOf(new Constructor(), Class.prototype); }; } return _construct(Parent, args, Class); } +function _construct(Parent, args, Class) { if ((typeof Reflect === "undefined" ? "undefined" : _typeof(Reflect)) === "object" && Reflect.construct) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Parent.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }