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 ascii::AsciiChar;
11use compact_str::{format_compact, CompactString};
12use memchr::memmem::Finder;
13use once_cell::sync::Lazy;
14use swc_atoms::Atom;
15use swc_common::{
16 comments::{CommentKind, Comments},
17 sync::Lrc,
18 BytePos, SourceMap, SourceMapper, Span, Spanned, DUMMY_SP,
19};
20use swc_ecma_ast::*;
21use swc_ecma_codegen_macros::emitter;
22
23pub use self::config::Config;
24use self::{text_writer::WriteJs, util::StartsWithAlphaNum};
25use crate::util::EndsWithAlphaNum;
26
27#[macro_use]
28pub mod macros;
29mod comments;
30mod config;
31mod decl;
32mod expr;
33mod jsx;
34mod stmt;
35#[cfg(test)]
36mod tests;
37pub mod text_writer;
38mod typescript;
39pub mod util;
40
41pub type Result = io::Result<()>;
42
43pub fn to_code_default(
45 cm: Lrc<SourceMap>,
46 comments: Option<&dyn Comments>,
47 node: &impl Node,
48) -> String {
49 let mut buf = std::vec::Vec::new();
50 {
51 let mut emitter = Emitter {
52 cfg: Default::default(),
53 cm: cm.clone(),
54 comments,
55 wr: text_writer::JsWriter::new(cm, "\n", &mut buf, None),
56 };
57 node.emit_with(&mut emitter).unwrap();
58 }
59
60 String::from_utf8(buf).expect("codegen generated non-utf8 output")
61}
62
63pub fn to_code_with_comments(comments: Option<&dyn Comments>, node: &impl Node) -> String {
65 to_code_default(Default::default(), comments, node)
66}
67
68pub fn to_code(node: &impl Node) -> String {
70 to_code_with_comments(None, node)
71}
72
73pub trait Node: Spanned {
74 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
75 where
76 W: WriteJs,
77 S: SourceMapper + SourceMapperExt;
78}
79impl<N: Node> Node for Box<N> {
80 #[inline]
81 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
82 where
83 W: WriteJs,
84 S: SourceMapper + SourceMapperExt,
85 {
86 (**self).emit_with(e)
87 }
88}
89impl<N: Node> Node for &N {
90 #[inline]
91 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
92 where
93 W: WriteJs,
94 S: SourceMapper + SourceMapperExt,
95 {
96 (**self).emit_with(e)
97 }
98}
99
100pub struct Emitter<'a, W, S: SourceMapper>
101where
102 W: WriteJs,
103 S: SourceMapperExt,
104{
105 pub cfg: config::Config,
106 pub cm: Lrc<S>,
107 pub comments: Option<&'a dyn Comments>,
108 pub wr: W,
109}
110
111enum CowStr<'a> {
112 Borrowed(&'a str),
113 Owned(CompactString),
114}
115
116impl Deref for CowStr<'_> {
117 type Target = str;
118
119 fn deref(&self) -> &str {
120 match self {
121 CowStr::Borrowed(s) => s,
122 CowStr::Owned(s) => s.as_str(),
123 }
124 }
125}
126
127fn replace_close_inline_script(raw: &str) -> CowStr {
128 let chars = raw.as_bytes();
129 let pattern_len = 8; let mut matched_indexes = chars
132 .iter()
133 .enumerate()
134 .filter(|(index, byte)| {
135 byte == &&b'<'
136 && index + pattern_len < chars.len()
137 && chars[index + 1..index + pattern_len].eq_ignore_ascii_case(b"/script")
138 && matches!(
139 chars[index + pattern_len],
140 b'>' | b' ' | b'\t' | b'\n' | b'\x0C' | b'\r'
141 )
142 })
143 .map(|(index, _)| index)
144 .peekable();
145
146 if matched_indexes.peek().is_none() {
147 return CowStr::Borrowed(raw);
148 }
149
150 let mut result = CompactString::new(raw);
151
152 for (offset, i) in matched_indexes.enumerate() {
153 result.insert(i + 1 + offset, '\\');
154 }
155
156 CowStr::Owned(result)
157}
158
159static NEW_LINE_TPL_REGEX: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"\\n|\n").unwrap());
160
161impl<W, S: SourceMapper> Emitter<'_, W, S>
162where
163 W: WriteJs,
164 S: SourceMapperExt,
165{
166 #[emitter]
167 pub fn emit_program(&mut self, node: &Program) -> Result {
168 match *node {
169 Program::Module(ref m) => emit!(m),
170 Program::Script(ref s) => emit!(s),
171 }
174 }
175
176 #[emitter]
177 #[tracing::instrument(skip_all)]
178 pub fn emit_module(&mut self, node: &Module) -> Result {
179 self.emit_leading_comments_of_span(node.span(), false)?;
180
181 if node.body.is_empty() {
182 srcmap!(node, true);
183 }
184
185 if let Some(ref shebang) = node.shebang {
186 punct!("#!");
187 self.wr.write_str_lit(DUMMY_SP, shebang)?;
188 self.wr.write_line()?;
189 }
190 for stmt in &node.body {
191 emit!(stmt);
192 }
193
194 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
195 if !self.cfg.omit_last_semi {
196 self.wr.commit_pending_semi()?;
197 }
198 }
199
200 #[emitter]
201 #[tracing::instrument(skip_all)]
202 pub fn emit_script(&mut self, node: &Script) -> Result {
203 self.emit_leading_comments_of_span(node.span(), false)?;
204
205 if node.body.is_empty() {
206 srcmap!(node, true);
207 }
208
209 if let Some(ref shebang) = node.shebang {
210 punct!("#!");
211 self.wr.write_str_lit(DUMMY_SP, shebang)?;
212 self.wr.write_line()?;
213 }
214 for stmt in &node.body {
215 emit!(stmt);
216 }
217
218 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
219 if !self.cfg.omit_last_semi {
220 self.wr.commit_pending_semi()?;
221 }
222 }
223
224 #[emitter]
225 pub fn emit_module_item(&mut self, node: &ModuleItem) -> Result {
226 self.emit_leading_comments_of_span(node.span(), false)?;
227 match *node {
228 ModuleItem::Stmt(ref stmt) => emit!(stmt),
229 ModuleItem::ModuleDecl(ref decl) => emit!(decl),
230 }
231 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
232 }
233
234 #[emitter]
235 fn emit_module_decl(&mut self, node: &ModuleDecl) -> Result {
236 self.emit_leading_comments_of_span(node.span(), false)?;
237
238 match *node {
239 ModuleDecl::Import(ref d) => emit!(d),
240 ModuleDecl::ExportDecl(ref d) => emit!(d),
241 ModuleDecl::ExportNamed(ref d) => emit!(d),
242 ModuleDecl::ExportDefaultDecl(ref d) => emit!(d),
243 ModuleDecl::ExportDefaultExpr(ref n) => emit!(n),
244 ModuleDecl::ExportAll(ref d) => emit!(d),
245 ModuleDecl::TsExportAssignment(ref n) => emit!(n),
246 ModuleDecl::TsImportEquals(ref n) => emit!(n),
247 ModuleDecl::TsNamespaceExport(ref n) => emit!(n),
248 }
249
250 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
251
252 if !self.cfg.minify {
253 self.wr.write_line()?;
254 }
255 }
256
257 #[emitter]
258 fn emit_export_decl(&mut self, n: &ExportDecl) -> Result {
259 srcmap!(n, true);
260
261 match &n.decl {
262 Decl::Class(decl) => {
263 for dec in &decl.class.decorators {
264 emit!(dec);
265 }
266
267 keyword!("export");
268
269 space!();
270 self.emit_class_decl_inner(decl, true)?;
271 }
272 _ => {
273 keyword!("export");
274
275 space!();
276 emit!(n.decl);
277 }
278 }
279 }
280
281 #[emitter]
282 fn emit_export_default_expr(&mut self, n: &ExportDefaultExpr) -> Result {
283 srcmap!(n, true);
284
285 keyword!("export");
286
287 space!();
288 keyword!("default");
289 {
290 let starts_with_alpha_num = n.expr.starts_with_alpha_num();
291 if starts_with_alpha_num {
292 space!();
293 } else {
294 formatting_space!();
295 }
296 emit!(n.expr);
297 }
298 semi!();
299
300 srcmap!(n, false);
301 }
302
303 #[emitter]
304 fn emit_export_default_decl(&mut self, n: &ExportDefaultDecl) -> Result {
305 self.emit_leading_comments_of_span(n.span(), false)?;
306
307 srcmap!(n, true);
308
309 keyword!("export");
310
311 space!();
312 keyword!("default");
313 space!();
314 match n.decl {
315 DefaultDecl::Class(ref n) => emit!(n),
316 DefaultDecl::Fn(ref n) => emit!(n),
317 DefaultDecl::TsInterfaceDecl(ref n) => emit!(n),
318 }
319 }
320
321 #[emitter]
322 fn emit_import(&mut self, n: &ImportDecl) -> Result {
323 self.emit_leading_comments_of_span(n.span(), false)?;
324
325 srcmap!(n, true);
326
327 keyword!("import");
328
329 if n.type_only {
330 space!();
331 keyword!("type");
332 }
333
334 match n.phase {
335 ImportPhase::Evaluation => {}
336 ImportPhase::Source => {
337 space!();
338 keyword!("source");
339 }
340 ImportPhase::Defer => {
341 space!();
342 keyword!("defer");
343 }
344 }
345
346 let starts_with_ident = !n.specifiers.is_empty()
347 && match &n.specifiers[0] {
348 ImportSpecifier::Default(_) => true,
349 _ => false,
350 };
351 if starts_with_ident {
352 space!();
353 } else {
354 formatting_space!();
355 }
356
357 let mut specifiers = Vec::new();
358 let mut emitted_default = false;
359 let mut emitted_ns = false;
360 for specifier in &n.specifiers {
361 match specifier {
362 ImportSpecifier::Named(ref s) => {
363 specifiers.push(s);
364 }
365 ImportSpecifier::Default(ref s) => {
366 emit!(s.local);
367 emitted_default = true;
368 }
369 ImportSpecifier::Namespace(ref ns) => {
370 if emitted_default {
371 punct!(",");
372 formatting_space!();
373 }
374
375 emitted_ns = true;
376
377 assert!(n.specifiers.len() <= 2);
378 punct!("*");
379 formatting_space!();
380 keyword!("as");
381 space!();
382 emit!(ns.local);
383 }
384 }
385 }
386
387 if specifiers.is_empty() {
388 if emitted_ns || emitted_default {
389 space!();
390 keyword!("from");
391 formatting_space!();
392 }
393 } else {
394 if emitted_default {
395 punct!(",");
396 formatting_space!();
397 }
398
399 punct!("{");
400 self.emit_list(
401 n.span(),
402 Some(&specifiers),
403 ListFormat::NamedImportsOrExportsElements,
404 )?;
405 punct!("}");
406 formatting_space!();
407
408 keyword!("from");
409 formatting_space!();
410 }
411
412 emit!(n.src);
413
414 if let Some(with) = &n.with {
415 formatting_space!();
416 if self.cfg.emit_assert_for_import_attributes {
417 keyword!("assert");
418 } else {
419 keyword!("with")
420 };
421 formatting_space!();
422 emit!(with);
423 }
424
425 semi!();
426
427 srcmap!(n, false);
428 }
429
430 #[emitter]
431 fn emit_import_specific(&mut self, node: &ImportNamedSpecifier) -> Result {
432 srcmap!(node, true);
433
434 if node.is_type_only {
435 keyword!("type");
436 space!();
437 }
438
439 if let Some(ref imported) = node.imported {
440 emit!(imported);
441 space!();
442 keyword!("as");
443 space!();
444 }
445
446 emit!(node.local);
447
448 srcmap!(node, false);
449 }
450
451 #[emitter]
452 fn emit_export_specifier(&mut self, node: &ExportSpecifier) -> Result {
453 match node {
454 ExportSpecifier::Default(..) => {
455 unimplemented!("codegen of `export default from 'foo';`")
456 }
457 ExportSpecifier::Namespace(ref node) => emit!(node),
458 ExportSpecifier::Named(ref node) => emit!(node),
459 }
460 }
461
462 #[emitter]
463 fn emit_namespace_export_specifier(&mut self, node: &ExportNamespaceSpecifier) -> Result {
464 self.emit_leading_comments_of_span(node.span(), false)?;
465
466 srcmap!(node, true);
467
468 punct!("*");
469 formatting_space!();
470 keyword!("as");
471 space!();
472 emit!(node.name);
473
474 srcmap!(node, false);
475 }
476
477 #[emitter]
478 fn emit_named_export_specifier(&mut self, node: &ExportNamedSpecifier) -> Result {
479 self.emit_leading_comments_of_span(node.span(), false)?;
480
481 srcmap!(node, true);
482
483 if node.is_type_only {
484 keyword!("type");
485 space!();
486 }
487
488 if let Some(exported) = &node.exported {
489 emit!(node.orig);
490 space!();
491 keyword!("as");
492 space!();
493 emit!(exported);
494 } else {
495 emit!(node.orig);
496 }
497 srcmap!(node, false);
498 }
499
500 #[emitter]
501 fn emit_named_export(&mut self, node: &NamedExport) -> Result {
502 self.emit_leading_comments_of_span(node.span(), false)?;
503
504 srcmap!(node, true);
505
506 struct Specifiers<'a> {
507 has_namespace_spec: bool,
508 namespace_spec: Option<&'a ExportNamespaceSpecifier>,
509 has_named_specs: bool,
510 named_specs: Vec<&'a ExportSpecifier>,
511 }
512 let Specifiers {
513 has_namespace_spec,
514 namespace_spec,
515 has_named_specs,
516 named_specs,
517 } = node.specifiers.iter().fold(
518 Specifiers {
519 has_namespace_spec: false,
520 namespace_spec: None,
521 has_named_specs: false,
522 named_specs: Vec::new(),
523 },
524 |mut result, s| match s {
525 ExportSpecifier::Namespace(spec) => {
526 result.has_namespace_spec = true;
527 if result.namespace_spec.is_none() {
529 result.namespace_spec = Some(spec)
530 }
531 result
532 }
533 spec => {
534 result.has_named_specs = true;
535 result.named_specs.push(spec);
536 result
537 }
538 },
539 );
540
541 keyword!("export");
542
543 if node.type_only {
544 space!();
545 keyword!("type");
546 }
547 formatting_space!();
548
549 if let Some(spec) = namespace_spec {
550 emit!(spec);
551 if has_named_specs {
552 punct!(",");
553 formatting_space!();
554 }
555 }
556 if has_named_specs || !has_namespace_spec {
557 punct!("{");
558 self.emit_list(
559 node.span,
560 Some(&named_specs),
561 ListFormat::NamedImportsOrExportsElements,
562 )?;
563 punct!("}");
564 }
565
566 if let Some(ref src) = node.src {
567 if has_named_specs || !has_namespace_spec {
568 formatting_space!();
569 } else if has_namespace_spec {
570 space!();
571 }
572 keyword!("from");
573 formatting_space!();
574 emit!(src);
575
576 if let Some(with) = &node.with {
577 formatting_space!();
578 if self.cfg.emit_assert_for_import_attributes {
579 keyword!("assert");
580 } else {
581 keyword!("with")
582 };
583 formatting_space!();
584 emit!(with);
585 }
586 }
587 semi!();
588
589 srcmap!(node, false);
590 }
591
592 #[emitter]
593 fn emit_export_all(&mut self, node: &ExportAll) -> Result {
594 self.emit_leading_comments_of_span(node.span(), false)?;
595
596 srcmap!(node, true);
597
598 keyword!("export");
599
600 if node.type_only {
601 space!();
602 keyword!("type");
603 space!();
604 } else {
605 formatting_space!();
606 }
607
608 punct!("*");
609 formatting_space!();
610 keyword!("from");
611 formatting_space!();
612 emit!(node.src);
613
614 if let Some(with) = &node.with {
615 formatting_space!();
616 if self.cfg.emit_assert_for_import_attributes {
617 keyword!("assert");
618 } else {
619 keyword!("with")
620 };
621 formatting_space!();
622 emit!(with);
623 }
624
625 semi!();
626
627 srcmap!(node, false);
628 }
629
630 #[emitter]
631
632 fn emit_lit(&mut self, node: &Lit) -> Result {
633 self.emit_leading_comments_of_span(node.span(), false)?;
634
635 srcmap!(node, true);
636
637 match *node {
638 Lit::Bool(Bool { value, .. }) => {
639 if value {
640 keyword!("true")
641 } else {
642 keyword!("false")
643 }
644 }
645 Lit::Null(Null { .. }) => keyword!("null"),
646 Lit::Str(ref s) => emit!(s),
647 Lit::BigInt(ref s) => emit!(s),
648 Lit::Num(ref n) => emit!(n),
649 Lit::Regex(ref n) => {
650 punct!("/");
651 self.wr.write_str(&n.exp)?;
652 punct!("/");
653 self.wr.write_str(&n.flags)?;
654 }
655 Lit::JSXText(ref n) => emit!(n),
656 }
657 }
658
659 fn emit_atom(&mut self, span: Span, value: &Atom) -> Result {
660 self.wr.write_str_lit(span, value)?;
661
662 Ok(())
663 }
664
665 #[emitter]
666
667 fn emit_str_lit(&mut self, node: &Str) -> Result {
668 self.wr.commit_pending_semi()?;
669
670 self.emit_leading_comments_of_span(node.span(), false)?;
671
672 srcmap!(node, true);
673
674 if &*node.value == "use strict"
675 && node.raw.is_some()
676 && node.raw.as_ref().unwrap().contains('\\')
677 && (!self.cfg.inline_script || !node.raw.as_ref().unwrap().contains("script"))
678 {
679 self.wr
680 .write_str_lit(DUMMY_SP, node.raw.as_ref().unwrap())?;
681
682 srcmap!(node, false);
683
684 return Ok(());
685 }
686
687 let target = self.cfg.target;
688
689 if !self.cfg.minify {
690 if let Some(raw) = &node.raw {
691 if (!self.cfg.ascii_only || raw.is_ascii())
692 && (!self.cfg.inline_script || !node.raw.as_ref().unwrap().contains("script"))
693 {
694 self.wr.write_str_lit(DUMMY_SP, raw)?;
695 return Ok(());
696 }
697 }
698 }
699
700 let (quote_char, mut value) = get_quoted_utf16(&node.value, self.cfg.ascii_only, target);
701
702 if self.cfg.inline_script {
703 value = CowStr::Owned(
704 replace_close_inline_script(&value)
705 .replace("\x3c!--", "\\x3c!--")
706 .replace("--\x3e", "--\\x3e")
707 .into(),
708 );
709 }
710
711 let quote_str = [quote_char.as_byte()];
712 let quote_str = unsafe {
713 str::from_utf8_unchecked("e_str)
715 };
716
717 self.wr.write_str(quote_str)?;
718 self.wr.write_str_lit(DUMMY_SP, &value)?;
719 self.wr.write_str(quote_str)?;
720
721 }
723
724 #[emitter]
725
726 fn emit_num_lit(&mut self, num: &Number) -> Result {
727 self.emit_num_lit_internal(num, false)?;
728 }
729
730 fn emit_num_lit_internal(
733 &mut self,
734 num: &Number,
735 mut detect_dot: bool,
736 ) -> std::result::Result<bool, io::Error> {
737 self.wr.commit_pending_semi()?;
738
739 self.emit_leading_comments_of_span(num.span(), false)?;
740
741 if num.value.is_infinite() && num.raw.is_none() {
743 if num.value.is_sign_negative() {
744 self.wr.write_str_lit(num.span, "-")?;
745 }
746 self.wr.write_str_lit(num.span, "Infinity")?;
747
748 return Ok(false);
749 }
750
751 let mut striped_raw = None;
752 let mut value = String::default();
753
754 srcmap!(self, num, true);
755
756 if self.cfg.minify {
757 if num.value.is_infinite() && num.raw.is_some() {
758 self.wr.write_str_lit(DUMMY_SP, num.raw.as_ref().unwrap())?;
759 } else {
760 value = minify_number(num.value, &mut detect_dot);
761 self.wr.write_str_lit(DUMMY_SP, &value)?;
762 }
763 } else {
764 match &num.raw {
765 Some(raw) => {
766 if raw.len() > 2 && self.cfg.target < EsVersion::Es2015 && {
767 let slice = &raw.as_bytes()[..2];
768 slice == b"0b" || slice == b"0o" || slice == b"0B" || slice == b"0O"
769 } {
770 if num.value.is_infinite() && num.raw.is_some() {
771 self.wr.write_str_lit(DUMMY_SP, num.raw.as_ref().unwrap())?;
772 } else {
773 value = num.value.to_string();
774 self.wr.write_str_lit(DUMMY_SP, &value)?;
775 }
776 } else if raw.len() > 2
777 && self.cfg.target < EsVersion::Es2021
778 && raw.contains('_')
779 {
780 let value = raw.replace('_', "");
781 self.wr.write_str_lit(DUMMY_SP, &value)?;
782
783 striped_raw = Some(value);
784 } else {
785 self.wr.write_str_lit(DUMMY_SP, raw)?;
786
787 if !detect_dot {
788 return Ok(false);
789 }
790
791 striped_raw = Some(raw.replace('_', ""));
792 }
793 }
794 _ => {
795 value = num.value.to_string();
796 self.wr.write_str_lit(DUMMY_SP, &value)?;
797 }
798 }
799 }
800
801 if !detect_dot {
803 return Ok(false);
804 }
805
806 Ok(striped_raw
807 .map(|raw| {
808 if raw.bytes().all(|c| c.is_ascii_digit()) {
809 let slice = raw.as_bytes();
812 if slice.len() >= 2 && slice[0] == b'0' {
813 return false;
814 }
815
816 return true;
817 }
818
819 false
820 })
821 .unwrap_or_else(|| {
822 let bytes = value.as_bytes();
823
824 if !bytes.contains(&b'.') && !bytes.contains(&b'e') {
825 return true;
826 }
827
828 false
829 }))
830 }
831
832 #[emitter]
833 fn emit_big_lit(&mut self, v: &BigInt) -> Result {
834 self.emit_leading_comments_of_span(v.span, false)?;
835
836 if self.cfg.minify {
837 let value = if *v.value >= 10000000000000000_i64.into() {
838 format!("0x{}", v.value.to_str_radix(16))
839 } else if *v.value <= (-10000000000000000_i64).into() {
840 format!("-0x{}", (-*v.value.clone()).to_str_radix(16))
841 } else {
842 v.value.to_string()
843 };
844 self.wr.write_lit(v.span, &value)?;
845 self.wr.write_lit(v.span, "n")?;
846 } else {
847 match &v.raw {
848 Some(raw) => {
849 if raw.len() > 2 && self.cfg.target < EsVersion::Es2021 && raw.contains('_') {
850 self.wr.write_str_lit(v.span, &raw.replace('_', ""))?;
851 } else {
852 self.wr.write_str_lit(v.span, raw)?;
853 }
854 }
855 _ => {
856 self.wr.write_lit(v.span, &v.value.to_string())?;
857 self.wr.write_lit(v.span, "n")?;
858 }
859 }
860 }
861 }
862
863 #[emitter]
888 fn emit_callee(&mut self, node: &Callee) -> Result {
889 match *node {
890 Callee::Expr(ref e) => {
891 if let Expr::New(new) = &**e {
892 self.emit_new(new, false)?;
893 } else {
894 emit!(e);
895 }
896 }
897 Callee::Super(ref n) => emit!(n),
898 Callee::Import(ref n) => emit!(n),
899 }
900 }
901
902 #[emitter]
903 fn emit_super(&mut self, node: &Super) -> Result {
904 keyword!(node.span, "super");
905 }
906
907 #[emitter]
908 fn emit_import_callee(&mut self, node: &Import) -> Result {
909 keyword!(node.span, "import");
910 match node.phase {
911 ImportPhase::Source => {
912 punct!(".");
913 keyword!("source")
914 }
915 ImportPhase::Defer => {
916 punct!(".");
917 keyword!("defer")
918 }
919 _ => {}
920 }
921 }
922
923 #[emitter]
924
925 fn emit_expr(&mut self, node: &Expr) -> Result {
926 match node {
927 Expr::Array(ref n) => emit!(n),
928 Expr::Arrow(ref n) => emit!(n),
929 Expr::Assign(ref n) => emit!(n),
930 Expr::Await(ref n) => emit!(n),
931 Expr::Bin(ref n) => emit!(n),
932 Expr::Call(ref n) => emit!(n),
933 Expr::Class(ref n) => emit!(n),
934 Expr::Cond(ref n) => emit!(n),
935 Expr::Fn(ref n) => emit!(n),
936 Expr::Ident(ref n) => emit!(n),
937 Expr::Lit(ref n) => emit!(n),
938 Expr::Member(ref n) => emit!(n),
939 Expr::SuperProp(ref n) => emit!(n),
940 Expr::MetaProp(ref n) => emit!(n),
941 Expr::New(ref n) => emit!(n),
942 Expr::Object(ref n) => emit!(n),
943 Expr::Paren(ref n) => emit!(n),
944 Expr::Seq(ref n) => emit!(n),
945 Expr::TaggedTpl(ref n) => emit!(n),
946 Expr::This(ref n) => emit!(n),
947 Expr::Tpl(ref n) => emit!(n),
948 Expr::Unary(ref n) => emit!(n),
949 Expr::Update(ref n) => emit!(n),
950 Expr::Yield(ref n) => emit!(n),
951 Expr::PrivateName(ref n) => emit!(n),
952
953 Expr::JSXMember(ref n) => emit!(n),
954 Expr::JSXNamespacedName(ref n) => emit!(n),
955 Expr::JSXEmpty(ref n) => emit!(n),
956 Expr::JSXElement(ref n) => emit!(n),
957 Expr::JSXFragment(ref n) => emit!(n),
958
959 Expr::TsAs(ref n) => emit!(n),
960 Expr::TsNonNull(ref n) => emit!(n),
961 Expr::TsTypeAssertion(ref n) => emit!(n),
962 Expr::TsConstAssertion(ref n) => emit!(n),
963 Expr::TsInstantiation(ref n) => emit!(n),
964 Expr::OptChain(ref n) => emit!(n),
965 Expr::Invalid(ref n) => emit!(n),
966 Expr::TsSatisfies(n) => {
967 emit!(n)
968 }
969 }
970
971 if self.comments.is_some() {
972 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
973 }
974 }
975
976 #[emitter]
977 fn emit_opt_chain(&mut self, n: &OptChainExpr) -> Result {
978 self.emit_leading_comments_of_span(n.span(), false)?;
979
980 match &*n.base {
981 OptChainBase::Member(ref e) => {
982 if let Expr::New(new) = &*e.obj {
983 self.emit_new(new, false)?;
984 } else {
985 emit!(e.obj);
986 }
987 if n.optional {
988 punct!("?.");
989 } else if !e.prop.is_computed() {
990 punct!(".");
991 }
992
993 match &e.prop {
994 MemberProp::Computed(computed) => emit!(computed),
995 MemberProp::Ident(i) => emit!(i),
996 MemberProp::PrivateName(p) => emit!(p),
997 }
998 }
999 OptChainBase::Call(ref e) => {
1000 debug_assert!(!e.callee.is_new());
1001 emit!(e.callee);
1002
1003 if n.optional {
1004 punct!("?.");
1005 }
1006
1007 punct!("(");
1008 self.emit_expr_or_spreads(n.span(), &e.args, ListFormat::CallExpressionArguments)?;
1009 punct!(")");
1010 }
1011 }
1012 }
1013
1014 #[emitter]
1015 fn emit_invalid(&mut self, n: &Invalid) -> Result {
1016 self.emit_leading_comments_of_span(n.span, false)?;
1017
1018 self.wr.write_str_lit(n.span, "<invalid>")?;
1019 }
1020
1021 #[emitter]
1022 fn emit_call_expr(&mut self, node: &CallExpr) -> Result {
1023 self.wr.commit_pending_semi()?;
1024
1025 self.emit_leading_comments_of_span(node.span(), false)?;
1026
1027 srcmap!(node, true);
1028
1029 emit!(node.callee);
1030
1031 if let Some(type_args) = &node.type_args {
1032 emit!(type_args);
1033 }
1034
1035 punct!("(");
1036 self.emit_expr_or_spreads(node.span(), &node.args, ListFormat::CallExpressionArguments)?;
1037 punct!(")");
1038
1039 }
1041
1042 fn emit_new(&mut self, node: &NewExpr, should_ignore_empty_args: bool) -> Result {
1043 self.wr.commit_pending_semi()?;
1044
1045 self.emit_leading_comments_of_span(node.span(), false)?;
1046
1047 srcmap!(self, node, true);
1048
1049 keyword!(self, "new");
1050
1051 let starts_with_alpha_num = node.callee.starts_with_alpha_num();
1052
1053 if starts_with_alpha_num {
1054 space!(self);
1055 } else {
1056 formatting_space!(self);
1057 }
1058 emit!(self, node.callee);
1059
1060 if let Some(type_args) = &node.type_args {
1061 emit!(self, type_args);
1062 }
1063
1064 if let Some(ref args) = node.args {
1065 if !(self.cfg.minify && args.is_empty() && should_ignore_empty_args) {
1066 punct!(self, "(");
1067 self.emit_expr_or_spreads(node.span(), args, ListFormat::NewExpressionArguments)?;
1068 punct!(self, ")");
1069 }
1070 }
1071
1072 if !should_ignore_empty_args && self.comments.is_some() {
1077 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
1078 }
1079
1080 Ok(())
1081 }
1082
1083 #[emitter]
1084 fn emit_new_expr(&mut self, node: &NewExpr) -> Result {
1085 self.emit_new(node, true)?;
1086 }
1087
1088 #[emitter]
1089 fn emit_member_expr(&mut self, node: &MemberExpr) -> Result {
1090 self.emit_leading_comments_of_span(node.span(), false)?;
1091
1092 srcmap!(node, true);
1093
1094 let mut needs_2dots_for_property_access = false;
1095
1096 match &*node.obj {
1097 Expr::New(new) => {
1098 self.emit_new(new, false)?;
1099 }
1100 Expr::Lit(Lit::Num(num)) => {
1101 needs_2dots_for_property_access = self.emit_num_lit_internal(num, true)?;
1102 }
1103 _ => {
1104 emit!(node.obj);
1105 }
1106 }
1107
1108 match &node.prop {
1109 MemberProp::Computed(computed) => emit!(computed),
1110 MemberProp::Ident(ident) => {
1111 if needs_2dots_for_property_access {
1112 if node.prop.span().lo() >= BytePos(2) {
1113 self.emit_leading_comments(node.prop.span().lo() - BytePos(2), false)?;
1114 }
1115 punct!(".");
1116 }
1117 if node.prop.span().lo() >= BytePos(1) {
1118 self.emit_leading_comments(node.prop.span().lo() - BytePos(1), false)?;
1119 }
1120 punct!(".");
1121 emit!(ident);
1122 }
1123 MemberProp::PrivateName(private) => {
1124 if needs_2dots_for_property_access {
1125 if node.prop.span().lo() >= BytePos(2) {
1126 self.emit_leading_comments(node.prop.span().lo() - BytePos(2), false)?;
1127 }
1128 punct!(".");
1129 }
1130 if node.prop.span().lo() >= BytePos(1) {
1131 self.emit_leading_comments(node.prop.span().lo() - BytePos(1), false)?;
1132 }
1133 punct!(".");
1134 emit!(private);
1135 }
1136 }
1137
1138 srcmap!(node, false);
1139 }
1140
1141 #[emitter]
1142 fn emit_super_expr(&mut self, node: &SuperPropExpr) -> Result {
1143 self.emit_leading_comments_of_span(node.span(), false)?;
1144
1145 srcmap!(node, true);
1146
1147 emit!(node.obj);
1148
1149 match &node.prop {
1150 SuperProp::Computed(computed) => emit!(computed),
1151 SuperProp::Ident(i) => {
1152 if node.prop.span().lo() >= BytePos(1) {
1153 self.emit_leading_comments(node.prop.span().lo() - BytePos(1), false)?;
1154 }
1155 punct!(".");
1156 emit!(i);
1157 }
1158 }
1159 }
1160
1161 #[emitter]
1162 fn emit_arrow_expr(&mut self, node: &ArrowExpr) -> Result {
1163 self.emit_leading_comments_of_span(node.span(), false)?;
1164
1165 srcmap!(node, true);
1166
1167 let space = !self.cfg.minify
1168 || match node.params.as_slice() {
1169 [Pat::Ident(_)] => true,
1170 _ => false,
1171 };
1172
1173 if node.is_async {
1174 keyword!("async");
1175 if space {
1176 space!();
1177 } else {
1178 formatting_space!();
1179 }
1180 }
1181 if node.is_generator {
1182 punct!("*")
1183 }
1184
1185 let parens = !self.cfg.minify
1186 || match node.params.as_slice() {
1187 [Pat::Ident(i)] => self.has_trailing_comment(i.span),
1188 _ => true,
1189 };
1190
1191 emit!(node.type_params);
1192
1193 if parens {
1194 punct!("(");
1195 }
1196
1197 self.emit_list(node.span, Some(&node.params), ListFormat::CommaListElements)?;
1198 if parens {
1199 punct!(")");
1200 }
1201
1202 if let Some(ty) = &node.return_type {
1203 punct!(":");
1204 formatting_space!();
1205 emit!(ty);
1206 formatting_space!();
1207 }
1208
1209 punct!("=>");
1210 emit!(node.body);
1211 }
1212
1213 #[emitter]
1214 fn emit_meta_prop_expr(&mut self, node: &MetaPropExpr) -> Result {
1215 if self.comments.is_some() {
1216 self.emit_leading_comments_of_span(node.span(), false)?;
1217 }
1218
1219 srcmap!(node, true);
1220
1221 match node.kind {
1222 MetaPropKind::ImportMeta => keyword!("import.meta"),
1223
1224 MetaPropKind::NewTarget => keyword!("new.target"),
1225 }
1226 }
1227
1228 #[emitter]
1229 fn emit_seq_expr(&mut self, node: &SeqExpr) -> Result {
1230 self.emit_leading_comments_of_span(node.span(), false)?;
1231
1232 srcmap!(node, true);
1233
1234 let mut first = true;
1235 for e in &node.exprs {
1237 if first {
1238 first = false
1239 } else {
1240 punct!(",");
1241 formatting_space!();
1242 }
1243
1244 emit!(e);
1245 }
1246 }
1247
1248 #[emitter]
1249 fn emit_assign_expr(&mut self, node: &AssignExpr) -> Result {
1250 self.emit_leading_comments_of_span(node.span(), false)?;
1251
1252 emit!(node.left);
1253 formatting_space!();
1254 operator!(node.op.as_str());
1255 formatting_space!();
1256 emit!(node.right);
1257 }
1258
1259 #[inline(never)]
1261 fn emit_bin_expr_trailing(&mut self, node: &BinExpr) -> Result {
1262 let is_kwd_op = match node.op {
1265 op!("in") | op!("instanceof") => true,
1266 _ => false,
1267 };
1268
1269 let need_pre_space = if self.cfg.minify {
1270 if is_kwd_op {
1271 node.left.ends_with_alpha_num()
1272 } else {
1273 match *node.left {
1275 Expr::Update(UpdateExpr {
1276 prefix: false, op, ..
1277 }) => matches!(
1278 (op, node.op),
1279 (op!("--"), op!(">") | op!(">>") | op!(">>>") | op!(">="))
1280 ),
1281 _ => false,
1282 }
1283 }
1284 } else {
1285 is_kwd_op
1286 || match *node.left {
1287 Expr::Update(UpdateExpr { prefix: false, .. }) => true,
1288 _ => false,
1289 }
1290 };
1291 if need_pre_space {
1292 space!(self);
1293 } else {
1294 formatting_space!(self);
1295 }
1296 operator!(self, node.op.as_str());
1297
1298 let need_post_space = if self.cfg.minify {
1299 if is_kwd_op {
1300 node.right.starts_with_alpha_num()
1301 } else if node.op == op!("/") {
1302 let span = node.right.span();
1303
1304 span.is_pure()
1305 || self
1306 .comments
1307 .map_or(false, |comments| comments.has_leading(node.right.span().lo))
1308 } else {
1309 require_space_before_rhs(&node.right, &node.op)
1310 }
1311 } else {
1312 is_kwd_op
1313 || match *node.right {
1314 Expr::Unary(..) | Expr::Update(UpdateExpr { prefix: true, .. }) => true,
1315 _ => false,
1316 }
1317 };
1318 if need_post_space {
1319 space!(self);
1320 } else {
1321 formatting_space!(self);
1322 }
1323 emit!(self, node.right);
1324
1325 Ok(())
1326 }
1327
1328 #[emitter]
1329 fn emit_bin_expr(&mut self, node: &BinExpr) -> Result {
1330 self.emit_leading_comments_of_span(node.span(), false)?;
1331
1332 srcmap!(node, true);
1333
1334 {
1335 let mut left = Some(node);
1336 let mut lefts = Vec::new();
1337 while let Some(l) = left {
1338 lefts.push(l);
1339
1340 match &*l.left {
1341 Expr::Bin(b) => {
1342 left = Some(b);
1343 }
1344 _ => break,
1345 }
1346 }
1347
1348 let len = lefts.len();
1349
1350 for (i, left) in lefts.into_iter().rev().enumerate() {
1351 if i == 0 {
1352 emit!(left.left);
1353 }
1354 if i + 1 != len {
1356 self.emit_bin_expr_trailing(left)?;
1357 }
1358 }
1359 }
1360
1361 self.emit_bin_expr_trailing(node)?;
1362 }
1363
1364 #[emitter]
1365 fn emit_decorator(&mut self, node: &Decorator) -> Result {
1366 self.emit_leading_comments_of_span(node.span(), false)?;
1367
1368 srcmap!(node, true);
1369
1370 punct!("@");
1371 emit!(node.expr);
1372 self.wr.write_line()?;
1373
1374 srcmap!(node, false);
1375 }
1376
1377 #[emitter]
1378 fn emit_class_expr(&mut self, node: &ClassExpr) -> Result {
1379 self.emit_leading_comments_of_span(node.span(), false)?;
1380
1381 srcmap!(node, true);
1382
1383 for dec in &node.class.decorators {
1384 emit!(dec);
1385 }
1386
1387 if node.class.is_abstract {
1388 keyword!("abstract");
1389 space!();
1390 }
1391
1392 keyword!("class");
1393
1394 if let Some(ref i) = node.ident {
1395 space!();
1396 emit!(i);
1397 emit!(node.class.type_params);
1398 }
1399
1400 self.emit_class_trailing(&node.class)?;
1401 }
1402
1403 #[emitter]
1404 fn emit_class_trailing(&mut self, node: &Class) -> Result {
1405 if node.super_class.is_some() {
1406 space!();
1407 keyword!("extends");
1408
1409 {
1410 let starts_with_alpha_num =
1411 node.super_class.as_ref().unwrap().starts_with_alpha_num();
1412
1413 if starts_with_alpha_num {
1414 space!();
1415 } else {
1416 formatting_space!()
1417 }
1418 }
1419 emit!(node.super_class);
1420 emit!(node.super_type_params);
1421 }
1422
1423 if !node.implements.is_empty() {
1424 space!();
1425 keyword!("implements");
1426
1427 space!();
1428
1429 self.emit_list(
1430 node.span,
1431 Some(&node.implements),
1432 ListFormat::ClassHeritageClauses,
1433 )?;
1434 }
1435
1436 formatting_space!();
1437
1438 punct!("{");
1439
1440 self.emit_list(node.span, Some(&node.body), ListFormat::ClassMembers)?;
1441
1442 srcmap!(node, false, true);
1443 punct!("}");
1444 }
1445
1446 #[emitter]
1447
1448 fn emit_class_member(&mut self, node: &ClassMember) -> Result {
1449 match *node {
1450 ClassMember::Constructor(ref n) => emit!(n),
1451 ClassMember::ClassProp(ref n) => emit!(n),
1452 ClassMember::Method(ref n) => emit!(n),
1453 ClassMember::PrivateMethod(ref n) => emit!(n),
1454 ClassMember::PrivateProp(ref n) => emit!(n),
1455 ClassMember::TsIndexSignature(ref n) => emit!(n),
1456 ClassMember::Empty(ref n) => emit!(n),
1457 ClassMember::StaticBlock(ref n) => emit!(n),
1458 ClassMember::AutoAccessor(ref n) => emit!(n),
1459 }
1460 }
1461
1462 #[emitter]
1463 fn emit_auto_accessor(&mut self, n: &AutoAccessor) -> Result {
1464 self.emit_list(n.span, Some(&n.decorators), ListFormat::Decorators)?;
1465
1466 self.emit_accessibility(n.accessibility)?;
1467
1468 if n.is_static {
1469 keyword!("static");
1470 space!();
1471 }
1472
1473 if n.is_abstract {
1474 keyword!("abstract");
1475 space!();
1476 }
1477
1478 if n.is_override {
1479 keyword!("override");
1480 space!();
1481 }
1482
1483 keyword!("accessor");
1484 space!();
1485
1486 emit!(n.key);
1487
1488 if let Some(type_ann) = &n.type_ann {
1489 if n.definite {
1490 punct!("!");
1491 }
1492 punct!(":");
1493 space!();
1494 emit!(type_ann);
1495 }
1496
1497 if let Some(init) = &n.value {
1498 formatting_space!();
1499 punct!("=");
1500 formatting_space!();
1501 emit!(init);
1502 }
1503
1504 semi!();
1505 }
1506
1507 #[emitter]
1508 fn emit_key(&mut self, n: &Key) -> Result {
1509 match n {
1510 Key::Private(n) => emit!(n),
1511 Key::Public(n) => emit!(n),
1512 }
1513 }
1514
1515 #[emitter]
1516 fn emit_private_method(&mut self, n: &PrivateMethod) -> Result {
1517 self.emit_leading_comments_of_span(n.span(), false)?;
1518
1519 srcmap!(n, true);
1520
1521 if n.is_static {
1522 keyword!("static");
1523 space!();
1524 }
1525 match n.kind {
1526 MethodKind::Method => {
1527 if n.function.is_async {
1528 keyword!("async");
1529 space!();
1530 }
1531 if n.function.is_generator {
1532 punct!("*");
1533 }
1534
1535 emit!(n.key);
1536 }
1537 MethodKind::Getter => {
1538 keyword!("get");
1539 space!();
1540
1541 emit!(n.key);
1542 }
1543 MethodKind::Setter => {
1544 keyword!("set");
1545 space!();
1546
1547 emit!(n.key);
1548 }
1549 }
1550
1551 self.emit_fn_trailing(&n.function)?;
1552 }
1553
1554 #[emitter]
1555 fn emit_bool(&mut self, n: &Bool) -> Result {
1556 self.emit_leading_comments_of_span(n.span(), false)?;
1557
1558 if n.value {
1559 keyword!(n.span, "true")
1560 } else {
1561 keyword!(n.span, "false")
1562 }
1563 }
1564
1565 #[emitter]
1566 fn emit_class_method(&mut self, n: &ClassMethod) -> Result {
1567 self.emit_leading_comments_of_span(n.span(), false)?;
1568
1569 self.emit_leading_comments_of_span(n.key.span(), false)?;
1570
1571 srcmap!(n, true);
1572
1573 for d in &n.function.decorators {
1574 emit!(d);
1575 }
1576
1577 self.emit_accessibility(n.accessibility)?;
1578
1579 if n.is_static {
1580 keyword!("static");
1581
1582 let starts_with_alpha_num = match n.kind {
1583 MethodKind::Method => {
1584 if n.function.is_async {
1585 true
1586 } else if n.function.is_generator {
1587 false
1588 } else {
1589 n.key.starts_with_alpha_num()
1590 }
1591 }
1592 MethodKind::Getter => true,
1593 MethodKind::Setter => true,
1594 };
1595
1596 if starts_with_alpha_num {
1597 space!();
1598 } else {
1599 formatting_space!();
1600 }
1601 }
1602
1603 if n.is_abstract {
1604 keyword!("abstract");
1605 space!()
1606 }
1607
1608 if n.is_override {
1609 keyword!("override");
1610 space!()
1611 }
1612
1613 match n.kind {
1614 MethodKind::Method => {
1615 if n.function.is_async {
1616 keyword!("async");
1617 space!();
1618 }
1619 if n.function.is_generator {
1620 punct!("*");
1621 }
1622
1623 emit!(n.key);
1624 }
1625 MethodKind::Getter => {
1626 keyword!("get");
1627
1628 if n.key.starts_with_alpha_num() {
1629 space!();
1630 } else {
1631 formatting_space!()
1632 }
1633
1634 emit!(n.key);
1635 }
1636 MethodKind::Setter => {
1637 keyword!("set");
1638
1639 if n.key.starts_with_alpha_num() {
1640 space!();
1641 } else {
1642 formatting_space!()
1643 }
1644
1645 emit!(n.key);
1646 }
1647 }
1648
1649 if n.is_optional {
1650 punct!("?");
1651 }
1652
1653 if let Some(type_params) = &n.function.type_params {
1654 emit!(type_params);
1655 }
1656
1657 punct!("(");
1658 self.emit_list(
1659 n.function.span,
1660 Some(&n.function.params),
1661 ListFormat::CommaListElements,
1662 )?;
1663
1664 punct!(")");
1665
1666 if let Some(ty) = &n.function.return_type {
1667 punct!(":");
1668 formatting_space!();
1669 emit!(ty);
1670 }
1671
1672 if let Some(body) = &n.function.body {
1673 formatting_space!();
1674 emit!(body);
1675 } else {
1676 formatting_semi!()
1677 }
1678 }
1679
1680 #[emitter]
1681 fn emit_private_prop(&mut self, n: &PrivateProp) -> Result {
1682 self.emit_leading_comments_of_span(n.span(), false)?;
1683
1684 srcmap!(n, true);
1685
1686 self.emit_list(n.span, Some(&n.decorators), ListFormat::Decorators)?;
1687
1688 self.emit_accessibility(n.accessibility)?;
1689
1690 if n.is_static {
1691 keyword!("static");
1692 space!();
1693 }
1694
1695 if n.is_override {
1696 keyword!("override");
1697 space!()
1698 }
1699
1700 if n.readonly {
1701 keyword!("readonly");
1702 space!();
1703 }
1704
1705 emit!(n.key);
1706
1707 if n.is_optional {
1708 punct!("?");
1709 }
1710
1711 if let Some(type_ann) = &n.type_ann {
1712 if n.definite {
1713 punct!("!");
1714 }
1715 punct!(":");
1716 space!();
1717 emit!(type_ann);
1718 }
1719
1720 if let Some(value) = &n.value {
1721 formatting_space!();
1722 punct!("=");
1723 formatting_space!();
1724
1725 if value.is_seq() {
1726 punct!("(");
1727 emit!(value);
1728 punct!(")");
1729 } else {
1730 emit!(value);
1731 }
1732 }
1733
1734 semi!();
1735
1736 srcmap!(n, false);
1737 }
1738
1739 #[emitter]
1740 fn emit_class_prop(&mut self, n: &ClassProp) -> Result {
1741 self.emit_leading_comments_of_span(n.span(), false)?;
1742 srcmap!(n, true);
1743
1744 for dec in &n.decorators {
1745 emit!(dec)
1746 }
1747
1748 if n.declare {
1749 keyword!("declare");
1750 space!();
1751 }
1752
1753 self.emit_accessibility(n.accessibility)?;
1754
1755 if n.is_static {
1756 keyword!("static");
1757 space!();
1758 }
1759
1760 if n.is_abstract {
1761 keyword!("abstract");
1762 space!()
1763 }
1764
1765 if n.is_override {
1766 keyword!("override");
1767 space!()
1768 }
1769
1770 if n.readonly {
1771 keyword!("readonly");
1772 space!()
1773 }
1774
1775 emit!(n.key);
1776
1777 if n.is_optional {
1778 punct!("?");
1779 }
1780
1781 if let Some(ty) = &n.type_ann {
1782 if n.definite {
1783 punct!("!");
1784 }
1785 punct!(":");
1786 space!();
1787 emit!(ty);
1788 }
1789
1790 if let Some(v) = &n.value {
1791 formatting_space!();
1792 punct!("=");
1793 formatting_space!();
1794
1795 if v.is_seq() {
1796 punct!("(");
1797 emit!(v);
1798 punct!(")");
1799 } else {
1800 emit!(v);
1801 }
1802 }
1803
1804 semi!();
1805
1806 srcmap!(n, false);
1807 }
1808
1809 fn emit_accessibility(&mut self, n: Option<Accessibility>) -> Result {
1810 if let Some(a) = n {
1811 match a {
1812 Accessibility::Public => keyword!(self, "public"),
1813 Accessibility::Protected => keyword!(self, "protected"),
1814 Accessibility::Private => keyword!(self, "private"),
1815 }
1816 space!(self);
1817 }
1818
1819 Ok(())
1820 }
1821
1822 #[emitter]
1823
1824 fn emit_class_constructor(&mut self, n: &Constructor) -> Result {
1825 self.emit_leading_comments_of_span(n.span(), false)?;
1826
1827 srcmap!(n, true);
1828
1829 self.emit_accessibility(n.accessibility)?;
1830
1831 keyword!("constructor");
1832 punct!("(");
1833 self.emit_list(n.span(), Some(&n.params), ListFormat::Parameters)?;
1834 punct!(")");
1835
1836 if let Some(body) = &n.body {
1837 emit!(body);
1838 } else {
1839 formatting_semi!();
1840 }
1841 }
1842
1843 #[emitter]
1844 fn emit_static_block(&mut self, n: &StaticBlock) -> Result {
1845 self.emit_leading_comments_of_span(n.span(), false)?;
1846
1847 srcmap!(n, true);
1848
1849 keyword!("static");
1850 emit!(n.body);
1851
1852 srcmap!(n, false);
1853 }
1854
1855 #[emitter]
1856 fn emit_prop_name(&mut self, node: &PropName) -> Result {
1857 match node {
1858 PropName::Ident(ident) => {
1859 self.emit_leading_comments_of_span(ident.span, false)?;
1861
1862 self.wr.commit_pending_semi()?;
1864
1865 srcmap!(ident, true);
1866
1867 if self.cfg.ascii_only {
1868 if self.wr.can_ignore_invalid_unicodes() {
1869 self.wr.write_symbol(
1870 DUMMY_SP,
1871 &get_ascii_only_ident(&ident.sym, true, self.cfg.target),
1872 )?;
1873 } else {
1874 self.wr.write_symbol(
1875 DUMMY_SP,
1876 &get_ascii_only_ident(
1877 &handle_invalid_unicodes(&ident.sym),
1878 true,
1879 self.cfg.target,
1880 ),
1881 )?;
1882 }
1883 } else {
1884 emit!(ident);
1885 }
1886 }
1887 PropName::Str(ref n) => emit!(n),
1888 PropName::Num(ref n) => emit!(n),
1889 PropName::BigInt(ref n) => emit!(n),
1890 PropName::Computed(ref n) => emit!(n),
1891 }
1892 }
1893
1894 #[emitter]
1895 fn emit_computed_prop_name(&mut self, n: &ComputedPropName) -> Result {
1896 srcmap!(n, true);
1897
1898 punct!("[");
1899 emit!(n.expr);
1900 punct!("]");
1901
1902 srcmap!(n, false);
1903 }
1904
1905 #[emitter]
1906 fn emit_cond_expr(&mut self, node: &CondExpr) -> Result {
1907 self.emit_leading_comments_of_span(node.span(), false)?;
1908
1909 srcmap!(node, true);
1910
1911 emit!(node.test);
1912 formatting_space!();
1913 punct!("?");
1914 formatting_space!();
1915 emit!(node.cons);
1916 formatting_space!();
1917 punct!(":");
1918 formatting_space!();
1919 emit!(node.alt);
1920 }
1921
1922 #[emitter]
1923 fn emit_fn_expr(&mut self, n: &FnExpr) -> Result {
1924 self.emit_leading_comments_of_span(n.span(), false)?;
1925
1926 self.wr.commit_pending_semi()?;
1927
1928 srcmap!(n, true);
1929
1930 if n.function.is_async {
1931 keyword!("async");
1932 space!();
1933 keyword!("function");
1934 } else {
1935 keyword!("function");
1936 }
1937
1938 if n.function.is_generator {
1939 punct!("*");
1940 }
1941 if let Some(ref i) = n.ident {
1942 space!();
1943 emit!(i);
1944 }
1945
1946 self.emit_fn_trailing(&n.function)?;
1947 }
1948
1949 #[emitter]
1951 fn emit_fn_trailing(&mut self, node: &Function) -> Result {
1952 if let Some(type_params) = &node.type_params {
1953 emit!(type_params);
1954 }
1955
1956 punct!("(");
1957 self.emit_list(node.span, Some(&node.params), ListFormat::CommaListElements)?;
1958 punct!(")");
1959
1960 if let Some(ty) = &node.return_type {
1961 punct!(":");
1962 formatting_space!();
1963 emit!(ty);
1964 }
1965
1966 if let Some(body) = &node.body {
1967 formatting_space!();
1968 self.emit_block_stmt_inner(body, true)?;
1969 } else {
1970 semi!();
1971 }
1972
1973 }
1975
1976 #[emitter]
1977 fn emit_block_stmt_or_expr(&mut self, node: &BlockStmtOrExpr) -> Result {
1978 match node {
1979 BlockStmtOrExpr::BlockStmt(block) => {
1980 self.emit_block_stmt_inner(block, true)?;
1981 }
1982 BlockStmtOrExpr::Expr(expr) => {
1983 self.wr.increase_indent()?;
1984 emit!(expr);
1985 self.wr.decrease_indent()?;
1986 }
1987 }
1988 }
1989
1990 #[emitter]
1991 fn emit_this_expr(&mut self, node: &ThisExpr) -> Result {
1992 self.emit_leading_comments_of_span(node.span(), false)?;
1993
1994 keyword!(node.span, "this");
1995 }
1996
1997 #[emitter]
1998 fn emit_tpl_lit(&mut self, node: &Tpl) -> Result {
1999 debug_assert!(node.quasis.len() == node.exprs.len() + 1);
2000
2001 self.emit_leading_comments_of_span(node.span(), false)?;
2002
2003 srcmap!(node, true);
2004
2005 punct!("`");
2006
2007 for i in 0..(node.quasis.len() + node.exprs.len()) {
2008 if i % 2 == 0 {
2009 emit!(node.quasis[i / 2]);
2010 } else {
2011 punct!("${");
2012 emit!(node.exprs[i / 2]);
2013 punct!("}");
2014 }
2015 }
2016
2017 punct!("`");
2018
2019 srcmap!(node, false);
2020 }
2021
2022 #[emitter]
2023 fn emit_quasi(&mut self, node: &TplElement) -> Result {
2024 let raw = node.raw.replace("\r\n", "\n").replace('\r', "\n");
2025 if self.cfg.minify || (self.cfg.ascii_only && !node.raw.is_ascii()) {
2026 let v = get_template_element_from_raw(&raw, self.cfg.ascii_only);
2027 let span = node.span();
2028
2029 let mut last_offset_gen = 0;
2030 let mut last_offset_origin = 0;
2031 for ((offset_gen, _), mat) in v
2032 .match_indices('\n')
2033 .zip(NEW_LINE_TPL_REGEX.find_iter(&raw))
2034 {
2035 if offset_gen != 0 {
2038 self.wr
2039 .add_srcmap(span.lo + BytePos(last_offset_origin as u32))?;
2040 }
2041
2042 self.wr
2043 .write_str_lit(DUMMY_SP, &v[last_offset_gen..=offset_gen])?;
2044 last_offset_gen = offset_gen + 1;
2045 last_offset_origin = mat.end();
2046 }
2047 self.wr
2048 .add_srcmap(span.lo + BytePos(last_offset_origin as u32))?;
2049 self.wr.write_str_lit(DUMMY_SP, &v[last_offset_gen..])?;
2050 self.wr.add_srcmap(span.hi)?;
2051 } else {
2052 self.wr.write_str_lit(node.span(), &raw)?;
2053 }
2054 }
2055
2056 #[emitter]
2057 fn emit_tagged_tpl_lit(&mut self, node: &TaggedTpl) -> Result {
2058 self.emit_leading_comments_of_span(node.span(), false)?;
2059
2060 srcmap!(node, true);
2061
2062 if let Expr::New(new) = &*node.tag {
2063 self.emit_new(new, false)?;
2064 } else {
2065 emit!(node.tag);
2066 }
2067
2068 emit!(node.type_params);
2069 self.emit_template_for_tagged_template(&node.tpl)?;
2070
2071 srcmap!(node, false);
2072 }
2073
2074 fn emit_template_for_tagged_template(&mut self, node: &Tpl) -> Result {
2075 debug_assert!(node.quasis.len() == node.exprs.len() + 1);
2076
2077 self.emit_leading_comments_of_span(node.span(), false)?;
2078
2079 srcmap!(self, node, true);
2080
2081 punct!(self, "`");
2082
2083 for i in 0..(node.quasis.len() + node.exprs.len()) {
2084 if i % 2 == 0 {
2085 self.emit_template_element_for_tagged_template(&node.quasis[i / 2])?;
2086 } else {
2087 punct!(self, "${");
2088 emit!(self, node.exprs[i / 2]);
2089 punct!(self, "}");
2090 }
2091 }
2092
2093 punct!(self, "`");
2094
2095 srcmap!(self, node, false);
2096
2097 Ok(())
2098 }
2099
2100 fn emit_template_element_for_tagged_template(&mut self, node: &TplElement) -> Result {
2101 srcmap!(self, node, true);
2102
2103 self.wr.write_str_lit(DUMMY_SP, &node.raw)?;
2104
2105 srcmap!(self, node, false);
2106
2107 Ok(())
2108 }
2109
2110 #[emitter]
2111 fn emit_unary_expr(&mut self, n: &UnaryExpr) -> Result {
2112 self.emit_leading_comments_of_span(n.span(), false)?;
2113
2114 srcmap!(n, true);
2115
2116 let need_formatting_space = match n.op {
2117 op!("typeof") | op!("void") | op!("delete") => {
2118 keyword!(n.op.as_str());
2119
2120 true
2121 }
2122 op!(unary, "+") | op!(unary, "-") | op!("!") | op!("~") => {
2123 punct!(n.op.as_str());
2124 false
2125 }
2126 };
2127
2128 if should_emit_whitespace_before_operand(n) {
2129 space!();
2130 } else if need_formatting_space {
2131 formatting_space!();
2132 }
2133
2134 emit!(n.arg);
2135 }
2136
2137 #[emitter]
2138 fn emit_update_expr(&mut self, node: &UpdateExpr) -> Result {
2139 self.emit_leading_comments_of_span(node.span(), false)?;
2140
2141 srcmap!(node, true);
2142
2143 if node.prefix {
2144 operator!(node.op.as_str());
2145 emit!(node.arg);
2147 } else {
2148 emit!(node.arg);
2149 operator!(node.op.as_str());
2150 }
2151 }
2152
2153 #[emitter]
2154 fn emit_yield_expr(&mut self, node: &YieldExpr) -> Result {
2155 self.emit_leading_comments_of_span(node.span(), false)?;
2156
2157 srcmap!(node, true);
2158
2159 keyword!("yield");
2160 if node.delegate {
2161 operator!("*");
2162 }
2163
2164 if let Some(ref arg) = node.arg {
2165 let need_paren = node
2166 .arg
2167 .as_deref()
2168 .map(|expr| self.has_leading_comment(expr))
2169 .unwrap_or(false);
2170 if need_paren {
2171 punct!("(")
2172 } else if !node.delegate && arg.starts_with_alpha_num() {
2173 space!()
2174 } else {
2175 formatting_space!()
2176 }
2177
2178 emit!(node.arg);
2179 if need_paren {
2180 punct!(")")
2181 }
2182 }
2183 }
2184
2185 fn emit_expr_or_spreads(
2186 &mut self,
2187 parent_node: Span,
2188 nodes: &[ExprOrSpread],
2189 format: ListFormat,
2190 ) -> Result {
2191 self.emit_list(parent_node, Some(nodes), format)
2192 }
2193
2194 #[emitter]
2195 fn emit_expr_or_spread(&mut self, node: &ExprOrSpread) -> Result {
2196 if let Some(span) = node.spread {
2197 self.emit_leading_comments_of_span(span, false)?;
2198
2199 punct!("...");
2200 }
2201
2202 emit!(node.expr);
2203 }
2204
2205 #[emitter]
2206 fn emit_await_expr(&mut self, n: &AwaitExpr) -> Result {
2207 self.emit_leading_comments_of_span(n.span(), false)?;
2208
2209 srcmap!(n, true);
2210
2211 keyword!("await");
2212 space!();
2213
2214 emit!(&n.arg);
2215 }
2216
2217 #[emitter]
2218 fn emit_array_lit(&mut self, node: &ArrayLit) -> Result {
2219 self.emit_leading_comments_of_span(node.span(), false)?;
2220
2221 srcmap!(node, true);
2222
2223 punct!("[");
2224 let mut format = ListFormat::ArrayLiteralExpressionElements;
2225 if let Some(None) = node.elems.last() {
2226 format |= ListFormat::ForceTrailingComma;
2227 }
2228
2229 self.emit_list(node.span(), Some(&node.elems), format)?;
2230 punct!("]");
2231
2232 srcmap!(node, false);
2233 }
2234
2235 #[emitter]
2236 fn emit_object_lit(&mut self, node: &ObjectLit) -> Result {
2237 self.emit_leading_comments_of_span(node.span(), false)?;
2238
2239 srcmap!(node, true);
2240
2241 punct!("{");
2242
2243 let emit_new_line = !self.cfg.minify
2244 && !(node.props.is_empty() && is_empty_comments(&node.span(), &self.comments));
2245
2246 if emit_new_line {
2247 self.wr.write_line()?;
2248 }
2249
2250 let mut list_format =
2251 ListFormat::ObjectLiteralExpressionProperties | ListFormat::CanSkipTrailingComma;
2252
2253 if !emit_new_line {
2254 list_format -= ListFormat::MultiLine | ListFormat::Indented;
2255 }
2256
2257 self.emit_list(node.span(), Some(&node.props), list_format)?;
2258
2259 if emit_new_line {
2260 self.wr.write_line()?;
2261 }
2262
2263 srcmap!(node, false, true);
2264 punct!("}");
2265 }
2266
2267 #[emitter]
2268 fn emit_prop(&mut self, node: &Prop) -> Result {
2269 match *node {
2270 Prop::Shorthand(ref n) => emit!(n),
2271 Prop::KeyValue(ref n) => emit!(n),
2272 Prop::Assign(ref n) => emit!(n),
2273 Prop::Getter(ref n) => emit!(n),
2274 Prop::Setter(ref n) => emit!(n),
2275 Prop::Method(ref n) => emit!(n),
2276 }
2277 }
2278
2279 #[emitter]
2280 fn emit_kv_prop(&mut self, node: &KeyValueProp) -> Result {
2281 self.emit_leading_comments_of_span(node.span(), false)?;
2282 let key_span = node.key.span();
2283 let value_span = node.value.span();
2284 if !key_span.is_dummy() {
2285 self.wr.add_srcmap(key_span.lo)?;
2286 }
2287 emit!(node.key);
2288 if !key_span.is_dummy() && value_span.is_dummy() {
2289 self.wr.add_srcmap(key_span.hi)?;
2290 }
2291 punct!(":");
2292 formatting_space!();
2293 if key_span.is_dummy() && !value_span.is_dummy() {
2294 self.wr.add_srcmap(value_span.lo)?;
2295 }
2296 emit!(node.value);
2297 }
2298
2299 #[emitter]
2300 fn emit_assign_prop(&mut self, node: &AssignProp) -> Result {
2301 self.emit_leading_comments_of_span(node.span(), false)?;
2302
2303 srcmap!(node, true);
2304
2305 emit!(node.key);
2306 punct!("=");
2307 emit!(node.value);
2308 }
2309
2310 #[emitter]
2311 fn emit_getter_prop(&mut self, node: &GetterProp) -> Result {
2312 self.emit_leading_comments_of_span(node.span(), false)?;
2313
2314 srcmap!(node, true);
2315
2316 keyword!("get");
2317
2318 let starts_with_alpha_num = match node.key {
2319 PropName::Str(_) | PropName::Computed(_) => false,
2320 _ => true,
2321 };
2322 if starts_with_alpha_num {
2323 space!();
2324 } else {
2325 formatting_space!();
2326 }
2327 emit!(node.key);
2328 formatting_space!();
2329 punct!("(");
2330 punct!(")");
2331 formatting_space!();
2332 emit!(node.body);
2333 }
2334
2335 #[emitter]
2336 fn emit_setter_prop(&mut self, node: &SetterProp) -> Result {
2337 self.emit_leading_comments_of_span(node.span(), false)?;
2338
2339 srcmap!(node, true);
2340
2341 keyword!("set");
2342
2343 let starts_with_alpha_num = match node.key {
2344 PropName::Str(_) | PropName::Computed(_) => false,
2345 _ => true,
2346 };
2347
2348 if starts_with_alpha_num {
2349 space!();
2350 } else {
2351 formatting_space!();
2352 }
2353
2354 emit!(node.key);
2355 formatting_space!();
2356
2357 punct!("(");
2358 if let Some(this) = &node.this_param {
2359 emit!(this);
2360 punct!(",");
2361
2362 formatting_space!();
2363 }
2364
2365 emit!(node.param);
2366
2367 punct!(")");
2368
2369 emit!(node.body);
2370 }
2371
2372 #[emitter]
2373 fn emit_method_prop(&mut self, node: &MethodProp) -> Result {
2374 self.emit_leading_comments_of_span(node.span(), false)?;
2375
2376 srcmap!(node, true);
2377
2378 if node.function.is_async {
2379 keyword!("async");
2380 space!();
2381 }
2382
2383 if node.function.is_generator {
2384 punct!("*");
2385 }
2386
2387 emit!(node.key);
2388 formatting_space!();
2389 self.emit_fn_trailing(&node.function)?;
2391 }
2392
2393 #[emitter]
2394 fn emit_paren_expr(&mut self, node: &ParenExpr) -> Result {
2395 self.wr.commit_pending_semi()?;
2396
2397 self.emit_leading_comments_of_span(node.span(), false)?;
2398
2399 srcmap!(node, true);
2400
2401 punct!("(");
2402 emit!(node.expr);
2403
2404 srcmap!(node, false, true);
2405 punct!(")");
2406 }
2407
2408 #[emitter]
2409 fn emit_private_name(&mut self, n: &PrivateName) -> Result {
2410 self.emit_leading_comments_of_span(n.span(), false)?;
2411
2412 srcmap!(n, true);
2413
2414 punct!("#");
2415 self.emit_ident_like(n.span, &n.name, false)?;
2416
2417 srcmap!(n, false);
2418 }
2419
2420 #[emitter]
2421 fn emit_binding_ident(&mut self, ident: &BindingIdent) -> Result {
2422 self.emit_ident_like(ident.span, &ident.sym, ident.optional)?;
2423
2424 if let Some(ty) = &ident.type_ann {
2425 punct!(":");
2426 formatting_space!();
2427 emit!(ty);
2428 }
2429
2430 }
2435
2436 #[emitter]
2437 fn emit_ident(&mut self, ident: &Ident) -> Result {
2438 self.emit_ident_like(ident.span, &ident.sym, ident.optional)?;
2439 }
2440
2441 #[emitter]
2442 fn emit_ident_name(&mut self, ident: &IdentName) -> Result {
2443 self.emit_ident_like(ident.span, &ident.sym, false)?;
2444 }
2445
2446 fn emit_ident_like(&mut self, span: Span, sym: &Atom, optional: bool) -> Result {
2447 self.emit_leading_comments_of_span(span, false)?;
2449
2450 self.wr.commit_pending_semi()?;
2452
2453 srcmap!(self, span, true);
2454 if self.cfg.ascii_only {
2457 if self.wr.can_ignore_invalid_unicodes() {
2458 self.wr
2459 .write_symbol(DUMMY_SP, &get_ascii_only_ident(sym, false, self.cfg.target))?;
2460 } else {
2461 self.wr.write_symbol(
2462 DUMMY_SP,
2463 &get_ascii_only_ident(&handle_invalid_unicodes(sym), false, self.cfg.target),
2464 )?;
2465 }
2466 } else if self.wr.can_ignore_invalid_unicodes() {
2467 self.wr.write_symbol(DUMMY_SP, sym)?;
2468 } else {
2469 self.wr
2470 .write_symbol(DUMMY_SP, &handle_invalid_unicodes(sym))?;
2471 }
2472
2473 if optional {
2474 punct!(self, "?");
2475 }
2476
2477 Ok(())
2483 }
2484
2485 fn emit_list<N: Node>(
2486 &mut self,
2487 parent_node: Span,
2488 children: Option<&[N]>,
2489 format: ListFormat,
2490 ) -> Result {
2491 self.emit_list5(
2492 parent_node,
2493 children,
2494 format,
2495 0,
2496 children.map(|c| c.len()).unwrap_or(0),
2497 )
2498 }
2499
2500 #[inline(never)]
2502 fn emit_first_of_list5(
2503 &mut self,
2504 parent_node: Span,
2505 children: Option<usize>,
2506 format: ListFormat,
2507 start: usize,
2508 count: usize,
2509 ) -> Option<Result> {
2510 if children.is_none() && format.contains(ListFormat::OptionalIfUndefined) {
2511 return Some(Ok(()));
2512 }
2513
2514 let is_empty = children.is_none() || start > children.unwrap() || count == 0;
2515 if is_empty && format.contains(ListFormat::OptionalIfEmpty) {
2516 return Some(Ok(()));
2517 }
2518
2519 if format.contains(ListFormat::BracketsMask) {
2520 if let Err(err) = self.wr.write_punct(None, format.opening_bracket()) {
2521 return Some(Err(err));
2522 }
2523
2524 if is_empty {
2525 if let Err(err) = self.emit_trailing_comments_of_pos(
2526 {
2527 parent_node.lo()
2530 },
2531 true,
2532 false,
2533 ) {
2534 return Some(Err(err));
2535 }
2536 }
2537 }
2538
2539 None
2540 }
2541
2542 #[inline(never)]
2544 fn emit_pre_child_for_list5(
2545 &mut self,
2546 parent_node: Span,
2547 format: ListFormat,
2548 previous_sibling: Option<Span>,
2549 child: Span,
2550 should_decrease_indent_after_emit: &mut bool,
2551 should_emit_intervening_comments: &mut bool,
2552 ) -> Result {
2553 if let Some(previous_sibling) = previous_sibling {
2555 if format.contains(ListFormat::DelimitersMask)
2563 && previous_sibling.hi != parent_node.hi()
2564 && self.comments.is_some()
2565 {
2566 self.emit_leading_comments(previous_sibling.hi(), true)?;
2567 }
2568
2569 self.write_delim(format)?;
2570
2571 if self.cm.should_write_separating_line_terminator(
2574 Some(previous_sibling),
2575 Some(child),
2576 format,
2577 ) {
2578 if (format & (ListFormat::LinesMask | ListFormat::Indented))
2581 == ListFormat::SingleLine
2582 && !self.cfg.minify
2583 {
2584 self.wr.increase_indent()?;
2585 *should_decrease_indent_after_emit = true;
2586 }
2587
2588 if !self.cfg.minify {
2589 self.wr.write_line()?;
2590 }
2591 *should_emit_intervening_comments = false;
2592 } else if format.contains(ListFormat::SpaceBetweenSiblings) {
2593 formatting_space!(self);
2594 }
2595 }
2596
2597 Ok(())
2598 }
2599
2600 #[inline(never)]
2602 fn emit_list_finisher_of_list5(
2603 &mut self,
2604 parent_node: Span,
2605 format: ListFormat,
2606 previous_sibling: Option<Span>,
2607 last_child: Option<Span>,
2608 ) -> Result {
2609 let has_trailing_comma = format.contains(ListFormat::ForceTrailingComma)
2611 || format.contains(ListFormat::AllowTrailingComma) && {
2612 if parent_node.is_dummy() {
2613 false
2614 } else {
2615 match self.cm.span_to_snippet(parent_node) {
2616 Ok(snippet) => {
2617 if snippet.len() < 3 {
2618 false
2619 } else {
2620 let last_char = snippet.chars().last().unwrap();
2621 snippet[..snippet.len() - last_char.len_utf8()]
2622 .trim()
2623 .ends_with(',')
2624 }
2625 }
2626 _ => false,
2627 }
2628 }
2629 };
2630
2631 if has_trailing_comma
2632 && format.contains(ListFormat::CommaDelimited)
2633 && (!self.cfg.minify || !format.contains(ListFormat::CanSkipTrailingComma))
2634 {
2635 punct!(self, ",");
2636 formatting_space!(self);
2637 }
2638
2639 {
2640 let emit_trailing_comments = {
2648 true
2653 };
2654
2655 if let Some(previous_sibling) = previous_sibling {
2656 if format.contains(ListFormat::DelimitersMask)
2657 && previous_sibling.hi() != parent_node.hi()
2658 && emit_trailing_comments
2659 && self.comments.is_some()
2660 {
2661 self.emit_leading_comments(previous_sibling.hi(), true)?;
2662 }
2663 }
2664 }
2665
2666 if format.contains(ListFormat::Indented) && !self.cfg.minify {
2668 self.wr.decrease_indent()?;
2669 }
2670
2671 if self
2673 .cm
2674 .should_write_closing_line_terminator(parent_node, last_child, format)
2675 {
2676 if !self.cfg.minify {
2677 self.wr.write_line()?;
2678 }
2679 } else if format.contains(ListFormat::SpaceBetweenBraces) && !self.cfg.minify {
2680 self.wr.write_space()?;
2681 }
2682
2683 Ok(())
2684 }
2685
2686 #[inline(never)]
2688 fn emit_last_of_list5(
2689 &mut self,
2690 parent_node: Span,
2691 is_empty: bool,
2692 format: ListFormat,
2693 _start: usize,
2694 _count: usize,
2695 ) -> Result {
2696 if format.contains(ListFormat::BracketsMask) {
2697 if is_empty {
2698 self.emit_leading_comments(
2699 {
2700 parent_node.hi()
2703 },
2704 true,
2705 )?; }
2707 self.wr.write_punct(None, format.closing_bracket())?;
2708 }
2709
2710 Ok(())
2711 }
2712
2713 fn emit_list5<N: Node>(
2714 &mut self,
2715 parent_node: Span,
2716 children: Option<&[N]>,
2717 format: ListFormat,
2718 start: usize,
2719 count: usize,
2720 ) -> Result {
2721 if let Some(result) =
2722 self.emit_first_of_list5(parent_node, children.map(|v| v.len()), format, start, count)
2723 {
2724 return result;
2725 }
2726
2727 let is_empty = children.is_none() || start > children.unwrap().len() || count == 0;
2728
2729 if is_empty {
2730 if format.contains(ListFormat::MultiLine) {
2733 if !self.cfg.minify {
2734 self.wr.write_line()?;
2735 }
2736 } else if format.contains(ListFormat::SpaceBetweenBraces)
2737 && !(format.contains(ListFormat::NoSpaceIfEmpty))
2738 && !self.cfg.minify
2739 {
2740 self.wr.write_space()?;
2741 }
2742 } else {
2743 let children = children.unwrap();
2744
2745 let may_emit_intervening_comments =
2747 !format.intersects(ListFormat::NoInterveningComments);
2748 let mut should_emit_intervening_comments = may_emit_intervening_comments;
2749 if self.cm.should_write_leading_line_terminator(
2750 parent_node,
2751 children.first().map(|v| v.span()),
2752 format,
2753 ) {
2754 if !self.cfg.minify {
2755 self.wr.write_line()?;
2756 }
2757 should_emit_intervening_comments = false;
2758 } else if format.contains(ListFormat::SpaceBetweenBraces) && !self.cfg.minify {
2759 self.wr.write_space()?;
2760 }
2761
2762 if format.contains(ListFormat::Indented) && !self.cfg.minify {
2764 self.wr.increase_indent()?;
2765 }
2766
2767 let mut previous_sibling: Option<Span> = None;
2769 let mut should_decrease_indent_after_emit = false;
2770 for i in 0..count {
2771 let child = &children[start + i];
2772
2773 self.emit_pre_child_for_list5(
2774 parent_node,
2775 format,
2776 previous_sibling,
2777 child.span(),
2778 &mut should_decrease_indent_after_emit,
2779 &mut should_emit_intervening_comments,
2780 )?;
2781
2782 child.emit_with(self)?;
2783
2784 if should_emit_intervening_comments {
2786 if self.comments.is_some() {
2787 let comment_range = child.comment_range();
2788 self.emit_trailing_comments_of_pos(comment_range.hi(), false, true)?;
2789 }
2790 } else {
2791 should_emit_intervening_comments = may_emit_intervening_comments;
2792 }
2793
2794 if should_decrease_indent_after_emit {
2795 self.wr.decrease_indent()?;
2796 should_decrease_indent_after_emit = false;
2797 }
2798
2799 previous_sibling = Some(child.span());
2800 }
2801
2802 self.emit_list_finisher_of_list5(
2803 parent_node,
2804 format,
2805 previous_sibling,
2806 children.last().map(|v| v.span()),
2807 )?;
2808 }
2809
2810 self.emit_last_of_list5(parent_node, is_empty, format, start, count)?;
2813 Ok(())
2814 }
2815}
2816
2817impl<W, S: SourceMapper> Emitter<'_, W, S>
2819where
2820 W: WriteJs,
2821 S: SourceMapperExt,
2822{
2823 #[emitter]
2824 fn emit_param(&mut self, node: &Param) -> Result {
2825 self.emit_leading_comments_of_span(node.span(), false)?;
2826
2827 srcmap!(node, true);
2828
2829 self.emit_list(node.span, Some(&node.decorators), ListFormat::Decorators)?;
2830
2831 emit!(node.pat);
2832
2833 srcmap!(node, false);
2834 }
2835
2836 #[emitter]
2837 fn emit_pat(&mut self, node: &Pat) -> Result {
2838 match node {
2839 Pat::Array(ref n) => emit!(n),
2840 Pat::Assign(ref n) => emit!(n),
2841 Pat::Expr(ref n) => emit!(n),
2842 Pat::Ident(ref n) => emit!(n),
2843 Pat::Object(ref n) => emit!(n),
2844 Pat::Rest(ref n) => emit!(n),
2845 Pat::Invalid(n) => emit!(n),
2846 }
2847
2848 if self.comments.is_some() {
2849 self.emit_trailing_comments_of_pos(node.span().hi, true, true)?;
2850 }
2851 }
2852
2853 #[emitter]
2854 fn emit_rest_pat(&mut self, node: &RestPat) -> Result {
2855 self.emit_leading_comments_of_span(node.span(), false)?;
2856
2857 punct!(node.dot3_token, "...");
2858 emit!(node.arg);
2859
2860 if let Some(type_ann) = &node.type_ann {
2861 punct!(":");
2862 formatting_space!();
2863 emit!(type_ann);
2864 }
2865 }
2866
2867 #[emitter]
2868 fn emit_prop_or_spread(&mut self, node: &PropOrSpread) -> Result {
2869 match *node {
2870 PropOrSpread::Prop(ref n) => emit!(n),
2871 PropOrSpread::Spread(ref n) => emit!(n),
2872 }
2873 }
2874
2875 #[emitter]
2876 fn emit_spread_element(&mut self, node: &SpreadElement) -> Result {
2877 if self.comments.is_some() {
2878 self.emit_leading_comments_of_span(node.span(), false)?;
2879 }
2880
2881 srcmap!(node, true);
2882
2883 punct!("...");
2884 emit!(node.expr);
2885
2886 srcmap!(node, false);
2887 }
2888
2889 #[emitter]
2890 fn emit_assign_target(&mut self, node: &AssignTarget) -> Result {
2891 match *node {
2892 AssignTarget::Simple(ref n) => emit!(n),
2893 AssignTarget::Pat(ref n) => emit!(n),
2894 }
2895 }
2896
2897 #[emitter]
2898 fn emit_simple_assign_target(&mut self, node: &SimpleAssignTarget) -> Result {
2899 match node {
2900 SimpleAssignTarget::Ident(n) => emit!(n),
2901 SimpleAssignTarget::Member(n) => emit!(n),
2902 SimpleAssignTarget::Invalid(n) => emit!(n),
2903 SimpleAssignTarget::SuperProp(n) => emit!(n),
2904 SimpleAssignTarget::Paren(n) => emit!(n),
2905 SimpleAssignTarget::OptChain(n) => emit!(n),
2906 SimpleAssignTarget::TsAs(n) => emit!(n),
2907 SimpleAssignTarget::TsNonNull(n) => emit!(n),
2908 SimpleAssignTarget::TsSatisfies(n) => emit!(n),
2909 SimpleAssignTarget::TsTypeAssertion(n) => emit!(n),
2910 SimpleAssignTarget::TsInstantiation(n) => emit!(n),
2911 }
2912 }
2913
2914 #[emitter]
2915 fn emit_assign_target_pat(&mut self, node: &AssignTargetPat) -> Result {
2916 match node {
2917 AssignTargetPat::Array(n) => emit!(n),
2918 AssignTargetPat::Object(n) => emit!(n),
2919 AssignTargetPat::Invalid(n) => emit!(n),
2920 }
2921 }
2922
2923 #[emitter]
2924 fn emit_array_pat(&mut self, node: &ArrayPat) -> Result {
2925 self.emit_leading_comments_of_span(node.span(), false)?;
2926
2927 srcmap!(node, true);
2928
2929 punct!("[");
2930
2931 let mut format = ListFormat::ArrayBindingPatternElements;
2932
2933 if let Some(None) = node.elems.last() {
2934 format |= ListFormat::ForceTrailingComma;
2935 }
2936
2937 self.emit_list(node.span(), Some(&node.elems), format)?;
2938 punct!("]");
2939 if node.optional {
2940 punct!("?");
2941 }
2942
2943 if let Some(type_ann) = &node.type_ann {
2944 punct!(":");
2945 space!();
2946 emit!(type_ann);
2947 }
2948
2949 srcmap!(node, false);
2950 }
2951
2952 #[emitter]
2953 fn emit_assign_pat(&mut self, node: &AssignPat) -> Result {
2954 self.emit_leading_comments_of_span(node.span(), false)?;
2955
2956 srcmap!(node, true);
2957
2958 emit!(node.left);
2959 formatting_space!();
2960 punct!("=");
2961 formatting_space!();
2962 emit!(node.right);
2963
2964 srcmap!(node, false);
2965 }
2966
2967 #[emitter]
2968 fn emit_object_pat(&mut self, node: &ObjectPat) -> Result {
2969 self.emit_leading_comments_of_span(node.span(), false)?;
2970
2971 srcmap!(node, true);
2972 punct!("{");
2973
2974 self.emit_list(
2975 node.span(),
2976 Some(&node.props),
2977 ListFormat::ObjectBindingPatternElements | ListFormat::CanSkipTrailingComma,
2978 )?;
2979
2980 punct!("}");
2981
2982 if node.optional {
2983 punct!("?");
2984 }
2985
2986 if let Some(type_ann) = &node.type_ann {
2987 punct!(":");
2988 space!();
2989 emit!(type_ann);
2990 }
2991
2992 srcmap!(node, false);
2993 }
2994
2995 #[emitter]
2996 fn emit_object_pat_prop(&mut self, node: &ObjectPatProp) -> Result {
2997 match *node {
2998 ObjectPatProp::KeyValue(ref node) => emit!(node),
2999 ObjectPatProp::Assign(ref node) => emit!(node),
3000 ObjectPatProp::Rest(ref node) => emit!(node),
3001 }
3002 }
3003
3004 #[emitter]
3005 fn emit_object_kv_pat(&mut self, node: &KeyValuePatProp) -> Result {
3006 self.emit_leading_comments_of_span(node.span(), false)?;
3007
3008 srcmap!(node, true);
3009
3010 emit!(node.key);
3011 punct!(":");
3012 formatting_space!();
3013 emit!(node.value);
3014
3015 srcmap!(node, false);
3016 }
3017
3018 #[emitter]
3019 fn emit_object_assign_pat(&mut self, node: &AssignPatProp) -> Result {
3020 self.emit_leading_comments_of_span(node.span(), false)?;
3021
3022 srcmap!(node, true);
3023
3024 emit!(node.key);
3025 if let Some(value) = &node.value {
3026 formatting_space!();
3027 punct!("=");
3028 formatting_space!();
3029 emit!(value);
3030 }
3031
3032 srcmap!(node, false);
3033 }
3034
3035 #[emitter]
3036 fn emit_for_head(&mut self, node: &ForHead) -> Result {
3037 match node {
3038 ForHead::Pat(n) => emit!(n),
3039 ForHead::VarDecl(n) => emit!(n),
3040 ForHead::UsingDecl(n) => emit!(n),
3041 }
3042 }
3043}
3044
3045impl<W, S: SourceMapper> Emitter<'_, W, S>
3047where
3048 W: WriteJs,
3049 S: SourceMapperExt,
3050{
3051 #[emitter]
3052 fn emit_stmt(&mut self, node: &Stmt) -> Result {
3053 match node {
3054 Stmt::Expr(ref e) => emit!(e),
3055 Stmt::Block(ref e) => {
3056 emit!(e);
3057 return Ok(());
3058 }
3059 Stmt::Empty(ref e) => emit!(e),
3060 Stmt::Debugger(ref e) => emit!(e),
3061 Stmt::With(ref e) => emit!(e),
3062 Stmt::Return(ref e) => emit!(e),
3063 Stmt::Labeled(ref e) => emit!(e),
3064 Stmt::Break(ref e) => emit!(e),
3065 Stmt::Continue(ref e) => emit!(e),
3066 Stmt::If(ref e) => emit!(e),
3067 Stmt::Switch(ref e) => emit!(e),
3068 Stmt::Throw(ref e) => emit!(e),
3069 Stmt::Try(ref e) => emit!(e),
3070 Stmt::While(ref e) => emit!(e),
3071 Stmt::DoWhile(ref e) => emit!(e),
3072 Stmt::For(ref e) => emit!(e),
3073 Stmt::ForIn(ref e) => emit!(e),
3074 Stmt::ForOf(ref e) => emit!(e),
3075 Stmt::Decl(Decl::Var(e)) => {
3076 emit!(e);
3077 semi!();
3078 }
3079 Stmt::Decl(e @ Decl::Using(..)) => {
3080 emit!(e);
3081 semi!();
3082 }
3083 Stmt::Decl(ref e) => emit!(e),
3084 }
3085 if self.comments.is_some() {
3086 self.emit_trailing_comments_of_pos(node.span().hi(), true, true)?;
3087 }
3088
3089 if !self.cfg.minify {
3090 self.wr.write_line()?;
3091 }
3092 }
3093
3094 #[emitter]
3095
3096 fn emit_expr_stmt(&mut self, e: &ExprStmt) -> Result {
3097 self.emit_leading_comments_of_span(e.span, false)?;
3098
3099 emit!(e.expr);
3100
3101 semi!();
3102 }
3103
3104 #[emitter]
3105
3106 fn emit_block_stmt(&mut self, node: &BlockStmt) -> Result {
3107 self.emit_block_stmt_inner(node, false)?;
3108 }
3109
3110 fn emit_block_stmt_inner(&mut self, node: &BlockStmt, skip_first_src_map: bool) -> Result {
3111 self.emit_leading_comments_of_span(node.span(), false)?;
3112
3113 if !skip_first_src_map {
3114 srcmap!(self, node, true);
3115 }
3116 punct!(self, "{");
3117
3118 let emit_new_line = !self.cfg.minify
3119 && !(node.stmts.is_empty() && is_empty_comments(&node.span(), &self.comments));
3120
3121 let mut list_format = ListFormat::MultiLineBlockStatements;
3122
3123 if !emit_new_line {
3124 list_format -= ListFormat::MultiLine | ListFormat::Indented;
3125 }
3126
3127 self.emit_list(node.span(), Some(&node.stmts), list_format)?;
3128
3129 self.emit_leading_comments_of_span(node.span(), true)?;
3130
3131 srcmap!(self, node, false, true);
3132 punct!(self, "}");
3133
3134 Ok(())
3135 }
3136
3137 #[emitter]
3138 fn emit_empty_stmt(&mut self, node: &EmptyStmt) -> Result {
3139 self.emit_leading_comments_of_span(node.span(), false)?;
3140
3141 self.wr.write_punct(None, ";")?;
3142 }
3143
3144 #[emitter]
3145 fn emit_debugger_stmt(&mut self, node: &DebuggerStmt) -> Result {
3146 self.wr.commit_pending_semi()?;
3147
3148 self.emit_leading_comments_of_span(node.span(), false)?;
3149
3150 keyword!(node.span, "debugger");
3151 semi!();
3152 }
3153
3154 #[emitter]
3155 fn emit_with_stmt(&mut self, node: &WithStmt) -> Result {
3156 self.wr.commit_pending_semi()?;
3157
3158 srcmap!(node, true);
3159
3160 keyword!("with");
3161 formatting_space!();
3162
3163 punct!("(");
3164 emit!(node.obj);
3165 punct!(")");
3166
3167 emit!(node.body);
3168 }
3169
3170 fn has_trailing_comment(&self, span: Span) -> bool {
3171 if let Some(cmt) = self.comments {
3172 let hi = span.hi;
3173
3174 if cmt.has_trailing(hi) {
3175 return true;
3176 }
3177 }
3178
3179 false
3180 }
3181
3182 fn simple_assign_target_has_leading_comment(&self, arg: &SimpleAssignTarget) -> bool {
3183 match arg {
3184 SimpleAssignTarget::Ident(i) => {
3185 span_has_leading_comment(self.comments.as_ref().unwrap(), i.span)
3186 }
3187 SimpleAssignTarget::Member(m) => {
3188 if self.has_leading_comment(&m.obj) {
3189 return true;
3190 }
3191
3192 false
3193 }
3194
3195 SimpleAssignTarget::SuperProp(m) => {
3196 if span_has_leading_comment(self.comments.as_ref().unwrap(), m.span) {
3197 return true;
3198 }
3199
3200 false
3201 }
3202
3203 _ => false,
3204 }
3205 }
3206
3207 fn has_leading_comment(&self, arg: &Expr) -> bool {
3208 let cmt = if let Some(cmt) = self.comments {
3209 if span_has_leading_comment(cmt, arg.span()) {
3210 return true;
3211 }
3212
3213 cmt
3214 } else {
3215 return false;
3216 };
3217
3218 match arg {
3219 Expr::Call(c) => {
3220 let has_leading = match &c.callee {
3221 Callee::Super(callee) => span_has_leading_comment(cmt, callee.span),
3222 Callee::Import(callee) => span_has_leading_comment(cmt, callee.span),
3223 Callee::Expr(callee) => self.has_leading_comment(callee),
3224 };
3225
3226 if has_leading {
3227 return true;
3228 }
3229 }
3230
3231 Expr::Member(m) => {
3232 if self.has_leading_comment(&m.obj) {
3233 return true;
3234 }
3235 }
3236
3237 Expr::SuperProp(m) => {
3238 if span_has_leading_comment(cmt, m.span) {
3239 return true;
3240 }
3241 }
3242
3243 Expr::Bin(e) => {
3244 if self.has_leading_comment(&e.left) {
3245 return true;
3246 }
3247 }
3248
3249 Expr::Cond(e) => {
3250 if self.has_leading_comment(&e.test) {
3251 return true;
3252 }
3253 }
3254
3255 Expr::Seq(e) => {
3256 if let Some(e) = e.exprs.first() {
3257 if self.has_leading_comment(e) {
3258 return true;
3259 }
3260 }
3261 }
3262
3263 Expr::Assign(e) => {
3264 let lo = e.span.lo;
3265
3266 if cmt.has_leading(lo) {
3267 return true;
3268 }
3269
3270 let has_leading = match &e.left {
3271 AssignTarget::Simple(e) => self.simple_assign_target_has_leading_comment(e),
3272
3273 AssignTarget::Pat(p) => match p {
3274 AssignTargetPat::Array(a) => span_has_leading_comment(cmt, a.span),
3275 AssignTargetPat::Object(o) => span_has_leading_comment(cmt, o.span),
3276 AssignTargetPat::Invalid(..) => false,
3277 },
3278 };
3279
3280 if has_leading {
3281 return true;
3282 }
3283 }
3284
3285 Expr::OptChain(e) => match &*e.base {
3286 OptChainBase::Member(m) => {
3287 if self.has_leading_comment(&m.obj) {
3288 return true;
3289 }
3290 }
3291 OptChainBase::Call(c) => {
3292 if self.has_leading_comment(&c.callee) {
3293 return true;
3294 }
3295 }
3296 },
3297
3298 _ => {}
3299 }
3300
3301 false
3302 }
3303
3304 #[emitter]
3305 fn emit_return_stmt(&mut self, n: &ReturnStmt) -> Result {
3306 self.wr.commit_pending_semi()?;
3307
3308 self.emit_leading_comments_of_span(n.span, false)?;
3309
3310 srcmap!(n, true);
3311
3312 keyword!("return");
3313
3314 if let Some(arg) = n.arg.as_deref() {
3315 let need_paren = n
3316 .arg
3317 .as_deref()
3318 .map(|expr| self.has_leading_comment(expr))
3319 .unwrap_or(false);
3320 if need_paren {
3321 punct!("(");
3322 } else if arg.starts_with_alpha_num() {
3323 space!();
3324 } else {
3325 formatting_space!();
3326 }
3327
3328 emit!(arg);
3329 if need_paren {
3330 punct!(")");
3331 }
3332 }
3333
3334 semi!();
3335 }
3336
3337 #[emitter]
3338 fn emit_labeled_stmt(&mut self, node: &LabeledStmt) -> Result {
3339 self.wr.commit_pending_semi()?;
3340
3341 emit!(node.label);
3342
3343 punct!(":");
3345 formatting_space!();
3346
3347 emit!(node.body);
3348 }
3349
3350 #[emitter]
3351 fn emit_break_stmt(&mut self, n: &BreakStmt) -> Result {
3352 self.wr.commit_pending_semi()?;
3353
3354 srcmap!(n, true);
3355
3356 keyword!("break");
3357
3358 if let Some(ref label) = n.label {
3359 space!();
3360 emit!(label);
3361 }
3362
3363 semi!();
3364 }
3365
3366 #[emitter]
3367 fn emit_continue_stmt(&mut self, n: &ContinueStmt) -> Result {
3368 self.wr.commit_pending_semi()?;
3369
3370 srcmap!(n, true);
3371
3372 keyword!("continue");
3373
3374 if let Some(ref label) = n.label {
3375 space!();
3376 emit!(label);
3377 }
3378
3379 semi!();
3380 }
3381
3382 #[emitter]
3383 fn emit_if_stmt(&mut self, n: &IfStmt) -> Result {
3384 self.emit_leading_comments_of_span(n.span(), false)?;
3385
3386 self.wr.commit_pending_semi()?;
3387
3388 srcmap!(n, true);
3389
3390 keyword!("if");
3391
3392 formatting_space!();
3393 punct!("(");
3394 emit!(n.test);
3395 punct!(")");
3396 formatting_space!();
3397
3398 let is_cons_block = match *n.cons {
3399 Stmt::Block(..) => true,
3400 _ => false,
3401 };
3402
3403 emit!(n.cons);
3404
3405 if let Some(ref alt) = n.alt {
3406 if is_cons_block {
3407 formatting_space!();
3408 }
3409 keyword!("else");
3410 if alt.starts_with_alpha_num() {
3411 space!();
3412 } else {
3413 formatting_space!();
3414 }
3415 emit!(alt);
3416 }
3417 }
3418
3419 #[emitter]
3420 fn emit_switch_stmt(&mut self, n: &SwitchStmt) -> Result {
3421 self.wr.commit_pending_semi()?;
3422
3423 self.emit_leading_comments_of_span(n.span(), false)?;
3424
3425 srcmap!(n, true);
3426
3427 keyword!("switch");
3428
3429 punct!("(");
3430 emit!(n.discriminant);
3431 punct!(")");
3432
3433 punct!("{");
3434 self.emit_list(n.span(), Some(&n.cases), ListFormat::CaseBlockClauses)?;
3435
3436 srcmap!(n, false, true);
3437 punct!("}");
3438 }
3439
3440 #[emitter]
3441 fn emit_catch_clause(&mut self, n: &CatchClause) -> Result {
3442 self.emit_leading_comments_of_span(n.span(), false)?;
3443
3444 srcmap!(n, true);
3445
3446 keyword!("catch");
3447
3448 formatting_space!();
3449
3450 if let Some(param) = &n.param {
3451 punct!("(");
3452 emit!(param);
3453 punct!(")");
3454 }
3455
3456 formatting_space!();
3457
3458 emit!(n.body);
3459 }
3460
3461 #[emitter]
3462 fn emit_switch_case(&mut self, n: &SwitchCase) -> Result {
3463 self.emit_leading_comments_of_span(n.span(), false)?;
3464
3465 srcmap!(n, true);
3466
3467 if let Some(ref test) = n.test {
3468 keyword!("case");
3469
3470 let starts_with_alpha_num = test.starts_with_alpha_num();
3471
3472 if starts_with_alpha_num {
3473 space!();
3474 } else {
3475 formatting_space!();
3476 }
3477
3478 emit!(test);
3479 } else {
3480 keyword!("default");
3481 }
3482
3483 let emit_as_single_stmt = n.cons.len() == 1 && {
3484 n.is_synthesized()
3486 || n.cons[0].is_synthesized()
3487 || self
3488 .cm
3489 .is_on_same_line(n.span().lo(), n.cons[0].span().lo())
3490 };
3491
3492 let mut format = ListFormat::CaseOrDefaultClauseStatements;
3493 if emit_as_single_stmt {
3494 punct!(":");
3495 space!();
3496 format &= !(ListFormat::MultiLine | ListFormat::Indented);
3497 } else {
3498 punct!(":");
3499 }
3500 self.emit_list(n.span(), Some(&n.cons), format)?;
3501 }
3502
3503 #[emitter]
3504 fn emit_throw_stmt(&mut self, n: &ThrowStmt) -> Result {
3505 self.emit_leading_comments_of_span(n.span(), false)?;
3506
3507 srcmap!(n, true);
3508
3509 keyword!("throw");
3510
3511 {
3512 let need_paren = self.has_leading_comment(&n.arg);
3513 if need_paren {
3514 punct!("(");
3515 } else if n.arg.starts_with_alpha_num() {
3516 space!();
3517 } else {
3518 formatting_space!();
3519 }
3520
3521 emit!(n.arg);
3522 if need_paren {
3523 punct!(")");
3524 }
3525 }
3526 semi!();
3527 }
3528
3529 #[emitter]
3530
3531 fn emit_try_stmt(&mut self, n: &TryStmt) -> Result {
3532 self.emit_leading_comments_of_span(n.span(), false)?;
3533
3534 self.wr.commit_pending_semi()?;
3535
3536 srcmap!(n, true);
3537
3538 keyword!("try");
3539
3540 formatting_space!();
3541 emit!(n.block);
3542
3543 if let Some(ref catch) = n.handler {
3544 formatting_space!();
3545 emit!(catch);
3546 }
3547
3548 if let Some(ref finally) = n.finalizer {
3549 formatting_space!();
3550 keyword!("finally");
3551 emit!(finally);
3553 }
3554 }
3555
3556 #[emitter]
3557 fn emit_while_stmt(&mut self, node: &WhileStmt) -> Result {
3558 self.wr.commit_pending_semi()?;
3559
3560 self.emit_leading_comments_of_span(node.span(), false)?;
3561
3562 srcmap!(node, true);
3563
3564 keyword!("while");
3565
3566 punct!("(");
3567 emit!(node.test);
3568 punct!(")");
3569
3570 emit!(node.body);
3571 }
3572
3573 #[emitter]
3574 fn emit_do_while_stmt(&mut self, node: &DoWhileStmt) -> Result {
3575 self.wr.commit_pending_semi()?;
3576
3577 self.emit_leading_comments_of_span(node.span(), false)?;
3578
3579 srcmap!(node, true);
3580
3581 keyword!("do");
3582 if node.body.starts_with_alpha_num() {
3583 space!();
3584 } else {
3585 formatting_space!()
3586 }
3587 emit!(node.body);
3588
3589 keyword!("while");
3590
3591 formatting_space!();
3592
3593 punct!("(");
3594 emit!(node.test);
3595 punct!(")");
3596
3597 if self.cfg.target <= EsVersion::Es5 {
3598 semi!();
3599 }
3600
3601 srcmap!(node, false);
3602 }
3603
3604 #[emitter]
3605 fn emit_for_stmt(&mut self, n: &ForStmt) -> Result {
3606 self.wr.commit_pending_semi()?;
3607
3608 self.emit_leading_comments_of_span(n.span(), false)?;
3609
3610 srcmap!(n, true);
3611
3612 keyword!("for");
3613
3614 punct!("(");
3615 opt!(n.init);
3616 self.wr.write_punct(None, ";")?;
3617 opt_leading_space!(n.test);
3618 self.wr.write_punct(None, ";")?;
3619 opt_leading_space!(n.update);
3620 punct!(")");
3621
3622 emit!(n.body);
3623 }
3624
3625 #[emitter]
3626 fn emit_for_in_stmt(&mut self, n: &ForInStmt) -> Result {
3627 self.wr.commit_pending_semi()?;
3628
3629 self.emit_leading_comments_of_span(n.span(), false)?;
3630
3631 srcmap!(n, true);
3632
3633 keyword!("for");
3634
3635 punct!("(");
3636 emit!(n.left);
3637
3638 if n.left.ends_with_alpha_num() {
3639 space!();
3640 } else {
3641 formatting_space!();
3642 }
3643 keyword!("in");
3644
3645 {
3646 let starts_with_alpha_num = n.right.starts_with_alpha_num();
3647
3648 if starts_with_alpha_num {
3649 space!();
3650 } else {
3651 formatting_space!()
3652 }
3653 emit!(n.right);
3654 }
3655
3656 punct!(")");
3657
3658 emit!(n.body);
3659 }
3660
3661 #[emitter]
3662 fn emit_for_of_stmt(&mut self, n: &ForOfStmt) -> Result {
3663 self.wr.commit_pending_semi()?;
3664
3665 self.emit_leading_comments_of_span(n.span(), false)?;
3666
3667 srcmap!(n, true);
3668
3669 keyword!("for");
3670
3671 if n.is_await {
3672 space!();
3673 keyword!("await");
3674 }
3675 formatting_space!();
3676 punct!("(");
3677 emit!(n.left);
3678 if n.left.ends_with_alpha_num() {
3679 space!();
3680 } else {
3681 formatting_space!();
3682 }
3683 keyword!("of");
3684
3685 {
3686 let starts_with_alpha_num = n.right.starts_with_alpha_num();
3687
3688 if starts_with_alpha_num {
3689 space!();
3690 } else {
3691 formatting_space!()
3692 }
3693 emit!(n.right);
3694 }
3695 punct!(")");
3696 emit!(n.body);
3697 }
3698
3699 #[emitter]
3700 pub fn emit_module_export_name(&mut self, node: &ModuleExportName) -> Result {
3701 match *node {
3702 ModuleExportName::Ident(ref ident) => emit!(ident),
3703 ModuleExportName::Str(ref s) => emit!(s),
3704 }
3705 }
3706}
3707
3708impl<W, S: SourceMapper> Emitter<'_, W, S>
3709where
3710 W: WriteJs,
3711 S: SourceMapperExt,
3712{
3713 fn write_delim(&mut self, f: ListFormat) -> Result {
3714 match f & ListFormat::DelimitersMask {
3715 ListFormat::None => {}
3716 ListFormat::CommaDelimited => self.wr.write_punct(None, ",")?,
3717 ListFormat::BarDelimited => {
3718 if !self.cfg.minify {
3719 self.wr.write_space()?;
3720 }
3721 self.wr.write_punct(None, "|")?;
3722 }
3723 ListFormat::AmpersandDelimited => {
3724 if !self.cfg.minify {
3725 self.wr.write_space()?;
3726 }
3727 self.wr.write_punct(None, "&")?;
3728 }
3729 _ => unreachable!(),
3730 }
3731
3732 Ok(())
3733 }
3734
3735 #[emitter]
3736 fn emit_var_decl_or_expr(&mut self, node: &VarDeclOrExpr) -> Result {
3737 match *node {
3738 VarDeclOrExpr::Expr(ref node) => emit!(node),
3739 VarDeclOrExpr::VarDecl(ref node) => emit!(node),
3740 }
3741 }
3742}
3743
3744fn should_emit_whitespace_before_operand(node: &UnaryExpr) -> bool {
3759 match *node {
3760 UnaryExpr {
3761 op: op!("void"), ..
3762 }
3763 | UnaryExpr {
3764 op: op!("typeof"), ..
3765 }
3766 | UnaryExpr {
3767 op: op!("delete"), ..
3768 } => return node.arg.starts_with_alpha_num(),
3769 _ => {}
3770 }
3771
3772 match &*node.arg {
3773 Expr::Update(UpdateExpr {
3774 op: op!("++"),
3775 prefix: true,
3776 ..
3777 })
3778 | Expr::Unary(UnaryExpr {
3779 op: op!(unary, "+"),
3780 ..
3781 }) if node.op == op!(unary, "+") => true,
3782 Expr::Update(UpdateExpr {
3783 op: op!("--"),
3784 prefix: true,
3785 ..
3786 })
3787 | Expr::Unary(UnaryExpr {
3788 op: op!(unary, "-"),
3789 ..
3790 }) if node.op == op!(unary, "-") => true,
3791
3792 Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() && node.op == op!(unary, "-") => true,
3793
3794 _ => false,
3795 }
3796}
3797
3798impl<N> Node for Option<N>
3799where
3800 N: Node,
3801{
3802 fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
3803 where
3804 W: WriteJs,
3805 S: SourceMapper + SourceMapperExt,
3806 {
3807 match *self {
3808 Some(ref n) => n.emit_with(e),
3809 None => Ok(()),
3810 }
3811 }
3812}
3813
3814fn get_template_element_from_raw(s: &str, ascii_only: bool) -> String {
3815 fn read_escaped(
3816 radix: u32,
3817 len: Option<usize>,
3818 buf: &mut String,
3819 iter: impl Iterator<Item = char>,
3820 ) {
3821 let mut v = 0;
3822 let mut pending = None;
3823
3824 for (i, c) in iter.enumerate() {
3825 if let Some(len) = len {
3826 if i == len {
3827 pending = Some(c);
3828 break;
3829 }
3830 }
3831
3832 match c.to_digit(radix) {
3833 None => {
3834 pending = Some(c);
3835 break;
3836 }
3837 Some(d) => {
3838 v = v * radix + d;
3839 }
3840 }
3841 }
3842
3843 match radix {
3844 16 => {
3845 match v {
3846 0 => match pending {
3847 Some('1'..='9') => write!(buf, "\\x00").unwrap(),
3848 _ => write!(buf, "\\0").unwrap(),
3849 },
3850 1..=15 => write!(buf, "\\x0{:x}", v).unwrap(),
3851 32..=126 => {
3853 let c = char::from_u32(v);
3854
3855 match c {
3856 Some(c) => write!(buf, "{}", c).unwrap(),
3857 _ => {
3858 unreachable!()
3859 }
3860 }
3861 }
3862 _ => {
3865 write!(buf, "\\x{:x}", v).unwrap();
3866 }
3867 }
3868 }
3869
3870 _ => unreachable!(),
3871 }
3872
3873 if let Some(pending) = pending {
3874 buf.push(pending);
3875 }
3876 }
3877
3878 let mut buf = String::with_capacity(s.len());
3879 let mut iter = s.chars().peekable();
3880
3881 let mut is_dollar_prev = false;
3882
3883 while let Some(c) = iter.next() {
3884 let unescape = match c {
3885 '\\' => match iter.next() {
3886 Some(c) => match c {
3887 'n' => Some('\n'),
3888 't' => Some('\t'),
3889 'x' => {
3890 read_escaped(16, Some(2), &mut buf, &mut iter);
3891
3892 None
3893 }
3894 '\u{2028}' | '\u{2029}' => None,
3897 '\\' | 'r' | 'v' | 'b' | 'f' | 'u' | '\r' | '\n' | '`' | '0'..='7' => {
3900 buf.push('\\');
3901 buf.push(c);
3902
3903 None
3904 }
3905 '$' if iter.peek() == Some(&'{') => {
3906 buf.push('\\');
3907 buf.push('$');
3908
3909 None
3910 }
3911 '{' if is_dollar_prev => {
3912 buf.push('\\');
3913 buf.push('{');
3914
3915 is_dollar_prev = false;
3916
3917 None
3918 }
3919 _ => Some(c),
3920 },
3921 None => Some('\\'),
3922 },
3923 _ => Some(c),
3924 };
3925
3926 match unescape {
3927 Some(c @ '$') => {
3928 is_dollar_prev = true;
3929
3930 buf.push(c);
3931 }
3932 Some('\x00') => {
3933 let next = iter.peek();
3934
3935 match next {
3936 Some('1'..='9') => buf.push_str("\\x00"),
3937 _ => buf.push_str("\\0"),
3938 }
3939 }
3940 Some('\u{0008}') => buf.push_str("\\b"),
3943 Some('\u{000c}') => buf.push_str("\\f"),
3944 Some('\n') => buf.push('\n'),
3945 Some('\u{000b}') => buf.push_str("\\v"),
3947 Some('\t') => buf.push('\t'),
3948 Some(c @ '\x20'..='\x7e') => {
3950 buf.push(c);
3951 }
3952 Some(c @ '\u{7f}'..='\u{ff}') => {
3953 let _ = write!(buf, "\\x{:x}", c as u8);
3954 }
3955 Some('\u{2028}') => {
3956 buf.push_str("\\u2028");
3957 }
3958 Some('\u{2029}') => {
3959 buf.push_str("\\u2029");
3960 }
3961 Some('\u{FEFF}') => {
3962 buf.push_str("\\uFEFF");
3963 }
3964 Some(c) => {
3966 if !ascii_only || c.is_ascii() {
3967 buf.push(c);
3968 } else {
3969 buf.extend(c.escape_unicode().map(|c| {
3970 if c == 'u' {
3971 c
3972 } else {
3973 c.to_ascii_uppercase()
3974 }
3975 }));
3976 }
3977 }
3978 None => {}
3979 }
3980 }
3981
3982 buf
3983}
3984
3985fn get_ascii_only_ident(sym: &str, may_need_quote: bool, target: EsVersion) -> CowStr {
3986 if sym.is_ascii() {
3987 return CowStr::Borrowed(sym);
3988 }
3989
3990 let mut first = true;
3991 let mut buf = CompactString::with_capacity(sym.len() + 8);
3992 let mut iter = sym.chars().peekable();
3993 let mut need_quote = false;
3994
3995 while let Some(c) = iter.next() {
3996 match c {
3997 '\x00' => {
3998 if may_need_quote {
3999 need_quote = true;
4000 let _ = write!(buf, "\\x00");
4001 } else {
4002 let _ = write!(buf, "\\u0000");
4003 }
4004 }
4005 '\u{0008}' => buf.push_str("\\b"),
4006 '\u{000c}' => buf.push_str("\\f"),
4007 '\n' => buf.push_str("\\n"),
4008 '\r' => buf.push_str("\\r"),
4009 '\u{000b}' => buf.push_str("\\v"),
4010 '\t' => buf.push('\t'),
4011 '\\' => {
4012 let next = iter.peek();
4013
4014 match next {
4015 Some('u') => {
4017 let mut inner_iter = iter.clone();
4018
4019 inner_iter.next();
4020
4021 let mut is_curly = false;
4022 let mut next = inner_iter.peek();
4023
4024 if next == Some(&'{') {
4025 is_curly = true;
4026
4027 inner_iter.next();
4028 next = inner_iter.peek();
4029 }
4030
4031 if let Some(c @ 'D' | c @ 'd') = next {
4032 let mut inner_buf = String::new();
4033
4034 inner_buf.push('\\');
4035 inner_buf.push('u');
4036
4037 if is_curly {
4038 inner_buf.push('{');
4039 }
4040
4041 inner_buf.push(*c);
4042
4043 inner_iter.next();
4044
4045 let mut is_valid = true;
4046
4047 for _ in 0..3 {
4048 let c = inner_iter.next();
4049
4050 match c {
4051 Some('0'..='9') | Some('a'..='f') | Some('A'..='F') => {
4052 inner_buf.push(c.unwrap());
4053 }
4054 _ => {
4055 is_valid = false;
4056
4057 break;
4058 }
4059 }
4060 }
4061
4062 if is_curly {
4063 inner_buf.push('}');
4064 }
4065
4066 if is_valid {
4067 buf.push_str(&inner_buf);
4068
4069 let end = if is_curly { 7 } else { 5 };
4070
4071 for _ in 0..end {
4072 iter.next();
4073 }
4074 }
4075 } else {
4076 buf.push_str("\\\\");
4077 }
4078 }
4079 _ => {
4080 buf.push_str("\\\\");
4081 }
4082 }
4083 }
4084 '\'' => {
4085 buf.push('\'');
4086 }
4087 '"' => {
4088 buf.push('"');
4089 }
4090 '\x01'..='\x0f' if !first => {
4091 if may_need_quote {
4092 need_quote = true;
4093 let _ = write!(buf, "\\x{:x}", c as u8);
4094 } else {
4095 let _ = write!(buf, "\\u00{:x}", c as u8);
4096 }
4097 }
4098 '\x10'..='\x1f' if !first => {
4099 if may_need_quote {
4100 need_quote = true;
4101 let _ = write!(buf, "\\x{:x}", c as u8);
4102 } else {
4103 let _ = write!(buf, "\\u00{:x}", c as u8);
4104 }
4105 }
4106 '\x20'..='\x7e' => {
4107 buf.push(c);
4108 }
4109 '\u{7f}'..='\u{ff}' => {
4110 if may_need_quote {
4111 need_quote = true;
4112 let _ = write!(buf, "\\x{:x}", c as u8);
4113 } else {
4114 let _ = write!(buf, "\\u00{:x}", c as u8);
4115 }
4116 }
4117 '\u{2028}' => {
4118 buf.push_str("\\u2028");
4119 }
4120 '\u{2029}' => {
4121 buf.push_str("\\u2029");
4122 }
4123 '\u{FEFF}' => {
4124 buf.push_str("\\uFEFF");
4125 }
4126 _ => {
4127 if c.is_ascii() {
4128 buf.push(c);
4129 } else if c > '\u{FFFF}' {
4130 if target <= EsVersion::Es5 {
4136 let h = ((c as u32 - 0x10000) / 0x400) + 0xd800;
4138 let l = (c as u32 - 0x10000) % 0x400 + 0xdc00;
4139
4140 let _ = write!(buf, r#""\u{:04X}\u{:04X}""#, h, l);
4141 } else {
4142 let _ = write!(buf, "\\u{{{:04X}}}", c as u32);
4143 }
4144 } else {
4145 let _ = write!(buf, "\\u{:04X}", c as u16);
4146 }
4147 }
4148 }
4149 first = false;
4150 }
4151
4152 if need_quote {
4153 CowStr::Owned(format_compact!("\"{}\"", buf))
4154 } else {
4155 CowStr::Owned(buf)
4156 }
4157}
4158
4159fn get_quoted_utf16(v: &str, ascii_only: bool, target: EsVersion) -> (AsciiChar, CowStr) {
4161 if v.is_ascii() {
4164 let mut needs_escaping = false;
4165 let mut single_quote_count = 0;
4166 let mut double_quote_count = 0;
4167
4168 for &b in v.as_bytes() {
4169 match b {
4170 b'\'' => single_quote_count += 1,
4171 b'"' => double_quote_count += 1,
4172 0..=0x1f | b'\\' => {
4174 needs_escaping = true;
4175 break;
4176 }
4177 _ => {}
4178 }
4179 }
4180
4181 if !needs_escaping {
4182 let quote_char = if double_quote_count > single_quote_count {
4183 AsciiChar::Apostrophe
4184 } else {
4185 AsciiChar::Quotation
4186 };
4187
4188 if (quote_char == AsciiChar::Apostrophe && single_quote_count == 0)
4190 || (quote_char == AsciiChar::Quotation && double_quote_count == 0)
4191 {
4192 return (quote_char, CowStr::Borrowed(v));
4193 }
4194 }
4195 }
4196
4197 let (mut single_quote_count, mut double_quote_count) = (0, 0);
4200 for c in v.chars() {
4201 match c {
4202 '\'' => single_quote_count += 1,
4203 '"' => double_quote_count += 1,
4204 _ => {}
4205 }
4206 }
4207
4208 let quote_char = if double_quote_count > single_quote_count {
4210 AsciiChar::Apostrophe
4211 } else {
4212 AsciiChar::Quotation
4213 };
4214 let escape_char = if quote_char == AsciiChar::Apostrophe {
4215 AsciiChar::Apostrophe
4216 } else {
4217 AsciiChar::Quotation
4218 };
4219 let escape_count = if quote_char == AsciiChar::Apostrophe {
4220 single_quote_count
4221 } else {
4222 double_quote_count
4223 };
4224
4225 let capacity = v.len() + escape_count;
4227 let mut buf = CompactString::with_capacity(capacity);
4228
4229 let mut iter = v.chars().peekable();
4230 while let Some(c) = iter.next() {
4231 match c {
4232 '\x00' => {
4233 if target < EsVersion::Es5 || matches!(iter.peek(), Some('0'..='9')) {
4234 buf.push_str("\\x00");
4235 } else {
4236 buf.push_str("\\0");
4237 }
4238 }
4239 '\u{0008}' => buf.push_str("\\b"),
4240 '\u{000c}' => buf.push_str("\\f"),
4241 '\n' => buf.push_str("\\n"),
4242 '\r' => buf.push_str("\\r"),
4243 '\u{000b}' => buf.push_str("\\v"),
4244 '\t' => buf.push('\t'),
4245 '\\' => {
4246 let next = iter.peek();
4247 match next {
4248 Some('u') => {
4249 let mut inner_iter = iter.clone();
4250 inner_iter.next();
4251
4252 let mut is_curly = false;
4253 let mut next = inner_iter.peek();
4254
4255 if next == Some(&'{') {
4256 is_curly = true;
4257 inner_iter.next();
4258 next = inner_iter.peek();
4259 } else if next != Some(&'D') && next != Some(&'d') {
4260 buf.push('\\');
4261 }
4262
4263 if let Some(c @ 'D' | c @ 'd') = next {
4264 let mut inner_buf = String::with_capacity(8);
4265 inner_buf.push('\\');
4266 inner_buf.push('u');
4267
4268 if is_curly {
4269 inner_buf.push('{');
4270 }
4271
4272 inner_buf.push(*c);
4273 inner_iter.next();
4274
4275 let mut is_valid = true;
4276 for _ in 0..3 {
4277 match inner_iter.next() {
4278 Some(c @ '0'..='9') | Some(c @ 'a'..='f')
4279 | Some(c @ 'A'..='F') => {
4280 inner_buf.push(c);
4281 }
4282 _ => {
4283 is_valid = false;
4284 break;
4285 }
4286 }
4287 }
4288
4289 if is_curly {
4290 inner_buf.push('}');
4291 }
4292
4293 let range = if is_curly {
4294 3..(inner_buf.len() - 1)
4295 } else {
4296 2..6
4297 };
4298
4299 if is_valid {
4300 let val_str = &inner_buf[range];
4301 if let Ok(v) = u32::from_str_radix(val_str, 16) {
4302 if v > 0xffff {
4303 buf.push_str(&inner_buf);
4304 let end = if is_curly { 7 } else { 5 };
4305 for _ in 0..end {
4306 iter.next();
4307 }
4308 } else if (0xd800..=0xdfff).contains(&v) {
4309 buf.push('\\');
4310 } else {
4311 buf.push_str("\\\\");
4312 }
4313 } else {
4314 buf.push_str("\\\\");
4315 }
4316 } else {
4317 buf.push_str("\\\\");
4318 }
4319 } else if is_curly {
4320 buf.push_str("\\\\");
4321 } else {
4322 buf.push('\\');
4323 }
4324 }
4325 _ => buf.push_str("\\\\"),
4326 }
4327 }
4328 c if c == escape_char => {
4329 buf.push('\\');
4330 buf.push(c);
4331 }
4332 '\x01'..='\x0f' => {
4333 buf.push_str("\\x0");
4334 write!(&mut buf, "{:x}", c as u8).unwrap();
4335 }
4336 '\x10'..='\x1f' => {
4337 buf.push_str("\\x");
4338 write!(&mut buf, "{:x}", c as u8).unwrap();
4339 }
4340 '\x20'..='\x7e' => buf.push(c),
4341 '\u{7f}'..='\u{ff}' => {
4342 if ascii_only || target <= EsVersion::Es5 {
4343 buf.push_str("\\x");
4344 write!(&mut buf, "{:x}", c as u8).unwrap();
4345 } else {
4346 buf.push(c);
4347 }
4348 }
4349 '\u{2028}' => buf.push_str("\\u2028"),
4350 '\u{2029}' => buf.push_str("\\u2029"),
4351 '\u{FEFF}' => buf.push_str("\\uFEFF"),
4352 c => {
4353 if c.is_ascii() {
4354 buf.push(c);
4355 } else if c > '\u{FFFF}' {
4356 if target <= EsVersion::Es5 {
4357 let h = ((c as u32 - 0x10000) / 0x400) + 0xd800;
4358 let l = (c as u32 - 0x10000) % 0x400 + 0xdc00;
4359 write!(&mut buf, "\\u{:04X}\\u{:04X}", h, l).unwrap();
4360 } else if ascii_only {
4361 write!(&mut buf, "\\u{{{:04X}}}", c as u32).unwrap();
4362 } else {
4363 buf.push(c);
4364 }
4365 } else if ascii_only {
4366 write!(&mut buf, "\\u{:04X}", c as u16).unwrap();
4367 } else {
4368 buf.push(c);
4369 }
4370 }
4371 }
4372 }
4373
4374 (quote_char, CowStr::Owned(buf))
4375}
4376
4377fn handle_invalid_unicodes(s: &str) -> Cow<str> {
4378 static NEEDLE: Lazy<Finder> = Lazy::new(|| Finder::new("\\\0"));
4379 if NEEDLE.find(s.as_bytes()).is_none() {
4380 return Cow::Borrowed(s);
4381 }
4382
4383 Cow::Owned(s.replace("\\\0", "\\"))
4384}
4385
4386fn require_space_before_rhs(rhs: &Expr, op: &BinaryOp) -> bool {
4387 match rhs {
4388 Expr::Lit(Lit::Num(v)) if v.value.is_sign_negative() && *op == op!(bin, "-") => true,
4389
4390 Expr::Update(UpdateExpr {
4391 prefix: true,
4392 op: update,
4393 ..
4394 }) => matches!(
4395 (op, update),
4396 (op!(bin, "-"), op!("--")) | (op!(bin, "+"), op!("++"))
4397 ),
4398
4399 Expr::Unary(UnaryExpr {
4401 op: op!("!"), arg, ..
4402 }) if *op == op!("<") || *op == op!("<<") => {
4403 if let Expr::Update(UpdateExpr { op: op!("--"), .. }) = &**arg {
4404 true
4405 } else {
4406 false
4407 }
4408 }
4409
4410 Expr::Unary(UnaryExpr { op: unary, .. }) => matches!(
4411 (op, unary),
4412 (op!(bin, "-"), op!(unary, "-")) | (op!(bin, "+"), op!(unary, "+"))
4413 ),
4414
4415 Expr::Bin(BinExpr { left, .. }) => require_space_before_rhs(left, op),
4416
4417 _ => false,
4418 }
4419}
4420
4421fn is_empty_comments(span: &Span, comments: &Option<&dyn Comments>) -> bool {
4422 span.is_dummy() || comments.map_or(true, |c| !c.has_leading(span.span_hi() - BytePos(1)))
4423}
4424
4425fn minify_number(num: f64, detect_dot: &mut bool) -> String {
4426 'hex: {
4430 if num.fract() == 0.0 && num.abs() <= u64::MAX as f64 {
4431 let int = num.abs() as u64;
4432
4433 if int < 10000000 {
4434 break 'hex;
4435 }
4436
4437 if int % 1000 == 0 {
4439 break 'hex;
4440 }
4441
4442 *detect_dot = false;
4443 return format!(
4444 "{}{:#x}",
4445 if num.is_sign_negative() { "-" } else { "" },
4446 int
4447 );
4448 }
4449 }
4450
4451 let mut num = num.to_string();
4452
4453 if num.contains(".") {
4454 *detect_dot = false;
4455 }
4456
4457 if let Some(num) = num.strip_prefix("0.") {
4458 let cnt = clz(num);
4459 if cnt > 2 {
4460 return format!("{}e-{}", &num[cnt..], num.len());
4461 }
4462 return format!(".{}", num);
4463 }
4464
4465 if let Some(num) = num.strip_prefix("-0.") {
4466 let cnt = clz(num);
4467 if cnt > 2 {
4468 return format!("-{}e-{}", &num[cnt..], num.len());
4469 }
4470 return format!("-.{}", num);
4471 }
4472
4473 if num.ends_with("000") {
4474 *detect_dot = false;
4475
4476 let cnt = num
4477 .as_bytes()
4478 .iter()
4479 .rev()
4480 .skip(3)
4481 .take_while(|&&c| c == b'0')
4482 .count()
4483 + 3;
4484
4485 num.truncate(num.len() - cnt);
4486 num.push('e');
4487 num.push_str(&cnt.to_string());
4488 }
4489
4490 num
4491}
4492
4493fn clz(s: &str) -> usize {
4494 s.as_bytes().iter().take_while(|&&c| c == b'0').count()
4495}
4496
4497fn span_has_leading_comment(cmt: &dyn Comments, span: Span) -> bool {
4498 let lo = span.lo;
4499
4500 if let Some(cmt) = cmt.get_leading(lo) {
4502 if cmt.iter().any(|cmt| {
4503 cmt.kind == CommentKind::Line
4504 || cmt
4505 .text
4506 .chars()
4507 .any(|c| c == '\n' || c == '\r' || c == '\u{2028}' || c == '\u{2029}')
4509 }) {
4510 return true;
4511 }
4512 }
4513
4514 false
4515}