Skip to main content

morph_cli/recipes/express_to_fastify/
analysis.rs

1#![allow(clippy::all, unused)]
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Default)]
5#[allow(unused)]
6pub struct MigrationAnalysis {
7    pub routes: Vec<RouteInfo>,
8    pub express_apps: Vec<usize>,
9    pub middleware_count: usize,
10    pub has_body_parser: bool,
11    pub has_auth_middleware: bool,
12    pub has_error_handler: bool,
13    pub async_handlers: usize,
14    pub complexity: ComplexityLevel,
15    pub risky_patterns: Vec<RiskyPattern>,
16    pub suggested_recipes: Vec<String>,
17    pub migration_blockers: Vec<String>,
18    pub unsupported_apis: Vec<String>,
19    pub estimated_difficulty: u8,
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub enum ComplexityLevel {
24    Simple,
25    Moderate,
26    Complex,
27    Unsupported,
28}
29
30impl Default for ComplexityLevel {
31    fn default() -> Self {
32        Self::Simple
33    }
34}
35
36#[derive(Debug, Clone)]
37#[allow(unused)]
38pub struct RouteInfo {
39    pub method: String,
40    pub path: String,
41    pub handler_type: String,
42    pub middleware_count: usize,
43    pub estimated_complexity: u8,
44}
45
46#[derive(Debug, Clone)]
47#[allow(unused)]
48pub struct RiskyPattern {
49    pub pattern: String,
50    pub location: String,
51    pub severity: u8,
52    pub description: String,
53}
54
55impl MigrationAnalysis {
56    pub fn classify_complexity(&mut self) {
57        let route_count = self.routes.len();
58        let middleware = self.middleware_count;
59        let async_count = self.async_handlers;
60        let risky = self.risky_patterns.len();
61
62        if risky > 3 || self.migration_blockers.len() > 2 {
63            self.complexity = ComplexityLevel::Unsupported;
64        } else if risky > 1 || middleware > 5 || route_count > 20 {
65            self.complexity = ComplexityLevel::Complex;
66        } else if middleware > 2 || route_count > 5 || async_count > 2 {
67            self.complexity = ComplexityLevel::Moderate;
68        } else {
69            self.complexity = ComplexityLevel::Simple;
70        }
71    }
72
73    pub fn detect_risky_patterns(&mut self) {
74        if self.has_error_handler {
75            self.risky_patterns.push(RiskyPattern {
76                pattern: "custom_error_handler".to_string(),
77                location: "middleware".to_string(),
78                severity: 60,
79                description: "Custom error middleware may need manual migration".to_string(),
80            });
81        }
82
83        if self.has_auth_middleware {
84            self.risky_patterns.push(RiskyPattern {
85                pattern: "auth_middleware".to_string(),
86                location: "middleware".to_string(),
87                severity: 50,
88                description: "Auth middleware should be reviewed for Fastify plugin compatibility"
89                    .to_string(),
90            });
91        }
92
93        if self.async_handlers > self.routes.len() / 2 {
94            self.risky_patterns.push(RiskyPattern {
95                pattern: "high_async_ratio".to_string(),
96                location: "routes".to_string(),
97                severity: 40,
98                description: "High async handler ratio - ensure proper error handling".to_string(),
99            });
100        }
101    }
102
103    pub fn suggest_recipes(&mut self) {
104        match self.complexity {
105            ComplexityLevel::Simple => {
106                self.suggested_recipes
107                    .push("express-to-fastify:basic".to_string());
108            }
109            ComplexityLevel::Moderate => {
110                self.suggested_recipes
111                    .push("express-to-fastify:basic".to_string());
112                self.suggested_recipes
113                    .push("express-to-fastify:middleware".to_string());
114            }
115            ComplexityLevel::Complex | ComplexityLevel::Unsupported => {
116                self.suggested_recipes
117                    .push("express-to-fastify:review-required".to_string());
118                self.migration_blockers
119                    .push("Manual review required for complex middleware".to_string());
120            }
121        }
122
123        if self.has_body_parser {
124            self.suggested_recipes
125                .push("fastify:@fastify/json".to_string());
126        }
127    }
128
129    pub fn unsupported_api(&mut self, api: &str) {
130        if !self.unsupported_apis.contains(&api.to_string()) {
131            self.unsupported_apis.push(api.to_string());
132        }
133    }
134
135    pub fn add_blocker(&mut self, blocker: &str) {
136        if !self.migration_blockers.contains(&blocker.to_string()) {
137            self.migration_blockers.push(blocker.to_string());
138        }
139    }
140
141    pub fn statistics(&self) -> AnalysisStats {
142        AnalysisStats {
143            total_routes: self.routes.len(),
144            async_routes: self.async_handlers,
145            sync_routes: self.routes.len() - self.async_handlers,
146            middleware: self.middleware_count,
147            estimated_lines: self.routes.len() * 10,
148            complexity_score: self.estimated_difficulty,
149        }
150    }
151}
152
153#[derive(Debug)]
154pub struct AnalysisStats {
155    pub total_routes: usize,
156    pub async_routes: usize,
157    pub sync_routes: usize,
158    pub middleware: usize,
159    pub estimated_lines: usize,
160    pub complexity_score: u8,
161}
162
163impl AnalysisStats {
164    pub fn print_summary(&self) {
165        println!();
166        println!(
167            "  Routes: {} (async: {}, sync: {})",
168            self.total_routes, self.async_routes, self.sync_routes
169        );
170        println!("  Middleware: {}", self.middleware);
171        println!("  Estimated complexity: {}/100", self.complexity_score);
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178
179    #[test]
180    fn test_simple_classification() {
181        let mut analysis = MigrationAnalysis::default();
182        analysis.routes.push(RouteInfo {
183            method: "get".to_string(),
184            path: "/".to_string(),
185            handler_type: "sync".to_string(),
186            middleware_count: 0,
187            estimated_complexity: 1,
188        });
189        analysis.classify_complexity();
190        assert_eq!(analysis.complexity, ComplexityLevel::Simple);
191    }
192
193    #[test]
194    fn test_complex_classification() {
195        let mut analysis = MigrationAnalysis::default();
196        analysis.middleware_count = 10;
197        analysis.classify_complexity();
198        assert_eq!(analysis.complexity, ComplexityLevel::Complex);
199    }
200
201    #[test]
202    fn test_statistics() {
203        let mut analysis = MigrationAnalysis::default();
204        analysis.routes.push(RouteInfo {
205            method: "get".to_string(),
206            path: "/".to_string(),
207            handler_type: "async".to_string(),
208            middleware_count: 2,
209            estimated_complexity: 1,
210        });
211        analysis.async_handlers = 1;
212        analysis.middleware_count = 2;
213        let stats = analysis.statistics();
214        assert_eq!(stats.total_routes, 1);
215        assert_eq!(stats.async_routes, 1);
216    }
217}