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 Expr::Bin(BinExpr { left, .. }) => {
935 if let Expr::Call(CallExpr {
936 callee: Callee::Expr(callee_expr),
937 ..
938 }) = &mut **left
939 {
940 if callee_expr.is_fn_expr() {
941 self.wrap(callee_expr)
942 }
943 }
944 }
945 _ => (),
946 }
947 }
948 }
949
950 let mut expr = SeqExpr { span: *span, exprs }.into();
951
952 if let Context::ForcedExpr = self.ctx {
953 self.wrap(&mut expr);
954 };
955
956 *e = expr;
957 }
958
959 Expr::Cond(expr) => {
960 match &mut *expr.test {
961 Expr::Seq(..)
962 | Expr::Assign(..)
963 | Expr::Cond(..)
964 | Expr::Arrow(..)
965 | Expr::Yield(..) => self.wrap(&mut expr.test),
966
967 Expr::Object(..) | Expr::Fn(..) | Expr::Class(..) => {
968 if self.ctx == Context::Default {
969 self.wrap(&mut expr.test)
970 }
971 }
972 _ => {}
973 };
974
975 if let Expr::Seq(..) = *expr.cons {
976 self.wrap(&mut expr.cons)
977 };
978
979 if let Expr::Seq(..) = *expr.alt {
980 self.wrap(&mut expr.alt)
981 };
982
983 if let Context::Callee { is_new: true } = self.ctx {
984 self.wrap(e)
985 }
986 }
987
988 Expr::Call(CallExpr {
989 callee: Callee::Expr(callee),
990 ..
991 }) if callee.is_seq()
992 || callee.is_arrow()
993 || callee.is_await_expr()
994 || callee.is_assign() =>
995 {
996 self.wrap(callee);
997 }
998 Expr::OptChain(OptChainExpr { base, .. }) => match &mut **base {
999 OptChainBase::Call(OptCall { callee, .. })
1000 if callee.is_seq()
1001 || callee.is_arrow()
1002 || callee.is_await_expr()
1003 || callee.is_assign() =>
1004 {
1005 self.wrap(callee);
1006 }
1007
1008 OptChainBase::Call(OptCall { callee, .. }) if callee.is_fn_expr() => match self.ctx
1009 {
1010 Context::ForcedExpr | Context::FreeExpr => {}
1011
1012 Context::Callee { is_new: true } => self.wrap(e),
1013
1014 _ => self.wrap(callee),
1015 },
1016
1017 _ => {}
1018 },
1019
1020 Expr::Call(CallExpr {
1022 callee: Callee::Expr(callee),
1023 ..
1024 }) if callee.is_fn_expr() => match self.ctx {
1025 Context::ForcedExpr | Context::FreeExpr => {}
1026
1027 Context::Callee { is_new: true } => self.wrap(e),
1028
1029 _ => self.wrap(callee),
1030 },
1031
1032 Expr::Member(MemberExpr { obj, .. }) => match &**obj {
1033 Expr::Lit(Lit::Num(num)) if num.value.signum() == -1. => {
1034 self.wrap(obj);
1035 }
1036 _ => {}
1037 },
1038 _ => {}
1039 }
1040 }
1041
1042 fn wrap(&mut self, e: &mut Expr) {
1044 if self.remove_only {
1045 return;
1046 }
1047
1048 let mut span = e.span();
1049
1050 if let Some(new_span) = self.span_map.shift_remove(&span) {
1051 span = new_span;
1052 }
1053
1054 if span.is_pure() {
1055 span = DUMMY_SP;
1056 }
1057
1058 let expr = Box::new(e.take());
1059 *e = ParenExpr { expr, span }.into();
1060 }
1061
1062 fn unwrap_expr(&mut self, e: &mut Expr) {
1064 loop {
1065 match e {
1066 Expr::Seq(SeqExpr { exprs, .. }) if exprs.len() == 1 => {
1067 *e = *exprs[0].take();
1068 }
1069
1070 Expr::Paren(ParenExpr {
1071 span: paren_span,
1072 expr,
1073 ..
1074 }) => {
1075 let expr_span = expr.span();
1076 let paren_span = *paren_span;
1077 *e = *expr.take();
1078
1079 self.span_map.insert(expr_span, paren_span);
1080 }
1081
1082 _ => return,
1083 }
1084 }
1085 }
1086
1087 fn handle_expr_stmt(&mut self, expr: &mut Expr) {
1088 match expr {
1089 Expr::Object(..) | Expr::Class(..) | Expr::Fn(..) => self.wrap(expr),
1091
1092 Expr::Assign(AssignExpr {
1094 left: AssignTarget::Pat(left),
1095 ..
1096 }) if left.is_object() => self.wrap(expr),
1097
1098 Expr::Seq(SeqExpr { exprs, .. }) => {
1099 debug_assert!(
1100 exprs.len() != 1,
1101 "SeqExpr should be unwrapped if exprs.len() == 1, but length is 1"
1102 );
1103
1104 let len = exprs.len();
1105 exprs.iter_mut().enumerate().for_each(|(i, expr)| {
1106 let is_last = len == i + 1;
1107
1108 if !is_last {
1109 self.handle_expr_stmt(expr);
1110 }
1111 });
1112 }
1113
1114 _ => {}
1115 }
1116 }
1117}
1118
1119fn ignore_return_value(expr: Box<Expr>, has_padding_value: &mut bool) -> Option<Box<Expr>> {
1120 match *expr {
1121 Expr::Fn(..) | Expr::Arrow(..) | Expr::Lit(..) => {
1122 if *has_padding_value {
1123 None
1124 } else {
1125 *has_padding_value = true;
1126 Some(expr)
1127 }
1128 }
1129 Expr::Seq(SeqExpr { span, exprs }) => {
1130 let len = exprs.len();
1131 let mut exprs: Vec<_> = exprs
1132 .into_iter()
1133 .enumerate()
1134 .filter_map(|(i, expr)| {
1135 if i + 1 == len {
1136 Some(expr)
1137 } else {
1138 ignore_return_value(expr, has_padding_value)
1139 }
1140 })
1141 .collect();
1142
1143 match exprs.len() {
1144 0 | 1 => exprs.pop(),
1145 _ => Some(SeqExpr { span, exprs }.into()),
1146 }
1147 }
1148 Expr::Unary(UnaryExpr {
1149 op: op!("void"),
1150 arg,
1151 ..
1152 }) => ignore_return_value(arg, has_padding_value),
1153 _ => Some(expr),
1154 }
1155}
1156
1157#[allow(clippy::vec_box)]
1160fn ignore_padding_value(exprs: Vec<Box<Expr>>) -> Vec<Box<Expr>> {
1161 let len = exprs.len();
1162
1163 if len > 2 {
1164 exprs
1165 .into_iter()
1166 .enumerate()
1167 .filter_map(|(i, e)| match e.as_ref() {
1168 Expr::Fn(..) | Expr::Arrow(..) | Expr::Lit(..) if i + 1 != len => None,
1169 _ => Some(e),
1170 })
1171 .collect()
1172 } else {
1173 exprs
1174 }
1175}
1176
1177fn will_eat_else_token(s: &Stmt) -> bool {
1178 match s {
1179 Stmt::If(s) => match &s.alt {
1180 Some(alt) => will_eat_else_token(alt),
1181 None => true,
1182 },
1183 Stmt::Block(..) => false,
1185
1186 Stmt::Labeled(s) => will_eat_else_token(&s.body),
1187
1188 Stmt::While(s) => will_eat_else_token(&s.body),
1189
1190 Stmt::For(s) => will_eat_else_token(&s.body),
1191
1192 Stmt::ForIn(s) => will_eat_else_token(&s.body),
1193
1194 Stmt::ForOf(s) => will_eat_else_token(&s.body),
1195
1196 _ => false,
1197 }
1198}
1199
1200#[cfg(test)]
1201mod tests {
1202 use swc_ecma_ast::noop_pass;
1203
1204 fn run_test(from: &str, to: &str) {
1205 crate::tests::test_transform(
1206 Default::default(),
1207 |_| noop_pass(),
1209 from,
1210 to,
1211 true,
1212 Default::default,
1213 );
1214 }
1215
1216 macro_rules! test_fixer {
1217 ($name:ident, $from:literal, $to:literal) => {
1218 #[test]
1219 fn $name() {
1220 run_test($from, $to);
1221 }
1222 };
1223 }
1224
1225 macro_rules! identical {
1226 ($name:ident, $src:literal) => {
1227 test_fixer!($name, $src, $src);
1228 };
1229 }
1230
1231 identical!(fn_expr_position, r#"foo(function(){}())"#);
1232
1233 identical!(fn_decl, r#"function foo(){}"#);
1234
1235 identical!(iife, r#"(function(){})()"#);
1236
1237 identical!(paren_seq_arg, "foo(( _temp = _this = init(), _temp));");
1238
1239 identical!(
1240 regression_01,
1241 "_set(_get_prototype_of(Obj.prototype), _ref = proper.prop, (_superRef = \
1242 +_get(_get_prototype_of(Obj.prototype), _ref, this)) + 1, this, true), _superRef;"
1243 );
1244
1245 identical!(
1246 regression_02,
1247 "var obj = (_obj = {}, _define_property(_obj, 'first', 'first'), _define_property(_obj, \
1248 'second', 'second'), _obj);"
1249 );
1250
1251 identical!(
1252 regression_03,
1253 "_iteratorNormalCompletion = (_step = _iterator.next()).done"
1254 );
1255
1256 identical!(
1257 regression_04,
1258 "var _tmp;
1259const _ref = {}, { c =( _tmp = {}, d = _extends({}, _tmp), _tmp) } = _ref;"
1260 );
1261
1262 identical!(
1263 regression_05,
1264 "for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step \
1265 = _iterator.next()).done); _iteratorNormalCompletion = true) {
1266 i = _step.value;
1267}"
1268 );
1269
1270 identical!(
1271 regression_06,
1272 "
1273 var _tmp;
1274 const { [( _tmp = {}, d = _extends({}, _tmp), _tmp)]: c } = _ref;
1275 "
1276 );
1277
1278 identical!(
1279 regression_07,
1280 "( _temp = super(), _initialize(this), _temp).method();"
1281 );
1282
1283 identical!(regression_08, "exports.bar = exports.default = void 0;");
1284
1285 identical!(regression_09, "({x} = { x: 1 });");
1286
1287 identical!(regression_10, "({x} = { x: 1 }), exports.x = x;");
1288
1289 identical!(regression_11, "(void 0).foo();");
1290
1291 identical!(regression_12, "(function(){})()");
1292
1293 identical!(regression_13, "a || (a = 1);");
1294
1295 identical!(issue_192, "a === true && (a = true)");
1296
1297 identical!(issue_199, "(i - 1).toString()");
1298
1299 identical!(
1300 issue_201_01,
1301 "outer = {
1302 inner: (_obj = {}, _define_property(_obj, ns.EXPORT1, true), _define_property(_obj, \
1303 ns.EXPORT2, true), _obj)
1304};"
1305 );
1306
1307 identical!(issue_207, "a => ({x: 'xxx', y: {a}});");
1308
1309 test_fixer!(
1310 fixer_01,
1311 "var a, b, c, d, e, f;
1312((a, b), (c())) + ((d, e), (f()));
1313",
1314 "var a, b, c, d, e, f;
1315(a, b, c()) + (d, e, f())"
1316 );
1317
1318 test_fixer!(fixer_02, "(b, c), d;", "b, c, d;");
1319
1320 test_fixer!(fixer_03, "((a, b), (c && d)) && e;", "(a, b, c && d) && e;");
1321
1322 test_fixer!(fixer_04, "for ((a, b), c;;) ;", "for(a, b, c;;);");
1323
1324 test_fixer!(
1325 fixer_05,
1326 "var a, b, c = (1), d, e, f = (2);
1327((a, b), c) + ((d, e), f);",
1328 "var a, b, c = 1, d, e, f = 2;
1329(a, b, c) + (d, e, f);"
1330 );
1331
1332 test_fixer!(
1333 fixer_06,
1334 "var a, b, c, d;
1335a = ((b, c), d);",
1336 "var a, b, c, d;
1337a = (b, c, d);"
1338 );
1339
1340 test_fixer!(
1341 fixer_07,
1342 "a => ((b, c) => ((a, b), c));",
1343 "(a)=>(b, c)=>(a, b, c);"
1344 );
1345
1346 test_fixer!(fixer_08, "typeof (((1), a), (2));", "typeof (a, 2)");
1347
1348 test_fixer!(
1349 fixer_09,
1350 "(((a, b), c), d) ? e : f;",
1351 "(a, b, c, d) ? e : f;"
1352 );
1353
1354 test_fixer!(
1355 fixer_10,
1356 "
1357function a() {
1358 return (((void (1)), (void (2))), a), (void (3));
1359}
1360",
1361 "
1362function a() {
1363 return a, void 3;
1364}
1365"
1366 );
1367
1368 test_fixer!(fixer_11, "c && ((((2), (3)), d), b);", "c && (d, b)");
1369
1370 test_fixer!(fixer_12, "(((a, b), c), d) + e;", "(a, b, c, d) + e;");
1371
1372 test_fixer!(fixer_13, "delete (((1), a), (2));", "delete (a, 2)");
1373
1374 test_fixer!(fixer_14, "(1, 2, a)", "1, a");
1375
1376 identical!(issue_231, "'' + (truthy && '?') + truthy;");
1377
1378 identical!(issue_252, "!!(a && b);");
1379
1380 identical!(issue_255, "b < 0 ? (t = b, b = 1) : (t = -b, b = 0);");
1381
1382 identical!(
1383 issue_266_1,
1384 "'Q' + +x1 + ',' + +y1 + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);"
1385 );
1386
1387 test_fixer!(
1388 issue_266_2,
1389 "'Q' + (+x1) + ',' + (+y1) + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);",
1390 "'Q' + +x1 + ',' + +y1 + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);"
1391 );
1392
1393 identical!(
1394 issue_280,
1395 "e.hasOwnProperty(a) && (t = e[a] ? this[a] = t(n) : 'target' === a ? this.target = r : \
1396 this[a] = n[a]);"
1397 );
1398
1399 identical!(
1400 issue_282,
1401 "!(A = [], B = (function () { return classNames; }).apply(exports, A), B !== undefined && \
1402 (module.exports = B));"
1403 );
1404
1405 identical!(
1406 issue_286,
1407 "var SHARED = '__core-js_shared__';
1408var store = global[SHARED] || (global[SHARED] = {});
1409(module.exports = function (key, value) {
1410 return store[key] || (store[key] = value !== undefined ? value : {});
1411})('versions', []).push({
1412 version: core.version,
1413 mode: __webpack_require__(39) ? 'pure' : 'global',
1414 copyright: '© 2018 Denis Pushkarev (zloirock.ru)'
1415});"
1416 );
1417
1418 identical!(
1419 issue_293_1,
1420 "for (var e in a) a.hasOwnProperty(e) && ((b = a[e]) ? this[e] = b(c) : 'target' === e ? \
1421 this.target = d : this[e] = c[e]);"
1422 );
1423
1424 identical!(
1425 issue_293_2,
1426 "(a = rb ? zb(a, c) : Ab(a, c)) ? (b = nb.getPooled(ub.beforeInput, b, c, d), b.data = a, \
1427 Ra(b)) : b = null;"
1428 );
1429
1430 identical!(member_object_lit, "({}).foo");
1431
1432 identical!(member_cond_expr, "(foo ? 1 : 2).foo");
1433
1434 identical!(member_new_exp_1, "(new Foo).foo");
1435
1436 identical!(member_new_exp_2, "new ctor().property");
1437
1438 identical!(member_tagged_tpl, "tag``.foo");
1439
1440 identical!(member_arrow_expr_1, "(a => a).foo");
1441
1442 identical!(member_arrow_expr_2, "((a) => a).foo");
1443
1444 identical!(member_class, "(class Foo{}).foo");
1445
1446 identical!(member_yield, "function* foo(){ (yield bar).baz }");
1447
1448 identical!(member_await, "async function foo(){ (await bar).baz }");
1449
1450 identical!(bin_yield_expr_1, "function* foo(){ (yield foo) && bar }");
1451
1452 identical!(bin_yield_expr_2, "function* foo(){ bar && (yield foo) }");
1453
1454 identical!(bin_seq_expr_1, "(foo(), op) || (seq(), foo)");
1455
1456 identical!(bin_seq_expr_2, "(foo, op) || (seq, foo)");
1457
1458 identical!(cond_object_1, "let foo = {} ? 1 : 2;");
1459
1460 identical!(cond_object_2, "({}) ? 1 : 2;");
1461
1462 identical!(cond_in_cond, "(foo ? 1 : 2) ? 3 : 4");
1463
1464 identical!(arrow_in_cond, "(() => {}) ? 3 : 4");
1465
1466 identical!(unary_cond_arg, "void (foo ? 1 : 2)");
1467
1468 identical!(unary_arrow_arg, "void ((foo) => foo)");
1469
1470 identical!(unary_yield_arg, "(function* foo() { void (yield foo); })()");
1471
1472 identical!(
1473 issue_365,
1474 "const foo = (() => {
1475 return 1
1476})();"
1477 );
1478
1479 identical!(
1480 issue_382_1,
1481 "const myFilter = (arr, filter) => arr.filter(((x) => x) || filter);"
1482 );
1483
1484 identical!(
1485 issue_382_2,
1486 "const myFilter = (arr, filter) => arr.filter(filter || ((x) => x));"
1487 );
1488
1489 identical!(issue_418, "const a = 1 - (1 - 1)");
1490
1491 test_fixer!(
1492 issue_439,
1493 "() => {
1494 return (
1495 Promise.resolve('foo')
1496 // Interfering comment
1497 .then(() => {})
1498 );
1499};",
1500 "() => {
1501 return Promise.resolve('foo')
1502 // Interfering comment
1503 .then(() => {})
1504 ;
1505};"
1506 );
1507
1508 test_fixer!(
1509 issue_451,
1510 "const instance = new (
1511 function() {
1512 function klass(opts) {
1513 this.options = opts;
1514 }
1515 return (Object.assign(klass.prototype, {
1516 method() {}
1517 }), klass);
1518 }()
1519)({ foo: 1 });",
1520 "const instance = new (function() {
1521 function klass(opts) {
1522 this.options = opts;
1523 }
1524 return Object.assign(klass.prototype, {
1525 method () {
1526 }
1527 }), klass;
1528}())({
1529 foo: 1
1530});"
1531 );
1532
1533 test_fixer!(void_and_bin, "(void 0) * 2", "(void 0) * 2");
1534
1535 test_fixer!(new_cond, "new (a ? B : C)()", "new (a ? B : C)()");
1536
1537 identical!(issue_931, "new (eval('Date'))();");
1538
1539 identical!(issue_1002, "new (P || (P = Promise))");
1540
1541 identical!(
1542 issue_1050,
1543 "
1544 (a) => (set) => (elemE(a, set) ? removeE : insertE)(a)(set)
1545 "
1546 );
1547
1548 identical!(
1549 deno_001,
1550 "
1551 var Status;
1552 (function init(Status1) {
1553 })(Status || (Status = {
1554 }));
1555"
1556 );
1557
1558 identical!(issue_1093, "const x = (fnA || fnB)();");
1559
1560 identical!(
1561 issue_1133,
1562 "async function foo() {
1563 const item = await (data === null || data === void 0 ? void 0 : data.foo());
1564 }"
1565 );
1566
1567 identical!(deno_8722, "console.log((true || false) ?? true);");
1568
1569 identical!(
1570 deno_8597,
1571 "
1572 biasInitializer = new (_a = class CustomInit extends Initializer {})();
1573 "
1574 );
1575
1576 test_fixer!(
1577 minifier_001,
1578 "var bitsLength = 3, bitsOffset = 3, what = (len = 0)",
1579 "var bitsLength = 3, bitsOffset = 3, what = len = 0"
1580 );
1581
1582 test_fixer!(minifier_002, "!(function(){})()", "!function(){}()");
1583
1584 identical!(
1585 issue_1397,
1586 "const main = async () => await (await server)()"
1587 );
1588
1589 identical!(deno_9810, "await (bar = Promise.resolve(2));");
1590
1591 identical!(issue_1493, "('a' ?? 'b') || ''");
1592 identical!(call_seq, "let x = ({}, () => 2)();");
1593
1594 test_fixer!(
1595 call_seq_with_padding,
1596 "let x = ({}, (1, 2), () => 2)();",
1597 "let x = ({}, () => 2)();"
1598 );
1599
1600 identical!(
1601 param_seq,
1602 "function t(x = ({}, 2)) {
1603 return x;
1604 }"
1605 );
1606
1607 identical!(
1608 yield_expr_cond,
1609 "function *test1(foo) {
1610 return (yield foo) ? 'bar' : 'baz';
1611 }"
1612 );
1613
1614 identical!(
1615 deno_10487_1,
1616 "var generator = class MultiVector extends (options.baseType||Float32Array) {}"
1617 );
1618
1619 identical!(
1620 deno_10487_2,
1621 "class MultiVector extends (options.baseType||Float32Array) {}"
1622 );
1623
1624 identical!(
1625 extends_nullish_coalescing,
1626 "class Foo extends (Bar ?? class{}) {}"
1627 );
1628
1629 identical!(extends_assign, "class Foo extends (Bar = class{}) {}");
1630
1631 identical!(
1632 extends_logical_or_assin,
1633 "class Foo extends (Bar ||= class{}) {}"
1634 );
1635
1636 identical!(
1637 extends_logical_and_assin,
1638 "class Foo extends (Bar &&= class{}) {}"
1639 );
1640
1641 identical!(
1642 extends_logical_nullish_assin,
1643 "class Foo extends (Bar ??= class{}) {}"
1644 );
1645
1646 identical!(extends_cond, "class Foo extends (true ? Bar : Baz) {}");
1647
1648 identical!(
1649 extends_await_yield,
1650 "
1651 async function* func() {
1652 class A extends (await p) {}
1653 class B extends (yield p) {}
1654 }
1655 "
1656 );
1657
1658 identical!(deno_10668_1, "console.log(null ?? (undefined && true))");
1659
1660 identical!(deno_10668_2, "console.log(null && (undefined ?? true))");
1661
1662 identical!(minifier_003, "(four ** one) ** two");
1663
1664 identical!(minifier_004, "(void 0)(0)");
1665
1666 identical!(issue_1781, "const n = ~~(Math.PI * 10)");
1667
1668 identical!(issue_1789, "+(+1 / 4)");
1669
1670 identical!(new_member_call_1, "new (getObj()).ctor()");
1671 test_fixer!(
1672 new_member_call_2,
1673 "new (getObj().ctor)()",
1674 "new (getObj()).ctor()"
1675 );
1676 test_fixer!(
1677 new_member_call_3,
1678 "new (x.getObj().ctor)()",
1679 "new (x.getObj()).ctor()"
1680 );
1681 identical!(new_call, "new (getCtor())");
1682 test_fixer!(new_member_1, "new obj.ctor()", "new obj.ctor()");
1683 test_fixer!(new_member_2, "new (obj.ctor)", "new obj.ctor");
1684
1685 identical!(
1686 new_await_1,
1687 "async function foo() { new (await getServerImpl())(options) }"
1688 );
1689 test_fixer!(minifier_005, "-(1/0)", "-1/0");
1690
1691 test_fixer!(minifier_006, "-('s'/'b')", "-('s'/'b')");
1692
1693 test_fixer!(minifier_007, "(void 0) === value", "void 0 === value");
1694 test_fixer!(minifier_008, "(size--) && (b = (c))", "size-- && (b = c)");
1695
1696 test_fixer!(
1697 minifier_009,
1698 "(--remaining) || deferred.resolveWith()",
1699 "--remaining || deferred.resolveWith()"
1700 );
1701
1702 test_fixer!(minifier_010, "(--remaining) + ''", "--remaining + ''");
1703
1704 identical!(
1705 if_stmt_001,
1706 "
1707 export const obj = {
1708 each: function (obj, callback, args) {
1709 var i = 0, length = obj.length, isArray = isArraylike(obj);
1710 if (args) {
1711 if (isArray)
1712 for (; i < length && !1 !== callback.apply(obj[i], args); i++);
1713 else
1714 for (i in obj)
1715 if (!1 === callback.apply(obj[i], args))
1716 break
1717 } else if (isArray)
1718 for (; i < length && !1 !== callback.call(obj[i], i, obj[i]); i++);
1719 else
1720 for (i in obj)
1721 if (!1 === callback.call(obj[i], i, obj[i]))
1722 break;
1723 return obj
1724 }
1725 };
1726 "
1727 );
1728
1729 identical!(
1730 issue_2155,
1731 "
1732 async function main() {
1733 let promise;
1734 await (promise || (promise = Promise.resolve('this is a string')));
1735 }
1736 "
1737 );
1738
1739 identical!(issue_2163_1, "() => ({foo} = bar());");
1740
1741 identical!(issue_2163_2, "() => ([foo] = bar());");
1742
1743 identical!(issue_2191, "(-1) ** h");
1744
1745 identical!(
1746 minifier_011,
1747 "
1748 function ItemsList() {
1749 var _ref;
1750
1751 var _temp, _this, _ret;
1752
1753 _class_call_check(this, ItemsList);
1754
1755 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
1756 args[_key] = arguments[_key];
1757 }
1758
1759 return _ret = (_temp = (_this = _possible_constructor_return(this, (_ref = \
1760 ItemsList.__proto__ || Object.getPrototypeOf(ItemsList)).call.apply(_ref, \
1761 [this].concat(args))), _this), _this.storeHighlightedItemReference = function \
1762 (highlightedItem) {
1763 _this.props.onHighlightedItemChange(highlightedItem === null ? null : \
1764 highlightedItem.item);
1765 }, _temp), _possible_constructor_return(_this, _ret);
1766 }
1767 "
1768 );
1769
1770 identical!(
1771 minifier_012,
1772 "
1773 function ItemsList() {
1774 for(var _ref, _temp, _this, _len = arguments.length, args = Array(_len), _key = 0; \
1775 _key < _len; _key++)args[_key] = arguments[_key];
1776 return _possible_constructor_return(_this, (_temp = (_this = \
1777 _possible_constructor_return(this, (_ref = ItemsList.__proto__ || \
1778 Object.getPrototypeOf(ItemsList)).call.apply(_ref, [
1779 this
1780 ].concat(args))), _this), _this.storeHighlightedItemReference = \
1781 function(highlightedItem) {
1782 _this.props.onHighlightedItemChange(null === highlightedItem ? null : \
1783 highlightedItem.item);
1784 }, _temp));
1785 }
1786 "
1787 );
1788
1789 test_fixer!(issue_2550_1, "(1 && { a: 1 })", "1 && { a:1 }");
1790
1791 identical!(issue_2550_2, "({ isNewPrefsActive }) && { a: 1 }");
1792
1793 test_fixer!(paren_of_bin_left_1, "({} && 1)", "({}) && 1");
1794 identical!(paren_of_bin_left_2, "({}) && 1");
1795 test_fixer!(
1796 paren_of_bin_left_3,
1797 "(function () {} || 2)",
1798 "(function () {}) || 2"
1799 );
1800 identical!(paren_of_bin_left_4, "(function () {}) || 2");
1801
1802 test_fixer!(paren_of_bin_left_5, "(class{} ?? 3)", "(class{}) ?? 3");
1803 identical!(paren_of_bin_left_6, "(class{}) ?? 3");
1804
1805 identical!(issue_4761, "x = { ...(0, foo) }");
1806
1807 identical!(issue_4914, "(a ?? b)?.()");
1808
1809 identical!(issue_5109_1, "(0, b)?.()");
1810 identical!(issue_5109_2, "1 + (0, b)?.()");
1811 identical!(issue_5109_3, "(0, a)() ? undefined : (0, b)?.()");
1812
1813 identical!(
1814 issue_5313,
1815 "
1816 async function* foo() {
1817 (await a)();
1818 (yield b)();
1819 }
1820 "
1821 );
1822
1823 identical!(issue_5417, "console.log(a ?? b ?? c)");
1824
1825 identical!(bin_and_unary, "console.log(a++ && b--)");
1826
1827 test_fixer!(
1828 issue_11322,
1829 "((function () { })() && a, b)",
1830 "(function () { })() && a, b"
1831 );
1832
1833 test_fixer!(
1834 issue_11322_simple,
1835 "(function () { })() && a",
1836 "(function () { })() && a"
1837 );
1838
1839 test_fixer!(
1840 issue_11322_stmt,
1841 "(function () { })() && a;",
1842 "(function () { })() && a;"
1843 );
1844}