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