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