cadi_scraper/
transformer.rs1use crate::error::Result;
2use crate::parser::CodeAst;
3
4pub struct Transformer;
6
7#[derive(Debug, Clone)]
8pub struct TransformResult {
9 pub original_language: String,
10 pub transformed_language: Option<String>,
11 pub transformations_applied: Vec<String>,
12 pub optimizations: Vec<String>,
13 pub warnings: Vec<String>,
14}
15
16impl Transformer {
17 pub fn transform(ast: &CodeAst, target_language: Option<&str>) -> Result<TransformResult> {
19 let mut result = TransformResult {
20 original_language: ast.language.clone(),
21 transformed_language: target_language.map(String::from),
22 transformations_applied: Vec::new(),
23 optimizations: Vec::new(),
24 warnings: Vec::new(),
25 };
26
27 match ast.language.as_str() {
29 "rust" => {
30 Self::transform_rust(ast, &mut result)?;
31 }
32 "typescript" => {
33 Self::transform_typescript(ast, &mut result)?;
34 }
35 "python" => {
36 Self::transform_python(ast, &mut result)?;
37 }
38 _ => {
39 result.transformations_applied
40 .push(format!("Basic transformation for {}", ast.language));
41 }
42 }
43
44 Ok(result)
45 }
46
47 fn transform_rust(ast: &CodeAst, result: &mut TransformResult) -> Result<()> {
48 if !ast.functions.is_empty()
50 && ast.functions.iter().any(|f| f.contains("_async")) {
51 result.optimizations.push(
52 "Consider using tokio runtime for async code optimization".to_string(),
53 );
54 }
55
56 if ast.traits.len() > 5 {
57 result.optimizations.push(
58 "High trait count detected - consider trait composition".to_string(),
59 );
60 }
61
62 result
63 .transformations_applied
64 .push("Applied Rust-specific AST transformation".to_string());
65
66 Ok(())
67 }
68
69 fn transform_typescript(ast: &CodeAst, result: &mut TransformResult) -> Result<()> {
70 if ast.interfaces.is_empty() && !ast.classes.is_empty() {
72 result
73 .warnings
74 .push("No interfaces defined - consider using interfaces for better type safety"
75 .to_string());
76 }
77
78 if ast.functions.len() > ast.classes.len() {
79 result.optimizations.push(
80 "Consider using more OOP patterns with classes".to_string(),
81 );
82 }
83
84 result
85 .transformations_applied
86 .push("Applied TypeScript-specific AST transformation".to_string());
87
88 Ok(())
89 }
90
91 fn transform_python(ast: &CodeAst, result: &mut TransformResult) -> Result<()> {
92 if ast.classes.is_empty() && !ast.functions.is_empty() {
94 result.warnings.push(
95 "Functional style detected - consider using classes for better organization"
96 .to_string(),
97 );
98 }
99
100 result
101 .transformations_applied
102 .push("Applied Python-specific AST transformation".to_string());
103
104 Ok(())
105 }
106
107 pub fn extract_features(ast: &CodeAst) -> Vec<String> {
109 let mut features = Vec::new();
110
111 if !ast.functions.is_empty() {
113 features.push(format!("defines_{}_{}_functions", ast.language, ast.functions.len()));
114 }
115
116 if !ast.classes.is_empty() {
117 features.push(format!("defines_{}_{}_classes", ast.language, ast.classes.len()));
118 }
119
120 if !ast.traits.is_empty() {
121 features.push(format!("uses_{}_{}_traits", ast.language, ast.traits.len()));
122 }
123
124 if !ast.imports.is_empty() {
125 features.push(format!("has_{}_{}_dependencies", ast.language, ast.imports.len()));
126 }
127
128 features
129 }
130
131 pub fn compute_quality_metrics(ast: &CodeAst) -> CodeQualityMetrics {
133 CodeQualityMetrics {
134 cyclomatic_complexity_estimate: estimate_complexity(ast),
135 api_surface_size: ast.functions.len() + ast.classes.len() + ast.traits.len(),
136 dependency_count: ast.imports.len(),
137 modularity_score: compute_modularity(ast),
138 }
139 }
140}
141
142#[derive(Debug, Clone)]
143pub struct CodeQualityMetrics {
144 pub cyclomatic_complexity_estimate: f32,
145 pub api_surface_size: usize,
146 pub dependency_count: usize,
147 pub modularity_score: f32,
148}
149
150fn estimate_complexity(ast: &CodeAst) -> f32 {
151 let func_count = ast.functions.len() as f32;
153 let class_count = ast.classes.len() as f32;
154 let trait_count = ast.traits.len() as f32;
155
156 (func_count + (class_count * 2.0) + (trait_count * 1.5)).min(100.0)
157}
158
159fn compute_modularity(ast: &CodeAst) -> f32 {
160 let total_elements = ast.functions.len() + ast.classes.len() + ast.traits.len();
162
163 if total_elements == 0 {
164 return 0.0;
165 }
166
167 let class_trait_ratio = (ast.classes.len() + ast.traits.len()) as f32 / total_elements as f32;
169 (class_trait_ratio * 100.0).min(100.0)
170}