swc_ecma_transforms_base/
fixer.rs

1use std::{hash::BuildHasherDefault, mem, ops::RangeFull};
2
3use indexmap::IndexMap;
4use rustc_hash::FxHasher;
5use swc_common::{comments::Comments, util::take::Take, Span, Spanned, DUMMY_SP};
6use swc_ecma_ast::*;
7use swc_ecma_utils::stack_size::maybe_grow_default;
8use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
9
10/// Fixes ast nodes before printing so semantics are preserved.
11///
12/// You don't have to bother to create appropriate parenthesis.
13/// The pass will insert parenthesis as needed. In other words, it's
14/// okay to store `a * (b + c)` as `Bin { a * Bin { b + c } }`.
15pub fn fixer(comments: Option<&dyn Comments>) -> impl '_ + Pass + VisitMut {
16    visit_mut_pass(Fixer {
17        comments,
18        ctx: Default::default(),
19        span_map: Default::default(),
20        in_for_stmt_head: Default::default(),
21        in_opt_chain: Default::default(),
22        remove_only: false,
23    })
24}
25
26pub fn paren_remover(comments: Option<&dyn Comments>) -> impl '_ + Pass + VisitMut {
27    visit_mut_pass(Fixer {
28        comments,
29        ctx: Default::default(),
30        span_map: Default::default(),
31        in_for_stmt_head: Default::default(),
32        in_opt_chain: Default::default(),
33        remove_only: true,
34    })
35}
36
37struct Fixer<'a> {
38    comments: Option<&'a dyn Comments>,
39    ctx: Context,
40    /// A hash map to preserve original span.
41    ///
42    /// Key is span of inner expression, and value is span of the paren
43    /// expression.
44    span_map: IndexMap<Span, Span, BuildHasherDefault<FxHasher>>,
45
46    in_for_stmt_head: bool,
47    in_opt_chain: bool,
48
49    remove_only: bool,
50}
51
52#[repr(u8)]
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
54enum Context {
55    #[default]
56    Default,
57
58    Callee {
59        is_new: bool,
60    },
61    /// Always treated as expr. (But number of comma-separated expression
62    /// matters)
63    ///
64    ///  - `foo((bar, x))` != `foo(bar, x)`
65    ///  - `var foo = (bar, x)` != `var foo = bar, x`
66    ///  - `[(foo, bar)]` != `[foo, bar]`
67    ForcedExpr,
68
69    /// Always treated as expr and comma does not matter.
70    FreeExpr,
71}
72
73impl Fixer<'_> {
74    fn wrap_callee(&mut self, e: &mut Expr) {
75        match e {
76            Expr::Lit(Lit::Num(..) | Lit::Str(..)) => (),
77            Expr::Cond(..)
78            | Expr::Class(..)
79            | Expr::Bin(..)
80            | Expr::Lit(..)
81            | Expr::Unary(..)
82            | Expr::Object(..)
83            | Expr::Await(..)
84            | Expr::Yield(..) => self.wrap(e),
85            _ => (),
86        }
87    }
88}
89
90impl VisitMut for Fixer<'_> {
91    noop_visit_mut_type!();
92
93    fn visit_mut_array_lit(&mut self, e: &mut ArrayLit) {
94        let ctx = mem::replace(&mut self.ctx, Context::ForcedExpr);
95        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
96        e.elems.visit_mut_with(self);
97        self.in_for_stmt_head = in_for_stmt_head;
98        self.ctx = ctx;
99    }
100
101    fn visit_mut_arrow_expr(&mut self, node: &mut ArrowExpr) {
102        let old = self.ctx;
103        self.ctx = Context::Default;
104        node.visit_mut_children_with(self);
105        match &mut *node.body {
106            BlockStmtOrExpr::Expr(e) if e.is_seq() => {
107                self.wrap(e);
108            }
109
110            BlockStmtOrExpr::Expr(e) if e.is_assign() => {
111                if let Expr::Assign(assign) = &**e {
112                    if let AssignTarget::Pat(..) = &assign.left {
113                        self.wrap(e);
114                    }
115                }
116            }
117
118            _ => {}
119        };
120        self.ctx = old;
121    }
122
123    fn visit_mut_assign_expr(&mut self, expr: &mut AssignExpr) {
124        expr.left.visit_mut_with(self);
125
126        let ctx = self.ctx;
127        self.ctx = Context::FreeExpr;
128        expr.right.visit_mut_with(self);
129        self.ctx = ctx;
130
131        fn rhs_need_paren(e: &Expr) -> bool {
132            match e {
133                Expr::Assign(e) => rhs_need_paren(&e.right),
134                Expr::Seq(..) => true,
135                _ => false,
136            }
137        }
138
139        if rhs_need_paren(&expr.right) {
140            self.wrap(&mut expr.right);
141        }
142
143        fn find_nearest_opt_chain_as_obj(e: &mut Expr) -> Option<&mut Expr> {
144            match e {
145                Expr::Member(MemberExpr { obj, .. }) => {
146                    if obj.is_opt_chain() {
147                        Some(obj)
148                    } else {
149                        find_nearest_opt_chain_as_obj(obj)
150                    }
151                }
152                _ => None,
153            }
154        }
155
156        let lhs_expr = match &mut expr.left {
157            AssignTarget::Simple(e) => Some(e),
158            AssignTarget::Pat(..) => None,
159            #[cfg(swc_ast_unknown)]
160            _ => None,
161        };
162
163        if let Some(e) = lhs_expr
164            .and_then(|e| e.as_mut_member())
165            .and_then(|me| find_nearest_opt_chain_as_obj(&mut me.obj))
166        {
167            self.wrap(e)
168        };
169    }
170
171    fn visit_mut_assign_pat(&mut self, node: &mut AssignPat) {
172        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
173        node.visit_mut_children_with(self);
174        self.in_for_stmt_head = in_for_stmt_head;
175
176        if let Expr::Seq(..) = &*node.right {
177            self.wrap(&mut node.right);
178        }
179    }
180
181    fn visit_mut_assign_pat_prop(&mut self, node: &mut AssignPatProp) {
182        node.key.visit_mut_children_with(self);
183
184        let old = self.ctx;
185        self.ctx = Context::ForcedExpr;
186        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
187        node.value.visit_mut_with(self);
188        self.in_for_stmt_head = in_for_stmt_head;
189        self.ctx = old;
190    }
191
192    fn visit_mut_assign_target(&mut self, n: &mut AssignTarget) {
193        n.visit_mut_children_with(self);
194
195        match n {
196            AssignTarget::Simple(a) => {
197                if let SimpleAssignTarget::Paren(s) = a {
198                    *n = AssignTarget::try_from(s.expr.take()).unwrap();
199                }
200            }
201            AssignTarget::Pat(b) => {
202                if let AssignTargetPat::Invalid(_) = b {
203                    *n = AssignTarget::Simple(SimpleAssignTarget::Invalid(Invalid {
204                        span: DUMMY_SP,
205                    }));
206                }
207            }
208            #[cfg(swc_ast_unknown)]
209            _ => (),
210        }
211    }
212
213    fn visit_mut_await_expr(&mut self, expr: &mut AwaitExpr) {
214        let old = self.ctx;
215        self.ctx = Context::ForcedExpr;
216        expr.arg.visit_mut_with(self);
217        self.ctx = old;
218
219        match &*expr.arg {
220            Expr::Cond(..)
221            | Expr::Assign(..)
222            | Expr::Bin(..)
223            | Expr::Yield(..)
224            | Expr::Arrow(..) => self.wrap(&mut expr.arg),
225            _ => {}
226        }
227    }
228
229    fn visit_mut_bin_expr(&mut self, expr: &mut BinExpr) {
230        expr.left.visit_mut_with(self);
231        let ctx = self.ctx;
232        self.ctx = Context::FreeExpr;
233        expr.right.visit_mut_with(self);
234        self.ctx = ctx;
235
236        match expr.op {
237            op!("||") | op!("&&") => match (&*expr.left, &*expr.right) {
238                (Expr::Update(..), Expr::Call(..)) => {
239                    return;
240                }
241
242                (Expr::Update(..), Expr::Assign(..)) => {
243                    self.wrap(&mut expr.right);
244                    return;
245                }
246
247                _ => {}
248            },
249
250            op!(">") | op!(">=") | op!("<") | op!("<=") => {
251                if let (Expr::Update(..) | Expr::Lit(..), Expr::Update(..) | Expr::Lit(..)) =
252                    (&*expr.left, &*expr.right)
253                {
254                    return;
255                }
256            }
257
258            op!("**") => match &*expr.left {
259                Expr::Unary(..) => {
260                    self.wrap(&mut expr.left);
261                }
262                Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() => {
263                    self.wrap(&mut expr.left);
264                }
265                _ => {}
266            },
267
268            _ => {}
269        }
270
271        match &mut *expr.right {
272            Expr::Assign(..)
273            | Expr::Seq(..)
274            | Expr::Yield(..)
275            | Expr::Cond(..)
276            | Expr::Arrow(..) => {
277                self.wrap(&mut expr.right);
278            }
279            Expr::Bin(BinExpr { op: op_of_rhs, .. }) => {
280                if *op_of_rhs == expr.op {
281                    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#precedence_and_associativity
282                    // `**` is the only right associative operator in js
283                    if !(expr.op.may_short_circuit() || expr.op == op!("**")) {
284                        self.wrap(&mut expr.right);
285                    }
286                } else if op_of_rhs.precedence() <= expr.op.precedence()
287                    || (*op_of_rhs == op!("&&") && expr.op == op!("??"))
288                {
289                    self.wrap(&mut expr.right);
290                }
291            }
292            _ => {}
293        };
294
295        match &mut *expr.left {
296            Expr::Bin(BinExpr { op: op!("??"), .. }) if expr.op != op!("??") => {
297                self.wrap(&mut expr.left);
298            }
299
300            // While simplifying, (1 + x) * Nan becomes `1 + x * Nan`.
301            // But it should be `(1 + x) * Nan`
302            Expr::Bin(BinExpr { op: op_of_lhs, .. }) => {
303                if op_of_lhs.precedence() < expr.op.precedence()
304                    || (op_of_lhs.precedence() == expr.op.precedence() && expr.op == op!("**"))
305                {
306                    self.wrap(&mut expr.left);
307                }
308            }
309
310            Expr::Unary(UnaryExpr {
311                op: op!("void"), ..
312            }) if expr.op == op!("==")
313                || expr.op == op!("===")
314                || expr.op == op!("!=")
315                || expr.op == op!("!==") => {}
316
317            Expr::Seq(..)
318            | Expr::Unary(UnaryExpr {
319                op: op!("delete"), ..
320            })
321            | Expr::Unary(UnaryExpr {
322                op: op!("void"), ..
323            })
324            | Expr::Yield(..)
325            | Expr::Cond(..)
326            | Expr::Assign(..)
327            | Expr::Arrow(..) => {
328                self.wrap(&mut expr.left);
329            }
330            Expr::Object(..)
331                if expr.op == op!("instanceof")
332                    || expr.op == op!("==")
333                    || expr.op == op!("===")
334                    || expr.op == op!("!=")
335                    || expr.op == op!("!==") =>
336            {
337                self.wrap(&mut expr.left)
338            }
339            _ => {}
340        }
341
342        if let op!("??") = expr.op {
343            match &*expr.left {
344                Expr::Bin(BinExpr { op, .. }) if *op != op!("??") => {
345                    self.wrap(&mut expr.left);
346                }
347                _ => (),
348            }
349        }
350    }
351
352    fn visit_mut_block_stmt(&mut self, n: &mut BlockStmt) {
353        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
354        n.visit_mut_children_with(self);
355        self.in_for_stmt_head = in_for_stmt_head;
356    }
357
358    fn visit_mut_block_stmt_or_expr(&mut self, body: &mut BlockStmtOrExpr) {
359        body.visit_mut_children_with(self);
360
361        match body {
362            BlockStmtOrExpr::Expr(expr) if expr.is_object() => {
363                self.wrap(expr);
364            }
365
366            _ => {}
367        }
368    }
369
370    fn visit_mut_call_expr(&mut self, node: &mut CallExpr) {
371        let ctx = mem::replace(&mut self.ctx, Context::Callee { is_new: false });
372
373        node.callee.visit_mut_with(self);
374        if let Callee::Expr(e) = &mut node.callee {
375            match &**e {
376                Expr::OptChain(_) if !self.in_opt_chain => self.wrap(e),
377                _ => self.wrap_callee(e),
378            }
379        }
380
381        self.ctx = Context::ForcedExpr;
382
383        node.args.visit_mut_with(self);
384
385        self.ctx = ctx;
386    }
387
388    fn visit_mut_class(&mut self, node: &mut Class) {
389        let ctx = mem::replace(&mut self.ctx, Context::Default);
390
391        node.super_class.visit_mut_with(self);
392
393        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
394        node.body.visit_mut_with(self);
395        self.in_for_stmt_head = in_for_stmt_head;
396
397        match &mut node.super_class {
398            Some(e)
399                if e.is_seq()
400                    || e.is_await_expr()
401                    || e.is_yield_expr()
402                    || e.is_bin()
403                    || e.is_assign()
404                    || e.is_cond()
405                    || e.is_unary() =>
406            {
407                self.wrap(e)
408            }
409            _ => {}
410        };
411        self.ctx = ctx;
412
413        node.body.retain(|m| !matches!(m, ClassMember::Empty(..)));
414    }
415
416    fn visit_mut_computed_prop_name(&mut self, name: &mut ComputedPropName) {
417        let ctx = self.ctx;
418        self.ctx = Context::FreeExpr;
419        name.visit_mut_children_with(self);
420        self.ctx = ctx;
421    }
422
423    fn visit_mut_cond_expr(&mut self, expr: &mut CondExpr) {
424        expr.test.visit_mut_with(self);
425
426        let ctx = self.ctx;
427        self.ctx = Context::FreeExpr;
428        expr.cons.visit_mut_with(self);
429        expr.alt.visit_mut_with(self);
430        self.ctx = ctx;
431    }
432
433    fn visit_mut_export_default_expr(&mut self, node: &mut ExportDefaultExpr) {
434        let old = self.ctx;
435        self.ctx = Context::Default;
436        node.visit_mut_children_with(self);
437        match &mut *node.expr {
438            Expr::Arrow(..) | Expr::Seq(..) => self.wrap(&mut node.expr),
439            Expr::Fn(FnExpr { ident: Some(_), .. })
440            | Expr::Class(ClassExpr { ident: Some(_), .. }) => self.wrap(&mut node.expr),
441            _ => {}
442        };
443        self.ctx = old;
444    }
445
446    fn visit_mut_expr(&mut self, e: &mut Expr) {
447        let ctx = self.ctx;
448
449        if ctx == Context::Default {
450            match e {
451                // might have a child expr in start of stmt
452                Expr::OptChain(_)
453                | Expr::Member(_)
454                | Expr::Bin(_)
455                | Expr::Assign(_)
456                | Expr::Seq(_)
457                | Expr::Cond(_)
458                | Expr::TaggedTpl(_)
459                | Expr::Update(UpdateExpr { prefix: false, .. }) => {}
460                _ => self.ctx = Context::FreeExpr,
461            }
462        }
463        self.unwrap_expr(e);
464
465        maybe_grow_default(|| e.visit_mut_children_with(self));
466
467        self.ctx = ctx;
468        self.wrap_with_paren_if_required(e)
469    }
470
471    fn visit_mut_expr_or_spread(&mut self, e: &mut ExprOrSpread) {
472        e.visit_mut_children_with(self);
473
474        if e.spread.is_none() {
475            if let Expr::Yield(..) = *e.expr {
476                self.wrap(&mut e.expr);
477            }
478        }
479    }
480
481    fn visit_mut_expr_stmt(&mut self, s: &mut ExprStmt) {
482        let old = self.ctx;
483        self.ctx = Context::Default;
484        s.expr.visit_mut_with(self);
485        self.ctx = old;
486
487        self.handle_expr_stmt(&mut s.expr);
488    }
489
490    fn visit_mut_for_head(&mut self, n: &mut ForHead) {
491        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, true);
492        n.visit_mut_children_with(self);
493        self.in_for_stmt_head = in_for_stmt_head;
494    }
495
496    fn visit_mut_for_of_stmt(&mut self, s: &mut ForOfStmt) {
497        s.visit_mut_children_with(self);
498
499        if !s.is_await {
500            match &s.left {
501                ForHead::Pat(p)
502                    if match &**p {
503                        Pat::Ident(BindingIdent {
504                            id: Ident { sym, .. },
505                            ..
506                        }) => &**sym == "async",
507                        _ => false,
508                    } =>
509                {
510                    let expr: Pat = p.clone().expect_ident().into();
511                    s.left = ForHead::Pat(expr.into());
512                }
513                _ => (),
514            }
515
516            if let ForHead::Pat(e) = &mut s.left {
517                if let Pat::Expr(expr) = &mut **e {
518                    if expr.is_ident_ref_to("async") {
519                        self.wrap(&mut *expr);
520                    }
521                }
522            }
523        }
524
525        if let Expr::Seq(..) | Expr::Await(..) = &*s.right {
526            self.wrap(&mut s.right)
527        }
528    }
529
530    fn visit_mut_for_stmt(&mut self, n: &mut ForStmt) {
531        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, true);
532        n.init.visit_mut_with(self);
533        self.in_for_stmt_head = in_for_stmt_head;
534
535        n.test.visit_mut_with(self);
536        n.update.visit_mut_with(self);
537        n.body.visit_mut_with(self);
538    }
539
540    fn visit_mut_if_stmt(&mut self, node: &mut IfStmt) {
541        node.visit_mut_children_with(self);
542
543        if will_eat_else_token(&node.cons) {
544            node.cons = Box::new(
545                BlockStmt {
546                    span: node.cons.span(),
547                    stmts: vec![*node.cons.take()],
548                    ..Default::default()
549                }
550                .into(),
551            );
552        }
553    }
554
555    fn visit_mut_key_value_pat_prop(&mut self, node: &mut KeyValuePatProp) {
556        let old = self.ctx;
557        self.ctx = Context::ForcedExpr;
558        node.key.visit_mut_with(self);
559        self.ctx = old;
560
561        node.value.visit_mut_with(self);
562    }
563
564    fn visit_mut_key_value_prop(&mut self, prop: &mut KeyValueProp) {
565        prop.visit_mut_children_with(self);
566
567        if let Expr::Seq(..) = *prop.value {
568            self.wrap(&mut prop.value)
569        }
570    }
571
572    fn visit_mut_member_expr(&mut self, n: &mut MemberExpr) {
573        n.visit_mut_children_with(self);
574
575        match *n.obj {
576            Expr::Object(..) if self.ctx == Context::ForcedExpr => {}
577            Expr::Fn(..)
578            | Expr::Cond(..)
579            | Expr::Unary(..)
580            | Expr::Seq(..)
581            | Expr::Update(..)
582            | Expr::Bin(..)
583            | Expr::Object(..)
584            | Expr::Assign(..)
585            | Expr::Arrow(..)
586            | Expr::Class(..)
587            | Expr::Yield(..)
588            | Expr::Await(..)
589            | Expr::New(NewExpr { args: None, .. }) => {
590                self.wrap(&mut n.obj);
591            }
592            Expr::Call(..) if self.ctx == Context::Callee { is_new: true } => {
593                self.wrap(&mut n.obj);
594            }
595            Expr::OptChain(..) if !self.in_opt_chain => {
596                self.wrap(&mut n.obj);
597            }
598            _ => {}
599        }
600    }
601
602    fn visit_mut_module(&mut self, n: &mut Module) {
603        debug_assert!(self.span_map.is_empty());
604        self.span_map.clear();
605
606        n.visit_mut_children_with(self);
607        if let Some(c) = self.comments {
608            for (to, from) in self.span_map.drain(RangeFull).rev() {
609                c.move_leading(from.lo, to.lo);
610                c.move_trailing(from.hi, to.hi);
611            }
612        }
613    }
614
615    fn visit_mut_new_expr(&mut self, node: &mut NewExpr) {
616        let ctx = mem::replace(&mut self.ctx, Context::ForcedExpr);
617
618        node.args.visit_mut_with(self);
619
620        self.ctx = Context::Callee { is_new: true };
621        node.callee.visit_mut_with(self);
622        match *node.callee {
623            Expr::Call(..)
624            | Expr::Await(..)
625            | Expr::Yield(..)
626            | Expr::Bin(..)
627            | Expr::Assign(..)
628            | Expr::Seq(..)
629            | Expr::Unary(..)
630            | Expr::Lit(..) => self.wrap(&mut node.callee),
631            _ => {}
632        }
633        self.ctx = ctx;
634    }
635
636    fn visit_mut_opt_call(&mut self, node: &mut OptCall) {
637        let ctx = mem::replace(&mut self.ctx, Context::Callee { is_new: false });
638        let in_opt_chain = mem::replace(&mut self.in_opt_chain, true);
639
640        node.callee.visit_mut_with(self);
641        self.wrap_callee(&mut node.callee);
642
643        self.in_opt_chain = in_opt_chain;
644
645        self.ctx = Context::ForcedExpr;
646        node.args.visit_mut_with(self);
647
648        self.ctx = ctx;
649    }
650
651    fn visit_mut_opt_chain_base(&mut self, n: &mut OptChainBase) {
652        if !n.is_member() {
653            n.visit_mut_children_with(self);
654            return;
655        }
656
657        let in_opt_chain = mem::replace(&mut self.in_opt_chain, true);
658        n.visit_mut_children_with(self);
659        self.in_opt_chain = in_opt_chain;
660    }
661
662    fn visit_mut_param(&mut self, node: &mut Param) {
663        let old = self.ctx;
664        self.ctx = Context::ForcedExpr;
665        node.visit_mut_children_with(self);
666        self.ctx = old;
667    }
668
669    fn visit_mut_prop_name(&mut self, name: &mut PropName) {
670        name.visit_mut_children_with(self);
671
672        match name {
673            PropName::Computed(c) if c.expr.is_seq() => {
674                self.wrap(&mut c.expr);
675            }
676            _ => {}
677        }
678    }
679
680    fn visit_mut_script(&mut self, n: &mut Script) {
681        debug_assert!(self.span_map.is_empty());
682        self.span_map.clear();
683
684        n.visit_mut_children_with(self);
685        if let Some(c) = self.comments {
686            for (to, from) in self.span_map.drain(RangeFull).rev() {
687                c.move_leading(from.lo, to.lo);
688                c.move_trailing(from.hi, to.hi);
689            }
690        }
691    }
692
693    fn visit_mut_seq_expr(&mut self, seq: &mut SeqExpr) {
694        if seq.exprs.len() > 1 {
695            seq.exprs[0].visit_mut_with(self);
696
697            let ctx = self.ctx;
698            self.ctx = Context::FreeExpr;
699            for expr in seq.exprs.iter_mut().skip(1) {
700                expr.visit_mut_with(self)
701            }
702            self.ctx = ctx;
703        } else {
704            seq.exprs.visit_mut_children_with(self)
705        }
706    }
707
708    fn visit_mut_spread_element(&mut self, e: &mut SpreadElement) {
709        let old = self.ctx;
710        self.ctx = Context::ForcedExpr;
711        e.visit_mut_children_with(self);
712        self.ctx = old;
713    }
714
715    fn visit_mut_stmt(&mut self, s: &mut Stmt) {
716        let old = self.ctx;
717        // only ExprStmt would have unparented expr,
718        // which would be handled in its own visit function
719        self.ctx = Context::FreeExpr;
720        s.visit_mut_children_with(self);
721        self.ctx = old;
722    }
723
724    fn visit_mut_tagged_tpl(&mut self, e: &mut TaggedTpl) {
725        e.visit_mut_children_with(self);
726
727        match &*e.tag {
728            Expr::Object(..) if self.ctx == Context::Default => {
729                self.wrap(&mut e.tag);
730            }
731            Expr::OptChain(..)
732            | Expr::Arrow(..)
733            | Expr::Cond(..)
734            | Expr::Bin(..)
735            | Expr::Seq(..)
736            | Expr::Fn(..)
737            | Expr::Assign(..)
738            | Expr::Unary(..) => {
739                self.wrap(&mut e.tag);
740            }
741            _ => {}
742        }
743    }
744
745    fn visit_mut_unary_expr(&mut self, n: &mut UnaryExpr) {
746        let old = self.ctx;
747        self.ctx = Context::FreeExpr;
748        n.visit_mut_children_with(self);
749        self.ctx = old;
750
751        match &*n.arg {
752            Expr::Bin(BinExpr {
753                op: op!("/") | op!("*"),
754                left,
755                right,
756                ..
757            }) if n.op == op!(unary, "-")
758                && match (&**left, &**right) {
759                    (Expr::Lit(Lit::Num(l)), Expr::Lit(Lit::Num(..))) => {
760                        !l.value.is_sign_negative()
761                    }
762                    _ => false,
763                } => {}
764
765            Expr::Assign(..)
766            | Expr::Bin(..)
767            | Expr::Seq(..)
768            | Expr::Cond(..)
769            | Expr::Arrow(..)
770            | Expr::Yield(..) => self.wrap(&mut n.arg),
771
772            _ => {}
773        }
774    }
775
776    fn visit_mut_var_declarator(&mut self, node: &mut VarDeclarator) {
777        node.name.visit_mut_children_with(self);
778
779        let old = self.ctx;
780        self.ctx = Context::ForcedExpr;
781        node.init.visit_mut_with(self);
782        self.ctx = old;
783    }
784
785    fn visit_mut_yield_expr(&mut self, expr: &mut YieldExpr) {
786        let old = self.ctx;
787        self.ctx = Context::ForcedExpr;
788        expr.arg.visit_mut_with(self);
789        self.ctx = old;
790    }
791
792    fn visit_mut_object_lit(&mut self, n: &mut ObjectLit) {
793        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
794        n.visit_mut_children_with(self);
795        self.in_for_stmt_head = in_for_stmt_head;
796    }
797
798    fn visit_mut_params(&mut self, n: &mut Vec<Param>) {
799        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
800        n.visit_mut_children_with(self);
801        self.in_for_stmt_head = in_for_stmt_head;
802    }
803
804    // only used in ArrowExpr
805    fn visit_mut_pats(&mut self, n: &mut Vec<Pat>) {
806        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
807        n.visit_mut_children_with(self);
808        self.in_for_stmt_head = in_for_stmt_head;
809    }
810
811    fn visit_mut_expr_or_spreads(&mut self, n: &mut Vec<ExprOrSpread>) {
812        let in_for_stmt_head = mem::replace(&mut self.in_for_stmt_head, false);
813        n.visit_mut_children_with(self);
814        self.in_for_stmt_head = in_for_stmt_head;
815    }
816}
817
818impl Fixer<'_> {
819    fn wrap_with_paren_if_required(&mut self, e: &mut Expr) {
820        let mut has_padding_value = false;
821        match e {
822            Expr::Bin(BinExpr { op: op!("in"), .. }) if self.in_for_stmt_head => {
823                // TODO:
824                // if the in expression is in a parentheses, we should not wrap it with a
825                // parentheses again. But the parentheses is added later,
826                // so we don't have enough information to detect it at this moment.
827                // Example:
828                // for(var a = 1 + (2 || b in c) in {});
829                //                 |~~~~~~~~~~~|
830                // this parentheses is removed by unwrap_expr and added again later
831                self.wrap(e);
832            }
833
834            Expr::Bin(BinExpr { left, .. })
835                if self.ctx == Context::Default
836                    && matches!(&**left, Expr::Object(..) | Expr::Fn(..) | Expr::Class(..)) =>
837            {
838                self.wrap(left);
839            }
840
841            // Flatten seq expr
842            Expr::Seq(SeqExpr { span, exprs }) => {
843                let len = exprs
844                    .iter()
845                    .map(|expr| match **expr {
846                        Expr::Paren(ParenExpr { ref expr, .. }) => {
847                            if let Expr::Seq(SeqExpr { exprs, .. }) = expr.as_ref() {
848                                exprs.len()
849                            } else {
850                                1
851                            }
852                        }
853                        Expr::Seq(SeqExpr { ref exprs, .. }) => exprs.len(),
854                        _ => 1,
855                    })
856                    .sum();
857
858                let exprs_len = exprs.len();
859                // don't has child seq
860                let mut exprs = if len == exprs_len {
861                    let mut exprs = exprs
862                        .iter_mut()
863                        .enumerate()
864                        .filter_map(|(i, e)| {
865                            let is_last = i + 1 == exprs_len;
866                            if is_last {
867                                Some(e.take())
868                            } else {
869                                ignore_return_value(e.take(), &mut has_padding_value)
870                            }
871                        })
872                        .collect::<Vec<_>>();
873                    if exprs.len() == 1 {
874                        *e = *exprs.pop().unwrap();
875                        return;
876                    }
877                    ignore_padding_value(exprs)
878                } else {
879                    let mut buf = Vec::with_capacity(len);
880                    for (i, expr) in exprs.iter_mut().enumerate() {
881                        let is_last = i + 1 == exprs_len;
882
883                        match &mut **expr {
884                            Expr::Seq(SeqExpr { exprs, .. }) => {
885                                let exprs = exprs.take();
886                                if !is_last {
887                                    buf.extend(exprs.into_iter().filter_map(|expr| {
888                                        ignore_return_value(expr, &mut has_padding_value)
889                                    }));
890                                } else {
891                                    let exprs_len = exprs.len();
892                                    for (i, expr) in exprs.into_iter().enumerate() {
893                                        let is_last = i + 1 == exprs_len;
894                                        if is_last {
895                                            buf.push(expr);
896                                        } else {
897                                            buf.extend(ignore_return_value(
898                                                expr,
899                                                &mut has_padding_value,
900                                            ));
901                                        }
902                                    }
903                                }
904                            }
905                            _ => {
906                                if is_last {
907                                    buf.push(expr.take());
908                                } else {
909                                    buf.extend(ignore_return_value(
910                                        expr.take(),
911                                        &mut has_padding_value,
912                                    ));
913                                }
914                            }
915                        }
916                    }
917
918                    if buf.len() == 1 {
919                        *e = *buf.pop().unwrap();
920                        return;
921                    }
922
923                    ignore_padding_value(buf)
924                };
925
926                if self.ctx == Context::Default {
927                    if let Some(expr) = exprs.first_mut() {
928                        match &mut **expr {
929                            Expr::Call(CallExpr {
930                                callee: Callee::Expr(callee_expr),
931                                ..
932                            }) if callee_expr.is_fn_expr() => self.wrap(callee_expr),
933                            _ => (),
934                        }
935                    }
936                }
937
938                let mut expr = SeqExpr { span: *span, exprs }.into();
939
940                if let Context::ForcedExpr = self.ctx {
941                    self.wrap(&mut expr);
942                };
943
944                *e = expr;
945            }
946
947            Expr::Cond(expr) => {
948                match &mut *expr.test {
949                    Expr::Seq(..)
950                    | Expr::Assign(..)
951                    | Expr::Cond(..)
952                    | Expr::Arrow(..)
953                    | Expr::Yield(..) => self.wrap(&mut expr.test),
954
955                    Expr::Object(..) | Expr::Fn(..) | Expr::Class(..) => {
956                        if self.ctx == Context::Default {
957                            self.wrap(&mut expr.test)
958                        }
959                    }
960                    _ => {}
961                };
962
963                if let Expr::Seq(..) = *expr.cons {
964                    self.wrap(&mut expr.cons)
965                };
966
967                if let Expr::Seq(..) = *expr.alt {
968                    self.wrap(&mut expr.alt)
969                };
970
971                if let Context::Callee { is_new: true } = self.ctx {
972                    self.wrap(e)
973                }
974            }
975
976            Expr::Call(CallExpr {
977                callee: Callee::Expr(callee),
978                ..
979            }) if callee.is_seq()
980                || callee.is_arrow()
981                || callee.is_await_expr()
982                || callee.is_assign() =>
983            {
984                self.wrap(callee);
985            }
986            Expr::OptChain(OptChainExpr { base, .. }) => match &mut **base {
987                OptChainBase::Call(OptCall { callee, .. })
988                    if callee.is_seq()
989                        || callee.is_arrow()
990                        || callee.is_await_expr()
991                        || callee.is_assign() =>
992                {
993                    self.wrap(callee);
994                }
995
996                OptChainBase::Call(OptCall { callee, .. }) if callee.is_fn_expr() => match self.ctx
997                {
998                    Context::ForcedExpr | Context::FreeExpr => {}
999
1000                    Context::Callee { is_new: true } => self.wrap(e),
1001
1002                    _ => self.wrap(callee),
1003                },
1004
1005                _ => {}
1006            },
1007
1008            // Function expression cannot start with `function`
1009            Expr::Call(CallExpr {
1010                callee: Callee::Expr(callee),
1011                ..
1012            }) if callee.is_fn_expr() => match self.ctx {
1013                Context::ForcedExpr | Context::FreeExpr => {}
1014
1015                Context::Callee { is_new: true } => self.wrap(e),
1016
1017                _ => self.wrap(callee),
1018            },
1019
1020            Expr::Member(MemberExpr { obj, .. }) => match &**obj {
1021                Expr::Lit(Lit::Num(num)) if num.value.signum() == -1. => {
1022                    self.wrap(obj);
1023                }
1024                _ => {}
1025            },
1026            _ => {}
1027        }
1028    }
1029
1030    /// Wrap with a paren.
1031    fn wrap(&mut self, e: &mut Expr) {
1032        if self.remove_only {
1033            return;
1034        }
1035
1036        let mut span = e.span();
1037
1038        if let Some(new_span) = self.span_map.shift_remove(&span) {
1039            span = new_span;
1040        }
1041
1042        if span.is_pure() {
1043            span = DUMMY_SP;
1044        }
1045
1046        let expr = Box::new(e.take());
1047        *e = ParenExpr { expr, span }.into();
1048    }
1049
1050    /// Removes paren
1051    fn unwrap_expr(&mut self, e: &mut Expr) {
1052        loop {
1053            match e {
1054                Expr::Seq(SeqExpr { exprs, .. }) if exprs.len() == 1 => {
1055                    *e = *exprs[0].take();
1056                }
1057
1058                Expr::Paren(ParenExpr {
1059                    span: paren_span,
1060                    expr,
1061                    ..
1062                }) => {
1063                    let expr_span = expr.span();
1064                    let paren_span = *paren_span;
1065                    *e = *expr.take();
1066
1067                    self.span_map.insert(expr_span, paren_span);
1068                }
1069
1070                _ => return,
1071            }
1072        }
1073    }
1074
1075    fn handle_expr_stmt(&mut self, expr: &mut Expr) {
1076        match expr {
1077            // It's important for arrow pass to work properly.
1078            Expr::Object(..) | Expr::Class(..) | Expr::Fn(..) => self.wrap(expr),
1079
1080            // ({ a } = foo)
1081            Expr::Assign(AssignExpr {
1082                left: AssignTarget::Pat(left),
1083                ..
1084            }) if left.is_object() => self.wrap(expr),
1085
1086            Expr::Seq(SeqExpr { exprs, .. }) => {
1087                debug_assert!(
1088                    exprs.len() != 1,
1089                    "SeqExpr should be unwrapped if exprs.len() == 1, but length is 1"
1090                );
1091
1092                let len = exprs.len();
1093                exprs.iter_mut().enumerate().for_each(|(i, expr)| {
1094                    let is_last = len == i + 1;
1095
1096                    if !is_last {
1097                        self.handle_expr_stmt(expr);
1098                    }
1099                });
1100            }
1101
1102            _ => {}
1103        }
1104    }
1105}
1106
1107fn ignore_return_value(expr: Box<Expr>, has_padding_value: &mut bool) -> Option<Box<Expr>> {
1108    match *expr {
1109        Expr::Fn(..) | Expr::Arrow(..) | Expr::Lit(..) => {
1110            if *has_padding_value {
1111                None
1112            } else {
1113                *has_padding_value = true;
1114                Some(expr)
1115            }
1116        }
1117        Expr::Seq(SeqExpr { span, exprs }) => {
1118            let len = exprs.len();
1119            let mut exprs: Vec<_> = exprs
1120                .into_iter()
1121                .enumerate()
1122                .filter_map(|(i, expr)| {
1123                    if i + 1 == len {
1124                        Some(expr)
1125                    } else {
1126                        ignore_return_value(expr, has_padding_value)
1127                    }
1128                })
1129                .collect();
1130
1131            match exprs.len() {
1132                0 | 1 => exprs.pop(),
1133                _ => Some(SeqExpr { span, exprs }.into()),
1134            }
1135        }
1136        Expr::Unary(UnaryExpr {
1137            op: op!("void"),
1138            arg,
1139            ..
1140        }) => ignore_return_value(arg, has_padding_value),
1141        _ => Some(expr),
1142    }
1143}
1144
1145// at least 3 element in seq, which means we can safely
1146// remove that padding, if not at last position
1147#[allow(clippy::vec_box)]
1148fn ignore_padding_value(exprs: Vec<Box<Expr>>) -> Vec<Box<Expr>> {
1149    let len = exprs.len();
1150
1151    if len > 2 {
1152        exprs
1153            .into_iter()
1154            .enumerate()
1155            .filter_map(|(i, e)| match e.as_ref() {
1156                Expr::Fn(..) | Expr::Arrow(..) | Expr::Lit(..) if i + 1 != len => None,
1157                _ => Some(e),
1158            })
1159            .collect()
1160    } else {
1161        exprs
1162    }
1163}
1164
1165fn will_eat_else_token(s: &Stmt) -> bool {
1166    match s {
1167        Stmt::If(s) => match &s.alt {
1168            Some(alt) => will_eat_else_token(alt),
1169            None => true,
1170        },
1171        // Ends with `}`.
1172        Stmt::Block(..) => false,
1173
1174        Stmt::Labeled(s) => will_eat_else_token(&s.body),
1175
1176        Stmt::While(s) => will_eat_else_token(&s.body),
1177
1178        Stmt::For(s) => will_eat_else_token(&s.body),
1179
1180        Stmt::ForIn(s) => will_eat_else_token(&s.body),
1181
1182        Stmt::ForOf(s) => will_eat_else_token(&s.body),
1183
1184        _ => false,
1185    }
1186}
1187
1188#[cfg(test)]
1189mod tests {
1190    use swc_ecma_ast::noop_pass;
1191
1192    fn run_test(from: &str, to: &str) {
1193        crate::tests::test_transform(
1194            Default::default(),
1195            // test_transform has alreay included fixer
1196            |_| noop_pass(),
1197            from,
1198            to,
1199            true,
1200            Default::default,
1201        );
1202    }
1203
1204    macro_rules! test_fixer {
1205        ($name:ident, $from:literal, $to:literal) => {
1206            #[test]
1207            fn $name() {
1208                run_test($from, $to);
1209            }
1210        };
1211    }
1212
1213    macro_rules! identical {
1214        ($name:ident, $src:literal) => {
1215            test_fixer!($name, $src, $src);
1216        };
1217    }
1218
1219    identical!(fn_expr_position, r#"foo(function(){}())"#);
1220
1221    identical!(fn_decl, r#"function foo(){}"#);
1222
1223    identical!(iife, r#"(function(){})()"#);
1224
1225    identical!(paren_seq_arg, "foo(( _temp = _this = init(), _temp));");
1226
1227    identical!(
1228        regression_01,
1229        "_set(_get_prototype_of(Obj.prototype), _ref = proper.prop, (_superRef = \
1230         +_get(_get_prototype_of(Obj.prototype), _ref, this)) + 1, this, true), _superRef;"
1231    );
1232
1233    identical!(
1234        regression_02,
1235        "var obj = (_obj = {}, _define_property(_obj, 'first', 'first'), _define_property(_obj, \
1236         'second', 'second'), _obj);"
1237    );
1238
1239    identical!(
1240        regression_03,
1241        "_iteratorNormalCompletion = (_step = _iterator.next()).done"
1242    );
1243
1244    identical!(
1245        regression_04,
1246        "var _tmp;
1247const _ref = {}, { c =( _tmp = {}, d = _extends({}, _tmp), _tmp)  } = _ref;"
1248    );
1249
1250    identical!(
1251        regression_05,
1252        "for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step \
1253         = _iterator.next()).done); _iteratorNormalCompletion = true) {
1254    i = _step.value;
1255}"
1256    );
1257
1258    identical!(
1259        regression_06,
1260        "
1261        var _tmp;
1262        const { [( _tmp = {}, d = _extends({}, _tmp), _tmp)]: c  } = _ref;
1263        "
1264    );
1265
1266    identical!(
1267        regression_07,
1268        "( _temp = super(), _initialize(this), _temp).method();"
1269    );
1270
1271    identical!(regression_08, "exports.bar = exports.default = void 0;");
1272
1273    identical!(regression_09, "({x} = { x: 1 });");
1274
1275    identical!(regression_10, "({x} = { x: 1 }), exports.x = x;");
1276
1277    identical!(regression_11, "(void 0).foo();");
1278
1279    identical!(regression_12, "(function(){})()");
1280
1281    identical!(regression_13, "a || (a = 1);");
1282
1283    identical!(issue_192, "a === true && (a = true)");
1284
1285    identical!(issue_199, "(i - 1).toString()");
1286
1287    identical!(
1288        issue_201_01,
1289        "outer = {
1290    inner: (_obj = {}, _define_property(_obj, ns.EXPORT1, true), _define_property(_obj, \
1291         ns.EXPORT2, true), _obj)
1292};"
1293    );
1294
1295    identical!(issue_207, "a => ({x: 'xxx', y: {a}});");
1296
1297    test_fixer!(
1298        fixer_01,
1299        "var a, b, c, d, e, f;
1300((a, b), (c())) + ((d, e), (f()));
1301",
1302        "var a, b, c, d, e, f;
1303(a, b, c()) + (d, e, f())"
1304    );
1305
1306    test_fixer!(fixer_02, "(b, c), d;", "b, c, d;");
1307
1308    test_fixer!(fixer_03, "((a, b), (c && d)) && e;", "(a, b, c && d) && e;");
1309
1310    test_fixer!(fixer_04, "for ((a, b), c;;) ;", "for(a, b, c;;);");
1311
1312    test_fixer!(
1313        fixer_05,
1314        "var a, b, c = (1), d, e, f = (2);
1315((a, b), c) + ((d, e), f);",
1316        "var a, b, c = 1, d, e, f = 2;
1317(a, b, c) + (d, e, f);"
1318    );
1319
1320    test_fixer!(
1321        fixer_06,
1322        "var a, b, c, d;
1323a = ((b, c), d);",
1324        "var a, b, c, d;
1325a = (b, c, d);"
1326    );
1327
1328    test_fixer!(
1329        fixer_07,
1330        "a => ((b, c) => ((a, b), c));",
1331        "(a)=>(b, c)=>(a, b, c);"
1332    );
1333
1334    test_fixer!(fixer_08, "typeof (((1), a), (2));", "typeof (a, 2)");
1335
1336    test_fixer!(
1337        fixer_09,
1338        "(((a, b), c), d) ? e : f;",
1339        "(a, b, c, d) ? e : f;"
1340    );
1341
1342    test_fixer!(
1343        fixer_10,
1344        "
1345function a() {
1346  return (((void (1)), (void (2))), a), (void (3));
1347}
1348",
1349        "
1350function a() {
1351  return a, void 3;
1352}
1353"
1354    );
1355
1356    test_fixer!(fixer_11, "c && ((((2), (3)), d), b);", "c && (d, b)");
1357
1358    test_fixer!(fixer_12, "(((a, b), c), d) + e;", "(a, b, c, d) + e;");
1359
1360    test_fixer!(fixer_13, "delete (((1), a), (2));", "delete (a, 2)");
1361
1362    test_fixer!(fixer_14, "(1, 2, a)", "1, a");
1363
1364    identical!(issue_231, "'' + (truthy && '?') + truthy;");
1365
1366    identical!(issue_252, "!!(a && b);");
1367
1368    identical!(issue_255, "b < 0 ? (t = b, b = 1) : (t = -b, b = 0);");
1369
1370    identical!(
1371        issue_266_1,
1372        "'Q' + +x1 + ',' + +y1 + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);"
1373    );
1374
1375    test_fixer!(
1376        issue_266_2,
1377        "'Q' + (+x1) + ',' + (+y1) + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);",
1378        "'Q' + +x1 + ',' + +y1 + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);"
1379    );
1380
1381    identical!(
1382        issue_280,
1383        "e.hasOwnProperty(a) && (t = e[a] ? this[a] = t(n) : 'target' === a ? this.target = r : \
1384         this[a] = n[a]);"
1385    );
1386
1387    identical!(
1388        issue_282,
1389        "!(A = [], B = (function () { return classNames; }).apply(exports, A), B !== undefined && \
1390         (module.exports = B));"
1391    );
1392
1393    identical!(
1394        issue_286,
1395        "var SHARED = '__core-js_shared__';
1396var store = global[SHARED] || (global[SHARED] = {});
1397(module.exports = function (key, value) {
1398  return store[key] || (store[key] = value !== undefined ? value : {});
1399})('versions', []).push({
1400  version: core.version,
1401  mode: __webpack_require__(39) ? 'pure' : 'global',
1402  copyright: '© 2018 Denis Pushkarev (zloirock.ru)'
1403});"
1404    );
1405
1406    identical!(
1407        issue_293_1,
1408        "for (var e in a) a.hasOwnProperty(e) && ((b = a[e]) ? this[e] = b(c) : 'target' === e ? \
1409         this.target = d : this[e] = c[e]);"
1410    );
1411
1412    identical!(
1413        issue_293_2,
1414        "(a = rb ? zb(a, c) : Ab(a, c)) ? (b = nb.getPooled(ub.beforeInput, b, c, d), b.data = a, \
1415         Ra(b)) : b = null;"
1416    );
1417
1418    identical!(member_object_lit, "({}).foo");
1419
1420    identical!(member_cond_expr, "(foo ? 1 : 2).foo");
1421
1422    identical!(member_new_exp_1, "(new Foo).foo");
1423
1424    identical!(member_new_exp_2, "new ctor().property");
1425
1426    identical!(member_tagged_tpl, "tag``.foo");
1427
1428    identical!(member_arrow_expr_1, "(a => a).foo");
1429
1430    identical!(member_arrow_expr_2, "((a) => a).foo");
1431
1432    identical!(member_class, "(class Foo{}).foo");
1433
1434    identical!(member_yield, "function* foo(){ (yield bar).baz }");
1435
1436    identical!(member_await, "async function foo(){ (await bar).baz }");
1437
1438    identical!(bin_yield_expr_1, "function* foo(){ (yield foo) && bar }");
1439
1440    identical!(bin_yield_expr_2, "function* foo(){ bar && (yield foo) }");
1441
1442    identical!(bin_seq_expr_1, "(foo(), op) || (seq(), foo)");
1443
1444    identical!(bin_seq_expr_2, "(foo, op) || (seq, foo)");
1445
1446    identical!(cond_object_1, "let foo = {} ? 1 : 2;");
1447
1448    identical!(cond_object_2, "({}) ? 1 : 2;");
1449
1450    identical!(cond_in_cond, "(foo ? 1 : 2) ? 3 : 4");
1451
1452    identical!(arrow_in_cond, "(() => {}) ? 3 : 4");
1453
1454    identical!(unary_cond_arg, "void (foo ? 1 : 2)");
1455
1456    identical!(unary_arrow_arg, "void ((foo) => foo)");
1457
1458    identical!(unary_yield_arg, "(function* foo() { void (yield foo); })()");
1459
1460    identical!(
1461        issue_365,
1462        "const foo = (() => {
1463  return 1
1464})();"
1465    );
1466
1467    identical!(
1468        issue_382_1,
1469        "const myFilter = (arr, filter) => arr.filter(((x) => x) || filter);"
1470    );
1471
1472    identical!(
1473        issue_382_2,
1474        "const myFilter = (arr, filter) => arr.filter(filter || ((x) => x));"
1475    );
1476
1477    identical!(issue_418, "const a = 1 - (1 - 1)");
1478
1479    test_fixer!(
1480        issue_439,
1481        "() => {
1482  return (
1483    Promise.resolve('foo')
1484      // Interfering comment
1485      .then(() => {})
1486  );
1487};",
1488        "() => {
1489  return Promise.resolve('foo')
1490      // Interfering comment
1491      .then(() => {})
1492  ;
1493};"
1494    );
1495
1496    test_fixer!(
1497        issue_451,
1498        "const instance = new (
1499  function() {
1500    function klass(opts) {
1501      this.options = opts;
1502    }
1503    return (Object.assign(klass.prototype, {
1504      method() {}
1505    }), klass);
1506  }()
1507)({ foo: 1 });",
1508        "const instance = new (function() {
1509    function klass(opts) {
1510        this.options = opts;
1511    }
1512    return Object.assign(klass.prototype, {
1513        method () {
1514        }
1515    }), klass;
1516}())({
1517    foo: 1
1518});"
1519    );
1520
1521    test_fixer!(void_and_bin, "(void 0) * 2", "(void 0) * 2");
1522
1523    test_fixer!(new_cond, "new (a ? B : C)()", "new (a ? B : C)()");
1524
1525    identical!(issue_931, "new (eval('Date'))();");
1526
1527    identical!(issue_1002, "new (P || (P = Promise))");
1528
1529    identical!(
1530        issue_1050,
1531        "
1532        (a) => (set) => (elemE(a, set) ? removeE : insertE)(a)(set)
1533        "
1534    );
1535
1536    identical!(
1537        deno_001,
1538        "
1539    var Status;
1540    (function init(Status1) {
1541    })(Status || (Status = {
1542    }));
1543"
1544    );
1545
1546    identical!(issue_1093, "const x = (fnA || fnB)();");
1547
1548    identical!(
1549        issue_1133,
1550        "async function foo() {
1551            const item = await (data === null || data === void 0 ? void 0 : data.foo());
1552        }"
1553    );
1554
1555    identical!(deno_8722, "console.log((true || false) ?? true);");
1556
1557    identical!(
1558        deno_8597,
1559        "
1560        biasInitializer = new (_a = class CustomInit extends Initializer {})();
1561        "
1562    );
1563
1564    test_fixer!(
1565        minifier_001,
1566        "var bitsLength = 3, bitsOffset = 3, what = (len = 0)",
1567        "var bitsLength = 3, bitsOffset = 3, what = len = 0"
1568    );
1569
1570    test_fixer!(minifier_002, "!(function(){})()", "!function(){}()");
1571
1572    identical!(
1573        issue_1397,
1574        "const main = async () => await (await server)()"
1575    );
1576
1577    identical!(deno_9810, "await (bar = Promise.resolve(2));");
1578
1579    identical!(issue_1493, "('a' ?? 'b') || ''");
1580    identical!(call_seq, "let x = ({}, () => 2)();");
1581
1582    test_fixer!(
1583        call_seq_with_padding,
1584        "let x = ({}, (1, 2), () => 2)();",
1585        "let x = ({}, () => 2)();"
1586    );
1587
1588    identical!(
1589        param_seq,
1590        "function t(x = ({}, 2)) {
1591            return x;
1592        }"
1593    );
1594
1595    identical!(
1596        yield_expr_cond,
1597        "function *test1(foo) {
1598            return (yield foo) ? 'bar' : 'baz';
1599        }"
1600    );
1601
1602    identical!(
1603        deno_10487_1,
1604        "var generator = class MultiVector extends (options.baseType||Float32Array) {}"
1605    );
1606
1607    identical!(
1608        deno_10487_2,
1609        "class MultiVector extends (options.baseType||Float32Array) {}"
1610    );
1611
1612    identical!(
1613        extends_nullish_coalescing,
1614        "class Foo extends (Bar ?? class{}) {}"
1615    );
1616
1617    identical!(extends_assign, "class Foo extends (Bar = class{}) {}");
1618
1619    identical!(
1620        extends_logical_or_assin,
1621        "class Foo extends (Bar ||= class{}) {}"
1622    );
1623
1624    identical!(
1625        extends_logical_and_assin,
1626        "class Foo extends (Bar &&= class{}) {}"
1627    );
1628
1629    identical!(
1630        extends_logical_nullish_assin,
1631        "class Foo extends (Bar ??= class{}) {}"
1632    );
1633
1634    identical!(extends_cond, "class Foo extends (true ? Bar : Baz) {}");
1635
1636    identical!(
1637        extends_await_yield,
1638        "
1639        async function* func() {
1640            class A extends (await p) {}
1641            class B extends (yield p) {}
1642        }
1643        "
1644    );
1645
1646    identical!(deno_10668_1, "console.log(null ?? (undefined && true))");
1647
1648    identical!(deno_10668_2, "console.log(null && (undefined ?? true))");
1649
1650    identical!(minifier_003, "(four ** one) ** two");
1651
1652    identical!(minifier_004, "(void 0)(0)");
1653
1654    identical!(issue_1781, "const n = ~~(Math.PI * 10)");
1655
1656    identical!(issue_1789, "+(+1 / 4)");
1657
1658    identical!(new_member_call_1, "new (getObj()).ctor()");
1659    test_fixer!(
1660        new_member_call_2,
1661        "new (getObj().ctor)()",
1662        "new (getObj()).ctor()"
1663    );
1664    test_fixer!(
1665        new_member_call_3,
1666        "new (x.getObj().ctor)()",
1667        "new (x.getObj()).ctor()"
1668    );
1669    identical!(new_call, "new (getCtor())");
1670    test_fixer!(new_member_1, "new obj.ctor()", "new obj.ctor()");
1671    test_fixer!(new_member_2, "new (obj.ctor)", "new obj.ctor");
1672
1673    identical!(
1674        new_await_1,
1675        "async function foo() { new (await getServerImpl())(options) }"
1676    );
1677    test_fixer!(minifier_005, "-(1/0)", "-1/0");
1678
1679    test_fixer!(minifier_006, "-('s'/'b')", "-('s'/'b')");
1680
1681    test_fixer!(minifier_007, "(void 0) === value", "void 0 === value");
1682    test_fixer!(minifier_008, "(size--) && (b = (c))", "size-- && (b = c)");
1683
1684    test_fixer!(
1685        minifier_009,
1686        "(--remaining) || deferred.resolveWith()",
1687        "--remaining || deferred.resolveWith()"
1688    );
1689
1690    test_fixer!(minifier_010, "(--remaining) + ''", "--remaining + ''");
1691
1692    identical!(
1693        if_stmt_001,
1694        "
1695        export const obj = {
1696            each: function (obj, callback, args) {
1697                var i = 0, length = obj.length, isArray = isArraylike(obj);
1698                if (args) {
1699                    if (isArray)
1700                        for (; i < length && !1 !== callback.apply(obj[i], args); i++);
1701                    else
1702                        for (i in obj)
1703                            if (!1 === callback.apply(obj[i], args))
1704                                break
1705                } else if (isArray)
1706                    for (; i < length && !1 !== callback.call(obj[i], i, obj[i]); i++);
1707                else
1708                    for (i in obj)
1709                        if (!1 === callback.call(obj[i], i, obj[i]))
1710                            break;
1711                return obj
1712            }
1713        };
1714        "
1715    );
1716
1717    identical!(
1718        issue_2155,
1719        "
1720        async function main() {
1721            let promise;
1722            await (promise || (promise = Promise.resolve('this is a string')));
1723        }
1724        "
1725    );
1726
1727    identical!(issue_2163_1, "() => ({foo} = bar());");
1728
1729    identical!(issue_2163_2, "() => ([foo] = bar());");
1730
1731    identical!(issue_2191, "(-1) ** h");
1732
1733    identical!(
1734        minifier_011,
1735        "
1736        function ItemsList() {
1737            var _ref;
1738
1739            var _temp, _this, _ret;
1740
1741            _class_call_check(this, ItemsList);
1742
1743            for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
1744              args[_key] = arguments[_key];
1745            }
1746
1747            return _ret = (_temp = (_this = _possible_constructor_return(this, (_ref = \
1748         ItemsList.__proto__ || Object.getPrototypeOf(ItemsList)).call.apply(_ref, \
1749         [this].concat(args))), _this), _this.storeHighlightedItemReference = function \
1750         (highlightedItem) {
1751              _this.props.onHighlightedItemChange(highlightedItem === null ? null : \
1752         highlightedItem.item);
1753            }, _temp), _possible_constructor_return(_this, _ret);
1754          }
1755        "
1756    );
1757
1758    identical!(
1759        minifier_012,
1760        "
1761        function ItemsList() {
1762            for(var _ref, _temp, _this, _len = arguments.length, args = Array(_len), _key = 0; \
1763         _key < _len; _key++)args[_key] = arguments[_key];
1764            return _possible_constructor_return(_this, (_temp = (_this = \
1765         _possible_constructor_return(this, (_ref = ItemsList.__proto__ || \
1766         Object.getPrototypeOf(ItemsList)).call.apply(_ref, [
1767                this
1768            ].concat(args))), _this), _this.storeHighlightedItemReference = \
1769         function(highlightedItem) {
1770                _this.props.onHighlightedItemChange(null === highlightedItem ? null : \
1771         highlightedItem.item);
1772            }, _temp));
1773        }
1774        "
1775    );
1776
1777    test_fixer!(issue_2550_1, "(1 && { a: 1 })", "1 && { a:1 }");
1778
1779    identical!(issue_2550_2, "({ isNewPrefsActive }) && { a: 1 }");
1780
1781    test_fixer!(paren_of_bin_left_1, "({} && 1)", "({}) && 1");
1782    identical!(paren_of_bin_left_2, "({}) && 1");
1783    test_fixer!(
1784        paren_of_bin_left_3,
1785        "(function () {} || 2)",
1786        "(function () {}) || 2"
1787    );
1788    identical!(paren_of_bin_left_4, "(function () {}) || 2");
1789
1790    test_fixer!(paren_of_bin_left_5, "(class{} ?? 3)", "(class{}) ?? 3");
1791    identical!(paren_of_bin_left_6, "(class{}) ?? 3");
1792
1793    identical!(issue_4761, "x = { ...(0, foo) }");
1794
1795    identical!(issue_4914, "(a ?? b)?.()");
1796
1797    identical!(issue_5109_1, "(0, b)?.()");
1798    identical!(issue_5109_2, "1 + (0, b)?.()");
1799    identical!(issue_5109_3, "(0, a)() ? undefined : (0, b)?.()");
1800
1801    identical!(
1802        issue_5313,
1803        "
1804        async function* foo() {
1805            (await a)();
1806            (yield b)();
1807        }
1808        "
1809    );
1810
1811    identical!(issue_5417, "console.log(a ?? b ?? c)");
1812
1813    identical!(bin_and_unary, "console.log(a++ && b--)");
1814}