act_lib/
act_process.rs

1use std::path::{Path, PathBuf};
2use std::{println, vec};
3
4use swc_common::{sync::Lrc, Span};
5use swc_common::{BytePos, SourceMap, SyntaxContext};
6use swc_ecma_ast::{
7    ArrowExpr, ClassDecl, Decl, EsVersion, FnDecl, FnExpr, Function, ModuleItem, Param, Pat,
8    TsKeywordType, TsKeywordTypeKind, TsType, VarDecl,
9};
10use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig};
11
12use crate::act_structs::get_acttype_from_string;
13use crate::{
14    act_patch::{apply_patches, get_function_params_patches},
15    act_structs::{ClassAct, FunctionAct, MethodAct, ParamAct, PatchAct, TypeAct},
16};
17
18pub fn get_typeact_from_typeid(typeid: TsKeywordTypeKind) -> TypeAct {
19    match typeid {
20        TsKeywordTypeKind::TsBooleanKeyword => TypeAct::Boolean,
21        TsKeywordTypeKind::TsNumberKeyword => TypeAct::Number,
22        TsKeywordTypeKind::TsStringKeyword => TypeAct::String,
23        TsKeywordTypeKind::TsUnknownKeyword => TypeAct::Unknown,
24        TsKeywordTypeKind::TsBigIntKeyword => TypeAct::BigInt,
25        TsKeywordTypeKind::TsSymbolKeyword => TypeAct::Symbol,
26        _ => TypeAct::Unknown,
27    }
28}
29
30pub fn get_param_type_ann(param_pat: &Pat) -> Result<Box<TsType>, String> {
31    // FIXME: This is a hack, we should not clone
32    let param_pat = param_pat.clone();
33    let mut param_type_ann: Box<TsType> = Box::new(TsType::TsKeywordType(TsKeywordType {
34        span: Span {
35            lo: BytePos::DUMMY,
36            hi: BytePos::DUMMY,
37            ctxt: SyntaxContext::default(),
38        },
39        kind: TsKeywordTypeKind::TsUnknownKeyword,
40    }));
41    if param_pat.is_ident() {
42        let param_ident = param_pat.ident().unwrap();
43        if param_ident.optional {
44            // If is optionnal, we skip it
45            return Ok(param_type_ann);
46        }
47        if param_ident.type_ann.is_none() {
48            return Err(String::from("param_ident.type_ann.is_none()"));
49        }
50        let param_type_ann_wraped = param_ident.type_ann.unwrap();
51        param_type_ann = param_type_ann_wraped.type_ann;
52    } else if param_pat.is_expr() {
53        let _param_expr = param_pat.expr().unwrap();
54        // TODO:
55    }
56
57    Ok(param_type_ann)
58}
59pub fn get_param_type_act(param_pat: &Pat) -> TypeAct {
60    let param_type_ann = get_param_type_ann(param_pat).unwrap();
61    if param_type_ann.is_ts_keyword_type() {
62        get_typeact_from_typeid(param_type_ann.ts_keyword_type().unwrap().kind)
63    } else if param_type_ann.is_ts_type_ref() {
64        let type_ref = param_type_ann.ts_type_ref().unwrap();
65        if type_ref.type_name.is_ident() {
66            let type_ref_type_name = type_ref.type_name.ident().unwrap().sym.to_string();
67            get_acttype_from_string(&type_ref_type_name)
68        } else {
69            TypeAct::Unknown
70        }
71    } else {
72        TypeAct::Unknown
73    }
74}
75
76fn get_param_name(param_pat: Pat) -> String {
77    if param_pat.is_ident() {
78        param_pat.ident().unwrap().sym.to_string()
79    } else {
80        "unknown".to_string()
81    }
82}
83pub fn get_function_params(params: Vec<Pat>) -> Vec<ParamAct> {
84    let mut params_act: Vec<ParamAct> = vec![];
85    for param in params {
86        let param_type_act = get_param_type_act(&param);
87        let param_name = get_param_name(param);
88        params_act.push(ParamAct {
89            name: param_name,
90            act_type: param_type_act,
91        })
92    }
93    params_act
94}
95
96pub fn get_function_act(function_name: String, function: Box<Function>) -> FunctionAct {
97    if function.body.is_none() {
98        panic!("Function body is empty get_function_act should not be called");
99    }
100    let function_body = function.body.unwrap();
101    let function_body_start = function_body.span.lo.0;
102    let function_act: FunctionAct = FunctionAct {
103        name: function_name,
104        params: get_function_params(get_pat_from_param(function.params)),
105        body_start: function_body_start,
106    };
107    function_act
108}
109
110pub fn get_function_patches(function_act: FunctionAct, file_name: &Path) -> Vec<PatchAct> {
111    let mut patches: Vec<PatchAct> = vec![];
112    patches.extend(get_function_params_patches(
113        function_act.params,
114        function_act.body_start,
115        function_act.name,
116        file_name.to_str().unwrap().to_string(),
117    ));
118    patches
119}
120
121pub fn process_function_decl(fn_decl: FnDecl, file_path: &Path) -> Vec<PatchAct> {
122    let function_name = fn_decl.ident.sym.to_string();
123    if fn_decl.function.body.is_some() {
124        let function_act = get_function_act(function_name, fn_decl.function);
125        let function_patches: Vec<PatchAct> = get_function_patches(function_act, file_path);
126        function_patches
127    } else {
128        vec![]
129    }
130}
131pub fn process_var_decl(var_decl: Box<VarDecl>, file_path: &Path) -> Vec<PatchAct> {
132    let var_decl_decls = var_decl.decls;
133    let mut patches: Vec<PatchAct> = vec![];
134    for var_decl_decl in var_decl_decls {
135        let var_decl_decl_name = var_decl_decl.name;
136        let var_decl_decl_init = var_decl_decl.init;
137        if var_decl_decl_init.is_some() {
138            let var_decl_decl_init_wraped = var_decl_decl_init.unwrap();
139            if var_decl_decl_init_wraped.is_fn_expr() {
140                let fn_expr = var_decl_decl_init_wraped.fn_expr().unwrap();
141                if var_decl_decl_name.is_ident() {
142                    let function_name = var_decl_decl_name.ident().unwrap().sym.to_string();
143                    let function_act = get_function_act(function_name, fn_expr.function);
144                    patches.extend(get_function_patches(function_act, file_path));
145                } else {
146                    let function_name = "unknonVarName".to_string();
147                    let function_act = get_function_act(function_name, fn_expr.function);
148                    patches.extend(get_function_patches(function_act, file_path));
149                }
150            } else if var_decl_decl_init_wraped.is_arrow() {
151                let arrow_expr = var_decl_decl_init_wraped.arrow().unwrap();
152                let function_body = arrow_expr.body;
153                if function_body.is_block_stmt() {
154                    if var_decl_decl_name.is_ident() {
155                        let function_name = var_decl_decl_name.ident().unwrap().sym.to_string();
156                        let function_body_block_stmt = function_body.block_stmt().unwrap();
157                        let function_body_start = function_body_block_stmt.span.lo.0;
158                        let function_act: FunctionAct = FunctionAct {
159                            name: function_name,
160                            params: get_function_params(arrow_expr.params),
161                            body_start: function_body_start,
162                        };
163                        let function_patches: Vec<PatchAct> =
164                            get_function_patches(function_act, file_path);
165                        patches.extend(function_patches);
166                    } else {
167                        let function_name = "unknonVarName".to_string();
168                        let function_body_block_stmt = function_body.block_stmt().unwrap();
169                        let function_body_start = function_body_block_stmt.span.lo.0;
170                        let function_act: FunctionAct = FunctionAct {
171                            name: function_name,
172                            params: get_function_params(arrow_expr.params),
173                            body_start: function_body_start,
174                        };
175                        let function_patches: Vec<PatchAct> =
176                            get_function_patches(function_act, file_path);
177                        patches.extend(function_patches);
178                    }
179                }
180            }
181        }
182    }
183    patches
184}
185pub fn process_function_expr(fn_expr: FnExpr, file_path: &Path) -> Vec<PatchAct> {
186    let function_name = fn_expr.ident.unwrap().sym.to_string();
187    if fn_expr.function.body.is_some() {
188        let function_act = get_function_act(function_name, fn_expr.function);
189        let function_patches: Vec<PatchAct> = get_function_patches(function_act, file_path);
190        function_patches
191    } else {
192        vec![]
193    }
194}
195
196pub fn process_function_arrow(arrow_expr: ArrowExpr, file_path: &Path) -> Vec<PatchAct> {
197    let function_body = arrow_expr.body;
198    if function_body.is_block_stmt() {
199        let function_body_block_stmt = function_body.block_stmt().unwrap();
200        let function_body_start = function_body_block_stmt.span.lo.0;
201        let function_act: FunctionAct = FunctionAct {
202            name: "AnonymousFunction".to_string(),
203            params: get_function_params(arrow_expr.params),
204            body_start: function_body_start,
205        };
206        let function_patches: Vec<PatchAct> = get_function_patches(function_act, file_path);
207        return function_patches;
208    }
209    vec![]
210}
211
212pub fn get_class_act(class_decl: ClassDecl) -> ClassAct {
213    let class_name = class_decl.ident.sym.to_string();
214    let class = class_decl.class;
215    let class_props = class.body;
216    let mut methods_act: Vec<MethodAct> = vec![];
217    for class_prop in class_props {
218        if class_prop.is_method() {
219            let method = class_prop.method().unwrap();
220            let method_key = method.key;
221            let mut method_name: String = "unknownName".to_string();
222            if method_key.is_ident() {
223                let method_key_ident = method_key.ident().unwrap();
224                method_name = method_key_ident.sym.to_string();
225            }
226            if method.function.body.is_some() {
227                let function_act = get_function_act(method_name, method.function);
228                let method_act: MethodAct = MethodAct {
229                    function: function_act,
230                };
231                methods_act.push(method_act)
232            }
233        } else if class_prop.is_constructor() {
234            let constructor = class_prop.constructor().unwrap();
235            if constructor.params.is_empty() {
236                continue;
237            }
238            if constructor.body.is_some() {
239                let constructor_body = constructor.body.unwrap();
240                let constructor_body_start = constructor_body.span.lo.0;
241                let mut params: Vec<Param> = vec![];
242                for param in constructor.params {
243                    if param.is_param() {
244                        params.push(param.param().unwrap())
245                    }
246                }
247                let constructor_act: MethodAct = MethodAct {
248                    function: FunctionAct {
249                        name: "constructor".to_string(),
250                        params: get_function_params(get_pat_from_param(params)),
251                        body_start: constructor_body_start,
252                    },
253                };
254                methods_act.push(constructor_act)
255            }
256        }
257    }
258    let class_act: ClassAct = ClassAct {
259        name: class_name,
260        methods: methods_act,
261    };
262    class_act
263}
264
265pub fn get_pat_from_param(params: Vec<Param>) -> Vec<Pat> {
266    let mut pats: Vec<Pat> = vec![];
267    for param in params {
268        pats.push(param.pat)
269    }
270    pats
271}
272
273pub fn get_class_patches(class_act: ClassAct, file_path: &Path) -> Vec<PatchAct> {
274    let mut patches: Vec<PatchAct> = vec![];
275    patches.extend(get_methods_patches(class_act, file_path));
276    patches
277}
278
279fn get_methods_patches(class_act: ClassAct, file_path: &Path) -> Vec<PatchAct> {
280    let mut patches: Vec<PatchAct> = vec![];
281    for method in class_act.methods {
282        patches.extend(get_function_params_patches(
283            method.function.params,
284            method.function.body_start,
285            method.function.name,
286            file_path.to_str().unwrap().to_string(),
287        ));
288    }
289    patches
290}
291
292pub fn process_class_decl(class_decl: ClassDecl, file_path: &Path) -> Vec<PatchAct> {
293    let class_act = get_class_act(class_decl);
294    let class_patches: Vec<PatchAct> = get_class_patches(class_act, file_path);
295    class_patches
296}
297
298pub fn process_decl(decl: Decl, file_path: &Path) -> Vec<PatchAct> {
299    if decl.is_fn_decl() {
300        let fn_decl = decl.fn_decl().unwrap();
301        process_function_decl(fn_decl, file_path)
302    } else if decl.is_class() {
303        let class_decl = decl.class().unwrap();
304        return process_class_decl(class_decl, file_path);
305    } else if decl.is_var() {
306        return process_var_decl(decl.var().unwrap(), file_path);
307    } else {
308        return vec![];
309    }
310}
311
312pub fn process_module_items(
313    module_items: Vec<ModuleItem>,
314    file_path: &Path,
315) -> Result<Vec<PatchAct>, String> {
316    let mut patches: Vec<PatchAct> = vec![];
317    for item in module_items {
318        if item.is_stmt() {
319            let stmt = item.stmt().unwrap();
320            if stmt.is_decl() {
321                let decl = stmt.decl().unwrap();
322                patches.extend(process_decl(decl, file_path));
323            } else if stmt.is_expr() {
324                let expr = stmt.expr().unwrap().expr;
325                if expr.is_fn_expr() {
326                    let fn_expr = expr.fn_expr().unwrap();
327                    patches.extend(process_function_expr(fn_expr, file_path));
328                } else if expr.is_arrow() {
329                    let arrow_expr = expr.arrow().unwrap();
330                    patches.extend(process_function_arrow(arrow_expr, file_path));
331                }
332            }
333        } else if item.is_module_decl() {
334            let module_decl = item.module_decl().unwrap();
335            if module_decl.is_export_decl() {
336                let export_decl = module_decl.export_decl().unwrap();
337                let decl = export_decl.decl;
338                patches.extend(process_decl(decl, file_path));
339            }
340        }
341    }
342    Ok(patches)
343}
344
345pub fn process_file(file_path: PathBuf) -> Result<(), String> {
346    println!("analysing file {}", file_path.to_str().unwrap());
347    let cm: Lrc<SourceMap> = Default::default();
348
349    let fm = cm.load_file(&file_path).expect("failed to load ts file");
350    let lexer = Lexer::new(
351        Syntax::Typescript(TsConfig {
352            decorators: true,
353            tsx: false,
354            disallow_ambiguous_jsx_like: true,
355            no_early_errors: true,
356            dts: false,
357        }),
358        EsVersion::EsNext,
359        StringInput::from(&*fm),
360        None,
361    );
362
363    let mut parser = Parser::new_from(lexer);
364
365    let module_wrap = parser.parse_typescript_module();
366    let mut patches: Vec<PatchAct> = vec![];
367    if module_wrap.is_ok() {
368        let module = module_wrap.unwrap();
369        let module_item_wrap = process_module_items(module.body, &file_path);
370        if module_item_wrap.is_ok() {
371            patches = module_item_wrap.unwrap();
372        } else if module_item_wrap.is_err() {
373            println!("error processing file {}", file_path.to_str().unwrap());
374            let err = module_item_wrap.err().unwrap();
375            println!("{:?}", err);
376        }
377    } else if module_wrap.is_err() {
378        println!("error parsing file {}", file_path.to_str().unwrap());
379        let err = module_wrap.err().unwrap();
380        println!("{:?}", err.into_kind());
381    }
382
383    apply_patches(patches, file_path).unwrap();
384
385    Ok(())
386}