koala-core 1.0.4

Shared types, invariant evaluator, and primitives for the koala framework.
Documentation
use std::path::{Path, PathBuf};
use walkdir::{DirEntry, WalkDir};

const SKIP_DIRS: &[&str] = &[".git", "target", "node_modules", "koala", ".worktrees"];

fn is_skipped(entry: &DirEntry) -> bool {
    if entry.depth() == 0 {
        return false;
    }
    let name = entry.file_name().to_string_lossy();
    SKIP_DIRS.iter().any(|s| *s == name)
}

pub(crate) fn walk_repo(root: &Path) -> impl Iterator<Item = DirEntry> {
    WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !is_skipped(e))
        .filter_map(Result::ok)
}

pub(crate) fn list_files_with_ext(root: &Path, ext: &str) -> Vec<PathBuf> {
    walk_repo(root)
        .filter(|e| e.file_type().is_file())
        .filter(|e| e.path().extension().and_then(|s| s.to_str()) == Some(ext))
        .map(|e| e.into_path())
        .collect()
}

pub(crate) fn list_cargo_tomls(root: &Path) -> Vec<PathBuf> {
    walk_repo(root)
        .filter(|e| e.file_type().is_file())
        .filter(|e| e.file_name() == "Cargo.toml")
        .map(|e| e.into_path())
        .collect()
}

/// Best-effort relative path for display; falls back to absolute.
pub(crate) fn rel(path: &Path, root: &Path) -> String {
    path.strip_prefix(root)
        .unwrap_or(path)
        .display()
        .to_string()
}