sniff-cli 0.1.0

An exhaustive LLM-backed slop finder for codebases
Documentation
use sniff::callgraph::{build_ref_count_flags, build_references};
use sniff::config::ResolvedConfig;
use sniff::file_verdicts::build_file_verdicts;
use sniff::parser::{parse_file, parse_file_symbols};
use sniff::report_types::StaticFlag;
use sniff::scorer::score;
use sniff::symbol_graph::SymbolGraph;
use sniff::types::{FileRecord, FindingTier, ResolvedSymbol};
use sniff::walker::walk;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

fn unique_tag(label: &str) -> String {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_nanos();
    format!("{}_{}_{}", label, std::process::id(), nanos)
}

fn write_temp_file(root: &Path, relative: &str, contents: &str) -> String {
    let path = root.join(relative);
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).unwrap();
    }
    fs::write(&path, contents).unwrap();
    path.to_string_lossy().to_string()
}

fn branchy_python_helpers(prefix: &str, count: usize) -> String {
    let mut helpers = String::new();
    for idx in 0..count {
        helpers.push_str(&format!(
            "\ndef {prefix}_helper_{idx:02}(value):\n    if value == 0:\n        return 0\n    if value == 1:\n        return 1\n    if value == 2:\n        return 2\n    return value\n",
            prefix = prefix,
            idx = idx
        ));
    }
    helpers
}

fn branchy_typescript_helpers(prefix: &str, count: usize) -> String {
    let mut helpers = String::new();
    for idx in 0..count {
        helpers.push_str(&format!(
            "\nexport function {prefix}Helper{idx:02}(value: number) {{\n  if (value === 0) {{\n    return 0;\n  }}\n  if (value === 1) {{\n    return 1;\n  }}\n  if (value === 2) {{\n    return 2;\n  }}\n  return value;\n}}\n",
            prefix = prefix,
            idx = idx
        ));
    }
    helpers
}

fn branchy_go_helpers(prefix: &str, count: usize) -> String {
    let mut helpers = String::new();
    for idx in 0..count {
        helpers.push_str(&format!(
            "\nfunc {prefix}Helper{idx:02}(value int) int {{\n    if value == 0 {{\n        return 0\n    }}\n    if value == 1 {{\n        return 1\n    }}\n    if value == 2 {{\n        return 2\n    }}\n    return value\n}}\n",
            prefix = prefix,
            idx = idx
        ));
    }
    helpers
}

fn branchy_rust_helpers(prefix: &str, count: usize) -> String {
    let mut helpers = String::new();
    for idx in 0..count {
        helpers.push_str(&format!(
            "\npub fn {prefix}_helper_{idx:02}(value: i32) -> i32 {{\n    if value == 0 {{\n        return 0;\n    }}\n    if value == 1 {{\n        return 1;\n    }}\n    if value == 2 {{\n        return 2;\n    }}\n    value\n}}\n",
            prefix = prefix,
            idx = idx
        ));
    }
    helpers
}

fn copy_dir_all(src: &Path, dst: &Path) -> io::Result<()> {
    if !dst.exists() {
        fs::create_dir_all(dst)?;
    }

    for entry in fs::read_dir(src)? {
        let entry = entry?;
        let ty = entry.file_type()?;
        let dest_path = dst.join(entry.file_name());
        if ty.is_dir() {
            copy_dir_all(&entry.path(), &dest_path)?;
        } else {
            fs::copy(entry.path(), dest_path)?;
        }
    }

    Ok(())
}

fn fixture_root() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("gold_fixtures")
        .join("repo")
}

fn normalize_path(path: &str) -> String {
    path.replace('\\', "/")
}

fn has_suffix(path: &str, suffix: &str) -> bool {
    normalize_path(path).ends_with(suffix)
}

fn parse_records(paths: &[String]) -> Vec<FileRecord> {
    paths.iter().map(|path| parse_file(path)).collect()
}

fn build_graph(paths: &[String], root: &str) -> SymbolGraph {
    let mut graph = SymbolGraph::new(root);
    for path in paths {
        graph.add_file(parse_file_symbols(path));
    }
    graph.resolve_all();
    graph
}

fn count_gate(flags: &[StaticFlag], gate: &str) -> usize {
    flags.iter().filter(|flag| flag.gate == gate).count()
}

fn git_cmd(root: &Path, args: &[&str]) {
    let status = Command::new("git")
        .current_dir(root)
        .args(args)
        .status()
        .unwrap();
    assert!(status.success(), "git command failed: {:?}", args);
}

#[path = "gold/analysis.rs"]
mod analysis;
#[path = "gold/bumpkin.rs"]
mod bumpkin;
#[path = "gold/contracts.rs"]
mod contracts;
#[path = "gold/core.rs"]
mod core;
#[path = "gold/graph.rs"]
mod graph;
#[path = "gold/language_runtime.rs"]
mod language_runtime;
#[path = "gold/language_surfaces.rs"]
mod language_surfaces;
#[path = "gold/policy.rs"]
mod policy;