1use swc_common::{SourceMapper, Spanned};
2use swc_ecma_ast::*;
3use swc_ecma_codegen_macros::emitter;
4
5use super::{Emitter, Result};
6use crate::text_writer::WriteJs;
7
8impl<W, S: SourceMapper> Emitter<'_, W, S>
9where
10 W: WriteJs,
11 S: SourceMapperExt,
12{
13 #[emitter]
14 fn emit_decl(&mut self, node: &Decl) -> Result {
15 match node {
16 Decl::Class(ref n) => emit!(n),
17 Decl::Fn(ref n) => emit!(n),
18
19 Decl::Var(ref n) => {
20 self.emit_var_decl_inner(n)?;
21 formatting_semi!();
22 srcmap!(n, false);
23 }
24 Decl::Using(n) => emit!(n),
25 Decl::TsEnum(ref n) => emit!(n),
26 Decl::TsInterface(ref n) => emit!(n),
27 Decl::TsModule(ref n) => emit!(n),
28 Decl::TsTypeAlias(ref n) => emit!(n),
29 }
30 }
31
32 #[emitter]
33 fn emit_class_decl(&mut self, node: &ClassDecl) -> Result {
34 self.emit_class_decl_inner(node, false)?;
35 }
36
37 #[emitter]
38 fn emit_using_decl(&mut self, node: &UsingDecl) -> Result {
39 self.emit_leading_comments_of_span(node.span(), false)?;
40
41 if node.is_await {
42 keyword!("await");
43 space!();
44 }
45
46 keyword!("using");
47 space!();
48
49 self.emit_list(
50 node.span,
51 Some(&node.decls),
52 ListFormat::VariableDeclarationList,
53 )?;
54 }
55
56 pub(super) fn emit_class_decl_inner(
57 &mut self,
58 node: &ClassDecl,
59 skip_decorators: bool,
60 ) -> Result {
61 self.emit_leading_comments_of_span(node.span(), false)?;
62
63 srcmap!(self, node, true);
64
65 if node.declare {
66 keyword!(self, "declare");
67 space!(self);
68 }
69
70 if !skip_decorators {
71 for dec in &node.class.decorators {
72 emit!(self, dec);
73 }
74 }
75
76 if node.class.is_abstract {
77 keyword!(self, "abstract");
78 space!(self);
79 }
80
81 keyword!(self, "class");
82 space!(self);
83 emit!(self, node.ident);
84 emit!(self, node.class.type_params);
85
86 self.emit_class_trailing(&node.class)?;
87
88 Ok(())
89 }
90
91 #[emitter]
92 fn emit_fn_decl(&mut self, node: &FnDecl) -> Result {
93 self.emit_leading_comments_of_span(node.span(), false)?;
94
95 self.wr.commit_pending_semi()?;
96
97 srcmap!(node, true);
98
99 if node.declare {
100 keyword!("declare");
101 space!();
102 }
103
104 if node.function.is_async {
105 keyword!("async");
106 space!();
107 }
108
109 keyword!("function");
110 if node.function.is_generator {
111 punct!("*");
112 formatting_space!();
113 } else {
114 space!();
115 }
116
117 emit!(node.ident);
118
119 self.emit_fn_trailing(&node.function)?;
120 }
121
122 #[emitter]
123 fn emit_var_decl(&mut self, node: &VarDecl) -> Result {
124 self.emit_var_decl_inner(node)?;
125 }
126
127 fn emit_var_decl_inner(&mut self, node: &VarDecl) -> Result {
128 self.emit_leading_comments_of_span(node.span, false)?;
129
130 self.wr.commit_pending_semi()?;
131
132 srcmap!(self, node, true);
133
134 if node.declare {
135 keyword!(self, "declare");
136 space!(self);
137 }
138
139 keyword!(self, node.kind.as_str());
140
141 let starts_with_ident = match node.decls.first() {
142 Some(VarDeclarator {
143 name: Pat::Array(..) | Pat::Rest(..) | Pat::Object(..),
144 ..
145 }) => false,
146 _ => true,
147 };
148 if starts_with_ident {
149 space!(self);
150 } else {
151 formatting_space!(self);
152 }
153
154 self.emit_list(
155 node.span(),
156 Some(&node.decls),
157 ListFormat::VariableDeclarationList,
158 )?;
159
160 Ok(())
161 }
162
163 #[emitter]
164 fn emit_var_declarator(&mut self, node: &VarDeclarator) -> Result {
165 self.emit_leading_comments_of_span(node.span(), false)?;
166
167 srcmap!(node, true);
168
169 emit!(node.name);
170
171 if let Some(ref init) = node.init {
172 formatting_space!();
173 punct!("=");
174 formatting_space!();
175 emit!(init);
176 }
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use crate::tests::assert_min;
183
184 #[test]
185 fn issue_275() {
186 assert_min(
187 "function* foo(){
188 yield getServiceHosts()
189 }",
190 "function*foo(){yield getServiceHosts()}",
191 );
192 }
193
194 #[test]
195 fn issue_1764() {
196 assert_min(
197 "class Hoge {};
198class HogeFuga extends Hoge {};",
199 "class Hoge{};class HogeFuga extends Hoge{};",
200 );
201 }
202
203 #[test]
204 fn single_argument_arrow_expression() {
205 assert_min("function* f(){ yield x => x}", "function*f(){yield x=>x}");
206 assert_min(
207 "function* f(){ yield ({x}) => x}",
208 "function*f(){yield({x})=>x}",
209 );
210 }
211
212 #[test]
213 fn class_static_block() {
214 assert_min("class Foo { static { 1 + 1; }}", "class Foo{static{1+1}}");
215 }
216}