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