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}