grapha 0.1.0

Blazingly fast code intelligence CLI and MCP server for Swift and Rust
Documentation
use serde::Serialize;

use grapha_core::graph::{Graph, NodeRole};

use super::SymbolRef;

#[derive(Debug, Serialize)]
pub struct EntriesResult {
    pub entries: Vec<SymbolRef>,
    pub total: usize,
}

pub fn query_entries(graph: &Graph) -> EntriesResult {
    let entries: Vec<SymbolRef> = graph
        .nodes
        .iter()
        .filter(|n| n.role == Some(NodeRole::EntryPoint))
        .map(|n| SymbolRef {
            id: n.id.clone(),
            name: n.name.clone(),
            kind: n.kind,
            file: n.file.to_string_lossy().to_string(),
        })
        .collect();

    let total = entries.len();
    EntriesResult { entries, total }
}

#[cfg(test)]
mod tests {
    use super::*;
    use grapha_core::graph::*;
    use std::collections::HashMap;
    use std::path::PathBuf;

    fn make_node(id: &str, role: Option<NodeRole>) -> Node {
        Node {
            id: id.into(),
            kind: NodeKind::Function,
            name: id.into(),
            file: PathBuf::from("test.rs"),
            span: Span {
                start: [0, 0],
                end: [1, 0],
            },
            visibility: Visibility::Public,
            metadata: HashMap::new(),
            role,
            signature: None,
            doc_comment: None,
            module: None,
            snippet: None,
        }
    }

    #[test]
    fn lists_entry_points() {
        let graph = Graph {
            version: "0.1.0".to_string(),
            nodes: vec![
                make_node("entry1", Some(NodeRole::EntryPoint)),
                make_node("entry2", Some(NodeRole::EntryPoint)),
                make_node("internal", Some(NodeRole::Internal)),
            ],
            edges: vec![],
        };

        let result = query_entries(&graph);
        assert_eq!(result.total, 2);
        let names: Vec<&str> = result.entries.iter().map(|e| e.name.as_str()).collect();
        assert!(names.contains(&"entry1"));
        assert!(names.contains(&"entry2"));
        assert!(!names.contains(&"internal"));
    }

    #[test]
    fn returns_empty_when_no_entries() {
        let graph = Graph {
            version: "0.1.0".to_string(),
            nodes: vec![
                make_node("a", None),
                make_node("b", Some(NodeRole::Internal)),
            ],
            edges: vec![],
        };

        let result = query_entries(&graph);
        assert_eq!(result.total, 0);
        assert!(result.entries.is_empty());
    }
}