swc_ecma_compat_es2018/
object_spread.rs1use swc_common::{util::take::Take, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_transforms_base::{helper, perf::Parallel};
4use swc_ecma_utils::ExprFactory;
5use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
6use swc_trace_macro::swc_trace;
7
8use super::object_rest_spread::Config;
9
10#[derive(Clone, Copy)]
11pub(super) struct ObjectSpread {
12 pub config: Config,
13}
14
15impl Parallel for ObjectSpread {
16 fn create(&self) -> Self {
17 ObjectSpread {
18 config: self.config,
19 }
20 }
21
22 fn merge(&mut self, _: Self) {}
23}
24
25#[swc_trace]
26impl VisitMut for ObjectSpread {
27 noop_visit_mut_type!(fail);
28
29 fn visit_mut_expr(&mut self, expr: &mut Expr) {
30 expr.visit_mut_children_with(self);
31
32 if let Expr::Object(ObjectLit { span, props }) = expr {
33 let has_spread = props.iter().any(|p| matches!(p, PropOrSpread::Spread(..)));
34 if !has_spread {
35 return;
36 }
37
38 let mut callee = if self.config.set_property {
39 helper!(extends)
40 } else {
41 helper!(object_spread)
42 };
43
44 let args = {
46 let mut buf = Vec::new();
47 let mut obj = ObjectLit {
48 span: DUMMY_SP,
49 props: Vec::new(),
50 };
51 let mut first = true;
52 for prop in props.take() {
53 match prop {
54 PropOrSpread::Prop(..) => {
55 if !first && obj.props.is_empty() && !self.config.pure_getters {
57 buf = vec![Expr::Call(CallExpr {
58 span: DUMMY_SP,
59 callee: callee.clone(),
60 args: buf.take(),
61 ..Default::default()
62 })
63 .as_arg()];
64 }
65 obj.props.push(prop)
66 }
67 PropOrSpread::Spread(SpreadElement { expr, .. }) => {
68 if first || !obj.props.is_empty() {
70 buf.push(obj.take().as_arg());
71 if !first && !self.config.pure_getters {
72 buf = vec![Expr::Call(CallExpr {
73 span: DUMMY_SP,
74 callee: helper!(object_spread_props),
75 args: buf.take(),
76 ..Default::default()
77 })
78 .as_arg()];
79 }
80 first = false;
81 }
82
83 buf.push(expr.as_arg());
84 }
85 #[cfg(swc_ast_unknown)]
86 _ => panic!("unable to access unknown nodes"),
87 }
88 }
89
90 if !obj.props.is_empty() {
91 if !self.config.pure_getters {
92 callee = helper!(object_spread_props);
93 }
94 buf.push(obj.as_arg());
95 }
96
97 buf
98 };
99
100 *expr = CallExpr {
101 span: *span,
102 callee,
103 args,
104 ..Default::default()
105 }
106 .into();
107 }
108 }
109}