sarah 0.1.9

Count tokens, lines and function sizes per file to help AI agents decide what to refactor
/// Stateless helpers that recognize generated files.
pub(super) struct GeneratedHelpers;

impl GeneratedHelpers {
    /// A marker in the first lines: generated code is never refactored by hand.
    pub(super) fn is_generated(text: &str) -> bool {
        text.lines().take(HEADER_LINES).any(|line| {
            let line = line.to_lowercase();
            MARKERS.iter().any(|marker| line.contains(marker))
        })
    }
}

// The marker list stays below the header lines, so this file is not taken for generated.
/// Lines at the top of a file that may carry a "generated" header.
const HEADER_LINES: usize = 5;

/// Markers of generated code (lowercase): Go's `// Code generated ... DO NOT EDIT.`,
/// `@generated` (Meta, Rust tools), protobuf/OpenAPI/bindgen headers.
const MARKERS: &[&str] = &[
    "@generated",
    "do not edit",
    "code generated",
    "auto-generated",
    "autogenerated",
    "automatically generated",
];

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn detects_headers_only_at_the_top() {
        assert!(GeneratedHelpers::is_generated(
            "// Code generated by protoc-gen-go. DO NOT EDIT.\npackage p\n"
        ));
        assert!(GeneratedHelpers::is_generated("# @generated by tool\n"));
        assert!(!GeneratedHelpers::is_generated("fn main() {}\n"));
        let late = format!("{}// @generated\n", "\n".repeat(HEADER_LINES));
        assert!(!GeneratedHelpers::is_generated(&late));
    }
}