gobby-code 1.3.3

Fast Rust CLI for Gobby's code index — AST-aware search, symbol navigation, and dependency graph
Documentation
use std::io::Read;
use std::path::Path;

const GENERATED_JS_MARKER_SCAN_BYTES: usize = 64 * 1024;
const GENERATED_JS_ANALYSIS_READ_BYTES: u64 = 256 * 1024;
pub(super) const MINIFIED_JS_MIN_BYTES: usize = 128 * 1024;
const MINIFIED_JS_LONG_LINE_BYTES: usize = 20 * 1024;
const MINIFIED_JS_MAX_LINES: usize = 20;
const MINIFIED_JS_AVG_LINE_BYTES: usize = 2 * 1024;
const GENERATED_JS_MARKERS: &[&str] = &[
    "generated by",
    "do not edit",
    "@generated",
    "auto-generated",
    "automatically generated",
];

pub(super) fn is_generated_js_bundle(path: &Path) -> bool {
    if !is_js_family_file(path) {
        return false;
    }

    let Ok(metadata) = path.metadata() else {
        return false;
    };
    let Ok(bytes) = read_file_prefix(path, GENERATED_JS_ANALYSIS_READ_BYTES) else {
        return false;
    };
    if contains_generated_js_marker(&bytes) {
        return true;
    }

    if metadata.len() < MINIFIED_JS_MIN_BYTES as u64 {
        return false;
    };

    looks_minified_js_bundle(&bytes)
}

fn read_file_prefix(path: &Path, max_bytes: u64) -> std::io::Result<Vec<u8>> {
    let mut file = std::fs::File::open(path)?;
    let mut bytes = Vec::with_capacity(max_bytes.min(usize::MAX as u64) as usize);
    file.by_ref().take(max_bytes).read_to_end(&mut bytes)?;
    Ok(bytes)
}

fn is_js_family_file(path: &Path) -> bool {
    path.extension()
        .and_then(|ext| ext.to_str())
        .map(|ext| {
            matches!(
                ext.to_ascii_lowercase().as_str(),
                "js" | "jsx" | "cjs" | "mjs"
            )
        })
        .unwrap_or(false)
}

fn contains_generated_js_marker(bytes: &[u8]) -> bool {
    let scan_len = bytes.len().min(GENERATED_JS_MARKER_SCAN_BYTES);
    let scan = String::from_utf8_lossy(&bytes[..scan_len]).to_ascii_lowercase();
    GENERATED_JS_MARKERS
        .iter()
        .any(|marker| scan.contains(marker))
}

fn looks_minified_js_bundle(bytes: &[u8]) -> bool {
    if bytes.len() < MINIFIED_JS_MIN_BYTES {
        return false;
    }

    let mut line_count = 0usize;
    let mut total_line_bytes = 0usize;
    let mut longest_line_bytes = 0usize;
    for line in bytes.split(|byte| *byte == b'\n') {
        let line_len = line.len();
        if line_len == 0 {
            continue;
        }
        line_count += 1;
        total_line_bytes += line_len;
        longest_line_bytes = longest_line_bytes.max(line_len);
    }

    if line_count == 0 {
        return false;
    }

    longest_line_bytes >= MINIFIED_JS_LONG_LINE_BYTES
        || (line_count <= MINIFIED_JS_MAX_LINES
            && total_line_bytes / line_count >= MINIFIED_JS_AVG_LINE_BYTES)
}