Skip to main content

swc_ecma_codegen/
lib.rs

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
54/// Generate a code from a syntax node using default options.
55pub 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
74/// Generate a code from a syntax node using default options.
75pub fn to_code_with_comments(comments: Option<&dyn Comments>, node: &impl Node) -> String {
76    to_code_default(Default::default(), comments, node)
77}
78
79/// Generate a code from a syntax node using default options.
80pub 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        // srcmap!(self, node, false);
233
234        // if it's false, it means it doesn't come from emit_expr,
235        // we need to compensate that
236        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    /// Prints operator and right node of a binary expression.
276    #[inline(never)]
277    fn emit_bin_expr_trailing(&mut self, node: &BinExpr) -> Result {
278        // let indent_before_op = needs_indention(node, &node.left, node.op);
279        // let indent_after_op = needs_indention(node, node.op, &node.right);
280        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                // space is mandatory to avoid outputting -->
290                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    /// prints `(b){}` from `function a(b){}`
345    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        // srcmap!(emitter,node, false);
370    }
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        // TODO: Use write_symbol when ident is a symbol.
393        self.emit_leading_comments_of_span(span, false)?;
394
395        // Source map
396        self.wr.commit_pending_semi()?;
397
398        srcmap!(self, span, true);
399        // TODO: span
400
401        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        // Call emitList directly since it could be an array of
423        // TypeParameterDeclarations _or_ type arguments
424
425        // emitList(node, node.typeArguments, ListFormat::TypeParameters);
426
427        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    /// This method exists to reduce compile time.
446    #[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                        // TODO: children.lo()
477
478                        parent_node.lo()
479                    },
480                    true,
481                    false,
482                ) {
483                    return Some(Err(err));
484                }
485            }
486        }
487
488        None
489    }
490
491    /// This method exists to reduce compile time.
492    #[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        // Write the delimiter if this is not the first node.
503        if let Some(previous_sibling) = previous_sibling {
504            // i.e
505            //      function commentedParameters(
506            //          /* Parameter a */
507            //          a
508            // /* End of parameter a */
509            // -> this comment isn't considered to be trailing comment of parameter "a" due
510            // to newline ,
511            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            // Write either a line terminator or whitespace to separate the elements.
521
522            if self.cm.should_write_separating_line_terminator(
523                Some(previous_sibling),
524                Some(child),
525                format,
526            ) {
527                // If a synthesized node in a single-line list starts on a new
528                // line, we should increase the indent.
529                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    /// This method exists to reduce compile time.
550    #[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        // Write a trailing comma, if requested.
559        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            // Emit any trailing comment of the last element in the list
590            // i.e
591            //       var array = [...
592            //          2
593            //          /* end of element 2 */
594            //       ];
595
596            let emit_trailing_comments = {
597                // TODO:
598                //
599                // !(getEmitFlags(previousSibling).contains(EmitFlags::NoTrailingComments))
600
601                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        // Decrease the indent, if requested.
616        if format.contains(ListFormat::Indented) && !self.cfg.minify {
617            self.wr.decrease_indent()?;
618        }
619
620        // Write the closing line terminator or closing whitespace.
621        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    /// This method exists to reduce compile time.
636    #[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                        //TODO: children.hi()
650
651                        parent_node.hi()
652                    },
653                    true,
654                )?; // Emit leading comments within empty lists
655            }
656            // Closing brackets never require committing pending semi
657            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            // Write a line terminator if the parent node was multi-line
681
682            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            // Write the opening line terminator or leading whitespace.
696            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            // Increase the indent, if requested.
713            if format.contains(ListFormat::Indented) && !self.cfg.minify {
714                self.wr.increase_indent()?;
715            }
716
717            // Emit each child.
718            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                // Emit this child.
735                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.handlers.onAfterEmitNodeArray(children);
761
762        self.emit_last_of_list5(parent_node, is_empty, format, start, count)?;
763        Ok(())
764    }
765}
766
767/// Statements
768impl<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            // Delimiters (`,`, `|`, `&`) never require committing pending semi
955            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
975/// In some cases, we need to emit a space between the operator and the operand.
976/// One obvious case is when the operator is an identifier, like delete or
977/// typeof. We also need to do this for plus and minus expressions in certain
978/// cases. Specifically, consider the following two cases (parens are just for
979/// clarity of exposition, and not part of the source code):
980///
981///  (+(+1))
982///  (+(++1))
983///
984/// We need to emit a space in both cases. In the first case, the absence of a
985/// space will make the resulting expression a prefix increment operation. And
986/// in the second, it will make the resulting expression a prefix increment
987/// whose operand is a plus expression - (++(+x)) The same is true of minus of
988/// course.
989fn 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                    // '\x20'..='\x7e'
1087                    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                    // '\x10'..='\x1f'
1098                    // '\u{7f}'..='\u{ff}'
1099                    _ => {
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                    // TODO handle `\u1111` and `\u{1111}` too
1139                    // Source - https://github.com/eslint/eslint/blob/main/lib/rules/no-useless-escape.js
1140                    '\u{2028}' | '\u{2029}' => None,
1141                    // `\t` and `\h` are special cases, because they can be replaced on real
1142                    // characters `\xXX` can be replaced on character
1143                    '\\' | '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            // Octal doesn't supported in template literals, except in tagged templates, but
1185            // we don't use this for tagged templates, they are printing as is
1186            Some('\u{0008}') => buf.push_str("\\b"),
1187            Some('\u{000c}') => buf.push_str("\\f"),
1188            Some('\n') => buf.push('\n'),
1189            // `\r` is impossible here, because it was removed on parser stage
1190            Some('\u{000b}') => buf.push_str("\\v"),
1191            Some('\t') => buf.push('\t'),
1192            // Print `"` and `'` without quotes
1193            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            // TODO(kdy1): Surrogate pairs
1209            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                    // TODO fix me - workaround for surrogate pairs
1260                    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 we've got this far the char isn't reserved and if the callee has specified
1375                    // we should output unicode for non-ascii chars then we have
1376                    // to make sure we output unicode that is safe for the target
1377                    // Es5 does not support code point escapes and so surrograte formula must be
1378                    // used
1379                    if target <= EsVersion::Es5 {
1380                        // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
1381                        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        // space is mandatory to avoid outputting <!--
1426        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    // see #415
1459    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                    // https://tc39.es/ecma262/#table-line-terminator-code-points
1466                    .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            // TODO: reenable once experimental_metadata breaking change is merged
1484            // _ => unreachable!(),
1485        }
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        // srcmap!(emitter, self, false);
1770
1771        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        //TODO: Indention
1968        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                // Check if it's last
2026                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 the string starts with a newline char, then adding a mark is redundant.
2203                // This catches both "no newlines" and "newline after several chars".
2204                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            //TODO: Check if we should use should_emit_whitespace_before_operand
2294            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        // Call emitList directly since it could be an array of
2440        // TypeParameterDeclarations _or_ type arguments
2441
2442        // emitList(node, node.typeArguments, ListFormat::TypeParameters);
2443
2444        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}