use crate::analyzer::display::BoxDrawer;
use crate::analyzer::{
ArchitecturePattern, DetectedTechnology, DockerAnalysis, LibraryType, OrchestrationPattern,
ProjectCategory, TechnologyCategory,
};
use colored::*;
pub fn get_category_emoji(category: &ProjectCategory) -> &'static str {
match category {
ProjectCategory::Frontend => "π",
ProjectCategory::Backend => "βοΈ",
ProjectCategory::Api => "π",
ProjectCategory::Service => "π",
ProjectCategory::Library => "π",
ProjectCategory::Tool => "π§",
ProjectCategory::Documentation => "π",
ProjectCategory::Infrastructure => "ποΈ",
ProjectCategory::Unknown => "β",
}
}
pub fn format_project_category(category: &ProjectCategory) -> &'static str {
match category {
ProjectCategory::Frontend => "Frontend",
ProjectCategory::Backend => "Backend",
ProjectCategory::Api => "API",
ProjectCategory::Service => "Service",
ProjectCategory::Library => "Library",
ProjectCategory::Tool => "Tool",
ProjectCategory::Documentation => "Documentation",
ProjectCategory::Infrastructure => "Infrastructure",
ProjectCategory::Unknown => "Unknown",
}
}
pub fn display_architecture_description(pattern: &ArchitecturePattern) {
match pattern {
ArchitecturePattern::Monolithic => {
println!(" π¦ This is a single, self-contained application");
}
ArchitecturePattern::Fullstack => {
println!(" π This is a full-stack application with separate frontend and backend");
}
ArchitecturePattern::Microservices => {
println!(
" π This is a microservices architecture with multiple independent services"
);
}
ArchitecturePattern::ApiFirst => {
println!(" π This is an API-first architecture focused on service interfaces");
}
ArchitecturePattern::EventDriven => {
println!(" π‘ This is an event-driven architecture with decoupled components");
}
ArchitecturePattern::Mixed => {
println!(" π This is a mixed architecture combining multiple patterns");
}
}
}
pub fn display_architecture_description_to_string(pattern: &ArchitecturePattern) -> String {
match pattern {
ArchitecturePattern::Monolithic => {
" π¦ This is a single, self-contained application\n".to_string()
}
ArchitecturePattern::Fullstack => {
" π This is a full-stack application with separate frontend and backend\n"
.to_string()
}
ArchitecturePattern::Microservices => {
" π This is a microservices architecture with multiple independent services\n"
.to_string()
}
ArchitecturePattern::ApiFirst => {
" π This is an API-first architecture focused on service interfaces\n".to_string()
}
ArchitecturePattern::EventDriven => {
" π‘ This is an event-driven architecture with decoupled components\n".to_string()
}
ArchitecturePattern::Mixed => {
" π This is a mixed architecture combining multiple patterns\n".to_string()
}
}
}
pub fn get_main_technologies(technologies: &[DetectedTechnology]) -> String {
let primary = technologies.iter().find(|t| t.is_primary);
let frameworks: Vec<_> = technologies
.iter()
.filter(|t| {
matches!(
t.category,
TechnologyCategory::FrontendFramework | TechnologyCategory::MetaFramework
)
})
.take(2)
.collect();
let mut result = Vec::new();
if let Some(p) = primary {
result.push(p.name.clone());
}
for f in frameworks {
if Some(&f.name) != primary.map(|p| &p.name) {
result.push(f.name.clone());
}
}
if result.is_empty() {
"-".to_string()
} else {
result.join(", ")
}
}
pub fn add_confidence_bar_to_drawer(score: f32, box_drawer: &mut BoxDrawer) {
let percentage = (score * 100.0) as u8;
let bar_width = 20;
let filled = ((score * bar_width as f32) as usize).min(bar_width);
let bar = format!(
"{}{}",
"β".repeat(filled).green(),
"β".repeat(bar_width - filled).dimmed()
);
let color = if percentage >= 80 {
"green"
} else if percentage >= 60 {
"yellow"
} else {
"red"
};
let confidence_info = format!("{} {}", bar, format!("{:.0}%", percentage).color(color));
box_drawer.add_line("Confidence:", &confidence_info, true);
}
pub fn display_technologies_detailed_legacy(technologies: &[DetectedTechnology]) {
let mut by_category: std::collections::HashMap<&TechnologyCategory, Vec<&DetectedTechnology>> =
std::collections::HashMap::new();
for tech in technologies {
by_category.entry(&tech.category).or_default().push(tech);
}
if let Some(primary) = technologies.iter().find(|t| t.is_primary) {
println!("\nπ οΈ Technology Stack:");
println!(
" π― PRIMARY: {} (confidence: {:.1}%)",
primary.name,
primary.confidence * 100.0
);
println!(" Architecture driver for this project");
}
let categories = [
(TechnologyCategory::MetaFramework, "ποΈ Meta-Frameworks"),
(
TechnologyCategory::BackendFramework,
"π₯οΈ Backend Frameworks",
),
(
TechnologyCategory::FrontendFramework,
"π¨ Frontend Frameworks",
),
(
TechnologyCategory::Library(LibraryType::UI),
"π¨ UI Libraries",
),
(
TechnologyCategory::Library(LibraryType::Utility),
"π Core Libraries",
),
(TechnologyCategory::BuildTool, "π¨ Build Tools"),
(TechnologyCategory::PackageManager, "π¦ Package Managers"),
(TechnologyCategory::Database, "ποΈ Database & ORM"),
(TechnologyCategory::Runtime, "β‘ Runtimes"),
(TechnologyCategory::Testing, "π§ͺ Testing"),
];
for (category, label) in &categories {
if let Some(techs) = by_category.get(category)
&& !techs.is_empty()
{
println!("\n {}:", label);
for tech in techs {
println!(
" β’ {} (confidence: {:.1}%)",
tech.name,
tech.confidence * 100.0
);
if let Some(version) = &tech.version {
println!(" Version: {}", version);
}
}
}
}
for (cat, techs) in &by_category {
if let TechnologyCategory::Library(lib_type) = cat {
let label = match lib_type {
LibraryType::StateManagement => "π State Management",
LibraryType::DataFetching => "π Data Fetching",
LibraryType::Routing => "πΊοΈ Routing",
LibraryType::Styling => "π¨ Styling",
LibraryType::HttpClient => "π HTTP Clients",
LibraryType::Authentication => "π Authentication",
LibraryType::Other(_) => "π¦ Other Libraries",
_ => continue, };
if !matches!(lib_type, LibraryType::UI | LibraryType::Utility) && !techs.is_empty() {
println!("\n {}:", label);
for tech in techs {
println!(
" β’ {} (confidence: {:.1}%)",
tech.name,
tech.confidence * 100.0
);
if let Some(version) = &tech.version {
println!(" Version: {}", version);
}
}
}
}
}
}
pub fn display_technologies_detailed_legacy_to_string(
technologies: &[DetectedTechnology],
) -> String {
let mut output = String::new();
let mut by_category: std::collections::HashMap<&TechnologyCategory, Vec<&DetectedTechnology>> =
std::collections::HashMap::new();
for tech in technologies {
by_category.entry(&tech.category).or_default().push(tech);
}
if let Some(primary) = technologies.iter().find(|t| t.is_primary) {
output.push_str("\nπ οΈ Technology Stack:\n");
output.push_str(&format!(
" π― PRIMARY: {} (confidence: {:.1}%)\n",
primary.name,
primary.confidence * 100.0
));
output.push_str(" Architecture driver for this project\n");
}
let categories = [
(TechnologyCategory::MetaFramework, "ποΈ Meta-Frameworks"),
(
TechnologyCategory::BackendFramework,
"π₯οΈ Backend Frameworks",
),
(
TechnologyCategory::FrontendFramework,
"π¨ Frontend Frameworks",
),
(
TechnologyCategory::Library(LibraryType::UI),
"π¨ UI Libraries",
),
(
TechnologyCategory::Library(LibraryType::Utility),
"π Core Libraries",
),
(TechnologyCategory::BuildTool, "π¨ Build Tools"),
(TechnologyCategory::PackageManager, "π¦ Package Managers"),
(TechnologyCategory::Database, "ποΈ Database & ORM"),
(TechnologyCategory::Runtime, "β‘ Runtimes"),
(TechnologyCategory::Testing, "π§ͺ Testing"),
];
for (category, label) in &categories {
if let Some(techs) = by_category.get(category)
&& !techs.is_empty()
{
output.push_str(&format!("\n {}:\n", label));
for tech in techs {
output.push_str(&format!(
" β’ {} (confidence: {:.1}%)\n",
tech.name,
tech.confidence * 100.0
));
if let Some(version) = &tech.version {
output.push_str(&format!(" Version: {}\n", version));
}
}
}
}
for (cat, techs) in &by_category {
if let TechnologyCategory::Library(lib_type) = cat {
let label = match lib_type {
LibraryType::StateManagement => "π State Management",
LibraryType::DataFetching => "π Data Fetching",
LibraryType::Routing => "πΊοΈ Routing",
LibraryType::Styling => "π¨ Styling",
LibraryType::HttpClient => "π HTTP Clients",
LibraryType::Authentication => "π Authentication",
LibraryType::Other(_) => "π¦ Other Libraries",
_ => continue, };
if !matches!(lib_type, LibraryType::UI | LibraryType::Utility) && !techs.is_empty() {
output.push_str(&format!("\n {}:\n", label));
for tech in techs {
output.push_str(&format!(
" β’ {} (confidence: {:.1}%)\n",
tech.name,
tech.confidence * 100.0
));
if let Some(version) = &tech.version {
output.push_str(&format!(" Version: {}\n", version));
}
}
}
}
}
output
}
pub fn display_docker_analysis_detailed_legacy(docker_analysis: &DockerAnalysis) {
println!("\n π³ Docker Infrastructure Analysis:");
if !docker_analysis.dockerfiles.is_empty() {
println!(
" π Dockerfiles ({}):",
docker_analysis.dockerfiles.len()
);
for dockerfile in &docker_analysis.dockerfiles {
println!(" β’ {}", dockerfile.path.display());
if let Some(env) = &dockerfile.environment {
println!(" Environment: {}", env);
}
if let Some(base_image) = &dockerfile.base_image {
println!(" Base image: {}", base_image);
}
if !dockerfile.exposed_ports.is_empty() {
println!(
" Exposed ports: {}",
dockerfile
.exposed_ports
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(", ")
);
}
if dockerfile.is_multistage {
println!(
" Multi-stage build: {} stages",
dockerfile.build_stages.len()
);
}
println!(" Instructions: {}", dockerfile.instruction_count);
}
}
if !docker_analysis.compose_files.is_empty() {
println!(
" π Compose Files ({}):",
docker_analysis.compose_files.len()
);
for compose_file in &docker_analysis.compose_files {
println!(" β’ {}", compose_file.path.display());
if let Some(env) = &compose_file.environment {
println!(" Environment: {}", env);
}
if let Some(version) = &compose_file.version {
println!(" Version: {}", version);
}
if !compose_file.service_names.is_empty() {
println!(
" Services: {}",
compose_file.service_names.join(", ")
);
}
if !compose_file.networks.is_empty() {
println!(" Networks: {}", compose_file.networks.join(", "));
}
if !compose_file.volumes.is_empty() {
println!(" Volumes: {}", compose_file.volumes.join(", "));
}
}
}
println!(
" ποΈ Orchestration Pattern: {:?}",
docker_analysis.orchestration_pattern
);
match docker_analysis.orchestration_pattern {
OrchestrationPattern::SingleContainer => {
println!(" Simple containerized application");
}
OrchestrationPattern::DockerCompose => {
println!(" Multi-service Docker Compose setup");
}
OrchestrationPattern::Microservices => {
println!(" Microservices architecture with service discovery");
}
OrchestrationPattern::EventDriven => {
println!(" Event-driven architecture with message queues");
}
OrchestrationPattern::ServiceMesh => {
println!(" Service mesh for advanced service communication");
}
OrchestrationPattern::Mixed => {
println!(" Mixed/complex orchestration pattern");
}
}
}
pub fn display_docker_analysis_detailed_legacy_to_string(
docker_analysis: &DockerAnalysis,
) -> String {
let mut output = String::new();
output.push_str("\n π³ Docker Infrastructure Analysis:\n");
if !docker_analysis.dockerfiles.is_empty() {
output.push_str(&format!(
" π Dockerfiles ({}):\n",
docker_analysis.dockerfiles.len()
));
for dockerfile in &docker_analysis.dockerfiles {
output.push_str(&format!(" β’ {}\n", dockerfile.path.display()));
if let Some(env) = &dockerfile.environment {
output.push_str(&format!(" Environment: {}\n", env));
}
if let Some(base_image) = &dockerfile.base_image {
output.push_str(&format!(" Base image: {}\n", base_image));
}
if !dockerfile.exposed_ports.is_empty() {
output.push_str(&format!(
" Exposed ports: {}\n",
dockerfile
.exposed_ports
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(", ")
));
}
if dockerfile.is_multistage {
output.push_str(&format!(
" Multi-stage build: {} stages\n",
dockerfile.build_stages.len()
));
}
output.push_str(&format!(
" Instructions: {}\n",
dockerfile.instruction_count
));
}
}
if !docker_analysis.compose_files.is_empty() {
output.push_str(&format!(
" π Compose Files ({}):\n",
docker_analysis.compose_files.len()
));
for compose_file in &docker_analysis.compose_files {
output.push_str(&format!(" β’ {}\n", compose_file.path.display()));
if let Some(env) = &compose_file.environment {
output.push_str(&format!(" Environment: {}\n", env));
}
if let Some(version) = &compose_file.version {
output.push_str(&format!(" Version: {}\n", version));
}
if !compose_file.service_names.is_empty() {
output.push_str(&format!(
" Services: {}\n",
compose_file.service_names.join(", ")
));
}
if !compose_file.networks.is_empty() {
output.push_str(&format!(
" Networks: {}\n",
compose_file.networks.join(", ")
));
}
if !compose_file.volumes.is_empty() {
output.push_str(&format!(
" Volumes: {}\n",
compose_file.volumes.join(", ")
));
}
}
}
output.push_str(&format!(
" ποΈ Orchestration Pattern: {:?}\n",
docker_analysis.orchestration_pattern
));
match docker_analysis.orchestration_pattern {
OrchestrationPattern::SingleContainer => {
output.push_str(" Simple containerized application\n");
}
OrchestrationPattern::DockerCompose => {
output.push_str(" Multi-service Docker Compose setup\n");
}
OrchestrationPattern::Microservices => {
output.push_str(" Microservices architecture with service discovery\n");
}
OrchestrationPattern::EventDriven => {
output.push_str(" Event-driven architecture with message queues\n");
}
OrchestrationPattern::ServiceMesh => {
output.push_str(" Service mesh for advanced service communication\n");
}
OrchestrationPattern::Mixed => {
output.push_str(" Mixed/complex orchestration pattern\n");
}
}
output
}