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;
46mod template;
47#[cfg(test)]
48mod tests;
49pub mod text_writer;
50mod typescript;
51pub mod util;
52
53pub type Result = io::Result<()>;
54
55/// Generate a code from a syntax node using default options.
56pub 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
75/// Generate a code from a syntax node using default options.
76pub fn to_code_with_comments(comments: Option<&dyn Comments>, node: &impl Node) -> String {
77    to_code_default(Default::default(), comments, node)
78}
79
80/// Generate a code from a syntax node using default options.
81pub 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/// The minimum precedence required by an expression's parent.
124///
125/// Most expressions are already parenthesized by the fixer, but non-finite
126/// numeric literals can expand into division expressions while being emitted.
127#[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            // Exponentiation cannot have an unparenthesized unary expression on
141            // the left-hand side.
142            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
174// Consume other escapes too, so an escaped backslash cannot start a newline.
175static 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    /// Emits an expression with the precedence required by its parent.
196    ///
197    /// This only changes non-finite numeric literals. All other expressions
198    /// continue through their existing emitters.
199    #[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    /// Returns whether an expression starts with an alphanumeric token after
217    /// applying code-generation-only rewrites.
218    #[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        // srcmap!(self, node, false);
309
310        // if it's false, it means it doesn't come from emit_expr,
311        // we need to compensate that
312        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    /// Prints operator and right node of a binary expression.
352    #[inline(never)]
353    fn emit_bin_expr_trailing(&mut self, node: &BinExpr) -> Result {
354        // let indent_before_op = needs_indention(node, &node.left, node.op);
355        // let indent_after_op = needs_indention(node, node.op, &node.right);
356        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                // space is mandatory to avoid outputting -->
366                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    /// prints `(b){}` from `function a(b){}`
436    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        // srcmap!(emitter,node, false);
459    }
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        // TODO: Use write_symbol when ident is a symbol.
482        self.emit_leading_comments_of_span(span, false)?;
483
484        // Source map
485        self.wr.commit_pending_semi()?;
486
487        srcmap!(self, span, true);
488        // TODO: span
489
490        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        // Call emitList directly since it could be an array of
512        // TypeParameterDeclarations _or_ type arguments
513
514        // emitList(node, node.typeArguments, ListFormat::TypeParameters);
515
516        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    /// This method exists to reduce compile time.
535    #[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                        // TODO: children.lo()
566
567                        parent_node.lo()
568                    },
569                    true,
570                    false,
571                ) {
572                    return Some(Err(err));
573                }
574            }
575        }
576
577        None
578    }
579
580    /// This method exists to reduce compile time.
581    #[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        // Write the delimiter if this is not the first node.
592        if let Some(previous_sibling) = previous_sibling {
593            // i.e
594            //      function commentedParameters(
595            //          /* Parameter a */
596            //          a
597            // /* End of parameter a */
598            // -> this comment isn't considered to be trailing comment of parameter "a" due
599            // to newline ,
600            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            // Write either a line terminator or whitespace to separate the elements.
610
611            if self.cm.should_write_separating_line_terminator(
612                Some(previous_sibling),
613                Some(child),
614                format,
615            ) {
616                // If a synthesized node in a single-line list starts on a new
617                // line, we should increase the indent.
618                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    /// This method exists to reduce compile time.
639    #[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        // Write a trailing comma, if requested.
648        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            // Emit any trailing comment of the last element in the list
679            // i.e
680            //       var array = [...
681            //          2
682            //          /* end of element 2 */
683            //       ];
684
685            let emit_trailing_comments = {
686                // TODO:
687                //
688                // !(getEmitFlags(previousSibling).contains(EmitFlags::NoTrailingComments))
689
690                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        // Decrease the indent, if requested.
705        if format.contains(ListFormat::Indented) && !self.cfg.minify {
706            self.wr.decrease_indent()?;
707        }
708
709        // Write the closing line terminator or closing whitespace.
710        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    /// This method exists to reduce compile time.
725    #[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                        //TODO: children.hi()
739
740                        parent_node.hi()
741                    },
742                    true,
743                )?; // Emit leading comments within empty lists
744            }
745            // Closing brackets never require committing pending semi
746            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            // Write a line terminator if the parent node was multi-line
770
771            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            // Write the opening line terminator or leading whitespace.
785            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            // Increase the indent, if requested.
802            if format.contains(ListFormat::Indented) && !self.cfg.minify {
803                self.wr.increase_indent()?;
804            }
805
806            // Emit each child.
807            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                // Emit this child.
824                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.handlers.onAfterEmitNodeArray(children);
850
851        self.emit_last_of_list5(parent_node, is_empty, format, start, count)?;
852        Ok(())
853    }
854}
855
856/// Statements
857impl<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            // Delimiters (`,`, `|`, `&`) never require committing pending semi
1055            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
1075/// In some cases, we need to emit a space between the operator and the operand.
1076/// One obvious case is when the operator is an identifier, like delete or
1077/// typeof. We also need to do this for plus and minus expressions in certain
1078/// cases. Specifically, consider the following two cases (parens are just for
1079/// clarity of exposition, and not part of the source code):
1080///
1081///  (+(+1))
1082///  (+(++1))
1083///
1084/// We need to emit a space in both cases. In the first case, the absence of a
1085/// space will make the resulting expression a prefix increment operation. And
1086/// in the second, it will make the resulting expression a prefix increment
1087/// whose operand is a plus expression - (++(+x)) The same is true of minus of
1088/// course.
1089fn 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                            // Decoded delimiters must not become template syntax or escapes.
1176                            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                    // Source - https://github.com/eslint/eslint/blob/main/lib/rules/no-useless-escape.js
1191                    '\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                // Adjacent decoded characters must not introduce an interpolation.
1209                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                // Decide after decoding the next character: an escaped digit or a
1217                // removed line continuation can otherwise turn \0 into an octal escape.
1218                buf.truncate(buf.len() - 2);
1219                buf.push_str("\\x00");
1220                buf.push(c);
1221            }
1222            // Octal doesn't supported in template literals, except in tagged templates, but
1223            // we don't use this for tagged templates, they are printing as is
1224            Some('\u{0008}') => buf.push_str("\\b"),
1225            Some('\u{000c}') => buf.push_str("\\f"),
1226            Some('\n') => buf.push('\n'),
1227            // A decoded carriage return must not be normalized to a line feed.
1228            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            // Print `"` and `'` without quotes
1235            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                    // TODO fix me - workaround for surrogate pairs
1301                    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 we've got this far the char isn't reserved and if the callee has specified
1416                    // we should output unicode for non-ascii chars then we have
1417                    // to make sure we output unicode that is safe for the target
1418                    // Es5 does not support code point escapes and so surrograte formula must be
1419                    // used
1420                    if target <= EsVersion::Es5 {
1421                        // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
1422                        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        // space is mandatory to avoid outputting <!--
1467        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    // see #415
1500    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                    // https://tc39.es/ecma262/#table-line-terminator-code-points
1507                    .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            // TODO: reenable once experimental_metadata breaking change is merged
1525            // _ => unreachable!(),
1526        }
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        // srcmap!(emitter, self, false);
1811
1812        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        //TODO: Indention
2010        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                // Check if it's last
2071                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            // Decoding escapes can introduce HTML script terminators or comment
2240            // markers, so protect the emitted text after the transformation.
2241            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 the string starts with a newline char, then adding a mark is redundant.
2258                // This catches both "no newlines" and "newline after several chars".
2259                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            //TODO: Check if we should use should_emit_whitespace_before_operand
2349            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        // Call emitList directly since it could be an array of
2495        // TypeParameterDeclarations _or_ type arguments
2496
2497        // emitList(node, node.typeArguments, ListFormat::TypeParameters);
2498
2499        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}