driven/sysinfo/
detectors.rs1use super::ProjectType;
7use std::path::Path;
8
9pub fn detect_project_type_from_path(path: &Path) -> ProjectType {
11 super::detect_project_type(path)
12}
13
14pub fn is_rust_project(path: &Path) -> bool {
16 path.join("Cargo.toml").exists()
17}
18
19pub fn is_node_project(path: &Path) -> bool {
21 path.join("package.json").exists()
22}
23
24pub fn is_python_project(path: &Path) -> bool {
26 path.join("pyproject.toml").exists()
27 || path.join("setup.py").exists()
28 || path.join("requirements.txt").exists()
29}
30
31pub fn is_go_project(path: &Path) -> bool {
33 path.join("go.mod").exists()
34}
35
36pub fn is_java_project(path: &Path) -> bool {
38 path.join("pom.xml").exists() || path.join("build.gradle").exists()
39}
40
41pub fn has_git_repo(path: &Path) -> bool {
43 path.join(".git").exists()
44}
45
46pub fn get_project_markers(project_type: ProjectType) -> Vec<&'static str> {
48 match project_type {
49 ProjectType::Rust => vec!["Cargo.toml", "Cargo.lock"],
50 ProjectType::Node => vec![
51 "package.json",
52 "package-lock.json",
53 "yarn.lock",
54 "pnpm-lock.yaml",
55 ],
56 ProjectType::Python => vec!["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"],
57 ProjectType::Go => vec!["go.mod", "go.sum"],
58 ProjectType::Java => vec!["pom.xml", "build.gradle", "build.gradle.kts"],
59 ProjectType::CSharp => vec!["*.csproj", "*.sln"],
60 ProjectType::Ruby => vec!["Gemfile", "Gemfile.lock"],
61 ProjectType::Php => vec!["composer.json", "composer.lock"],
62 ProjectType::Swift => vec!["Package.swift"],
63 ProjectType::Kotlin => vec!["build.gradle.kts"],
64 ProjectType::Cpp => vec!["CMakeLists.txt", "*.cpp", "*.hpp"],
65 ProjectType::C => vec!["Makefile", "*.c", "*.h"],
66 ProjectType::Mixed | ProjectType::Unknown => vec![],
67 }
68}
69
70pub fn detect_primary_language(path: &Path) -> Option<ProjectType> {
72 use std::collections::HashMap;
73
74 let mut counts: HashMap<ProjectType, usize> = HashMap::new();
75
76 let entries = walkdir::WalkDir::new(path)
77 .max_depth(3)
78 .into_iter()
79 .filter_map(|e| e.ok());
80
81 for entry in entries {
82 if let Some(ext) = entry.path().extension().and_then(|e| e.to_str()) {
83 let project_type = match ext {
84 "rs" => Some(ProjectType::Rust),
85 "js" | "ts" | "jsx" | "tsx" => Some(ProjectType::Node),
86 "py" => Some(ProjectType::Python),
87 "go" => Some(ProjectType::Go),
88 "java" => Some(ProjectType::Java),
89 "cs" => Some(ProjectType::CSharp),
90 "rb" => Some(ProjectType::Ruby),
91 "php" => Some(ProjectType::Php),
92 "swift" => Some(ProjectType::Swift),
93 "kt" | "kts" => Some(ProjectType::Kotlin),
94 "cpp" | "cc" | "cxx" | "hpp" => Some(ProjectType::Cpp),
95 "c" | "h" => Some(ProjectType::C),
96 _ => None,
97 };
98
99 if let Some(pt) = project_type {
100 *counts.entry(pt).or_insert(0) += 1;
101 }
102 }
103 }
104
105 counts
106 .into_iter()
107 .max_by_key(|(_, count)| *count)
108 .map(|(pt, _)| pt)
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use std::fs;
115 use tempfile::TempDir;
116
117 #[test]
118 fn test_is_rust_project() {
119 let temp = TempDir::new().unwrap();
120 fs::write(temp.path().join("Cargo.toml"), "[package]").unwrap();
121
122 assert!(is_rust_project(temp.path()));
123 }
124
125 #[test]
126 fn test_is_node_project() {
127 let temp = TempDir::new().unwrap();
128 fs::write(temp.path().join("package.json"), "{}").unwrap();
129
130 assert!(is_node_project(temp.path()));
131 }
132
133 #[test]
134 fn test_has_git_repo() {
135 let temp = TempDir::new().unwrap();
136 fs::create_dir(temp.path().join(".git")).unwrap();
137
138 assert!(has_git_repo(temp.path()));
139 }
140
141 #[test]
142 fn test_get_project_markers() {
143 let markers = get_project_markers(ProjectType::Rust);
144 assert!(markers.contains(&"Cargo.toml"));
145 }
146}