relay-knowledge 1.0.7

Graph-database-based knowledge graph project.
Documentation
use tree_sitter::Node;

#[derive(Debug, Clone)]
pub(super) struct SyntaxRange {
    pub(super) byte_start: usize,
    pub(super) byte_end: usize,
    pub(super) line_start: usize,
    pub(super) line_end: usize,
}

pub(super) fn syntax_range(node: Node<'_>) -> SyntaxRange {
    SyntaxRange {
        byte_start: node.start_byte(),
        byte_end: node.end_byte(),
        line_start: node.start_position().row + 1,
        line_end: node.end_position().row + 1,
    }
}

pub(super) fn node_text(content: &str, node: Node<'_>) -> String {
    node.utf8_text(content.as_bytes())
        .unwrap_or_default()
        .trim()
        .to_owned()
}

pub(super) fn last_identifier_text(content: &str, node: Node<'_>) -> Option<String> {
    let mut stack = Vec::with_capacity(node.child_count().saturating_add(1));
    stack.push(node);
    let mut last = None;
    while let Some(current) = stack.pop() {
        if matches!(
            current.kind(),
            "command_name"
                | "identifier"
                | "field_identifier"
                | "property_identifier"
                | "type_identifier"
                | "word"
        ) {
            last = Some(node_text(content, current));
            continue;
        }
        push_children_reverse(current, &mut stack);
    }

    last
}

pub(super) fn push_children_reverse<'tree>(node: Node<'tree>, stack: &mut Vec<Node<'tree>>) {
    for index in (0..node.child_count()).rev() {
        let Ok(index) = u32::try_from(index) else {
            continue;
        };
        if let Some(child) = node.child(index) {
            stack.push(child);
        }
    }
}

pub(super) fn first_named_child_of_kind<'tree>(
    root: Node<'tree>,
    kind: &str,
) -> Option<Node<'tree>> {
    let mut stack = Vec::new();
    push_children_reverse(root, &mut stack);
    while let Some(node) = stack.pop() {
        if node.kind() == kind {
            return Some(node);
        }
        push_children_reverse(node, &mut stack);
    }

    None
}

pub(super) fn compact_whitespace(value: &str) -> String {
    value.split_whitespace().collect::<Vec<_>>().join(" ")
}