use std::path::Path;
pub fn is_vendor_or_generated_solidity(path: &Path, source: &str) -> bool {
has_generated_header(source) || is_vendor_path(path) || is_build_output_path(path)
}
fn has_generated_header(source: &str) -> bool {
source.lines().take(10).any(is_generated_header_line)
}
fn is_generated_header_line(line: &str) -> bool {
let lower = line.to_ascii_lowercase();
lower.contains("automatically generated")
|| (lower.contains("generated") && lower.contains("do not edit"))
}
fn is_vendor_path(path: &Path) -> bool {
let path_text = path.to_string_lossy();
path_text.contains("node_modules/@openzeppelin/contracts")
|| path_text.contains("lib/openzeppelin-contracts")
|| path_text.contains("lib/openzeppelin-contracts-upgradeable")
}
fn is_build_output_path(path: &Path) -> bool {
path.components().any(|component| {
let name = component.as_os_str().to_string_lossy();
matches!(name.as_ref(), "out" | "cache" | "artifacts")
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generated_header_detection() {
let source = "// Automatically generated by TypeChain\npragma solidity 0.8.20;";
assert!(is_vendor_or_generated_solidity(
Path::new("contracts/Generated.sol"),
source
));
}
#[test]
fn test_openzeppelin_vendor_path_detection() {
assert!(is_vendor_or_generated_solidity(
Path::new("node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol"),
"pragma solidity 0.8.20;"
));
assert!(is_vendor_or_generated_solidity(
Path::new("lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"),
"pragma solidity 0.8.20;"
));
}
#[test]
fn test_build_output_path_detection() {
assert!(is_vendor_or_generated_solidity(
Path::new("out/Token.sol/Token.json"),
"{}"
));
assert!(is_vendor_or_generated_solidity(
Path::new("artifacts/contracts/Token.sol"),
"pragma solidity 0.8.20;"
));
}
#[test]
fn test_regular_contract_not_generated() {
assert!(!is_vendor_or_generated_solidity(
Path::new("contracts/Token.sol"),
"import \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";"
));
}
}