diff --git a/packages/babel-core/src/config/validation/options.js b/packages/babel-core/src/config/validation/options.js index 507b183fa07a..e2c3bfd2dafb 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([ "mutableTemplateObject", "newableArrowFunctions", + "setClassMethods", "setPublicClassFields", ]); diff --git a/packages/babel-plugin-transform-classes/src/index.js b/packages/babel-plugin-transform-classes/src/index.js index 8f0ecfc202ca..5fbd90f82a32 100644 --- a/packages/babel-plugin-transform-classes/src/index.js +++ b/packages/babel-plugin-transform-classes/src/index.js @@ -21,6 +21,8 @@ export default declare((api, options) => { const { loose } = options; + const setClassMethods = options.loose || api.assumption("setClassMethods"); + // todo: investigate traversal requeueing const VISITED = Symbol(); @@ -58,7 +60,9 @@ export default declare((api, options) => { node[VISITED] = true; path.replaceWith( - transformClass(path, state.file, builtinClasses, loose), + transformClass(path, state.file, builtinClasses, loose, { + setClassMethods, + }), ); if (path.isCallExpression()) { diff --git a/packages/babel-plugin-transform-classes/src/transformClass.js b/packages/babel-plugin-transform-classes/src/transformClass.js index 5b8f5f5171b1..00096aeac65e 100644 --- a/packages/babel-plugin-transform-classes/src/transformClass.js +++ b/packages/babel-plugin-transform-classes/src/transformClass.js @@ -12,6 +12,8 @@ import addCreateSuperHelper from "./inline-createSuper-helpers"; type ReadonlySet = Set | { has(val: T): boolean }; +type ClassAssumptions = { setClassMethods: boolean }; + function buildConstructor(classRef, constructorBody, node) { const func = t.functionDeclaration( t.cloneNode(classRef), @@ -27,6 +29,7 @@ export default function transformClass( file: any, builtinClasses: ReadonlySet, isLoose: boolean, + assumptions: ClassAssumptions, ) { const classState = { parent: undefined, @@ -431,7 +434,7 @@ export default function transformClass( } function processMethod(node, scope) { - if (classState.isLoose && !node.decorators) { + if (assumptions.setClassMethods && !node.decorators) { // use assignments instead of define properties for loose classes let { classRef } = classState; if (!node.static) { diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/input.js new file mode 100644 index 000000000000..e3ad20145b86 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/input.js @@ -0,0 +1,5 @@ +class Foo { + "bar"() { + + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/output.js new file mode 100644 index 000000000000..610fbb5a157e --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/output.js @@ -0,0 +1,13 @@ +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + var _proto = Foo.prototype; + + _proto["bar"] = function bar() {}; + + return Foo; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/input.js new file mode 100644 index 000000000000..918e7469b6c7 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/input.js @@ -0,0 +1,6 @@ +// @flow +class C { + m(x: number): string { + return 'a'; + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/options.json new file mode 100644 index 000000000000..1f9617ec390b --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + "external-helpers", + "transform-function-name", + ["transform-classes", { "loose": true }], + "transform-spread", + "transform-block-scoping", + "syntax-flow" + ] +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/output.js new file mode 100644 index 000000000000..45403829143d --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/output.js @@ -0,0 +1,14 @@ +// @flow +var C = /*#__PURE__*/function () { + "use strict"; + + function C() {} + + var _proto = C.prototype; + + _proto.m = function m(x: number): string { + return 'a'; + }; + + return C; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/input.js new file mode 100644 index 000000000000..1c08a3644980 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/input.js @@ -0,0 +1,5 @@ +class Test { + a() {} + static b() {} + c() {} +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/output.js new file mode 100644 index 000000000000..844b0d7655e7 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/output.js @@ -0,0 +1,17 @@ +var Test = /*#__PURE__*/function () { + "use strict"; + + function Test() { + babelHelpers.classCallCheck(this, Test); + } + + var _proto = Test.prototype; + + _proto.a = function a() {}; + + Test.b = function b() {}; + + _proto.c = function c() {}; + + return Test; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/options.json new file mode 100644 index 000000000000..62562eb645d7 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/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": { + "setClassMethods": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/input.js new file mode 100644 index 000000000000..4bbf0638b3be --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/input.js @@ -0,0 +1,7 @@ +"use strict"; + +class Foo { + method() { + + } +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/output.js new file mode 100644 index 000000000000..96acb356c59a --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/output.js @@ -0,0 +1,13 @@ +"use strict"; + +var Foo = /*#__PURE__*/function () { + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + var _proto = Foo.prototype; + + _proto.method = function method() {}; + + return Foo; +}();