use std::path::Path;
use std::fs;
use crate::discovery::models::Framework;
pub fn detect_framework(project_root: &Path) -> Framework {
if has_openapi_spec(project_root) {
return Framework::OpenAPI;
}
if let Some(framework) = detect_python_framework(project_root) {
return framework;
}
if let Some(framework) = detect_node_framework(project_root) {
return framework;
}
if let Some(framework) = detect_java_framework(project_root) {
return framework;
}
if let Some(framework) = detect_php_framework(project_root) {
return framework;
}
if let Some(framework) = detect_rust_framework(project_root) {
return framework;
}
if let Some(framework) = detect_go_framework(project_root) {
return framework;
}
Framework::Unknown
}
fn has_openapi_spec(root: &Path) -> bool {
let spec_files = [
"openapi.yaml",
"openapi.yml",
"openapi.json",
"swagger.yaml",
"swagger.yml",
"swagger.json",
"api/openapi.yaml",
"api/openapi.yml",
"docs/openapi.yaml",
"docs/swagger.yaml",
];
for file in &spec_files {
if root.join(file).exists() {
return true;
}
}
false
}
pub fn find_openapi_spec(root: &Path) -> Option<std::path::PathBuf> {
let spec_files = [
"openapi.yaml",
"openapi.yml",
"openapi.json",
"swagger.yaml",
"swagger.yml",
"swagger.json",
"api/openapi.yaml",
"api/openapi.yml",
"docs/openapi.yaml",
"docs/swagger.yaml",
];
for file in &spec_files {
let path = root.join(file);
if path.exists() {
return Some(path);
}
}
None
}
fn detect_python_framework(root: &Path) -> Option<Framework> {
let files_to_check = ["requirements.txt", "pyproject.toml", "setup.py", "Pipfile"];
for file in &files_to_check {
let path = root.join(file);
if let Ok(content) = fs::read_to_string(&path) {
let lower = content.to_lowercase();
if lower.contains("fastapi") {
return Some(Framework::FastAPI);
}
if lower.contains("flask") {
return Some(Framework::Flask);
}
if lower.contains("django") {
return Some(Framework::Django);
}
}
}
if root.join("manage.py").exists() {
return Some(Framework::Django);
}
for entry in ["main.py", "app.py", "app/__init__.py", "src/main.py"].iter() {
let path = root.join(entry);
if let Ok(content) = fs::read_to_string(&path) {
if content.contains("FastAPI") || content.contains("from fastapi") {
return Some(Framework::FastAPI);
}
if content.contains("Flask") || content.contains("from flask") {
return Some(Framework::Flask);
}
}
}
None
}
fn detect_node_framework(root: &Path) -> Option<Framework> {
let package_json = root.join("package.json");
if let Ok(content) = fs::read_to_string(&package_json) {
let lower = content.to_lowercase();
if lower.contains("@nestjs") {
return Some(Framework::NestJS);
}
if lower.contains("\"express\"") {
return Some(Framework::Express);
}
}
None
}
fn detect_rust_framework(root: &Path) -> Option<Framework> {
let cargo_toml = root.join("Cargo.toml");
if let Ok(content) = fs::read_to_string(&cargo_toml) {
let lower = content.to_lowercase();
if lower.contains("actix-web") {
return Some(Framework::Actix);
}
if lower.contains("axum") {
return Some(Framework::Axum);
}
}
None
}
fn detect_java_framework(root: &Path) -> Option<Framework> {
if let Ok(content) = fs::read_to_string(root.join("pom.xml")) {
if content.contains("spring-boot-starter-web") {
return Some(Framework::SpringBoot);
}
}
if let Ok(content) = fs::read_to_string(root.join("build.gradle")) {
if content.contains("org.springframework.boot") {
return Some(Framework::SpringBoot);
}
}
if let Ok(content) = fs::read_to_string(root.join("build.gradle.kts")) {
if content.contains("org.springframework.boot") {
return Some(Framework::SpringBoot);
}
}
None
}
fn detect_php_framework(root: &Path) -> Option<Framework> {
if let Ok(content) = fs::read_to_string(root.join("composer.json")) {
if content.contains("laravel/framework") {
return Some(Framework::Laravel);
}
}
if root.join("artisan").exists() {
return Some(Framework::Laravel);
}
None
}
fn detect_go_framework(root: &Path) -> Option<Framework> {
let go_mod = root.join("go.mod");
if let Ok(content) = fs::read_to_string(&go_mod) {
if content.contains("github.com/gin-gonic/gin") {
return Some(Framework::Gin);
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use tempfile::tempdir;
#[test]
fn test_detect_openapi() {
let dir = tempdir().unwrap();
File::create(dir.path().join("openapi.yaml")).unwrap();
assert_eq!(detect_framework(dir.path()), Framework::OpenAPI);
}
}