diff --git a/ecmascript/transforms/compat/src/es2020/operators.rs b/ecmascript/transforms/compat/src/es2020/operators.rs index 447130447b74..2abf8775eb84 100644 --- a/ecmascript/transforms/compat/src/es2020/operators.rs +++ b/ecmascript/transforms/compat/src/es2020/operators.rs @@ -2,7 +2,8 @@ use swc_common::DUMMY_SP; use swc_ecma_ast::*; use swc_ecma_transforms_base::{ext::MapWithMut, perf::Check}; use swc_ecma_transforms_macros::fast_path; -use swc_ecma_utils::prepend; +use swc_ecma_utils::ExprFactory; +use swc_ecma_utils::{alias_if_required, prepend}; use swc_ecma_visit::{ as_folder, noop_visit_mut_type, noop_visit_type, Fold, Node, Visit, VisitMut, VisitMutWith, }; @@ -20,8 +21,89 @@ struct Operators { impl VisitMut for Operators { noop_visit_mut_type!(); - fn visit_mut_expr(&mut self, n: &mut Expr) { - n.visit_mut_children_with(self); + fn visit_mut_expr(&mut self, e: &mut Expr) { + e.visit_mut_children_with(self); + + match e { + Expr::Assign(AssignExpr { + span, + op: op!("||="), + left: PatOrExpr::Expr(left), + right, + }) if left.is_ident() || left.is_member() => { + let (alias, aliased) = alias_if_required( + match &**left { + Expr::Member(MemberExpr { + obj: ExprOrSuper::Expr(obj), + .. + }) => &obj, + _ => left, + }, + "_ref", + ); + let aliased = aliased + && match &**left { + Expr::Member(MemberExpr { + obj: ExprOrSuper::Super(..), + .. + }) => false, + _ => true, + }; + + if aliased { + self.vars.push(VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(alias.clone().into()), + init: None, + definite: false, + }); + } + + let result_left = if aliased { + let left: MemberExpr = left.clone().member().unwrap(); + + Box::new(Expr::Member(MemberExpr { + span: left.span, + obj: AssignExpr { + span: DUMMY_SP, + op: op!("="), + left: PatOrExpr::Pat(Box::new(Pat::Ident(alias.clone().into()))), + right: left.obj.expr().unwrap(), + } + .as_obj(), + prop: left.prop, + computed: left.computed, + })) + } else { + Box::new(Expr::Ident(left.clone().ident().unwrap())) + }; + + let right = Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: op!("="), + left: if aliased { + let left = left.take().member().unwrap(); + PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: alias.clone().as_obj(), + prop: left.prop, + computed: left.computed, + }))) + } else { + PatOrExpr::Pat(Box::new(Pat::Ident(left.take().ident().unwrap().into()))) + }, + right: right.take(), + })); + + *e = Expr::Bin(BinExpr { + span: *span, + op: op!("||"), + left: result_left, + right, + }); + } + _ => {} + } } fn visit_mut_module(&mut self, n: &mut Module) {