1const EXTENSION_MAP: &[(&str, &str)] = &[
13 ("c", "c"),
14 ("cc", "cpp"),
15 ("cjs", "javascript"),
16 ("cpp", "cpp"),
17 ("cxx", "cpp"),
18 ("f", "fortran"),
19 ("f03", "fortran"),
20 ("f08", "fortran"),
21 ("f77", "fortran"),
22 ("f90", "fortran"),
23 ("f95", "fortran"),
24 ("for", "fortran"),
25 ("ftn", "fortran"),
26 ("h", "cpp"),
27 ("cs", "csharp"),
28 ("hpp", "cpp"),
29 ("hxx", "cpp"),
30 ("js", "javascript"),
31 ("mjs", "javascript"),
32 ("go", "go"),
33 ("java", "java"),
34 ("kt", "kotlin"),
35 ("kts", "kotlin"),
36 ("py", "python"),
37 ("rs", "rust"),
38 ("ts", "typescript"),
39 ("tsx", "tsx"),
40 ("html", "html"),
41 ("htm", "html"),
42 ("md", "markdown"),
43 ("mdx", "markdown"),
44 ("astro", "astro"),
45 ("css", "css"),
46 ("yaml", "yaml"),
47 ("yml", "yaml"),
48 ("json", "json"),
49 ("toml", "toml"),
50];
51
52#[must_use]
59pub fn language_for_extension(ext: &str) -> Option<&'static str> {
60 EXTENSION_MAP
61 .iter()
62 .find(|(e, _)| e.eq_ignore_ascii_case(ext))
63 .map(|(_, lang)| *lang)
64}
65
66#[must_use]
71pub fn supported_extensions() -> Vec<&'static str> {
72 EXTENSION_MAP.iter().map(|(ext, _)| *ext).collect()
73}
74
75#[must_use]
80pub fn supported_languages() -> &'static [&'static str] {
81 &[
82 "rust",
83 "go",
84 "java",
85 "kotlin",
86 "python",
87 "typescript",
88 "tsx",
89 "javascript",
90 "fortran",
91 "c",
92 "cpp",
93 "csharp",
94 "html",
95 "markdown",
96 ]
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_language_for_extension_happy_path() {
105 assert_eq!(language_for_extension("rs"), Some("rust"));
106 assert_eq!(language_for_extension("py"), Some("python"));
107 assert_eq!(language_for_extension("go"), Some("go"));
108 assert_eq!(language_for_extension("java"), Some("java"));
109 assert_eq!(language_for_extension("ts"), Some("typescript"));
110 assert_eq!(language_for_extension("tsx"), Some("tsx"));
111 assert_eq!(language_for_extension("f90"), Some("fortran"));
112 assert_eq!(language_for_extension("for"), Some("fortran"));
113 assert_eq!(language_for_extension("ftn"), Some("fortran"));
114 assert_eq!(language_for_extension("c"), Some("c"));
115 assert_eq!(language_for_extension("cpp"), Some("cpp"));
116 assert_eq!(language_for_extension("h"), Some("cpp"));
117 assert_eq!(language_for_extension("hpp"), Some("cpp"));
118 assert_eq!(language_for_extension("cc"), Some("cpp"));
119 assert_eq!(language_for_extension("kt"), Some("kotlin"));
120 assert_eq!(language_for_extension("kts"), Some("kotlin"));
121 }
122
123 #[test]
128 fn test_supported_file_ext_pattern_covers_all_extension_map_entries() {
129 #[cfg(feature = "schemars")]
130 for (ext, _lang) in EXTENSION_MAP {
131 let in_alternation = crate::schema_helpers::SUPPORTED_FILE_EXT_PATTERN
132 .contains(&format!("{ext}|"))
133 || crate::schema_helpers::SUPPORTED_FILE_EXT_PATTERN.contains(&format!("{ext})"));
134 assert!(
135 in_alternation,
136 "SUPPORTED_FILE_EXT_PATTERN is missing extension '{ext}' from EXTENSION_MAP; \
137 add it to schema_helpers.rs"
138 );
139 }
140 }
141
142 #[test]
143 fn test_language_for_extension_edge_case() {
144 assert_eq!(language_for_extension("unknown"), None);
145 assert_eq!(language_for_extension(""), None);
146 assert_eq!(language_for_extension("RS"), Some("rust"));
147 assert_eq!(language_for_extension("F90"), Some("fortran"));
149 assert_eq!(language_for_extension("FOR"), Some("fortran"));
150 }
151}