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