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 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 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 }
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(¶m);
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}