1pub struct Language {
8 pub name: &'static str,
9 pub extensions: &'static [&'static str],
10 pub aliases: &'static [&'static str],
11}
12
13pub const LANGUAGES: &[Language] = &[
14 Language {
15 name: "rust",
16 extensions: &["rs"],
17 aliases: &["rs"],
18 },
19 Language {
20 name: "c",
21 extensions: &["c", "h"],
22 aliases: &[],
23 },
24 Language {
25 name: "cpp",
26 extensions: &["cpp", "cc", "cp", "cxx", "hpp", "hh", "hxx", "ino", "tpp"],
27 aliases: &["c++", "cxx"],
28 },
29 Language {
30 name: "lua",
31 extensions: &["lua"],
32 aliases: &["lua"],
33 },
34 Language {
35 name: "python",
36 extensions: &["py", "pyi", "pyw"],
37 aliases: &["py"],
38 },
39 Language {
40 name: "go",
41 extensions: &["go"],
42 aliases: &["golang"],
43 },
44 Language {
45 name: "javascript",
46 extensions: &["js", "jsx", "mjs", "cjs"],
47 aliases: &["js"],
48 },
49 Language {
50 name: "typescript",
51 extensions: &["ts", "tsx", "mts", "cts"],
52 aliases: &["ts"],
53 },
54 Language {
55 name: "json",
56 extensions: &["json", "jsonc"],
57 aliases: &[],
58 },
59 Language {
60 name: "shellscript",
61 extensions: &["sh", "bash", "zsh", "ksh"],
62 aliases: &["sh", "bash", "shell"],
63 },
64];
65
66pub fn language_for_extension_name(ext: &str) -> Option<&'static str> {
68 LANGUAGES
69 .iter()
70 .find(|language| language.extensions.contains(&ext))
71 .map(|language| language.name)
72}
73
74pub fn language_for_extension(ext_with_dot: &str) -> Option<&'static str> {
76 language_for_extension_name(ext_with_dot.strip_prefix('.')?)
77}
78
79pub fn extensions_for_language(name_or_alias: &str) -> Option<&'static [&'static str]> {
81 LANGUAGES
82 .iter()
83 .find(|language| {
84 language.name == name_or_alias || language.aliases.contains(&name_or_alias)
85 })
86 .map(|language| language.extensions)
87}
88
89pub fn language_names() -> impl Iterator<Item = &'static str> {
91 LANGUAGES.iter().map(|language| language.name)
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn lua_resolves_through_extension_name_and_alias() {
100 assert_eq!(language_for_extension(".lua"), Some("lua"));
101 assert_eq!(language_for_extension_name("lua"), Some("lua"));
102 assert_eq!(extensions_for_language("lua"), Some(&["lua"][..]));
103 assert!(language_names().any(|name| name == "lua"));
104 }
105
106 #[test]
107 fn ambiguous_headers_follow_one_policy() {
108 assert_eq!(language_for_extension(".h"), Some("c"));
111 for header in [".hpp", ".hh", ".hxx"] {
112 assert_eq!(language_for_extension(header), Some("cpp"));
113 }
114 }
115
116 #[test]
117 fn cpp_membership_covers_the_documented_extensions() {
118 assert_eq!(
119 extensions_for_language("c++"),
120 Some(&["cpp", "cc", "cp", "cxx", "hpp", "hh", "hxx", "ino", "tpp",][..])
121 );
122 }
123}