morph_cli/recipes/express_to_fastify/
analysis.rs1#![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}