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