1#![recursion_limit = "1024"]
2#![deny(clippy::all)]
3#![deny(unused)]
4#![allow(clippy::match_like_matches_macro)]
5#![allow(clippy::nonminimal_bool)]
6#![allow(non_local_definitions)]
7
8use std::{borrow::Cow, fmt::Write, io, ops::Deref, str};
9
10use compact_str::{format_compact, CompactString};
11use memchr::memmem::Finder;
12use once_cell::sync::Lazy;
13use swc_atoms::Atom;
14use swc_common::{
15 comments::{CommentKind, Comments},
16 sync::Lrc,
17 BytePos, SourceMap, SourceMapper, Span, Spanned, DUMMY_SP,
18};
19use swc_ecma_ast::*;
20use swc_ecma_codegen_macros::node_impl;
21
22pub use self::config::Config;
23use self::{text_writer::WriteJs, util::StartsWithAlphaNum};
24use crate::util::EndsWithAlphaNum;
25
26#[macro_use]
27pub mod macros;
28mod class;
29mod comments;
30mod config;
31mod decl;
32mod expr;
33mod jsx;
34mod lit;
35mod module_decls;
36mod object;
37mod pat;
38mod stmt;
39#[cfg(test)]
40mod tests;
41pub mod text_writer;
42mod typescript;
43pub mod util;
44
45pub type Result = io::Result<()>;
46
47pub fn to_code_default(
49 cm: Lrc<SourceMap>,
50 comments: Option<&dyn Comments>,
51 node: &impl Node,
52) -> String {
53 let mut buf = std::vec::Vec::new();
54 {
55 let mut emitter = Emitter {
56 cfg: Default::default(),
57 cm: cm.clone(),
58 comments,
59 wr: text_writer::JsWriter::new(cm, "\n", &mut buf, None),
60 };
61 node.emit_with(&mut emitter).unwrap();
62 }
63
64 String::from_utf8(buf).expect("codegen generated non-utf8 output")
65}
66
67pub fn to_code_with_comments(comments: Option<&dyn Comments>, node: &impl Node) -> String {
69 to_code_default(Default::default(), comments, node)
70}
71
72pub fn to_code(node: &impl Node) -> String {
74 to_code_with_comments(None, node)
75}
76
77pub trait Node: Spanned {
78 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
79 where
80 W: WriteJs,
81 S: SourceMapper + SourceMapperExt;
82}
83impl<N: Node> Node for Box<N> {
84 #[inline]
85 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
86 where
87 W: WriteJs,
88 S: SourceMapper + SourceMapperExt,
89 {
90 (**self).emit_with(e)
91 }
92}
93impl<N: Node> Node for &N {
94 #[inline]
95 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
96 where
97 W: WriteJs,
98 S: SourceMapper + SourceMapperExt,
99 {
100 (**self).emit_with(e)
101 }
102}
103
104pub struct Emitter<'a, W, S: SourceMapper>
105where
106 W: WriteJs,
107 S: SourceMapperExt,
108{
109 pub cfg: config::Config,
110 pub cm: Lrc<S>,
111 pub comments: Option<&'a dyn Comments>,
112 pub wr: W,
113}
114
115enum CowStr<'a> {
116 Borrowed(&'a str),
117 Owned(CompactString),
118}
119
120impl Deref for CowStr<'_> {
121 type Target = str;
122
123 fn deref(&self) -> &str {
124 match self {
125 CowStr::Borrowed(s) => s,
126 CowStr::Owned(s) => s.as_str(),
127 }
128 }
129}
130
131static NEW_LINE_TPL_REGEX: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"\\n|\n").unwrap());
132
133impl<W, S: SourceMapper> Emitter<'_, W, S>
134where
135 W: WriteJs,
136 S: SourceMapperExt,
137{
138 pub fn emit_program(&mut self, node: &Program) -> Result {
139 node.emit_with(self)
140 }
141
142 pub fn emit_module(&mut self, node: &Module) -> Result {
143 node.emit_with(self)
144 }
145
146 pub fn emit_script(&mut self, node: &Script) -> Result {
147 node.emit_with(self)
148 }
149
150 fn emit_new(&mut self, node: &NewExpr, should_ignore_empty_args: bool) -> Result {
151 self.wr.commit_pending_semi()?;
152
153 self.emit_leading_comments_of_span(node.span(), false)?;
154
155 srcmap!(self, node, true);
156
157 keyword!(self, "new");
158
159 let starts_with_alpha_num = node.callee.starts_with_alpha_num();
160
161 if starts_with_alpha_num {
162 space!(self);
163 } else {
164 formatting_space!(self);
165 }
166 emit!(self, node.callee);
167
168 if let Some(type_args) = &node.type_args {
169 emit!(self, type_args);
170 }
171
172 if let Some(ref args) = node.args {
173 if !(self.cfg.minify && args.is_empty() && should_ignore_empty_args) {
174 punct!(self, "(");
175 self.emit_expr_or_spreads(node.span(), args, ListFormat::NewExpressionArguments)?;
176 punct!(self, ")");
177 }
178 }
179
180 if !should_ignore_empty_args && self.comments.is_some() {
185 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
186 }
187
188 Ok(())
189 }
190
191 fn emit_template_for_tagged_template(&mut self, node: &Tpl) -> Result {
192 debug_assert!(node.quasis.len() == node.exprs.len() + 1);
193
194 self.emit_leading_comments_of_span(node.span(), false)?;
195
196 srcmap!(self, node, true);
197
198 punct!(self, "`");
199
200 for i in 0..(node.quasis.len() + node.exprs.len()) {
201 if i % 2 == 0 {
202 self.emit_template_element_for_tagged_template(&node.quasis[i / 2])?;
203 } else {
204 punct!(self, "${");
205 emit!(self, node.exprs[i / 2]);
206 punct!(self, "}");
207 }
208 }
209
210 punct!(self, "`");
211
212 srcmap!(self, node, false);
213
214 Ok(())
215 }
216
217 fn emit_atom(&mut self, span: Span, value: &Atom) -> Result {
218 self.wr.write_str_lit(span, value)?;
219
220 Ok(())
221 }
222
223 #[inline(never)]
225 fn emit_bin_expr_trailing(&mut self, node: &BinExpr) -> Result {
226 let is_kwd_op = match node.op {
229 op!("in") | op!("instanceof") => true,
230 _ => false,
231 };
232
233 let need_pre_space = if self.cfg.minify {
234 if is_kwd_op {
235 node.left.ends_with_alpha_num()
236 } else {
237 match *node.left {
239 Expr::Update(UpdateExpr {
240 prefix: false, op, ..
241 }) => matches!(
242 (op, node.op),
243 (op!("--"), op!(">") | op!(">>") | op!(">>>") | op!(">="))
244 ),
245 _ => false,
246 }
247 }
248 } else {
249 is_kwd_op
250 || match *node.left {
251 Expr::Update(UpdateExpr { prefix: false, .. }) => true,
252 _ => false,
253 }
254 };
255 if need_pre_space {
256 space!(self);
257 } else {
258 formatting_space!(self);
259 }
260 operator!(self, node.op.as_str());
261
262 let need_post_space = if self.cfg.minify {
263 if is_kwd_op {
264 node.right.starts_with_alpha_num()
265 } else if node.op == op!("/") {
266 let span = node.right.span();
267
268 span.is_pure()
269 || self
270 .comments
271 .is_some_and(|comments| comments.has_leading(node.right.span().lo))
272 } else {
273 require_space_before_rhs(&node.right, &node.op)
274 }
275 } else {
276 is_kwd_op
277 || match *node.right {
278 Expr::Unary(..) | Expr::Update(UpdateExpr { prefix: true, .. }) => true,
279 _ => false,
280 }
281 };
282 if need_post_space {
283 space!(self);
284 } else {
285 formatting_space!(self);
286 }
287 emit!(self, node.right);
288
289 Ok(())
290 }
291
292 fn emit_fn_trailing(&mut self, node: &Function) -> Result {
294 if let Some(type_params) = &node.type_params {
295 emit!(self, type_params);
296 }
297
298 punct!(self, "(");
299 self.emit_list(node.span, Some(&node.params), ListFormat::CommaListElements)?;
300 punct!(self, ")");
301
302 if let Some(ty) = &node.return_type {
303 punct!(self, ":");
304 formatting_space!(self);
305 emit!(self, ty);
306 }
307
308 if let Some(body) = &node.body {
309 formatting_space!(self);
310 self.emit_block_stmt_inner(body, true)?;
311 } else {
312 semi!(self);
313 }
314
315 Ok(())
316
317 }
319
320 fn emit_template_element_for_tagged_template(&mut self, node: &TplElement) -> Result {
321 srcmap!(self, node, true);
322
323 self.wr.write_str_lit(DUMMY_SP, &node.raw)?;
324
325 srcmap!(self, node, false);
326
327 Ok(())
328 }
329
330 fn emit_expr_or_spreads(
331 &mut self,
332 parent_node: Span,
333 nodes: &[ExprOrSpread],
334 format: ListFormat,
335 ) -> Result {
336 self.emit_list(parent_node, Some(nodes), format)
337 }
338
339 fn emit_ident_like(&mut self, span: Span, sym: &Atom, optional: bool) -> Result {
340 self.emit_leading_comments_of_span(span, false)?;
342
343 self.wr.commit_pending_semi()?;
345
346 srcmap!(self, span, true);
347 if self.cfg.ascii_only {
350 if self.wr.can_ignore_invalid_unicodes() {
351 self.wr
352 .write_symbol(DUMMY_SP, &get_ascii_only_ident(sym, false, self.cfg.target))?;
353 } else {
354 self.wr.write_symbol(
355 DUMMY_SP,
356 &get_ascii_only_ident(&handle_invalid_unicodes(sym), false, self.cfg.target),
357 )?;
358 }
359 } else if self.wr.can_ignore_invalid_unicodes() {
360 self.wr.write_symbol(DUMMY_SP, sym)?;
361 } else {
362 self.wr
363 .write_symbol(DUMMY_SP, &handle_invalid_unicodes(sym))?;
364 }
365
366 if optional {
367 punct!(self, "?");
368 }
369
370 Ok(())
376 }
377
378 fn emit_list<N: Node>(
379 &mut self,
380 parent_node: Span,
381 children: Option<&[N]>,
382 format: ListFormat,
383 ) -> Result {
384 self.emit_list5(
385 parent_node,
386 children,
387 format,
388 0,
389 children.map(|c| c.len()).unwrap_or(0),
390 )
391 }
392
393 #[inline(never)]
395 fn emit_first_of_list5(
396 &mut self,
397 parent_node: Span,
398 children: Option<usize>,
399 format: ListFormat,
400 start: usize,
401 count: usize,
402 ) -> Option<Result> {
403 if children.is_none() && format.contains(ListFormat::OptionalIfUndefined) {
404 return Some(Ok(()));
405 }
406
407 let is_empty = children.is_none() || start > children.unwrap() || count == 0;
408 if is_empty && format.contains(ListFormat::OptionalIfEmpty) {
409 return Some(Ok(()));
410 }
411
412 if format.contains(ListFormat::BracketsMask) {
413 if let Err(err) = self.wr.write_punct(None, format.opening_bracket()) {
414 return Some(Err(err));
415 }
416
417 if is_empty {
418 if let Err(err) = self.emit_trailing_comments_of_pos(
419 {
420 parent_node.lo()
423 },
424 true,
425 false,
426 ) {
427 return Some(Err(err));
428 }
429 }
430 }
431
432 None
433 }
434
435 #[inline(never)]
437 fn emit_pre_child_for_list5(
438 &mut self,
439 parent_node: Span,
440 format: ListFormat,
441 previous_sibling: Option<Span>,
442 child: Span,
443 should_decrease_indent_after_emit: &mut bool,
444 should_emit_intervening_comments: &mut bool,
445 ) -> Result {
446 if let Some(previous_sibling) = previous_sibling {
448 if format.contains(ListFormat::DelimitersMask)
456 && previous_sibling.hi != parent_node.hi()
457 && self.comments.is_some()
458 {
459 self.emit_leading_comments(previous_sibling.hi(), true)?;
460 }
461
462 self.write_delim(format)?;
463
464 if self.cm.should_write_separating_line_terminator(
467 Some(previous_sibling),
468 Some(child),
469 format,
470 ) {
471 if (format & (ListFormat::LinesMask | ListFormat::Indented))
474 == ListFormat::SingleLine
475 && !self.cfg.minify
476 {
477 self.wr.increase_indent()?;
478 *should_decrease_indent_after_emit = true;
479 }
480
481 if !self.cfg.minify {
482 self.wr.write_line()?;
483 }
484 *should_emit_intervening_comments = false;
485 } else if format.contains(ListFormat::SpaceBetweenSiblings) {
486 formatting_space!(self);
487 }
488 }
489
490 Ok(())
491 }
492
493 #[inline(never)]
495 fn emit_list_finisher_of_list5(
496 &mut self,
497 parent_node: Span,
498 format: ListFormat,
499 previous_sibling: Option<Span>,
500 last_child: Option<Span>,
501 ) -> Result {
502 let has_trailing_comma = format.contains(ListFormat::ForceTrailingComma)
504 || format.contains(ListFormat::AllowTrailingComma) && {
505 if parent_node.is_dummy() {
506 false
507 } else {
508 match self.cm.span_to_snippet(parent_node) {
509 Ok(snippet) => {
510 if snippet.len() < 3 {
511 false
512 } else {
513 let last_char = snippet.chars().last().unwrap();
514 snippet[..snippet.len() - last_char.len_utf8()]
515 .trim()
516 .ends_with(',')
517 }
518 }
519 _ => false,
520 }
521 }
522 };
523
524 if has_trailing_comma
525 && format.contains(ListFormat::CommaDelimited)
526 && (!self.cfg.minify || !format.contains(ListFormat::CanSkipTrailingComma))
527 {
528 punct!(self, ",");
529 formatting_space!(self);
530 }
531
532 {
533 let emit_trailing_comments = {
541 true
546 };
547
548 if let Some(previous_sibling) = previous_sibling {
549 if format.contains(ListFormat::DelimitersMask)
550 && previous_sibling.hi() != parent_node.hi()
551 && emit_trailing_comments
552 && self.comments.is_some()
553 {
554 self.emit_leading_comments(previous_sibling.hi(), true)?;
555 }
556 }
557 }
558
559 if format.contains(ListFormat::Indented) && !self.cfg.minify {
561 self.wr.decrease_indent()?;
562 }
563
564 if self
566 .cm
567 .should_write_closing_line_terminator(parent_node, last_child, format)
568 {
569 if !self.cfg.minify {
570 self.wr.write_line()?;
571 }
572 } else if format.contains(ListFormat::SpaceBetweenBraces) && !self.cfg.minify {
573 self.wr.write_space()?;
574 }
575
576 Ok(())
577 }
578
579 #[inline(never)]
581 fn emit_last_of_list5(
582 &mut self,
583 parent_node: Span,
584 is_empty: bool,
585 format: ListFormat,
586 _start: usize,
587 _count: usize,
588 ) -> Result {
589 if format.contains(ListFormat::BracketsMask) {
590 if is_empty {
591 self.emit_leading_comments(
592 {
593 parent_node.hi()
596 },
597 true,
598 )?; }
600 self.wr.write_punct(None, format.closing_bracket())?;
601 }
602
603 Ok(())
604 }
605
606 fn emit_list5<N: Node>(
607 &mut self,
608 parent_node: Span,
609 children: Option<&[N]>,
610 format: ListFormat,
611 start: usize,
612 count: usize,
613 ) -> Result {
614 if let Some(result) =
615 self.emit_first_of_list5(parent_node, children.map(|v| v.len()), format, start, count)
616 {
617 return result;
618 }
619
620 let is_empty = children.is_none() || start > children.unwrap().len() || count == 0;
621
622 if is_empty {
623 if format.contains(ListFormat::MultiLine) {
626 if !self.cfg.minify {
627 self.wr.write_line()?;
628 }
629 } else if format.contains(ListFormat::SpaceBetweenBraces)
630 && !(format.contains(ListFormat::NoSpaceIfEmpty))
631 && !self.cfg.minify
632 {
633 self.wr.write_space()?;
634 }
635 } else {
636 let children = children.unwrap();
637
638 let may_emit_intervening_comments =
640 !format.intersects(ListFormat::NoInterveningComments);
641 let mut should_emit_intervening_comments = may_emit_intervening_comments;
642 if self.cm.should_write_leading_line_terminator(
643 parent_node,
644 children.first().map(|v| v.span()),
645 format,
646 ) {
647 if !self.cfg.minify {
648 self.wr.write_line()?;
649 }
650 should_emit_intervening_comments = false;
651 } else if format.contains(ListFormat::SpaceBetweenBraces) && !self.cfg.minify {
652 self.wr.write_space()?;
653 }
654
655 if format.contains(ListFormat::Indented) && !self.cfg.minify {
657 self.wr.increase_indent()?;
658 }
659
660 let mut previous_sibling: Option<Span> = None;
662 let mut should_decrease_indent_after_emit = false;
663 for i in 0..count {
664 let child = &children[start + i];
665
666 self.emit_pre_child_for_list5(
667 parent_node,
668 format,
669 previous_sibling,
670 child.span(),
671 &mut should_decrease_indent_after_emit,
672 &mut should_emit_intervening_comments,
673 )?;
674
675 child.emit_with(self)?;
676
677 if should_emit_intervening_comments {
679 if self.comments.is_some() {
680 let comment_range = child.comment_range();
681 self.emit_trailing_comments_of_pos(comment_range.hi(), false, true)?;
682 }
683 } else {
684 should_emit_intervening_comments = may_emit_intervening_comments;
685 }
686
687 if should_decrease_indent_after_emit {
688 self.wr.decrease_indent()?;
689 should_decrease_indent_after_emit = false;
690 }
691
692 previous_sibling = Some(child.span());
693 }
694
695 self.emit_list_finisher_of_list5(
696 parent_node,
697 format,
698 previous_sibling,
699 children.last().map(|v| v.span()),
700 )?;
701 }
702
703 self.emit_last_of_list5(parent_node, is_empty, format, start, count)?;
706 Ok(())
707 }
708}
709
710impl<W, S: SourceMapper> Emitter<'_, W, S>
712where
713 W: WriteJs,
714 S: SourceMapperExt,
715{
716 fn emit_block_stmt_inner(&mut self, node: &BlockStmt, skip_first_src_map: bool) -> Result {
717 self.emit_leading_comments_of_span(node.span(), false)?;
718
719 if !skip_first_src_map {
720 srcmap!(self, node, true);
721 }
722 punct!(self, "{");
723
724 let emit_new_line = !self.cfg.minify
725 && !(node.stmts.is_empty() && is_empty_comments(&node.span(), &self.comments));
726
727 let mut list_format = ListFormat::MultiLineBlockStatements;
728
729 if !emit_new_line {
730 list_format -= ListFormat::MultiLine | ListFormat::Indented;
731 }
732
733 self.emit_list(node.span(), Some(&node.stmts), list_format)?;
734
735 self.emit_leading_comments_of_span(node.span(), true)?;
736
737 srcmap!(self, node, false, true);
738 punct!(self, "}");
739
740 Ok(())
741 }
742
743 fn has_trailing_comment(&self, span: Span) -> bool {
744 if let Some(cmt) = self.comments {
745 let hi = span.hi;
746
747 if cmt.has_trailing(hi) {
748 return true;
749 }
750 }
751
752 false
753 }
754
755 fn simple_assign_target_has_leading_comment(&self, arg: &SimpleAssignTarget) -> bool {
756 match arg {
757 SimpleAssignTarget::Ident(i) => {
758 span_has_leading_comment(self.comments.as_ref().unwrap(), i.span)
759 }
760 SimpleAssignTarget::Member(m) => {
761 if self.has_leading_comment(&m.obj) {
762 return true;
763 }
764
765 false
766 }
767
768 SimpleAssignTarget::SuperProp(m) => {
769 if span_has_leading_comment(self.comments.as_ref().unwrap(), m.span) {
770 return true;
771 }
772
773 false
774 }
775
776 _ => false,
777 }
778 }
779
780 fn has_leading_comment(&self, arg: &Expr) -> bool {
781 let cmt = if let Some(cmt) = self.comments {
782 if span_has_leading_comment(cmt, arg.span()) {
783 return true;
784 }
785
786 cmt
787 } else {
788 return false;
789 };
790
791 match arg {
792 Expr::Call(c) => {
793 let has_leading = match &c.callee {
794 Callee::Super(callee) => span_has_leading_comment(cmt, callee.span),
795 Callee::Import(callee) => span_has_leading_comment(cmt, callee.span),
796 Callee::Expr(callee) => self.has_leading_comment(callee),
797 #[cfg(swc_ast_unknown)]
798 _ => false,
799 };
800
801 if has_leading {
802 return true;
803 }
804 }
805
806 Expr::Member(m) => {
807 if self.has_leading_comment(&m.obj) {
808 return true;
809 }
810 }
811
812 Expr::SuperProp(m) => {
813 if span_has_leading_comment(cmt, m.span) {
814 return true;
815 }
816 }
817
818 Expr::Bin(e) => {
819 if self.has_leading_comment(&e.left) {
820 return true;
821 }
822 }
823
824 Expr::Cond(e) => {
825 if self.has_leading_comment(&e.test) {
826 return true;
827 }
828 }
829
830 Expr::Seq(e) => {
831 if let Some(e) = e.exprs.first() {
832 if self.has_leading_comment(e) {
833 return true;
834 }
835 }
836 }
837
838 Expr::Assign(e) => {
839 let lo = e.span.lo;
840
841 if cmt.has_leading(lo) {
842 return true;
843 }
844
845 let has_leading = match &e.left {
846 AssignTarget::Simple(e) => self.simple_assign_target_has_leading_comment(e),
847
848 AssignTarget::Pat(p) => match p {
849 AssignTargetPat::Array(a) => span_has_leading_comment(cmt, a.span),
850 AssignTargetPat::Object(o) => span_has_leading_comment(cmt, o.span),
851 AssignTargetPat::Invalid(..) => false,
852 #[cfg(swc_ast_unknown)]
853 _ => false,
854 },
855 #[cfg(swc_ast_unknown)]
856 _ => false,
857 };
858
859 if has_leading {
860 return true;
861 }
862 }
863
864 Expr::OptChain(e) => match &*e.base {
865 OptChainBase::Member(m) => {
866 if self.has_leading_comment(&m.obj) {
867 return true;
868 }
869 }
870 OptChainBase::Call(c) => {
871 if self.has_leading_comment(&c.callee) {
872 return true;
873 }
874 }
875 #[cfg(swc_ast_unknown)]
876 _ => (),
877 },
878
879 _ => {}
880 }
881
882 false
883 }
884}
885
886impl<W, S: SourceMapper> Emitter<'_, W, S>
887where
888 W: WriteJs,
889 S: SourceMapperExt,
890{
891 fn write_delim(&mut self, f: ListFormat) -> Result {
892 match f & ListFormat::DelimitersMask {
893 ListFormat::None => {}
894 ListFormat::CommaDelimited => self.wr.write_punct(None, ",")?,
895 ListFormat::BarDelimited => {
896 if !self.cfg.minify {
897 self.wr.write_space()?;
898 }
899 self.wr.write_punct(None, "|")?;
900 }
901 ListFormat::AmpersandDelimited => {
902 if !self.cfg.minify {
903 self.wr.write_space()?;
904 }
905 self.wr.write_punct(None, "&")?;
906 }
907 _ => unreachable!(),
908 }
909
910 Ok(())
911 }
912}
913
914fn should_emit_whitespace_before_operand(node: &UnaryExpr) -> bool {
929 match *node {
930 UnaryExpr {
931 op: op!("void"), ..
932 }
933 | UnaryExpr {
934 op: op!("typeof"), ..
935 }
936 | UnaryExpr {
937 op: op!("delete"), ..
938 } => return node.arg.starts_with_alpha_num(),
939 _ => {}
940 }
941
942 match &*node.arg {
943 Expr::Update(UpdateExpr {
944 op: op!("++"),
945 prefix: true,
946 ..
947 })
948 | Expr::Unary(UnaryExpr {
949 op: op!(unary, "+"),
950 ..
951 }) if node.op == op!(unary, "+") => true,
952 Expr::Update(UpdateExpr {
953 op: op!("--"),
954 prefix: true,
955 ..
956 })
957 | Expr::Unary(UnaryExpr {
958 op: op!(unary, "-"),
959 ..
960 }) if node.op == op!(unary, "-") => true,
961
962 Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() && node.op == op!(unary, "-") => true,
963
964 _ => false,
965 }
966}
967
968impl<N> Node for Option<N>
969where
970 N: Node,
971{
972 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
973 where
974 W: WriteJs,
975 S: SourceMapper + SourceMapperExt,
976 {
977 match *self {
978 Some(ref n) => n.emit_with(e),
979 None => Ok(()),
980 }
981 }
982}
983
984fn get_template_element_from_raw(
985 s: &str,
986 ascii_only: bool,
987 reduce_escaped_newline: bool,
988) -> String {
989 fn read_escaped(
990 radix: u32,
991 len: Option<usize>,
992 buf: &mut String,
993 iter: impl Iterator<Item = char>,
994 ) {
995 let mut v = 0;
996 let mut pending = None;
997
998 for (i, c) in iter.enumerate() {
999 if let Some(len) = len {
1000 if i == len {
1001 pending = Some(c);
1002 break;
1003 }
1004 }
1005
1006 match c.to_digit(radix) {
1007 None => {
1008 pending = Some(c);
1009 break;
1010 }
1011 Some(d) => {
1012 v = v * radix + d;
1013 }
1014 }
1015 }
1016
1017 match radix {
1018 16 => {
1019 match v {
1020 0 => match pending {
1021 Some('1'..='9') => write!(buf, "\\x00").unwrap(),
1022 _ => write!(buf, "\\0").unwrap(),
1023 },
1024 1..=15 => write!(buf, "\\x0{v:x}").unwrap(),
1025 32..=126 => {
1027 let c = char::from_u32(v);
1028
1029 match c {
1030 Some(c) => write!(buf, "{c}").unwrap(),
1031 _ => {
1032 unreachable!()
1033 }
1034 }
1035 }
1036 _ => {
1039 write!(buf, "\\x{v:x}").unwrap();
1040 }
1041 }
1042 }
1043
1044 _ => unreachable!(),
1045 }
1046
1047 if let Some(pending) = pending {
1048 buf.push(pending);
1049 }
1050 }
1051
1052 let mut buf = String::with_capacity(s.len());
1053 let mut iter = s.chars().peekable();
1054
1055 let mut is_dollar_prev = false;
1056
1057 while let Some(c) = iter.next() {
1058 let unescape = match c {
1059 '\\' => match iter.next() {
1060 Some(c) => match c {
1061 'n' => {
1062 if reduce_escaped_newline {
1063 Some('\n')
1064 } else {
1065 buf.push('\\');
1066 buf.push('n');
1067
1068 None
1069 }
1070 }
1071 't' => Some('\t'),
1072 'x' => {
1073 read_escaped(16, Some(2), &mut buf, &mut iter);
1074
1075 None
1076 }
1077 '\u{2028}' | '\u{2029}' => None,
1080 '\\' | 'r' | 'v' | 'b' | 'f' | 'u' | '\r' | '\n' | '`' | '0'..='7' => {
1083 buf.push('\\');
1084 buf.push(c);
1085
1086 None
1087 }
1088 '$' if iter.peek() == Some(&'{') => {
1089 buf.push('\\');
1090 buf.push('$');
1091
1092 None
1093 }
1094 '{' if is_dollar_prev => {
1095 buf.push('\\');
1096 buf.push('{');
1097
1098 is_dollar_prev = false;
1099
1100 None
1101 }
1102 _ => Some(c),
1103 },
1104 None => Some('\\'),
1105 },
1106 _ => Some(c),
1107 };
1108
1109 match unescape {
1110 Some(c @ '$') => {
1111 is_dollar_prev = true;
1112
1113 buf.push(c);
1114 }
1115 Some('\x00') => {
1116 let next = iter.peek();
1117
1118 match next {
1119 Some('1'..='9') => buf.push_str("\\x00"),
1120 _ => buf.push_str("\\0"),
1121 }
1122 }
1123 Some('\u{0008}') => buf.push_str("\\b"),
1126 Some('\u{000c}') => buf.push_str("\\f"),
1127 Some('\n') => buf.push('\n'),
1128 Some('\u{000b}') => buf.push_str("\\v"),
1130 Some('\t') => buf.push('\t'),
1131 Some(c @ '\x20'..='\x7e') => {
1133 buf.push(c);
1134 }
1135 Some(c @ '\u{7f}'..='\u{ff}') => {
1136 let _ = write!(buf, "\\x{:x}", c as u8);
1137 }
1138 Some('\u{2028}') => {
1139 buf.push_str("\\u2028");
1140 }
1141 Some('\u{2029}') => {
1142 buf.push_str("\\u2029");
1143 }
1144 Some('\u{FEFF}') => {
1145 buf.push_str("\\uFEFF");
1146 }
1147 Some(c) => {
1149 if !ascii_only || c.is_ascii() {
1150 buf.push(c);
1151 } else {
1152 buf.extend(c.escape_unicode().map(|c| {
1153 if c == 'u' {
1154 c
1155 } else {
1156 c.to_ascii_uppercase()
1157 }
1158 }));
1159 }
1160 }
1161 None => {}
1162 }
1163 }
1164
1165 buf
1166}
1167
1168fn get_ascii_only_ident(sym: &str, may_need_quote: bool, target: EsVersion) -> CowStr {
1169 if sym.is_ascii() {
1170 return CowStr::Borrowed(sym);
1171 }
1172
1173 let mut first = true;
1174 let mut buf = CompactString::with_capacity(sym.len() + 8);
1175 let mut iter = sym.chars().peekable();
1176 let mut need_quote = false;
1177
1178 while let Some(c) = iter.next() {
1179 match c {
1180 '\x00' => {
1181 if may_need_quote {
1182 need_quote = true;
1183 let _ = write!(buf, "\\x00");
1184 } else {
1185 let _ = write!(buf, "\\u0000");
1186 }
1187 }
1188 '\u{0008}' => buf.push_str("\\b"),
1189 '\u{000c}' => buf.push_str("\\f"),
1190 '\n' => buf.push_str("\\n"),
1191 '\r' => buf.push_str("\\r"),
1192 '\u{000b}' => buf.push_str("\\v"),
1193 '\t' => buf.push('\t'),
1194 '\\' => {
1195 let next = iter.peek();
1196
1197 match next {
1198 Some('u') => {
1200 let mut inner_iter = iter.clone();
1201
1202 inner_iter.next();
1203
1204 let mut is_curly = false;
1205 let mut next = inner_iter.peek();
1206
1207 if next == Some(&'{') {
1208 is_curly = true;
1209
1210 inner_iter.next();
1211 next = inner_iter.peek();
1212 }
1213
1214 if let Some(c @ 'D' | c @ 'd') = next {
1215 let mut inner_buf = String::new();
1216
1217 inner_buf.push('\\');
1218 inner_buf.push('u');
1219
1220 if is_curly {
1221 inner_buf.push('{');
1222 }
1223
1224 inner_buf.push(*c);
1225
1226 inner_iter.next();
1227
1228 let mut is_valid = true;
1229
1230 for _ in 0..3 {
1231 let c = inner_iter.next();
1232
1233 match c {
1234 Some('0'..='9') | Some('a'..='f') | Some('A'..='F') => {
1235 inner_buf.push(c.unwrap());
1236 }
1237 _ => {
1238 is_valid = false;
1239
1240 break;
1241 }
1242 }
1243 }
1244
1245 if is_curly {
1246 inner_buf.push('}');
1247 }
1248
1249 if is_valid {
1250 buf.push_str(&inner_buf);
1251
1252 let end = if is_curly { 7 } else { 5 };
1253
1254 for _ in 0..end {
1255 iter.next();
1256 }
1257 }
1258 } else {
1259 buf.push_str("\\\\");
1260 }
1261 }
1262 _ => {
1263 buf.push_str("\\\\");
1264 }
1265 }
1266 }
1267 '\'' => {
1268 buf.push('\'');
1269 }
1270 '"' => {
1271 buf.push('"');
1272 }
1273 '\x01'..='\x0f' if !first => {
1274 if may_need_quote {
1275 need_quote = true;
1276 let _ = write!(buf, "\\x{:x}", c as u8);
1277 } else {
1278 let _ = write!(buf, "\\u00{:x}", c as u8);
1279 }
1280 }
1281 '\x10'..='\x1f' if !first => {
1282 if may_need_quote {
1283 need_quote = true;
1284 let _ = write!(buf, "\\x{:x}", c as u8);
1285 } else {
1286 let _ = write!(buf, "\\u00{:x}", c as u8);
1287 }
1288 }
1289 '\x20'..='\x7e' => {
1290 buf.push(c);
1291 }
1292 '\u{7f}'..='\u{ff}' => {
1293 if may_need_quote {
1294 need_quote = true;
1295 let _ = write!(buf, "\\x{:x}", c as u8);
1296 } else {
1297 let _ = write!(buf, "\\u00{:x}", c as u8);
1298 }
1299 }
1300 '\u{2028}' => {
1301 buf.push_str("\\u2028");
1302 }
1303 '\u{2029}' => {
1304 buf.push_str("\\u2029");
1305 }
1306 '\u{FEFF}' => {
1307 buf.push_str("\\uFEFF");
1308 }
1309 _ => {
1310 if c.is_ascii() {
1311 buf.push(c);
1312 } else if c > '\u{FFFF}' {
1313 if target <= EsVersion::Es5 {
1319 let h = ((c as u32 - 0x10000) / 0x400) + 0xd800;
1321 let l = (c as u32 - 0x10000) % 0x400 + 0xdc00;
1322
1323 let _ = write!(buf, r#""\u{h:04X}\u{l:04X}""#);
1324 } else {
1325 let _ = write!(buf, "\\u{{{:04X}}}", c as u32);
1326 }
1327 } else {
1328 let _ = write!(buf, "\\u{:04X}", c as u16);
1329 }
1330 }
1331 }
1332 first = false;
1333 }
1334
1335 if need_quote {
1336 CowStr::Owned(format_compact!("\"{}\"", buf))
1337 } else {
1338 CowStr::Owned(buf)
1339 }
1340}
1341
1342fn handle_invalid_unicodes(s: &str) -> Cow<str> {
1343 static NEEDLE: Lazy<Finder> = Lazy::new(|| Finder::new("\\\0"));
1344 if NEEDLE.find(s.as_bytes()).is_none() {
1345 return Cow::Borrowed(s);
1346 }
1347
1348 Cow::Owned(s.replace("\\\0", "\\"))
1349}
1350
1351fn require_space_before_rhs(rhs: &Expr, op: &BinaryOp) -> bool {
1352 match rhs {
1353 Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() && *op == op!(bin, "-") => true,
1354
1355 Expr::Update(UpdateExpr {
1356 prefix: true,
1357 op: update,
1358 ..
1359 }) => matches!(
1360 (op, update),
1361 (op!(bin, "-"), op!("--")) | (op!(bin, "+"), op!("++"))
1362 ),
1363
1364 Expr::Unary(UnaryExpr {
1366 op: op!("!"), arg, ..
1367 }) if *op == op!("<") || *op == op!("<<") => {
1368 if let Expr::Update(UpdateExpr { op: op!("--"), .. }) = &**arg {
1369 true
1370 } else {
1371 false
1372 }
1373 }
1374
1375 Expr::Unary(UnaryExpr { op: unary, .. }) => matches!(
1376 (op, unary),
1377 (op!(bin, "-"), op!(unary, "-")) | (op!(bin, "+"), op!(unary, "+"))
1378 ),
1379
1380 Expr::Bin(BinExpr { left, .. }) => require_space_before_rhs(left, op),
1381
1382 _ => false,
1383 }
1384}
1385
1386fn is_empty_comments(span: &Span, comments: &Option<&dyn Comments>) -> bool {
1387 span.is_dummy() || comments.map_or(true, |c| !c.has_leading(span.span_hi() - BytePos(1)))
1388}
1389
1390fn span_has_leading_comment(cmt: &dyn Comments, span: Span) -> bool {
1391 let lo = span.lo;
1392
1393 if lo.is_dummy() {
1394 return false;
1395 }
1396
1397 if let Some(cmt) = cmt.get_leading(lo) {
1399 if cmt.iter().any(|cmt| {
1400 cmt.kind == CommentKind::Line
1401 || cmt
1402 .text
1403 .chars()
1404 .any(|c| c == '\n' || c == '\r' || c == '\u{2028}' || c == '\u{2029}')
1406 }) {
1407 return true;
1408 }
1409 }
1410
1411 false
1412}
1413
1414#[node_impl]
1415impl MacroNode for Program {
1416 fn emit(&mut self, emitter: &mut Macro) -> Result {
1417 match self {
1418 Program::Module(m) => emit!(m),
1419 Program::Script(s) => emit!(s),
1420 #[cfg(swc_ast_unknown)]
1421 _ => return Err(unknown_error()),
1422 }
1425
1426 Ok(())
1427 }
1428}
1429
1430#[node_impl]
1431impl MacroNode for Module {
1432 #[tracing::instrument(level = "debug", skip_all)]
1433 fn emit(&mut self, emitter: &mut Macro) -> Result {
1434 let should_skip_leading_comments = self.body.iter().any(|s| s.span().lo == self.span.lo);
1435
1436 if !should_skip_leading_comments {
1437 emitter.emit_leading_comments_of_span(self.span(), false)?;
1438 }
1439
1440 if self.body.is_empty() {
1441 srcmap!(emitter, self, true);
1442 }
1443
1444 if let Some(ref shebang) = self.shebang {
1445 punct!(emitter, "#!");
1446 emitter.wr.write_str_lit(DUMMY_SP, shebang)?;
1447 emitter.wr.write_line()?;
1448 }
1449 for stmt in &self.body {
1450 emit!(stmt);
1451 }
1452
1453 emitter.emit_trailing_comments_of_pos(self.span().hi, true, true)?;
1454 if !emitter.cfg.omit_last_semi {
1455 emitter.wr.commit_pending_semi()?;
1456 }
1457
1458 Ok(())
1459 }
1460}
1461
1462#[node_impl]
1463impl MacroNode for Script {
1464 #[tracing::instrument(level = "debug", skip_all)]
1465 fn emit(&mut self, emitter: &mut Macro) -> Result {
1466 let should_skip_leading_comments = self.body.iter().any(|s| s.span().lo == self.span.lo);
1467
1468 if !should_skip_leading_comments {
1469 emitter.emit_leading_comments_of_span(self.span(), false)?;
1470 }
1471
1472 if self.body.is_empty() {
1473 srcmap!(emitter, self, true);
1474 }
1475
1476 if let Some(ref shebang) = self.shebang {
1477 punct!(emitter, "#!");
1478 emitter.wr.write_str_lit(DUMMY_SP, shebang)?;
1479 emitter.wr.write_line()?;
1480 }
1481 for stmt in &self.body {
1482 emit!(stmt);
1483 }
1484
1485 emitter.emit_trailing_comments_of_pos(self.span().hi, true, true)?;
1486 if !emitter.cfg.omit_last_semi {
1487 emitter.wr.commit_pending_semi()?;
1488 }
1489
1490 Ok(())
1491 }
1492}
1493
1494#[node_impl]
1495impl MacroNode for ModuleItem {
1496 fn emit(&mut self, emitter: &mut Macro) -> Result {
1497 emitter.emit_leading_comments_of_span(self.span(), false)?;
1498 match self {
1499 ModuleItem::Stmt(stmt) => emit!(stmt),
1500 ModuleItem::ModuleDecl(decl) => emit!(decl),
1501 #[cfg(swc_ast_unknown)]
1502 _ => return Err(unknown_error()),
1503 }
1504 emitter.emit_trailing_comments_of_pos(self.span().hi, true, true)?;
1505
1506 Ok(())
1507 }
1508}
1509
1510#[node_impl]
1511impl MacroNode for Callee {
1512 fn emit(&mut self, emitter: &mut Macro) -> Result {
1513 match self {
1514 Callee::Expr(e) => {
1515 if let Expr::New(new) = &**e {
1516 emitter.emit_new(new, false)?;
1517 } else {
1518 emit!(e);
1519 }
1520 }
1521 Callee::Super(n) => emit!(n),
1522 Callee::Import(n) => emit!(n),
1523 #[cfg(swc_ast_unknown)]
1524 _ => return Err(unknown_error()),
1525 }
1526
1527 Ok(())
1528 }
1529}
1530
1531#[node_impl]
1532impl MacroNode for Super {
1533 fn emit(&mut self, emitter: &mut Macro) -> Result {
1534 keyword!(emitter, self.span, "super");
1535
1536 Ok(())
1537 }
1538}
1539
1540#[node_impl]
1541impl MacroNode for Import {
1542 fn emit(&mut self, emitter: &mut Macro) -> Result {
1543 keyword!(emitter, self.span, "import");
1544 match self.phase {
1545 ImportPhase::Source => {
1546 punct!(emitter, ".");
1547 keyword!(emitter, "source")
1548 }
1549 ImportPhase::Defer => {
1550 punct!(emitter, ".");
1551 keyword!(emitter, "defer")
1552 }
1553 _ => {}
1554 }
1555
1556 Ok(())
1557 }
1558}
1559
1560#[node_impl]
1561impl MacroNode for Expr {
1562 fn emit(&mut self, emitter: &mut Macro) -> Result {
1563 match self {
1564 Expr::Array(n) => emit!(n),
1565 Expr::Arrow(n) => emit!(n),
1566 Expr::Assign(n) => emit!(n),
1567 Expr::Await(n) => emit!(n),
1568 Expr::Bin(n) => emit!(n),
1569 Expr::Call(n) => emit!(n),
1570 Expr::Class(n) => emit!(n),
1571 Expr::Cond(n) => emit!(n),
1572 Expr::Fn(n) => emit!(n),
1573 Expr::Ident(n) => emit!(n),
1574 Expr::Lit(n) => emit!(n),
1575 Expr::Member(n) => emit!(n),
1576 Expr::SuperProp(n) => emit!(n),
1577 Expr::MetaProp(n) => emit!(n),
1578 Expr::New(n) => emit!(n),
1579 Expr::Object(n) => emit!(n),
1580 Expr::Paren(n) => emit!(n),
1581 Expr::Seq(n) => emit!(n),
1582 Expr::TaggedTpl(n) => emit!(n),
1583 Expr::This(n) => emit!(n),
1584 Expr::Tpl(n) => emit!(n),
1585 Expr::Unary(n) => emit!(n),
1586 Expr::Update(n) => emit!(n),
1587 Expr::Yield(n) => emit!(n),
1588 Expr::PrivateName(n) => emit!(n),
1589
1590 Expr::JSXMember(n) => emit!(n),
1591 Expr::JSXNamespacedName(n) => emit!(n),
1592 Expr::JSXEmpty(n) => emit!(n),
1593 Expr::JSXElement(n) => emit!(n),
1594 Expr::JSXFragment(n) => emit!(n),
1595
1596 Expr::TsAs(n) => emit!(n),
1597 Expr::TsNonNull(n) => emit!(n),
1598 Expr::TsTypeAssertion(n) => emit!(n),
1599 Expr::TsConstAssertion(n) => emit!(n),
1600 Expr::TsInstantiation(n) => emit!(n),
1601 Expr::OptChain(n) => emit!(n),
1602 Expr::Invalid(n) => emit!(n),
1603 Expr::TsSatisfies(n) => {
1604 emit!(n)
1605 }
1606 #[cfg(swc_ast_unknown)]
1607 _ => return Err(unknown_error()),
1608 }
1609
1610 if emitter.comments.is_some() {
1611 emitter.emit_trailing_comments_of_pos(self.span().hi, true, true)?;
1612 }
1613
1614 Ok(())
1615 }
1616}
1617
1618#[node_impl]
1619impl MacroNode for OptChainExpr {
1620 fn emit(&mut self, emitter: &mut Macro) -> Result {
1621 emitter.emit_leading_comments_of_span(self.span(), false)?;
1622
1623 match &*self.base {
1624 OptChainBase::Member(e) => {
1625 if let Expr::New(new) = &*e.obj {
1626 emitter.emit_new(new, false)?;
1627 } else {
1628 emit!(e.obj);
1629 }
1630 if self.optional {
1631 punct!(emitter, "?.");
1632 } else if !e.prop.is_computed() {
1633 punct!(emitter, ".");
1634 }
1635
1636 match &e.prop {
1637 MemberProp::Computed(computed) => emit!(computed),
1638 MemberProp::Ident(i) => emit!(i),
1639 MemberProp::PrivateName(p) => emit!(p),
1640 #[cfg(swc_ast_unknown)]
1641 _ => return Err(unknown_error()),
1642 }
1643 }
1644 OptChainBase::Call(e) => {
1645 debug_assert!(!e.callee.is_new());
1646 emit!(e.callee);
1647
1648 if self.optional {
1649 punct!(emitter, "?.");
1650 }
1651
1652 punct!(emitter, "(");
1653 emitter.emit_expr_or_spreads(
1654 self.span(),
1655 &e.args,
1656 ListFormat::CallExpressionArguments,
1657 )?;
1658 punct!(emitter, ")");
1659 }
1660 #[cfg(swc_ast_unknown)]
1661 _ => return Err(unknown_error()),
1662 }
1663
1664 Ok(())
1665 }
1666}
1667
1668#[node_impl]
1669impl MacroNode for Invalid {
1670 fn emit(&mut self, emitter: &mut Macro) -> Result {
1671 emitter.emit_leading_comments_of_span(self.span, false)?;
1672
1673 emitter.wr.write_str_lit(self.span, "<invalid>")?;
1674
1675 Ok(())
1676 }
1677}
1678
1679#[node_impl]
1680impl MacroNode for CallExpr {
1681 fn emit(&mut self, emitter: &mut Macro) -> Result {
1682 emitter.wr.commit_pending_semi()?;
1683
1684 emitter.emit_leading_comments_of_span(self.span(), false)?;
1685
1686 srcmap!(emitter, self, true);
1687
1688 emit!(self.callee);
1689
1690 if let Some(type_args) = &self.type_args {
1691 emit!(type_args);
1692 }
1693
1694 punct!(emitter, "(");
1695 emitter.emit_expr_or_spreads(
1696 self.span(),
1697 &self.args,
1698 ListFormat::CallExpressionArguments,
1699 )?;
1700 punct!(emitter, ")");
1701
1702 Ok(())
1705 }
1706}
1707
1708#[node_impl]
1709impl MacroNode for NewExpr {
1710 fn emit(&mut self, emitter: &mut Macro) -> Result {
1711 emitter.emit_new(self, true)?;
1712
1713 Ok(())
1714 }
1715}
1716
1717#[node_impl]
1718impl MacroNode for MemberExpr {
1719 fn emit(&mut self, emitter: &mut Macro) -> Result {
1720 emitter.emit_leading_comments_of_span(self.span(), false)?;
1721
1722 srcmap!(emitter, self, true);
1723
1724 let mut needs_2dots_for_property_access = false;
1725
1726 match &*self.obj {
1727 Expr::New(new) => {
1728 emitter.emit_new(new, false)?;
1729 }
1730 Expr::Lit(Lit::Num(num)) => {
1731 needs_2dots_for_property_access = emitter.emit_num_lit_internal(num, true)?;
1732 }
1733 _ => {
1734 emit!(self.obj);
1735 }
1736 }
1737
1738 match &self.prop {
1739 MemberProp::Computed(computed) => emit!(computed),
1740 MemberProp::Ident(ident) => {
1741 if needs_2dots_for_property_access {
1742 if self.prop.span().lo() >= BytePos(2) {
1743 emitter.emit_leading_comments(self.prop.span().lo() - BytePos(2), false)?;
1744 }
1745 punct!(emitter, ".");
1746 }
1747 if self.prop.span().lo() >= BytePos(1) {
1748 emitter.emit_leading_comments(self.prop.span().lo() - BytePos(1), false)?;
1749 }
1750 punct!(emitter, ".");
1751 emit!(ident);
1752 }
1753 MemberProp::PrivateName(private) => {
1754 if needs_2dots_for_property_access {
1755 if self.prop.span().lo() >= BytePos(2) {
1756 emitter.emit_leading_comments(self.prop.span().lo() - BytePos(2), false)?;
1757 }
1758 punct!(emitter, ".");
1759 }
1760 if self.prop.span().lo() >= BytePos(1) {
1761 emitter.emit_leading_comments(self.prop.span().lo() - BytePos(1), false)?;
1762 }
1763 punct!(emitter, ".");
1764 emit!(private);
1765 }
1766 #[cfg(swc_ast_unknown)]
1767 _ => return Err(unknown_error()),
1768 }
1769
1770 srcmap!(emitter, self, false);
1771
1772 Ok(())
1773 }
1774}
1775
1776#[node_impl]
1777impl MacroNode for SuperPropExpr {
1778 fn emit(&mut self, emitter: &mut Macro) -> Result {
1779 emitter.emit_leading_comments_of_span(self.span(), false)?;
1780
1781 srcmap!(emitter, self, true);
1782
1783 emit!(self.obj);
1784
1785 match &self.prop {
1786 SuperProp::Computed(computed) => emit!(computed),
1787 SuperProp::Ident(i) => {
1788 if self.prop.span().lo() >= BytePos(1) {
1789 emitter.emit_leading_comments(self.prop.span().lo() - BytePos(1), false)?;
1790 }
1791 punct!(emitter, ".");
1792 emit!(i);
1793 }
1794 #[cfg(swc_ast_unknown)]
1795 _ => return Err(unknown_error()),
1796 }
1797
1798 Ok(())
1799 }
1800}
1801
1802#[node_impl]
1803impl MacroNode for ArrowExpr {
1804 fn emit(&mut self, emitter: &mut Macro) -> Result {
1805 emitter.emit_leading_comments_of_span(self.span(), false)?;
1806
1807 srcmap!(emitter, self, true);
1808
1809 let space = !emitter.cfg.minify
1810 || match self.params.as_slice() {
1811 [Pat::Ident(_)] => true,
1812 _ => false,
1813 };
1814
1815 if self.is_async {
1816 keyword!(emitter, "async");
1817 if space {
1818 space!(emitter);
1819 } else {
1820 formatting_space!(emitter);
1821 }
1822 }
1823 if self.is_generator {
1824 punct!(emitter, "*")
1825 }
1826
1827 let parens = !emitter.cfg.minify
1828 || match self.params.as_slice() {
1829 [Pat::Ident(i)] => emitter.has_trailing_comment(i.span),
1830 _ => true,
1831 };
1832
1833 emit!(self.type_params);
1834
1835 if parens {
1836 punct!(emitter, "(");
1837 }
1838
1839 emitter.emit_list(self.span, Some(&self.params), ListFormat::CommaListElements)?;
1840 if parens {
1841 punct!(emitter, ")");
1842 }
1843
1844 if let Some(ty) = &self.return_type {
1845 punct!(emitter, ":");
1846 formatting_space!(emitter);
1847 emit!(ty);
1848 formatting_space!(emitter);
1849 }
1850
1851 punct!(emitter, "=>");
1852 emit!(self.body);
1853
1854 Ok(())
1855 }
1856}
1857
1858#[node_impl]
1859impl MacroNode for MetaPropExpr {
1860 fn emit(&mut self, emitter: &mut Macro) -> Result {
1861 if emitter.comments.is_some() {
1862 emitter.emit_leading_comments_of_span(self.span(), false)?;
1863 }
1864
1865 srcmap!(emitter, self, true);
1866
1867 match self.kind {
1868 MetaPropKind::ImportMeta => keyword!(emitter, "import.meta"),
1869
1870 MetaPropKind::NewTarget => keyword!(emitter, "new.target"),
1871
1872 #[cfg(swc_ast_unknown)]
1873 _ => return Err(unknown_error()),
1874 }
1875
1876 Ok(())
1877 }
1878}
1879
1880#[node_impl]
1881impl MacroNode for SeqExpr {
1882 fn emit(&mut self, emitter: &mut Macro) -> Result {
1883 emitter.emit_leading_comments_of_span(self.span(), false)?;
1884
1885 srcmap!(emitter, self, true);
1886
1887 let mut first = true;
1888 for e in &self.exprs {
1890 if first {
1891 first = false
1892 } else {
1893 punct!(emitter, ",");
1894 formatting_space!(emitter);
1895 }
1896
1897 emit!(e);
1898 }
1899
1900 Ok(())
1901 }
1902}
1903
1904#[node_impl]
1905impl MacroNode for AssignExpr {
1906 fn emit(&mut self, emitter: &mut Macro) -> Result {
1907 emitter.emit_leading_comments_of_span(self.span(), false)?;
1908
1909 emit!(self.left);
1910 formatting_space!(emitter);
1911 operator!(emitter, self.op.as_str());
1912 formatting_space!(emitter);
1913 emit!(self.right);
1914
1915 Ok(())
1916 }
1917}
1918
1919#[node_impl]
1920impl MacroNode for BinExpr {
1921 fn emit(&mut self, emitter: &mut Macro) -> Result {
1922 emitter.emit_leading_comments_of_span(self.span(), false)?;
1923
1924 srcmap!(emitter, self, true);
1925
1926 {
1927 let mut left = Some(self);
1928 let mut lefts = Vec::new();
1929 while let Some(l) = left {
1930 lefts.push(l);
1931
1932 match &*l.left {
1933 Expr::Bin(b) => {
1934 left = Some(b);
1935 }
1936 _ => break,
1937 }
1938 }
1939
1940 let len = lefts.len();
1941
1942 for (i, left) in lefts.into_iter().rev().enumerate() {
1943 if i == 0 {
1944 emit!(left.left);
1945 }
1946 if i + 1 != len {
1948 emitter.emit_bin_expr_trailing(left)?;
1949 }
1950 }
1951 }
1952
1953 emitter.emit_bin_expr_trailing(self)?;
1954
1955 Ok(())
1956 }
1957}
1958
1959#[node_impl]
1960impl MacroNode for Decorator {
1961 fn emit(&mut self, emitter: &mut Macro) -> Result {
1962 emitter.emit_leading_comments_of_span(self.span(), false)?;
1963
1964 srcmap!(emitter, self, true);
1965
1966 punct!(emitter, "@");
1967 emit!(self.expr);
1968 emitter.wr.write_line()?;
1969
1970 srcmap!(emitter, self, false);
1971
1972 Ok(())
1973 }
1974}
1975
1976#[node_impl]
1977impl MacroNode for CondExpr {
1978 fn emit(&mut self, emitter: &mut Macro) -> Result {
1979 emitter.emit_leading_comments_of_span(self.span(), false)?;
1980
1981 srcmap!(emitter, self, true);
1982
1983 emit!(self.test);
1984 formatting_space!(emitter);
1985 punct!(emitter, "?");
1986 formatting_space!(emitter);
1987 emit!(self.cons);
1988 formatting_space!(emitter);
1989 punct!(emitter, ":");
1990 formatting_space!(emitter);
1991 emit!(self.alt);
1992
1993 Ok(())
1994 }
1995}
1996
1997#[node_impl]
1998impl MacroNode for FnExpr {
1999 fn emit(&mut self, emitter: &mut Macro) -> Result {
2000 emitter.emit_leading_comments_of_span(self.span(), false)?;
2001
2002 emitter.wr.commit_pending_semi()?;
2003
2004 srcmap!(emitter, self, true);
2005
2006 if self.function.is_async {
2007 keyword!(emitter, "async");
2008 space!(emitter);
2009 keyword!(emitter, "function");
2010 } else {
2011 keyword!(emitter, "function");
2012 }
2013
2014 if self.function.is_generator {
2015 punct!(emitter, "*");
2016 }
2017 if let Some(ref i) = self.ident {
2018 space!(emitter);
2019 emit!(i);
2020 }
2021
2022 emitter.emit_fn_trailing(&self.function)?;
2023
2024 Ok(())
2025 }
2026}
2027
2028#[node_impl]
2029impl MacroNode for BlockStmtOrExpr {
2030 fn emit(&mut self, emitter: &mut Macro) -> Result {
2031 match self {
2032 BlockStmtOrExpr::BlockStmt(block) => {
2033 emitter.emit_block_stmt_inner(block, true)?;
2034 }
2035 BlockStmtOrExpr::Expr(expr) => {
2036 emitter.wr.increase_indent()?;
2037 emit!(expr);
2038 emitter.wr.decrease_indent()?;
2039 }
2040 #[cfg(swc_ast_unknown)]
2041 _ => return Err(unknown_error()),
2042 }
2043
2044 Ok(())
2045 }
2046}
2047
2048#[node_impl]
2049impl MacroNode for ThisExpr {
2050 fn emit(&mut self, emitter: &mut Macro) -> Result {
2051 emitter.emit_leading_comments_of_span(self.span(), false)?;
2052
2053 keyword!(emitter, self.span, "this");
2054
2055 Ok(())
2056 }
2057}
2058
2059#[node_impl]
2060impl MacroNode for Tpl {
2061 fn emit(&mut self, emitter: &mut Macro) -> Result {
2062 debug_assert!(self.quasis.len() == self.exprs.len() + 1);
2063
2064 emitter.emit_leading_comments_of_span(self.span(), false)?;
2065
2066 srcmap!(emitter, self, true);
2067
2068 punct!(emitter, "`");
2069
2070 for i in 0..(self.quasis.len() + self.exprs.len()) {
2071 if i % 2 == 0 {
2072 emit!(self.quasis[i / 2]);
2073 } else {
2074 punct!(emitter, "${");
2075 emit!(self.exprs[i / 2]);
2076 punct!(emitter, "}");
2077 }
2078 }
2079
2080 punct!(emitter, "`");
2081
2082 srcmap!(emitter, self, false);
2083
2084 Ok(())
2085 }
2086}
2087
2088#[node_impl]
2089impl MacroNode for TplElement {
2090 fn emit(&mut self, emitter: &mut Macro) -> Result {
2091 let raw = self.raw.replace("\r\n", "\n").replace('\r', "\n");
2092 if emitter.cfg.minify || (emitter.cfg.ascii_only && !self.raw.is_ascii()) {
2093 let v = get_template_element_from_raw(
2094 &raw,
2095 emitter.cfg.ascii_only,
2096 emitter.cfg.reduce_escaped_newline,
2097 );
2098 let span = self.span();
2099
2100 let mut last_offset_gen = 0;
2101 let mut last_offset_origin = 0;
2102 for ((offset_gen, _), mat) in v
2103 .match_indices('\n')
2104 .zip(NEW_LINE_TPL_REGEX.find_iter(&raw))
2105 {
2106 if offset_gen != 0 {
2109 emitter
2110 .wr
2111 .add_srcmap(span.lo + BytePos(last_offset_origin as u32))?;
2112 }
2113
2114 emitter
2115 .wr
2116 .write_str_lit(DUMMY_SP, &v[last_offset_gen..=offset_gen])?;
2117 last_offset_gen = offset_gen + 1;
2118 last_offset_origin = mat.end();
2119 }
2120 emitter
2121 .wr
2122 .add_srcmap(span.lo + BytePos(last_offset_origin as u32))?;
2123 emitter.wr.write_str_lit(DUMMY_SP, &v[last_offset_gen..])?;
2124 emitter.wr.add_srcmap(span.hi)?;
2125 } else {
2126 emitter.wr.write_str_lit(self.span(), &raw)?;
2127 }
2128
2129 Ok(())
2130 }
2131}
2132
2133#[node_impl]
2134impl MacroNode for TaggedTpl {
2135 fn emit(&mut self, emitter: &mut Macro) -> Result {
2136 emitter.emit_leading_comments_of_span(self.span(), false)?;
2137
2138 srcmap!(emitter, self, true);
2139
2140 if let Expr::New(new) = &*self.tag {
2141 emitter.emit_new(new, false)?;
2142 } else {
2143 emit!(self.tag);
2144 }
2145
2146 emit!(self.type_params);
2147 emitter.emit_template_for_tagged_template(&self.tpl)?;
2148
2149 srcmap!(emitter, self, false);
2150
2151 Ok(())
2152 }
2153}
2154
2155#[node_impl]
2156impl MacroNode for UnaryExpr {
2157 fn emit(&mut self, emitter: &mut Macro) -> Result {
2158 emitter.emit_leading_comments_of_span(self.span(), false)?;
2159
2160 srcmap!(emitter, self, true);
2161
2162 let need_formatting_space = match self.op {
2163 op!("typeof") | op!("void") | op!("delete") => {
2164 keyword!(emitter, self.op.as_str());
2165
2166 true
2167 }
2168 op!(unary, "+") | op!(unary, "-") | op!("!") | op!("~") => {
2169 punct!(emitter, self.op.as_str());
2170 false
2171 }
2172 #[cfg(swc_ast_unknown)]
2173 _ => return Err(unknown_error()),
2174 };
2175
2176 if should_emit_whitespace_before_operand(self) {
2177 space!(emitter);
2178 } else if need_formatting_space {
2179 formatting_space!(emitter);
2180 }
2181
2182 emit!(self.arg);
2183
2184 Ok(())
2185 }
2186}
2187
2188#[node_impl]
2189impl MacroNode for UpdateExpr {
2190 fn emit(&mut self, emitter: &mut Macro) -> Result {
2191 emitter.emit_leading_comments_of_span(self.span(), false)?;
2192
2193 srcmap!(emitter, self, true);
2194
2195 if self.prefix {
2196 operator!(emitter, self.op.as_str());
2197 emit!(self.arg);
2199 } else {
2200 emit!(self.arg);
2201 operator!(emitter, self.op.as_str());
2202 }
2203
2204 Ok(())
2205 }
2206}
2207
2208#[node_impl]
2209impl MacroNode for YieldExpr {
2210 fn emit(&mut self, emitter: &mut Macro) -> Result {
2211 emitter.emit_leading_comments_of_span(self.span(), false)?;
2212
2213 srcmap!(emitter, self, true);
2214
2215 keyword!(emitter, "yield");
2216 if self.delegate {
2217 operator!(emitter, "*");
2218 }
2219
2220 if let Some(ref arg) = self.arg {
2221 let need_paren = self
2222 .arg
2223 .as_deref()
2224 .map(|expr| emitter.has_leading_comment(expr))
2225 .unwrap_or(false);
2226 if need_paren {
2227 punct!(emitter, "(")
2228 } else if !self.delegate && arg.starts_with_alpha_num() {
2229 space!(emitter)
2230 } else {
2231 formatting_space!(emitter)
2232 }
2233
2234 emit!(self.arg);
2235 if need_paren {
2236 punct!(emitter, ")")
2237 }
2238 }
2239
2240 Ok(())
2241 }
2242}
2243
2244#[node_impl]
2245impl MacroNode for ExprOrSpread {
2246 fn emit(&mut self, emitter: &mut Macro) -> Result {
2247 if let Some(span) = self.spread {
2248 emitter.emit_leading_comments_of_span(span, false)?;
2249
2250 punct!(emitter, "...");
2251 }
2252
2253 emit!(self.expr);
2254
2255 Ok(())
2256 }
2257}
2258
2259#[node_impl]
2260impl MacroNode for AwaitExpr {
2261 fn emit(&mut self, emitter: &mut Macro) -> Result {
2262 emitter.emit_leading_comments_of_span(self.span(), false)?;
2263
2264 srcmap!(emitter, self, true);
2265
2266 keyword!(emitter, "await");
2267 space!(emitter);
2268
2269 emit!(self.arg);
2270
2271 Ok(())
2272 }
2273}
2274
2275#[node_impl]
2276impl MacroNode for ArrayLit {
2277 fn emit(&mut self, emitter: &mut Macro) -> Result {
2278 emitter.emit_leading_comments_of_span(self.span(), false)?;
2279
2280 srcmap!(emitter, self, true);
2281
2282 punct!(emitter, "[");
2283 let mut format = ListFormat::ArrayLiteralExpressionElements;
2284 if let Some(None) = self.elems.last() {
2285 format |= ListFormat::ForceTrailingComma;
2286 }
2287
2288 emitter.emit_list(self.span(), Some(&self.elems), format)?;
2289 punct!(emitter, "]");
2290
2291 srcmap!(emitter, self, false);
2292
2293 Ok(())
2294 }
2295}
2296
2297#[node_impl]
2298impl MacroNode for ParenExpr {
2299 fn emit(&mut self, emitter: &mut Macro) -> Result {
2300 emitter.wr.commit_pending_semi()?;
2301
2302 emitter.emit_leading_comments_of_span(self.span(), false)?;
2303
2304 srcmap!(emitter, self, true);
2305
2306 punct!(emitter, "(");
2307 emit!(self.expr);
2308
2309 srcmap!(emitter, self, false, true);
2310 punct!(emitter, ")");
2311
2312 Ok(())
2313 }
2314}
2315
2316#[node_impl]
2317impl MacroNode for PrivateName {
2318 fn emit(&mut self, emitter: &mut Macro) -> Result {
2319 emitter.emit_leading_comments_of_span(self.span(), false)?;
2320
2321 srcmap!(emitter, self, true);
2322
2323 punct!(emitter, "#");
2324 emitter.emit_ident_like(self.span, &self.name, false)?;
2325
2326 srcmap!(emitter, self, false);
2327
2328 Ok(())
2329 }
2330}
2331
2332#[node_impl]
2333impl MacroNode for BindingIdent {
2334 fn emit(&mut self, emitter: &mut Macro) -> Result {
2335 emitter.emit_ident_like(self.span, &self.sym, self.optional)?;
2336
2337 if let Some(ty) = &self.type_ann {
2338 punct!(emitter, ":");
2339 formatting_space!(emitter);
2340 emit!(ty);
2341 }
2342
2343 Ok(())
2349 }
2350}
2351
2352#[node_impl]
2353impl MacroNode for Ident {
2354 fn emit(&mut self, emitter: &mut Macro) -> Result {
2355 emitter.emit_ident_like(self.span, &self.sym, self.optional)?;
2356
2357 Ok(())
2358 }
2359}
2360
2361#[node_impl]
2362impl MacroNode for IdentName {
2363 fn emit(&mut self, emitter: &mut Macro) -> Result {
2364 emitter.emit_ident_like(self.span, &self.sym, false)?;
2365
2366 Ok(())
2367 }
2368}
2369
2370#[cfg(swc_ast_unknown)]
2371fn unknown_error() -> io::Error {
2372 io::Error::new(
2373 io::ErrorKind::Unsupported,
2374 "emit unknown variant is not supported",
2375 )
2376}