Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 87 additions & 26 deletions src/analyzer/context/project_type.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::analyzer::{DetectedLanguage, DetectedTechnology, EntryPoint, Port, ProjectType};
use super::microservices::MicroserviceInfo;
use crate::analyzer::{DetectedLanguage, DetectedTechnology, EntryPoint, Port, ProjectType};

/// Enhanced project type determination including microservice structure analysis
pub(crate) fn determine_project_type_with_structure(
Expand Down Expand Up @@ -30,70 +30,131 @@ fn determine_project_type(
let has_database_ports = ports.iter().any(|p| {
if let Some(desc) = &p.description {
let desc_lower = desc.to_lowercase();
desc_lower.contains("postgres") || desc_lower.contains("mysql") ||
desc_lower.contains("mongodb") || desc_lower.contains("database")
desc_lower.contains("postgres")
|| desc_lower.contains("mysql")
|| desc_lower.contains("mongodb")
|| desc_lower.contains("database")
} else {
false
}
});

let has_multiple_services = ports.iter()
let has_multiple_services = ports
.iter()
.filter_map(|p| p.description.as_ref())
.filter(|desc| {
let desc_lower = desc.to_lowercase();
desc_lower.contains("service") || desc_lower.contains("application")
})
.count() > 1;
.count()
> 1;

let has_orchestration_framework = technologies.iter()
let has_orchestration_framework = technologies
.iter()
.any(|t| t.name == "Encore" || t.name == "Dapr" || t.name == "Temporal");

// Check for web frameworks
let web_frameworks = ["Express", "Fastify", "Koa", "Next.js", "React", "Vue", "Angular",
"Django", "Flask", "FastAPI", "Spring Boot", "Actix Web", "Rocket",
"Gin", "Echo", "Fiber", "Svelte", "SvelteKit", "SolidJS", "Astro",
"Encore", "Hono", "Elysia", "React Router v7", "Tanstack Start",
"SolidStart", "Qwik", "Nuxt.js", "Gatsby"];
let web_frameworks = [
"Express",
"Fastify",
"Koa",
"Next.js",
"React",
"Vue",
"Angular",
"Django",
"Flask",
"FastAPI",
"Spring Boot",
"Actix Web",
"Rocket",
"Gin",
"Echo",
"Fiber",
"Svelte",
"SvelteKit",
"SolidJS",
"Astro",
"Encore",
"Hono",
"Elysia",
"React Router v7",
"Tanstack Start",
"SolidStart",
"Qwik",
"Nuxt.js",
"Gatsby",
];

let has_web_framework = technologies.iter()
let has_web_framework = technologies
.iter()
.any(|t| web_frameworks.contains(&t.name.as_str()));

// Check for CLI indicators
let cli_indicators = ["cobra", "clap", "argparse", "commander"];
let has_cli_framework = technologies.iter()
let has_cli_framework = technologies
.iter()
.any(|t| cli_indicators.contains(&t.name.to_lowercase().as_str()));

// Check for API indicators
let api_frameworks = ["FastAPI", "Express", "Gin", "Echo", "Actix Web", "Spring Boot",
"Fastify", "Koa", "Nest.js", "Encore", "Hono", "Elysia"];
let has_api_framework = technologies.iter()
let api_frameworks = [
"FastAPI",
"Express",
"Gin",
"Echo",
"Actix Web",
"Spring Boot",
"Fastify",
"Koa",
"Nest.js",
"Encore",
"Hono",
"Elysia",
];
let has_api_framework = technologies
.iter()
.any(|t| api_frameworks.contains(&t.name.as_str()));

// Check for static site generators
let static_generators = ["Gatsby", "Hugo", "Jekyll", "Eleventy", "Astro"];
let has_static_generator = technologies.iter()
let has_static_generator = technologies
.iter()
.any(|t| static_generators.contains(&t.name.as_str()));

// Check for functions app indicators
let functions_apps: [&'static str; 1] = ["Azure Functions"];
let has_functions_app = technologies
.iter()
.any(|t| functions_apps.contains(&t.name.as_str()));

// Determine type based on indicators
if (has_database_ports || has_multiple_services) && (has_orchestration_framework || has_api_framework) {
if (has_database_ports || has_multiple_services)
&& (has_orchestration_framework || has_api_framework)
{
ProjectType::Microservice
} else if has_static_generator {
ProjectType::StaticSite
} else if has_api_framework && !has_web_framework {
ProjectType::ApiService
} else if has_web_framework {
ProjectType::WebApplication
} else if has_functions_app {
ProjectType::FunctionApp
} else if has_cli_framework || (entry_points.len() == 1 && ports.is_empty()) {
ProjectType::CliTool
} else if entry_points.is_empty() && ports.is_empty() {
// Check if it's a library
let has_lib_indicators = languages.iter().any(|l| {
match l.name.as_str() {
"Rust" => l.files.iter().any(|f| f.to_string_lossy().contains("lib.rs")),
"Python" => l.files.iter().any(|f| f.to_string_lossy().contains("__init__.py")),
"JavaScript" | "TypeScript" => l.main_dependencies.is_empty(),
_ => false,
}
let has_lib_indicators = languages.iter().any(|l| match l.name.as_str() {
"Rust" => l
.files
.iter()
.any(|f| f.to_string_lossy().contains("lib.rs")),
"Python" => l
.files
.iter()
.any(|f| f.to_string_lossy().contains("__init__.py")),
"JavaScript" | "TypeScript" => l.main_dependencies.is_empty(),
_ => false,
});

if has_lib_indicators {
Expand All @@ -104,4 +165,4 @@ fn determine_project_type(
} else {
ProjectType::Unknown
}
}
}
Loading