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