devgen_splitter/lang.rs
1//
2// lang.rs
3// Copyright (C) 2024 imotai <codego.me@gmail.com>
4// Distributed under terms of the MIT license.
5//
6
7mod queries;
8use queries::ALL_LANGS;
9
10/// the language config
11#[derive(Debug)]
12pub struct LangConfig {
13 /// e.g.: ["Typescript", "TSX"], ["Rust"]
14 pub lang: &'static [&'static str],
15 /// tree-sitter grammar for this language
16 pub grammar: fn() -> tree_sitter::Language,
17 /// file_extensions for this language
18 pub file_extensions: &'static [&'static str],
19 /// the query used to extract the class, function definition
20 pub query: &'static str,
21}
22
23pub struct Lang;
24
25impl Lang {
26 /// Determines the language configuration based on the given filename.
27 ///
28 /// This method attempts to match the file extension of the provided filename
29 /// with the supported language configurations. If a match is found, it returns
30 /// the corresponding `LangConfig`.
31 ///
32 /// # Arguments
33 ///
34 /// * `filename` - A string slice that holds the name of the file
35 ///
36 /// # Returns
37 ///
38 /// * `Some(&'static LangConfig)` if a matching language configuration is found
39 /// * `None` if no matching language configuration is found
40 ///
41 /// # Example
42 ///
43 /// ```no_run
44 /// use devgen_splitter::Lang;
45 /// let filename = "example.rs";
46 /// if let Some(lang_config) = Lang::from_filename(filename) {
47 /// println!("Language: {:?}", lang_config.lang);
48 /// println!("File extensions: {:?}", lang_config.file_extensions);
49 /// } else {
50 /// println!("Unsupported file type");
51 /// }
52 /// ```
53 pub fn from_filename(filename: &str) -> Option<&'static LangConfig> {
54 let path = std::path::Path::new(filename);
55 let file_ext = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
56 let lang = ALL_LANGS
57 .iter()
58 .find(|l| l.file_extensions.iter().any(|&ext| ext == file_ext));
59 match lang {
60 Some(lang) => Some(lang),
61 None => None,
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 use rstest::rstest;
70
71 #[rstest]
72 #[case("example.rs", Some("Rust"))]
73 #[case("example.ts", Some("TypeScript"))]
74 #[case("unknown.xyz", None)]
75 fn test_from_filename(#[case] filename: &str, #[case] expected_lang: Option<&str>) {
76 let result = Lang::from_filename(filename);
77 match expected_lang {
78 Some(lang) => {
79 assert!(result.is_some());
80 assert_eq!(result.unwrap().lang[0], lang);
81 }
82 None => assert!(result.is_none()),
83 }
84 }
85}