diff --git a/crates/oxc_transformer/src/common/arrow_function_converter.rs b/crates/oxc_transformer/src/common/arrow_function_converter.rs index 267f030b45ca3..82d89a97a0e23 100644 --- a/crates/oxc_transformer/src/common/arrow_function_converter.rs +++ b/crates/oxc_transformer/src/common/arrow_function_converter.rs @@ -1164,23 +1164,51 @@ impl<'a, 'v> ConstructorBodyThisAfterSuperInserter<'a, 'v> { } impl<'a> VisitMut<'a> for ConstructorBodyThisAfterSuperInserter<'a, '_> { - #[inline] // `#[inline]` because is a no-op - fn visit_class(&mut self, _class: &mut Class<'a>) { - // Do not need to insert in nested classes - - // TODO: Need to transform `super()` in: - // 1. Class `extends` clause. - // 2. Class property computed key - // 3. Class method computed key + fn visit_class(&mut self, class: &mut Class<'a>) { + // Only need to transform `super()` in: // - // So do need to visit class, but only the above parts. - // Stop traversal in `visit_property_definition`, `visit_accessor_property`, `visit_static_block` - // and `visit_function` instead of here. - // (the same places as `this_depth` is incremented in `StaticVisitor` in class properties transform). + // 1. Class decorators + // 2. Class `extends` clause + // 3. Class property decorators and computed key + // 4. Class method decorators and computed key + // 5. Class accessor decorators and computed key // - // https://babeljs.io/repl#?code_lz=MYGwhgzhAEDyCuAXApgJ2sgHigdgExgRVQGV4AHNaAbwChppgB7HCRVeYRJ1ACgEoa9Bo3BRoASRw4qWXAWgQKaAUJEiA2ksp9-AXWgBeaAEYA3MPVswiAJbBoW5boPGATBcubtK_auoAvl4M1nYOTjoCev5B6rEiIMiI0ABmOEbQkACeOA6qhgB80IgAFrYQFgxBQUA&presets=&externalPlugins=%40babel%2Fplugin-external-helpers%407.25.9%2C%40babel%2Fplugin-transform-async-to-generator%407.25.9&assumptions=%7B%7D - } + // Because the `super()` points to the parent class, not the current class. + + // `@(super()) class Inner {}` + // ^^^^^^^ + self.visit_decorators(&mut class.decorators); + + // `class Inner extends super() {}` + // ^^^^^^^ + if let Some(super_class) = &mut class.super_class { + self.visit_expression(super_class); + } + for element in &mut class.body.body { + match element { + // `class Inner { @(super()) [super()]() {} }` + // ^^^^^^^ ^^^^^^^ + ClassElement::MethodDefinition(method) if method.computed => { + self.visit_decorators(&mut method.decorators); + self.visit_property_key(&mut method.key); + } + // `class Inner { @(super()) [super()] = 123; }` + // ^^^^^^^ ^^^^^^^ + ClassElement::PropertyDefinition(prop) if prop.computed => { + self.visit_decorators(&mut prop.decorators); + self.visit_property_key(&mut prop.key); + } + // `class Inner { @(super()) accessor [super()] = 123; }` + // ^^^^^^^ ^^^^^^^ + ClassElement::AccessorProperty(prop) if prop.computed => { + self.visit_decorators(&mut prop.decorators); + self.visit_property_key(&mut prop.key); + } + _ => {} + } + } + } // TODO: Stop traversal at a `Function` too. `super()` can't appear in a nested function, // so no point traversing it. This is for performance, not correctness. diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 733f0b0ce6e79..52a39ff61c468 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 125/143 +Passed: 126/144 # All Passed: * babel-plugin-transform-class-static-block diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/outer-super-in-nested-class/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/outer-super-in-nested-class/input.js new file mode 100644 index 0000000000000..02540a0cf5bb6 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/outer-super-in-nested-class/input.js @@ -0,0 +1,12 @@ +class Outer extends OuterSuper { + constructor() { + class Inner extends super() { + [super()] = 1; + static [super()] = 2; + + [super()]() {} + static [super()]() {} + } + let fn = async () => this; + } +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/outer-super-in-nested-class/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/outer-super-in-nested-class/output.js new file mode 100644 index 0000000000000..de3461714b4a3 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/outer-super-in-nested-class/output.js @@ -0,0 +1,22 @@ +class Outer extends OuterSuper { + constructor() { + var _this; + + class Inner extends (super(), _this = this) { + [(super(), _this = this)] = 1; + static [(super(), _this = this)] = 2; + [(super(), _this = this)]() {} + static [(super(), _this = this)]() {} + } + + let fn = /*#__PURE__*/function () { + var _ref = babelHelpers.asyncToGenerator(function* () { + return _this; + }); + return function fn() { + return _ref.apply(this, arguments); + }; + }(); + + } +} \ No newline at end of file