ricecoder_research/
dependency_analyzer.rs1use crate::error::ResearchError;
17use crate::models::{Dependency, Language};
18use std::path::Path;
19use tracing::debug;
20
21mod dart_parser;
22mod dotnet_parser;
23mod go_parser;
24mod java_parser;
25mod kotlin_parser;
26mod nodejs_parser;
27mod php_parser;
28mod python_parser;
29mod ruby_parser;
30mod rust_parser;
31mod swift_parser;
32mod version_analyzer;
33
34pub use dart_parser::DartParser;
35pub use dotnet_parser::DotNetParser;
36pub use go_parser::GoParser;
37pub use java_parser::JavaParser;
38pub use kotlin_parser::KotlinParser;
39pub use nodejs_parser::NodeJsParser;
40pub use php_parser::PhpParser;
41pub use python_parser::PythonParser;
42pub use ruby_parser::RubyParser;
43pub use rust_parser::RustParser;
44pub use swift_parser::SwiftParser;
45pub use version_analyzer::VersionAnalyzer;
46
47#[derive(Debug)]
49pub struct DependencyAnalyzer {
50 rust_parser: RustParser,
51 nodejs_parser: NodeJsParser,
52 python_parser: PythonParser,
53 go_parser: GoParser,
54 java_parser: JavaParser,
55 kotlin_parser: KotlinParser,
56 dotnet_parser: DotNetParser,
57 php_parser: PhpParser,
58 ruby_parser: RubyParser,
59 swift_parser: SwiftParser,
60 dart_parser: DartParser,
61 version_analyzer: VersionAnalyzer,
62}
63
64impl DependencyAnalyzer {
65 pub fn new() -> Self {
67 DependencyAnalyzer {
68 rust_parser: RustParser::new(),
69 nodejs_parser: NodeJsParser::new(),
70 python_parser: PythonParser::new(),
71 go_parser: GoParser::new(),
72 java_parser: JavaParser::new(),
73 kotlin_parser: KotlinParser::new(),
74 dotnet_parser: DotNetParser::new(),
75 php_parser: PhpParser::new(),
76 ruby_parser: RubyParser::new(),
77 swift_parser: SwiftParser::new(),
78 dart_parser: DartParser::new(),
79 version_analyzer: VersionAnalyzer::new(),
80 }
81 }
82
83 pub fn analyze(&self, root: &Path) -> Result<Vec<Dependency>, ResearchError> {
88 debug!("Analyzing dependencies in {:?}", root);
89
90 let mut all_dependencies = Vec::new();
91
92 if let Ok(deps) = self.rust_parser.parse(root) {
94 debug!("Found {} Rust dependencies", deps.len());
95 all_dependencies.extend(deps);
96 }
97
98 if let Ok(deps) = self.nodejs_parser.parse(root) {
99 debug!("Found {} Node.js dependencies", deps.len());
100 all_dependencies.extend(deps);
101 }
102
103 if let Ok(deps) = self.python_parser.parse(root) {
104 debug!("Found {} Python dependencies", deps.len());
105 all_dependencies.extend(deps);
106 }
107
108 if let Ok(deps) = self.go_parser.parse(root) {
109 debug!("Found {} Go dependencies", deps.len());
110 all_dependencies.extend(deps);
111 }
112
113 if let Ok(deps) = self.java_parser.parse(root) {
114 debug!("Found {} Java dependencies", deps.len());
115 all_dependencies.extend(deps);
116 }
117
118 if let Ok(deps) = self.kotlin_parser.parse(root) {
119 debug!("Found {} Kotlin dependencies", deps.len());
120 all_dependencies.extend(deps);
121 }
122
123 if let Ok(deps) = self.dotnet_parser.parse(root) {
124 debug!("Found {} .NET dependencies", deps.len());
125 all_dependencies.extend(deps);
126 }
127
128 if let Ok(deps) = self.php_parser.parse(root) {
129 debug!("Found {} PHP dependencies", deps.len());
130 all_dependencies.extend(deps);
131 }
132
133 if let Ok(deps) = self.ruby_parser.parse(root) {
134 debug!("Found {} Ruby dependencies", deps.len());
135 all_dependencies.extend(deps);
136 }
137
138 if let Ok(deps) = self.swift_parser.parse(root) {
139 debug!("Found {} Swift dependencies", deps.len());
140 all_dependencies.extend(deps);
141 }
142
143 if let Ok(deps) = self.dart_parser.parse(root) {
144 debug!("Found {} Dart/Flutter dependencies", deps.len());
145 all_dependencies.extend(deps);
146 }
147
148 all_dependencies
150 .sort_by(|a, b| a.name.cmp(&b.name).then_with(|| a.version.cmp(&b.version)));
151 all_dependencies.dedup_by(|a, b| a.name == b.name && a.version == b.version);
152
153 Ok(all_dependencies)
154 }
155
156 pub fn detect_languages(&self, root: &Path) -> Result<Vec<Language>, ResearchError> {
158 let mut languages = Vec::new();
159
160 if self.rust_parser.has_manifest(root) {
161 languages.push(Language::Rust);
162 }
163
164 if self.nodejs_parser.has_manifest(root) {
165 languages.push(Language::TypeScript);
166 }
167
168 if self.python_parser.has_manifest(root) {
169 languages.push(Language::Python);
170 }
171
172 if self.go_parser.has_manifest(root) {
173 languages.push(Language::Go);
174 }
175
176 if self.java_parser.has_manifest(root) {
177 languages.push(Language::Java);
178 }
179
180 if self.kotlin_parser.has_manifest(root) {
181 languages.push(Language::Kotlin);
182 }
183
184 if self.dotnet_parser.has_manifest(root) {
185 languages.push(Language::CSharp);
186 }
187
188 if self.php_parser.has_manifest(root) {
189 languages.push(Language::Php);
190 }
191
192 if self.ruby_parser.has_manifest(root) {
193 languages.push(Language::Ruby);
194 }
195
196 if self.swift_parser.has_manifest(root) {
197 languages.push(Language::Swift);
198 }
199
200 if self.dart_parser.has_manifest(root) {
201 languages.push(Language::Dart);
202 }
203
204 Ok(languages)
205 }
206
207 pub fn analyze_version_conflicts(&self, dependencies: &[Dependency]) -> Vec<VersionConflict> {
209 self.version_analyzer.find_conflicts(dependencies)
210 }
211
212 pub fn suggest_updates(&self, dependencies: &[Dependency]) -> Vec<VersionUpdate> {
214 self.version_analyzer.suggest_updates(dependencies)
215 }
216}
217
218impl Default for DependencyAnalyzer {
219 fn default() -> Self {
220 Self::new()
221 }
222}
223
224#[derive(Debug, Clone)]
226pub struct VersionConflict {
227 pub dependency_name: String,
229 pub versions: Vec<String>,
231 pub description: String,
233}
234
235#[derive(Debug, Clone)]
237pub struct VersionUpdate {
238 pub dependency_name: String,
240 pub current_version: String,
242 pub suggested_version: String,
244 pub reason: String,
246}
247
248pub trait DependencyParser: Send + Sync {
250 fn parse(&self, root: &Path) -> Result<Vec<Dependency>, ResearchError>;
252
253 fn has_manifest(&self, root: &Path) -> bool;
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260
261 #[test]
262 fn test_dependency_analyzer_creation() {
263 let analyzer = DependencyAnalyzer::new();
264 assert!(true);
266 }
267
268 #[test]
269 fn test_dependency_analyzer_default() {
270 let analyzer = DependencyAnalyzer::default();
271 assert!(true);
273 }
274}