use phf::phf_map;
use std::path::Path;
static EXTENSION_TO_LANG: phf::Map<&'static str, &'static str> = phf_map! {
"rs" => "rust",
"py" => "python",
"pyw" => "python",
"pyi" => "python",
"js" => "javascript",
"mjs" => "javascript",
"cjs" => "javascript",
"jsx" => "javascript",
"ts" => "typescript",
"tsx" => "typescript",
"mts" => "typescript",
"cts" => "typescript",
"go" => "go",
"c" => "c",
"h" => "c",
"cc" => "cpp",
"cpp" => "cpp",
"cxx" => "cpp",
"hpp" => "cpp",
"hxx" => "cpp",
"hh" => "cpp",
"java" => "java",
"cs" => "csharp",
"rb" => "ruby",
"rake" => "ruby",
"gemspec" => "ruby",
"php" => "php",
"php3" => "php",
"php4" => "php",
"php5" => "php",
"phtml" => "php",
"swift" => "swift",
"kt" => "kotlin",
"kts" => "kotlin",
"scala" => "scala",
"sc" => "scala",
"ex" => "elixir",
"exs" => "elixir",
"lua" => "lua",
"r" => "r",
"R" => "r",
"dart" => "dart",
"sol" => "solidity",
"elm" => "elm",
"ml" => "ocaml",
"mli" => "ocaml_interface",
"d" => "d",
"gleam" => "gleam",
"hcl" => "hcl",
"tf" => "hcl",
"rkt" => "racket",
"pony" => "pony",
"ql" => "ql",
"lisp" => "commonlisp",
"cl" => "commonlisp",
"el" => "elisp",
"ino" => "arduino",
"properties" => "properties",
};
static FILENAME_TO_LANG: phf::Map<&'static str, &'static str> = phf_map! {
"Makefile" => "make",
"makefile" => "make",
"GNUmakefile" => "make",
"Dockerfile" => "dockerfile",
"Containerfile" => "dockerfile",
"Gemfile" => "ruby",
"Rakefile" => "ruby",
".gitignore" => "gitignore",
".dockerignore" => "gitignore",
};
pub fn detect_language(path: &Path) -> Option<&'static str> {
if let Some(filename) = path.file_name().and_then(|s| s.to_str())
&& let Some(&lang) = FILENAME_TO_LANG.get(filename)
{
return Some(lang);
}
if let Some(ext) = path.extension().and_then(|s| s.to_str())
&& let Some(&lang) = EXTENSION_TO_LANG.get(ext)
{
return Some(lang);
}
None
}
pub fn has_query_support(lang: &str) -> bool {
matches!(
lang,
"rust"
| "python"
| "javascript"
| "typescript"
| "go"
| "c"
| "cpp"
| "java"
| "csharp"
| "ruby"
| "php"
| "swift"
| "kotlin"
| "scala"
| "elixir"
| "lua"
| "r"
| "dart"
| "solidity"
| "elm"
| "ocaml"
| "ocaml_interface"
| "d"
| "gleam"
| "hcl"
| "racket"
| "pony"
| "ql"
| "commonlisp"
| "elisp"
| "arduino"
| "properties"
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
#[test]
fn detect_by_extension() {
assert_eq!(detect_language(Path::new("main.rs")), Some("rust"));
assert_eq!(detect_language(Path::new("lib.py")), Some("python"));
assert_eq!(detect_language(Path::new("app.ts")), Some("typescript"));
assert_eq!(detect_language(Path::new("main.go")), Some("go"));
assert_eq!(detect_language(Path::new("App.java")), Some("java"));
}
#[test]
fn detect_by_full_name() {
assert_eq!(detect_language(Path::new("Makefile")), Some("make"));
assert_eq!(detect_language(Path::new("Dockerfile")), Some("dockerfile"));
assert_eq!(detect_language(Path::new("Gemfile")), Some("ruby"));
}
#[test]
fn detect_unknown_returns_none() {
assert_eq!(detect_language(Path::new("data.csv")), None);
assert_eq!(detect_language(Path::new("image.png")), None);
assert_eq!(detect_language(Path::new("README")), None);
}
#[test]
fn detect_with_path() {
assert_eq!(detect_language(Path::new("src/lib/main.rs")), Some("rust"));
assert_eq!(
detect_language(Path::new("/absolute/path/to/file.py")),
Some("python")
);
}
#[test]
fn has_query_support_basic() {
assert!(has_query_support("rust"));
assert!(has_query_support("python"));
assert!(has_query_support("typescript"));
assert!(!has_query_support("make"));
assert!(!has_query_support("dockerfile"));
}
}