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