1pub fn from_path(path: &str) -> Option<&'static str> {
6 let extension = path.rsplit('.').next()?.to_ascii_lowercase();
7 Some(match extension.as_str() {
8 "ts" | "tsx" => "typescript",
9 "js" | "jsx" | "mjs" | "cjs" => "javascript",
10 "py" => "python",
11 "rb" => "ruby",
12 "rs" => "rust",
13 "go" => "go",
14 "java" => "java",
15 "kt" => "kotlin",
16 "swift" => "swift",
17 "c" | "h" => "c",
18 "cpp" | "cc" | "cxx" | "hpp" => "cpp",
19 "cs" => "csharp",
20 "php" => "php",
21 "sh" | "bash" | "zsh" => "bash",
22 "fish" => "fish",
23 "ps1" => "powershell",
24 "sql" => "sql",
25 "html" | "htm" => "html",
26 "css" => "css",
27 "scss" => "scss",
28 "sass" => "sass",
29 "less" => "less",
30 "json" => "json",
31 "yaml" | "yml" => "yaml",
32 "toml" => "toml",
33 "xml" => "xml",
34 "md" | "markdown" => "markdown",
35 "dockerfile" => "dockerfile",
36 "makefile" => "makefile",
37 "cmake" => "cmake",
38 "lua" => "lua",
39 "perl" => "perl",
40 "r" => "r",
41 "scala" => "scala",
42 "clj" => "clojure",
43 "ex" | "exs" => "elixir",
44 "erl" => "erlang",
45 "hs" => "haskell",
46 "ml" => "ocaml",
47 "vim" => "vim",
48 "graphql" => "graphql",
49 "proto" => "protobuf",
50 "tf" | "hcl" => "hcl",
51 _ => return None,
52 })
53}
54
55#[cfg(test)]
56mod tests {
57 use super::from_path;
58
59 #[test]
60 fn languages_by_extension() {
61 assert_eq!(from_path("src/main.rs"), Some("rust"));
62 assert_eq!(from_path("a/b.test.TSX"), Some("typescript"));
63 assert_eq!(from_path("Dockerfile"), Some("dockerfile"));
64 assert_eq!(from_path("notes.txt"), None);
65 assert_eq!(from_path("Makefile.am"), None);
66 assert_eq!(from_path("trailing."), None);
67 }
68}