use tree_sitter::Language;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SupportedLanguage {
Rust,
Python,
JavaScript,
TypeScript,
Go,
C,
Cpp,
Java,
CSharp,
}
impl SupportedLanguage {
pub fn name(&self) -> &'static str {
match self {
Self::Rust => "rust",
Self::Python => "python",
Self::JavaScript => "javascript",
Self::TypeScript => "typescript",
Self::Go => "go",
Self::C => "c",
Self::Cpp => "cpp",
Self::Java => "java",
Self::CSharp => "csharp",
}
}
pub fn tree_sitter_language(&self) -> Language {
match self {
Self::Rust => tree_sitter_rust::language(),
Self::Python => tree_sitter_python::language(),
Self::JavaScript => tree_sitter_javascript::language(),
Self::TypeScript => tree_sitter_typescript::language_typescript(),
Self::Go => tree_sitter_go::language(),
Self::C => tree_sitter_c::language(),
Self::Cpp => tree_sitter_cpp::language(),
Self::Java => tree_sitter_java::language(),
Self::CSharp => tree_sitter_c_sharp::language(),
}
}
pub fn function_node_types(&self) -> &'static [&'static str] {
match self {
Self::Rust => &["function_item"],
Self::Python => &["function_definition"],
Self::JavaScript => &[
"function_declaration",
"method_definition",
"arrow_function",
],
Self::TypeScript => &[
"function_declaration",
"method_definition",
"arrow_function",
],
Self::Go => &["function_declaration", "method_declaration"],
Self::C => &["function_definition"],
Self::Cpp => &["function_definition"],
Self::Java => &["method_declaration"],
Self::CSharp => &[
"method_declaration",
"constructor_declaration",
"property_declaration",
],
}
}
pub fn class_node_types(&self) -> &'static [&'static str] {
match self {
Self::Rust => &["struct_item", "enum_item", "trait_item", "impl_item"],
Self::Python => &["class_definition"],
Self::JavaScript | Self::TypeScript => &["class_declaration"],
Self::Go => &["type_declaration"],
Self::C => &["struct_specifier"],
Self::Cpp => &["class_specifier", "struct_specifier"],
Self::Java => &["class_declaration", "interface_declaration"],
Self::CSharp => &[
"class_declaration",
"interface_declaration",
"struct_declaration",
"record_declaration",
],
}
}
pub fn name_field(&self) -> &'static str {
match self {
Self::Rust => "name",
Self::Python => "name",
Self::JavaScript | Self::TypeScript => "name",
Self::Go => "name",
Self::C | Self::Cpp => "declarator",
Self::Java => "name",
Self::CSharp => "name",
}
}
}
pub fn get_language(extension: &str) -> Option<SupportedLanguage> {
match extension.to_lowercase().as_str() {
"rs" => Some(SupportedLanguage::Rust),
"py" | "pyi" => Some(SupportedLanguage::Python),
"js" | "jsx" | "mjs" | "cjs" => Some(SupportedLanguage::JavaScript),
"ts" | "tsx" => Some(SupportedLanguage::TypeScript),
"go" => Some(SupportedLanguage::Go),
"c" | "h" => Some(SupportedLanguage::C),
"cpp" | "cc" | "cxx" | "hpp" | "hxx" => Some(SupportedLanguage::Cpp),
"java" => Some(SupportedLanguage::Java),
"cs" => Some(SupportedLanguage::CSharp),
_ => None,
}
}
pub fn get_non_code_language(filename: &str, extension: &str) -> Option<&'static str> {
match filename.to_lowercase().as_str() {
"dockerfile" => return Some("dockerfile"),
"package.json" | "tsconfig.json" | "appsettings.json" => return Some("json"),
".env.example" => return Some("env"),
_ => {}
}
match extension.to_lowercase().as_str() {
"md" => Some("markdown"),
"yml" | "yaml" => Some("yaml"),
"toml" => Some("toml"),
"dockerfile" => Some("dockerfile"),
"sql" => Some("sql"),
"sh" | "bash" => Some("shell"),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_non_code_language_extensions() {
assert_eq!(get_non_code_language("README.md", "md"), Some("markdown"));
assert_eq!(get_non_code_language("ci.yml", "yml"), Some("yaml"));
assert_eq!(get_non_code_language("ci.yaml", "yaml"), Some("yaml"));
assert_eq!(get_non_code_language("Cargo.toml", "toml"), Some("toml"));
assert_eq!(get_non_code_language("schema.sql", "sql"), Some("sql"));
assert_eq!(get_non_code_language("build.sh", "sh"), Some("shell"));
assert_eq!(get_non_code_language("install.bash", "bash"), Some("shell"));
}
#[test]
fn test_get_non_code_language_exact_filenames() {
assert_eq!(get_non_code_language("Dockerfile", ""), Some("dockerfile"));
assert_eq!(get_non_code_language("dockerfile", ""), Some("dockerfile"));
assert_eq!(get_non_code_language("package.json", "json"), Some("json"));
assert_eq!(get_non_code_language("tsconfig.json", "json"), Some("json"));
assert_eq!(
get_non_code_language("appsettings.json", "json"),
Some("json")
);
assert_eq!(
get_non_code_language(".env.example", "example"),
Some("env")
);
}
#[test]
fn test_get_non_code_language_env_never_indexed() {
assert_eq!(get_non_code_language(".env", ""), None);
assert_eq!(get_non_code_language(".env.local", "local"), None);
assert_eq!(get_non_code_language(".env.production", "production"), None);
}
#[test]
fn test_get_non_code_language_arbitrary_json_not_indexed() {
assert_eq!(get_non_code_language("config.json", "json"), None);
assert_eq!(get_non_code_language("data.json", "json"), None);
assert_eq!(
get_non_code_language("appsettings.Development.json", "json"),
None
);
assert_eq!(
get_non_code_language("appsettings.Production.json", "json"),
None
);
}
#[test]
fn test_get_non_code_language_unknown_returns_none() {
assert_eq!(get_non_code_language("image.png", "png"), None);
assert_eq!(get_non_code_language("binary.bin", "bin"), None);
assert_eq!(get_non_code_language("notes.txt", "txt"), None);
}
}