From 5d71d1826f7315f588bd842c7007e9be632504f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sun, 31 Jan 2021 00:57:58 +0100 Subject: [PATCH 1/5] Implement `constantSuper` assumption --- .../src/config/validation/options.js | 1 + .../src/fields.js | 14 ++++++--- .../src/index.js | 3 +- .../babel-helper-replace-supers/src/index.js | 11 ++++--- .../assumption-constantSuper/options.json | 17 +++++++++++ .../private-method-super/input.js | 19 ++++++++++++ .../private-method-super/output.js | 29 ++++++++++++++++++ .../src/index.js | 2 ++ .../src/transformClass.js | 4 +-- .../accessing-super-class/input.js | 13 ++++++++ .../accessing-super-class/output.js | 30 +++++++++++++++++++ .../accessing-super-properties/input.js | 7 +++++ .../accessing-super-properties/output.js | 19 ++++++++++++ .../input.js | 6 ++++ .../options.json | 10 +++++++ .../output.js | 17 +++++++++++ .../calling-super-properties/input.js | 11 +++++++ .../calling-super-properties/output.js | 28 +++++++++++++++++ .../default-super/input.js | 17 +++++++++++ .../default-super/output.js | 23 ++++++++++++++ .../assumption-constantSuper/options.json | 12 ++++++++ .../super-function-fallback/input.js | 5 ++++ .../super-function-fallback/output.js | 6 ++++ 23 files changed, 293 insertions(+), 11 deletions(-) create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js diff --git a/packages/babel-core/src/config/validation/options.js b/packages/babel-core/src/config/validation/options.js index cd61fc913782..3b11368e8db8 100644 --- a/packages/babel-core/src/config/validation/options.js +++ b/packages/babel-core/src/config/validation/options.js @@ -334,6 +334,7 @@ export type NestingPath = RootPath | OverridesPath | EnvPath; export const assumptionsNames = new Set([ "arrayLikeIsIterable", "constantReexports", + "constantSuper", "enumerableModuleMeta", "ignoreFunctionLength", "ignoreToPrimitiveHint", diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 81cfcb6e2efc..c257630f98c3 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -647,12 +647,12 @@ const thisContextVisitor = traverse.visitors.merge([ environmentVisitor, ]); -function replaceThisContext(path, ref, superRef, file, loose) { +function replaceThisContext(path, ref, superRef, file, constantSuper) { const state = { classRef: ref, needsClassRef: false }; const replacer = new ReplaceSupers({ methodPath: path, - isLoose: loose, + constantSuper: constantSuper, superRef, file, refToPreserve: ref, @@ -678,7 +678,7 @@ export function buildFieldsInitNodes( state, setPublicClassFields, privateFieldsAsProperties, - loose, + constantSuper, ) { const staticNodes = []; const instanceNodes = []; @@ -695,7 +695,13 @@ export function buildFieldsInitNodes( const isMethod = !isField; if (isStatic || (isMethod && isPrivate)) { - const replaced = replaceThisContext(prop, ref, superRef, state, loose); + const replaced = replaceThisContext( + prop, + ref, + superRef, + state, + constantSuper, + ); needsClassRef = needsClassRef || replaced; } diff --git a/packages/babel-helper-create-class-features-plugin/src/index.js b/packages/babel-helper-create-class-features-plugin/src/index.js index ea33cd344777..7c2c097c485e 100644 --- a/packages/babel-helper-create-class-features-plugin/src/index.js +++ b/packages/babel-helper-create-class-features-plugin/src/index.js @@ -41,6 +41,7 @@ export function createClassFeaturePlugin({ }) { const setPublicClassFields = api.assumption("setPublicClassFields"); const privateFieldsAsProperties = api.assumption("privateFieldsAsProperties"); + const constantSuper = api.assumption("constantSuper"); const noDocumentAll = api.assumption("noDocumentAll"); if (loose) { @@ -217,7 +218,7 @@ export function createClassFeaturePlugin({ state, setPublicClassFields ?? loose, privateFieldsAsProperties ?? loose, - loose, + constantSuper ?? loose, )); } diff --git a/packages/babel-helper-replace-supers/src/index.js b/packages/babel-helper-replace-supers/src/index.js index 248d44f9637e..7ae8b2799333 100644 --- a/packages/babel-helper-replace-supers/src/index.js +++ b/packages/babel-helper-replace-supers/src/index.js @@ -255,7 +255,7 @@ const looseHandlers = { type ReplaceSupersOptionsBase = {| methodPath: NodePath, superRef: Object, - isLoose: boolean, + constantSuper: boolean, file: any, // objectRef might have been shadowed in child scopes, // in that case, we need to rename related variables. @@ -284,13 +284,16 @@ export default class ReplaceSupers { this.file = opts.file; this.superRef = opts.superRef; - this.isLoose = opts.isLoose; + this.constantSuper = process.env.BABEL_8_BREAKING + ? opts.constantSuper + : // Fallback to isLoose for backward compatibility + opts.constantSuper ?? (opts: any).isLoose; this.opts = opts; } declare file: HubInterface; declare isDerivedConstructor: boolean; - declare isLoose: boolean; + declare constantSuper: boolean; declare isPrivateMethod: boolean; declare isStatic: boolean; declare methodPath: NodePath; @@ -309,7 +312,7 @@ export default class ReplaceSupers { }); } - const handler = this.isLoose ? looseHandlers : specHandlers; + const handler = this.constantSuper ? looseHandlers : specHandlers; memberExpressionToFunctions(this.methodPath, visitor, { file: this.file, diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json new file mode 100644 index 000000000000..4ada272a1b6b --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json @@ -0,0 +1,17 @@ +{ + "plugins": [ + [ + "external-helpers", + { + "helperVersion": "7.1000.0" + } + ], + "proposal-private-methods", + "proposal-class-properties", + "transform-block-scoping", + "syntax-class-properties" + ], + "assumptions": { + "constantSuper": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js new file mode 100644 index 000000000000..d85e01133ac1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js @@ -0,0 +1,19 @@ +class Base { + superMethod() { + return 'good'; + } +} + +class Sub extends Base { + superMethod() { + return 'bad'; + } + + #privateMethod() { + return super.superMethod(); + } + + publicMethod() { + return this.#privateMethod(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js new file mode 100644 index 000000000000..6c26d54af7c3 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js @@ -0,0 +1,29 @@ +class Base { + superMethod() { + return 'good'; + } + +} + +var _privateMethod = new WeakSet(); + +class Sub extends Base { + constructor(...args) { + super(...args); + + _privateMethod.add(this); + } + + superMethod() { + return 'bad'; + } + + publicMethod() { + return babelHelpers.classPrivateMethodGet(this, _privateMethod, _privateMethod2).call(this); + } + +} + +var _privateMethod2 = function _privateMethod2() { + return Base.prototype.superMethod.call(this); +}; diff --git a/packages/babel-plugin-transform-classes/src/index.js b/packages/babel-plugin-transform-classes/src/index.js index c999abbe6fc0..744f31ff936d 100644 --- a/packages/babel-plugin-transform-classes/src/index.js +++ b/packages/babel-plugin-transform-classes/src/index.js @@ -22,6 +22,7 @@ export default declare((api, options) => { const { loose } = options; const setClassMethods = api.assumption("setClassMethods") ?? options.loose; + const constantSuper = api.assumption("constantSuper") ?? options.loose; // todo: investigate traversal requeueing const VISITED = Symbol(); @@ -62,6 +63,7 @@ export default declare((api, options) => { path.replaceWith( transformClass(path, state.file, builtinClasses, loose, { setClassMethods, + constantSuper, }), ); diff --git a/packages/babel-plugin-transform-classes/src/transformClass.js b/packages/babel-plugin-transform-classes/src/transformClass.js index 67df2ab0d56d..fe4cc5d62e0d 100644 --- a/packages/babel-plugin-transform-classes/src/transformClass.js +++ b/packages/babel-plugin-transform-classes/src/transformClass.js @@ -11,7 +11,7 @@ import addCreateSuperHelper from "./inline-createSuper-helpers"; type ReadonlySet = Set | { has(val: T): boolean }; -type ClassAssumptions = { setClassMethods: boolean }; +type ClassAssumptions = { setClassMethods: boolean, constantSuper: boolean }; function buildConstructor(classRef, constructorBody, node) { const func = t.functionDeclaration( @@ -164,7 +164,7 @@ export default function transformClass( methodPath: path, objectRef: classState.classRef, superRef: classState.superName, - isLoose: classState.isLoose, + constantSuper: assumptions.constantSuper, file: classState.file, refToPreserve: classState.classRef, }); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js new file mode 100644 index 000000000000..83f054a6e911 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js @@ -0,0 +1,13 @@ +class Test extends Foo { + constructor() { + woops.super.test(); + super(); + super.test(); + + super(...arguments); + super("test", ...arguments); + + super.test(...arguments); + super.test("test", ...arguments); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js new file mode 100644 index 000000000000..929c2c08fe95 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js @@ -0,0 +1,30 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + var _super = babelHelpers.createSuper(Test); + + function Test() { + var _Foo$prototype$test; + + var _this; + + babelHelpers.classCallCheck(this, Test); + woops.super.test(); + _this = _super.call(this); + + _Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this)); + + _this = _super.apply(this, arguments); + _this = _super.call.apply(_super, [this, "test"].concat(Array.prototype.slice.call(arguments))); + + _Foo.prototype.test.apply(babelHelpers.assertThisInitialized(_this), arguments); + + (_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [babelHelpers.assertThisInitialized(_this), "test"].concat(Array.prototype.slice.call(arguments))); + + return _this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js new file mode 100644 index 000000000000..fad2b31584ef --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js @@ -0,0 +1,7 @@ +class Test extends Foo { + constructor() { + super(); + super.test; + super.test.whatever; + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js new file mode 100644 index 000000000000..57ce4e416d44 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js @@ -0,0 +1,19 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + var _super = babelHelpers.createSuper(Test); + + function Test() { + var _this; + + babelHelpers.classCallCheck(this, Test); + _this = _super.call(this); + _Foo.prototype.test; + _Foo.prototype.test.whatever; + return _this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js new file mode 100644 index 000000000000..e0788b60b37f --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js @@ -0,0 +1,6 @@ +class Test extends Foo { + constructor() { + super.foo?.bar; + super.foo?.(); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json new file mode 100644 index 000000000000..d969db5fb34d --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + ["proposal-optional-chaining", { "loose": true }], + "transform-function-name", + ["transform-classes", { "loose": true }], + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ] +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js new file mode 100644 index 000000000000..d076ccfc9cce --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js @@ -0,0 +1,17 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inheritsLoose(Test, _Foo); + + function Test() { + var _Foo$prototype$foo, _Foo$prototype$foo2; + + var _this; + + (_Foo$prototype$foo = _Foo.prototype.foo) == null ? void 0 : _Foo$prototype$foo.bar; + (_Foo$prototype$foo2 = _Foo.prototype.foo) == null ? void 0 : _Foo$prototype$foo2.call(babelHelpers.assertThisInitialized(_this)); + return babelHelpers.assertThisInitialized(_this); + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js new file mode 100644 index 000000000000..0b392d3eb252 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js @@ -0,0 +1,11 @@ +class Test extends Foo { + constructor() { + super(); + super.test.whatever(); + super.test(); + } + + static test() { + return super.wow(); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js new file mode 100644 index 000000000000..d071019228d2 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js @@ -0,0 +1,28 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + var _super = babelHelpers.createSuper(Test); + + function Test() { + var _this; + + babelHelpers.classCallCheck(this, Test); + _this = _super.call(this); + + _Foo.prototype.test.whatever(); + + _Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this)); + + return _this; + } + + babelHelpers.createClass(Test, null, [{ + key: "test", + value: function test() { + return _Foo.wow.call(this); + } + }]); + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js new file mode 100644 index 000000000000..eaba10ab2bbd --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js @@ -0,0 +1,17 @@ +class Test { + constructor() { + return super.constructor; + } + + static test() { + return super.constructor; + } +} + +// Instances +expect(Object.getPrototypeOf(Test.prototype)).toBe(Object.prototype); +expect(new Test()).toBe(Object); + +// Static +expect(Object.getPrototypeOf(Test)).toBe(Function.prototype); +expect(Test.test()).toBe(Function); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js new file mode 100644 index 000000000000..56f85c05785c --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js @@ -0,0 +1,23 @@ +var Test = /*#__PURE__*/function () { + "use strict"; + + function Test() { + babelHelpers.classCallCheck(this, Test); + return Object.prototype.constructor; + } + + babelHelpers.createClass(Test, null, [{ + key: "test", + value: function test() { + return Function.prototype.constructor; + } + }]); + return Test; +}(); // Instances + + +expect(Object.getPrototypeOf(Test.prototype)).toBe(Object.prototype); +expect(new Test()).toBe(Object); // Static + +expect(Object.getPrototypeOf(Test)).toBe(Function.prototype); +expect(Test.test()).toBe(Function); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json new file mode 100644 index 000000000000..39e1d1bab810 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "constantSuper": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js new file mode 100644 index 000000000000..18ebeb8f3085 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js @@ -0,0 +1,5 @@ +class Test { + constructor() { + super.hasOwnProperty("test"); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js new file mode 100644 index 000000000000..f57c0d549409 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js @@ -0,0 +1,6 @@ +var Test = function Test() { + "use strict"; + + babelHelpers.classCallCheck(this, Test); + Object.prototype.hasOwnProperty.call(this, "test"); +}; From 3529d84358e0393b84a46f4ebd5042028c37679c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sun, 31 Jan 2021 01:14:58 +0100 Subject: [PATCH 2/5] Implement `superIsCallableConstructor` --- .../src/config/validation/options.js | 1 + .../src/index.js | 3 +++ .../src/transformClass.js | 10 +++++--- .../options.json | 12 +++++++++ .../super-class-id-member-expression/input.js | 7 ++++++ .../output.js | 25 +++++++++++++++++++ .../super-class-this-usage/input.js | 9 +++++++ .../super-class-this-usage/output.js | 17 +++++++++++++ .../super-class/input.js | 1 + .../super-class/output.js | 12 +++++++++ 10 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js diff --git a/packages/babel-core/src/config/validation/options.js b/packages/babel-core/src/config/validation/options.js index 3b11368e8db8..a431ba08ec7e 100644 --- a/packages/babel-core/src/config/validation/options.js +++ b/packages/babel-core/src/config/validation/options.js @@ -350,6 +350,7 @@ export const assumptionsNames = new Set([ "setPublicClassFields", "setSpreadProperties", "skipForOfIteratorClosing", + "superIsCallableConstructor", ]); function getSource(loc: NestingPath): OptionsSource { diff --git a/packages/babel-plugin-transform-classes/src/index.js b/packages/babel-plugin-transform-classes/src/index.js index 744f31ff936d..3f2819804289 100644 --- a/packages/babel-plugin-transform-classes/src/index.js +++ b/packages/babel-plugin-transform-classes/src/index.js @@ -23,6 +23,8 @@ export default declare((api, options) => { const setClassMethods = api.assumption("setClassMethods") ?? options.loose; const constantSuper = api.assumption("constantSuper") ?? options.loose; + const superIsCallableConstructor = + api.assumption("superIsCallableConstructor") ?? options.loose; // todo: investigate traversal requeueing const VISITED = Symbol(); @@ -64,6 +66,7 @@ export default declare((api, options) => { transformClass(path, state.file, builtinClasses, loose, { setClassMethods, constantSuper, + superIsCallableConstructor, }), ); diff --git a/packages/babel-plugin-transform-classes/src/transformClass.js b/packages/babel-plugin-transform-classes/src/transformClass.js index fe4cc5d62e0d..c1d7832e0407 100644 --- a/packages/babel-plugin-transform-classes/src/transformClass.js +++ b/packages/babel-plugin-transform-classes/src/transformClass.js @@ -11,7 +11,11 @@ import addCreateSuperHelper from "./inline-createSuper-helpers"; type ReadonlySet = Set | { has(val: T): boolean }; -type ClassAssumptions = { setClassMethods: boolean, constantSuper: boolean }; +type ClassAssumptions = { + setClassMethods: boolean, + constantSuper: boolean, + superIsCallableConstructor: boolean, +}; function buildConstructor(classRef, constructorBody, node) { const func = t.functionDeclaration( @@ -249,7 +253,7 @@ export default function transformClass( const bareSuperNode = bareSuper.node; let call; - if (classState.isLoose) { + if (assumptions.superIsCallableConstructor) { bareSuperNode.arguments.unshift(t.thisExpression()); if ( bareSuperNode.arguments.length === 2 && @@ -566,7 +570,7 @@ export default function transformClass( // Unshift to ensure that the constructor inheritance is set up before // any properties can be assigned to the prototype. - if (!classState.isLoose) { + if (!assumptions.superIsCallableConstructor) { classState.body.unshift( t.variableDeclaration("var", [ t.variableDeclarator( diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json new file mode 100644 index 000000000000..7002b66f731e --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "superIsCallableConstructor": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js new file mode 100644 index 000000000000..e245d3a69baa --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js @@ -0,0 +1,7 @@ +class BaseController extends Chaplin.Controller { + +} + +class BaseController2 extends Chaplin.Controller.Another { + +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js new file mode 100644 index 000000000000..1b4b3a994b0d --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js @@ -0,0 +1,25 @@ +var BaseController = /*#__PURE__*/function (_Chaplin$Controller) { + "use strict"; + + babelHelpers.inherits(BaseController, _Chaplin$Controller); + + function BaseController() { + babelHelpers.classCallCheck(this, BaseController); + return _Chaplin$Controller.apply(this, arguments) || this; + } + + return BaseController; +}(Chaplin.Controller); + +var BaseController2 = /*#__PURE__*/function (_Chaplin$Controller$A) { + "use strict"; + + babelHelpers.inherits(BaseController2, _Chaplin$Controller$A); + + function BaseController2() { + babelHelpers.classCallCheck(this, BaseController2); + return _Chaplin$Controller$A.apply(this, arguments) || this; + } + + return BaseController2; +}(Chaplin.Controller.Another); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js new file mode 100644 index 000000000000..f27cd5b8b449 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js @@ -0,0 +1,9 @@ +class Test extends Foo { + constructor() { + super(); + + this; + + this.prop = 1; + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js new file mode 100644 index 000000000000..f516eaf62a1f --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js @@ -0,0 +1,17 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + function Test() { + var _this; + + babelHelpers.classCallCheck(this, Test); + _this = _Foo.call(this) || this; + babelHelpers.assertThisInitialized(_this); + _this.prop = 1; + return _this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js new file mode 100644 index 000000000000..13a98b37be8b --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js @@ -0,0 +1 @@ +class Test extends Foo { } diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js new file mode 100644 index 000000000000..01c3014c0112 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js @@ -0,0 +1,12 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + function Test() { + babelHelpers.classCallCheck(this, Test); + return _Foo.apply(this, arguments) || this; + } + + return Test; +}(Foo); From 6ff97b56e3eea5d1222fe1bed3549a4b172945b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sun, 31 Jan 2021 01:19:10 +0100 Subject: [PATCH 3/5] Implement `noCallClass` assumption --- .../src/config/validation/options.js | 1 + .../src/index.js | 2 ++ .../src/transformClass.js | 3 ++- .../assumption-noCallClass/class/input.js | 1 + .../assumption-noCallClass/class/output.js | 3 +++ .../assumption-noCallClass/options.json | 12 +++++++++++ .../with-constructor/input.js | 11 ++++++++++ .../with-constructor/output.js | 19 ++++++++++++++++++ .../with-superClass/input.js | 8 ++++++++ .../with-superClass/output.js | 20 +++++++++++++++++++ 10 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.js create mode 100644 packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js diff --git a/packages/babel-core/src/config/validation/options.js b/packages/babel-core/src/config/validation/options.js index a431ba08ec7e..9ab61c278c32 100644 --- a/packages/babel-core/src/config/validation/options.js +++ b/packages/babel-core/src/config/validation/options.js @@ -340,6 +340,7 @@ export const assumptionsNames = new Set([ "ignoreToPrimitiveHint", "iterableIsArray", "mutableTemplateObject", + "noCallClass", "noDocumentAll", "noNewArrows", "objectRestNoSymbols", diff --git a/packages/babel-plugin-transform-classes/src/index.js b/packages/babel-plugin-transform-classes/src/index.js index 3f2819804289..fc08c9144966 100644 --- a/packages/babel-plugin-transform-classes/src/index.js +++ b/packages/babel-plugin-transform-classes/src/index.js @@ -25,6 +25,7 @@ export default declare((api, options) => { const constantSuper = api.assumption("constantSuper") ?? options.loose; const superIsCallableConstructor = api.assumption("superIsCallableConstructor") ?? options.loose; + const noCallClass = api.assumption("noCallClass") ?? options.loose; // todo: investigate traversal requeueing const VISITED = Symbol(); @@ -67,6 +68,7 @@ export default declare((api, options) => { setClassMethods, constantSuper, superIsCallableConstructor, + noCallClass, }), ); diff --git a/packages/babel-plugin-transform-classes/src/transformClass.js b/packages/babel-plugin-transform-classes/src/transformClass.js index c1d7832e0407..3088cd5f740e 100644 --- a/packages/babel-plugin-transform-classes/src/transformClass.js +++ b/packages/babel-plugin-transform-classes/src/transformClass.js @@ -15,6 +15,7 @@ type ClassAssumptions = { setClassMethods: boolean, constantSuper: boolean, superIsCallableConstructor: boolean, + noCallClass: boolean, }; function buildConstructor(classRef, constructorBody, node) { @@ -670,7 +671,7 @@ export default function transformClass( buildBody(); // make sure this class isn't directly called (with A() instead new A()) - if (!classState.isLoose) { + if (!assumptions.noCallClass) { constructorBody.body.unshift( t.expressionStatement( t.callExpression(classState.file.addHelper("classCallCheck"), [ diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js new file mode 100644 index 000000000000..a869c2849526 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js @@ -0,0 +1 @@ +class A {} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js new file mode 100644 index 000000000000..60718092a600 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js @@ -0,0 +1,3 @@ +var A = function A() { + "use strict"; +}; diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json new file mode 100644 index 000000000000..a84727399b4c --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "noCallClass": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js new file mode 100644 index 000000000000..9da66478b288 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js @@ -0,0 +1,11 @@ +class A { + constructor() { + console.log('a'); + } +} + +class B { + b() { + console.log('b'); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js new file mode 100644 index 000000000000..a9666614fef8 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js @@ -0,0 +1,19 @@ +var A = function A() { + "use strict"; + + console.log('a'); +}; + +var B = /*#__PURE__*/function () { + "use strict"; + + function B() {} + + babelHelpers.createClass(B, [{ + key: "b", + value: function b() { + console.log('b'); + } + }]); + return B; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.js new file mode 100644 index 000000000000..76bb1ebddfbf --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.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-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js new file mode 100644 index 000000000000..1d09fd08d8e6 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js @@ -0,0 +1,20 @@ +var B = function B() { + "use strict"; +}; + +var A = /*#__PURE__*/function (_B) { + "use strict"; + + babelHelpers.inherits(A, _B); + + var _super = babelHelpers.createSuper(A); + + function A(track) { + var _this; + + if (track !== undefined) _this = _super.call(this, track);else _this = _super.call(this); + return babelHelpers.possibleConstructorReturn(_this); + } + + return A; +}(B); From 7b32568661e97844df90ed49b4c5cd8cd0526f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 8 Feb 2021 19:53:05 +0100 Subject: [PATCH 4/5] noCallClass -> noClassCalls --- packages/babel-core/src/config/validation/options.js | 2 +- packages/babel-plugin-transform-classes/src/index.js | 4 ++-- packages/babel-plugin-transform-classes/src/transformClass.js | 4 ++-- .../test/fixtures/assumption-noCallClass/options.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/babel-core/src/config/validation/options.js b/packages/babel-core/src/config/validation/options.js index 9ab61c278c32..6289286e8ed5 100644 --- a/packages/babel-core/src/config/validation/options.js +++ b/packages/babel-core/src/config/validation/options.js @@ -340,7 +340,7 @@ export const assumptionsNames = new Set([ "ignoreToPrimitiveHint", "iterableIsArray", "mutableTemplateObject", - "noCallClass", + "noClassCalls", "noDocumentAll", "noNewArrows", "objectRestNoSymbols", diff --git a/packages/babel-plugin-transform-classes/src/index.js b/packages/babel-plugin-transform-classes/src/index.js index fc08c9144966..cceccf155e49 100644 --- a/packages/babel-plugin-transform-classes/src/index.js +++ b/packages/babel-plugin-transform-classes/src/index.js @@ -25,7 +25,7 @@ export default declare((api, options) => { const constantSuper = api.assumption("constantSuper") ?? options.loose; const superIsCallableConstructor = api.assumption("superIsCallableConstructor") ?? options.loose; - const noCallClass = api.assumption("noCallClass") ?? options.loose; + const noClassCalls = api.assumption("noClassCalls") ?? options.loose; // todo: investigate traversal requeueing const VISITED = Symbol(); @@ -68,7 +68,7 @@ export default declare((api, options) => { setClassMethods, constantSuper, superIsCallableConstructor, - noCallClass, + noClassCalls, }), ); diff --git a/packages/babel-plugin-transform-classes/src/transformClass.js b/packages/babel-plugin-transform-classes/src/transformClass.js index 3088cd5f740e..5244e6b64022 100644 --- a/packages/babel-plugin-transform-classes/src/transformClass.js +++ b/packages/babel-plugin-transform-classes/src/transformClass.js @@ -15,7 +15,7 @@ type ClassAssumptions = { setClassMethods: boolean, constantSuper: boolean, superIsCallableConstructor: boolean, - noCallClass: boolean, + noClassCalls: boolean, }; function buildConstructor(classRef, constructorBody, node) { @@ -671,7 +671,7 @@ export default function transformClass( buildBody(); // make sure this class isn't directly called (with A() instead new A()) - if (!assumptions.noCallClass) { + if (!assumptions.noClassCalls) { constructorBody.body.unshift( t.expressionStatement( t.callExpression(classState.file.addHelper("classCallCheck"), [ diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json index a84727399b4c..fe4fa1e68bec 100644 --- a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json @@ -7,6 +7,6 @@ "transform-block-scoping" ], "assumptions": { - "noCallClass": true + "noClassCalls": true } } From 41ea6999cf7651acec1401a0973ced53734ee767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Tue, 16 Feb 2021 23:18:32 +0100 Subject: [PATCH 5/5] Update packages/babel-helper-create-class-features-plugin/src/fields.js Co-authored-by: Justin Ridgewell --- .../babel-helper-create-class-features-plugin/src/fields.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index c257630f98c3..cf1071bff1a3 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -652,7 +652,7 @@ function replaceThisContext(path, ref, superRef, file, constantSuper) { const replacer = new ReplaceSupers({ methodPath: path, - constantSuper: constantSuper, + constantSuper, superRef, file, refToPreserve: ref,