diff --git a/crates/oxc_transformer/src/common/helper_loader.rs b/crates/oxc_transformer/src/common/helper_loader.rs index 1468bc7435934b..60cc96d5b8303a 100644 --- a/crates/oxc_transformer/src/common/helper_loader.rs +++ b/crates/oxc_transformer/src/common/helper_loader.rs @@ -161,6 +161,8 @@ pub enum Helper { ClassPrivateFieldLooseBase, SuperPropGet, SuperPropSet, + ReadOnlyError, + WriteOnlyError, } impl Helper { @@ -187,6 +189,8 @@ impl Helper { Self::ClassPrivateFieldLooseBase => "classPrivateFieldLooseBase", Self::SuperPropGet => "superPropGet", Self::SuperPropSet => "superPropSet", + Self::ReadOnlyError => "readOnlyError", + Self::WriteOnlyError => "writeOnlyError", } } } diff --git a/crates/oxc_transformer/src/es2022/class_properties/class.rs b/crates/oxc_transformer/src/es2022/class_properties/class.rs index d6b823aeba7396..0d3f223ce025b3 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/class.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/class.rs @@ -1,6 +1,7 @@ //! ES2022: Class Properties //! Transform of class itself. +use indexmap::map::Entry; use oxc_allocator::{Address, GetAddress}; use oxc_ast::{ast::*, NONE}; use oxc_span::SPAN; @@ -93,7 +94,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let binding = ctx.generate_uid_in_current_hoist_scope(&ident.name); private_props.insert( ident.name.clone(), - PrivateProp::new(binding, prop.r#static, false, false), + PrivateProp::new(binding, prop.r#static, None, false), ); } @@ -135,10 +136,22 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ctx.current_block_scope_id(), SymbolFlags::FunctionScopedVariable, ); - private_props.insert( - ident.name.clone(), - PrivateProp::new(binding, method.r#static, true, false), - ); + + match private_props.entry(ident.name.clone()) { + Entry::Occupied(mut entry) => { + // If there's already a binding for this private property, + // it's a setter or getter, so store the binding in `binding2`. + entry.get_mut().set_binding2(binding); + } + Entry::Vacant(entry) => { + entry.insert(PrivateProp::new( + binding, + method.r#static, + Some(method.kind), + false, + )); + } + } } } ClassElement::AccessorProperty(prop) => { @@ -148,7 +161,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let dummy_binding = BoundIdentifier::new(Atom::empty(), SymbolId::new(0)); private_props.insert( ident.name.clone(), - PrivateProp::new(dummy_binding, prop.r#static, true, true), + PrivateProp::new(dummy_binding, prop.r#static, None, true), ); } } @@ -443,7 +456,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { self.ctx.statement_injector.insert_many_before( &stmt_address, private_props.iter().filter_map(|(name, prop)| { - if prop.is_method || prop.is_accessor { + if prop.is_method() || prop.is_accessor { return None; } @@ -459,10 +472,10 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { self.ctx.statement_injector.insert_many_before( &stmt_address, private_props.values().filter_map(|prop| { - if prop.is_static || (prop.is_method && has_method) || prop.is_accessor { + if prop.is_static || (prop.is_method() && has_method) || prop.is_accessor { return None; } - if prop.is_method { + if prop.is_method() { // `var _C_brand = new WeakSet();` has_method = true; let binding = class_details.bindings.brand(); @@ -583,7 +596,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { // TODO(improve-on-babel): Simplify this. if self.private_fields_as_properties { exprs.extend(private_props.iter().filter_map(|(name, prop)| { - if prop.is_method || prop.is_accessor { + if prop.is_method() || prop.is_accessor { return None; } @@ -598,7 +611,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let mut weakmap_symbol_id = None; let mut has_method = false; exprs.extend(private_props.values().filter_map(|prop| { - if prop.is_method || prop.is_accessor { + if prop.is_method() || prop.is_accessor { if prop.is_static || has_method { return None; } diff --git a/crates/oxc_transformer/src/es2022/class_properties/class_details.rs b/crates/oxc_transformer/src/es2022/class_properties/class_details.rs index 0289923c95e8ae..fca20cbf6c65de 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/class_details.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/class_details.rs @@ -40,18 +40,29 @@ impl<'a> ClassDetails<'a> { pub(super) struct PrivateProp<'a> { pub binding: BoundIdentifier<'a>, pub is_static: bool, - pub is_method: bool, + pub method_kind: Option, pub is_accessor: bool, + // For accessor methods, they have two bindings, + // one for getter and one for setter. + pub binding2: Option>, } impl<'a> PrivateProp<'a> { pub fn new( binding: BoundIdentifier<'a>, is_static: bool, - is_method: bool, + method_kind: Option, is_accessor: bool, ) -> Self { - Self { binding, is_static, is_method, is_accessor } + Self { binding, is_static, method_kind, is_accessor, binding2: None } + } + + pub fn is_method(&self) -> bool { + self.method_kind.is_some() + } + + pub fn set_binding2(&mut self, binding: BoundIdentifier<'a>) { + self.binding2 = Some(binding); } } @@ -101,31 +112,130 @@ impl<'a> ClassesStack<'a> { self.stack.last_mut() } - /// Lookup details of private property referred to by `ident`. - pub fn find_private_prop<'b>( + pub fn lookup_private_prop< + 'b, + Ret, + RetFn: Fn(&'b PrivateProp<'a>, &'b mut ClassBindings<'a>, bool) -> Ret, + >( &'b mut self, ident: &PrivateIdentifier<'a>, - ) -> ResolvedPrivateProp<'a, 'b> { + ret_fn: RetFn, + ) -> Ret { // Check for binding in closest class first, then enclosing classes. // We skip the first, because this is a `NonEmptyStack` with dummy first entry. // TODO: Check there are tests for bindings in enclosing classes. for class in self.stack[1..].iter_mut().rev() { if let Some(private_props) = &mut class.private_props { if let Some(prop) = private_props.get(&ident.name) { - return ResolvedPrivateProp { - prop_binding: &prop.binding, - class_bindings: &mut class.bindings, - is_static: prop.is_static, - is_method: prop.is_method, - is_accessor: prop.is_accessor, - is_declaration: class.is_declaration, - }; + return ret_fn(prop, &mut class.bindings, class.is_declaration); } } } - unreachable!(); } + + /// Lookup details of private property referred to by `ident`. + pub fn find_private_prop<'b>( + &'b mut self, + ident: &PrivateIdentifier<'a>, + is_assignment: bool, + ) -> ResolvedPrivateProp<'a, 'b> { + self.lookup_private_prop(ident, move |prop, class_bindings, is_declaration| { + let prop_binding = match (is_assignment, prop.method_kind) { + (false, Some(MethodDefinitionKind::Set)) + | (true, Some(MethodDefinitionKind::Get)) => { + if let Some(binding2) = &prop.binding2 { + binding2 + } else { + // TODO: Warn there is no setter method + &prop.binding + } + } + _ => &prop.binding, + }; + + ResolvedPrivateProp { + prop_binding, + class_bindings, + is_static: prop.is_static, + is_method: prop.method_kind.is_some(), + is_accessor: prop.is_accessor + || prop.method_kind.is_some_and(|kind| kind.is_accessor()), + is_declaration, + } + }) + } + + /// Lookup details of private property referred to by `ident`. + pub fn find_private_prop2<'b>( + &'b mut self, + ident: &PrivateIdentifier<'a>, + ) -> ResolvedPrivateProp2<'a, 'b> { + self.lookup_private_prop(ident, move |prop, class_bindings, is_declaration| { + let (get_binding, set_binding) = match prop.method_kind { + Some(MethodDefinitionKind::Set) => (prop.binding2.as_ref(), Some(&prop.binding)), + Some(_) => (Some(&prop.binding), prop.binding2.as_ref()), + _ => (Some(&prop.binding), Some(&prop.binding)), + }; + ResolvedPrivateProp2 { + set_binding, + get_binding, + class_bindings, + is_static: prop.is_static, + is_method: prop.method_kind.is_some(), + is_accessor: prop.is_accessor + || prop.method_kind.is_some_and(|kind| kind.is_accessor()), + is_declaration, + } + }) + } + + /// Lookup details of private property referred to by `ident`. + pub fn find_readable_private_prop<'b>( + &'b mut self, + ident: &PrivateIdentifier<'a>, + ) -> Option> { + self.lookup_private_prop(ident, move |prop, class_bindings, is_declaration| { + let prop_binding = if matches!(prop.method_kind, Some(MethodDefinitionKind::Set)) { + prop.binding2.as_ref() + } else { + Some(&prop.binding) + }; + prop_binding.map(|prop_binding| ResolvedPrivateProp { + prop_binding, + class_bindings, + is_static: prop.is_static, + is_method: prop.is_method(), + is_accessor: prop.is_accessor + || prop.method_kind.is_some_and(|kind| kind.is_accessor()), + is_declaration, + }) + }) + } + + /// Lookup details of private property referred to by `ident`. + pub fn find_writeable_private_prop<'b>( + &'b mut self, + ident: &PrivateIdentifier<'a>, + ) -> Option> { + self.lookup_private_prop(ident, move |prop, class_bindings, is_declaration| { + let prop_binding = if matches!(prop.method_kind, Some(MethodDefinitionKind::Set) | None) + { + Some(&prop.binding) + } else { + prop.binding2.as_ref() + }; + prop_binding.map(|prop_binding| ResolvedPrivateProp { + prop_binding, + class_bindings, + is_static: prop.is_static, + is_method: prop.is_method(), + is_accessor: prop.is_accessor + || prop.method_kind.is_some_and(|kind| kind.is_accessor()), + is_declaration, + }) + }) + } } /// Details of a private property resolved for a private field. @@ -138,9 +248,31 @@ pub(super) struct ResolvedPrivateProp<'a, 'b> { pub class_bindings: &'b mut ClassBindings<'a>, /// `true` if is a static property pub is_static: bool, - /// `true` if is a private method + /// `true` if is a private method or accessor property + pub is_method: bool, + /// `true` if is a private accessor property or [`PrivateProp::method_kind`] is + /// `Some(MethodDefinitionKind::Get)` or `Some(MethodDefinitionKind::Set)` + pub is_accessor: bool, + /// `true` if class which defines this property is a class declaration + pub is_declaration: bool, +} + +/// Details of a private property resolved for a private field. +/// +/// This is the return value of [`ClassesStack::find_private_prop`]. +pub(super) struct ResolvedPrivateProp2<'a, 'b> { + /// Binding for temp var representing the property or setter method + pub set_binding: Option<&'b BoundIdentifier<'a>>, + /// Binding for temp var representing the property or getter method + pub get_binding: Option<&'b BoundIdentifier<'a>>, + /// Bindings for class name and temp var for class + pub class_bindings: &'b mut ClassBindings<'a>, + /// `true` if is a static property + pub is_static: bool, + /// `true` if is a private method or accessor property pub is_method: bool, - /// `true` if is a private accessor property + /// `true` if is a private accessor property or [`PrivateProp::method_kind`] is + /// `Some(MethodDefinitionKind::Get)` or `Some(MethodDefinitionKind::Set)` pub is_accessor: bool, /// `true` if class which defines this property is a class declaration pub is_declaration: bool, diff --git a/crates/oxc_transformer/src/es2022/class_properties/private_field.rs b/crates/oxc_transformer/src/es2022/class_properties/private_field.rs index d96b28f3e9787a..bb2213c832fadc 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/private_field.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/private_field.rs @@ -3,6 +3,7 @@ use std::mem; +use oxc_allocator::{String as ArenaString, Vec as ArenaVec}; use oxc_ast::{ast::*, NONE}; use oxc_span::SPAN; use oxc_syntax::{reference::ReferenceId, symbol::SymbolId}; @@ -13,8 +14,9 @@ use oxc_traverse::{ use crate::{common::helper_loader::Helper, TransformCtx}; use super::{ + class_details::ResolvedPrivateProp2, utils::{ - create_assignment, create_underscore_ident_name, + create_assignment, create_bind_call, create_call_call, create_underscore_ident_name, debug_assert_expr_is_not_parenthesis_or_typescript_syntax, }, ClassProperties, ResolvedPrivateProp, @@ -26,6 +28,12 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { /// Not loose: /// * Instance prop: `object.#prop` -> `_classPrivateFieldGet2(_prop, object)` /// * Static prop: `object.#prop` -> `_assertClassBrand(Class, object, _prop)._` + /// * Instance method: `object.#method` -> `_assertClassBrand(_Class_brand, object, _prop)` + /// * Static method: `object.#method` -> `_assertClassBrand(Class, object, _prop)` + /// * Instance getter: `object.#getter` -> `get_getter.call(_assertClassBrand(_Class_brand, object))` + /// * Static getter: `object.#getter` -> `get_getter.call(_assertClassBrand(Class, object))` + /// * Instance setter: `object.#setter` -> `set_setter.bind(_assertClassBrand(_Class_brand, object))` + /// * Static setter: `object.#setter` -> `set_setter.bind(_assertClassBrand(Class, object))` /// /// Loose: `object.#prop` -> `_classPrivateFieldLooseBase(object, _prop)[_prop]` // @@ -37,12 +45,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ctx: &mut TraverseCtx<'a>, ) { let Expression::PrivateFieldExpression(field_expr) = expr else { unreachable!() }; - - if let Some(replacement) = - self.transform_private_field_expression_impl(field_expr, false, ctx) - { - *expr = replacement; - } + *expr = self.transform_private_field_expression_impl(field_expr, false, ctx); } fn transform_private_field_expression_impl( @@ -50,7 +53,34 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { field_expr: &mut PrivateFieldExpression<'a>, is_assignment: bool, ctx: &mut TraverseCtx<'a>, - ) -> Option> { + ) -> Expression<'a> { + let span = field_expr.span; + let object = ctx.ast.move_expression(&mut field_expr.object); + let resolved = if is_assignment { + if let Some(prop) = self.classes_stack.find_writeable_private_prop(&field_expr.field) { + prop + } else { + // Early return for read-only error + return self.create_sequence_with_read_only_error( + &field_expr.field.name, + object, + None, + span, + ctx, + ); + } + } else if let Some(prop) = self.classes_stack.find_readable_private_prop(&field_expr.field) + { + prop + } else { + return self.create_sequence_with_write_only_error( + &field_expr.field.name, + object, + span, + ctx, + ); + }; + let ResolvedPrivateProp { prop_binding, class_bindings, @@ -58,30 +88,22 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { is_method, is_accessor, is_declaration, - } = self.classes_stack.find_private_prop(&field_expr.field); - - let span = field_expr.span; - let object = ctx.ast.move_expression(&mut field_expr.object); + } = resolved; if self.private_fields_as_properties { // `_classPrivateFieldLooseBase(object, _prop)[_prop]` - return Some(Expression::from(Self::create_private_field_member_expr_loose( + return Expression::from(Self::create_private_field_member_expr_loose( object, prop_binding, span, self.ctx, ctx, - ))); + )); } let prop_ident = prop_binding.create_read_expression(ctx); - let replacement = if is_static { - if is_assignment && (is_method || is_accessor) { - // TODO: Handle assignment to static private method or static accessor - return None; - } - + if is_static { // TODO: Ensure there are tests for nested classes with references to private static props // of outer class inside inner class, to make sure we're getting the right `class_bindings`. @@ -92,19 +114,65 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { &object, ctx, ) { - // `_prop._` - ctx.symbols_mut().delete_resolved_reference(class_symbol_id, object_reference_id); - if is_method || is_accessor { - prop_ident + if is_method { + if is_accessor || is_assignment { + if is_assignment { + // `toSetter(_prop.bind(object), [])._` + let call = create_bind_call(prop_ident, object, span, ctx); + self.create_to_setter_without_arguments(call, span, ctx) + } else { + // `_prop.call(object)` + let arguments = ctx.ast.vec1(Argument::from(object)); + create_call_call(prop_ident, arguments, span, ctx) + } + } else { + ctx.symbols_mut() + .delete_resolved_reference(class_symbol_id, object_reference_id); + // `_prop` + prop_ident + } } else { + ctx.symbols_mut() + .delete_resolved_reference(class_symbol_id, object_reference_id); + // `_prop._` Self::create_underscore_member_expression(prop_ident, span, ctx) } } else { // `_assertClassBrand(Class, object, _prop)._` let class_binding = class_bindings.get_or_init_static_binding(ctx); let class_ident = class_binding.create_read_expression(ctx); - if is_method || is_accessor { - self.create_assert_class_brand(class_ident, object, prop_ident, span, ctx) + if is_method { + let prop_method = if is_accessor { + if is_assignment { + // `_prop.call(_assertClassBrand(Class, object))` + self.create_setter_with_assert_class_brand( + class_ident, + object, + prop_ident, + None, + SPAN, + ctx, + ) + } else { + // `_prop.bind(_assertClassBrand(Class, object))` + self.create_getter_with_assert_class_brand( + class_ident, + object, + prop_ident, + span, + ctx, + ) + } + } else { + self.create_assert_class_brand(class_ident, object, prop_ident, span, ctx) + }; + + if is_assignment { + // `toSetter(prop_method, [])._` + self.create_to_setter_without_arguments(prop_method, span, ctx) + } else { + prop_method + } } else { self.create_assert_class_brand_underscore( class_ident, @@ -115,22 +183,46 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) } } - } else if is_assignment { - if is_method || is_accessor { - // TODO: Handle assignment to private method or accessor - return None; + } else if is_method { + let brand_ident = class_bindings.brand().create_read_expression(ctx); + let prop_method = if is_accessor { + if is_assignment { + // `_prop.call(_assertClassBrand(_Class_brand, object))` + self.create_setter_with_assert_class_brand( + brand_ident, + object, + prop_ident, + None, + SPAN, + ctx, + ) + } else { + // `_prop.bind(_assertClassBrand(_Class_brand, object))` + self.create_getter_with_assert_class_brand( + brand_ident, + object, + prop_ident, + span, + ctx, + ) + } + } else { + // `_assertClassBrand(_Class_brand, object, _prop)` + self.create_assert_class_brand(brand_ident, object, prop_ident, span, ctx) + }; + if is_assignment { + // `_toSetter(prop_method, [])._` + self.create_to_setter_without_arguments(prop_method, span, ctx) + } else { + prop_method } + } else if is_assignment { // `_toSetter(_classPrivateFieldSet2, [_prop, object])._` - self.create_to_setter(prop_ident, object, span, ctx) - } else if is_method || is_accessor { - let brand_ident = class_bindings.brand().create_read_expression(ctx); - self.create_assert_class_brand(brand_ident, object, prop_ident, span, ctx) + self.create_to_setter_for_private_field_set(prop_ident, object, span, ctx) } else { // `_classPrivateFieldGet2(_prop, object)` self.create_private_field_get(prop_ident, object, span, ctx) - }; - - Some(replacement) + } } /// Check if can use shorter version of static private prop transform. @@ -171,6 +263,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { /// Not loose: /// * Instance prop: `object.#prop(arg)` -> `_classPrivateFieldGet2(_prop, object).call(object, arg)` /// * Static prop: `object.#prop(arg)` -> `_assertClassBrand(Class, object, _prop)._.call(object, arg)` + /// * Instance method: `object.#method(arg)` -> `_assertClassBrand(_Class_brand, object, _prop).call(object, arg)` + /// * Static method: `object.#method(arg)` -> `_assertClassBrand(Class, object, _prop).call(object, arg)` /// /// Loose: `object.#prop(arg)` -> `_classPrivateFieldLooseBase(object, _prop)[_prop](arg)` /// @@ -204,7 +298,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { if self.private_fields_as_properties { // `object.#prop(arg)` -> `_classPrivateFieldLooseBase(object, _prop)[_prop](arg)` let ResolvedPrivateProp { prop_binding, is_method, is_accessor, .. } = - self.classes_stack.find_private_prop(&field_expr.field); + self.classes_stack.find_private_prop(&field_expr.field, false); if is_method || is_accessor { return; @@ -281,7 +375,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { is_method, is_accessor, is_declaration, - } = self.classes_stack.find_private_prop(&field_expr.field); + } = self.classes_stack.find_private_prop(&field_expr.field, false); let span = field_expr.span; let prop_ident = prop_binding.create_read_expression(ctx); @@ -324,9 +418,20 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { // Make 2 copies of `object` let (object1, object2) = self.duplicate_object(object, ctx); - let assert_obj = if is_method || is_accessor { - // `_assertClassBrand(Class, object, _prop)._` - self.create_assert_class_brand(class_ident, object1, prop_ident, span, ctx) + let assert_obj = if is_method { + if is_accessor { + // `_prop.call(_assertClassBrand(_Class_brand, object))` + self.create_getter_with_assert_class_brand( + class_ident, + object1, + prop_ident, + span, + ctx, + ) + } else { + // `_assertClassBrand(Class, object, _prop)._` + self.create_assert_class_brand(class_ident, object1, prop_ident, span, ctx) + } } else { // `_assertClassBrand(Class, object, _prop)._` self.create_assert_class_brand_underscore( @@ -345,10 +450,22 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { // Make 2 copies of `object` let (object1, object2) = self.duplicate_object(object, ctx); - let callee = if is_method || is_accessor { + let callee = if is_method { // `(_Class_brand, this)` let brand_ident = self.current_class().bindings.brand().create_read_expression(ctx); - self.create_assert_class_brand(brand_ident, object1, prop_ident, span, ctx) + if is_accessor { + // `_prop.call(_assertClassBrand(_Class_brand, object))` + self.create_getter_with_assert_class_brand( + brand_ident, + object1, + prop_ident, + span, + ctx, + ) + } else { + // `_assertClassBrand(_Class_brand, object, _prop)` + self.create_assert_class_brand(brand_ident, object1, prop_ident, span, ctx) + } } else { // `_classPrivateFieldGet2(_prop, object)` self.create_private_field_get(prop_ident, object1, span, ctx) @@ -393,26 +510,26 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { unreachable!() }; - let ResolvedPrivateProp { - prop_binding, + let ResolvedPrivateProp2 { + get_binding, + set_binding, class_bindings, is_static, is_method, - is_accessor, is_declaration, - } = self.classes_stack.find_private_prop(&field_expr.field); - - if is_method || is_accessor { - return; - }; + .. + } = self.classes_stack.find_private_prop2(&field_expr.field); if self.private_fields_as_properties { + if is_method { + return; + }; // `object.#prop = value` -> `_classPrivateFieldLooseBase(object, _prop)[_prop] = value` // Same for all other assignment operators e.g. `+=`, `&&=`, `??=`. let object = ctx.ast.move_expression(&mut field_expr.object); let replacement = Self::create_private_field_member_expr_loose( object, - prop_binding, + get_binding.unwrap(), field_expr.span, self.ctx, ctx, @@ -421,14 +538,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { return; } - // Note: `transform_static_assignment_expression` and `transform_instance_assignment_expression` - // are marked `#[inline]`, so hopefully compiler will see these clones of `BoundIdentifier`s - // can be elided. - // Can't break this up into separate functions otherwise, as `&BoundIdentifier`s keep `&self` ref - // taken by `lookup_private_property` alive. - let prop_binding = prop_binding.clone(); - - if is_static { + if is_static && !is_method { // TODO: No temp var is required if able to use shortcut version, so want to skip calling // `class_bindings.get_or_init_temp_binding(ctx)` if shortcut can be used. // But can't pass `class_bindings` as a `&mut ClassBinding` into @@ -441,6 +551,9 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let class_binding = class_bindings.get_or_init_static_binding(ctx); let class_binding = class_binding.clone(); let class_symbol_id = class_bindings.name_symbol_id(); + // Clone as borrow restrictions + // Unwrap is safe because `is_method` is false, so static private prop is always have a `get_binding` + let prop_binding = get_binding.cloned().unwrap(); self.transform_static_assignment_expression( expr, @@ -450,8 +563,30 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { is_declaration, ctx, ); + } else if !is_method || !assign_expr.operator.is_assign() || set_binding.is_none() { + // Clone as borrow restrictions + let class_binding = is_method.then(|| { + if is_static { + class_bindings.get_or_init_static_binding(ctx).clone() + } else { + class_bindings.brand().clone() + } + }); + let get_binding = get_binding.cloned(); + let set_binding = set_binding.cloned(); + + self.transform_instance_assignment_expression( + expr, + get_binding.as_ref(), + set_binding.as_ref(), + class_binding.as_ref(), + ctx, + ); } else { - self.transform_instance_assignment_expression(expr, &prop_binding, ctx); + // `object.#setter = object.#setter2 = value` + // Leave this to `transform_assignment_target` to handle + // TODO: After we have alternative to `classPrivateSetter` helper, + // we can handle this here. } } @@ -472,7 +607,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { // `transform_assignment_expression` can be elided. #[inline] fn transform_static_assignment_expression( - &self, + &mut self, expr: &mut Expression<'a>, prop_binding: &BoundIdentifier<'a>, class_binding: &BoundIdentifier<'a>, @@ -639,7 +774,9 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { fn transform_instance_assignment_expression( &self, expr: &mut Expression<'a>, - prop_binding: &BoundIdentifier<'a>, + get_binding: Option<&BoundIdentifier<'a>>, + set_binding: Option<&BoundIdentifier<'a>>, + class_binding: Option<&BoundIdentifier<'a>>, ctx: &mut TraverseCtx<'a>, ) { let assign_expr = match ctx.ast.move_expression(expr) { @@ -647,46 +784,75 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { _ => unreachable!(), }; let AssignmentExpression { span, operator, right: value, left } = assign_expr; - let object = match left { - AssignmentTarget::PrivateFieldExpression(field_expr) => { - field_expr.unbox().object.into_inner_expression() - } - _ => unreachable!(), - }; - - let prop_ident = prop_binding.create_read_expression(ctx); + let AssignmentTarget::PrivateFieldExpression(field_expr) = left else { unreachable!() }; + let PrivateFieldExpression { field, object, .. } = field_expr.unbox(); if operator == AssignmentOperator::Assign { // `object.#prop = value` -> `_classPrivateFieldSet2(_prop, object, value)` - *expr = self.create_private_field_set(prop_ident, object, value, span, ctx); + *expr = self.create_private_setter( + &field.name, + class_binding, + set_binding, + object, + value, + span, + ctx, + ); } else { // Make 2 copies of `object` - let (object1, object2) = self.duplicate_object(object, ctx); - - let prop_ident2 = prop_binding.create_read_expression(ctx); + let (object1, object2) = self.duplicate_object(object.into_inner_expression(), ctx); if let Some(operator) = operator.to_binary_operator() { // `object.#prop += value` // -> `_classPrivateFieldSet2(_prop, object, _classPrivateFieldGet2(_prop, object) + value)` // `_classPrivateFieldGet2(_prop, object)` - let get_call = self.create_private_field_get(prop_ident, object2, SPAN, ctx); + let get_call = self.create_private_getter( + &field.name, + class_binding, + get_binding, + object2, + SPAN, + ctx, + ); // `_classPrivateFieldGet2(_prop, object) + value` let value = ctx.ast.expression_binary(SPAN, get_call, operator, value); // `_classPrivateFieldSet2(_prop, object, _classPrivateFieldGet2(_prop, object) + value)` - *expr = self.create_private_field_set(prop_ident2, object1, value, span, ctx); + *expr = self.create_private_setter( + &field.name, + class_binding, + set_binding, + object1, + value, + span, + ctx, + ); } else if let Some(operator) = operator.to_logical_operator() { // `object.#prop &&= value` // -> `_classPrivateFieldGet2(_prop, object) && _classPrivateFieldSet2(_prop, object, value)` // `_classPrivateFieldGet2(_prop, object)` - let get_call = self.create_private_field_get(prop_ident, object1, SPAN, ctx); + let get_call = self.create_private_getter( + &field.name, + class_binding, + get_binding, + object1, + SPAN, + ctx, + ); // `_classPrivateFieldSet2(_prop, object, value)` - let set_call = - self.create_private_field_set(prop_ident2, object2, value, SPAN, ctx); + let set_call = self.create_private_setter( + &field.name, + class_binding, + set_binding, + object2, + value, + SPAN, + ctx, + ); // `_classPrivateFieldGet2(_prop, object) && _classPrivateFieldSet2(_prop, object, value)` *expr = ctx.ast.expression_logical(span, get_call, operator, set_call); } else { @@ -782,25 +948,25 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { _ => unreachable!(), }; - let ResolvedPrivateProp { - prop_binding, + let ResolvedPrivateProp2 { + get_binding, + set_binding, class_bindings, is_static, is_method, is_accessor, is_declaration, - } = self.classes_stack.find_private_prop(&field_expr.field); - - if is_method || is_accessor { - return; - }; + } = self.classes_stack.find_private_prop2(&field_expr.field); if self.private_fields_as_properties { + if is_method || is_accessor { + return; + }; // `object.#prop++` -> `_classPrivateFieldLooseBase(object, _prop)[_prop]++` let object = ctx.ast.move_expression(&mut field_expr.object); let replacement = Self::create_private_field_member_expr_loose( object, - prop_binding, + get_binding.unwrap(), field_expr.span, self.ctx, ctx, @@ -809,16 +975,17 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { return; } - let prop_ident = prop_binding.create_read_expression(ctx); - let prop_ident2 = prop_binding.create_read_expression(ctx); - let temp_var_name_base = get_var_name_from_node(field_expr); // TODO(improve-on-babel): Could avoid `move_expression` here and replace `update_expr.argument` instead. // Only doing this first to match the order Babel creates temp vars. let object = ctx.ast.move_expression(field_expr.object.get_inner_expression_mut()); - if is_static { + if is_static && !is_method { + // Unwrap as private prop always has set and get binding + let prop_binding = get_binding.unwrap(); + let prop_ident = prop_binding.create_read_expression(ctx); + let prop_ident2 = prop_binding.create_read_expression(ctx); // If `object` is reference to class name, and class is declaration, use shortcuts: // `++Class.#prop` -> `_prop._ = ((_Class$prop = _prop._), ++_Class$prop)` // `Class.#prop++` -> `_prop._ = (_Class$prop = _prop._, _Class$prop2 = _Class$prop++, _Class$prop), _Class$prop2` @@ -946,11 +1113,30 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ); } } else { + // Clone as borrow restrictions + let class_binding = is_method.then(|| { + if is_static { + class_bindings.get_or_init_static_binding(ctx).clone() + } else { + class_bindings.brand().clone() + } + }); + let get_binding = get_binding.cloned(); + let set_binding = set_binding.cloned(); + let private_name = field_expr.field.name.clone(); + // Make 2 copies of `object` let (object1, object2) = self.duplicate_object(object, ctx); // `_classPrivateFieldGet(_prop, object)` - let get_call = self.create_private_field_get(prop_ident, object2, SPAN, ctx); + let get_call = self.create_private_getter( + &private_name, + class_binding.as_ref(), + get_binding.as_ref(), + object2, + SPAN, + ctx, + ); // `_object$prop = _classPrivateFieldGet(_prop, object)` let temp_binding = self.ctx.var_declarations.create_uid_var(&temp_var_name_base, ctx); @@ -969,7 +1155,15 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { .ast .expression_sequence(SPAN, ctx.ast.vec_from_array([assignment, update_expr])); // `_classPrivateFieldSet(_prop, object, )` - *expr = self.create_private_field_set(prop_ident2, object1, value, span, ctx); + *expr = self.create_private_setter( + &private_name, + class_binding.as_ref(), + set_binding.as_ref(), + object1, + value, + span, + ctx, + ); } else { // Source = `object.#prop++` (postfix `++`) // `_object$prop2 = _object$prop++` @@ -987,9 +1181,17 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ]), ); + let set_binding = set_binding.clone(); // `_classPrivateFieldSet(_prop, object, )` - let set_call = - self.create_private_field_set(prop_ident2, object1, value, span, ctx); + let set_call = self.create_private_setter( + &private_name, + class_binding.as_ref(), + set_binding.as_ref(), + object1, + value, + span, + ctx, + ); // `(_classPrivateFieldSet(_prop, object, ), _object$prop2)` // TODO(improve-on-babel): Final `_object$prop2` is only needed if this expression // is consumed (i.e. not in an `ExpressionStatement`) @@ -1584,7 +1786,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { // ``` // But this is not needed, so we omit it. let ResolvedPrivateProp { prop_binding, is_method, is_accessor, .. } = - self.classes_stack.find_private_prop(&field_expr.field); + self.classes_stack.find_private_prop(&field_expr.field, false); if is_method || is_accessor { return None; @@ -1658,11 +1860,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let AssignmentTarget::PrivateFieldExpression(private_field) = target else { unreachable!() }; - if let Some(replacement) = - self.transform_private_field_expression_impl(private_field, true, ctx) - { - *target = AssignmentTarget::from(replacement.into_member_expression()); - } + let replacement = self.transform_private_field_expression_impl(private_field, true, ctx); + *target = AssignmentTarget::from(replacement.into_member_expression()); } /// Duplicate object to be used in get/set pair. @@ -1768,28 +1967,47 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) } - /// `_toSetter(_classPrivateFieldSet2, [_prop, object])._` + /// `_toSetter(func, func_arguments)._` fn create_to_setter( + &self, + func: Expression<'a>, + func_arguments: ArenaVec<'a, ArrayExpressionElement<'a>>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let func_arguments = ctx.ast.expression_array(span, func_arguments, None); + let arguments = + ctx.ast.vec_from_array([Argument::from(func), Argument::from(func_arguments)]); + let call = self.ctx.helper_call_expr(Helper::ToSetter, span, arguments, ctx); + Self::create_underscore_member_expression(call, span, ctx) + } + + /// `_toSetter(func)._` + fn create_to_setter_without_arguments( + &self, + func: Expression<'a>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let arguments = ctx.ast.vec_from_array([Argument::from(func)]); + let call = self.ctx.helper_call_expr(Helper::ToSetter, span, arguments, ctx); + Self::create_underscore_member_expression(call, span, ctx) + } + + /// `_toSetter(_classPrivateFieldSet2, [_prop, object])._` + fn create_to_setter_for_private_field_set( &self, prop_ident: Expression<'a>, object: Expression<'a>, span: Span, ctx: &mut TraverseCtx<'a>, ) -> Expression<'a> { - let arguments = ctx.ast.expression_array( - SPAN, - ctx.ast.vec_from_array([ - ArrayExpressionElement::from(prop_ident), - ArrayExpressionElement::from(object), - ]), - None, - ); let arguments = ctx.ast.vec_from_array([ - Argument::from(self.ctx.helper_load(Helper::ClassPrivateFieldSet2, ctx)), - Argument::from(arguments), + ArrayExpressionElement::from(prop_ident), + ArrayExpressionElement::from(object), ]); - let call = self.ctx.helper_call_expr(Helper::ToSetter, span, arguments, ctx); - Self::create_underscore_member_expression(call, span, ctx) + let helper = self.ctx.helper_load(Helper::ClassPrivateFieldSet2, ctx); + self.create_to_setter(helper, arguments, span, ctx) } /// `_assertClassBrand(Class, object, value)` or `_assertClassBrand(Class, object, _prop)` @@ -1813,6 +2031,56 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) } + /// `_assertClassBrand(Class, object)` + fn create_assert_class_without_value( + &self, + class_ident: Expression<'a>, + object: Expression<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let arguments = + ctx.ast.vec_from_array([Argument::from(class_ident), Argument::from(object)]); + self.ctx.helper_call_expr(Helper::AssertClassBrand, SPAN, arguments, ctx) + } + + /// `_prop.call(_assertClassBrand(_Class, object))` + fn create_getter_with_assert_class_brand( + &self, + class_ident: Expression<'a>, + object: Expression<'a>, + prop: Expression<'a>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let context = self.create_assert_class_without_value(class_ident, object, ctx); + let arguments = ctx.ast.vec1(Argument::from(context)); + create_call_call(prop, arguments, span, ctx) + } + + /// * Value: + /// `_prop.bind(_assertClassBrand(_Class, object))` + /// + /// * Without value: + /// `_prop.call(_assertClassBrand(_Class, object), value)` + fn create_setter_with_assert_class_brand( + &self, + class_ident: Expression<'a>, + object: Expression<'a>, + prop: Expression<'a>, + value: Option>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let context = self.create_assert_class_without_value(class_ident, object, ctx); + if let Some(value) = value { + let arguments = + ctx.ast.vec_from_array([Argument::from(context), Argument::from(value)]); + create_call_call(prop, arguments, span, ctx) + } else { + create_bind_call(prop, context, span, ctx) + } + } + /// `_assertClassBrand(Class, object, _prop)._` fn create_assert_class_brand_underscore( &self, @@ -1852,4 +2120,114 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) -> MemberExpression<'a> { ctx.ast.member_expression_static(span, object, create_underscore_ident_name(ctx), false) } + + /// * Getter: `_prop.call(_assertClassBrand(Class, object))` + /// * Prop: `_privateFieldGet(_prop, object)` + fn create_private_getter( + &self, + private_name: &str, + class_binding: Option<&BoundIdentifier<'a>>, + prop_binding: Option<&BoundIdentifier<'a>>, + object: Expression<'a>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let Some(prop_binding) = prop_binding else { + return self.create_sequence_with_write_only_error(private_name, object, span, ctx); + }; + let prop_ident = prop_binding.create_read_expression(ctx); + + if let Some(class_binding) = class_binding { + let class_ident = class_binding.create_read_expression(ctx); + self.create_getter_with_assert_class_brand(class_ident, object, prop_ident, span, ctx) + } else { + self.create_private_field_get(prop_ident, object, span, ctx) + } + } + + /// * Setter: `_prop.call(_assertClassBrand(Class, object), value)` + /// * Prop: `_privateFieldSet(_prop, object, value)` + #[allow(clippy::too_many_arguments)] + fn create_private_setter( + &self, + private_name: &str, + class_binding: Option<&BoundIdentifier<'a>>, + prop_binding: Option<&BoundIdentifier<'a>>, + object: Expression<'a>, + value: Expression<'a>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let Some(prop_binding) = prop_binding else { + return self.create_sequence_with_read_only_error( + private_name, + object, + Some(value), + span, + ctx, + ); + }; + let prop_ident = prop_binding.create_read_expression(ctx); + if let Some(class_binding) = class_binding { + let class_ident = class_binding.create_read_expression(ctx); + self.create_setter_with_assert_class_brand( + class_ident, + object, + prop_ident, + Some(value), + span, + ctx, + ) + } else { + self.create_private_field_set(prop_ident, object, value, span, ctx) + } + } + + fn create_throw_error( + &self, + helper: Helper, + private_name: &str, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let mut message = ArenaString::with_capacity_in(private_name.len() + 1, ctx.ast.allocator); + message.push('#'); + message.push_str(private_name); + let message = ctx.ast.expression_string_literal(SPAN, message.into_bump_str(), None); + self.ctx.helper_call_expr(helper, SPAN, ctx.ast.vec1(Argument::from(message)), ctx) + } + + fn create_sequence_with_read_only_error( + &self, + private_name: &str, + object: Expression<'a>, + value: Option>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let has_value = value.is_some(); + let error = self.create_throw_error(Helper::ReadOnlyError, private_name, ctx); + let expressions = if let Some(value) = value { + ctx.ast.vec_from_array([object, value, error]) + } else { + ctx.ast.vec_from_array([object, error]) + }; + let expr = ctx.ast.expression_sequence(span, expressions); + if has_value { + expr + } else { + Expression::from(Self::create_underscore_member_expr(expr, span, ctx)) + } + } + + fn create_sequence_with_write_only_error( + &self, + private_name: &str, + object: Expression<'a>, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let error = self.create_throw_error(Helper::WriteOnlyError, private_name, ctx); + let expressions = ctx.ast.vec_from_array([object, error]); + ctx.ast.expression_sequence(span, expressions) + } } diff --git a/crates/oxc_transformer/src/es2022/class_properties/private_method.rs b/crates/oxc_transformer/src/es2022/class_properties/private_method.rs index 3f7d78395fd644..2513af2055a8aa 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/private_method.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/private_method.rs @@ -40,13 +40,15 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { method: &mut MethodDefinition<'a>, ctx: &mut TraverseCtx<'a>, ) -> bool { - let PropertyKey::PrivateIdentifier(ident) = &method.key else { + let MethodDefinition { key, value, span, kind, r#static, .. } = method; + let PropertyKey::PrivateIdentifier(ident) = &key else { return false; }; - let mut function = ctx.ast.move_function(&mut method.value); + let mut function = ctx.ast.move_function(value); + let temp_binding = self.classes_stack.find_private_prop(ident, kind.is_set()).prop_binding; - let temp_binding = self.classes_stack.find_private_prop(ident).prop_binding; + function.span = *span; function.id = Some(temp_binding.create_binding_identifier(ctx)); function.r#type = FunctionType::FunctionDeclaration; @@ -55,11 +57,16 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let scope_id = function.scope_id(); let new_parent_id = ctx.current_scope_id(); ctx.scopes_mut().change_parent_id(scope_id, Some(new_parent_id)); - if !ctx.current_scope_flags().is_strict_mode() { - *ctx.scopes_mut().get_flags_mut(scope_id) -= ScopeFlags::StrictMode; + let is_strict_mode = ctx.current_scope_flags().is_strict_mode(); + let flags = ctx.scopes_mut().get_flags_mut(scope_id); + *flags -= ScopeFlags::GetAccessor | ScopeFlags::SetAccessor; + if !is_strict_mode { + // TODO: Needs to remove all child scopes' strict mode flag if child scope + // is inherited from this scope. + *flags -= ScopeFlags::StrictMode; } - PrivateMethodVisitor::new(method.r#static, self, ctx) + PrivateMethodVisitor::new(*r#static, self, ctx) .visit_function(&mut function, ScopeFlags::Function); let function = ctx.ast.alloc(function); diff --git a/crates/oxc_transformer/src/es2022/class_properties/utils.rs b/crates/oxc_transformer/src/es2022/class_properties/utils.rs index 55f2c0188c302d..21e862187a6828 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/utils.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/utils.rs @@ -3,7 +3,8 @@ use std::path::PathBuf; -use oxc_ast::ast::*; +use oxc_allocator::Vec as Arena; +use oxc_ast::{ast::*, NONE}; use oxc_span::SPAN; use oxc_syntax::reference::ReferenceFlags; use oxc_traverse::{BoundIdentifier, TraverseCtx}; @@ -81,3 +82,28 @@ pub(super) fn create_prototype_member<'a>( let static_member = ctx.ast.member_expression_static(SPAN, object, property, false); Expression::from(static_member) } + +/// `object` -> `object.bind(this)`. +pub(super) fn create_bind_call<'a>( + callee: Expression<'a>, + this: Expression<'a>, + span: Span, + ctx: &mut TraverseCtx<'a>, +) -> Expression<'a> { + let property = ctx.ast.identifier_name(SPAN, Atom::from("bind")); + let callee = Expression::from(ctx.ast.member_expression_static(SPAN, callee, property, false)); + let arguments = ctx.ast.vec1(Argument::from(this)); + ctx.ast.expression_call(span, callee, NONE, arguments, false) +} + +/// `object` -> `object.call(...arguments)`. +pub(super) fn create_call_call<'a>( + callee: Expression<'a>, + arguments: Arena<'a, Argument<'a>>, + span: Span, + ctx: &mut TraverseCtx<'a>, +) -> Expression<'a> { + let property = ctx.ast.identifier_name(SPAN, Atom::from("call")); + let callee = Expression::from(ctx.ast.member_expression_static(SPAN, callee, property, false)); + ctx.ast.expression_call(span, callee, NONE, arguments, false) +} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/class-binding/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/class-binding/output.js new file mode 100644 index 00000000000000..b60fc1cc02778a --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/class-binding/output.js @@ -0,0 +1,11 @@ +var _A; +var _A_brand = new WeakSet(); +class A { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _A_brand); + } +} +_A = A; +function _get_getA() { + return _A; +} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/destructuring/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/destructuring/output.js new file mode 100644 index 00000000000000..52ae57d2312e31 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/destructuring/output.js @@ -0,0 +1,12 @@ +var _A_brand = new WeakSet(); +class A { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _A_brand); + } + m() { + [babelHelpers.toSetter(_set_setter.bind(babelHelpers.assertClassBrand(_A_brand, this)))._] = [1]; + [(this, babelHelpers.readOnlyError("#getter"))._] = [1]; + } +} +function _set_setter(v) {} +function _get_getter() {} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/preserve-comments/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/preserve-comments/output.js new file mode 100644 index 00000000000000..51d2d41eb0ff88 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/preserve-comments/output.js @@ -0,0 +1,10 @@ +var _C_brand = new WeakSet(); +class C { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _C_brand); + } +} +function _get_a() { + return 42; +} +function _set_a(v) {} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/reassignment/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/reassignment/output.js new file mode 100644 index 00000000000000..6fcaf0c05b9e58 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/reassignment/output.js @@ -0,0 +1,15 @@ +let results = []; +var _Foo_brand = new WeakSet(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + this.self, results.push(2), babelHelpers.readOnlyError("#privateFieldValue"); + } + get self() { + results.push(1); + return this; + } +} +function _get_privateFieldValue() { + return 42; +} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/set-only-getter/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/set-only-getter/output.js new file mode 100644 index 00000000000000..111aea4ae384ef --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/set-only-getter/output.js @@ -0,0 +1,18 @@ +var _privateField = new WeakMap(); +var _Cl_brand = new WeakSet(); +class Cl { + get self() { + this.counter++; + return this; + } + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Cl_brand); + babelHelpers.classPrivateFieldInitSpec(this, _privateField, 0); + babelHelpers.defineProperty(this, "counter", 0); + this.self, 1([(this.self, babelHelpers.readOnlyError("#privateFieldValue"))._] = [1]), babelHelpers.readOnlyError("#privateFieldValue"); + } +} +function _get_privateFieldValue() { + return babelHelpers.classPrivateFieldGet2(_privateField, this); +} +const cl = new Cl(); diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/tagged-template/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/tagged-template/output.js new file mode 100644 index 00000000000000..cc0dc3d4def498 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/accessors/tagged-template/output.js @@ -0,0 +1,11 @@ +var _Foo_brand = new WeakSet(); +class Foo { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Foo_brand); + _get_tag.call(babelHelpers.assertClassBrand(_Foo_brand, this)).bind(this)``; + } +} +function _get_tag() { + return () => this; +} +new Foo(); diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/duplicated-names/get-set/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/duplicated-names/get-set/output.js new file mode 100644 index 00000000000000..5d7d533f1ab557 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/duplicated-names/get-set/output.js @@ -0,0 +1,14 @@ +var _privateField = new WeakMap(); +var _Cl_brand = new WeakSet(); +class Cl { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Cl_brand); + babelHelpers.classPrivateFieldInitSpec(this, _privateField, 0); + } +} +function _get_getSet() { + return babelHelpers.classPrivateFieldGet2(_privateField, this); +} +function _set_getSet(newValue) { + babelHelpers.classPrivateFieldSet2(_privateField, this, newValue); +} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/duplicated-names/set-get/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/duplicated-names/set-get/output.js new file mode 100644 index 00000000000000..14a4d723462184 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/duplicated-names/set-get/output.js @@ -0,0 +1,14 @@ +var _privateField = new WeakMap(); +var _Cl_brand = new WeakSet(); +class Cl { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Cl_brand); + babelHelpers.classPrivateFieldInitSpec(this, _privateField, 0); + } +} +function _set_getSet(newValue) { + babelHelpers.classPrivateFieldSet2(_privateField, this, newValue); +} +function _get_getSet() { + return babelHelpers.classPrivateFieldGet2(_privateField, this); +} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/misc/multiple/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/misc/multiple/output.js new file mode 100644 index 00000000000000..b0c86f1f945de1 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/misc/multiple/output.js @@ -0,0 +1,16 @@ +var _A_brand = new WeakSet(); +class A { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _A_brand); + babelHelpers.assertClassBrand(_A_brand, this, _method).call(this); + _get_getter.call(babelHelpers.assertClassBrand(_A_brand, this)); + babelHelpers.toSetter(_set_setter.bind(babelHelpers.assertClassBrand(_A_brand, this)), [])._ = 1; + _get_getset.call(babelHelpers.assertClassBrand(_A_brand, this)); + babelHelpers.toSetter(_set_getset.bind(babelHelpers.assertClassBrand(_A_brand, this)), [])._ = 2; + } +} +function _method() {} +function _get_getter() {} +function _set_setter(v) {} +function _get_getset() {} +function _set_getset(v) {} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/destructure-set/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/destructure-set/output.js new file mode 100644 index 00000000000000..3bce547f6ea1ad --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/destructure-set/output.js @@ -0,0 +1,10 @@ +class C { + constructor() { + [babelHelpers.toSetter(_set_p.bind(C))._] = [0]; + } +} +function _set_p(v) { + _q._ = v; +} +var _q = { _: void 0 }; +new C(); diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/preserve-comments/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/preserve-comments/output.js new file mode 100644 index 00000000000000..548f31dc0012a4 --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/preserve-comments/output.js @@ -0,0 +1,5 @@ +class C {} +function _get_a() { + return 42; +} +function _set_a(v) {} diff --git a/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/tagged-template/output.js b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/tagged-template/output.js new file mode 100644 index 00000000000000..ef09b7d2a8ef1e --- /dev/null +++ b/tasks/transform_conformance/overrides/babel-plugin-transform-private-methods/test/fixtures/static-accessors/tagged-template/output.js @@ -0,0 +1,11 @@ +class Foo { + static test() { + const receiver = _get_tag.call(babelHelpers.assertClassBrand(Foo, this)).bind(this)``; + expect(receiver).toBe(this); + } +} +function _get_tag() { + return function() { + return this; + }; +} diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index 36e768c979910d..53aad36349978f 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 641/1095 +Passed: 653/1095 # All Passed: * babel-plugin-transform-logical-assignment-operators @@ -462,33 +462,20 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-private-methods (26/148) +# babel-plugin-transform-private-methods (38/148) * accessors/arguments/input.js x Output mismatch * accessors/basic/input.js x Output mismatch -* accessors/class-binding/input.js -x Output mismatch - -* accessors/destructuring/input.js -x Output mismatch - * accessors/get-only-setter/input.js x Output mismatch -* accessors/preserve-comments/input.js -x Output mismatch - -* accessors/reassignment/input.js -x Output mismatch - -* accessors/set-only-getter/input.js -x Output mismatch - * accessors/tagged-template/input.js -x Output mismatch +Scope flags mismatch: +after transform: ScopeId(3): ScopeFlags(StrictMode | Function | Arrow) +rebuilt : ScopeId(4): ScopeFlags(Function | Arrow) * accessors/updates/input.js x Output mismatch @@ -556,24 +543,9 @@ x Output mismatch * assumption-constantSuper/private-method-super/input.js x Output mismatch -* duplicated-names/get-set/input.js -x Output mismatch - -* duplicated-names/set-get/input.js -x Output mismatch - * misc/multiple/input.js x Output mismatch -* private-method/destructuring/input.js -x Output mismatch - -* private-method/read-only/input.js -x Output mismatch - -* private-method/reassignment/input.js -x Output mismatch - * private-method/super/input.js x Output mismatch @@ -789,20 +761,16 @@ x Output mismatch * static-accessors/basic/input.js x Output mismatch -* static-accessors/destructure-set/input.js -x Output mismatch - * static-accessors/get-only-setter/input.js x Output mismatch -* static-accessors/preserve-comments/input.js -x Output mismatch - * static-accessors/set-only-getter/input.js x Output mismatch * static-accessors/tagged-template/input.js -x Output mismatch +Scope flags mismatch: +after transform: ScopeId(3): ScopeFlags(StrictMode | Function) +rebuilt : ScopeId(4): ScopeFlags(Function) * static-accessors/updates/input.js x Output mismatch diff --git a/tasks/transform_conformance/snapshots/babel_exec.snap.md b/tasks/transform_conformance/snapshots/babel_exec.snap.md index 4f5b236567f396..2e77c34e8f7cab 100644 --- a/tasks/transform_conformance/snapshots/babel_exec.snap.md +++ b/tasks/transform_conformance/snapshots/babel_exec.snap.md @@ -2,7 +2,7 @@ commit: 54a8389f node: v22.12.0 -Passed: 251 of 362 (69.34%) +Passed: 282 of 362 (77.90%) Failures: @@ -117,24 +117,6 @@ TypeError: Cannot read properties of undefined (reading 'x') at Foo.test (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-optional-chaining-test-fixtures-general-parenthesized-expression-member-call-loose-exec.test.js:25:63) at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-optional-chaining-test-fixtures-general-parenthesized-expression-member-call-loose-exec.test.js:68:12 -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-arguments-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-basic-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-class-binding-exec.test.js -AssertionError: expected [Function _get_getA] to be [Function A] // Object.is equality - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-class-binding-exec.test.js:22:26 - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-get-only-setter-exec.test.js -AssertionError: expected function to throw an error, but it didn't - at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-get-only-setter-exec.test.js:14:77) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-get-only-setter-exec.test.js:20:13 - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-helper-exec.test.js -Private field '#foo' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-basic-exec.test.js ReferenceError: _Cl_brand is not defined at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-basic-exec.test.js:10:38) @@ -147,8 +129,8 @@ ReferenceError: _A_brand is not defined ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-get-only-setter-exec.test.js ReferenceError: _Cl_brand is not defined - at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-get-only-setter-exec.test.js:10:38) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-get-only-setter-exec.test.js:21:13 + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-get-only-setter-exec.test.js:11:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-get-only-setter-exec.test.js:22:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-helper-exec.test.js ReferenceError: _Cl_brand is not defined @@ -161,8 +143,8 @@ AssertionError: expected +0 to be 1 // Object.is equality ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-set-only-getter-exec.test.js ReferenceError: _Cl_brand is not defined - at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-set-only-getter-exec.test.js:10:38) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-set-only-getter-exec.test.js:22:13 + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-set-only-getter-exec.test.js:11:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-set-only-getter-exec.test.js:23:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-loose-updates-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class @@ -179,8 +161,8 @@ ReferenceError: _A_brand is not defined ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js ReferenceError: _Cl_brand is not defined - at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:10:38) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:21:13 + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:11:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:22:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-helper-exec.test.js ReferenceError: _Cl_brand is not defined @@ -189,51 +171,18 @@ ReferenceError: _Cl_brand is not defined ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-set-only-getter-exec.test.js ReferenceError: _Cl_brand is not defined - at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-set-only-getter-exec.test.js:10:38) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-set-only-getter-exec.test.js:22:13 + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-set-only-getter-exec.test.js:11:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-set-only-getter-exec.test.js:23:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsProperties-updates-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-basic-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-class-binding-exec.test.js -AssertionError: expected [Function _get_getA] to be [Function A] // Object.is equality - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-class-binding-exec.test.js:22:26 - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js -AssertionError: expected [Function _set_privateFieldValue] to be undefined - at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:1236:20) - at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:923:17) - at Proxy.methodWrapper (./node_modules/.pnpm/chai@5.1.2/node_modules/chai/chai.js:1610:25) - at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js:14:71) +TypeError: "#privateFieldValue" is write-only + at _writeOnlyError (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/writeOnlyError.js:2:9) + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js:14:18) at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js:20:13 -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-helper-exec.test.js -Private field '#foo' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-set-only-getter-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-privateFieldsAsSymbols-updates-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-reassignment-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-set-only-getter-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-updates-bigint-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-updates-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-context-exec.test.js -Private field '#getStatus' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-assignment-exec.test.js ReferenceError: _Foo_brand is not defined at new Foo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-assignment-exec.test.js:8:38) @@ -251,8 +200,8 @@ ReferenceError: _A_brand is not defined ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-context-exec.test.js ReferenceError: _Foo_brand is not defined - at new Foo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-context-exec.test.js:8:38) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-context-exec.test.js:34:12 + at new Foo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-context-exec.test.js:9:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-context-exec.test.js:35:12 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-exfiltrated-exec.test.js ReferenceError: _Foo_brand is not defined @@ -290,8 +239,8 @@ ReferenceError: _A_brand is not defined ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-context-exec.test.js ReferenceError: _Foo_brand is not defined - at new Foo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-context-exec.test.js:8:38) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-context-exec.test.js:34:12 + at new Foo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-context-exec.test.js:9:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-context-exec.test.js:35:12 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-exfiltrated-exec.test.js ReferenceError: _Foo_brand is not defined @@ -308,15 +257,6 @@ ReferenceError: _Sub_brand is not defined at new Sub (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-super-exec.test.js:16:38) at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-super-exec.test.js:29:9 -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-context-exec.test.js -Private field '#getStatus' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-read-only-exec.test.js -Private field '#method' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-reassignment-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-loose-basic-exec.test.js TypeError: attempted to use private field on non-instance at _classPrivateFieldBase (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/classPrivateFieldLooseBase.js:2:44) @@ -401,30 +341,11 @@ TypeError: attempted to use private field on non-instance at Function.extract (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsProperties-this-exec.test.js:17:12) at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsProperties-this-exec.test.js:27:25 -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-reassignment-exec.test.js -Private field '#privateStaticMethod' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-read-only-exec.test.js -Private field '#method' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-reassignment-exec.test.js -Private field '#privateStaticMethod' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-access-in-static-field-initializer-exec.test.js -Private field '#p' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-basic-exec.test.js -Private field '#privateStaticFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-destructure-set-exec.test.js -Private field '#p' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-get-only-setter-exec.test.js -AssertionError: expected [Function _set_privateStaticFieldValue] to be undefined - at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:1236:20) - at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:923:17) - at Proxy.methodWrapper (./node_modules/.pnpm/chai@5.1.2/node_modules/chai/chai.js:1610:25) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-get-only-setter-exec.test.js:13:42 +TypeError: "#privateStaticFieldValue" is write-only + at _writeOnlyError (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/writeOnlyError.js:2:9) + at Function.getPrivateStaticFieldValue (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-get-only-setter-exec.test.js:7:15) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-get-only-setter-exec.test.js:14:12 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-access-in-static-field-initializer-exec.test.js TypeError: attempted to use private field on non-instance @@ -446,10 +367,10 @@ TypeError: attempted to use private field on non-instance at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-destructure-set-exec.test.js:22:2 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-get-only-setter-exec.test.js -TypeError: attempted to use private field on non-instance - at _classPrivateFieldBase (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/classPrivateFieldLooseBase.js:2:44) - at Function.getPrivateStaticFieldValue (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-get-only-setter-exec.test.js:10:11) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-get-only-setter-exec.test.js:21:12 +TypeError: "#privateStaticFieldValue" is write-only + at _writeOnlyError (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/writeOnlyError.js:2:9) + at Function.getPrivateStaticFieldValue (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-get-only-setter-exec.test.js:11:15) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-get-only-setter-exec.test.js:22:12 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-loose-updates-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class @@ -474,41 +395,19 @@ TypeError: attempted to use private field on non-instance at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-destructure-set-exec.test.js:22:2 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js -TypeError: attempted to use private field on non-instance - at _classPrivateFieldBase (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/classPrivateFieldLooseBase.js:2:44) - at Function.getPrivateStaticFieldValue (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:10:11) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:21:12 +TypeError: "#privateStaticFieldValue" is write-only + at _writeOnlyError (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/writeOnlyError.js:2:9) + at Function.getPrivateStaticFieldValue (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:11:15) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-get-only-setter-exec.test.js:22:12 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsProperties-updates-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-access-in-static-field-initializer-exec.test.js -Private field '#p' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-basic-exec.test.js -Private field '#privateStaticFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-destructure-set-exec.test.js -Private field '#p' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js -AssertionError: expected [Function _set_privateStaticFieldValue] to be undefined - at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:1236:20) - at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:923:17) - at Proxy.methodWrapper (./node_modules/.pnpm/chai@5.1.2/node_modules/chai/chai.js:1610:25) - at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js:13:42 - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-set-only-getter-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-updates-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-set-only-getter-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-updates-exec.test.js -Private field '#privateFieldValue' must be declared in an enclosing class +TypeError: "#privateStaticFieldValue" is write-only + at _writeOnlyError (./node_modules/.pnpm/@babel+runtime@7.26.0/node_modules/@babel/runtime/helpers/writeOnlyError.js:2:9) + at Function.getPrivateStaticFieldValue (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js:7:15) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-static-accessors-privateFieldsAsSymbols-get-only-setter-exec.test.js:14:12 ./fixtures/babel/babel-preset-env-test-fixtures-plugins-integration-issue-15170-exec.test.js AssertionError: expected [Function] to not throw an error but 'ReferenceError: x is not defined' was thrown