actr_cli/
project_language.rs1use std::{fmt, path::Path};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum DetectedProjectLanguage {
5 Rust,
6 Swift,
7 Kotlin,
8 Python,
9 TypeScript,
10 Ambiguous,
11 Unknown,
12}
13
14impl DetectedProjectLanguage {
15 pub fn detect(root: &Path) -> Self {
16 let has_swift = root.join("Package.swift").exists() || root.join("project.yml").exists();
17 let has_kotlin =
18 root.join("build.gradle.kts").exists() || root.join("build.gradle").exists();
19 let has_python =
20 root.join("pyproject.toml").exists() || root.join("requirements.txt").exists();
21 let has_typescript =
22 root.join("tsconfig.json").exists() || root.join("package.json").exists();
23 let has_rust = root.join("Cargo.toml").exists();
24
25 let matched_count = [has_swift, has_kotlin, has_python, has_typescript, has_rust]
26 .into_iter()
27 .filter(|matched| *matched)
28 .count();
29
30 match matched_count {
31 0 => Self::Unknown,
32 1 => {
33 if has_swift {
34 Self::Swift
35 } else if has_kotlin {
36 Self::Kotlin
37 } else if has_python {
38 Self::Python
39 } else if has_typescript {
40 Self::TypeScript
41 } else {
42 Self::Rust
43 }
44 }
45 _ => Self::Ambiguous,
46 }
47 }
48
49 pub fn cli_name(self) -> &'static str {
50 match self {
51 Self::Rust => "rust",
52 Self::Swift => "swift",
53 Self::Kotlin => "kotlin",
54 Self::Python => "python",
55 Self::TypeScript => "typescript",
56 Self::Ambiguous => "ambiguous",
57 Self::Unknown => "unknown",
58 }
59 }
60}
61
62impl fmt::Display for DetectedProjectLanguage {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.write_str(self.cli_name())
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::DetectedProjectLanguage;
71 use std::fs;
72 use tempfile::TempDir;
73
74 #[test]
75 fn detects_rust_from_cargo_toml() {
76 let dir = TempDir::new().unwrap();
77 fs::write(
78 dir.path().join("Cargo.toml"),
79 "[package]\nname = \"demo\"\n",
80 )
81 .unwrap();
82
83 assert_eq!(
84 DetectedProjectLanguage::detect(dir.path()),
85 DetectedProjectLanguage::Rust
86 );
87 }
88
89 #[test]
90 fn returns_unknown_without_language_markers() {
91 let dir = TempDir::new().unwrap();
92
93 assert_eq!(
94 DetectedProjectLanguage::detect(dir.path()),
95 DetectedProjectLanguage::Unknown
96 );
97 }
98
99 #[test]
100 fn returns_ambiguous_with_multiple_language_markers() {
101 let dir = TempDir::new().unwrap();
102 fs::write(
103 dir.path().join("Cargo.toml"),
104 "[package]\nname = \"demo\"\n",
105 )
106 .unwrap();
107 fs::write(
108 dir.path().join("package.json"),
109 "{\n \"name\": \"demo\"\n}\n",
110 )
111 .unwrap();
112
113 assert_eq!(
114 DetectedProjectLanguage::detect(dir.path()),
115 DetectedProjectLanguage::Ambiguous
116 );
117 }
118}