sniff-cli 0.1.3

An exhaustive LLM-backed slop finder for codebases
Documentation
#![allow(dead_code)]

use super::*;

pub(super) fn line_indent(line: &str) -> usize {
    line.chars().take_while(|c| c.is_whitespace()).count()
}

pub(super) fn parse_python_name(trimmed: &str) -> Option<String> {
    trimmed
        .strip_prefix("def ")?
        .split_once('(')
        .map(|(name, _)| name.trim().to_string())
}

pub(super) fn parse_python_params(trimmed: &str) -> Vec<String> {
    let inside = trimmed
        .split_once('(')
        .and_then(|(_, rest)| rest.split_once(')').map(|(inside, _)| inside))
        .unwrap_or("");
    inside
        .split(',')
        .map(|part| part.trim())
        .filter(|part| !part.is_empty())
        .map(|part| {
            part.split_once(':')
                .map(|(name, _)| name.trim())
                .unwrap_or(part)
                .split_once('=')
                .map(|(name, _)| name.trim())
                .unwrap_or(part)
                .trim_start_matches('*')
                .trim()
                .to_string()
        })
        .filter(|name| !name.is_empty())
        .collect()
}

pub(super) fn parse_python_from_imports(trimmed: &str) -> Option<Vec<ImportRecord>> {
    let rest = trimmed.strip_prefix("from ")?;
    let (source_module, import_part) = rest.split_once(" import ")?;
    let source_module = source_module.trim().to_string();
    let import_part = import_part
        .trim()
        .trim_start_matches('(')
        .trim_end_matches(')')
        .trim();
    let mut records = Vec::new();

    for imported in import_part.split(',') {
        let imported = imported.trim();
        if imported.is_empty() {
            continue;
        }

        if imported == "*" {
            records.push(ImportRecord {
                local_name: "*".to_string(),
                source_module: source_module.clone(),
                imported_name: "*".to_string(),
            });
            continue;
        }

        let (imported_name, local_name) =
            if let Some((source_name, alias_name)) = imported.split_once(" as ") {
                (source_name.trim(), alias_name.trim())
            } else {
                let name = imported.split_whitespace().last()?;
                (name.trim(), name.trim())
            };

        if imported_name.is_empty() || local_name.is_empty() {
            continue;
        }

        records.push(ImportRecord {
            local_name: local_name.to_string(),
            source_module: source_module.clone(),
            imported_name: imported_name.to_string(),
        });
    }

    if records.is_empty() {
        None
    } else {
        Some(records)
    }
}

pub(super) fn parse_python_namespace_imports(trimmed: &str) -> Option<Vec<ImportRecord>> {
    let rest = trimmed.strip_prefix("import ")?;
    let mut records = Vec::new();

    for imported in rest.split(',') {
        let imported = imported.trim().trim_end_matches(';');
        if imported.is_empty() {
            continue;
        }

        let (module_path, local_name) =
            if let Some((module_path, alias_name)) = imported.split_once(" as ") {
                let module_path = module_path.trim();
                let alias_name = alias_name.trim();
                if module_path.is_empty() || alias_name.is_empty() {
                    continue;
                }
                (module_path, alias_name)
            } else {
                let module_path = imported.trim();
                let local_name = module_path.split('.').next().unwrap_or(module_path).trim();
                if module_path.is_empty() || local_name.is_empty() {
                    continue;
                }
                (module_path, local_name)
            };

        records.push(ImportRecord {
            local_name: local_name.to_string(),
            source_module: module_path.to_string(),
            imported_name: "*".to_string(),
        });
    }

    if records.is_empty() {
        None
    } else {
        Some(records)
    }
}