Skip to main content

ward/detection/
project_type.rs

1use serde::Serialize;
2
3/// Detected project type for a repository.
4#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
5pub enum ProjectType {
6    Gradle,
7    Npm,
8    Cargo,
9    Unknown,
10}
11
12impl ProjectType {
13    /// Detect from the presence of known build files.
14    pub fn from_files(files: &[String]) -> Self {
15        const DETECTORS: &[(&[&str], ProjectType)] = &[
16            (&["build.gradle.kts", "build.gradle"], ProjectType::Gradle),
17            (&["package.json"], ProjectType::Npm),
18            (&["Cargo.toml"], ProjectType::Cargo),
19        ];
20
21        DETECTORS
22            .iter()
23            .find(|(markers, _)| markers.iter().any(|m| files.iter().any(|f| f == m)))
24            .map(|(_, pt)| pt.clone())
25            .unwrap_or(Self::Unknown)
26    }
27}
28
29impl std::fmt::Display for ProjectType {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        match self {
32            Self::Gradle => write!(f, "Gradle"),
33            Self::Npm => write!(f, "npm"),
34            Self::Cargo => write!(f, "Cargo"),
35            Self::Unknown => write!(f, "Unknown"),
36        }
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    fn files(names: &[&str]) -> Vec<String> {
45        names.iter().map(|s| s.to_string()).collect()
46    }
47
48    #[test]
49    fn detect_gradle_kts() {
50        assert_eq!(
51            ProjectType::from_files(&files(&["build.gradle.kts", "settings.gradle.kts"])),
52            ProjectType::Gradle
53        );
54    }
55
56    #[test]
57    fn detect_gradle_groovy() {
58        assert_eq!(
59            ProjectType::from_files(&files(&["build.gradle"])),
60            ProjectType::Gradle
61        );
62    }
63
64    #[test]
65    fn detect_npm() {
66        assert_eq!(
67            ProjectType::from_files(&files(&["package.json", "package-lock.json"])),
68            ProjectType::Npm
69        );
70    }
71
72    #[test]
73    fn detect_cargo() {
74        assert_eq!(
75            ProjectType::from_files(&files(&["Cargo.toml", "Cargo.lock"])),
76            ProjectType::Cargo
77        );
78    }
79
80    #[test]
81    fn detect_unknown_for_empty() {
82        assert_eq!(ProjectType::from_files(&[]), ProjectType::Unknown);
83    }
84
85    #[test]
86    fn detect_unknown_for_unrecognized() {
87        assert_eq!(
88            ProjectType::from_files(&files(&["Makefile", "go.mod"])),
89            ProjectType::Unknown
90        );
91    }
92
93    #[test]
94    fn gradle_takes_priority_over_npm() {
95        assert_eq!(
96            ProjectType::from_files(&files(&["build.gradle.kts", "package.json"])),
97            ProjectType::Gradle
98        );
99    }
100
101    #[test]
102    fn display_formatting() {
103        assert_eq!(format!("{}", ProjectType::Gradle), "Gradle");
104        assert_eq!(format!("{}", ProjectType::Npm), "npm");
105        assert_eq!(format!("{}", ProjectType::Cargo), "Cargo");
106        assert_eq!(format!("{}", ProjectType::Unknown), "Unknown");
107    }
108}