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