1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2pub enum LanguageId {
3 Rust,
4 TypeScript,
5 JavaScript,
6 Python,
7 Go,
8 Java,
9 C,
10 Cpp,
11 Ruby,
12 CSharp,
13 Kotlin,
14 Swift,
15 Php,
16 Bash,
17 Dart,
18 Scala,
19 Elixir,
20 Zig,
21 Vue,
22 Svelte,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct LanguageCapabilities {
27 pub deps_edges: bool,
28 pub deep_queries: bool,
29 pub import_resolver: bool,
30}
31
32impl LanguageId {
33 pub fn id_str(&self) -> &'static str {
34 match self {
35 LanguageId::Rust => "rust",
36 LanguageId::TypeScript => "typescript",
37 LanguageId::JavaScript => "javascript",
38 LanguageId::Python => "python",
39 LanguageId::Go => "go",
40 LanguageId::Java => "java",
41 LanguageId::C => "c",
42 LanguageId::Cpp => "cpp",
43 LanguageId::Ruby => "ruby",
44 LanguageId::CSharp => "csharp",
45 LanguageId::Kotlin => "kotlin",
46 LanguageId::Swift => "swift",
47 LanguageId::Php => "php",
48 LanguageId::Bash => "bash",
49 LanguageId::Dart => "dart",
50 LanguageId::Scala => "scala",
51 LanguageId::Elixir => "elixir",
52 LanguageId::Zig => "zig",
53 LanguageId::Vue => "vue",
54 LanguageId::Svelte => "svelte",
55 }
56 }
57}
58
59pub fn capabilities(lang: LanguageId) -> LanguageCapabilities {
60 match lang {
61 LanguageId::Rust
63 | LanguageId::TypeScript
64 | LanguageId::JavaScript
65 | LanguageId::Python
66 | LanguageId::Go
67 | LanguageId::Java
68 | LanguageId::C
69 | LanguageId::Cpp
70 | LanguageId::Ruby
71 | LanguageId::CSharp
72 | LanguageId::Kotlin
73 | LanguageId::Swift
74 | LanguageId::Php
75 | LanguageId::Bash
76 | LanguageId::Dart
77 | LanguageId::Scala
78 | LanguageId::Elixir
79 | LanguageId::Zig => LanguageCapabilities {
80 deps_edges: true,
81 deep_queries: true,
82 import_resolver: true,
83 },
84 LanguageId::Vue | LanguageId::Svelte => LanguageCapabilities {
86 deps_edges: true,
87 deep_queries: false,
88 import_resolver: false,
89 },
90 }
91}
92
93pub fn language_for_ext(ext: &str) -> Option<LanguageId> {
94 let e = ext.trim().trim_start_matches('.').to_lowercase();
95 match e.as_str() {
96 "rs" => Some(LanguageId::Rust),
97 "ts" | "tsx" => Some(LanguageId::TypeScript),
98 "js" | "jsx" => Some(LanguageId::JavaScript),
99 "py" => Some(LanguageId::Python),
100 "go" => Some(LanguageId::Go),
101 "java" => Some(LanguageId::Java),
102 "c" | "h" => Some(LanguageId::C),
103 "cpp" | "cc" | "cxx" | "hpp" | "hxx" | "hh" => Some(LanguageId::Cpp),
104 "rb" => Some(LanguageId::Ruby),
105 "cs" => Some(LanguageId::CSharp),
106 "kt" | "kts" => Some(LanguageId::Kotlin),
107 "swift" => Some(LanguageId::Swift),
108 "php" => Some(LanguageId::Php),
109 "sh" | "bash" => Some(LanguageId::Bash),
110 "dart" => Some(LanguageId::Dart),
111 "scala" | "sc" => Some(LanguageId::Scala),
112 "ex" | "exs" => Some(LanguageId::Elixir),
113 "zig" => Some(LanguageId::Zig),
114 "vue" => Some(LanguageId::Vue),
115 "svelte" => Some(LanguageId::Svelte),
116 _ => None,
117 }
118}
119
120pub fn language_for_path(path: &str) -> Option<LanguageId> {
121 std::path::Path::new(path)
122 .extension()
123 .and_then(|e| e.to_str())
124 .and_then(language_for_ext)
125}
126
127pub fn is_indexable_ext(ext: &str) -> bool {
128 language_for_ext(ext).is_some()
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn ext_mapping_basic() {
137 assert_eq!(language_for_ext("rs"), Some(LanguageId::Rust));
138 assert_eq!(language_for_ext(".tsx"), Some(LanguageId::TypeScript));
139 assert_eq!(language_for_ext("JS"), Some(LanguageId::JavaScript));
140 assert_eq!(language_for_ext("hxx"), Some(LanguageId::Cpp));
141 assert_eq!(language_for_ext("exs"), Some(LanguageId::Elixir));
142 assert_eq!(language_for_ext("unknown"), None);
143 }
144
145 #[test]
146 fn indexable_ext_true_for_known() {
147 assert!(is_indexable_ext("rs"));
148 assert!(is_indexable_ext("vue"));
149 assert!(!is_indexable_ext("md"));
150 }
151
152 #[test]
153 fn caps_are_deterministic() {
154 let c1 = capabilities(LanguageId::Rust);
155 let c2 = capabilities(LanguageId::Rust);
156 assert_eq!(c1, c2);
157 assert!(c1.deps_edges);
158 }
159}