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};
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}