relay-knowledge 1.1.17

Graph-database-based knowledge graph project.
Documentation
const MAX_FLASK_ROUTE_DECORATOR_LINES: usize = 12;
const MAX_PYTHON_ROUTER_PREFIX_LINES: usize = 12;

pub(super) fn python_router_prefix_statement(
    lines: &[String],
    start: usize,
) -> Option<(String, usize)> {
    let first_line = lines[start].trim();
    if !first_line.contains('=')
        || (!first_line.contains("APIRouter(")
            && !first_line.contains("FastAPI(")
            && !first_line.contains("Blueprint("))
    {
        return None;
    }
    Some(python_parenthesized_statement(
        lines,
        start,
        MAX_PYTHON_ROUTER_PREFIX_LINES,
    ))
}

pub(super) fn python_include_router_statement(
    lines: &[String],
    start: usize,
) -> Option<(String, usize)> {
    let first_line = lines[start].trim();
    if !first_line.contains(".include_router(") {
        return None;
    }
    Some(python_parenthesized_statement(
        lines,
        start,
        MAX_PYTHON_ROUTER_PREFIX_LINES,
    ))
}

pub(super) fn python_register_blueprint_statement(
    lines: &[String],
    start: usize,
) -> Option<(String, usize)> {
    let first_line = lines[start].trim();
    if !first_line.contains(".register_blueprint(") {
        return None;
    }
    Some(python_parenthesized_statement(
        lines,
        start,
        MAX_PYTHON_ROUTER_PREFIX_LINES,
    ))
}

pub(super) fn python_add_url_rule_statement(
    lines: &[String],
    start: usize,
) -> Option<(String, usize)> {
    let first_line = lines[start].trim();
    if !first_line.contains(".add_url_rule(") {
        return None;
    }
    Some(python_parenthesized_statement(
        lines,
        start,
        MAX_FLASK_ROUTE_DECORATOR_LINES,
    ))
}

pub(super) fn flask_decorator_statement(lines: &[String], start: usize) -> (String, usize) {
    python_parenthesized_statement(lines, start, MAX_FLASK_ROUTE_DECORATOR_LINES)
}

fn python_parenthesized_statement(
    lines: &[String],
    start: usize,
    max_lines: usize,
) -> (String, usize) {
    let mut statement = String::new();
    let mut depth = 0usize;
    let mut quote = None;
    let mut escaped = false;
    let mut saw_open = false;
    let mut consumed = 0usize;
    for line in lines.iter().skip(start).take(max_lines) {
        let segment = line.trim();
        if !statement.is_empty() {
            statement.push(' ');
        }
        statement.push_str(segment);
        consumed += 1;
        for character in segment.chars() {
            if let Some(quote_char) = quote {
                if escaped {
                    escaped = false;
                    continue;
                }
                if character == '\\' {
                    escaped = true;
                    continue;
                }
                if character == quote_char {
                    quote = None;
                }
                continue;
            }
            match character {
                '\'' | '"' => quote = Some(character),
                '(' => {
                    depth += 1;
                    saw_open = true;
                }
                ')' => {
                    depth = depth.saturating_sub(1);
                    if saw_open && depth == 0 {
                        return (statement, consumed);
                    }
                }
                _ => {}
            }
        }
        if !saw_open {
            return (statement, consumed);
        }
    }
    (statement, consumed.max(1))
}

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