Skip to main content

swc_ecma_codegen/
object.rs

1use swc_common::{Spanned, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_codegen_macros::node_impl;
4
5#[cfg(swc_ast_unknown)]
6use crate::unknown_error;
7use crate::{
8    is_empty_comments,
9    scope_helpers::for_each_param_binding,
10    text_writer::{BindingStorage, ScopeKind},
11    ListFormat,
12};
13
14#[node_impl]
15impl MacroNode for ObjectLit {
16    fn emit(&mut self, emitter: &mut Macro) -> Result {
17        emitter.emit_leading_comments_of_span(self.span(), false)?;
18
19        srcmap!(emitter, self, true);
20
21        punct!(emitter, "{");
22
23        let emit_new_line = !emitter.cfg.minify
24            && !(self.props.is_empty() && is_empty_comments(&self.span(), &emitter.comments));
25
26        if emit_new_line {
27            emitter.wr.write_line()?;
28        }
29
30        let mut list_format =
31            ListFormat::ObjectLiteralExpressionProperties | ListFormat::CanSkipTrailingComma;
32
33        if !emit_new_line {
34            list_format -= ListFormat::MultiLine | ListFormat::Indented;
35        }
36
37        emitter.emit_list(self.span(), Some(&self.props), list_format)?;
38
39        if emit_new_line {
40            emitter.wr.write_line()?;
41        }
42
43        srcmap!(emitter, self, false, true);
44        punct!(emitter, "}");
45
46        Ok(())
47    }
48}
49
50#[node_impl]
51impl MacroNode for Prop {
52    fn emit(&mut self, emitter: &mut Macro) -> Result {
53        match self {
54            Prop::Shorthand(ref n) => emit!(n),
55            Prop::KeyValue(ref n) => emit!(n),
56            Prop::Assign(ref n) => emit!(n),
57            Prop::Getter(ref n) => emit!(n),
58            Prop::Setter(ref n) => emit!(n),
59            Prop::Method(ref n) => emit!(n),
60            #[cfg(swc_ast_unknown)]
61            _ => return Err(unknown_error()),
62        }
63
64        Ok(())
65    }
66}
67
68#[node_impl]
69impl MacroNode for KeyValueProp {
70    fn emit(&mut self, emitter: &mut Macro) -> Result {
71        emitter.emit_leading_comments_of_span(self.span(), false)?;
72        let key_span = self.key.span();
73        let value_span = self.value.span();
74        if !key_span.is_dummy() {
75            emitter.wr.add_srcmap(key_span.lo)?;
76        }
77        emit!(self.key);
78        if !key_span.is_dummy() && value_span.is_dummy() {
79            emitter.wr.add_srcmap(key_span.hi)?;
80        }
81        punct!(emitter, ":");
82        formatting_space!(emitter);
83        if key_span.is_dummy() && !value_span.is_dummy() {
84            emitter.wr.add_srcmap(value_span.lo)?;
85        }
86        emit!(self.value);
87
88        Ok(())
89    }
90}
91
92#[node_impl]
93impl MacroNode for AssignProp {
94    fn emit(&mut self, emitter: &mut Macro) -> Result {
95        emitter.emit_leading_comments_of_span(self.span(), false)?;
96
97        srcmap!(emitter, self, true);
98
99        emit!(self.key);
100        punct!(emitter, "=");
101        emit!(self.value);
102
103        Ok(())
104    }
105}
106
107#[node_impl]
108impl MacroNode for GetterProp {
109    fn emit(&mut self, emitter: &mut Macro) -> Result {
110        emitter.emit_leading_comments_of_span(self.span(), false)?;
111
112        srcmap!(emitter, self, true);
113        emitter.start_scope(
114            None,
115            ScopeKind::Function,
116            true,
117            false,
118            Some(self.function.span),
119        )?;
120
121        keyword!(emitter, "get");
122
123        let starts_with_alpha_num = match self.key {
124            PropName::Str(_) | PropName::Computed(_) => false,
125            _ => true,
126        };
127        if starts_with_alpha_num {
128            space!(emitter);
129        } else {
130            formatting_space!(emitter);
131        }
132        emit!(self.key);
133        formatting_space!(emitter);
134        emitter.emit_fn_trailing(&self.function)?;
135        emitter.end_scope()?;
136
137        Ok(())
138    }
139}
140
141#[node_impl]
142impl MacroNode for SetterProp {
143    fn emit(&mut self, emitter: &mut Macro) -> Result {
144        emitter.emit_leading_comments_of_span(self.span(), false)?;
145
146        srcmap!(emitter, self, true);
147        emitter.start_scope(
148            None,
149            ScopeKind::Function,
150            true,
151            false,
152            Some(self.function.span),
153        )?;
154        if emitter.scope_tracking_enabled() {
155            let mut names = vec![];
156            for_each_param_binding(&self.function.params, &mut |name| {
157                names.push(name.to_string())
158            });
159            for name in names {
160                emitter.add_scope_variable(&name, Some(&name), BindingStorage::Lexical)?;
161            }
162        }
163
164        keyword!(emitter, "set");
165
166        let starts_with_alpha_num = match self.key {
167            PropName::Str(_) | PropName::Computed(_) => false,
168            _ => true,
169        };
170
171        if starts_with_alpha_num {
172            space!(emitter);
173        } else {
174            formatting_space!(emitter);
175        }
176
177        emit!(self.key);
178        formatting_space!(emitter);
179
180        if let Some(type_params) = &self.function.type_params {
181            emit!(type_params);
182        }
183
184        emitter.emit_fn_params(&self.function)?;
185
186        if let Some(return_type) = &self.function.return_type {
187            punct!(emitter, ":");
188            formatting_space!(emitter);
189            emit!(return_type);
190        }
191
192        if let Some(body) = &self.function.body {
193            emit!(body);
194        } else {
195            semi!(emitter);
196        }
197        emitter.end_scope()?;
198
199        Ok(())
200    }
201}
202
203#[node_impl]
204impl MacroNode for MethodProp {
205    fn emit(&mut self, emitter: &mut Macro) -> Result {
206        emitter.emit_leading_comments_of_span(self.span(), false)?;
207
208        srcmap!(emitter, self, true);
209        emitter.start_scope(
210            None,
211            ScopeKind::Function,
212            true,
213            false,
214            Some(self.function.span),
215        )?;
216        if emitter.scope_tracking_enabled() {
217            let mut names = vec![];
218            for_each_param_binding(&self.function.params, &mut |name| {
219                names.push(name.to_string())
220            });
221            for name in names {
222                emitter.add_scope_variable(&name, Some(&name), BindingStorage::Lexical)?;
223            }
224        }
225
226        if self.function.is_async {
227            keyword!(emitter, "async");
228            space!(emitter);
229        }
230
231        if self.function.is_generator {
232            punct!(emitter, "*");
233        }
234
235        emit!(self.key);
236        formatting_space!(emitter);
237        // TODO
238        emitter.emit_fn_trailing(&self.function)?;
239        emitter.end_scope()?;
240
241        Ok(())
242    }
243}
244
245#[node_impl]
246impl MacroNode for PropName {
247    fn emit(&mut self, emitter: &mut Macro) -> Result {
248        match self {
249            PropName::Ident(ident) => {
250                // TODO: Use write_symbol when ident is a symbol.
251                emitter.emit_leading_comments_of_span(ident.span, false)?;
252
253                // Source map
254                emitter.wr.commit_pending_semi()?;
255
256                srcmap!(emitter, ident, true);
257
258                if emitter.cfg.ascii_only {
259                    if emitter.wr.can_ignore_invalid_unicodes() {
260                        emitter.wr.write_symbol(
261                            DUMMY_SP,
262                            &crate::get_ascii_only_ident(&ident.sym, true, emitter.cfg.target),
263                        )?;
264                    } else {
265                        emitter.wr.write_symbol(
266                            DUMMY_SP,
267                            &crate::get_ascii_only_ident(
268                                &crate::handle_invalid_unicodes(&ident.sym),
269                                true,
270                                emitter.cfg.target,
271                            ),
272                        )?;
273                    }
274                } else {
275                    emit!(ident);
276                }
277            }
278            PropName::Str(ref n) => emit!(n),
279            PropName::Num(ref n) => emit!(n),
280            PropName::BigInt(ref n) => emit!(n),
281            PropName::Computed(ref n) => emit!(n),
282            #[cfg(swc_ast_unknown)]
283            _ => return Err(unknown_error()),
284        }
285
286        Ok(())
287    }
288}
289
290#[node_impl]
291impl MacroNode for ComputedPropName {
292    fn emit(&mut self, emitter: &mut Macro) -> Result {
293        srcmap!(emitter, self, true);
294
295        punct!(emitter, "[");
296        emit!(self.expr);
297        punct!(emitter, "]");
298
299        srcmap!(emitter, self, false);
300
301        Ok(())
302    }
303}