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