From 8ba35ae2d5f8a8f1a76ea365d7461d8a79f5015b Mon Sep 17 00:00:00 2001 From: Alex Holmberg Date: Sat, 7 Jun 2025 00:01:45 +0200 Subject: [PATCH 1/2] feat: Improved Framework modularity for languages and expanded Services/Tools and Framework options --- src/analyzer/display.rs | 59 +- src/analyzer/framework_detector.rs | 2220 ++----------------------- src/analyzer/frameworks/go.rs | 256 +++ src/analyzer/frameworks/java.rs | 1062 ++++++++++++ src/analyzer/frameworks/javascript.rs | 853 ++++++++++ src/analyzer/frameworks/mod.rs | 214 +++ src/analyzer/frameworks/python.rs | 818 +++++++++ src/analyzer/frameworks/rust.rs | 244 +++ src/analyzer/mod.rs | 1 + 9 files changed, 3595 insertions(+), 2132 deletions(-) create mode 100644 src/analyzer/frameworks/go.rs create mode 100644 src/analyzer/frameworks/java.rs create mode 100644 src/analyzer/frameworks/javascript.rs create mode 100644 src/analyzer/frameworks/mod.rs create mode 100644 src/analyzer/frameworks/python.rs create mode 100644 src/analyzer/frameworks/rust.rs diff --git a/src/analyzer/display.rs b/src/analyzer/display.rs index b6b02f26..605d4258 100644 --- a/src/analyzer/display.rs +++ b/src/analyzer/display.rs @@ -234,40 +234,40 @@ impl BoxDrawer { if total_needed <= available_space { // Everything fits - right-align the value - let padding_needed = available_space - label_width - value_width; + let padding_needed = available_space.saturating_sub(label_width).saturating_sub(value_width); format!("{}{}{}", formatted_label, " ".repeat(padding_needed), formatted_value) } else { // Need to truncate value let max_value_width = available_space.saturating_sub(label_width + min_space_between); let truncated_value = truncate_to_width(&formatted_value, max_value_width); let truncated_value_width = visual_width(&truncated_value); - let padding_needed = available_space - label_width - truncated_value_width; + let padding_needed = available_space.saturating_sub(label_width).saturating_sub(truncated_value_width); format!("{}{}{}", formatted_label, " ".repeat(padding_needed), truncated_value) } } else if !line.value.is_empty() { // Value only - left-align it (for descriptions, etc.) let value_width = visual_width(&formatted_value); if value_width <= content_width { - let padding_needed = content_width - value_width; + let padding_needed = content_width.saturating_sub(value_width); format!("{}{}", formatted_value, " ".repeat(padding_needed)) } else { // Truncate and ensure it fills exactly content_width let truncated = truncate_to_width(&formatted_value, content_width); let actual_width = visual_width(&truncated); - let padding_needed = content_width - actual_width; + let padding_needed = content_width.saturating_sub(actual_width); format!("{}{}", truncated, " ".repeat(padding_needed)) } } else if !line.label.is_empty() { // Label only - left-align it let label_width = visual_width(&formatted_label); if label_width <= content_width { - let padding_needed = content_width - label_width; + let padding_needed = content_width.saturating_sub(label_width); format!("{}{}", formatted_label, " ".repeat(padding_needed)) } else { // Truncate and ensure it fills exactly content_width let truncated = truncate_to_width(&formatted_label, content_width); let actual_width = visual_width(&truncated); - let padding_needed = content_width - actual_width; + let padding_needed = content_width.saturating_sub(actual_width); format!("{}{}", truncated, " ".repeat(padding_needed)) } } else { @@ -285,7 +285,7 @@ impl BoxDrawer { content } else { // Add padding to reach exact width for non-table content - let padding_needed = content_width - actual_content_width; + let padding_needed = content_width.saturating_sub(actual_content_width); format!("{}{}", content, " ".repeat(padding_needed)) } } else { @@ -624,10 +624,10 @@ fn display_single_project_matrix(analysis: &MonorepoAnalysis) { box_drawer.add_line("Name:", &project.name.yellow(), true); box_drawer.add_line("Type:", &format_project_category(&project.project_category).green(), true); - // Languages with confidence + // Languages if !project.analysis.languages.is_empty() { let lang_info = project.analysis.languages.iter() - .map(|l| format!("{} ({:.0}%)", l.name, l.confidence * 100.0)) + .map(|l| l.name.clone()) .collect::>() .join(", "); box_drawer.add_line("Languages:", &lang_info.blue(), true); @@ -669,10 +669,7 @@ fn add_technologies_to_drawer(technologies: &[DetectedTechnology], box_drawer: & // Display primary technology first if let Some(primary) = technologies.iter().find(|t| t.is_primary) { - let primary_info = format!("{} {}", - primary.name.bright_yellow().bold(), - format!("({:.0}%)", primary.confidence * 100.0).dimmed() - ); + let primary_info = primary.name.bright_yellow().bold().to_string(); box_drawer.add_line("Primary Stack:", &primary_info, true); } @@ -687,7 +684,7 @@ fn add_technologies_to_drawer(technologies: &[DetectedTechnology], box_drawer: & for (category, label) in &categories { if let Some(techs) = by_category.get(category) { let tech_names = techs.iter() - .map(|t| format!("{} ({:.0}%)", t.name, t.confidence * 100.0)) + .map(|t| t.name.clone()) .collect::>() .join(", "); @@ -698,16 +695,40 @@ fn add_technologies_to_drawer(technologies: &[DetectedTechnology], box_drawer: & } } - // Handle Library category separately since it's parameterized + // Handle Library category separately since it's parameterized - use vertical layout for many items + let mut all_libraries: Vec<&DetectedTechnology> = Vec::new(); for (cat, techs) in &by_category { if matches!(cat, TechnologyCategory::Library(_)) { - let tech_names = techs.iter() - .map(|t| format!("{} ({:.0}%)", t.name, t.confidence * 100.0)) + all_libraries.extend(techs.iter().copied()); + } + } + + if !all_libraries.is_empty() { + // Sort libraries by confidence for better display + all_libraries.sort_by(|a, b| b.confidence.partial_cmp(&a.confidence).unwrap_or(std::cmp::Ordering::Equal)); + + if all_libraries.len() <= 3 { + // For few libraries, keep horizontal layout + let tech_names = all_libraries.iter() + .map(|t| t.name.clone()) .collect::>() .join(", "); + box_drawer.add_line("Libraries:", &tech_names.magenta(), true); + } else { + // For many libraries, use vertical layout with multiple rows + box_drawer.add_line("Libraries:", "", true); - if !tech_names.is_empty() { - box_drawer.add_line("Libraries:", &tech_names.magenta(), true); + // Group libraries into rows of 3-4 items each + let items_per_row = 3; + for chunk in all_libraries.chunks(items_per_row) { + let row_items = chunk.iter() + .map(|t| t.name.clone()) + .collect::>() + .join(", "); + + // Add indented row + let indented_row = format!(" {}", row_items); + box_drawer.add_value_only(&indented_row.magenta()); } } } diff --git a/src/analyzer/framework_detector.rs b/src/analyzer/framework_detector.rs index 694316e6..32193f14 100644 --- a/src/analyzer/framework_detector.rs +++ b/src/analyzer/framework_detector.rs @@ -1,24 +1,7 @@ -use crate::analyzer::{AnalysisConfig, DetectedTechnology, DetectedLanguage, TechnologyCategory, LibraryType}; +use crate::analyzer::{AnalysisConfig, DetectedTechnology, DetectedLanguage}; +use crate::analyzer::frameworks::*; use crate::error::Result; -// Remove unused import use std::path::Path; -use std::collections::HashMap; - -/// Technology detection rules with proper classification and relationships -struct TechnologyRule { - name: String, - category: TechnologyCategory, - confidence: f32, - dependency_patterns: Vec, - /// Dependencies this technology requires (e.g., Next.js requires React) - requires: Vec, - /// Technologies that conflict with this one (mutually exclusive) - conflicts_with: Vec, - /// Whether this technology typically drives the architecture - is_primary_indicator: bool, - /// Alternative names for this technology - alternative_names: Vec, -} /// Detects technologies (frameworks, libraries, tools) with proper classification pub fn detect_frameworks( @@ -28,23 +11,30 @@ pub fn detect_frameworks( ) -> Result> { let mut all_technologies = Vec::new(); + // Initialize language-specific detectors + let rust_detector = rust::RustFrameworkDetector; + let js_detector = javascript::JavaScriptFrameworkDetector; + let python_detector = python::PythonFrameworkDetector; + let go_detector = go::GoFrameworkDetector; + let java_detector = java::JavaFrameworkDetector; + for language in languages { let lang_technologies = match language.name.as_str() { - "Rust" => detect_rust_technologies(language), - "JavaScript" | "TypeScript" | "JavaScript/TypeScript" => detect_js_technologies(language), - "Python" => detect_python_technologies(language), - "Go" => detect_go_technologies(language), - "Java" | "Kotlin" | "Java/Kotlin" => detect_jvm_technologies(language), + "Rust" => rust_detector.detect_frameworks(language)?, + "JavaScript" | "TypeScript" | "JavaScript/TypeScript" => js_detector.detect_frameworks(language)?, + "Python" => python_detector.detect_frameworks(language)?, + "Go" => go_detector.detect_frameworks(language)?, + "Java" | "Kotlin" | "Java/Kotlin" => java_detector.detect_frameworks(language)?, _ => Vec::new(), }; all_technologies.extend(lang_technologies); } // Apply exclusivity rules and resolve conflicts - let resolved_technologies = resolve_technology_conflicts(all_technologies); + let resolved_technologies = FrameworkDetectionUtils::resolve_technology_conflicts(all_technologies); // Mark primary technologies - let final_technologies = mark_primary_technologies(resolved_technologies); + let final_technologies = FrameworkDetectionUtils::mark_primary_technologies(resolved_technologies); // Sort by confidence and remove exact duplicates let mut result = final_technologies; @@ -54,1926 +44,10 @@ pub fn detect_frameworks( Ok(result) } -/// Detect Rust technologies with proper classification -fn detect_rust_technologies(language: &DetectedLanguage) -> Vec { - let rules = get_rust_technology_rules(); - - // Combine main and dev dependencies for comprehensive detection - let all_deps: Vec = language.main_dependencies.iter() - .chain(language.dev_dependencies.iter()) - .cloned() - .collect(); - - detect_technologies_by_dependencies(&rules, &all_deps, language.confidence) -} - -/// Detect JavaScript/TypeScript technologies with proper classification -fn detect_js_technologies(language: &DetectedLanguage) -> Vec { - let rules = get_js_technology_rules(); - - // Combine main and dev dependencies for comprehensive detection - let all_deps: Vec = language.main_dependencies.iter() - .chain(language.dev_dependencies.iter()) - .cloned() - .collect(); - - let mut technologies = detect_technologies_by_dependencies(&rules, &all_deps, language.confidence); - - // Enhanced detection: analyze actual source files for usage patterns - if let Some(enhanced_techs) = detect_technologies_from_source_files(language, &rules) { - // Merge with dependency-based detection, preferring higher confidence scores - for enhanced_tech in enhanced_techs { - if let Some(existing) = technologies.iter_mut().find(|t| t.name == enhanced_tech.name) { - // Use higher confidence between dependency and source file analysis - if enhanced_tech.confidence > existing.confidence { - existing.confidence = enhanced_tech.confidence; - } - } else { - // Add new technology found in source files - technologies.push(enhanced_tech); - } - } - } - - technologies -} - -/// Detect Python technologies with proper classification -fn detect_python_technologies(language: &DetectedLanguage) -> Vec { - let rules = get_python_technology_rules(); - - // Combine main and dev dependencies for comprehensive detection - let all_deps: Vec = language.main_dependencies.iter() - .chain(language.dev_dependencies.iter()) - .cloned() - .collect(); - - detect_technologies_by_dependencies(&rules, &all_deps, language.confidence) -} - -/// Detect Go technologies with proper classification -fn detect_go_technologies(language: &DetectedLanguage) -> Vec { - let rules = get_go_technology_rules(); - - // Combine main and dev dependencies for comprehensive detection - let all_deps: Vec = language.main_dependencies.iter() - .chain(language.dev_dependencies.iter()) - .cloned() - .collect(); - - detect_technologies_by_dependencies(&rules, &all_deps, language.confidence) -} - -/// Detect JVM technologies with proper classification -fn detect_jvm_technologies(language: &DetectedLanguage) -> Vec { - let rules = get_jvm_technology_rules(); - - // Combine main and dev dependencies for comprehensive detection - let all_deps: Vec = language.main_dependencies.iter() - .chain(language.dev_dependencies.iter()) - .cloned() - .collect(); - - detect_technologies_by_dependencies(&rules, &all_deps, language.confidence) -} - -/// Generic technology detection based on dependency patterns -fn detect_technologies_by_dependencies( - rules: &[TechnologyRule], - dependencies: &[String], - base_confidence: f32, -) -> Vec { - let mut technologies = Vec::new(); - - // Debug logging for Tanstack Start detection - let tanstack_deps: Vec<_> = dependencies.iter() - .filter(|dep| dep.contains("tanstack") || dep.contains("vinxi")) - .collect(); - if !tanstack_deps.is_empty() { - log::debug!("Found potential Tanstack dependencies: {:?}", tanstack_deps); - } - - for rule in rules { - let mut matches = 0; - let total_patterns = rule.dependency_patterns.len(); - - if total_patterns == 0 { - continue; - } - - for pattern in &rule.dependency_patterns { - let matching_deps: Vec<_> = dependencies.iter() - .filter(|dep| matches_pattern(dep, pattern)) - .collect(); - - if !matching_deps.is_empty() { - matches += 1; - - // Debug logging for Tanstack Start specifically - if rule.name.contains("Tanstack") { - log::debug!("Tanstack Start: Pattern '{}' matched dependencies: {:?}", pattern, matching_deps); - } - } - } - - // Calculate confidence based on pattern matches and base language confidence - if matches > 0 { - let pattern_confidence = matches as f32 / total_patterns as f32; - let final_confidence = (rule.confidence * pattern_confidence * base_confidence).min(1.0); - - // Debug logging for Tanstack Start detection - if rule.name.contains("Tanstack") { - log::debug!("Tanstack Start detected with {} matches out of {} patterns, confidence: {:.2}", - matches, total_patterns, final_confidence); - } - - technologies.push(DetectedTechnology { - name: rule.name.clone(), - version: None, // TODO: Extract version from dependencies - category: rule.category.clone(), - confidence: final_confidence, - requires: rule.requires.clone(), - conflicts_with: rule.conflicts_with.clone(), - is_primary: rule.is_primary_indicator, - }); - } else if rule.name.contains("Tanstack") { - // Debug logging when Tanstack Start is not detected - log::debug!("Tanstack Start not detected - no patterns matched. Available dependencies: {:?}", - dependencies.iter().take(10).collect::>()); - } - } - - technologies -} - -/// Resolves conflicts between mutually exclusive technologies -fn resolve_technology_conflicts(technologies: Vec) -> Vec { - let mut resolved = Vec::new(); - let mut name_to_tech: HashMap = HashMap::new(); - - // First pass: collect all technologies - for tech in technologies { - if let Some(existing) = name_to_tech.get(&tech.name) { - // Keep the one with higher confidence - if tech.confidence > existing.confidence { - name_to_tech.insert(tech.name.clone(), tech); - } - } else { - name_to_tech.insert(tech.name.clone(), tech); - } - } - - // Second pass: resolve conflicts - let all_techs: Vec<_> = name_to_tech.values().collect(); - let mut excluded_names = std::collections::HashSet::new(); - - for tech in &all_techs { - if excluded_names.contains(&tech.name) { - continue; - } - - // Check for conflicts - for conflict in &tech.conflicts_with { - if let Some(conflicting_tech) = name_to_tech.get(conflict) { - if tech.confidence > conflicting_tech.confidence { - excluded_names.insert(conflict.clone()); - log::info!("Excluding {} (confidence: {}) in favor of {} (confidence: {})", - conflict, conflicting_tech.confidence, tech.name, tech.confidence); - } else { - excluded_names.insert(tech.name.clone()); - log::info!("Excluding {} (confidence: {}) in favor of {} (confidence: {})", - tech.name, tech.confidence, conflict, conflicting_tech.confidence); - break; - } - } - } - } - - // Collect non-excluded technologies - for tech in name_to_tech.into_values() { - if !excluded_names.contains(&tech.name) { - resolved.push(tech); - } - } - - resolved -} - -/// Marks technologies that are primary drivers of the application architecture -fn mark_primary_technologies(mut technologies: Vec) -> Vec { - // Meta-frameworks are always primary - let mut has_meta_framework = false; - for tech in &mut technologies { - if matches!(tech.category, TechnologyCategory::MetaFramework) { - tech.is_primary = true; - has_meta_framework = true; - } - } - - // If no meta-framework, mark the highest confidence backend or frontend framework as primary - if !has_meta_framework { - let mut best_framework: Option = None; - let mut best_confidence = 0.0; - - for (i, tech) in technologies.iter().enumerate() { - if matches!(tech.category, TechnologyCategory::BackendFramework | TechnologyCategory::FrontendFramework) { - if tech.confidence > best_confidence { - best_confidence = tech.confidence; - best_framework = Some(i); - } - } - } - - if let Some(index) = best_framework { - technologies[index].is_primary = true; - } - } - - technologies -} - -/// Check if a dependency matches a pattern (supports wildcards) -fn matches_pattern(dependency: &str, pattern: &str) -> bool { - if pattern.contains('*') { - // Simple wildcard matching - let parts: Vec<&str> = pattern.split('*').collect(); - if parts.len() == 2 { - dependency.starts_with(parts[0]) && dependency.ends_with(parts[1]) - } else { - dependency.contains(&pattern.replace('*', "")) - } - } else { - dependency == pattern || dependency.contains(pattern) - } -} - -/// Enhanced detection that analyzes actual source files for technology usage patterns -fn detect_technologies_from_source_files(language: &DetectedLanguage, rules: &[TechnologyRule]) -> Option> { - use std::fs; - - let mut detected = Vec::new(); - - // Analyze files for usage patterns - for file_path in &language.files { - if let Ok(content) = fs::read_to_string(file_path) { - // Analyze Drizzle ORM usage patterns - if let Some(drizzle_confidence) = analyze_drizzle_usage(&content, file_path) { - detected.push(DetectedTechnology { - name: "Drizzle ORM".to_string(), - version: None, - category: TechnologyCategory::Database, - confidence: drizzle_confidence, - requires: vec![], - conflicts_with: vec![], - is_primary: false, - }); - } - - // Analyze Prisma usage patterns - if let Some(prisma_confidence) = analyze_prisma_usage(&content, file_path) { - detected.push(DetectedTechnology { - name: "Prisma".to_string(), - version: None, - category: TechnologyCategory::Database, - confidence: prisma_confidence, - requires: vec![], - conflicts_with: vec![], - is_primary: false, - }); - } - - // Analyze Encore usage patterns - if let Some(encore_confidence) = analyze_encore_usage(&content, file_path) { - detected.push(DetectedTechnology { - name: "Encore".to_string(), - version: None, - category: TechnologyCategory::BackendFramework, - confidence: encore_confidence, - requires: vec![], - conflicts_with: vec![], - is_primary: true, - }); - } - - // Analyze Tanstack Start usage patterns - if let Some(tanstack_confidence) = analyze_tanstack_start_usage(&content, file_path) { - detected.push(DetectedTechnology { - name: "Tanstack Start".to_string(), - version: None, - category: TechnologyCategory::MetaFramework, - confidence: tanstack_confidence, - requires: vec!["React".to_string()], - conflicts_with: vec!["Next.js".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], - is_primary: true, - }); - } - } - } - - if detected.is_empty() { - None - } else { - Some(detected) - } -} - -/// Analyzes Drizzle ORM usage patterns in source files -fn analyze_drizzle_usage(content: &str, file_path: &std::path::Path) -> Option { - let file_name = file_path.file_name()?.to_string_lossy(); - let mut confidence: f32 = 0.0; - - // High confidence indicators - if content.contains("drizzle-orm") { - confidence += 0.3; - } - - // Schema file patterns (very high confidence) - if file_name.contains("schema") || file_name.contains("db.ts") || file_name.contains("database") { - if content.contains("pgTable") || content.contains("mysqlTable") || content.contains("sqliteTable") { - confidence += 0.4; - } - if content.contains("pgEnum") || content.contains("relations") { - confidence += 0.3; - } - } - - // Drizzle-specific imports - if content.contains("from 'drizzle-orm/pg-core'") || - content.contains("from 'drizzle-orm/mysql-core'") || - content.contains("from 'drizzle-orm/sqlite-core'") { - confidence += 0.3; - } - - // Drizzle query patterns - if content.contains("db.select()") || content.contains("db.insert()") || - content.contains("db.update()") || content.contains("db.delete()") { - confidence += 0.2; - } - - // Configuration patterns - if content.contains("drizzle(") && (content.contains("connectionString") || content.contains("postgres(")) { - confidence += 0.2; - } - - // Migration patterns - if content.contains("drizzle.config") || file_name.contains("migrate") { - confidence += 0.2; - } - - // Prepared statements - if content.contains(".prepare()") && content.contains("drizzle") { - confidence += 0.1; - } - - if confidence > 0.0 { - Some(confidence.min(1.0_f32)) - } else { - None - } -} - -/// Analyzes Prisma usage patterns in source files -fn analyze_prisma_usage(content: &str, file_path: &std::path::Path) -> Option { - let file_name = file_path.file_name()?.to_string_lossy(); - let mut confidence: f32 = 0.0; - let mut has_prisma_import = false; - - // Only detect Prisma if there are actual Prisma-specific imports - if content.contains("@prisma/client") || content.contains("from '@prisma/client'") { - confidence += 0.4; - has_prisma_import = true; - } - - // Prisma schema files (very specific) - if file_name == "schema.prisma" { - if content.contains("model ") || content.contains("generator ") || content.contains("datasource ") { - confidence += 0.6; - has_prisma_import = true; - } - } - - // Only check for client usage if we have confirmed Prisma imports - if has_prisma_import { - // Prisma client instantiation (very specific) - if content.contains("new PrismaClient") || content.contains("PrismaClient()") { - confidence += 0.3; - } - - // Prisma-specific query patterns (only if we know it's Prisma) - if content.contains("prisma.") && ( - content.contains(".findUnique(") || - content.contains(".findFirst(") || - content.contains(".upsert(") || - content.contains(".$connect()") || - content.contains(".$disconnect()") - ) { - confidence += 0.2; - } - } - - // Only return confidence if we have actual Prisma indicators - if confidence > 0.0 && has_prisma_import { - Some(confidence.min(1.0_f32)) - } else { - None - } -} - -/// Analyzes Encore usage patterns in source files -fn analyze_encore_usage(content: &str, file_path: &std::path::Path) -> Option { - let file_name = file_path.file_name()?.to_string_lossy(); - let mut confidence: f32 = 0.0; - - // Skip generated files (like Encore client code) - if content.contains("// Code generated by the Encore") || content.contains("DO NOT EDIT") { - return None; - } - - // Skip client-only files (generated or consumption only) - if file_name.contains("client.ts") || file_name.contains("client.js") { - return None; - } - - // Only detect Encore when there are actual service development patterns - let mut has_service_patterns = false; - - // Service definition files (high confidence for actual Encore development) - if file_name.contains("encore.service") || file_name.contains("service.ts") { - confidence += 0.4; - has_service_patterns = true; - } - - // API endpoint definitions (indicates actual Encore service development) - if content.contains("encore.dev/api") && (content.contains("export") || content.contains("api.")) { - confidence += 0.4; - has_service_patterns = true; - } - - // Database service patterns (actual Encore service code) - if content.contains("SQLDatabase") && content.contains("encore.dev") { - confidence += 0.3; - has_service_patterns = true; - } - - // Secret configuration (actual Encore service code) - if content.contains("secret(") && content.contains("encore.dev/config") { - confidence += 0.3; - has_service_patterns = true; - } - - // PubSub service patterns (actual Encore service code) - if content.contains("Topic") && content.contains("encore.dev/pubsub") { - confidence += 0.3; - has_service_patterns = true; - } - - // Cron job patterns (actual Encore service code) - if content.contains("cron") && content.contains("encore.dev") { - confidence += 0.2; - has_service_patterns = true; - } - - // Only return confidence if we have actual service development patterns - if confidence > 0.0 && has_service_patterns { - Some(confidence.min(1.0_f32)) - } else { - None - } -} - -/// Analyzes Tanstack Start usage patterns in source files -fn analyze_tanstack_start_usage(content: &str, file_path: &std::path::Path) -> Option { - let file_name = file_path.file_name()?.to_string_lossy(); - let mut confidence: f32 = 0.0; - let mut has_start_patterns = false; - - // Configuration files (high confidence) - if file_name == "app.config.ts" || file_name == "app.config.js" { - if content.contains("@tanstack/react-start") || content.contains("tanstack") { - confidence += 0.5; - has_start_patterns = true; - } - } - - // Router configuration patterns (very high confidence) - if file_name.contains("router.") && (file_name.ends_with(".ts") || file_name.ends_with(".tsx")) { - if content.contains("createRouter") && content.contains("@tanstack/react-router") { - confidence += 0.4; - has_start_patterns = true; - } - if content.contains("routeTree") { - confidence += 0.2; - has_start_patterns = true; - } - } - - // Server entry point patterns - if file_name == "ssr.tsx" || file_name == "ssr.ts" { - if content.contains("createStartHandler") || content.contains("@tanstack/react-start/server") { - confidence += 0.5; - has_start_patterns = true; - } - } - - // Client entry point patterns - if file_name == "client.tsx" || file_name == "client.ts" { - if content.contains("StartClient") && content.contains("@tanstack/react-start") { - confidence += 0.5; - has_start_patterns = true; - } - if content.contains("hydrateRoot") && content.contains("createRouter") { - confidence += 0.3; - has_start_patterns = true; - } - } - - // Root route patterns (in app/routes/__root.tsx) - if file_name == "__root.tsx" || file_name == "__root.ts" { - if content.contains("createRootRoute") && content.contains("@tanstack/react-router") { - confidence += 0.4; - has_start_patterns = true; - } - if content.contains("HeadContent") && content.contains("Scripts") { - confidence += 0.3; - has_start_patterns = true; - } - } - - // Route files with createFileRoute - if file_path.to_string_lossy().contains("routes/") { - if content.contains("createFileRoute") && content.contains("@tanstack/react-router") { - confidence += 0.3; - has_start_patterns = true; - } - } - - // Server functions (key Tanstack Start feature) - if content.contains("createServerFn") && content.contains("@tanstack/react-start") { - confidence += 0.4; - has_start_patterns = true; - } - - // Import patterns specific to Tanstack Start - if content.contains("from '@tanstack/react-start'") { - confidence += 0.3; - has_start_patterns = true; - } - - // Vinxi configuration patterns - if file_name == "vinxi.config.ts" || file_name == "vinxi.config.js" { - confidence += 0.2; - has_start_patterns = true; - } - - // Only return confidence if we have actual Tanstack Start patterns - if confidence > 0.0 && has_start_patterns { - Some(confidence.min(1.0_f32)) - } else { - None - } -} - -/// JavaScript/TypeScript technology detection rules with proper classification -fn get_js_technology_rules() -> Vec { - vec![ - // META-FRAMEWORKS (Mutually Exclusive) - TechnologyRule { - name: "Next.js".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["next".to_string()], - requires: vec!["React".to_string()], - conflicts_with: vec!["Tanstack Start".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], - is_primary_indicator: true, - alternative_names: vec!["nextjs".to_string()], - }, - TechnologyRule { - name: "Tanstack Start".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["@tanstack/react-start".to_string()], - requires: vec!["React".to_string()], - conflicts_with: vec!["Next.js".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], - is_primary_indicator: true, - alternative_names: vec!["tanstack-start".to_string(), "TanStack Start".to_string()], - }, - TechnologyRule { - name: "React Router v7".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["react-router".to_string(), "@remix-run/react".to_string()], - requires: vec!["React".to_string()], - conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], - is_primary_indicator: true, - alternative_names: vec!["remix".to_string(), "react-router".to_string()], - }, - TechnologyRule { - name: "SvelteKit".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["@sveltejs/kit".to_string()], - requires: vec!["Svelte".to_string()], - conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "React Router v7".to_string(), "Nuxt.js".to_string()], - is_primary_indicator: true, - alternative_names: vec!["svelte-kit".to_string()], - }, - TechnologyRule { - name: "Nuxt.js".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["nuxt".to_string(), "@nuxt/core".to_string()], - requires: vec!["Vue.js".to_string()], - conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "React Router v7".to_string(), "SvelteKit".to_string()], - is_primary_indicator: true, - alternative_names: vec!["nuxtjs".to_string()], - }, - TechnologyRule { - name: "Astro".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["astro".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "SolidStart".to_string(), - category: TechnologyCategory::MetaFramework, - confidence: 0.95, - dependency_patterns: vec!["solid-start".to_string()], - requires: vec!["SolidJS".to_string()], - conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "React Router v7".to_string(), "SvelteKit".to_string()], - is_primary_indicator: true, - alternative_names: vec![], - }, - - // FRONTEND FRAMEWORKS (Provide structure) - TechnologyRule { - name: "Angular".to_string(), - category: TechnologyCategory::FrontendFramework, - confidence: 0.90, - dependency_patterns: vec!["@angular/core".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["angular".to_string()], - }, - TechnologyRule { - name: "Svelte".to_string(), - category: TechnologyCategory::FrontendFramework, - confidence: 0.95, - dependency_patterns: vec!["svelte".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, // SvelteKit would be primary - alternative_names: vec![], - }, - - // UI LIBRARIES (Not frameworks!) - TechnologyRule { - name: "React".to_string(), - category: TechnologyCategory::Library(LibraryType::UI), - confidence: 0.90, - dependency_patterns: vec!["react".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, // Meta-frameworks using React would be primary - alternative_names: vec!["reactjs".to_string()], - }, - TechnologyRule { - name: "Vue.js".to_string(), - category: TechnologyCategory::Library(LibraryType::UI), - confidence: 0.90, - dependency_patterns: vec!["vue".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["vuejs".to_string()], - }, - TechnologyRule { - name: "SolidJS".to_string(), - category: TechnologyCategory::Library(LibraryType::UI), - confidence: 0.95, - dependency_patterns: vec!["solid-js".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["solid".to_string()], - }, - TechnologyRule { - name: "HTMX".to_string(), - category: TechnologyCategory::Library(LibraryType::UI), - confidence: 0.95, - dependency_patterns: vec!["htmx.org".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["htmx".to_string()], - }, - - // Note: Removed utility libraries (Tanstack Query, Tanstack Router, state management) - // as they don't provide value for IaC generation decisions - - // BACKEND FRAMEWORKS - TechnologyRule { - name: "Express.js".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["express".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["express".to_string()], - }, - TechnologyRule { - name: "Fastify".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["fastify".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Nest.js".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["@nestjs/core".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["nestjs".to_string()], - }, - TechnologyRule { - name: "Hono".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["hono".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Elysia".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["elysia".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Encore".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["encore.dev".to_string(), "encore".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["encore-ts-starter".to_string()], - }, - - // BUILD TOOLS (Not frameworks!) - TechnologyRule { - name: "Vite".to_string(), - category: TechnologyCategory::BuildTool, - confidence: 0.80, - dependency_patterns: vec!["vite".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Webpack".to_string(), - category: TechnologyCategory::BuildTool, - confidence: 0.80, - dependency_patterns: vec!["webpack".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // DATABASE/ORM (Important for Docker/infrastructure setup, migrations, etc.) - TechnologyRule { - name: "Prisma".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["prisma".to_string(), "@prisma/client".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Drizzle ORM".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["drizzle-orm".to_string(), "drizzle-kit".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["drizzle".to_string()], - }, - - // RUNTIMES (Important for IaC - determines base images, package managers) - TechnologyRule { - name: "Node.js".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.90, - dependency_patterns: vec!["node".to_string()], // This will need file-based detection - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["nodejs".to_string()], - }, - TechnologyRule { - name: "Bun".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.95, - dependency_patterns: vec!["bun".to_string()], // Look for bun in devDependencies or bun.lockb file - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Deno".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.95, - dependency_patterns: vec!["@deno/core".to_string(), "deno".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // TESTING (Keep minimal - only major frameworks that affect build process) - TechnologyRule { - name: "Jest".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["jest".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Vitest".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["vitest".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - ] -} - -/// Rust technology detection rules with comprehensive framework coverage -fn get_rust_technology_rules() -> Vec { - vec![ - // WEB FRAMEWORKS - TechnologyRule { - name: "Actix Web".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["actix-web".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["actix".to_string()], - }, - TechnologyRule { - name: "Axum".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["axum".to_string()], - requires: vec!["Tokio".to_string()], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Rocket".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["rocket".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Warp".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["warp".to_string()], - requires: vec!["Tokio".to_string()], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Loco".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["loco-rs".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["loco".to_string()], - }, - TechnologyRule { - name: "Poem".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["poem".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Salvo".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["salvo".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Trillium".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["trillium".to_string()], - requires: vec!["Tokio".to_string()], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - - // ASYNC RUNTIMES - TechnologyRule { - name: "Tokio".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.90, - dependency_patterns: vec!["tokio".to_string()], - requires: vec![], - conflicts_with: vec!["async-std".to_string()], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "async-std".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.90, - dependency_patterns: vec!["async-std".to_string()], - requires: vec![], - conflicts_with: vec!["Tokio".to_string()], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // DATABASE/ORM - TechnologyRule { - name: "SeaORM".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["sea-orm".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["sea_orm".to_string()], - }, - TechnologyRule { - name: "Diesel".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["diesel".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "SQLx".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["sqlx".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // SERIALIZATION - TechnologyRule { - name: "Serde".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["serde".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // TESTING - TechnologyRule { - name: "Criterion".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["criterion".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // GUI FRAMEWORKS (WASM/Desktop) - TechnologyRule { - name: "Leptos".to_string(), - category: TechnologyCategory::FrontendFramework, - confidence: 0.95, - dependency_patterns: vec!["leptos".to_string()], - requires: vec![], - conflicts_with: vec!["Yew".to_string(), "Dioxus".to_string()], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Yew".to_string(), - category: TechnologyCategory::FrontendFramework, - confidence: 0.95, - dependency_patterns: vec!["yew".to_string()], - requires: vec![], - conflicts_with: vec!["Leptos".to_string(), "Dioxus".to_string()], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Dioxus".to_string(), - category: TechnologyCategory::FrontendFramework, - confidence: 0.95, - dependency_patterns: vec!["dioxus".to_string()], - requires: vec![], - conflicts_with: vec!["Leptos".to_string(), "Yew".to_string()], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Tauri".to_string(), - category: TechnologyCategory::Library(LibraryType::UI), - confidence: 0.95, - dependency_patterns: vec!["tauri".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "egui".to_string(), - category: TechnologyCategory::Library(LibraryType::UI), - confidence: 0.95, - dependency_patterns: vec!["egui".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - ] -} - -/// Python technology detection rules with comprehensive framework coverage -fn get_python_technology_rules() -> Vec { - vec![ - // WEB FRAMEWORKS - Full Stack - TechnologyRule { - name: "Django".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["django".to_string(), "Django".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Django REST Framework".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["djangorestframework".to_string(), "rest_framework".to_string()], - requires: vec!["Django".to_string()], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["DRF".to_string()], - }, - - // MICRO FRAMEWORKS - TechnologyRule { - name: "Flask".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["flask".to_string(), "Flask".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "FastAPI".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["fastapi".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Starlette".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["starlette".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Quart".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["quart".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Sanic".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["sanic".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Tornado".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["tornado".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Falcon".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["falcon".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Bottle".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["bottle".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "aiohttp".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["aiohttp".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - - // DATABASE/ORM - TechnologyRule { - name: "SQLAlchemy".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["sqlalchemy".to_string(), "SQLAlchemy".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Peewee".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["peewee".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Tortoise ORM".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["tortoise-orm".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["tortoise".to_string()], - }, - TechnologyRule { - name: "Django ORM".to_string(), - category: TechnologyCategory::Database, - confidence: 0.95, - dependency_patterns: vec!["django.db".to_string()], - requires: vec!["Django".to_string()], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // ASYNC FRAMEWORKS - TechnologyRule { - name: "asyncio".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.85, - dependency_patterns: vec!["asyncio".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // DATA SCIENCE FRAMEWORKS (Important for containerization/deployment) - TechnologyRule { - name: "NumPy".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["numpy".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Pandas".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["pandas".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Scikit-learn".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["scikit-learn".to_string(), "sklearn".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["sklearn".to_string()], - }, - TechnologyRule { - name: "TensorFlow".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.90, - dependency_patterns: vec!["tensorflow".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "PyTorch".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.90, - dependency_patterns: vec!["torch".to_string(), "pytorch".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["torch".to_string()], - }, - - // TASK QUEUES - TechnologyRule { - name: "Celery".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.90, - dependency_patterns: vec!["celery".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // TESTING - TechnologyRule { - name: "pytest".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["pytest".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "unittest".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.80, - dependency_patterns: vec!["unittest".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // WSGI/ASGI SERVERS - TechnologyRule { - name: "Gunicorn".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.85, - dependency_patterns: vec!["gunicorn".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Uvicorn".to_string(), - category: TechnologyCategory::Runtime, - confidence: 0.85, - dependency_patterns: vec!["uvicorn".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - ] -} - -/// Go technology detection rules with comprehensive framework coverage -fn get_go_technology_rules() -> Vec { - vec![ - // WEB FRAMEWORKS - TechnologyRule { - name: "Gin".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["github.com/gin-gonic/gin".to_string(), "gin-gonic".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["gin-gonic".to_string()], - }, - TechnologyRule { - name: "Echo".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["github.com/labstack/echo".to_string(), "labstack/echo".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["labstack/echo".to_string()], - }, - TechnologyRule { - name: "Fiber".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["github.com/gofiber/fiber".to_string(), "gofiber".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["gofiber".to_string()], - }, - TechnologyRule { - name: "Beego".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["github.com/beego/beego".to_string(), "beego".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Chi".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["github.com/go-chi/chi".to_string(), "go-chi".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["go-chi".to_string()], - }, - TechnologyRule { - name: "Gorilla Mux".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["github.com/gorilla/mux".to_string(), "gorilla/mux".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["mux".to_string(), "gorilla".to_string()], - }, - TechnologyRule { - name: "Revel".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["github.com/revel/revel".to_string(), "revel".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Buffalo".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["github.com/gobuffalo/buffalo".to_string(), "gobuffalo".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["gobuffalo".to_string()], - }, - TechnologyRule { - name: "Iris".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["github.com/kataras/iris".to_string(), "kataras/iris".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "FastHTTP".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["github.com/valyala/fasthttp".to_string(), "fasthttp".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["valyala/fasthttp".to_string()], - }, - TechnologyRule { - name: "Hertz".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["github.com/cloudwego/hertz".to_string(), "cloudwego/hertz".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["cloudwego".to_string()], - }, - - // DATABASE/ORM - TechnologyRule { - name: "GORM".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["gorm.io/gorm".to_string(), "gorm".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Ent".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["entgo.io/ent".to_string(), "facebook/ent".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["entgo".to_string()], - }, - TechnologyRule { - name: "Xorm".to_string(), - category: TechnologyCategory::Database, - confidence: 0.85, - dependency_patterns: vec!["xorm.io/xorm".to_string(), "xorm".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // MICROSERVICES - TechnologyRule { - name: "Go Kit".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.90, - dependency_patterns: vec!["github.com/go-kit/kit".to_string(), "go-kit".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["kit".to_string()], - }, - TechnologyRule { - name: "Kratos".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["github.com/go-kratos/kratos".to_string(), "go-kratos".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["go-kratos".to_string()], - }, - - // MESSAGE QUEUES - TechnologyRule { - name: "Sarama".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["github.com/shopify/sarama".to_string(), "sarama".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["shopify/sarama".to_string()], - }, - - // TESTING - TechnologyRule { - name: "Testify".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["github.com/stretchr/testify".to_string(), "testify".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["stretchr/testify".to_string()], - }, - TechnologyRule { - name: "Ginkgo".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["github.com/onsi/ginkgo".to_string(), "ginkgo".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["onsi/ginkgo".to_string()], - }, - - // CLI FRAMEWORKS - TechnologyRule { - name: "Cobra".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["github.com/spf13/cobra".to_string(), "cobra".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["spf13/cobra".to_string()], - }, - - // CONFIG MANAGEMENT - TechnologyRule { - name: "Viper".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.80, - dependency_patterns: vec!["github.com/spf13/viper".to_string(), "viper".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["spf13/viper".to_string()], - }, - ] -} - -/// Java/JVM technology detection rules with comprehensive framework coverage -fn get_jvm_technology_rules() -> Vec { - vec![ - // SPRING ECOSYSTEM - TechnologyRule { - name: "Spring Boot".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["spring-boot".to_string(), "org.springframework.boot".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["spring".to_string()], - }, - TechnologyRule { - name: "Spring Framework".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["spring-context".to_string(), "org.springframework".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["spring".to_string()], - }, - TechnologyRule { - name: "Spring Data".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["spring-data".to_string(), "org.springframework.data".to_string()], - requires: vec!["Spring Framework".to_string()], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Spring Security".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.90, - dependency_patterns: vec!["spring-security".to_string(), "org.springframework.security".to_string()], - requires: vec!["Spring Framework".to_string()], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Spring Cloud".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.90, - dependency_patterns: vec!["spring-cloud".to_string(), "org.springframework.cloud".to_string()], - requires: vec!["Spring Boot".to_string()], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // MICROSERVICES FRAMEWORKS - TechnologyRule { - name: "Quarkus".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["quarkus".to_string(), "io.quarkus".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Micronaut".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["micronaut".to_string(), "io.micronaut".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Helidon".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["helidon".to_string(), "io.helidon".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Vert.x".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["vertx".to_string(), "io.vertx".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["eclipse vert.x".to_string(), "vertx".to_string()], - }, - - // TRADITIONAL FRAMEWORKS - TechnologyRule { - name: "Struts".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["struts".to_string(), "org.apache.struts".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["apache struts".to_string()], - }, - TechnologyRule { - name: "JSF".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.85, - dependency_patterns: vec!["jsf".to_string(), "javax.faces".to_string(), "jakarta.faces".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["javaserver faces".to_string()], - }, - - // LIGHTWEIGHT FRAMEWORKS - TechnologyRule { - name: "Dropwizard".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["dropwizard".to_string(), "io.dropwizard".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Spark Java".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["spark-core".to_string(), "com.sparkjava".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["spark".to_string()], - }, - TechnologyRule { - name: "Javalin".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["javalin".to_string(), "io.javalin".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - TechnologyRule { - name: "Ratpack".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["ratpack".to_string(), "io.ratpack".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - - // PLAY FRAMEWORK - TechnologyRule { - name: "Play Framework".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["play".to_string(), "com.typesafe.play".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["play".to_string()], - }, - - // ORM/DATABASE - TechnologyRule { - name: "Hibernate".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["hibernate".to_string(), "org.hibernate".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["hibernate orm".to_string()], - }, - TechnologyRule { - name: "MyBatis".to_string(), - category: TechnologyCategory::Database, - confidence: 0.90, - dependency_patterns: vec!["mybatis".to_string(), "org.mybatis".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "JOOQ".to_string(), - category: TechnologyCategory::Database, - confidence: 0.85, - dependency_patterns: vec!["jooq".to_string(), "org.jooq".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // ENTERPRISE JAVA - TechnologyRule { - name: "Jakarta EE".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.90, - dependency_patterns: vec!["jakarta.".to_string(), "jakarta-ee".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec!["java ee".to_string()], - }, - - // BUILD TOOLS - TechnologyRule { - name: "Maven".to_string(), - category: TechnologyCategory::BuildTool, - confidence: 0.80, - dependency_patterns: vec!["maven".to_string(), "org.apache.maven".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["apache maven".to_string()], - }, - TechnologyRule { - name: "Gradle".to_string(), - category: TechnologyCategory::BuildTool, - confidence: 0.80, - dependency_patterns: vec!["gradle".to_string(), "org.gradle".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // TESTING - TechnologyRule { - name: "JUnit".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["junit".to_string(), "org.junit".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "TestNG".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.85, - dependency_patterns: vec!["testng".to_string(), "org.testng".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - TechnologyRule { - name: "Mockito".to_string(), - category: TechnologyCategory::Testing, - confidence: 0.80, - dependency_patterns: vec!["mockito".to_string(), "org.mockito".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // REACTIVE FRAMEWORKS - TechnologyRule { - name: "Reactor".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["reactor".to_string(), "io.projectreactor".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec!["project reactor".to_string()], - }, - TechnologyRule { - name: "RxJava".to_string(), - category: TechnologyCategory::Library(LibraryType::Utility), - confidence: 0.85, - dependency_patterns: vec!["rxjava".to_string(), "io.reactivex".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: false, - alternative_names: vec![], - }, - - // KOTLIN SPECIFIC - TechnologyRule { - name: "Ktor".to_string(), - category: TechnologyCategory::BackendFramework, - confidence: 0.95, - dependency_patterns: vec!["ktor".to_string(), "io.ktor".to_string()], - requires: vec![], - conflicts_with: vec![], - is_primary_indicator: true, - alternative_names: vec![], - }, - ] -} - #[cfg(test)] mod tests { use super::*; + use crate::analyzer::{TechnologyCategory, LibraryType}; use std::path::PathBuf; #[test] @@ -1988,136 +62,102 @@ mod tests { package_manager: Some("cargo".to_string()), }; - let technologies = detect_rust_technologies(&language); - - // This is a simplified test - in real implementation, we'd need access to dependencies - assert!(technologies.is_empty() || technologies.iter().any(|f| f.name.contains("Actix"))); - } - - #[test] - fn test_framework_pattern_matching() { - assert!(matches_pattern("express", "express")); - assert!(matches_pattern("@nestjs/core", "@nestjs/*")); - assert!(matches_pattern("spring-boot-starter-web", "spring-boot-starter*")); - assert!(!matches_pattern("react", "vue")); - } - - #[test] - fn test_framework_categories() { - let rules = get_js_technology_rules(); - - let express_rule = rules.iter().find(|r| r.name == "Express.js").unwrap(); - assert!(matches!(express_rule.category, TechnologyCategory::BackendFramework)); - - let jest_rule = rules.iter().find(|r| r.name == "Jest").unwrap(); - assert!(matches!(jest_rule.category, TechnologyCategory::Testing)); - - // Test new frameworks - let drizzle_rule = rules.iter().find(|r| r.name == "Drizzle ORM").unwrap(); - assert!(matches!(drizzle_rule.category, TechnologyCategory::Database)); - - let svelte_rule = rules.iter().find(|r| r.name == "Svelte").unwrap(); - assert!(matches!(svelte_rule.category, TechnologyCategory::FrontendFramework)); + let config = AnalysisConfig::default(); + let project_root = Path::new("."); - let encore_rule = rules.iter().find(|r| r.name == "Encore").unwrap(); - assert!(matches!(encore_rule.category, TechnologyCategory::BackendFramework)); + let technologies = detect_frameworks(project_root, &[language], &config).unwrap(); - let hono_rule = rules.iter().find(|r| r.name == "Hono").unwrap(); - assert!(matches!(hono_rule.category, TechnologyCategory::BackendFramework)); - } - - #[test] - fn test_modern_framework_detection() { - let rules = get_js_technology_rules(); + // Should detect Actix Web and Tokio + let actix_web = technologies.iter().find(|t| t.name == "Actix Web"); + let tokio = technologies.iter().find(|t| t.name == "Tokio"); - // Test that we have all the new frameworks - let framework_names: Vec<&str> = rules.iter().map(|r| r.name.as_str()).collect(); + if let Some(actix) = actix_web { + assert!(matches!(actix.category, TechnologyCategory::BackendFramework)); + assert!(actix.is_primary); + assert!(actix.confidence > 0.8); + } - assert!(framework_names.contains(&"Svelte")); - assert!(framework_names.contains(&"SvelteKit")); - assert!(framework_names.contains(&"Astro")); - assert!(framework_names.contains(&"SolidJS")); - assert!(framework_names.contains(&"Encore")); - assert!(framework_names.contains(&"Hono")); - assert!(framework_names.contains(&"Elysia")); - assert!(framework_names.contains(&"Drizzle ORM")); - assert!(framework_names.contains(&"React Router v7")); - assert!(framework_names.contains(&"Tanstack Start")); + if let Some(tokio_tech) = tokio { + assert!(matches!(tokio_tech.category, TechnologyCategory::Runtime)); + assert!(!tokio_tech.is_primary); + } } #[test] - fn test_tanstack_start_detection() { + fn test_javascript_next_js_detection() { let language = DetectedLanguage { - name: "TypeScript".to_string(), - version: Some("5.0.0".to_string()), - confidence: 0.925, - files: vec![PathBuf::from("src/routes/index.tsx")], + name: "JavaScript".to_string(), + version: Some("18.0.0".to_string()), + confidence: 0.9, + files: vec![PathBuf::from("pages/index.js")], main_dependencies: vec![ - "@tanstack/react-start".to_string(), - "@tanstack/react-router".to_string(), + "next".to_string(), "react".to_string(), "react-dom".to_string(), ], - dev_dependencies: vec![ - "vinxi".to_string(), - "typescript".to_string(), - ], + dev_dependencies: vec!["eslint".to_string()], package_manager: Some("npm".to_string()), }; - let technologies = detect_js_technologies(&language); - - // Should detect Tanstack Start - let tanstack_start = technologies.iter().find(|t| t.name == "Tanstack Start"); - assert!(tanstack_start.is_some(), "Tanstack Start should be detected"); + let config = AnalysisConfig::default(); + let project_root = Path::new("."); - let tanstack_start = tanstack_start.unwrap(); - assert!(matches!(tanstack_start.category, TechnologyCategory::MetaFramework)); - assert!(tanstack_start.is_primary, "Tanstack Start should be marked as primary"); - assert!(tanstack_start.confidence > 0.8, "Tanstack Start detection confidence should be high"); + let technologies = detect_frameworks(project_root, &[language], &config).unwrap(); - // Should also detect React + // Should detect Next.js and React + let nextjs = technologies.iter().find(|t| t.name == "Next.js"); let react = technologies.iter().find(|t| t.name == "React"); - assert!(react.is_some(), "React should be detected as a dependency"); + + if let Some(next) = nextjs { + assert!(matches!(next.category, TechnologyCategory::MetaFramework)); + assert!(next.is_primary); + assert!(next.requires.contains(&"React".to_string())); + } + + if let Some(react_tech) = react { + assert!(matches!(react_tech.category, TechnologyCategory::Library(LibraryType::UI))); + assert!(!react_tech.is_primary); // Should be false since Next.js is the meta-framework + } } - + #[test] - fn test_comprehensive_python_detection() { + fn test_python_fastapi_detection() { let language = DetectedLanguage { name: "Python".to_string(), version: Some("3.11.0".to_string()), confidence: 0.95, - files: vec![PathBuf::from("app.py")], + files: vec![PathBuf::from("main.py")], main_dependencies: vec![ "fastapi".to_string(), - "sqlalchemy".to_string(), - "pandas".to_string(), - "torch".to_string(), - "gunicorn".to_string(), + "uvicorn".to_string(), + "pydantic".to_string(), ], dev_dependencies: vec!["pytest".to_string()], package_manager: Some("pip".to_string()), }; - let technologies = detect_python_technologies(&language); - let tech_names: Vec<&str> = technologies.iter().map(|t| t.name.as_str()).collect(); + let config = AnalysisConfig::default(); + let project_root = Path::new("."); + + let technologies = detect_frameworks(project_root, &[language], &config).unwrap(); - // Should detect FastAPI as primary backend framework - assert!(tech_names.contains(&"FastAPI")); - assert!(tech_names.contains(&"SQLAlchemy")); - assert!(tech_names.contains(&"Pandas")); - assert!(tech_names.contains(&"PyTorch")); - assert!(tech_names.contains(&"Gunicorn")); - assert!(tech_names.contains(&"pytest")); + // Should detect FastAPI and Uvicorn + let fastapi = technologies.iter().find(|t| t.name == "FastAPI"); + let uvicorn = technologies.iter().find(|t| t.name == "Uvicorn"); - // FastAPI should be marked as primary - let fastapi = technologies.iter().find(|t| t.name == "FastAPI").unwrap(); - assert!(fastapi.is_primary); - assert!(matches!(fastapi.category, TechnologyCategory::BackendFramework)); + if let Some(fastapi_tech) = fastapi { + assert!(matches!(fastapi_tech.category, TechnologyCategory::BackendFramework)); + assert!(fastapi_tech.is_primary); + } + + if let Some(uvicorn_tech) = uvicorn { + assert!(matches!(uvicorn_tech.category, TechnologyCategory::Runtime)); + assert!(!uvicorn_tech.is_primary); + } } - + #[test] - fn test_comprehensive_go_detection() { + fn test_go_gin_detection() { let language = DetectedLanguage { name: "Go".to_string(), version: Some("1.21.0".to_string()), @@ -2126,31 +166,33 @@ mod tests { main_dependencies: vec![ "github.com/gin-gonic/gin".to_string(), "gorm.io/gorm".to_string(), - "github.com/spf13/cobra".to_string(), - "github.com/spf13/viper".to_string(), ], dev_dependencies: vec!["github.com/stretchr/testify".to_string()], package_manager: Some("go mod".to_string()), }; - let technologies = detect_go_technologies(&language); - let tech_names: Vec<&str> = technologies.iter().map(|t| t.name.as_str()).collect(); + let config = AnalysisConfig::default(); + let project_root = Path::new("."); + + let technologies = detect_frameworks(project_root, &[language], &config).unwrap(); + + // Should detect Gin and GORM + let gin = technologies.iter().find(|t| t.name == "Gin"); + let gorm = technologies.iter().find(|t| t.name == "GORM"); - // Should detect Gin as primary backend framework - assert!(tech_names.contains(&"Gin")); - assert!(tech_names.contains(&"GORM")); - assert!(tech_names.contains(&"Cobra")); - assert!(tech_names.contains(&"Viper")); - assert!(tech_names.contains(&"Testify")); + if let Some(gin_tech) = gin { + assert!(matches!(gin_tech.category, TechnologyCategory::BackendFramework)); + assert!(gin_tech.is_primary); + } - // Gin should be marked as primary - let gin = technologies.iter().find(|t| t.name == "Gin").unwrap(); - assert!(gin.is_primary); - assert!(matches!(gin.category, TechnologyCategory::BackendFramework)); + if let Some(gorm_tech) = gorm { + assert!(matches!(gorm_tech.category, TechnologyCategory::Database)); + assert!(!gorm_tech.is_primary); + } } - + #[test] - fn test_comprehensive_jvm_detection() { + fn test_java_spring_boot_detection() { let language = DetectedLanguage { name: "Java".to_string(), version: Some("17.0.0".to_string()), @@ -2158,74 +200,28 @@ mod tests { files: vec![PathBuf::from("src/main/java/Application.java")], main_dependencies: vec![ "spring-boot".to_string(), - "spring-data".to_string(), - "hibernate".to_string(), - "io.projectreactor".to_string(), + "spring-web".to_string(), ], - dev_dependencies: vec!["junit".to_string(), "mockito".to_string()], + dev_dependencies: vec!["junit".to_string()], package_manager: Some("maven".to_string()), }; - let technologies = detect_jvm_technologies(&language); - let tech_names: Vec<&str> = technologies.iter().map(|t| t.name.as_str()).collect(); - - // Should detect Spring Boot as primary backend framework - assert!(tech_names.contains(&"Spring Boot")); - assert!(tech_names.contains(&"Spring Data")); - assert!(tech_names.contains(&"Hibernate")); - assert!(tech_names.contains(&"Reactor")); - assert!(tech_names.contains(&"JUnit")); - assert!(tech_names.contains(&"Mockito")); - - // Spring Boot should be marked as primary - let spring_boot = technologies.iter().find(|t| t.name == "Spring Boot").unwrap(); - assert!(spring_boot.is_primary); - assert!(matches!(spring_boot.category, TechnologyCategory::BackendFramework)); - } - - #[test] - fn test_comprehensive_rust_detection() { - let language = DetectedLanguage { - name: "Rust".to_string(), - version: Some("1.70.0".to_string()), - confidence: 0.95, - files: vec![PathBuf::from("src/main.rs")], - main_dependencies: vec![ - "axum".to_string(), - "tokio".to_string(), - "sqlx".to_string(), - "serde".to_string(), - "tauri".to_string(), - ], - dev_dependencies: vec!["criterion".to_string()], - package_manager: Some("cargo".to_string()), - }; - - let technologies = detect_rust_technologies(&language); - let tech_names: Vec<&str> = technologies.iter().map(|t| t.name.as_str()).collect(); + let config = AnalysisConfig::default(); + let project_root = Path::new("."); - // Should detect Axum as primary backend framework - assert!(tech_names.contains(&"Axum")); - assert!(tech_names.contains(&"Tokio")); - assert!(tech_names.contains(&"SQLx")); - assert!(tech_names.contains(&"Serde")); - assert!(tech_names.contains(&"Tauri")); - assert!(tech_names.contains(&"Criterion")); + let technologies = detect_frameworks(project_root, &[language], &config).unwrap(); - // Axum should be marked as primary - let axum = technologies.iter().find(|t| t.name == "Axum").unwrap(); - assert!(axum.is_primary); - assert!(matches!(axum.category, TechnologyCategory::BackendFramework)); + // Should detect Spring Boot + let spring_boot = technologies.iter().find(|t| t.name == "Spring Boot"); - // Axum should require Tokio - assert!(axum.requires.contains(&"Tokio".to_string())); + if let Some(spring) = spring_boot { + assert!(matches!(spring.category, TechnologyCategory::BackendFramework)); + assert!(spring.is_primary); + } } #[test] fn test_technology_conflicts_resolution() { - use crate::analyzer::AnalysisConfig; - use std::path::Path; - let language = DetectedLanguage { name: "Rust".to_string(), version: Some("1.70.0".to_string()), @@ -2242,9 +238,7 @@ mod tests { let config = AnalysisConfig::default(); let project_root = Path::new("."); - // Use the main detection function which includes conflict resolution let technologies = detect_frameworks(project_root, &[language], &config).unwrap(); - let _tech_names: Vec<&str> = technologies.iter().map(|t| t.name.as_str()).collect(); // Should only have one async runtime (higher confidence wins) let async_runtimes: Vec<_> = technologies.iter() diff --git a/src/analyzer/frameworks/go.rs b/src/analyzer/frameworks/go.rs new file mode 100644 index 00000000..44d1ade8 --- /dev/null +++ b/src/analyzer/frameworks/go.rs @@ -0,0 +1,256 @@ +use super::{LanguageFrameworkDetector, TechnologyRule, FrameworkDetectionUtils}; +use crate::analyzer::{DetectedTechnology, DetectedLanguage, TechnologyCategory, LibraryType}; +use crate::error::Result; + +pub struct GoFrameworkDetector; + +impl LanguageFrameworkDetector for GoFrameworkDetector { + fn detect_frameworks(&self, language: &DetectedLanguage) -> Result> { + let rules = get_go_technology_rules(); + + // Combine main and dev dependencies for comprehensive detection + let all_deps: Vec = language.main_dependencies.iter() + .chain(language.dev_dependencies.iter()) + .cloned() + .collect(); + + let technologies = FrameworkDetectionUtils::detect_technologies_by_dependencies( + &rules, &all_deps, language.confidence + ); + + Ok(technologies) + } + + fn supported_languages(&self) -> Vec<&'static str> { + vec!["Go"] + } +} + +/// Go technology detection rules with comprehensive framework coverage +fn get_go_technology_rules() -> Vec { + vec![ + // WEB FRAMEWORKS + TechnologyRule { + name: "Gin".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["github.com/gin-gonic/gin".to_string(), "gin-gonic".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["gin-gonic".to_string()], + }, + TechnologyRule { + name: "Echo".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["github.com/labstack/echo".to_string(), "labstack/echo".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["labstack/echo".to_string()], + }, + TechnologyRule { + name: "Fiber".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["github.com/gofiber/fiber".to_string(), "gofiber".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["gofiber".to_string()], + }, + TechnologyRule { + name: "Beego".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["github.com/beego/beego".to_string(), "beego".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Chi".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["github.com/go-chi/chi".to_string(), "go-chi".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["go-chi".to_string()], + }, + TechnologyRule { + name: "Gorilla Mux".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["github.com/gorilla/mux".to_string(), "gorilla/mux".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["mux".to_string(), "gorilla".to_string()], + }, + TechnologyRule { + name: "Revel".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["github.com/revel/revel".to_string(), "revel".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Buffalo".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["github.com/gobuffalo/buffalo".to_string(), "gobuffalo".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["gobuffalo".to_string()], + }, + TechnologyRule { + name: "Iris".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["github.com/kataras/iris".to_string(), "kataras/iris".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "FastHTTP".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["github.com/valyala/fasthttp".to_string(), "fasthttp".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["valyala/fasthttp".to_string()], + }, + TechnologyRule { + name: "Hertz".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["github.com/cloudwego/hertz".to_string(), "cloudwego/hertz".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["cloudwego".to_string()], + }, + + // DATABASE/ORM + TechnologyRule { + name: "GORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["gorm.io/gorm".to_string(), "gorm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Ent".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["entgo.io/ent".to_string(), "facebook/ent".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["entgo".to_string()], + }, + TechnologyRule { + name: "Xorm".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["xorm.io/xorm".to_string(), "xorm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // MICROSERVICES + TechnologyRule { + name: "Go Kit".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["github.com/go-kit/kit".to_string(), "go-kit".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["kit".to_string()], + }, + TechnologyRule { + name: "Kratos".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["github.com/go-kratos/kratos".to_string(), "go-kratos".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["go-kratos".to_string()], + }, + + // MESSAGE QUEUES + TechnologyRule { + name: "Sarama".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["github.com/shopify/sarama".to_string(), "sarama".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["shopify/sarama".to_string()], + }, + + // TESTING + TechnologyRule { + name: "Testify".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["github.com/stretchr/testify".to_string(), "testify".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["stretchr/testify".to_string()], + }, + TechnologyRule { + name: "Ginkgo".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["github.com/onsi/ginkgo".to_string(), "ginkgo".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["onsi/ginkgo".to_string()], + }, + + // CLI FRAMEWORKS + TechnologyRule { + name: "Cobra".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["github.com/spf13/cobra".to_string(), "cobra".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["spf13/cobra".to_string()], + }, + + // CONFIG MANAGEMENT + TechnologyRule { + name: "Viper".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["github.com/spf13/viper".to_string(), "viper".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["spf13/viper".to_string()], + }, + ] +} \ No newline at end of file diff --git a/src/analyzer/frameworks/java.rs b/src/analyzer/frameworks/java.rs new file mode 100644 index 00000000..b64c130c --- /dev/null +++ b/src/analyzer/frameworks/java.rs @@ -0,0 +1,1062 @@ +use super::{LanguageFrameworkDetector, TechnologyRule, FrameworkDetectionUtils}; +use crate::analyzer::{DetectedTechnology, DetectedLanguage, TechnologyCategory, LibraryType}; +use crate::error::Result; + +pub struct JavaFrameworkDetector; + +impl LanguageFrameworkDetector for JavaFrameworkDetector { + fn detect_frameworks(&self, language: &DetectedLanguage) -> Result> { + let rules = get_jvm_technology_rules(); + + // Combine main and dev dependencies for comprehensive detection + let all_deps: Vec = language.main_dependencies.iter() + .chain(language.dev_dependencies.iter()) + .cloned() + .collect(); + + let technologies = FrameworkDetectionUtils::detect_technologies_by_dependencies( + &rules, &all_deps, language.confidence + ); + + Ok(technologies) + } + + fn supported_languages(&self) -> Vec<&'static str> { + vec!["Java", "Kotlin", "Java/Kotlin"] + } +} + +/// Java technology detection rules with comprehensive framework coverage +fn get_jvm_technology_rules() -> Vec { + vec![ + // SPRING ECOSYSTEM - COMPREHENSIVE COVERAGE + TechnologyRule { + name: "Spring Boot".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["spring-boot".to_string(), "org.springframework.boot".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["spring".to_string()], + }, + TechnologyRule { + name: "Spring Framework".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["spring-context".to_string(), "org.springframework".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["spring".to_string()], + }, + TechnologyRule { + name: "Spring Data".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["spring-data".to_string(), "org.springframework.data".to_string(), "spring-data-jpa".to_string(), "spring-data-mongodb".to_string(), "spring-data-redis".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Security".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["spring-security".to_string(), "org.springframework.security".to_string(), "spring-security-core".to_string(), "spring-security-oauth2".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Cloud".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["spring-cloud".to_string(), "org.springframework.cloud".to_string()], + requires: vec!["Spring Boot".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Cloud Gateway".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["spring-cloud-gateway".to_string(), "spring-cloud-starter-gateway".to_string()], + requires: vec!["Spring Cloud".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Cloud Config".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["spring-cloud-config".to_string(), "spring-cloud-starter-config".to_string()], + requires: vec!["Spring Cloud".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Cloud Netflix".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["spring-cloud-netflix".to_string(), "spring-cloud-starter-netflix-eureka".to_string(), "spring-cloud-starter-netflix-hystrix".to_string()], + requires: vec!["Spring Cloud".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring WebFlux".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["spring-webflux".to_string(), "org.springframework.webflux".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring MVC".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["spring-webmvc".to_string(), "spring-web".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Batch".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["spring-batch".to_string(), "org.springframework.batch".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring Integration".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["spring-integration".to_string(), "org.springframework.integration".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spring AOP".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["spring-aop".to_string(), "org.springframework.aop".to_string()], + requires: vec!["Spring Framework".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // MICROSERVICES FRAMEWORKS + TechnologyRule { + name: "Quarkus".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["quarkus".to_string(), "io.quarkus".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Micronaut".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["micronaut".to_string(), "io.micronaut".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Helidon".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["helidon".to_string(), "io.helidon".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Vert.x".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["vertx".to_string(), "io.vertx".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["eclipse vert.x".to_string(), "vertx".to_string()], + }, + + // TRADITIONAL FRAMEWORKS + TechnologyRule { + name: "Struts".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["struts".to_string(), "org.apache.struts".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["apache struts".to_string()], + }, + TechnologyRule { + name: "JSF".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.85, + dependency_patterns: vec!["jsf".to_string(), "javax.faces".to_string(), "jakarta.faces".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["javaserver faces".to_string()], + }, + + // LIGHTWEIGHT FRAMEWORKS + TechnologyRule { + name: "Dropwizard".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["dropwizard".to_string(), "io.dropwizard".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Spark Java".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["spark-core".to_string(), "com.sparkjava".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["spark".to_string()], + }, + TechnologyRule { + name: "Javalin".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["javalin".to_string(), "io.javalin".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Ratpack".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["ratpack".to_string(), "io.ratpack".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Ninja Framework".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["ninja".to_string(), "org.ninjaframework".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["ninja".to_string()], + }, + TechnologyRule { + name: "Blade".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["blade".to_string(), "com.bladejava".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // PLAY FRAMEWORK + TechnologyRule { + name: "Play Framework".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["play".to_string(), "com.typesafe.play".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["play".to_string()], + }, + + // ORM/DATABASE - EXPANDED + TechnologyRule { + name: "Hibernate".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["hibernate".to_string(), "org.hibernate".to_string(), "hibernate-core".to_string(), "hibernate-entitymanager".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["hibernate orm".to_string()], + }, + TechnologyRule { + name: "MyBatis".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["mybatis".to_string(), "org.mybatis".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "JOOQ".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["jooq".to_string(), "org.jooq".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "JPA".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["javax.persistence".to_string(), "jakarta.persistence".to_string(), "jpa".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["java persistence api".to_string()], + }, + TechnologyRule { + name: "EclipseLink".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["eclipselink".to_string(), "org.eclipse.persistence".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Apache OpenJPA".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["openjpa".to_string(), "org.apache.openjpa".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["openjpa".to_string()], + }, + TechnologyRule { + name: "QueryDSL".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["querydsl".to_string(), "com.querydsl".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "JDBI".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["jdbi".to_string(), "org.jdbi".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // DATABASE DRIVERS - CRITICAL FOR INFRASTRUCTURE + TechnologyRule { + name: "MySQL Connector".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["mysql-connector-java".to_string(), "com.mysql".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["mysql".to_string()], + }, + TechnologyRule { + name: "PostgreSQL Driver".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["postgresql".to_string(), "org.postgresql".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["postgres".to_string()], + }, + TechnologyRule { + name: "MongoDB Driver".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["mongodb-driver".to_string(), "org.mongodb".to_string(), "mongo-java-driver".to_string(), "spring-boot-starter-data-mongodb".to_string(), "spring-data-mongodb".to_string(), "spring-boot-starter-data-mongodb-reactive".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["mongodb".to_string()], + }, + TechnologyRule { + name: "Redis Jedis".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["jedis".to_string(), "redis.clients".to_string(), "spring-boot-starter-data-redis".to_string(), "spring-data-redis".to_string(), "lettuce-core".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["redis".to_string()], + }, + TechnologyRule { + name: "H2 Database".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["com.h2database".to_string(), "h2database".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Apache Derby".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["derby".to_string(), "org.apache.derby".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["derby".to_string()], + }, + TechnologyRule { + name: "SQLite JDBC".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["sqlite-jdbc".to_string(), "org.xerial".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["sqlite".to_string()], + }, + TechnologyRule { + name: "Oracle JDBC".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["ojdbc".to_string(), "com.oracle.database.jdbc".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["oracle".to_string()], + }, + TechnologyRule { + name: "SQL Server JDBC".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["mssql-jdbc".to_string(), "com.microsoft.sqlserver".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["sqlserver".to_string()], + }, + + // ENTERPRISE JAVA + TechnologyRule { + name: "Jakarta EE".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["jakarta.".to_string(), "jakarta-ee".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["java ee".to_string()], + }, + + // BUILD TOOLS + TechnologyRule { + name: "Maven".to_string(), + category: TechnologyCategory::BuildTool, + confidence: 0.80, + dependency_patterns: vec!["maven".to_string(), "org.apache.maven".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["apache maven".to_string()], + }, + TechnologyRule { + name: "Gradle".to_string(), + category: TechnologyCategory::BuildTool, + confidence: 0.80, + dependency_patterns: vec!["gradle".to_string(), "org.gradle".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TESTING + TechnologyRule { + name: "JUnit".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["junit".to_string(), "org.junit".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "TestNG".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["testng".to_string(), "org.testng".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Mockito".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.80, + dependency_patterns: vec!["mockito".to_string(), "org.mockito".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // REACTIVE FRAMEWORKS + TechnologyRule { + name: "Reactor".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["reactor".to_string(), "io.projectreactor".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["project reactor".to_string()], + }, + TechnologyRule { + name: "RxJava".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["rxjava".to_string(), "io.reactivex".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "RSocket".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["rsocket".to_string(), "io.rsocket".to_string(), "rsocket-core".to_string(), "rsocket-transport-netty".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // KOTLIN SPECIFIC + TechnologyRule { + name: "Ktor".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["ktor".to_string(), "io.ktor".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // MESSAGE BROKERS & MESSAGING (Critical for infrastructure) + TechnologyRule { + name: "Apache Kafka".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["kafka".to_string(), "org.apache.kafka".to_string(), "kafka-clients".to_string(), "spring-kafka".to_string(), "reactor-kafka".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["kafka".to_string()], + }, + TechnologyRule { + name: "RabbitMQ".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["amqp-client".to_string(), "com.rabbitmq".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["rabbitmq".to_string()], + }, + TechnologyRule { + name: "Apache ActiveMQ".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["activemq".to_string(), "org.apache.activemq".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["activemq".to_string()], + }, + TechnologyRule { + name: "Apache Pulsar".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["pulsar-client".to_string(), "org.apache.pulsar".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["pulsar".to_string()], + }, + + // SEARCH ENGINES (Critical for data infrastructure) + TechnologyRule { + name: "Elasticsearch".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["elasticsearch".to_string(), "org.elasticsearch".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["elastic".to_string()], + }, + TechnologyRule { + name: "Apache Solr".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["solr".to_string(), "org.apache.solr".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["solr".to_string()], + }, + TechnologyRule { + name: "Apache Lucene".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["lucene".to_string(), "org.apache.lucene".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["lucene".to_string()], + }, + + // CACHING (Critical for performance) + TechnologyRule { + name: "Hazelcast".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["hazelcast".to_string(), "com.hazelcast".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Apache Ignite".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["ignite".to_string(), "org.apache.ignite".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["ignite".to_string()], + }, + TechnologyRule { + name: "EhCache".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["ehcache".to_string(), "org.ehcache".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Caffeine".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["caffeine".to_string(), "com.github.ben-manes.caffeine".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // SECURITY FRAMEWORKS (Critical for enterprise) + TechnologyRule { + name: "Apache Shiro".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["shiro".to_string(), "org.apache.shiro".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["shiro".to_string()], + }, + TechnologyRule { + name: "Bouncy Castle".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["bcprov".to_string(), "org.bouncycastle".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Keycloak".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["keycloak".to_string(), "org.keycloak".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Jasypt".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["jasypt".to_string(), "org.jasypt".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // WEB SERVERS & APPLICATION SERVERS (Critical for deployment) + TechnologyRule { + name: "Apache Tomcat".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["tomcat".to_string(), "org.apache.tomcat".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["tomcat".to_string()], + }, + TechnologyRule { + name: "Jetty".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["jetty".to_string(), "org.eclipse.jetty".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["eclipse jetty".to_string()], + }, + TechnologyRule { + name: "Undertow".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["undertow".to_string(), "io.undertow".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Netty".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["netty".to_string(), "io.netty".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // HTTP CLIENTS (Important for integration) + TechnologyRule { + name: "Apache HttpClient".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["httpclient".to_string(), "org.apache.httpcomponents".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["httpclient".to_string()], + }, + TechnologyRule { + name: "OkHttp".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["okhttp".to_string(), "com.squareup.okhttp3".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Retrofit".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["retrofit".to_string(), "com.squareup.retrofit2".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // JSON/XML PROCESSING (Critical for APIs) + TechnologyRule { + name: "Jackson".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["jackson".to_string(), "com.fasterxml.jackson".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Gson".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["gson".to_string(), "com.google.gson".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Apache JAXB".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["jaxb".to_string(), "javax.xml.bind".to_string(), "jakarta.xml.bind".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["jaxb".to_string()], + }, + + // LOGGING (Critical for monitoring) + TechnologyRule { + name: "Logback".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["logback".to_string(), "ch.qos.logback".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Log4j".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["log4j".to_string(), "org.apache.logging.log4j".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["apache log4j".to_string()], + }, + TechnologyRule { + name: "SLF4J".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["slf4j".to_string(), "org.slf4j".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // MONITORING & METRICS (Critical for production) + TechnologyRule { + name: "Micrometer".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["micrometer".to_string(), "io.micrometer".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Prometheus".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["prometheus".to_string(), "io.prometheus".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Actuator".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["spring-boot-starter-actuator".to_string(), "actuator".to_string()], + requires: vec!["Spring Boot".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // VALIDATION (Important for data integrity) + TechnologyRule { + name: "Bean Validation".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["validation-api".to_string(), "javax.validation".to_string(), "jakarta.validation".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["jsr303".to_string(), "jsr380".to_string()], + }, + TechnologyRule { + name: "Hibernate Validator".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["hibernate-validator".to_string(), "org.hibernate.validator".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // ADDITIONAL TESTING FRAMEWORKS + TechnologyRule { + name: "Selenium".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.90, + dependency_patterns: vec!["selenium".to_string(), "org.seleniumhq.selenium".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Cucumber".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["cucumber".to_string(), "io.cucumber".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "WireMock".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["wiremock".to_string(), "com.github.tomakehurst".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "REST Assured".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["rest-assured".to_string(), "io.rest-assured".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Testcontainers".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.90, + dependency_patterns: vec!["testcontainers".to_string(), "org.testcontainers".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // BIG DATA & ANALYTICS (Important for enterprise) + TechnologyRule { + name: "Apache Spark".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["spark".to_string(), "org.apache.spark".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["spark".to_string()], + }, + TechnologyRule { + name: "Apache Flink".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["flink".to_string(), "org.apache.flink".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["flink".to_string()], + }, + TechnologyRule { + name: "Apache Storm".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["storm".to_string(), "org.apache.storm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["storm".to_string()], + }, + + // UTILITIES & TOOLS + TechnologyRule { + name: "Lombok".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["lombok".to_string(), "org.projectlombok".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "MapStruct".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["mapstruct".to_string(), "org.mapstruct".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Google Guava".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["guava".to_string(), "com.google.guava".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["guava".to_string()], + }, + TechnologyRule { + name: "Apache Commons".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.75, + dependency_patterns: vec!["commons-".to_string(), "org.apache.commons".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["commons".to_string()], + }, + ] +} \ No newline at end of file diff --git a/src/analyzer/frameworks/javascript.rs b/src/analyzer/frameworks/javascript.rs new file mode 100644 index 00000000..9e161ee6 --- /dev/null +++ b/src/analyzer/frameworks/javascript.rs @@ -0,0 +1,853 @@ +use super::{LanguageFrameworkDetector, TechnologyRule, FrameworkDetectionUtils}; +use crate::analyzer::{DetectedTechnology, DetectedLanguage, TechnologyCategory, LibraryType}; +use crate::error::Result; +use std::path::Path; + +pub struct JavaScriptFrameworkDetector; + +impl LanguageFrameworkDetector for JavaScriptFrameworkDetector { + fn detect_frameworks(&self, language: &DetectedLanguage) -> Result> { + let rules = get_js_technology_rules(); + + // Combine main and dev dependencies for comprehensive detection + let all_deps: Vec = language.main_dependencies.iter() + .chain(language.dev_dependencies.iter()) + .cloned() + .collect(); + + let mut technologies = FrameworkDetectionUtils::detect_technologies_by_dependencies( + &rules, &all_deps, language.confidence + ); + + // Enhanced detection: analyze actual source files for usage patterns + if let Some(enhanced_techs) = detect_technologies_from_source_files(language, &rules) { + // Merge with dependency-based detection, preferring higher confidence scores + for enhanced_tech in enhanced_techs { + if let Some(existing) = technologies.iter_mut().find(|t| t.name == enhanced_tech.name) { + // Use higher confidence between dependency and source file analysis + if enhanced_tech.confidence > existing.confidence { + existing.confidence = enhanced_tech.confidence; + } + } else { + // Add new technology found in source files + technologies.push(enhanced_tech); + } + } + } + + Ok(technologies) + } + + fn supported_languages(&self) -> Vec<&'static str> { + vec!["JavaScript", "TypeScript", "JavaScript/TypeScript"] + } +} + +/// Enhanced detection that analyzes actual source files for technology usage patterns +fn detect_technologies_from_source_files(language: &DetectedLanguage, _rules: &[TechnologyRule]) -> Option> { + use std::fs; + + let mut detected = Vec::new(); + + // Analyze files for usage patterns + for file_path in &language.files { + if let Ok(content) = fs::read_to_string(file_path) { + // Analyze Drizzle ORM usage patterns + if let Some(drizzle_confidence) = analyze_drizzle_usage(&content, file_path) { + detected.push(DetectedTechnology { + name: "Drizzle ORM".to_string(), + version: None, + category: TechnologyCategory::Database, + confidence: drizzle_confidence, + requires: vec![], + conflicts_with: vec![], + is_primary: false, + }); + } + + // Analyze Prisma usage patterns + if let Some(prisma_confidence) = analyze_prisma_usage(&content, file_path) { + detected.push(DetectedTechnology { + name: "Prisma".to_string(), + version: None, + category: TechnologyCategory::Database, + confidence: prisma_confidence, + requires: vec![], + conflicts_with: vec![], + is_primary: false, + }); + } + + // Analyze Encore usage patterns + if let Some(encore_confidence) = analyze_encore_usage(&content, file_path) { + detected.push(DetectedTechnology { + name: "Encore".to_string(), + version: None, + category: TechnologyCategory::BackendFramework, + confidence: encore_confidence, + requires: vec![], + conflicts_with: vec![], + is_primary: true, + }); + } + + // Analyze Tanstack Start usage patterns + if let Some(tanstack_confidence) = analyze_tanstack_start_usage(&content, file_path) { + detected.push(DetectedTechnology { + name: "Tanstack Start".to_string(), + version: None, + category: TechnologyCategory::MetaFramework, + confidence: tanstack_confidence, + requires: vec!["React".to_string()], + conflicts_with: vec!["Next.js".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], + is_primary: true, + }); + } + } + } + + if detected.is_empty() { + None + } else { + Some(detected) + } +} + +/// Analyzes Drizzle ORM usage patterns in source files +fn analyze_drizzle_usage(content: &str, file_path: &Path) -> Option { + let file_name = file_path.file_name()?.to_string_lossy(); + let mut confidence: f32 = 0.0; + + // High confidence indicators + if content.contains("drizzle-orm") { + confidence += 0.3; + } + + // Schema file patterns (very high confidence) + if file_name.contains("schema") || file_name.contains("db.ts") || file_name.contains("database") { + if content.contains("pgTable") || content.contains("mysqlTable") || content.contains("sqliteTable") { + confidence += 0.4; + } + if content.contains("pgEnum") || content.contains("relations") { + confidence += 0.3; + } + } + + // Drizzle-specific imports + if content.contains("from 'drizzle-orm/pg-core'") || + content.contains("from 'drizzle-orm/mysql-core'") || + content.contains("from 'drizzle-orm/sqlite-core'") { + confidence += 0.3; + } + + // Drizzle query patterns + if content.contains("db.select()") || content.contains("db.insert()") || + content.contains("db.update()") || content.contains("db.delete()") { + confidence += 0.2; + } + + // Configuration patterns + if content.contains("drizzle(") && (content.contains("connectionString") || content.contains("postgres(")) { + confidence += 0.2; + } + + // Migration patterns + if content.contains("drizzle.config") || file_name.contains("migrate") { + confidence += 0.2; + } + + // Prepared statements + if content.contains(".prepare()") && content.contains("drizzle") { + confidence += 0.1; + } + + if confidence > 0.0 { + Some(confidence.min(1.0_f32)) + } else { + None + } +} + +/// Analyzes Prisma usage patterns in source files +fn analyze_prisma_usage(content: &str, file_path: &Path) -> Option { + let file_name = file_path.file_name()?.to_string_lossy(); + let mut confidence: f32 = 0.0; + let mut has_prisma_import = false; + + // Only detect Prisma if there are actual Prisma-specific imports + if content.contains("@prisma/client") || content.contains("from '@prisma/client'") { + confidence += 0.4; + has_prisma_import = true; + } + + // Prisma schema files (very specific) + if file_name == "schema.prisma" { + if content.contains("model ") || content.contains("generator ") || content.contains("datasource ") { + confidence += 0.6; + has_prisma_import = true; + } + } + + // Only check for client usage if we have confirmed Prisma imports + if has_prisma_import { + // Prisma client instantiation (very specific) + if content.contains("new PrismaClient") || content.contains("PrismaClient()") { + confidence += 0.3; + } + + // Prisma-specific query patterns (only if we know it's Prisma) + if content.contains("prisma.") && ( + content.contains(".findUnique(") || + content.contains(".findFirst(") || + content.contains(".upsert(") || + content.contains(".$connect()") || + content.contains(".$disconnect()") + ) { + confidence += 0.2; + } + } + + // Only return confidence if we have actual Prisma indicators + if confidence > 0.0 && has_prisma_import { + Some(confidence.min(1.0_f32)) + } else { + None + } +} + +/// Analyzes Encore usage patterns in source files +fn analyze_encore_usage(content: &str, file_path: &Path) -> Option { + let file_name = file_path.file_name()?.to_string_lossy(); + let mut confidence: f32 = 0.0; + + // Skip generated files (like Encore client code) + if content.contains("// Code generated by the Encore") || content.contains("DO NOT EDIT") { + return None; + } + + // Skip client-only files (generated or consumption only) + if file_name.contains("client.ts") || file_name.contains("client.js") { + return None; + } + + // Only detect Encore when there are actual service development patterns + let mut has_service_patterns = false; + + // Service definition files (high confidence for actual Encore development) + if file_name.contains("encore.service") || file_name.contains("service.ts") { + confidence += 0.4; + has_service_patterns = true; + } + + // API endpoint definitions (indicates actual Encore service development) + if content.contains("encore.dev/api") && (content.contains("export") || content.contains("api.")) { + confidence += 0.4; + has_service_patterns = true; + } + + // Database service patterns (actual Encore service code) + if content.contains("SQLDatabase") && content.contains("encore.dev") { + confidence += 0.3; + has_service_patterns = true; + } + + // Secret configuration (actual Encore service code) + if content.contains("secret(") && content.contains("encore.dev/config") { + confidence += 0.3; + has_service_patterns = true; + } + + // PubSub service patterns (actual Encore service code) + if content.contains("Topic") && content.contains("encore.dev/pubsub") { + confidence += 0.3; + has_service_patterns = true; + } + + // Cron job patterns (actual Encore service code) + if content.contains("cron") && content.contains("encore.dev") { + confidence += 0.2; + has_service_patterns = true; + } + + // Only return confidence if we have actual service development patterns + if confidence > 0.0 && has_service_patterns { + Some(confidence.min(1.0_f32)) + } else { + None + } +} + +/// Analyzes Tanstack Start usage patterns in source files +fn analyze_tanstack_start_usage(content: &str, file_path: &Path) -> Option { + let file_name = file_path.file_name()?.to_string_lossy(); + let mut confidence: f32 = 0.0; + let mut has_start_patterns = false; + + // Configuration files (high confidence) + if file_name == "app.config.ts" || file_name == "app.config.js" { + if content.contains("@tanstack/react-start") || content.contains("tanstack") { + confidence += 0.5; + has_start_patterns = true; + } + } + + // Router configuration patterns (very high confidence) + if file_name.contains("router.") && (file_name.ends_with(".ts") || file_name.ends_with(".tsx")) { + if content.contains("createRouter") && content.contains("@tanstack/react-router") { + confidence += 0.4; + has_start_patterns = true; + } + if content.contains("routeTree") { + confidence += 0.2; + has_start_patterns = true; + } + } + + // Server entry point patterns + if file_name == "ssr.tsx" || file_name == "ssr.ts" { + if content.contains("createStartHandler") || content.contains("@tanstack/react-start/server") { + confidence += 0.5; + has_start_patterns = true; + } + } + + // Client entry point patterns + if file_name == "client.tsx" || file_name == "client.ts" { + if content.contains("StartClient") && content.contains("@tanstack/react-start") { + confidence += 0.5; + has_start_patterns = true; + } + if content.contains("hydrateRoot") && content.contains("createRouter") { + confidence += 0.3; + has_start_patterns = true; + } + } + + // Root route patterns (in app/routes/__root.tsx) + if file_name == "__root.tsx" || file_name == "__root.ts" { + if content.contains("createRootRoute") && content.contains("@tanstack/react-router") { + confidence += 0.4; + has_start_patterns = true; + } + if content.contains("HeadContent") && content.contains("Scripts") { + confidence += 0.3; + has_start_patterns = true; + } + } + + // Route files with createFileRoute + if file_path.to_string_lossy().contains("routes/") { + if content.contains("createFileRoute") && content.contains("@tanstack/react-router") { + confidence += 0.3; + has_start_patterns = true; + } + } + + // Server functions (key Tanstack Start feature) + if content.contains("createServerFn") && content.contains("@tanstack/react-start") { + confidence += 0.4; + has_start_patterns = true; + } + + // Import patterns specific to Tanstack Start + if content.contains("from '@tanstack/react-start'") { + confidence += 0.3; + has_start_patterns = true; + } + + // Vinxi configuration patterns + if file_name == "vinxi.config.ts" || file_name == "vinxi.config.js" { + confidence += 0.2; + has_start_patterns = true; + } + + // Only return confidence if we have actual Tanstack Start patterns + if confidence > 0.0 && has_start_patterns { + Some(confidence.min(1.0_f32)) + } else { + None + } +} + +/// JavaScript/TypeScript technology detection rules with proper classification +fn get_js_technology_rules() -> Vec { + vec![ + // META-FRAMEWORKS (Mutually Exclusive) + TechnologyRule { + name: "Next.js".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["next".to_string()], + requires: vec!["React".to_string()], + conflicts_with: vec!["Tanstack Start".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], + is_primary_indicator: true, + alternative_names: vec!["nextjs".to_string()], + }, + TechnologyRule { + name: "Tanstack Start".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["@tanstack/react-start".to_string()], + requires: vec!["React".to_string()], + conflicts_with: vec!["Next.js".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string()], + is_primary_indicator: true, + alternative_names: vec!["tanstack-start".to_string(), "TanStack Start".to_string()], + }, + TechnologyRule { + name: "React Router v7".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["react-router".to_string(), "react-dom".to_string(), "react-router-dom".to_string()], + requires: vec!["React".to_string()], + conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string(), "React Native".to_string(), "Expo".to_string()], + is_primary_indicator: true, + alternative_names: vec!["remix".to_string(), "react-router".to_string()], + }, + TechnologyRule { + name: "SvelteKit".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["@sveltejs/kit".to_string()], + requires: vec!["Svelte".to_string()], + conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "React Router v7".to_string(), "Nuxt.js".to_string()], + is_primary_indicator: true, + alternative_names: vec!["svelte-kit".to_string()], + }, + TechnologyRule { + name: "Nuxt.js".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["nuxt".to_string(), "@nuxt/core".to_string()], + requires: vec!["Vue.js".to_string()], + conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "React Router v7".to_string(), "SvelteKit".to_string()], + is_primary_indicator: true, + alternative_names: vec!["nuxtjs".to_string()], + }, + TechnologyRule { + name: "Astro".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["astro".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "SolidStart".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.95, + dependency_patterns: vec!["solid-start".to_string()], + requires: vec!["SolidJS".to_string()], + conflicts_with: vec!["Next.js".to_string(), "Tanstack Start".to_string(), "React Router v7".to_string(), "SvelteKit".to_string()], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // MOBILE FRAMEWORKS (React Native/Expo) + TechnologyRule { + name: "React Native".to_string(), + category: TechnologyCategory::FrontendFramework, + confidence: 0.95, + dependency_patterns: vec!["react-native".to_string()], + requires: vec!["React".to_string()], + conflicts_with: vec!["Next.js".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string(), "Tanstack Start".to_string()], + is_primary_indicator: true, + alternative_names: vec!["reactnative".to_string()], + }, + TechnologyRule { + name: "Expo".to_string(), + category: TechnologyCategory::MetaFramework, + confidence: 0.98, + dependency_patterns: vec!["expo".to_string(), "expo-router".to_string(), "@expo/vector-icons".to_string()], + requires: vec!["React Native".to_string()], + conflicts_with: vec!["Next.js".to_string(), "React Router v7".to_string(), "SvelteKit".to_string(), "Nuxt.js".to_string(), "Tanstack Start".to_string()], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // FRONTEND FRAMEWORKS (Provide structure) + TechnologyRule { + name: "Angular".to_string(), + category: TechnologyCategory::FrontendFramework, + confidence: 0.90, + dependency_patterns: vec!["@angular/core".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["angular".to_string()], + }, + TechnologyRule { + name: "Svelte".to_string(), + category: TechnologyCategory::FrontendFramework, + confidence: 0.95, + dependency_patterns: vec!["svelte".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, // SvelteKit would be primary + alternative_names: vec![], + }, + + // UI LIBRARIES (Not frameworks!) + TechnologyRule { + name: "React".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.90, + dependency_patterns: vec!["react".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, // Meta-frameworks using React would be primary + alternative_names: vec!["reactjs".to_string()], + }, + TechnologyRule { + name: "Vue.js".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.90, + dependency_patterns: vec!["vue".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["vuejs".to_string()], + }, + TechnologyRule { + name: "SolidJS".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.95, + dependency_patterns: vec!["solid-js".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["solid".to_string()], + }, + TechnologyRule { + name: "HTMX".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.95, + dependency_patterns: vec!["htmx.org".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["htmx".to_string()], + }, + + // BACKEND FRAMEWORKS + TechnologyRule { + name: "Express.js".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["express".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["express".to_string()], + }, + TechnologyRule { + name: "Fastify".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["fastify".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Nest.js".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["@nestjs/core".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["nestjs".to_string()], + }, + TechnologyRule { + name: "Hono".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["hono".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Elysia".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["elysia".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Encore".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["encore.dev".to_string(), "encore".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["encore-ts-starter".to_string()], + }, + + // BUILD TOOLS (Not frameworks!) + TechnologyRule { + name: "Vite".to_string(), + category: TechnologyCategory::BuildTool, + confidence: 0.80, + dependency_patterns: vec!["vite".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Webpack".to_string(), + category: TechnologyCategory::BuildTool, + confidence: 0.80, + dependency_patterns: vec!["webpack".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // DATABASE/ORM (Important for Docker/infrastructure setup, migrations, etc.) + TechnologyRule { + name: "Prisma".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["prisma".to_string(), "@prisma/client".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Drizzle ORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["drizzle-orm".to_string(), "drizzle-kit".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["drizzle".to_string()], + }, + TechnologyRule { + name: "Sequelize".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["sequelize".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "TypeORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["typeorm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "MikroORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["@mikro-orm/core".to_string(), "@mikro-orm/postgresql".to_string(), "@mikro-orm/mysql".to_string(), "@mikro-orm/sqlite".to_string(), "@mikro-orm/mongodb".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["mikro-orm".to_string()], + }, + TechnologyRule { + name: "Mongoose".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["mongoose".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Typegoose".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["@typegoose/typegoose".to_string()], + requires: vec!["Mongoose".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Objection.js".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["objection".to_string()], + requires: vec!["Knex.js".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["objectionjs".to_string()], + }, + TechnologyRule { + name: "Bookshelf".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["bookshelf".to_string()], + requires: vec!["Knex.js".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Waterline".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["waterline".to_string(), "sails-mysql".to_string(), "sails-postgresql".to_string(), "sails-disk".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Knex.js".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["knex".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["knexjs".to_string()], + }, + + // RUNTIMES (Important for IaC - determines base images, package managers) + TechnologyRule { + name: "Node.js".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.90, + dependency_patterns: vec!["node".to_string()], // This will need file-based detection + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["nodejs".to_string()], + }, + TechnologyRule { + name: "Bun".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.95, + dependency_patterns: vec!["bun".to_string()], // Look for bun in devDependencies or bun.lockb file + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Deno".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.95, + dependency_patterns: vec!["@deno/core".to_string(), "deno".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "WinterJS".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.95, + dependency_patterns: vec!["winterjs".to_string(), "winter-js".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["winter.js".to_string()], + }, + TechnologyRule { + name: "Cloudflare Workers".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.90, + dependency_patterns: vec!["@cloudflare/workers-types".to_string(), "@cloudflare/vitest-pool-workers".to_string(), "wrangler".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["cloudflare-workers".to_string()], + }, + TechnologyRule { + name: "Vercel Edge Runtime".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.90, + dependency_patterns: vec!["@vercel/edge-runtime".to_string(), "@edge-runtime/vm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["vercel-edge".to_string()], + }, + TechnologyRule { + name: "Hermes".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["hermes-engine".to_string()], + requires: vec!["React Native".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Electron".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.95, + dependency_patterns: vec!["electron".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Tauri".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.95, + dependency_patterns: vec!["@tauri-apps/cli".to_string(), "@tauri-apps/api".to_string()], + requires: vec![], + conflicts_with: vec!["Electron".to_string()], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "QuickJS".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["quickjs".to_string(), "quickjs-emscripten".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TESTING (Keep minimal - only major frameworks that affect build process) + TechnologyRule { + name: "Jest".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["jest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Vitest".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["vitest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + ] +} \ No newline at end of file diff --git a/src/analyzer/frameworks/mod.rs b/src/analyzer/frameworks/mod.rs new file mode 100644 index 00000000..4ffa4ca5 --- /dev/null +++ b/src/analyzer/frameworks/mod.rs @@ -0,0 +1,214 @@ +pub mod rust; +pub mod javascript; +pub mod python; +pub mod go; +pub mod java; + +use crate::analyzer::{DetectedTechnology, DetectedLanguage}; +use crate::error::Result; +use std::collections::HashMap; + +/// Common interface for language-specific framework detection +pub trait LanguageFrameworkDetector { + /// Detect frameworks for a specific language + fn detect_frameworks(&self, language: &DetectedLanguage) -> Result>; + + /// Get the supported language name(s) for this detector + fn supported_languages(&self) -> Vec<&'static str>; +} + +/// Technology detection rules with proper classification and relationships +#[derive(Clone, Debug)] +pub struct TechnologyRule { + pub name: String, + pub category: crate::analyzer::TechnologyCategory, + pub confidence: f32, + pub dependency_patterns: Vec, + /// Dependencies this technology requires (e.g., Next.js requires React) + pub requires: Vec, + /// Technologies that conflict with this one (mutually exclusive) + pub conflicts_with: Vec, + /// Whether this technology typically drives the architecture + pub is_primary_indicator: bool, + /// Alternative names for this technology + pub alternative_names: Vec, +} + +/// Shared utilities for framework detection across languages +pub struct FrameworkDetectionUtils; + +impl FrameworkDetectionUtils { + /// Generic technology detection based on dependency patterns + pub fn detect_technologies_by_dependencies( + rules: &[TechnologyRule], + dependencies: &[String], + base_confidence: f32, + ) -> Vec { + let mut technologies = Vec::new(); + + // Debug logging for Tanstack Start detection + let tanstack_deps: Vec<_> = dependencies.iter() + .filter(|dep| dep.contains("tanstack") || dep.contains("vinxi")) + .collect(); + if !tanstack_deps.is_empty() { + log::debug!("Found potential Tanstack dependencies: {:?}", tanstack_deps); + } + + for rule in rules { + let mut matches = 0; + let total_patterns = rule.dependency_patterns.len(); + + if total_patterns == 0 { + continue; + } + + for pattern in &rule.dependency_patterns { + let matching_deps: Vec<_> = dependencies.iter() + .filter(|dep| Self::matches_pattern(dep, pattern)) + .collect(); + + if !matching_deps.is_empty() { + matches += 1; + + // Debug logging for Tanstack Start specifically + if rule.name.contains("Tanstack") { + log::debug!("Tanstack Start: Pattern '{}' matched dependencies: {:?}", pattern, matching_deps); + } + } + } + + // Calculate confidence based on pattern matches and base language confidence + if matches > 0 { + let pattern_confidence = matches as f32 / total_patterns as f32; + // Use additive approach instead of multiplicative to avoid extremely low scores + // Base confidence provides a floor, pattern confidence provides the scaling + let final_confidence = (rule.confidence * pattern_confidence + base_confidence * 0.1).min(1.0); + + // Debug logging for Tanstack Start detection + if rule.name.contains("Tanstack") { + log::debug!("Tanstack Start detected with {} matches out of {} patterns, confidence: {:.2}", + matches, total_patterns, final_confidence); + } + + technologies.push(DetectedTechnology { + name: rule.name.clone(), + version: None, // TODO: Extract version from dependencies + category: rule.category.clone(), + confidence: final_confidence, + requires: rule.requires.clone(), + conflicts_with: rule.conflicts_with.clone(), + is_primary: rule.is_primary_indicator, + }); + } else if rule.name.contains("Tanstack") { + // Debug logging when Tanstack Start is not detected + log::debug!("Tanstack Start not detected - no patterns matched. Available dependencies: {:?}", + dependencies.iter().take(10).collect::>()); + } + } + + technologies + } + + /// Check if a dependency matches a pattern (supports wildcards) + pub fn matches_pattern(dependency: &str, pattern: &str) -> bool { + if pattern.contains('*') { + // Simple wildcard matching + let parts: Vec<&str> = pattern.split('*').collect(); + if parts.len() == 2 { + dependency.starts_with(parts[0]) && dependency.ends_with(parts[1]) + } else { + dependency.contains(&pattern.replace('*', "")) + } + } else { + dependency == pattern || dependency.contains(pattern) + } + } + + /// Resolves conflicts between mutually exclusive technologies + pub fn resolve_technology_conflicts(technologies: Vec) -> Vec { + let mut resolved = Vec::new(); + let mut name_to_tech: HashMap = HashMap::new(); + + // First pass: collect all technologies + for tech in technologies { + if let Some(existing) = name_to_tech.get(&tech.name) { + // Keep the one with higher confidence + if tech.confidence > existing.confidence { + name_to_tech.insert(tech.name.clone(), tech); + } + } else { + name_to_tech.insert(tech.name.clone(), tech); + } + } + + // Second pass: resolve conflicts + let all_techs: Vec<_> = name_to_tech.values().collect(); + let mut excluded_names = std::collections::HashSet::new(); + + for tech in &all_techs { + if excluded_names.contains(&tech.name) { + continue; + } + + // Check for conflicts + for conflict in &tech.conflicts_with { + if let Some(conflicting_tech) = name_to_tech.get(conflict) { + if tech.confidence > conflicting_tech.confidence { + excluded_names.insert(conflict.clone()); + log::info!("Excluding {} (confidence: {}) in favor of {} (confidence: {})", + conflict, conflicting_tech.confidence, tech.name, tech.confidence); + } else { + excluded_names.insert(tech.name.clone()); + log::info!("Excluding {} (confidence: {}) in favor of {} (confidence: {})", + tech.name, tech.confidence, conflict, conflicting_tech.confidence); + break; + } + } + } + } + + // Collect non-excluded technologies + for tech in name_to_tech.into_values() { + if !excluded_names.contains(&tech.name) { + resolved.push(tech); + } + } + + resolved + } + + /// Marks technologies that are primary drivers of the application architecture + pub fn mark_primary_technologies(mut technologies: Vec) -> Vec { + use crate::analyzer::TechnologyCategory; + + // Meta-frameworks are always primary + let mut has_meta_framework = false; + for tech in &mut technologies { + if matches!(tech.category, TechnologyCategory::MetaFramework) { + tech.is_primary = true; + has_meta_framework = true; + } + } + + // If no meta-framework, mark the highest confidence backend or frontend framework as primary + if !has_meta_framework { + let mut best_framework: Option = None; + let mut best_confidence = 0.0; + + for (i, tech) in technologies.iter().enumerate() { + if matches!(tech.category, TechnologyCategory::BackendFramework | TechnologyCategory::FrontendFramework) { + if tech.confidence > best_confidence { + best_confidence = tech.confidence; + best_framework = Some(i); + } + } + } + + if let Some(index) = best_framework { + technologies[index].is_primary = true; + } + } + + technologies + } +} \ No newline at end of file diff --git a/src/analyzer/frameworks/python.rs b/src/analyzer/frameworks/python.rs new file mode 100644 index 00000000..88f12c5b --- /dev/null +++ b/src/analyzer/frameworks/python.rs @@ -0,0 +1,818 @@ +use super::{LanguageFrameworkDetector, TechnologyRule, FrameworkDetectionUtils}; +use crate::analyzer::{DetectedTechnology, DetectedLanguage, TechnologyCategory, LibraryType}; +use crate::error::Result; + +pub struct PythonFrameworkDetector; + +impl LanguageFrameworkDetector for PythonFrameworkDetector { + fn detect_frameworks(&self, language: &DetectedLanguage) -> Result> { + let rules = get_python_technology_rules(); + + // Combine main and dev dependencies for comprehensive detection + let all_deps: Vec = language.main_dependencies.iter() + .chain(language.dev_dependencies.iter()) + .cloned() + .collect(); + + let technologies = FrameworkDetectionUtils::detect_technologies_by_dependencies( + &rules, &all_deps, language.confidence + ); + + Ok(technologies) + } + + fn supported_languages(&self) -> Vec<&'static str> { + vec!["Python"] + } +} + +/// Python technology detection rules with comprehensive framework coverage +fn get_python_technology_rules() -> Vec { + vec![ + // WEB FRAMEWORKS - Full Stack + TechnologyRule { + name: "Django".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["django".to_string(), "Django".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Django REST Framework".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["djangorestframework".to_string(), "rest_framework".to_string()], + requires: vec!["Django".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["DRF".to_string()], + }, + + // MICRO FRAMEWORKS + TechnologyRule { + name: "Flask".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["flask".to_string(), "Flask".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "FastAPI".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["fastapi".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Starlette".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["starlette".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Quart".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["quart".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Sanic".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["sanic".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Tornado".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["tornado".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Falcon".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["falcon".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Bottle".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["bottle".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "aiohttp".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["aiohttp".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "CherryPy".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["cherrypy".to_string(), "CherryPy".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Pyramid".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["pyramid".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "TurboGears".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["turbogears".to_string(), "tg".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["TG".to_string()], + }, + TechnologyRule { + name: "Web2py".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["web2py".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "BlueBream".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.85, + dependency_patterns: vec!["bluebream".to_string(), "zope.app".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["Zope3".to_string()], + }, + TechnologyRule { + name: "Hug".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["hug".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "BlackSheep".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["blacksheep".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Litestar".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.90, + dependency_patterns: vec!["litestar".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Muffin".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.85, + dependency_patterns: vec!["muffin".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // DATA SCIENCE FRAMEWORKS (Important for containerization/deployment) + TechnologyRule { + name: "Streamlit".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["streamlit".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Gradio".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["gradio".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Dash".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["dash".to_string(), "plotly-dash".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["Plotly Dash".to_string()], + }, + TechnologyRule { + name: "Reflex".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["reflex".to_string(), "pynecone".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["Pynecone".to_string()], + }, + TechnologyRule { + name: "Jupyter".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["jupyter".to_string(), "jupyterlab".to_string(), "notebook".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["JupyterLab".to_string()], + }, + + // DATABASE/ORM + TechnologyRule { + name: "SQLAlchemy".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["sqlalchemy".to_string(), "SQLAlchemy".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Peewee".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["peewee".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Tortoise ORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["tortoise-orm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["tortoise".to_string()], + }, + TechnologyRule { + name: "Django ORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.95, + dependency_patterns: vec!["django.db".to_string()], + requires: vec!["Django".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "SQLModel".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["sqlmodel".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Databases".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["databases".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Alembic".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["alembic".to_string()], + requires: vec!["SQLAlchemy".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Psycopg2".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["psycopg2".to_string(), "psycopg2-binary".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Asyncpg".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["asyncpg".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "PyMongo".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["pymongo".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Motor".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["motor".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Beanie".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["beanie".to_string()], + requires: vec!["Motor".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "MongoEngine".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["mongoengine".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Redis-py".to_string(), + category: TechnologyCategory::Database, + confidence: 0.85, + dependency_patterns: vec!["redis".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["redis-py".to_string()], + }, + TechnologyRule { + name: "Pydantic".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["pydantic".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Marshmallow".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["marshmallow".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // ASYNC FRAMEWORKS & UTILITIES + TechnologyRule { + name: "asyncio".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["asyncio".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "aiofiles".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["aiofiles".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // DATA SCIENCE LIBRARIES (Important for containerization/deployment) + TechnologyRule { + name: "NumPy".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["numpy".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Pandas".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["pandas".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Scikit-learn".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["scikit-learn".to_string(), "sklearn".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["sklearn".to_string()], + }, + TechnologyRule { + name: "TensorFlow".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["tensorflow".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "PyTorch".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["torch".to_string(), "pytorch".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["torch".to_string()], + }, + TechnologyRule { + name: "Matplotlib".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["matplotlib".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Plotly".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["plotly".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Seaborn".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["seaborn".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TASK QUEUES (Important for architecture) + TechnologyRule { + name: "Celery".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["celery".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "RQ".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["rq".to_string(), "redis-queue".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["Redis Queue".to_string()], + }, + TechnologyRule { + name: "Dramatiq".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["dramatiq".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Huey".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["huey".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TEMPLATE ENGINES + TechnologyRule { + name: "Jinja2".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["jinja2".to_string(), "Jinja2".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Mako".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["mako".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // AUTHENTICATION & SECURITY + TechnologyRule { + name: "Authlib".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["authlib".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Flask-Security".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["flask-security".to_string(), "flask-security-too".to_string()], + requires: vec!["Flask".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["Flask-Security-Too".to_string()], + }, + TechnologyRule { + name: "Django-allauth".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["django-allauth".to_string()], + requires: vec!["Django".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TESTING (Important for CI/CD) + TechnologyRule { + name: "pytest".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["pytest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "unittest".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.80, + dependency_patterns: vec!["unittest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Tox".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.80, + dependency_patterns: vec!["tox".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Nose".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.75, + dependency_patterns: vec!["nose".to_string(), "nose2".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["nose2".to_string()], + }, + TechnologyRule { + name: "Behave".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["behave".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Robot Framework".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["robotframework".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // WSGI/ASGI SERVERS (Critical for deployment) + TechnologyRule { + name: "Gunicorn".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["gunicorn".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Uvicorn".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["uvicorn".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Hypercorn".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["hypercorn".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Daphne".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["daphne".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Granian".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.85, + dependency_patterns: vec!["granian".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "uWSGI".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.80, + dependency_patterns: vec!["uwsgi".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Waitress".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.80, + dependency_patterns: vec!["waitress".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // PROCESS MANAGERS & DEPLOYMENT + TechnologyRule { + name: "Supervisor".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.80, + dependency_patterns: vec!["supervisor".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // API DOCUMENTATION & VALIDATION + TechnologyRule { + name: "Flask-RESTful".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["flask-restful".to_string()], + requires: vec!["Flask".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "Flask-RESTX".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["flask-restx".to_string()], + requires: vec!["Flask".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + ] +} \ No newline at end of file diff --git a/src/analyzer/frameworks/rust.rs b/src/analyzer/frameworks/rust.rs new file mode 100644 index 00000000..a82badeb --- /dev/null +++ b/src/analyzer/frameworks/rust.rs @@ -0,0 +1,244 @@ +use super::{LanguageFrameworkDetector, TechnologyRule, FrameworkDetectionUtils}; +use crate::analyzer::{DetectedTechnology, DetectedLanguage, TechnologyCategory, LibraryType}; +use crate::error::Result; + +pub struct RustFrameworkDetector; + +impl LanguageFrameworkDetector for RustFrameworkDetector { + fn detect_frameworks(&self, language: &DetectedLanguage) -> Result> { + let rules = get_rust_technology_rules(); + + // Combine main and dev dependencies for comprehensive detection + let all_deps: Vec = language.main_dependencies.iter() + .chain(language.dev_dependencies.iter()) + .cloned() + .collect(); + + let technologies = FrameworkDetectionUtils::detect_technologies_by_dependencies( + &rules, &all_deps, language.confidence + ); + + Ok(technologies) + } + + fn supported_languages(&self) -> Vec<&'static str> { + vec!["Rust"] + } +} + +/// Rust technology detection rules with comprehensive framework coverage +fn get_rust_technology_rules() -> Vec { + vec![ + // WEB FRAMEWORKS + TechnologyRule { + name: "Actix Web".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["actix-web".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["actix".to_string()], + }, + TechnologyRule { + name: "Axum".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["axum".to_string()], + requires: vec!["Tokio".to_string()], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Rocket".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["rocket".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Warp".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["warp".to_string()], + requires: vec!["Tokio".to_string()], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Loco".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["loco-rs".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["loco".to_string()], + }, + TechnologyRule { + name: "Poem".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["poem".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Salvo".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["salvo".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Trillium".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["trillium".to_string()], + requires: vec!["Tokio".to_string()], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // ASYNC RUNTIMES + TechnologyRule { + name: "Tokio".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.90, + dependency_patterns: vec!["tokio".to_string()], + requires: vec![], + conflicts_with: vec!["async-std".to_string()], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "async-std".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.90, + dependency_patterns: vec!["async-std".to_string()], + requires: vec![], + conflicts_with: vec!["Tokio".to_string()], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // DATABASE/ORM + TechnologyRule { + name: "SeaORM".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["sea-orm".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec!["sea_orm".to_string()], + }, + TechnologyRule { + name: "Diesel".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["diesel".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "SQLx".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["sqlx".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // SERIALIZATION + TechnologyRule { + name: "Serde".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["serde".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TESTING + TechnologyRule { + name: "Criterion".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["criterion".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // GUI FRAMEWORKS (WASM/Desktop) + TechnologyRule { + name: "Leptos".to_string(), + category: TechnologyCategory::FrontendFramework, + confidence: 0.95, + dependency_patterns: vec!["leptos".to_string()], + requires: vec![], + conflicts_with: vec!["Yew".to_string(), "Dioxus".to_string()], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Yew".to_string(), + category: TechnologyCategory::FrontendFramework, + confidence: 0.95, + dependency_patterns: vec!["yew".to_string()], + requires: vec![], + conflicts_with: vec!["Leptos".to_string(), "Dioxus".to_string()], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Dioxus".to_string(), + category: TechnologyCategory::FrontendFramework, + confidence: 0.95, + dependency_patterns: vec!["dioxus".to_string()], + requires: vec![], + conflicts_with: vec!["Leptos".to_string(), "Yew".to_string()], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Tauri".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.95, + dependency_patterns: vec!["tauri".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "egui".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.95, + dependency_patterns: vec!["egui".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + ] +} \ No newline at end of file diff --git a/src/analyzer/mod.rs b/src/analyzer/mod.rs index d59e8f73..5d19830f 100644 --- a/src/analyzer/mod.rs +++ b/src/analyzer/mod.rs @@ -14,6 +14,7 @@ use std::path::{Path, PathBuf}; pub mod dependency_parser; pub mod framework_detector; +pub mod frameworks; pub mod language_detector; pub mod project_context; pub mod vulnerability_checker; From 05f7e983b2c9eabd586499de6e9e71fc4cf2d485 Mon Sep 17 00:00:00 2001 From: Alex Holmberg Date: Sat, 7 Jun 2025 00:14:28 +0200 Subject: [PATCH 2/2] feat: Added 50+ service discoveries in Rust --- README.md | 113 ++++-- src/analyzer/frameworks/rust.rs | 608 +++++++++++++++++++++++++++++++- 2 files changed, 686 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 8f5b81bb..e04438e6 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,29 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![Crates.io Downloads](https://img.shields.io/crates/d/syncable-cli) +## ๐ŸŽฏ **260+ Technologies Supported** +**The most comprehensive project analyzer supporting 5 major languages and their complete ecosystems:** +- โ˜• **Java/JVM**: 98 technologies (13 Spring components + enterprise stack) +- ๐Ÿ **Python**: 76 technologies (Django, FastAPI, ML/Data Science) +- ๐ŸŸจ **JavaScript/TypeScript**: 46 technologies (React, Next.js, Node.js) +- ๐Ÿน **Go**: 21 technologies (cloud-native & microservices) +- ๐Ÿฆ€ **Rust**: 20 technologies (high-performance web & systems) + +## ๐ŸŒŸ Help Other Developers Discover This Tool + +**If this tool saves you time, please consider giving it a โญ on GitHub!** + +Stars help other developers find Syncable CLI, and the more builders who discover it early, the better we can make it for everyone. Every star helps us reach developers who could benefit from automated infrastructure analysis and generation. + +[โญ **Star on GitHub**](https://github.com/syncable-dev/syncable-cli) + + ## โœจ Features ### ๐Ÿ” Comprehensive Project Analysis -- **Language Detection**: Automatically detects JavaScript/TypeScript, Python, Rust, Go, Java/Kotlin -- **Framework Recognition**: Identifies 70+ frameworks including Express, React, Django, FastAPI, Spring Boot -- **Dependency Analysis**: Parses all package managers and extracts version constraints +- **Language Detection**: Automatically detects JavaScript/TypeScript, Python, Rust, Go, Java/Kotlin with precise version detection +- **Framework Recognition**: Identifies **260+ technologies** across all major ecosystems including complete Spring, Django, React, and Express families +- **Dependency Analysis**: Parses all package managers (npm/yarn/pnpm, pip/poetry, cargo, go mod, maven/gradle) and extracts version constraints - **Vulnerability Scanning**: Integrates with security databases for each language ecosystem - **Security Analysis**: Basic secret detection and environment variable security checks - **Context Extraction**: Discovers entry points, ports, environment variables, and build scripts @@ -277,28 +294,74 @@ max_file_size = 2097152 # 2MB format = "json" # or "yaml", "toml" ``` -## ๐Ÿงช Supported Technologies - -### Languages & Runtimes -- JavaScript/TypeScript (Node.js) -- Python (3.7+) -- Rust -- Go -- Java/Kotlin - -### Frameworks (70+ supported) -- **JavaScript**: Express, Next.js, React, Vue, Angular, Nest.js -- **Python**: Django, Flask, FastAPI, Pyramid -- **Rust**: Actix-web, Rocket, Axum, Warp -- **Go**: Gin, Echo, Fiber, Chi -- **Java**: Spring Boot, Micronaut, Quarkus - -### Package Managers -- npm, yarn, pnpm -- pip, poetry, pipenv -- cargo -- go mod -- maven, gradle +## ๐Ÿงช Comprehensive Technology Support (260+ Technologies) + +### ๐Ÿ“Š Coverage by Language +- **โ˜• Java/JVM**: **98 technologies** - The most comprehensive JVM ecosystem coverage +- **๐Ÿ Python**: **76 technologies** - Complete Python web, data, and ML stack +- **๐ŸŸจ JavaScript/TypeScript**: **46 technologies** - Full-stack web development ecosystem +- **๐Ÿน Go**: **21 technologies** - Modern cloud-native and microservices tools +- **๐Ÿฆ€ Rust**: **20 technologies** - High-performance systems and web frameworks + +### ๐ŸŒŸ Major Ecosystem Coverage + +#### โ˜• **Java/JVM Ecosystem** (98 technologies) +**Spring Family** (13 technologies): +- Spring Boot, Spring Framework, Spring Security, Spring Data +- Spring Cloud (Gateway, Config, Netflix), Spring WebFlux, Spring MVC +- Spring Batch, Spring Integration, Spring AOP, and more + +**Enterprise & Microservices**: Quarkus, Micronaut, Dropwizard, Jakarta EE +**Database & ORM**: Hibernate, MyBatis, JPA, JDBI, MongoDB Driver, Redis Jedis +**Message Brokers**: Apache Kafka, RabbitMQ, ActiveMQ, Apache Pulsar +**Search & Big Data**: Elasticsearch, Apache Solr, Apache Spark, Apache Flink +**Security**: Apache Shiro, Keycloak, Bouncy Castle, JWT, OAuth2 +**Build Tools**: Maven, Gradle, Ant +**Testing**: JUnit, TestNG, Mockito, Selenium, Cucumber, Testcontainers +**Web Servers**: Tomcat, Jetty, Undertow, Netty + +#### ๐Ÿ **Python Ecosystem** (76 technologies) +**Web Frameworks**: Django, Flask, FastAPI, Pyramid, CherryPy, Tornado, Falcon +**Django Family**: Django REST Framework, Django ORM, Django-allauth +**Data & ML**: NumPy, Pandas, Scikit-learn, TensorFlow, PyTorch, Keras +**Database & ORM**: SQLAlchemy, Alembic, psycopg2, PyMongo, Redis-py +**Async & Messaging**: Celery, asyncio, aiohttp, Dramatiq +**Scientific**: Matplotlib, Seaborn, Jupyter, SciPy +**WSGI/ASGI Servers**: Gunicorn, Uvicorn, Hypercorn, Daphne, Waitress +**Testing**: pytest, unittest, nose2, behave, Robot Framework + +#### ๐ŸŸจ **JavaScript/TypeScript Ecosystem** (46 technologies) +**Meta-Frameworks**: Next.js, Nuxt.js, SvelteKit, Astro, SolidStart, Tanstack Start +**Frontend**: React, Vue.js, Angular, Svelte, SolidJS +**Mobile**: React Native, Expo +**Backend**: Express.js, Nest.js, Fastify, Hono, Elysia +**Database/ORM**: Prisma, Drizzle ORM, TypeORM, Mongoose, Sequelize +**Build Tools**: Vite, Webpack, Rollup, Parcel +**Runtimes**: Node.js, Bun, Deno, Cloudflare Workers, Vercel Edge +**Testing**: Jest, Vitest, Cypress, Playwright + +#### ๐Ÿน **Go Ecosystem** (21 technologies) +**Web Frameworks**: Gin, Echo, Fiber, Chi, Gorilla Mux, Beego +**Microservices**: gRPC, go-kit, go-micro +**Database**: GORM, sqlx, pgx +**Cloud Native**: Kubernetes client, Docker, Consul +**Testing**: Testify, Ginkgo, GoConvey + +#### ๐Ÿฆ€ **Rust Ecosystem** (20 technologies) +**Web Frameworks**: Actix-web, Axum, Rocket, Warp, Tide +**Async Runtimes**: Tokio, async-std +**Database/ORM**: SeaORM, Diesel, SQLx +**Serialization**: Serde +**Testing**: Built-in test framework, criterion (benchmarking) + +### ๐Ÿ“ฆ **Package Manager Support** +- **JavaScript**: npm, yarn, pnpm, bun +- **Python**: pip, poetry, pipenv, conda, pdm +- **Java**: Maven, Gradle +- **Rust**: Cargo +- **Go**: go mod +- **PHP**: Composer +- **Ruby**: Bundler ## ๐Ÿค Contributing diff --git a/src/analyzer/frameworks/rust.rs b/src/analyzer/frameworks/rust.rs index a82badeb..e9c07f1d 100644 --- a/src/analyzer/frameworks/rust.rs +++ b/src/analyzer/frameworks/rust.rs @@ -71,20 +71,20 @@ fn get_rust_technology_rules() -> Vec { alternative_names: vec![], }, TechnologyRule { - name: "Loco".to_string(), + name: "Tide".to_string(), category: TechnologyCategory::BackendFramework, confidence: 0.95, - dependency_patterns: vec!["loco-rs".to_string()], - requires: vec![], + dependency_patterns: vec!["tide".to_string()], + requires: vec!["async-std".to_string()], conflicts_with: vec![], is_primary_indicator: true, - alternative_names: vec!["loco".to_string()], + alternative_names: vec![], }, TechnologyRule { name: "Poem".to_string(), category: TechnologyCategory::BackendFramework, confidence: 0.95, - dependency_patterns: vec!["poem".to_string()], + dependency_patterns: vec!["poem".to_string(), "poem-openapi".to_string()], requires: vec![], conflicts_with: vec![], is_primary_indicator: true, @@ -100,6 +100,86 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: true, alternative_names: vec![], }, + TechnologyRule { + name: "Gotham".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["gotham".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Iron".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["iron".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Nickel".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["nickel".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Thruster".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["thruster".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Rouille".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["rouille".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Cot".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["cot".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Tardis".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["tardis".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "Loco".to_string(), + category: TechnologyCategory::BackendFramework, + confidence: 0.95, + dependency_patterns: vec!["loco-rs".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec!["loco".to_string()], + }, TechnologyRule { name: "Trillium".to_string(), category: TechnologyCategory::BackendFramework, @@ -110,7 +190,7 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: true, alternative_names: vec![], }, - + // ASYNC RUNTIMES TechnologyRule { name: "Tokio".to_string(), @@ -132,7 +212,49 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: false, alternative_names: vec![], }, - + TechnologyRule { + name: "smol".to_string(), + category: TechnologyCategory::Runtime, + confidence: 0.90, + dependency_patterns: vec!["smol".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // HTTP CLIENTS & SERVERS + TechnologyRule { + name: "reqwest".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["reqwest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "hyper".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["hyper".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "ureq".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.90, + dependency_patterns: vec!["ureq".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + // DATABASE/ORM TechnologyRule { name: "SeaORM".to_string(), @@ -164,7 +286,79 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: false, alternative_names: vec![], }, - + TechnologyRule { + name: "rusqlite".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["rusqlite".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "redis".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["redis".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "MongoDB".to_string(), + category: TechnologyCategory::Database, + confidence: 0.90, + dependency_patterns: vec!["mongodb".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // ERROR HANDLING + TechnologyRule { + name: "anyhow".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["anyhow".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "thiserror".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["thiserror".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "eyre".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["eyre".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "color-eyre".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["color-eyre".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + // SERIALIZATION TechnologyRule { name: "Serde".to_string(), @@ -176,8 +370,142 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: false, alternative_names: vec![], }, - + TechnologyRule { + name: "serde_json".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["serde_json".to_string()], + requires: vec!["Serde".to_string()], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "bincode".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["bincode".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "toml".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["toml".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "ron".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["ron".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // CLI FRAMEWORKS + TechnologyRule { + name: "clap".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["clap".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "structopt".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["structopt".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "argh".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["argh".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // LOGGING AND TRACING + TechnologyRule { + name: "tracing".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["tracing".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "log".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["log".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "env_logger".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["env_logger".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + // TESTING + TechnologyRule { + name: "rstest".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["rstest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "proptest".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["proptest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "quickcheck".to_string(), + category: TechnologyCategory::Testing, + confidence: 0.85, + dependency_patterns: vec!["quickcheck".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, TechnologyRule { name: "Criterion".to_string(), category: TechnologyCategory::Testing, @@ -188,7 +516,93 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: false, alternative_names: vec![], }, - + + // CRYPTOGRAPHY + TechnologyRule { + name: "ring".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["ring".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "rustls".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["rustls".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "sha2".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["sha2".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // DATE/TIME + TechnologyRule { + name: "chrono".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["chrono".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "time".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["time".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // CONCURRENCY + TechnologyRule { + name: "rayon".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["rayon".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "crossbeam".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["crossbeam".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "dashmap".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["dashmap".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + // GUI FRAMEWORKS (WASM/Desktop) TechnologyRule { name: "Leptos".to_string(), @@ -240,5 +654,179 @@ fn get_rust_technology_rules() -> Vec { is_primary_indicator: false, alternative_names: vec![], }, + TechnologyRule { + name: "iced".to_string(), + category: TechnologyCategory::Library(LibraryType::UI), + confidence: 0.95, + dependency_patterns: vec!["iced".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // WASM + TechnologyRule { + name: "wasm-bindgen".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["wasm-bindgen".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "js-sys".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["js-sys".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "web-sys".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["web-sys".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // GAME DEVELOPMENT + TechnologyRule { + name: "Bevy".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["bevy".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + TechnologyRule { + name: "ggez".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.95, + dependency_patterns: vec!["ggez".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: true, + alternative_names: vec![], + }, + + // MATH/SCIENCE + TechnologyRule { + name: "ndarray".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["ndarray".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "nalgebra".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["nalgebra".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // IMAGE PROCESSING + TechnologyRule { + name: "image".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["image".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // TEMPLATING + TechnologyRule { + name: "handlebars".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["handlebars".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "tera".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["tera".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "askama".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["askama".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // PARSING + TechnologyRule { + name: "nom".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["nom".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "pest".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["pest".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + + // COMPRESSION + TechnologyRule { + name: "flate2".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["flate2".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, + TechnologyRule { + name: "zstd".to_string(), + category: TechnologyCategory::Library(LibraryType::Utility), + confidence: 0.85, + dependency_patterns: vec!["zstd".to_string()], + requires: vec![], + conflicts_with: vec![], + is_primary_indicator: false, + alternative_names: vec![], + }, ] } \ No newline at end of file