relay-knowledge 1.1.10

Graph-database-based knowledge graph project.
Documentation
use crate::{
    code::source_line_defines_identity,
    domain::{CodeRetrievalHit, CodeRetrievalLayer},
};

pub(super) fn hit_has_complete_source_surface(hit: &CodeRetrievalHit, identity: &str) -> bool {
    if !hit.retrieval_layers.iter().any(|layer| {
        matches!(
            layer,
            CodeRetrievalLayer::Symbol
                | CodeRetrievalLayer::Definition
                | CodeRetrievalLayer::CallGraph
        )
    }) {
        return false;
    }

    hit.excerpt
        .lines()
        .map(str::trim)
        .any(|line| source_surface_line_defines_identity(line, identity))
}

fn source_surface_line_defines_identity(line: &str, identity: &str) -> bool {
    if line.is_empty() || source_identifier_ranges(line, identity).next().is_none() {
        return false;
    }
    if synthetic_qualified_summary_line(line) {
        return false;
    }
    if source_line_defines_identity(line, identity) {
        return true;
    }
    let exported_type_surface = line
        .trim_start()
        .strip_prefix("export ")
        .or_else(|| line.trim_start().strip_prefix("pub "))
        .is_some_and(|stripped| stripped.trim_start().starts_with("type "));
    let stripped = strip_source_surface_modifiers(line);
    source_line_defines_identity(stripped, identity)
        || source_value_declaration_defines_identity(stripped, identity)
        || (exported_type_surface && source_type_alias_defines_identity(stripped, identity))
}

fn synthetic_qualified_summary_line(line: &str) -> bool {
    let Some((prefix, _)) = line.split_once(':') else {
        return false;
    };
    let prefix = prefix.trim();
    (prefix.contains('.') || prefix.contains("::"))
        && prefix.chars().all(|character| {
            character.is_ascii_alphanumeric() || matches!(character, '_' | '.' | ':')
        })
}

fn strip_source_surface_modifiers(mut line: &str) -> &str {
    loop {
        let trimmed = line.trim_start();
        let Some(stripped) = trimmed
            .strip_prefix("export default ")
            .or_else(|| trimmed.strip_prefix("export "))
            .or_else(|| trimmed.strip_prefix("pub "))
            .or_else(|| trimmed.strip_prefix("public "))
            .or_else(|| trimmed.strip_prefix("private "))
            .or_else(|| trimmed.strip_prefix("protected "))
            .or_else(|| trimmed.strip_prefix("static "))
            .or_else(|| trimmed.strip_prefix("async "))
        else {
            return trimmed;
        };
        line = stripped;
    }
}

fn source_value_declaration_defines_identity(line: &str, identity: &str) -> bool {
    let Some(remainder) = line
        .strip_prefix("const ")
        .or_else(|| line.strip_prefix("let "))
        .or_else(|| line.strip_prefix("var "))
    else {
        return false;
    };
    source_identity_starts_declaration(remainder, identity, |after| {
        after.starts_with('=') || after.starts_with(':') || after.starts_with("satisfies ")
    })
}

fn source_type_alias_defines_identity(line: &str, identity: &str) -> bool {
    let Some(remainder) = line.strip_prefix("type ") else {
        return false;
    };
    source_identity_starts_declaration(remainder, identity, |after| {
        after.starts_with('=') || after.starts_with('<')
    })
}

fn source_identity_starts_declaration(
    remainder: &str,
    identity: &str,
    accepts_suffix: impl Fn(&str) -> bool,
) -> bool {
    source_identifier_ranges(remainder, identity)
        .next()
        .is_some_and(|(start, end)| {
            start == 0
                && remainder
                    .get(end..)
                    .is_some_and(|after| accepts_suffix(after.trim_start()))
        })
}

fn source_identifier_ranges<'a>(
    line: &'a str,
    identity: &'a str,
) -> impl Iterator<Item = (usize, usize)> + 'a {
    line.match_indices(identity).filter_map(|(start, _)| {
        let end = start + identity.len();
        let has_start_boundary = line.get(..start).is_some_and(|prefix| {
            prefix
                .chars()
                .next_back()
                .is_none_or(|character| !source_identifier_char(character))
        });
        let has_end_boundary = line.get(end..).is_some_and(|suffix| {
            suffix
                .chars()
                .next()
                .is_none_or(|character| !source_identifier_char(character))
        });
        (has_start_boundary && has_end_boundary).then_some((start, end))
    })
}

fn source_identifier_char(character: char) -> bool {
    character.is_ascii_alphanumeric() || character == '_'
}