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