1use std::iter;
2
3use swc_atoms::atom;
4use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
5use swc_ecma_ast::*;
6
7#[allow(clippy::wrong_self_convention)]
19pub trait ExprFactory: Into<Box<Expr>> {
20 #[cfg_attr(not(debug_assertions), inline(always))]
39 fn as_arg(self) -> ExprOrSpread {
40 ExprOrSpread {
41 expr: self.into(),
42 spread: None,
43 }
44 }
45
46 #[cfg_attr(not(debug_assertions), inline(always))]
48 fn into_stmt(self) -> Stmt {
49 let expr = self.into();
50 ExprStmt {
51 span: expr.span(),
52 expr,
53 }
54 .into()
55 }
56
57 #[cfg_attr(not(debug_assertions), inline(always))]
59 fn into_return_stmt(self) -> ReturnStmt {
60 ReturnStmt {
61 span: DUMMY_SP,
62 arg: Some(self.into()),
63 }
64 }
65
66 #[cfg_attr(not(debug_assertions), inline(always))]
67 fn as_callee(self) -> Callee {
68 Callee::Expr(self.into())
69 }
70
71 #[cfg_attr(not(debug_assertions), inline(always))]
72 fn as_iife(self) -> CallExpr {
73 CallExpr {
74 span: DUMMY_SP,
75 callee: self.as_callee(),
76 ..Default::default()
77 }
78 }
79
80 #[cfg_attr(not(debug_assertions), inline(always))]
83 fn into_lazy_arrow(self, params: Vec<Pat>) -> ArrowExpr {
84 ArrowExpr {
85 params,
86 body: Box::new(BlockStmtOrExpr::Expr(self.into())),
87 ..Default::default()
88 }
89 }
90
91 #[cfg_attr(not(debug_assertions), inline(always))]
94 fn into_lazy_fn(self, params: Vec<Param>) -> Function {
95 Function {
96 params,
97 decorators: Default::default(),
98 span: DUMMY_SP,
99 body: Some(BlockStmt {
100 span: DUMMY_SP,
101 stmts: vec![self.into_return_stmt().into()],
102 ..Default::default()
103 }),
104 ..Default::default()
105 }
106 }
107
108 #[cfg_attr(not(debug_assertions), inline(always))]
109 fn into_lazy_auto(self, params: Vec<Pat>, support_arrow: bool) -> Expr {
110 if support_arrow {
111 self.into_lazy_arrow(params).into()
112 } else {
113 self.into_lazy_fn(params.into_iter().map(From::from).collect())
114 .into_fn_expr(None)
115 .into()
116 }
117 }
118
119 #[cfg_attr(not(debug_assertions), inline(always))]
122 fn into_var_decl(self, kind: VarDeclKind, name: Pat) -> VarDecl {
123 let var_declarator = VarDeclarator {
124 span: DUMMY_SP,
125 name,
126 init: Some(self.into()),
127 definite: false,
128 };
129
130 VarDecl {
131 kind,
132 decls: vec![var_declarator],
133 ..Default::default()
134 }
135 }
136
137 #[cfg_attr(not(debug_assertions), inline(always))]
138 fn into_new_expr(self, span: Span, args: Option<Vec<ExprOrSpread>>) -> NewExpr {
139 NewExpr {
140 span,
141 callee: self.into(),
142 args,
143 ..Default::default()
144 }
145 }
146
147 #[cfg_attr(not(debug_assertions), inline(always))]
148 fn apply(self, span: Span, this: Box<Expr>, args: Vec<ExprOrSpread>) -> Expr {
149 let apply = self.make_member(IdentName::new(atom!("apply"), span));
150
151 CallExpr {
152 span,
153 callee: apply.as_callee(),
154 args: iter::once(this.as_arg()).chain(args).collect(),
155
156 ..Default::default()
157 }
158 .into()
159 }
160
161 #[cfg_attr(not(debug_assertions), inline(always))]
162 fn call_fn(self, span: Span, args: Vec<ExprOrSpread>) -> Expr {
163 CallExpr {
164 span,
165 args,
166 callee: self
167 .make_member(IdentName::new(atom!("call"), span))
168 .as_callee(),
169 ..Default::default()
170 }
171 .into()
172 }
173
174 #[cfg_attr(not(debug_assertions), inline(always))]
175 fn as_call(self, span: Span, args: Vec<ExprOrSpread>) -> Expr {
176 CallExpr {
177 span,
178 args,
179 callee: self.as_callee(),
180 ..Default::default()
181 }
182 .into()
183 }
184
185 #[cfg_attr(not(debug_assertions), inline(always))]
186 fn as_fn_decl(self) -> Option<FnDecl> {
187 match *self.into() {
188 Expr::Fn(FnExpr {
189 ident: Some(ident),
190 function,
191 }) => Some(FnDecl {
192 ident,
193 declare: false,
194 function,
195 }),
196 _ => None,
197 }
198 }
199
200 #[cfg_attr(not(debug_assertions), inline(always))]
201 fn as_class_decl(self) -> Option<ClassDecl> {
202 match *self.into() {
203 Expr::Class(ClassExpr {
204 ident: Some(ident),
205 class,
206 }) => Some(ClassDecl {
207 ident,
208 declare: false,
209 class,
210 }),
211 _ => None,
212 }
213 }
214
215 #[cfg_attr(not(debug_assertions), inline(always))]
216 fn wrap_with_paren(self) -> Expr {
217 let expr = self.into();
218 let span = expr.span();
219 ParenExpr { expr, span }.into()
220 }
221
222 #[cfg_attr(not(debug_assertions), inline(always))]
224 fn make_eq<T>(self, right: T) -> Expr
225 where
226 T: Into<Expr>,
227 {
228 self.make_bin(op!("==="), right)
229 }
230
231 #[cfg_attr(not(debug_assertions), inline(always))]
233 fn make_bin<T>(self, op: BinaryOp, right: T) -> Expr
234 where
235 T: Into<Expr>,
236 {
237 let right = Box::new(right.into());
238
239 BinExpr {
240 span: DUMMY_SP,
241 left: self.into(),
242 op,
243 right,
244 }
245 .into()
246 }
247
248 #[cfg_attr(not(debug_assertions), inline(always))]
250 fn make_assign_to(self, op: AssignOp, left: AssignTarget) -> Expr {
251 let right = self.into();
252
253 AssignExpr {
254 span: DUMMY_SP,
255 left,
256 op,
257 right,
258 }
259 .into()
260 }
261
262 #[cfg_attr(not(debug_assertions), inline(always))]
263 fn make_member(self, prop: IdentName) -> MemberExpr {
264 MemberExpr {
265 obj: self.into(),
266 span: DUMMY_SP,
267 prop: MemberProp::Ident(prop),
268 }
269 }
270
271 #[cfg_attr(not(debug_assertions), inline(always))]
272 fn computed_member<T>(self, prop: T) -> MemberExpr
273 where
274 T: Into<Box<Expr>>,
275 {
276 MemberExpr {
277 obj: self.into(),
278 span: DUMMY_SP,
279 prop: MemberProp::Computed(ComputedPropName {
280 span: DUMMY_SP,
281 expr: prop.into(),
282 }),
283 }
284 }
285}
286
287impl<T: Into<Box<Expr>>> ExprFactory for T {}
288
289pub trait IntoIndirectCall
290where
291 Self: std::marker::Sized,
292{
293 type Item;
294 fn into_indirect(self) -> Self::Item;
295}
296
297impl IntoIndirectCall for CallExpr {
298 type Item = CallExpr;
299
300 #[cfg_attr(not(debug_assertions), inline(always))]
301 fn into_indirect(self) -> CallExpr {
302 let callee = self.callee.into_indirect();
303
304 CallExpr { callee, ..self }
305 }
306}
307
308impl IntoIndirectCall for Callee {
309 type Item = Callee;
310
311 #[cfg_attr(not(debug_assertions), inline(always))]
312 fn into_indirect(self) -> Callee {
313 SeqExpr {
314 span: DUMMY_SP,
315 exprs: vec![0f64.into(), self.expect_expr()],
316 }
317 .as_callee()
318 }
319}
320
321impl IntoIndirectCall for TaggedTpl {
322 type Item = TaggedTpl;
323
324 #[cfg_attr(not(debug_assertions), inline(always))]
325 fn into_indirect(mut self) -> Self {
326 Self {
327 tag: Box::new(
328 SeqExpr {
329 span: DUMMY_SP,
330 exprs: vec![0f64.into(), self.tag.take()],
331 }
332 .into(),
333 ),
334 ..self
335 }
336 }
337}
338
339pub trait FunctionFactory: Into<Box<Function>> {
340 #[cfg_attr(not(debug_assertions), inline(always))]
341 fn into_fn_expr(self, ident: Option<Ident>) -> FnExpr {
342 FnExpr {
343 ident,
344 function: self.into(),
345 }
346 }
347
348 #[cfg_attr(not(debug_assertions), inline(always))]
349 fn into_fn_decl(self, ident: Ident) -> FnDecl {
350 FnDecl {
351 ident,
352 declare: false,
353 function: self.into(),
354 }
355 }
356
357 #[cfg_attr(not(debug_assertions), inline(always))]
358 fn into_method_prop(self, key: PropName) -> MethodProp {
359 MethodProp {
360 key,
361 function: self.into(),
362 }
363 }
364}
365
366impl<T: Into<Box<Function>>> FunctionFactory for T {}