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