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