1use swc_common::{Span, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_transforms_base::helper;
4use swc_ecma_utils::{prop_name_to_expr, prop_name_to_expr_value, quote_ident, ExprFactory};
5use swc_trace_macro::swc_trace;
6
7use super::Config;
8
9pub(super) enum MemberInit {
10 PubProp(PubProp),
11 PrivProp(PrivProp),
12 PrivMethod(PrivMethod),
13 PrivAccessor(PrivAccessor),
14 StaticBlock(Box<Expr>),
15}
16
17pub(super) struct PubProp {
18 pub span: Span,
19 pub name: PropName,
20 pub value: Box<Expr>,
21}
22
23pub(super) struct PrivProp {
24 pub span: Span,
25 pub name: Ident,
26 pub value: Box<Expr>,
27}
28
29pub(super) struct PrivMethod {
30 pub span: Span,
31 pub name: Ident,
32 pub fn_name: Ident,
34}
35
36pub(super) struct PrivAccessor {
37 pub span: Span,
38 pub name: Ident,
39 pub getter: Option<Ident>,
40 pub setter: Option<Ident>,
41}
42
43pub(super) struct MemberInitRecord {
44 c: Config,
45 pub record: Vec<MemberInit>,
46}
47
48#[swc_trace]
49impl MemberInitRecord {
50 pub fn new(c: Config) -> Self {
51 Self {
52 c,
53 record: Vec::new(),
54 }
55 }
56
57 pub fn push(&mut self, member: MemberInit) -> bool {
58 if let MemberInit::PrivAccessor(accessor) = member {
60 if let Some(MemberInit::PrivAccessor(previous)) =
61 self.record.iter_mut().find(|item| matches!(item, MemberInit::PrivAccessor(PrivAccessor { name, .. }) if name.sym == accessor.name.sym))
62 {
63 previous.getter = previous.getter.take().or(accessor.getter);
64 previous.setter = previous.setter.take().or(accessor.setter);
65 false
66 } else {
67 self.record.push(MemberInit::PrivAccessor(accessor));
68 true
69 }
70 } else {
71 self.record.push(member);
72 true
73 }
74 }
75
76 pub fn into_init(self) -> Vec<Box<Expr>> {
77 let mut normal_init = Vec::new();
78 let mut value_init = Vec::new();
79 for init in self.record {
80 match init {
81 MemberInit::PrivMethod(PrivMethod {
82 span,
83 name,
84 fn_name,
85 }) => {
86 let (callee, args) = if self.c.private_as_properties {
87 (
88 obj_def_prop(),
89 vec![
90 ThisExpr { span: DUMMY_SP }.as_arg(),
91 name.as_arg(),
92 get_method_desc(Box::new(fn_name.into())).as_arg(),
93 ],
94 )
95 } else {
96 (
97 helper!(class_private_method_init),
98 vec![ThisExpr { span: DUMMY_SP }.as_arg(), name.as_arg()],
99 )
100 };
101 normal_init.push(
102 CallExpr {
103 span,
104 callee,
105 args,
106 ..Default::default()
107 }
108 .into(),
109 )
110 }
111 MemberInit::PrivProp(PrivProp { span, name, value }) => value_init.push(
112 CallExpr {
113 span,
114 callee: if self.c.private_as_properties {
115 obj_def_prop()
116 } else {
117 helper!(class_private_field_init)
118 },
119 args: vec![
120 ThisExpr { span: DUMMY_SP }.as_arg(),
121 name.as_arg(),
122 get_value_desc(value).as_arg(),
123 ],
124 ..Default::default()
125 }
126 .into(),
127 ),
128 MemberInit::PrivAccessor(PrivAccessor {
129 span,
130 name,
131 getter,
132 setter,
133 }) => normal_init.push(
134 CallExpr {
135 span,
136 callee: if self.c.private_as_properties {
137 obj_def_prop()
138 } else {
139 helper!(class_private_field_init)
140 },
141 args: vec![
142 ThisExpr { span: DUMMY_SP }.as_arg(),
143 name.as_arg(),
144 get_accessor_desc(getter, setter).as_arg(),
145 ],
146 ..Default::default()
147 }
148 .into(),
149 ),
150 MemberInit::PubProp(PubProp { span, name, value }) => value_init.push(
151 if self.c.set_public_fields {
152 let this = ThisExpr { span: DUMMY_SP };
153 Expr::from(AssignExpr {
154 span,
155 left: match name {
156 PropName::Ident(id) => this.make_member(id).into(),
157 _ => this.computed_member(prop_name_to_expr(name)).into(),
158 },
159 op: op!("="),
160 right: value,
161 })
162 } else {
163 CallExpr {
164 span,
165 callee: helper!(define_property),
166 args: vec![
167 ThisExpr { span: DUMMY_SP }.as_arg(),
168 prop_name_to_expr_value(name).as_arg(),
169 value.as_arg(),
170 ],
171 ..Default::default()
172 }
173 .into()
174 }
175 .into(),
176 ),
177 MemberInit::StaticBlock(..) => unreachable!(),
178 }
179 }
180
181 normal_init.extend(value_init);
182
183 normal_init
184 }
185
186 pub fn into_init_static(self, class_ident: Ident) -> Vec<Stmt> {
187 let mut normal_init = Vec::new();
188 let mut value_init = Vec::new();
189
190 for value in self.record {
191 match value {
192 MemberInit::PubProp(PubProp { span, name, value }) => value_init.push(
193 ExprStmt {
194 span,
195 expr: (if self.c.set_public_fields {
196 let class = class_ident.clone();
197 Expr::from(AssignExpr {
198 span,
199 left: match name {
200 PropName::Ident(id) => class.make_member(id).into(),
201 _ => class.computed_member(prop_name_to_expr(name)).into(),
202 },
203 op: op!("="),
204 right: value,
205 })
206 } else {
207 CallExpr {
208 span,
209 callee: helper!(define_property),
210 args: vec![
211 class_ident.clone().as_arg(),
212 prop_name_to_expr_value(name).as_arg(),
213 value.as_arg(),
214 ],
215 ..Default::default()
216 }
217 .into()
218 })
219 .into(),
220 }
221 .into(),
222 ),
223 MemberInit::PrivProp(PrivProp { span, name, value }) => {
224 value_init.push(if self.c.private_as_properties {
225 ExprStmt {
226 span,
227 expr: CallExpr {
228 span,
229 callee: obj_def_prop(),
230 args: vec![
231 class_ident.clone().as_arg(),
232 name.as_arg(),
233 get_value_desc(value).as_arg(),
234 ],
235 ..Default::default()
236 }
237 .into(),
238 }
239 .into()
240 } else {
241 VarDecl {
242 span,
243 kind: VarDeclKind::Var,
244 decls: vec![VarDeclarator {
245 span,
246 name: name.into(),
247 init: Some(Expr::Object(get_value_desc(value)).into()),
248 definite: false,
249 }],
250 ..Default::default()
251 }
252 .into()
253 })
254 }
255 MemberInit::PrivAccessor(PrivAccessor {
256 span,
257 name,
258 getter,
259 setter,
260 }) => normal_init.push(if self.c.private_as_properties {
261 ExprStmt {
262 span,
263 expr: CallExpr {
264 span,
265 callee: obj_def_prop(),
266 args: vec![
267 class_ident.clone().as_arg(),
268 name.as_arg(),
269 get_accessor_desc(getter, setter).as_arg(),
270 ],
271 ..Default::default()
272 }
273 .into(),
274 }
275 .into()
276 } else {
277 VarDecl {
278 span,
279 kind: VarDeclKind::Var,
280 decls: vec![VarDeclarator {
281 span,
282 name: name.into(),
283 init: Some(Expr::Object(get_accessor_desc(getter, setter)).into()),
284 definite: false,
285 }],
286 ..Default::default()
287 }
288 .into()
289 }),
290 MemberInit::PrivMethod(PrivMethod {
291 span,
292 name,
293 fn_name,
294 }) => {
295 if self.c.private_as_properties {
296 normal_init.push(
297 ExprStmt {
298 span,
299 expr: CallExpr {
300 span,
301 callee: obj_def_prop(),
302 args: vec![
303 class_ident.clone().as_arg(),
304 name.as_arg(),
305 get_method_desc(Box::new(fn_name.into())).as_arg(),
306 ],
307 ..Default::default()
308 }
309 .into(),
310 }
311 .into(),
312 )
313 } else {
314 unreachable!()
315 }
316 }
317 MemberInit::StaticBlock(expr) => value_init.push(expr.into_stmt()),
318 }
319 }
320
321 normal_init.extend(value_init);
322
323 normal_init
324 }
325}
326
327fn get_value_desc(value: Box<Expr>) -> ObjectLit {
328 ObjectLit {
329 span: DUMMY_SP,
330 props: vec![
331 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
333 key: PropName::Ident(quote_ident!("writable")),
334 value: true.into(),
335 }))),
336 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
338 key: PropName::Ident(quote_ident!("value")),
339 value,
340 }))),
341 ],
342 }
343}
344
345fn get_accessor_desc(getter: Option<Ident>, setter: Option<Ident>) -> ObjectLit {
346 ObjectLit {
347 span: DUMMY_SP,
348 props: vec![
349 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
350 key: PropName::Ident(quote_ident!("get")),
351 value: getter
352 .map(|id| Box::new(id.into()))
353 .unwrap_or_else(|| Expr::undefined(DUMMY_SP)),
354 }))),
355 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
356 key: PropName::Ident(quote_ident!("set")),
357 value: setter
358 .map(|id| Box::new(id.into()))
359 .unwrap_or_else(|| Expr::undefined(DUMMY_SP)),
360 }))),
361 ],
362 }
363}
364
365fn get_method_desc(value: Box<Expr>) -> ObjectLit {
366 ObjectLit {
367 span: DUMMY_SP,
368 props: vec![
369 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
371 key: PropName::Ident(quote_ident!("value")),
372 value,
373 }))),
374 ],
375 }
376}
377
378fn obj_def_prop() -> Callee {
379 quote_ident!("Object")
380 .make_member(quote_ident!("defineProperty"))
381 .as_callee()
382}