1use std::marker::PhantomData;
2
3use swc_common::{util::take::Take, Spanned, DUMMY_SP};
4use swc_ecma_ast::*;
5
6use crate::ExprFactory;
7
8pub struct FunctionWrapper<T> {
9 pub binding_ident: Option<Ident>,
10 pub function: Expr,
11
12 pub ignore_function_name: bool,
13 pub ignore_function_length: bool,
14
15 function_ident: Option<Ident>,
16 params: Vec<Param>,
17
18 _type: PhantomData<T>,
19}
20
21impl<T> FunctionWrapper<T> {
22 fn get_params<'a, ParamsIter, Item>(params_iter: ParamsIter) -> Vec<Param>
24 where
25 Item: Into<&'a Param>,
26 ParamsIter: IntoIterator<Item = Item>,
27 {
28 params_iter
29 .into_iter()
30 .map(Into::into)
31 .map_while(|param| match param.pat {
32 Pat::Ident(..) => Some(param.clone()),
33 Pat::Array(..) | Pat::Object(..) => Some(Param {
34 span: param.span,
35 decorators: param.decorators.clone(),
36 pat: private_ident!("_").into(),
37 }),
38 _ => None,
39 })
40 .collect()
41 }
42
43 fn build_anonymous_expression_wrapper(&mut self) -> Expr {
53 let name_ident = self.binding_ident.take();
54 let ref_ident = private_ident!("_ref");
55
56 let ref_decl: Decl = VarDecl {
57 kind: VarDeclKind::Var,
58 decls: vec![VarDeclarator {
59 span: DUMMY_SP,
60 name: Pat::Ident(ref_ident.clone().into()),
61 init: Some(Box::new(self.function.take())),
62 definite: false,
63 }],
64 ..Default::default()
65 }
66 .into();
67
68 let return_fn_stmt = {
69 let fn_expr = self.build_function_forward(ref_ident, name_ident);
70
71 ReturnStmt {
72 span: DUMMY_SP,
73 arg: Some(Box::new(fn_expr.into())),
74 }
75 }
76 .into();
77
78 let block_stmt = BlockStmt {
79 stmts: vec![ref_decl.into(), return_fn_stmt],
80 ..Default::default()
81 };
82
83 let function = Box::new(Function {
84 span: DUMMY_SP,
85 body: Some(block_stmt),
86 is_generator: false,
87 is_async: false,
88 ..Default::default()
89 });
90
91 FnExpr {
92 ident: None,
93 function,
94 }
95 .as_iife()
96 .into()
97 }
98
99 fn build_named_expression_wrapper(&mut self, name_ident: Ident) -> Expr {
110 let ref_ident = self.function_ident.as_ref().map_or_else(
111 || private_ident!("_ref"),
112 |ident| private_ident!(ident.span, format!("_{}", ident.sym)),
113 );
114
115 let ref_stmt: Stmt = VarDecl {
116 kind: VarDeclKind::Var,
117 decls: vec![VarDeclarator {
118 span: DUMMY_SP,
119 name: Pat::Ident(ref_ident.clone().into()),
120 init: Some(Box::new(self.function.take())),
121 definite: false,
122 }],
123
124 ..Default::default()
125 }
126 .into();
127
128 let fn_decl_stmt = {
129 let FnExpr { function, .. } = self.build_function_forward(ref_ident, None);
130
131 FnDecl {
132 ident: name_ident.clone(),
133 declare: false,
134 function,
135 }
136 .into()
137 };
138
139 let return_stmt = ReturnStmt {
140 span: DUMMY_SP,
141 arg: Some(Box::new(name_ident.into())),
142 }
143 .into();
144
145 let block_stmt = BlockStmt {
146 stmts: vec![ref_stmt, fn_decl_stmt, return_stmt],
147 ..Default::default()
148 };
149
150 let function = Box::new(Function {
151 span: DUMMY_SP,
152 body: Some(block_stmt),
153 is_generator: false,
154 is_async: false,
155 ..Default::default()
156 });
157
158 FnExpr {
159 ident: None,
160 function,
161 }
162 .as_iife()
163 .into()
164 }
165
166 fn build_declaration_wrapper(&mut self, name_ident: Option<Ident>) -> (FnExpr, FnDecl) {
177 let ref_ident = self.function_ident.as_ref().map_or_else(
178 || private_ident!("_ref"),
179 |ident| private_ident!(ident.span, format!("_{}", ident.sym)),
180 );
181
182 let fn_expr = self.build_function_forward(ref_ident.clone(), name_ident);
184
185 let assign_stmt = AssignExpr {
186 span: DUMMY_SP,
187 op: op!("="),
188 left: ref_ident.clone().into(),
189 right: Box::new(self.function.take()),
190 }
191 .into_stmt();
192
193 let return_ref_apply_stmt = fn_expr
195 .function
196 .body
197 .as_ref()
198 .expect("The `fn_expr` we construct cannot be None")
199 .stmts[0]
200 .clone();
201
202 let ref_fn_block_stmt = BlockStmt {
203 stmts: vec![assign_stmt, return_ref_apply_stmt],
204 ..Default::default()
205 };
206
207 let ref_decl = FnDecl {
209 declare: false,
210 ident: ref_ident,
211 function: Box::new(Function {
212 span: DUMMY_SP,
213 is_async: false,
214 is_generator: false,
215 params: self.params.take(),
216 body: Some(ref_fn_block_stmt),
217 ..Default::default()
218 }),
219 };
220
221 (fn_expr, ref_decl)
222 }
223
224 fn build_function_forward(&mut self, ref_ident: Ident, name_ident: Option<Ident>) -> FnExpr {
231 let apply = ReturnStmt {
232 span: DUMMY_SP,
233 arg: Some(Box::new(ref_ident.apply(
234 DUMMY_SP,
235 ThisExpr { span: DUMMY_SP }.into(),
236 vec![quote_ident!("arguments").as_arg()],
237 ))),
238 }
239 .into();
240
241 FnExpr {
242 ident: name_ident,
243 function: Box::new(Function {
244 params: self.params.take(),
245 span: DUMMY_SP,
246 body: Some(BlockStmt {
247 stmts: vec![apply],
248 ..Default::default()
249 }),
250 is_generator: false,
251 is_async: false,
252
253 ..Default::default()
254 }),
255 }
256 }
257}
258
259impl From<FnExpr> for FunctionWrapper<Expr> {
260 fn from(mut fn_expr: FnExpr) -> Self {
261 let function_ident = fn_expr.ident.take();
262 let params = Self::get_params(fn_expr.function.params.iter());
263 Self {
264 binding_ident: None,
265 function_ident,
266 params,
267 ignore_function_name: false,
268 ignore_function_length: false,
269 function: fn_expr.into(),
270 _type: Default::default(),
271 }
272 }
273}
274
275impl From<ArrowExpr> for FunctionWrapper<Expr> {
276 fn from(
277 ArrowExpr {
278 span,
279 params,
280 body,
281 is_async,
282 is_generator,
283 ..
284 }: ArrowExpr,
285 ) -> Self {
286 let body = Some(match *body {
287 BlockStmtOrExpr::BlockStmt(block) => block,
288 BlockStmtOrExpr::Expr(expr) => BlockStmt {
289 stmts: vec![Stmt::Return(ReturnStmt {
290 span: expr.span(),
291 arg: Some(expr),
292 })],
293 ..Default::default()
294 },
295 });
296
297 let function = Box::new(Function {
298 span,
299 params: params.into_iter().map(Into::into).collect(),
300 body,
301 type_params: None,
302 return_type: None,
303 is_generator,
304 is_async,
305 ..Default::default()
306 });
307
308 let fn_expr = FnExpr {
309 ident: None,
310 function,
311 };
312
313 Self {
314 binding_ident: None,
315 function_ident: None,
316 ignore_function_name: false,
317 ignore_function_length: false,
318 params: Self::get_params(fn_expr.function.params.iter()),
319 function: fn_expr.into(),
320 _type: Default::default(),
321 }
322 }
323}
324
325#[allow(clippy::from_over_into)]
326impl Into<Expr> for FunctionWrapper<Expr> {
327 fn into(mut self) -> Expr {
340 if let Some(name_ident) = self.function_ident.as_ref().cloned() {
341 self.build_named_expression_wrapper(name_ident)
342 } else if (!self.ignore_function_name && self.binding_ident.is_some())
343 || (!self.ignore_function_length && !self.params.is_empty())
344 {
345 self.build_anonymous_expression_wrapper()
346 } else {
347 self.function
348 }
349 }
350}
351
352impl From<FnDecl> for FunctionWrapper<FnDecl> {
353 fn from(mut fn_decl: FnDecl) -> Self {
354 let function_ident = Some(fn_decl.ident.take());
355 let params = Self::get_params(fn_decl.function.params.iter());
356 Self {
357 binding_ident: None,
358 function_ident,
359 params,
360 ignore_function_name: false,
361 ignore_function_length: false,
362 function: FnExpr {
363 ident: None,
364 function: fn_decl.function,
365 }
366 .into(),
367 _type: Default::default(),
368 }
369 }
370}
371
372pub struct FnWrapperResult<N, R> {
387 pub name_fn: N,
388 pub ref_fn: R,
389}
390
391impl From<FunctionWrapper<FnDecl>> for FnWrapperResult<FnDecl, FnDecl> {
392 fn from(mut value: FunctionWrapper<FnDecl>) -> Self {
393 let name_ident = value
394 .function_ident
395 .clone()
396 .expect("`FunctionWrapper` converted from `FnDecl` definitely has `Ident`");
397
398 let (FnExpr { function, .. }, ref_fn) = value.build_declaration_wrapper(None);
399
400 FnWrapperResult {
401 name_fn: FnDecl {
402 ident: name_ident,
403 declare: false,
404 function,
405 },
406 ref_fn,
407 }
408 }
409}
410
411impl From<FunctionWrapper<Expr>> for FnWrapperResult<FnExpr, FnDecl> {
412 fn from(mut value: FunctionWrapper<Expr>) -> Self {
413 let name_ident = value
414 .function_ident
415 .clone()
416 .or_else(|| value.binding_ident.clone());
417
418 let (name_fn, ref_fn) = value.build_declaration_wrapper(name_ident);
419
420 FnWrapperResult { name_fn, ref_fn }
421 }
422}