1use swc_common::Spanned;
2use swc_ecma_ast::*;
3use swc_ecma_codegen_macros::node_impl;
4
5use crate::util::{EndsWithAlphaNum, StartsWithAlphaNum};
6
7#[node_impl]
8impl MacroNode for Stmt {
9 fn emit(&mut self, emitter: &mut Macro) -> Result {
10 match self {
11 Stmt::Expr(ref e) => emit!(e),
12 Stmt::Block(ref e) => {
13 emit!(e);
14 return Ok(());
15 }
16 Stmt::Empty(ref e) => emit!(e),
17 Stmt::Debugger(ref e) => emit!(e),
18 Stmt::With(ref e) => emit!(e),
19 Stmt::Return(ref e) => emit!(e),
20 Stmt::Labeled(ref e) => emit!(e),
21 Stmt::Break(ref e) => emit!(e),
22 Stmt::Continue(ref e) => emit!(e),
23 Stmt::If(ref e) => emit!(e),
24 Stmt::Switch(ref e) => emit!(e),
25 Stmt::Throw(ref e) => emit!(e),
26 Stmt::Try(ref e) => emit!(e),
27 Stmt::While(ref e) => emit!(e),
28 Stmt::DoWhile(ref e) => emit!(e),
29 Stmt::For(ref e) => emit!(e),
30 Stmt::ForIn(ref e) => emit!(e),
31 Stmt::ForOf(ref e) => emit!(e),
32 Stmt::Decl(Decl::Var(e)) => {
33 emit!(e);
34 semi!(emitter);
35 }
36 Stmt::Decl(e @ Decl::Using(..)) => {
37 emit!(e);
38 semi!(emitter);
39 }
40 Stmt::Decl(ref e) => emit!(e),
41 }
42 if emitter.comments.is_some() {
43 emitter.emit_trailing_comments_of_pos(self.span().hi(), true, true)?;
44 }
45
46 if !emitter.cfg.minify {
47 emitter.wr.write_line()?;
48 }
49
50 Ok(())
51 }
52}
53
54#[node_impl]
55impl MacroNode for EmptyStmt {
56 fn emit(&mut self, emitter: &mut Macro) -> Result {
57 emitter.emit_leading_comments_of_span(self.span(), false)?;
58
59 emitter.wr.write_punct(None, ";")?;
60
61 Ok(())
62 }
63}
64
65#[node_impl]
66impl MacroNode for BlockStmt {
67 fn emit(&mut self, emitter: &mut Macro) -> Result {
68 emitter.emit_block_stmt_inner(self, false)?;
69
70 Ok(())
71 }
72}
73
74#[node_impl]
75impl MacroNode for ExprStmt {
76 fn emit(&mut self, emitter: &mut Macro) -> Result {
77 emitter.emit_leading_comments_of_span(self.span, false)?;
78
79 emitter.emit_trailing_comments_of_pos_with(self.span.hi, true, |emitter| {
80 emit!(self.expr);
81
82 semi!(emitter);
83
84 Ok(())
85 })?;
86
87 Ok(())
88 }
89}
90
91#[node_impl]
92impl MacroNode for DebuggerStmt {
93 fn emit(&mut self, emitter: &mut Macro) -> Result {
94 emitter.wr.commit_pending_semi()?;
95
96 emitter.emit_leading_comments_of_span(self.span(), false)?;
97
98 keyword!(emitter, self.span, "debugger");
99 semi!(emitter);
100
101 Ok(())
102 }
103}
104
105#[node_impl]
106impl MacroNode for WithStmt {
107 fn emit(&mut self, emitter: &mut Macro) -> Result {
108 emitter.wr.commit_pending_semi()?;
109
110 srcmap!(emitter, self, true);
111
112 keyword!(emitter, "with");
113 formatting_space!(emitter);
114
115 punct!(emitter, "(");
116 emit!(self.obj);
117 punct!(emitter, ")");
118
119 emit!(self.body);
120
121 Ok(())
122 }
123}
124
125#[node_impl]
126impl MacroNode for ReturnStmt {
127 fn emit(&mut self, emitter: &mut Macro) -> Result {
128 emitter.wr.commit_pending_semi()?;
129
130 emitter.emit_leading_comments_of_span(self.span, false)?;
131
132 srcmap!(emitter, self, true);
133
134 keyword!(emitter, "return");
135
136 if let Some(arg) = self.arg.as_deref() {
137 let need_paren = self
138 .arg
139 .as_deref()
140 .map(|expr| emitter.has_leading_comment(expr))
141 .unwrap_or(false);
142 if need_paren {
143 punct!(emitter, "(");
144 } else if arg.starts_with_alpha_num() {
145 space!(emitter);
146 } else {
147 formatting_space!(emitter);
148 }
149
150 emit!(arg);
151 if need_paren {
152 punct!(emitter, ")");
153 }
154 }
155
156 semi!(emitter);
157
158 Ok(())
159 }
160}
161
162#[node_impl]
163impl MacroNode for LabeledStmt {
164 fn emit(&mut self, emitter: &mut Macro) -> Result {
165 emitter.wr.commit_pending_semi()?;
166
167 emit!(self.label);
168
169 punct!(emitter, ":");
171 formatting_space!(emitter);
172
173 emit!(self.body);
174
175 Ok(())
176 }
177}
178
179#[node_impl]
180impl MacroNode for SwitchStmt {
181 fn emit(&mut self, emitter: &mut Macro) -> Result {
182 emitter.wr.commit_pending_semi()?;
183
184 emitter.emit_leading_comments_of_span(self.span(), false)?;
185
186 srcmap!(emitter, self, true);
187
188 keyword!(emitter, "switch");
189
190 punct!(emitter, "(");
191 emit!(self.discriminant);
192 punct!(emitter, ")");
193
194 punct!(emitter, "{");
195 emitter.emit_list(self.span(), Some(&self.cases), ListFormat::CaseBlockClauses)?;
196
197 srcmap!(emitter, self, false, true);
198 punct!(emitter, "}");
199
200 Ok(())
201 }
202}
203
204#[node_impl]
205impl MacroNode for CatchClause {
206 fn emit(&mut self, emitter: &mut Macro) -> Result {
207 emitter.emit_leading_comments_of_span(self.span(), false)?;
208
209 srcmap!(emitter, self, true);
210
211 keyword!(emitter, "catch");
212
213 formatting_space!(emitter);
214
215 if let Some(param) = &self.param {
216 punct!(emitter, "(");
217 emit!(param);
218 punct!(emitter, ")");
219 }
220
221 formatting_space!(emitter);
222
223 emit!(self.body);
224
225 Ok(())
226 }
227}
228
229#[node_impl]
230impl MacroNode for SwitchCase {
231 fn emit(&mut self, emitter: &mut Macro) -> Result {
232 emitter.emit_leading_comments_of_span(self.span(), false)?;
233
234 srcmap!(emitter, self, true);
235
236 if let Some(ref test) = self.test {
237 keyword!(emitter, "case");
238
239 let starts_with_alpha_num = test.starts_with_alpha_num();
240
241 if starts_with_alpha_num {
242 space!(emitter);
243 } else {
244 formatting_space!(emitter);
245 }
246
247 emit!(test);
248 } else {
249 keyword!(emitter, "default");
250 }
251
252 let emit_as_single_stmt = self.cons.len() == 1 && {
253 self.is_synthesized()
255 || self.cons[0].is_synthesized()
256 || emitter
257 .cm
258 .is_on_same_line(self.span().lo(), self.cons[0].span().lo())
259 };
260
261 let mut format = ListFormat::CaseOrDefaultClauseStatements;
262 if emit_as_single_stmt {
263 punct!(emitter, ":");
264 space!(emitter);
265 format &= !(ListFormat::MultiLine | ListFormat::Indented);
266 } else {
267 punct!(emitter, ":");
268 }
269 emitter.emit_list(self.span(), Some(&self.cons), format)?;
270
271 Ok(())
272 }
273}
274
275#[node_impl]
276impl MacroNode for ThrowStmt {
277 fn emit(&mut self, emitter: &mut Macro) -> Result {
278 emitter.emit_leading_comments_of_span(self.span(), false)?;
279
280 srcmap!(emitter, self, true);
281
282 keyword!(emitter, "throw");
283
284 {
285 let need_paren = emitter.has_leading_comment(&self.arg);
286 if need_paren {
287 punct!(emitter, "(");
288 } else if self.arg.starts_with_alpha_num() {
289 space!(emitter);
290 } else {
291 formatting_space!(emitter);
292 }
293
294 emit!(self.arg);
295 if need_paren {
296 punct!(emitter, ")");
297 }
298 }
299 semi!(emitter);
300
301 Ok(())
302 }
303}
304
305#[node_impl]
306impl MacroNode for TryStmt {
307 fn emit(&mut self, emitter: &mut Macro) -> Result {
308 emitter.emit_leading_comments_of_span(self.span(), false)?;
309
310 emitter.wr.commit_pending_semi()?;
311
312 srcmap!(emitter, self, true);
313
314 keyword!(emitter, "try");
315
316 formatting_space!(emitter);
317 emit!(self.block);
318
319 if let Some(ref catch) = self.handler {
320 formatting_space!(emitter);
321 emit!(catch);
322 }
323
324 if let Some(ref finally) = self.finalizer {
325 formatting_space!(emitter);
326 keyword!(emitter, "finally");
327 emit!(finally);
329 }
330
331 Ok(())
332 }
333}
334
335#[node_impl]
336impl MacroNode for WhileStmt {
337 fn emit(&mut self, emitter: &mut Macro) -> Result {
338 emitter.wr.commit_pending_semi()?;
339
340 emitter.emit_leading_comments_of_span(self.span(), false)?;
341
342 srcmap!(emitter, self, true);
343
344 keyword!(emitter, "while");
345
346 punct!(emitter, "(");
347 emit!(self.test);
348 punct!(emitter, ")");
349
350 emit!(self.body);
351
352 Ok(())
353 }
354}
355
356#[node_impl]
357impl MacroNode for DoWhileStmt {
358 fn emit(&mut self, emitter: &mut Macro) -> Result {
359 emitter.wr.commit_pending_semi()?;
360
361 emitter.emit_leading_comments_of_span(self.span(), false)?;
362
363 srcmap!(emitter, self, true);
364
365 keyword!(emitter, "do");
366 if self.body.starts_with_alpha_num() {
367 space!(emitter);
368 } else {
369 formatting_space!(emitter)
370 }
371 emit!(self.body);
372
373 keyword!(emitter, "while");
374
375 formatting_space!(emitter);
376
377 punct!(emitter, "(");
378 emit!(self.test);
379 punct!(emitter, ")");
380
381 if emitter.cfg.target <= EsVersion::Es5 {
382 semi!(emitter);
383 }
384
385 srcmap!(emitter, self, false);
386
387 Ok(())
388 }
389}
390
391#[node_impl]
392impl MacroNode for ForStmt {
393 fn emit(&mut self, emitter: &mut Macro) -> Result {
394 emitter.wr.commit_pending_semi()?;
395
396 emitter.emit_leading_comments_of_span(self.span(), false)?;
397
398 srcmap!(emitter, self, true);
399
400 keyword!(emitter, "for");
401
402 punct!(emitter, "(");
403 opt!(emitter, self.init);
404 emitter.wr.write_punct(None, ";")?;
405 opt_leading_space!(emitter, self.test);
406 emitter.wr.write_punct(None, ";")?;
407 opt_leading_space!(emitter, self.update);
408 punct!(emitter, ")");
409
410 emit!(self.body);
411
412 Ok(())
413 }
414}
415
416#[node_impl]
417impl MacroNode for ForInStmt {
418 fn emit(&mut self, emitter: &mut Macro) -> Result {
419 emitter.wr.commit_pending_semi()?;
420
421 emitter.emit_leading_comments_of_span(self.span(), false)?;
422
423 srcmap!(emitter, self, true);
424
425 keyword!(emitter, "for");
426
427 punct!(emitter, "(");
428 emit!(self.left);
429
430 if self.left.ends_with_alpha_num() {
431 space!(emitter);
432 } else {
433 formatting_space!(emitter);
434 }
435 keyword!(emitter, "in");
436
437 {
438 let starts_with_alpha_num = self.right.starts_with_alpha_num();
439
440 if starts_with_alpha_num {
441 space!(emitter);
442 } else {
443 formatting_space!(emitter)
444 }
445 emit!(self.right);
446 }
447
448 punct!(emitter, ")");
449
450 emit!(self.body);
451
452 Ok(())
453 }
454}
455
456#[node_impl]
457impl MacroNode for ForOfStmt {
458 fn emit(&mut self, emitter: &mut Macro) -> Result {
459 emitter.wr.commit_pending_semi()?;
460
461 emitter.emit_leading_comments_of_span(self.span(), false)?;
462
463 srcmap!(emitter, self, true);
464
465 keyword!(emitter, "for");
466
467 if self.is_await {
468 space!(emitter);
469 keyword!(emitter, "await");
470 }
471 formatting_space!(emitter);
472 punct!(emitter, "(");
473 emit!(self.left);
474 if self.left.ends_with_alpha_num() {
475 space!(emitter);
476 } else {
477 formatting_space!(emitter);
478 }
479 keyword!(emitter, "of");
480
481 {
482 let starts_with_alpha_num = self.right.starts_with_alpha_num();
483
484 if starts_with_alpha_num {
485 space!(emitter);
486 } else {
487 formatting_space!(emitter)
488 }
489 emit!(self.right);
490 }
491 punct!(emitter, ")");
492 emit!(self.body);
493
494 Ok(())
495 }
496}
497
498#[node_impl]
499impl MacroNode for BreakStmt {
500 fn emit(&mut self, emitter: &mut Macro) -> Result {
501 emitter.wr.commit_pending_semi()?;
502
503 srcmap!(emitter, self, true);
504
505 keyword!(emitter, "break");
506
507 if let Some(ref label) = self.label {
508 space!(emitter);
509 emit!(label);
510 }
511
512 semi!(emitter);
513
514 Ok(())
515 }
516}
517
518#[node_impl]
519impl MacroNode for ContinueStmt {
520 fn emit(&mut self, emitter: &mut Macro) -> Result {
521 emitter.wr.commit_pending_semi()?;
522
523 srcmap!(emitter, self, true);
524
525 keyword!(emitter, "continue");
526
527 if let Some(ref label) = self.label {
528 space!(emitter);
529 emit!(label);
530 }
531
532 semi!(emitter);
533
534 Ok(())
535 }
536}
537
538#[node_impl]
539impl MacroNode for IfStmt {
540 fn emit(&mut self, emitter: &mut Macro) -> Result {
541 emitter.emit_leading_comments_of_span(self.span(), false)?;
542
543 emitter.wr.commit_pending_semi()?;
544
545 srcmap!(emitter, self, true);
546
547 keyword!(emitter, "if");
548
549 formatting_space!(emitter);
550 punct!(emitter, "(");
551 emit!(self.test);
552 punct!(emitter, ")");
553 formatting_space!(emitter);
554
555 let is_cons_block = match *self.cons {
556 Stmt::Block(..) => true,
557 _ => false,
558 };
559
560 emit!(self.cons);
561
562 if let Some(ref alt) = self.alt {
563 if is_cons_block {
564 formatting_space!(emitter);
565 }
566 keyword!(emitter, "else");
567 if alt.starts_with_alpha_num() {
568 space!(emitter);
569 } else {
570 formatting_space!(emitter);
571 }
572 emit!(alt);
573 }
574
575 Ok(())
576 }
577}
578
579#[node_impl]
580impl MacroNode for ModuleExportName {
581 fn emit(&mut self, emitter: &mut Macro) -> Result {
582 match self {
583 ModuleExportName::Ident(ident) => emit!(ident),
584 ModuleExportName::Str(s) => emit!(s),
585 }
586
587 Ok(())
588 }
589}
590
591#[node_impl]
592impl MacroNode for VarDeclOrExpr {
593 fn emit(&mut self, emitter: &mut Macro) -> Result {
594 match self {
595 VarDeclOrExpr::Expr(node) => emit!(node),
596 VarDeclOrExpr::VarDecl(node) => emit!(node),
597 }
598
599 Ok(())
600 }
601}
602
603#[cfg(test)]
607mod tests {
608 use crate::tests::{assert_min, assert_pretty};
609
610 #[test]
611 fn block_statement() {
612 assert_min("{}", "{}");
613 assert_min("{foo;}", "{foo}");
614 }
615
616 #[test]
617 fn empty_block_statement() {
618 assert_pretty("{\n}", "{}");
619 assert_pretty("{\n//todo\n}", "{\n//todo\n}");
620
621 assert_pretty(
622 "try {\n\n} catch {\n // Pass\n}\n",
623 "try {} catch {\n// Pass\n}",
624 );
625 }
626
627 #[test]
628 fn empty_object_lit() {
629 assert_pretty("Object.assign({\n}, a, b);", "Object.assign({}, a, b);");
630 }
631
632 #[test]
633 fn labeled_statement() {
634 assert_min("foo: {}", "foo:{}");
635 assert_min("foo: bar;", "foo:bar");
636 }
637
638 #[test]
639 fn function_statement() {
640 assert_min("function foo() {}", "function foo(){}");
641 }
642
643 #[test]
644 fn declaration_statement() {
645 assert_min("var foo;", "var foo");
646 assert_min("let foo;", "let foo");
647 assert_min("var foo = 10;", "var foo=10");
648 assert_min("let foo = 10;", "let foo=10");
649 assert_min("const foo = 10;", "const foo=10");
650 assert_min("var foo, bar;", "var foo,bar");
651 assert_min("let foo, bar;", "let foo,bar");
652 assert_min("var foo = 10, bar = 20;", "var foo=10,bar=20");
653 assert_min("let foo = 10, bar = 20;", "let foo=10,bar=20");
654 assert_min("const foo = 10, bar = 20;", "const foo=10,bar=20");
655 assert_min("const a = {...foo};", "const a={...foo}");
656 }
657
658 #[test]
659 fn if_statement() {
660 assert_min("if (true) foo;", "if(true)foo");
661 assert_min("if (true) { foo; }", "if(true){foo}");
662 assert_min("if (true) foo; else bar;", "if(true)foo;else bar");
663 assert_min("if (true) { foo; } else { bar; }", "if(true){foo}else{bar}");
664 assert_min("if (true) foo; else { bar; }", "if(true)foo;else{bar}");
665 assert_min("if (true) { foo; } else bar;", "if(true){foo}else bar");
666 assert_min("if (true) y(); else x++;", "if(true)y();else x++");
667 assert_min("if (true) y(); else x--;", "if(true)y();else x--");
668 }
669
670 #[test]
671 fn while_statement() {
672 assert_min("while (true) foo;", "while(true)foo");
673 assert_min("while (true) { foo; }", "while(true){foo}");
674 }
675
676 #[test]
677 fn do_statement() {
678 assert_min("do { foo; } while (true)", "do{foo}while(true)");
679 assert_min("do foo; while (true)", "do foo;while(true)");
680 }
681
682 #[test]
683 fn for_statement() {
684 assert_min("for (var i = 0; i < 10; i++) {}", "for(var i=0;i<10;i++){}");
685 assert_min("for (i = 0; i < 10; i++) {}", "for(i=0;i<10;i++){}");
686 assert_min("for (;;) {}", "for(;;){}");
687 assert_min("for (foo in bar){}", "for(foo in bar){}");
688 assert_min("for (let foo in bar){}", "for(let foo in bar){}");
689 assert_min("for (foo of bar){}", "for(foo of bar){}");
690 assert_min("for (let foo of bar){}", "for(let foo of bar){}");
691 }
692
693 #[test]
694 fn for_statement_pretty() {
695 assert_pretty(
696 "for (var i = 0; i < 10; i++) {}",
697 "for(var i = 0; i < 10; i++){}",
698 );
699 assert_pretty("for (i = 0; i < 10; i++) {}", "for(i = 0; i < 10; i++){}");
700 assert_pretty("for (;;) {}", "for(;;){}");
701 assert_pretty("for (foo in bar){}", "for(foo in bar){}");
702 assert_pretty("for (let foo in bar){}", "for(let foo in bar){}");
703 assert_pretty("for (foo of bar){}", "for (foo of bar){}");
704 assert_pretty("for (let foo of bar){}", "for (let foo of bar){}");
705 }
706
707 #[test]
708 fn import() {
709 assert_min(
710 "import colors, { color } from 'patterns/colors';",
711 "import colors,{color}from\"patterns/colors\"",
712 );
713 assert_pretty(
714 "import colors, { color } from 'patterns/colors';",
715 "import colors, { color } from 'patterns/colors';",
716 );
717 }
718
719 #[test]
720 fn issue_204_01() {
721 assert_min(r"'\r\n';", r#""\r\n""#);
722 }
723
724 #[test]
725 fn issue_204_02() {
726 assert_min(r"const a = fn() + '\r\n';", r#"const a=fn()+"\r\n""#);
727 }
728
729 #[test]
730 fn issue_177() {
731 assert_min(
732 "#!/usr/bin/env node
733let x = 4;",
734 "#!/usr/bin/env node
735let x=4",
736 );
737 }
738
739 #[test]
740 fn issue_197() {
741 assert_pretty(
742 "// type Foo = 'Oops';
743const Link = 'Boo';",
744 "// type Foo = 'Oops';
745const Link = 'Boo';",
746 );
747 }
748
749 #[test]
750 fn issue_266() {
751 assert_min(
752 "'Q' + +x1 + ',' + +y1 + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);",
753 "\"Q\"+ +x1+\",\"+ +y1+\",\"+(this._x1=+x)+\",\"+(this._y1=+y)",
754 );
755 }
756}