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