leindex 1.6.0

LeIndex MCP and semantic code search engine for AI tools and large codebases
// Dart language parser implementation

use crate::parse::traits::{CodeIntelligence, ComplexityMetrics, Error, Graph, Result, SignatureInfo};
use crate::parse::traits::{Block, Edge, EdgeType, Parameter, Visibility};
use tree_sitter::Parser;

pub struct DartParser;

impl Default for DartParser {
    fn default() -> Self { Self::new() }
}

impl DartParser {
    pub fn new() -> Self { Self }
}

impl CodeIntelligence for DartParser {
    fn get_signatures(&self, source: &[u8]) -> Result<Vec<SignatureInfo>> {
        let mut parser = Parser::new();
        parser.set_language(&crate::parse::traits::languages::dart::language())
            .map_err(|e| Error::ParseFailed(e.to_string()))?;
        let tree = parser.parse(source, None)
            .ok_or_else(|| Error::ParseFailed("Failed to parse Dart source".to_string()))?;
        let mut signatures = Vec::new();
        fn visit(node: &tree_sitter::Node, source: &[u8], sigs: &mut Vec<SignatureInfo>) {
            match node.kind() {
                "function_definition" => {
                    if let Some(name) = node.child_by_field_name("name").and_then(|n| n.utf8_text(source).ok()) {
                        sigs.push(SignatureInfo {
                            name: name.to_string(),
                            qualified_name: name.to_string(),
                            parameters: vec![],
                            return_type: None,
                            visibility: Visibility::Public,
                            is_async: {
                                let mut cursor = node.walk();
                                let mut found = false;
                                for child in node.children(&mut cursor) {
                                    if let Ok(text) = child.utf8_text(source) {
                                        if text == "async" {
                                            found = true;
                                            break;
                                        }
                                    }
                                }
                                found
                            },
                            is_method: false,
                            docstring: None,
                            calls: vec![],
                            imports: vec![],
                            byte_range: (0, 0),
                            cyclomatic_complexity: 0,
                            });
                    }
                }
                "class_definition" => {
                    if let Some(name) = node.child_by_field_name("name").and_then(|n| n.utf8_text(source).ok()) {
                        sigs.push(SignatureInfo {
                            name: name.to_string(),
                            qualified_name: name.to_string(),
                            parameters: vec![],
                            return_type: Some("class".to_string()),
                            visibility: Visibility::Public,
                            is_async: false,
                            is_method: false,
                            docstring: None,
                            calls: vec![],
                            imports: vec![],
                            byte_range: (0, 0),
                            cyclomatic_complexity: 0,
                            });
                    }
                }
                _ => { let mut c = node.walk(); for ch in node.children(&mut c) { visit(&ch, source, sigs); } }
            }
        }
        visit(&tree.root_node(), source, &mut signatures);
        Ok(signatures)
    }

    fn compute_cfg(&self, source: &[u8], _node_id: usize) -> Result<Graph<Block, Edge>> {
        let mut parser = Parser::new();
        parser.set_language(&crate::parse::traits::languages::dart::language())
            .map_err(|e| Error::ParseFailed(e.to_string()))?;
        parser.parse(source, None).ok_or_else(|| Error::ParseFailed("Failed to parse".to_string()))?;
        Ok(Graph { blocks: vec![], edges: vec![], entry_block: 0, exit_blocks: vec![] })
    }

    fn extract_complexity(&self, node: &tree_sitter::Node) -> ComplexityMetrics {
        ComplexityMetrics { cyclomatic: 1, nesting_depth: 0, line_count: 1, token_count: node.child_count() }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_dart_function() {
        let source = b"String greet(String name) => 'Hello, $name';";
        let parser = DartParser::new();
        assert!(parser.get_signatures(source).unwrap().len() > 0);
    }

    #[test]
    fn test_dart_async() {
        let source = b"Future<void> fetchData() async {}";
        let parser = DartParser::new();
        let sigs = parser.get_signatures(source).unwrap();
        assert_eq!(sigs.len(), 1);
        assert!(sigs[0].is_async);
    }
}