diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index 3c5194ac11..705d607f45 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -377,6 +377,14 @@ helpers.inherits = template(` }) `); +helpers.inheritsLoose = template(` + (function (subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; + }) +`); + helpers.instanceof = template(` (function (left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { diff --git a/packages/babel-plugin-transform-es2015-classes/src/vanilla.js b/packages/babel-plugin-transform-es2015-classes/src/vanilla.js index 42d20bf368..52e5153e91 100644 --- a/packages/babel-plugin-transform-es2015-classes/src/vanilla.js +++ b/packages/babel-plugin-transform-es2015-classes/src/vanilla.js @@ -127,13 +127,15 @@ export default class ClassTransformer { // this.buildBody(); - // make sure this class isn't directly called - constructorBody.body.unshift(t.expressionStatement(t.callExpression( - file.addHelper("classCallCheck"), [ - t.thisExpression(), - this.classRef, - ] - ))); + // make sure this class isn't directly called (with A() instead new A()) + if (!this.isLoose) { + constructorBody.body.unshift(t.expressionStatement(t.callExpression( + file.addHelper("classCallCheck"), [ + t.thisExpression(), + this.classRef, + ] + ))); + } body = body.concat(this.staticPropBody.map((fn) => fn(this.classRef))); @@ -374,10 +376,16 @@ export default class ClassTransformer { ); } - let call = t.callExpression( - this.file.addHelper("possibleConstructorReturn"), - [t.thisExpression(), bareSuperNode] - ); + let call; + + if (this.isLoose) { + call = t.logicalExpression("||", bareSuperNode, t.thisExpression()); + } else { + call = t.callExpression( + this.file.addHelper("possibleConstructorReturn"), + [t.thisExpression(), bareSuperNode] + ); + } const bareSuperAfter = this.bareSuperAfter.map((fn) => fn(thisRef)); @@ -446,10 +454,18 @@ export default class ClassTransformer { thisPath.replaceWith(thisRef); } - const wrapReturn = (returnArg) => t.callExpression( - this.file.addHelper("possibleConstructorReturn"), - [thisRef].concat(returnArg || []) - ); + let wrapReturn; + + if (this.isLoose) { + wrapReturn = (returnArg) => { + return returnArg ? t.logicalExpression("||", returnArg, thisRef) : thisRef; + }; + } else { + wrapReturn = (returnArg) => t.callExpression( + this.file.addHelper("possibleConstructorReturn"), + [thisRef].concat(returnArg || []) + ); + } // if we have a return as the last node in the body then we've already caught that // return @@ -546,7 +562,7 @@ export default class ClassTransformer { // any properties can be assigned to the prototype. this.pushedInherits = true; this.body.unshift(t.expressionStatement(t.callExpression( - this.file.addHelper("inherits"), + this.isLoose ? this.file.addHelper("inheritsLoose") : this.file.addHelper("inherits"), [this.classRef, this.superName] ))); } diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/class/actual.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/class/actual.js new file mode 100644 index 0000000000..a869c28495 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/class/actual.js @@ -0,0 +1 @@ +class A {} diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/class/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/class/expected.js new file mode 100644 index 0000000000..8311a6c3db --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/class/expected.js @@ -0,0 +1 @@ +let A = function A() {}; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/options.json b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/options.json new file mode 100644 index 0000000000..cad18de53d --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["transform-es2015-classes", { + "loose": true + }] + ] +} diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-constructor/actual.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-constructor/actual.js new file mode 100644 index 0000000000..9da66478b2 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-constructor/actual.js @@ -0,0 +1,11 @@ +class A { + constructor() { + console.log('a'); + } +} + +class B { + b() { + console.log('b'); + } +} diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-constructor/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-constructor/expected.js new file mode 100644 index 0000000000..e0e9ee4b85 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-constructor/expected.js @@ -0,0 +1,13 @@ +let A = function A() { + console.log('a'); +}; + +let B = function () { + function B() {} + + B.prototype.b = function b() { + console.log('b'); + }; + + return B; +}(); \ No newline at end of file diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-superClass/actual.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-superClass/actual.js new file mode 100644 index 0000000000..76bb1ebddf --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-superClass/actual.js @@ -0,0 +1,8 @@ +class B {} + +class A extends B { + constructor(track) { + if (track !== undefined) super(track); + else super(); + } +} diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-superClass/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-superClass/expected.js new file mode 100644 index 0000000000..2ba8ea8a73 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose-classCallCheck/with-superClass/expected.js @@ -0,0 +1,18 @@ +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + +let B = function B() {}; + +let A = function (_B) { + _inheritsLoose(A, _B); + + function A(track) { + if (track !== undefined) { + var _this = _B.call(this, track) || this; + } else { + var _this = _B.call(this) || this; + } + return _this; + } + + return A; +}(B); diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-class/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-class/expected.js index f837c9c172..697df5c608 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-class/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-class/expected.js @@ -1,20 +1,18 @@ var Test = function (_Foo) { - babelHelpers.inherits(Test, _Foo); + babelHelpers.inheritsLoose(Test, _Foo); function Test() { var _Foo$prototype$test, _Foo$prototype$test2; - babelHelpers.classCallCheck(this, Test); - woops.super.test(); - var _this = babelHelpers.possibleConstructorReturn(this, _Foo.call(this)); + var _this = _Foo.call(this) || this; _Foo.prototype.test.call(_this); - var _this = babelHelpers.possibleConstructorReturn(this, _Foo.apply(this, arguments)); + var _this = _Foo.apply(this, arguments) || this; - var _this = babelHelpers.possibleConstructorReturn(this, _Foo.call.apply(_Foo, [this, "test"].concat(Array.prototype.slice.call(arguments)))); + var _this = _Foo.call.apply(_Foo, [this, "test"].concat(Array.prototype.slice.call(arguments))) || this; (_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [_this].concat(Array.prototype.slice.call(arguments))); (_Foo$prototype$test2 = _Foo.prototype.test).call.apply(_Foo$prototype$test2, [_this, "test"].concat(Array.prototype.slice.call(arguments))); diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-properties/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-properties/expected.js index b1da9bd99f..03969d0f8d 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-properties/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/accessing-super-properties/expected.js @@ -1,10 +1,8 @@ var Test = function (_Foo) { - babelHelpers.inherits(Test, _Foo); + babelHelpers.inheritsLoose(Test, _Foo); function Test() { - babelHelpers.classCallCheck(this, Test); - - var _this = babelHelpers.possibleConstructorReturn(this, _Foo.call(this)); + var _this = _Foo.call(this) || this; _Foo.prototype.test; _Foo.prototype.test.whatever; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/calling-super-properties/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/calling-super-properties/expected.js index 25bdf6a1c3..3ef936da91 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/calling-super-properties/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/calling-super-properties/expected.js @@ -1,10 +1,8 @@ var Test = function (_Foo) { - babelHelpers.inherits(Test, _Foo); + babelHelpers.inheritsLoose(Test, _Foo); function Test() { - babelHelpers.classCallCheck(this, Test); - - var _this = babelHelpers.possibleConstructorReturn(this, _Foo.call(this)); + var _this = _Foo.call(this) || this; _Foo.prototype.test.whatever(); _Foo.prototype.test.call(_this); diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/constructor-order/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/constructor-order/expected.js index 4ebd527994..be7df63f56 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/constructor-order/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/constructor-order/expected.js @@ -6,8 +6,6 @@ var x = function () { }; function x() { - babelHelpers.classCallCheck(this, x); - 4; 5; 6; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/literal-key/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/literal-key/expected.js index 9d78574423..126cb3ecde 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/literal-key/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/literal-key/expected.js @@ -1,7 +1,5 @@ var Foo = function () { - function Foo() { - babelHelpers.classCallCheck(this, Foo); - } + function Foo() {} Foo.prototype["bar"] = function bar() {}; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/method-return-type-annotation/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/method-return-type-annotation/expected.js index c426f3b6ac..513dccbcdf 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/method-return-type-annotation/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/method-return-type-annotation/expected.js @@ -1,8 +1,6 @@ // @flow var C = function () { - function C() { - babelHelpers.classCallCheck(this, C); - } + function C() {} C.prototype.m = function m(x: number): string { return 'a'; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/options.json b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/options.json index 5ba1a293bd..14e2e6ea02 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/options.json +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/options.json @@ -1,3 +1,9 @@ { - "plugins": ["external-helpers", "transform-es2015-function-name", ["transform-es2015-classes", { "loose": true }], "transform-es2015-spread", "transform-es2015-block-scoping"] + "plugins": [ + "external-helpers", + "transform-es2015-function-name", + ["transform-es2015-classes", { "loose": true }], + ["transform-es2015-spread", { "loose": true }], + "transform-es2015-block-scoping" + ] } diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class-id-member-expression/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class-id-member-expression/expected.js index e03b4f885c..fad14f464e 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class-id-member-expression/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class-id-member-expression/expected.js @@ -1,20 +1,18 @@ var BaseController = function (_Chaplin$Controller) { - babelHelpers.inherits(BaseController, _Chaplin$Controller); + babelHelpers.inheritsLoose(BaseController, _Chaplin$Controller); function BaseController() { - babelHelpers.classCallCheck(this, BaseController); - return babelHelpers.possibleConstructorReturn(this, _Chaplin$Controller.apply(this, arguments)); + return _Chaplin$Controller.apply(this, arguments) || this; } return BaseController; }(Chaplin.Controller); var BaseController2 = function (_Chaplin$Controller$A) { - babelHelpers.inherits(BaseController2, _Chaplin$Controller$A); + babelHelpers.inheritsLoose(BaseController2, _Chaplin$Controller$A); function BaseController2() { - babelHelpers.classCallCheck(this, BaseController2); - return babelHelpers.possibleConstructorReturn(this, _Chaplin$Controller$A.apply(this, arguments)); + return _Chaplin$Controller$A.apply(this, arguments) || this; } return BaseController2; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class/expected.js index dd6df765b8..d9e146771b 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-class/expected.js @@ -1,9 +1,8 @@ var Test = function (_Foo) { - babelHelpers.inherits(Test, _Foo); + babelHelpers.inheritsLoose(Test, _Foo); function Test() { - babelHelpers.classCallCheck(this, Test); - return babelHelpers.possibleConstructorReturn(this, _Foo.apply(this, arguments)); + return _Foo.apply(this, arguments) || this; } return Test; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-function-fallback/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-function-fallback/expected.js index 1f23d494a8..090bb67b1b 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-function-fallback/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/loose/super-function-fallback/expected.js @@ -1,5 +1,3 @@ var Test = function Test() { - babelHelpers.classCallCheck(this, Test); - Function.prototype.hasOwnProperty.call(this, "test"); }; diff --git a/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6755/expected.js b/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6755/expected.js index 3a32ac177a..74bafa673b 100644 --- a/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6755/expected.js +++ b/packages/babel-plugin-transform-es2015-classes/test/fixtures/regression/T6755/expected.js @@ -1,11 +1,7 @@ "use strict"; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var Example = function () { - function Example() { - _classCallCheck(this, Example); - } + function Example() {} Example.prototype.test1 = async function test1() { await Promise.resolve(2); diff --git a/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/transformed-class-method-loose-return-type-annotation/expected.js b/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/transformed-class-method-loose-return-type-annotation/expected.js index 5df0023a18..8fd3bee001 100644 --- a/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/transformed-class-method-loose-return-type-annotation/expected.js +++ b/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/transformed-class-method-loose-return-type-annotation/expected.js @@ -2,13 +2,11 @@ // @flow var C = function () { - function C() { - babelHelpers.classCallCheck(this, C); - } + function C() {} C.prototype.m = function m(x /*: number*/) /*: string*/ { return 'a'; }; return C; -}(); \ No newline at end of file +}(); diff --git a/packages/babel-plugin-transform-flow-strip-types/test/fixtures/regression/transformed-class-method-loose-return-type-annotation/expected.js b/packages/babel-plugin-transform-flow-strip-types/test/fixtures/regression/transformed-class-method-loose-return-type-annotation/expected.js index b12c969201..d3f42768b7 100644 --- a/packages/babel-plugin-transform-flow-strip-types/test/fixtures/regression/transformed-class-method-loose-return-type-annotation/expected.js +++ b/packages/babel-plugin-transform-flow-strip-types/test/fixtures/regression/transformed-class-method-loose-return-type-annotation/expected.js @@ -1,13 +1,11 @@ "use strict"; var C = function () { - function C() { - babelHelpers.classCallCheck(this, C); - } + function C() {} C.prototype.m = function m(x) { return 'a'; }; return C; -}(); \ No newline at end of file +}();