Skip to main content

aptu_coder_core/
lang.rs

1// SPDX-FileCopyrightText: 2026 aptu-coder contributors
2// SPDX-License-Identifier: Apache-2.0
3//! Language detection by file extension.
4//!
5//! Maps file extensions to supported language identifiers.
6
7const EXTENSION_MAP: &[(&str, &str)] = &[
8    #[cfg(feature = "lang-cpp")]
9    ("c", "c"),
10    #[cfg(feature = "lang-cpp")]
11    ("cc", "cpp"),
12    #[cfg(feature = "lang-javascript")]
13    ("cjs", "javascript"),
14    #[cfg(feature = "lang-cpp")]
15    ("cpp", "cpp"),
16    #[cfg(feature = "lang-cpp")]
17    ("cxx", "cpp"),
18    #[cfg(feature = "lang-fortran")]
19    ("f", "fortran"),
20    #[cfg(feature = "lang-fortran")]
21    ("f03", "fortran"),
22    #[cfg(feature = "lang-fortran")]
23    ("f08", "fortran"),
24    #[cfg(feature = "lang-fortran")]
25    ("f77", "fortran"),
26    #[cfg(feature = "lang-fortran")]
27    ("f90", "fortran"),
28    #[cfg(feature = "lang-fortran")]
29    ("f95", "fortran"),
30    #[cfg(feature = "lang-fortran")]
31    ("for", "fortran"),
32    #[cfg(feature = "lang-fortran")]
33    ("ftn", "fortran"),
34    #[cfg(feature = "lang-cpp")]
35    ("h", "cpp"),
36    #[cfg(feature = "lang-csharp")]
37    ("cs", "csharp"),
38    #[cfg(feature = "lang-cpp")]
39    ("hpp", "cpp"),
40    #[cfg(feature = "lang-cpp")]
41    ("hxx", "cpp"),
42    #[cfg(feature = "lang-javascript")]
43    ("js", "javascript"),
44    #[cfg(feature = "lang-javascript")]
45    ("mjs", "javascript"),
46    #[cfg(feature = "lang-go")]
47    ("go", "go"),
48    #[cfg(feature = "lang-java")]
49    ("java", "java"),
50    #[cfg(feature = "lang-kotlin")]
51    ("kt", "kotlin"),
52    #[cfg(feature = "lang-kotlin")]
53    ("kts", "kotlin"),
54    #[cfg(feature = "lang-python")]
55    ("py", "python"),
56    #[cfg(feature = "lang-rust")]
57    ("rs", "rust"),
58    #[cfg(feature = "lang-typescript")]
59    ("ts", "typescript"),
60    #[cfg(feature = "lang-tsx")]
61    ("tsx", "tsx"),
62];
63
64/// Returns the language identifier for the given file extension, or `None` if unsupported.
65///
66/// The lookup is case-insensitive. Supported extensions include `rs`, `py`, `go`, `java`,
67/// `ts`, `tsx`, `js`, `mjs`, `cjs`, `c`, `cc`, `cpp`, `cxx`, `h`, `hpp`, `hxx`, `cs`,
68/// and Fortran variants `f`, `f77`, `f90`, `f95`, `f03`, `f08`, `for`, `ftn`.
69#[must_use]
70pub fn language_for_extension(ext: &str) -> Option<&'static str> {
71    EXTENSION_MAP
72        .iter()
73        .find(|(e, _)| e.eq_ignore_ascii_case(ext))
74        .map(|(_, lang)| *lang)
75}
76
77/// Returns a static slice of all supported language names based on compiled features.
78///
79/// The returned slice contains language identifiers like `"rust"`, `"python"`, `"go"`, etc.,
80/// depending on which language features are enabled at compile time.
81#[must_use]
82pub fn supported_languages() -> &'static [&'static str] {
83    &[
84        #[cfg(feature = "lang-rust")]
85        "rust",
86        #[cfg(feature = "lang-go")]
87        "go",
88        #[cfg(feature = "lang-java")]
89        "java",
90        #[cfg(feature = "lang-kotlin")]
91        "kotlin",
92        #[cfg(feature = "lang-python")]
93        "python",
94        #[cfg(feature = "lang-typescript")]
95        "typescript",
96        #[cfg(feature = "lang-tsx")]
97        "tsx",
98        #[cfg(feature = "lang-javascript")]
99        "javascript",
100        #[cfg(feature = "lang-fortran")]
101        "fortran",
102        #[cfg(feature = "lang-cpp")]
103        "c",
104        #[cfg(feature = "lang-cpp")]
105        "cpp",
106        #[cfg(feature = "lang-csharp")]
107        "csharp",
108    ]
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_language_for_extension_happy_path() {
117        #[cfg(feature = "lang-rust")]
118        assert_eq!(language_for_extension("rs"), Some("rust"));
119        #[cfg(feature = "lang-python")]
120        assert_eq!(language_for_extension("py"), Some("python"));
121        #[cfg(feature = "lang-go")]
122        assert_eq!(language_for_extension("go"), Some("go"));
123        #[cfg(feature = "lang-java")]
124        assert_eq!(language_for_extension("java"), Some("java"));
125        #[cfg(feature = "lang-typescript")]
126        assert_eq!(language_for_extension("ts"), Some("typescript"));
127        #[cfg(feature = "lang-tsx")]
128        assert_eq!(language_for_extension("tsx"), Some("tsx"));
129        #[cfg(feature = "lang-fortran")]
130        assert_eq!(language_for_extension("f90"), Some("fortran"));
131        #[cfg(feature = "lang-fortran")]
132        assert_eq!(language_for_extension("for"), Some("fortran"));
133        #[cfg(feature = "lang-fortran")]
134        assert_eq!(language_for_extension("ftn"), Some("fortran"));
135        #[cfg(feature = "lang-cpp")]
136        assert_eq!(language_for_extension("c"), Some("c"));
137        #[cfg(feature = "lang-cpp")]
138        assert_eq!(language_for_extension("cpp"), Some("cpp"));
139        #[cfg(feature = "lang-cpp")]
140        assert_eq!(language_for_extension("h"), Some("cpp"));
141        #[cfg(feature = "lang-cpp")]
142        assert_eq!(language_for_extension("hpp"), Some("cpp"));
143        #[cfg(feature = "lang-cpp")]
144        assert_eq!(language_for_extension("cc"), Some("cpp"));
145        #[cfg(feature = "lang-kotlin")]
146        assert_eq!(language_for_extension("kt"), Some("kotlin"));
147        #[cfg(feature = "lang-kotlin")]
148        assert_eq!(language_for_extension("kts"), Some("kotlin"));
149    }
150
151    #[test]
152    fn test_language_for_extension_edge_case() {
153        assert_eq!(language_for_extension("unknown"), None);
154        assert_eq!(language_for_extension(""), None);
155        #[cfg(feature = "lang-rust")]
156        assert_eq!(language_for_extension("RS"), Some("rust"));
157        // Uppercase Fortran extensions resolved via eq_ignore_ascii_case
158        #[cfg(feature = "lang-fortran")]
159        assert_eq!(language_for_extension("F90"), Some("fortran"));
160        #[cfg(feature = "lang-fortran")]
161        assert_eq!(language_for_extension("FOR"), Some("fortran"));
162    }
163}