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
10pub 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 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 ForcedExpr,
68
69 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 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 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 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 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 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 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 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 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 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 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 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 Expr::Object(..) | Expr::Class(..) | Expr::Fn(..) => self.wrap(expr),
1073
1074 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#[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 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 |_| 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}