relay-knowledge 1.1.16

Graph-database-based knowledge graph project.
Documentation
pub(in crate::code::parser) fn import_specs(import_declaration: &str) -> Vec<String> {
    let mut specs = Vec::new();
    let mut search_start = 0usize;
    while let Some((quote_start, quote)) = next_import_quote(import_declaration, search_start) {
        let Some(quote_end) = import_declaration[quote_start + quote.len_utf8()..]
            .find(quote)
            .map(|offset| quote_start + quote.len_utf8() + offset)
        else {
            break;
        };
        let import_path = &import_declaration[quote_start + quote.len_utf8()..quote_end];
        if let Some(spec) = import_spec_before_quote(import_declaration, quote_start, import_path)
            && !specs.contains(&spec)
        {
            specs.push(spec);
        }
        search_start = quote_end + quote.len_utf8();
    }

    specs
}

fn next_import_quote(value: &str, start: usize) -> Option<(usize, char)> {
    let mut line_comment = false;
    let mut block_comment = false;
    let mut characters = value[start..].char_indices().peekable();
    while let Some((offset, character)) = characters.next() {
        let index = start + offset;
        if line_comment {
            if character == '\n' {
                line_comment = false;
            }
            continue;
        }
        if block_comment {
            if character == '*' && value[index + character.len_utf8()..].starts_with('/') {
                characters.next();
                block_comment = false;
            }
            continue;
        }
        if character == '/' && value[index + character.len_utf8()..].starts_with('/') {
            characters.next();
            line_comment = true;
            continue;
        }
        if character == '/' && value[index + character.len_utf8()..].starts_with('*') {
            characters.next();
            block_comment = true;
            continue;
        }
        if matches!(character, '"' | '`') {
            return Some((index, character));
        }
    }

    None
}

fn import_spec_before_quote(
    import_declaration: &str,
    quote_start: usize,
    import_path: &str,
) -> Option<String> {
    if import_path.trim().is_empty() {
        return None;
    }
    let prefix_start = import_declaration[..quote_start]
        .rfind(['\n', '(', ';'])
        .map_or(0, |index| index + 1);
    let raw_prefix = import_declaration[prefix_start..quote_start].trim();
    if raw_prefix.contains("//")
        || raw_prefix.starts_with("/*")
        || raw_prefix.rfind("/*") > raw_prefix.rfind("*/")
    {
        return None;
    }
    let prefix = raw_prefix
        .strip_prefix("import")
        .map_or(raw_prefix, str::trim);
    let alias = prefix
        .split_whitespace()
        .last()
        .filter(|value| matches!(*value, "." | "_") || go_identifier(value));

    Some(match alias {
        Some(alias) => format!("{alias} {import_path}"),
        None => import_path.to_owned(),
    })
}

fn go_identifier(value: &str) -> bool {
    let mut characters = value.chars();
    characters
        .next()
        .is_some_and(|character| character == '_' || character.is_ascii_alphabetic())
        && characters.all(|character| character == '_' || character.is_ascii_alphanumeric())
}

#[cfg(test)]
#[path = "imports_tests.rs"]
mod tests;