From f42dbdf56b355b7c74586646d60d8d5aee7cef30 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:35:05 +0000 Subject: [PATCH] fix(transformer/class-properties): output is not the same with Babel when PrivateFieldExpression is optional (#7762) Part of https://github.com/oxc-project/oxc/pull/7749 --- .../src/es2022/class_properties/private.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/oxc_transformer/src/es2022/class_properties/private.rs b/crates/oxc_transformer/src/es2022/class_properties/private.rs index 84a0ccbee4509..ba8ebd27f425f 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/private.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/private.rs @@ -1094,23 +1094,29 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) -> Expression<'a> { let Expression::PrivateFieldExpression(field_expr) = expr else { unreachable!() }; + let is_optional = field_expr.optional; let object = &mut field_expr.object; - let left = self.transform_first_optional_expression(object, ctx).unwrap_or_else(|| { - // Even though no optional expression, we still need to transform the object - self.transform_expression_to_wrap_nullish_check(object, ctx) - }); + let left = if is_optional { + Some(self.transform_expression_to_wrap_nullish_check(object, ctx)) + } else { + self.transform_first_optional_expression(object, ctx) + }; if matches!(ctx.ancestor(1), Ancestor::CallExpressionCallee(_)) { // `(Foo?.#m)();` -> `(Foo === null || Foo === void 0 ? void 0 : _m._.bind(Foo))();` // ^^^^^^^^^^^^ is a call expression, we need to bind the proper context - *expr = self - .transform_bindable_private_field(field_expr, ctx) - .unwrap_or_else(|| unreachable!()); + *expr = self.transform_bindable_private_field(field_expr, ctx).unwrap(); } else { self.transform_private_field_expression(expr, ctx); } - left + left.unwrap_or_else(|| { + // `o.Foo.#x?.self` -> `(_babelHelpers$assertC = expr === null || _babelHelpers$assertC === void 0 ? + // void 0 : _babelHelpers$assertC?.self;` + // `expr` is `o.Foo.#x` that has transformed to `babelHelpers.assertClassBrand(Foo, o.Foo, _x)._)` by + // `self.transform_private_field_expression`. + self.transform_expression_to_wrap_nullish_check(expr, ctx) + }) } fn transform_member_expression_of_chain_expression( @@ -1121,7 +1127,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { let is_optional = member.optional(); let object = member.object_mut(); let result = self.transform_chain_element_recursively(object, ctx)?; - if is_optional { + if is_optional && !object.is_identifier_reference() { // `o?.Foo.#self.self?.self.unicorn;` -> `(result ? void 0 : object)?.self.unicorn` // ^^^^^^^^^^^^^^^^^ the object has transformed, if the current member is optional, // then we need to wrap it to a conditional expression