diff --git a/crates/oxc_transformer/src/es2022/class_properties/class.rs b/crates/oxc_transformer/src/es2022/class_properties/class.rs index 24ae380de5a81..55dff5512283e 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/class.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/class.rs @@ -531,7 +531,10 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) { // Get value let value = match &mut prop.value { - Some(value) => ctx.ast.move_expression(value), + Some(value) => { + self.transform_instance_initializer(value, ctx); + ctx.ast.move_expression(value) + } None => ctx.ast.void_0(SPAN), }; diff --git a/crates/oxc_transformer/src/es2022/class_properties/instance_prop_init.rs b/crates/oxc_transformer/src/es2022/class_properties/instance_prop_init.rs new file mode 100644 index 0000000000000..adc4399d83303 --- /dev/null +++ b/crates/oxc_transformer/src/es2022/class_properties/instance_prop_init.rs @@ -0,0 +1,76 @@ +//! ES2022: Class Properties +//! Transform of instance property initializers. + +use std::cell::Cell; + +use oxc_ast::{ast::*, visit::VisitMut}; +use oxc_syntax::scope::{ScopeFlags, ScopeId}; +use oxc_traverse::TraverseCtx; + +use super::ClassProperties; + +impl<'a, 'ctx> ClassProperties<'a, 'ctx> { + /// Transform instance property initializer. + /// + /// Instance property initializers move from the class body into either class constructor, + /// or a `_super` function. Change parent scope of first-level scopes in initializer to reflect this. + pub(super) fn transform_instance_initializer( + &mut self, + value: &mut Expression<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + let mut updater = InstanceInitializerVisitor::new(self, ctx); + updater.visit_expression(value); + } +} + +/// Visitor to change parent scope of first-level scopes in instance property initializer. +struct InstanceInitializerVisitor<'a, 'v> { + /// Incremented when entering a scope, decremented when exiting it. + /// Parent `ScopeId` should be updated when `scope_depth == 0`. + scope_depth: u32, + /// Parent scope + parent_scope_id: ScopeId, + /// `TraverseCtx` object. + ctx: &'v mut TraverseCtx<'a>, +} + +impl<'a, 'v> InstanceInitializerVisitor<'a, 'v> { + fn new( + class_properties: &'v mut ClassProperties<'a, '_>, + ctx: &'v mut TraverseCtx<'a>, + ) -> Self { + let parent_scope_id = class_properties.instance_inits_scope_id; + Self { scope_depth: 0, parent_scope_id, ctx } + } +} + +impl<'a, 'v> VisitMut<'a> for InstanceInitializerVisitor<'a, 'v> { + /// Update parent scope for first level of scopes. + /// Convert scope to sloppy mode if `self.make_sloppy_mode == true`. + fn enter_scope(&mut self, _flags: ScopeFlags, scope_id: &Cell>) { + let scope_id = scope_id.get().unwrap(); + + // TODO: Not necessary to do this check for all scopes. + // In JS, only `Function`, `ArrowFunctionExpression` or `Class` can be the first-level scope, + // as all other types which have a scope are statements or `StaticBlock` which would need to be + // inside a function or class. But some TS types with scopes could be first level via + // e.g. `TaggedTemplateExpression::type_parameters`, which contains `TSType`. + // Not sure if that matters though, as they'll be stripped out anyway by TS transform. + if self.scope_depth == 0 { + self.reparent_scope(scope_id); + } + self.scope_depth += 1; + } + + fn leave_scope(&mut self) { + self.scope_depth -= 1; + } +} + +impl<'a, 'v> InstanceInitializerVisitor<'a, 'v> { + /// Update parent of scope to scope above class. + fn reparent_scope(&mut self, scope_id: ScopeId) { + self.ctx.scopes_mut().change_parent_id(scope_id, Some(self.parent_scope_id)); + } +} diff --git a/crates/oxc_transformer/src/es2022/class_properties/mod.rs b/crates/oxc_transformer/src/es2022/class_properties/mod.rs index 60bb2264fe1b3..ca2e661afded9 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/mod.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/mod.rs @@ -130,6 +130,7 @@ //! * `constructor.rs`: Insertion of property initializers into class constructor. //! * `private.rs`: Transform of private property usages (`this.#prop`). //! * `private_props.rs`: Structures storing details of private properties. +//! * `instance_prop_init.rs`: Transform of instance property initializers. //! * `static_prop_init.rs`: Transform of static property initializers. //! * `class_bindings.rs`: Structure containing bindings for class name and temp var. //! * `super.rs`: Transform `super` expressions. @@ -158,6 +159,7 @@ use crate::TransformCtx; mod class; mod class_bindings; mod constructor; +mod instance_prop_init; mod private; mod private_props; mod static_prop_init; diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index 7a72ff8d9fa86..feaa20d067656 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 564/927 +Passed: 578/927 # All Passed: * babel-plugin-transform-class-static-block @@ -276,7 +276,7 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-class-properties (178/264) +# babel-plugin-transform-class-properties (192/264) * assumption-constantSuper/complex-super-class/input.js x Output mismatch @@ -298,46 +298,6 @@ x Output mismatch * assumption-setPublicClassFields/constructor-collision/input.js x Output mismatch -* assumption-setPublicClassFields/foobar/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(2): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - -* assumption-setPublicClassFields/regression-T7364/input.mjs -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(7)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(7): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Scope children mismatch: -after transform: ScopeId(3): [ScopeId(4), ScopeId(8)] -rebuilt : ScopeId(4): [ScopeId(5)] -Scope children mismatch: -after transform: ScopeId(8): [] -rebuilt : ScopeId(5): [ScopeId(6)] -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(3)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Scope children mismatch: -after transform: ScopeId(5): [ScopeId(6), ScopeId(9)] -rebuilt : ScopeId(7): [ScopeId(8)] -Scope children mismatch: -after transform: ScopeId(9): [] -rebuilt : ScopeId(8): [ScopeId(9)] -Scope parent mismatch: -after transform: ScopeId(6): Some(ScopeId(5)) -rebuilt : ScopeId(9): Some(ScopeId(8)) - * assumption-setPublicClassFields/static-infer-name/input.js x Output mismatch @@ -378,17 +338,6 @@ x Output mismatch * nested-class/super-property-in-decorator/input.js x Output mismatch -* private/call/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)] -rebuilt : ScopeId(1): [ScopeId(2), ScopeId(4)] -Scope children mismatch: -after transform: ScopeId(4): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - * private/class-shadow-builtins/input.mjs x Output mismatch @@ -398,17 +347,6 @@ x Output mismatch * private/extracted-this/input.js x Output mismatch -* private/foobar/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(2): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - * private/nested-class-computed-redeclared/input.js x Output mismatch @@ -439,52 +377,12 @@ x Output mismatch * private/parenthesized-optional-member-call-with-transform/input.js x Output mismatch -* private/regression-T7364/input.mjs -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(7)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(7): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Scope children mismatch: -after transform: ScopeId(3): [ScopeId(4), ScopeId(8)] -rebuilt : ScopeId(4): [ScopeId(5)] -Scope children mismatch: -after transform: ScopeId(8): [] -rebuilt : ScopeId(5): [ScopeId(6)] -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(3)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Scope children mismatch: -after transform: ScopeId(5): [ScopeId(6), ScopeId(9)] -rebuilt : ScopeId(7): [ScopeId(8)] -Scope children mismatch: -after transform: ScopeId(9): [] -rebuilt : ScopeId(8): [ScopeId(9)] -Scope parent mismatch: -after transform: ScopeId(6): Some(ScopeId(5)) -rebuilt : ScopeId(9): Some(ScopeId(8)) - * private/static-infer-name/input.js x Output mismatch * private/static-shadow/input.js x Output mismatch -* private-loose/call/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)] -rebuilt : ScopeId(1): [ScopeId(2), ScopeId(4)] -Scope children mismatch: -after transform: ScopeId(4): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - * private-loose/class-shadow-builtins/input.mjs x Output mismatch @@ -494,17 +392,6 @@ x Output mismatch * private-loose/extracted-this/input.js x Output mismatch -* private-loose/foobar/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(2): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - * private-loose/nested-class-computed-redeclared/input.js x Output mismatch @@ -573,17 +460,6 @@ x Output mismatch * private-loose/static-infer-name/input.js x Output mismatch -* public/call/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)] -rebuilt : ScopeId(1): [ScopeId(2), ScopeId(4)] -Scope children mismatch: -after transform: ScopeId(4): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - * public/class-shadow-builtins/input.mjs x Output mismatch @@ -599,46 +475,6 @@ x Output mismatch * public/extracted-this/input.js x Output mismatch -* public/foobar/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(2): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - -* public/regression-T7364/input.mjs -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(7)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(7): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Scope children mismatch: -after transform: ScopeId(3): [ScopeId(4), ScopeId(8)] -rebuilt : ScopeId(4): [ScopeId(5)] -Scope children mismatch: -after transform: ScopeId(8): [] -rebuilt : ScopeId(5): [ScopeId(6)] -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(3)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Scope children mismatch: -after transform: ScopeId(5): [ScopeId(6), ScopeId(9)] -rebuilt : ScopeId(7): [ScopeId(8)] -Scope children mismatch: -after transform: ScopeId(9): [] -rebuilt : ScopeId(8): [ScopeId(9)] -Scope parent mismatch: -after transform: ScopeId(6): Some(ScopeId(5)) -rebuilt : ScopeId(9): Some(ScopeId(8)) - * public/static-infer-name/input.js x Output mismatch @@ -654,46 +490,6 @@ x Output mismatch * public-loose/constructor-collision/input.js x Output mismatch -* public-loose/foobar/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(2): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - -* public-loose/regression-T7364/input.mjs -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(7)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(7): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Scope children mismatch: -after transform: ScopeId(3): [ScopeId(4), ScopeId(8)] -rebuilt : ScopeId(4): [ScopeId(5)] -Scope children mismatch: -after transform: ScopeId(8): [] -rebuilt : ScopeId(5): [ScopeId(6)] -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(3)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Scope children mismatch: -after transform: ScopeId(5): [ScopeId(6), ScopeId(9)] -rebuilt : ScopeId(7): [ScopeId(8)] -Scope children mismatch: -after transform: ScopeId(9): [] -rebuilt : ScopeId(8): [ScopeId(9)] -Scope parent mismatch: -after transform: ScopeId(6): Some(ScopeId(5)) -rebuilt : ScopeId(9): Some(ScopeId(8)) - * public-loose/static-infer-name/input.js x Output mismatch @@ -706,17 +502,6 @@ x Output mismatch * regression/6153/input.js x Output mismatch -* regression/6154/input.js -Scope children mismatch: -after transform: ScopeId(3): [ScopeId(4), ScopeId(6)] -rebuilt : ScopeId(3): [ScopeId(4)] -Scope children mismatch: -after transform: ScopeId(6): [] -rebuilt : ScopeId(4): [ScopeId(5)] -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(3)) -rebuilt : ScopeId(5): Some(ScopeId(4)) - * regression/7951/input.mjs x Output mismatch @@ -734,35 +519,6 @@ Symbol scope ID mismatch for "_bar": after transform: SymbolId(3): ScopeId(2) rebuilt : SymbolId(3): ScopeId(0) -* regression/T7364/input.mjs -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(7)] -rebuilt : ScopeId(1): [ScopeId(2)] -Scope children mismatch: -after transform: ScopeId(7): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Scope children mismatch: -after transform: ScopeId(3): [ScopeId(4), ScopeId(8)] -rebuilt : ScopeId(4): [ScopeId(5)] -Scope children mismatch: -after transform: ScopeId(8): [] -rebuilt : ScopeId(5): [ScopeId(6)] -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(3)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Scope children mismatch: -after transform: ScopeId(5): [ScopeId(6), ScopeId(9)] -rebuilt : ScopeId(7): [ScopeId(8)] -Scope children mismatch: -after transform: ScopeId(9): [] -rebuilt : ScopeId(8): [ScopeId(9)] -Scope parent mismatch: -after transform: ScopeId(6): Some(ScopeId(5)) -rebuilt : ScopeId(9): Some(ScopeId(8)) - # babel-plugin-transform-nullish-coalescing-operator (5/12) * assumption-noDocumentAll/transform/input.js diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 387c20f4e124e..2612af6f909ad 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 107/121 +Passed: 108/121 # All Passed: * babel-plugin-transform-class-static-block @@ -16,18 +16,7 @@ Passed: 107/121 * regexp -# babel-plugin-transform-class-properties (8/11) -* private-loose-tagged-template/input.js -Scope children mismatch: -after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)] -rebuilt : ScopeId(1): [ScopeId(2), ScopeId(4)] -Scope children mismatch: -after transform: ScopeId(4): [] -rebuilt : ScopeId(2): [ScopeId(3)] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(1)) -rebuilt : ScopeId(3): Some(ScopeId(2)) - +# babel-plugin-transform-class-properties (9/11) * typescript/optional-call/input.ts Symbol reference IDs mismatch for "X": after transform: SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), ReferenceId(11), ReferenceId(16)]