const HEADER_SCAN_BYTES: usize = 8 * 1024;
pub(in crate::code) fn is_generated_file(path: &str, bytes: &[u8]) -> bool {
path_has_generated_signal(path) || header_has_generated_signal(bytes)
}
pub(in crate::code) fn path_has_generated_signal(path: &str) -> bool {
let normalized = normalized_path(path);
let file_name = normalized.rsplit('/').next().unwrap_or(&normalized);
generated_file_name(file_name) || generated_path_segments(&normalized)
}
fn generated_file_name(file_name: &str) -> bool {
file_name.ends_with(".pb.go")
|| file_name.ends_with(".pulsar.go")
|| file_name.ends_with(".generated.ts")
|| file_name.ends_with(".generated.tsx")
|| file_name.ends_with(".generated.js")
|| file_name.ends_with(".auto.ts")
|| file_name.ends_with(".auto.tsx")
|| file_name.ends_with(".auto.js")
|| file_name.ends_with(".min.js")
|| file_name.ends_with(".min.css")
}
fn generated_path_segments(path: &str) -> bool {
let segments = path
.split('/')
.filter(|segment| !segment.is_empty())
.collect::<Vec<_>>();
segments
.first()
.is_some_and(|segment| matches!(*segment, "dist" | "build"))
|| segments
.windows(2)
.any(|window| window == ["target", "generated"])
}
fn header_has_generated_signal(bytes: &[u8]) -> bool {
let header = &bytes[..bytes.len().min(HEADER_SCAN_BYTES)];
if header.is_empty() || header_contains_nul(header) {
return false;
}
let header = String::from_utf8_lossy(header).to_ascii_lowercase();
[
"code generated by",
"auto-generated",
"autogenerated",
"@generated",
"this file was generated",
"openapi generator",
"swagger codegen",
]
.iter()
.any(|marker| header.contains(marker))
}
fn header_contains_nul(bytes: &[u8]) -> bool {
bytes.contains(&0)
}
fn normalized_path(path: &str) -> String {
path.replace('\\', "/").to_ascii_lowercase()
}
#[cfg(test)]
#[path = "mod_tests.rs"]
mod tests;