relay-knowledge 1.1.16

Graph-database-based knowledge graph project.
Documentation
use crate::code::parser::imports::{ScriptLine, ScriptLineImport, line_range, source_lines};

pub(in crate::code::parser) fn line_imports(content: &str) -> Vec<ScriptLineImport> {
    let lines = source_lines(content);
    let mut imports = Vec::new();
    for (index, line) in lines.iter().enumerate() {
        let statement = line.text.trim();
        if !bash_source_statement(statement) {
            continue;
        }
        let previous = previous_shellcheck_source_comment(&lines, index);
        let range_start = previous.unwrap_or(line);
        let module = previous.map_or_else(
            || statement.to_owned(),
            |comment| format!("{}\n{}", comment.text.trim(), statement),
        );
        imports.push(ScriptLineImport {
            module,
            range: line_range(range_start, line),
        });
    }

    imports
}

fn bash_source_statement(statement: &str) -> bool {
    bash_keyword_statement(statement, "source")
        || statement
            .strip_prefix(r"\.")
            .is_some_and(|rest| rest.starts_with(char::is_whitespace) && !rest.trim().is_empty())
        || statement
            .strip_prefix('.')
            .is_some_and(|rest| rest.starts_with(char::is_whitespace) && !rest.trim().is_empty())
}

fn bash_keyword_statement(statement: &str, keyword: &str) -> bool {
    statement
        .strip_prefix(keyword)
        .is_some_and(|rest| rest.starts_with(char::is_whitespace) || rest.starts_with('('))
}

fn previous_shellcheck_source_comment<'a>(
    lines: &'a [ScriptLine<'a>],
    index: usize,
) -> Option<&'a ScriptLine<'a>> {
    let previous = index.checked_sub(1).and_then(|index| lines.get(index))?;
    let text = previous.text.trim();

    (text.starts_with("# shellcheck ") && text.contains("source=")).then_some(previous)
}

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