crabmap 0.1.1

Rust code satellite map — index, query, and navigate your entire codebase
use crate::model::{CodeGraph, Node, NodeKind};
use serde_json::{Value, json};

use super::index::QueryIndex;
use super::traversal::node_value;

pub(crate) fn ranked_nodes<'a>(
    graph: &'a CodeGraph,
    index: &QueryIndex<'a>,
    query: &str,
    limit: usize,
) -> Vec<&'a Node> {
    let terms = query
        .to_lowercase()
        .split(|char: char| !char.is_ascii_alphanumeric() && char != '_')
        .filter(|term| !term.is_empty())
        .map(ToString::to_string)
        .collect::<Vec<_>>();
    let mut nodes = graph
        .nodes
        .iter()
        .filter(|node| !matches!(node.kind, NodeKind::Project))
        .map(|node| {
            let haystack = format!(
                "{} {} {} {}",
                node.name,
                node.qualified_name,
                node.file.as_deref().unwrap_or_default(),
                node.docs.as_deref().unwrap_or_default()
            )
            .to_lowercase();
            let text_score = if terms.is_empty() {
                1
            } else {
                terms
                    .iter()
                    .map(|term| {
                        if haystack == *term {
                            100
                        } else if haystack.contains(term) {
                            20
                        } else {
                            0
                        }
                    })
                    .sum()
            };
            if !terms.is_empty() && text_score == 0 {
                return (0, node);
            }
            let degree = index.degree(&node.id);
            (text_score + degree, node)
        })
        .filter(|(score, _)| *score > 0)
        .collect::<Vec<_>>();
    nodes.sort_by_key(|(score, node)| {
        (
            std::cmp::Reverse(*score),
            node.kind.as_str().to_string(),
            node.qualified_name.clone(),
        )
    });
    nodes
        .into_iter()
        .map(|(_, node)| node)
        .take(limit)
        .collect()
}

pub(crate) fn hot_symbols(graph: &CodeGraph, index: &QueryIndex, limit: usize) -> Vec<Value> {
    let mut items = graph
        .nodes
        .iter()
        .filter(|node| {
            !matches!(
                node.kind,
                NodeKind::Project | NodeKind::Crate | NodeKind::File | NodeKind::Module
            )
        })
        .map(|node| (index.degree(&node.id), node))
        .collect::<Vec<_>>();
    items.sort_by_key(|(degree, node)| (std::cmp::Reverse(*degree), node.qualified_name.clone()));
    items
        .into_iter()
        .take(limit)
        .map(|(degree, node)| {
            let mut value = node_value(index, node);
            value["degree"] = json!(degree);
            value
        })
        .collect()
}