Skip to main content

swc_ecma_codegen/
decl.rs

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