Skip to main content

qex_core/chunk/languages/
csharp.rs

1use super::{extract_preceding_comments, find_child_text, find_name, NodeMetadata, LanguageChunker};
2use crate::chunk::ChunkType;
3
4pub struct CSharpChunker;
5
6impl LanguageChunker for CSharpChunker {
7    fn tree_sitter_language(&self) -> tree_sitter::Language {
8        tree_sitter_c_sharp::LANGUAGE.into()
9    }
10
11    fn language_name(&self) -> &str {
12        "csharp"
13    }
14
15    fn file_extensions(&self) -> &[&str] {
16        &["cs"]
17    }
18
19    fn is_splittable(&self, node_type: &str) -> bool {
20        matches!(
21            node_type,
22            "method_declaration"
23                | "class_declaration"
24                | "interface_declaration"
25                | "struct_declaration"
26                | "enum_declaration"
27                | "namespace_declaration"
28                | "constructor_declaration"
29                | "property_declaration"
30        )
31    }
32
33    fn has_nested_chunks(&self, node_type: &str) -> bool {
34        matches!(
35            node_type,
36            "class_declaration"
37                | "interface_declaration"
38                | "struct_declaration"
39                | "namespace_declaration"
40        )
41    }
42
43    fn classify_node(&self, node_type: &str, parent_name: Option<&str>) -> ChunkType {
44        match node_type {
45            "class_declaration" => ChunkType::Class,
46            "interface_declaration" => ChunkType::Interface,
47            "struct_declaration" => ChunkType::Struct,
48            "enum_declaration" => ChunkType::Enum,
49            "namespace_declaration" => ChunkType::Namespace,
50            "method_declaration" | "constructor_declaration" | "property_declaration" => {
51                if parent_name.is_some() {
52                    ChunkType::Method
53                } else {
54                    ChunkType::Function
55                }
56            }
57            _ => ChunkType::ModuleLevel,
58        }
59    }
60
61    fn extract_metadata(&self, node: tree_sitter::Node, source: &str) -> NodeMetadata {
62        let mut meta = NodeMetadata::default();
63
64        match node.kind() {
65            "method_declaration" | "constructor_declaration" | "property_declaration" => {
66                meta.name = find_name(node, source);
67                meta.docstring = extract_preceding_comments(node, source);
68                // Check for attributes
69                if let Some(prev) = node.prev_sibling() {
70                    if prev.kind() == "attribute_list" {
71                        let text = &source[prev.start_byte()..prev.end_byte()];
72                        meta.decorators.push(text.to_string());
73                    }
74                }
75                let text = &source[node.start_byte()..node.end_byte()];
76                meta.is_async = text.contains("async ");
77            }
78            "class_declaration" | "interface_declaration" | "struct_declaration"
79            | "enum_declaration" => {
80                meta.name = find_name(node, source);
81                meta.docstring = extract_preceding_comments(node, source);
82            }
83            "namespace_declaration" => {
84                meta.name = find_name(node, source)
85                    .or_else(|| find_child_text(node, source, "qualified_name"));
86                meta.docstring = extract_preceding_comments(node, source);
87            }
88            _ => {
89                meta.name = find_name(node, source);
90                meta.docstring = extract_preceding_comments(node, source);
91            }
92        }
93
94        meta
95    }
96}