use harn_languages::Language;
pub const EXCLUDED_DIRS: &[&str] = &[
".git",
".build",
".burin",
".harn",
".harn-runs",
"node_modules",
".next",
"dist",
"build",
"__pycache__",
".venv",
"venv",
".tox",
"target",
".gradle",
".idea",
".vscode",
"Pods",
"DerivedData",
".swiftpm",
"vendor",
".cache",
".nuget",
"coverage",
".nyc_output",
".turbo",
".parcel-cache",
];
pub fn is_excluded_dir(name: &str) -> bool {
EXCLUDED_DIRS.contains(&name)
}
pub fn should_traverse(relative_path: &str) -> bool {
relative_path
.split('/')
.all(|segment| !is_excluded_dir(segment))
}
pub fn should_include(relative_path: &str) -> bool {
should_traverse(relative_path) && file_language(relative_path).is_some()
}
pub fn file_language(relative_path: &str) -> Option<Language> {
Language::from_path(relative_path)
}
pub fn file_name(relative_path: &str) -> &str {
relative_path.rsplit('/').next().unwrap_or(relative_path)
}
pub fn parent_dir(relative_path: &str) -> &str {
match relative_path.rsplit_once('/') {
Some((parent, _)) => parent,
None => "",
}
}
pub fn folder_key(relative_path: &str) -> &str {
let parent = parent_dir(relative_path);
if parent.is_empty() {
"."
} else {
parent
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn excluded_segments_block_traversal() {
assert!(!should_traverse("node_modules/foo/bar.js"));
assert!(!should_traverse(".git/HEAD"));
assert!(should_traverse("src/lib.rs"));
}
#[test]
fn include_requires_a_registry_language() {
assert!(should_include("src/main.rs"));
assert!(should_include("app/Dockerfile"));
assert!(should_include("src/build.gradle.kts"));
assert!(!should_include("src/main.txt"));
assert!(!should_include("README"));
}
#[test]
fn parent_and_folder_key() {
assert_eq!(parent_dir("src/lib.rs"), "src");
assert_eq!(parent_dir("Cargo.toml"), "");
assert_eq!(folder_key("Cargo.toml"), ".");
assert_eq!(folder_key("src/lib.rs"), "src");
}
}