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