1pub mod c;
7pub mod cfg_builder;
8pub mod csharp;
9pub mod ecmascript;
10pub mod function_body;
11pub mod go;
12pub mod java;
13pub mod parser;
14pub mod python;
15pub mod rust;
16pub mod span;
17pub mod tree_sitter_utils;
18
19use std::path::Path;
20
21use serde::{Deserialize, Serialize};
22
23pub use c::{CCfgBuilder, CParser};
24pub use cfg_builder::{get_builder_for_function, CfgBuilder};
25pub use csharp::{CSharpCfgBuilder, CSharpParser};
26pub use ecmascript::{ECMAScriptCfgBuilder, ECMAScriptParser, VueParser};
27pub use function_body::FunctionBody;
28pub use go::{GoCfgBuilder, GoParser};
29pub use java::{JavaCfgBuilder, JavaParser};
30pub use parser::{LanguageParser, ParsedModule};
31pub use python::{PythonCfgBuilder, PythonParser};
32pub use rust::{RustCfgBuilder, RustParser};
33pub use span::SourceSpan;
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub enum Language {
38 TypeScript,
40 TypeScriptReact,
42 JavaScript,
44 JavaScriptReact,
46 Go,
48 Java,
50 Python,
52 Rust,
54 Vue,
56 CSharp,
58 C,
60 CHeader,
62}
63
64impl Language {
65 pub fn from_extension(ext: &str) -> Option<Self> {
80 match ext {
81 "ts" | "mts" | "cts" => Some(Language::TypeScript),
83 "tsx" | "mtsx" | "ctsx" => Some(Language::TypeScriptReact),
84 "js" | "mjs" | "cjs" => Some(Language::JavaScript),
86 "jsx" | "mjsx" | "cjsx" => Some(Language::JavaScriptReact),
87 "go" => Some(Language::Go),
89 "java" => Some(Language::Java),
91 "py" | "pyw" => Some(Language::Python),
93 "rs" => Some(Language::Rust),
95 "vue" => Some(Language::Vue),
97 "cs" => Some(Language::CSharp),
99 "c" => Some(Language::C),
101 "h" => Some(Language::CHeader),
102 _ => None,
104 }
105 }
106
107 pub fn suppression_comment_prefix(&self) -> &'static str {
113 match self {
114 Language::Python => "#",
115 _ => "//",
116 }
117 }
118
119 pub fn from_path(path: &Path) -> Option<Self> {
143 path.extension()
144 .and_then(|ext| ext.to_str())
145 .and_then(Self::from_extension)
146 }
147
148 pub fn name(&self) -> &'static str {
161 match self {
162 Language::TypeScript => "TypeScript",
163 Language::TypeScriptReact => "TypeScript React",
164 Language::JavaScript => "JavaScript",
165 Language::JavaScriptReact => "JavaScript React",
166 Language::Go => "Go",
167 Language::Java => "Java",
168 Language::Python => "Python",
169 Language::Rust => "Rust",
170 Language::Vue => "Vue",
171 Language::CSharp => "C#",
172 Language::C => "C",
173 Language::CHeader => "C Header",
174 }
175 }
176
177 pub fn is_typescript(&self) -> bool {
179 matches!(self, Language::TypeScript | Language::TypeScriptReact)
180 }
181
182 pub fn is_javascript(&self) -> bool {
184 matches!(self, Language::JavaScript | Language::JavaScriptReact)
185 }
186
187 pub fn is_ecmascript(&self) -> bool {
189 self.is_typescript() || self.is_javascript()
190 }
191
192 pub fn extensions(&self) -> &[&'static str] {
196 match self {
197 Language::TypeScript => &["ts", "mts", "cts"],
198 Language::TypeScriptReact => &["tsx", "mtsx", "ctsx"],
199 Language::JavaScript => &["js", "mjs", "cjs"],
200 Language::JavaScriptReact => &["jsx", "mjsx", "cjsx"],
201 Language::Go => &["go"],
202 Language::Java => &["java"],
203 Language::Python => &["py", "pyw"],
204 Language::Rust => &["rs"],
205 Language::Vue => &["vue"],
206 Language::CSharp => &["cs"],
207 Language::C => &["c"],
208 Language::CHeader => &["h"],
209 }
210 }
211
212 pub fn from_name(s: &str) -> Option<Self> {
214 match s {
215 "TypeScript" => Some(Language::TypeScript),
216 "TypeScript React" => Some(Language::TypeScriptReact),
217 "JavaScript" => Some(Language::JavaScript),
218 "JavaScript React" => Some(Language::JavaScriptReact),
219 "Go" => Some(Language::Go),
220 "Java" => Some(Language::Java),
221 "Python" => Some(Language::Python),
222 "Rust" => Some(Language::Rust),
223 "Vue" => Some(Language::Vue),
224 "C#" => Some(Language::CSharp),
225 "C" => Some(Language::C),
226 "C Header" => Some(Language::CHeader),
227 _ => None,
228 }
229 }
230}
231
232impl Serialize for Language {
233 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
234 s.serialize_str(self.name())
235 }
236}
237
238impl<'de> Deserialize<'de> for Language {
239 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
240 let s = String::deserialize(d)?;
241 Language::from_name(&s)
242 .ok_or_else(|| serde::de::Error::custom(format!("unknown language: {s}")))
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn test_from_extension_typescript() {
252 assert_eq!(Language::from_extension("ts"), Some(Language::TypeScript));
253 assert_eq!(Language::from_extension("mts"), Some(Language::TypeScript));
254 assert_eq!(Language::from_extension("cts"), Some(Language::TypeScript));
255 assert_eq!(
256 Language::from_extension("tsx"),
257 Some(Language::TypeScriptReact)
258 );
259 }
260
261 #[test]
262 fn test_from_extension_javascript() {
263 assert_eq!(Language::from_extension("js"), Some(Language::JavaScript));
264 assert_eq!(Language::from_extension("mjs"), Some(Language::JavaScript));
265 assert_eq!(Language::from_extension("cjs"), Some(Language::JavaScript));
266 assert_eq!(
267 Language::from_extension("jsx"),
268 Some(Language::JavaScriptReact)
269 );
270 }
271
272 #[test]
273 fn test_from_extension_go() {
274 assert_eq!(Language::from_extension("go"), Some(Language::Go));
275 }
276
277 #[test]
278 fn test_from_extension_rust() {
279 assert_eq!(Language::from_extension("rs"), Some(Language::Rust));
280 }
281
282 #[test]
283 fn test_from_extension_java() {
284 assert_eq!(Language::from_extension("java"), Some(Language::Java));
285 }
286
287 #[test]
288 fn test_from_extension_unknown() {
289 assert_eq!(Language::from_extension("cpp"), None);
290 assert_eq!(Language::from_extension(""), None);
291 }
292
293 #[test]
294 fn test_from_extension_c() {
295 assert_eq!(Language::from_extension("c"), Some(Language::C));
296 assert_eq!(Language::from_extension("h"), Some(Language::CHeader));
297 }
298
299 #[test]
300 fn test_from_path() {
301 assert_eq!(
302 Language::from_path(Path::new("src/main.ts")),
303 Some(Language::TypeScript)
304 );
305 assert_eq!(
306 Language::from_path(Path::new("src/component.tsx")),
307 Some(Language::TypeScriptReact)
308 );
309 assert_eq!(
310 Language::from_path(Path::new("main.go")),
311 Some(Language::Go)
312 );
313 assert_eq!(
314 Language::from_path(Path::new("lib.rs")),
315 Some(Language::Rust)
316 );
317 assert_eq!(Language::from_path(Path::new("README.md")), None);
318 assert_eq!(Language::from_path(Path::new("Makefile")), None);
319 }
320
321 #[test]
322 fn test_name() {
323 assert_eq!(Language::TypeScript.name(), "TypeScript");
324 assert_eq!(Language::TypeScriptReact.name(), "TypeScript React");
325 assert_eq!(Language::JavaScript.name(), "JavaScript");
326 assert_eq!(Language::JavaScriptReact.name(), "JavaScript React");
327 assert_eq!(Language::Go.name(), "Go");
328 assert_eq!(Language::Rust.name(), "Rust");
329 }
330
331 #[test]
332 fn test_is_typescript() {
333 assert!(Language::TypeScript.is_typescript());
334 assert!(Language::TypeScriptReact.is_typescript());
335 assert!(!Language::JavaScript.is_typescript());
336 assert!(!Language::Go.is_typescript());
337 assert!(!Language::Rust.is_typescript());
338 }
339
340 #[test]
341 fn test_is_javascript() {
342 assert!(Language::JavaScript.is_javascript());
343 assert!(Language::JavaScriptReact.is_javascript());
344 assert!(!Language::TypeScript.is_javascript());
345 assert!(!Language::Go.is_javascript());
346 assert!(!Language::Rust.is_javascript());
347 }
348
349 #[test]
350 fn test_is_ecmascript() {
351 assert!(Language::TypeScript.is_ecmascript());
352 assert!(Language::TypeScriptReact.is_ecmascript());
353 assert!(Language::JavaScript.is_ecmascript());
354 assert!(Language::JavaScriptReact.is_ecmascript());
355 assert!(!Language::Go.is_ecmascript());
356 assert!(!Language::Rust.is_ecmascript());
357 }
358
359 #[test]
360 fn test_extensions() {
361 assert_eq!(Language::TypeScript.extensions(), &["ts", "mts", "cts"]);
362 assert_eq!(
363 Language::TypeScriptReact.extensions(),
364 &["tsx", "mtsx", "ctsx"]
365 );
366 assert_eq!(Language::Go.extensions(), &["go"]);
367 assert_eq!(Language::Rust.extensions(), &["rs"]);
368 }
369}