arborist_cli/
traversal.rs1use std::path::{Path, PathBuf};
2
3use ignore::WalkBuilder;
4
5use crate::error::ArboristError;
6
7fn extension_to_language(ext: &str) -> Option<&'static str> {
9 match ext {
10 "rs" => Some("rust"),
11 "py" => Some("python"),
12 "js" => Some("javascript"),
13 "ts" => Some("typescript"),
14 "tsx" => Some("tsx"),
15 "jsx" => Some("jsx"),
16 "java" => Some("java"),
17 "go" => Some("go"),
18 "c" | "h" => Some("c"),
19 "cpp" | "cc" | "cxx" | "hpp" => Some("cpp"),
20 "cs" => Some("c_sharp"),
21 "rb" => Some("ruby"),
22 "swift" => Some("swift"),
23 "kt" | "kts" => Some("kotlin"),
24 "php" => Some("php"),
25 _ => None,
26 }
27}
28
29pub fn collect_files(
30 paths: &[PathBuf],
31 languages_filter: Option<&[String]>,
32 gitignore: bool,
33) -> Result<Vec<PathBuf>, ArboristError> {
34 let mut files = Vec::new();
35
36 for path in paths {
37 if path.is_file() {
38 files.push(path.clone());
39 } else if path.is_dir() {
40 collect_directory(path, languages_filter, gitignore, &mut files)?;
41 } else {
42 return Err(ArboristError::Io(std::io::Error::new(
43 std::io::ErrorKind::NotFound,
44 format!("file not found: {}", path.display()),
45 )));
46 }
47 }
48
49 Ok(files)
50}
51
52fn collect_directory(
53 dir: &Path,
54 languages_filter: Option<&[String]>,
55 gitignore: bool,
56 files: &mut Vec<PathBuf>,
57) -> Result<(), ArboristError> {
58 let walker = WalkBuilder::new(dir)
59 .git_ignore(gitignore)
60 .git_global(false)
61 .git_exclude(false)
62 .hidden(false)
63 .build();
64
65 let languages_lower: Option<Vec<String>> =
66 languages_filter.map(|langs| langs.iter().map(|l| l.to_lowercase()).collect());
67
68 for entry in walker {
69 let entry = entry.map_err(|e| ArboristError::Io(std::io::Error::other(e.to_string())))?;
70
71 let path = entry.path();
72 if !path.is_file() {
73 continue;
74 }
75
76 let ext = match path.extension().and_then(|e| e.to_str()) {
77 Some(ext) => ext,
78 None => continue,
79 };
80
81 let lang = match extension_to_language(ext) {
82 Some(lang) => lang,
83 None => continue,
84 };
85
86 if let Some(ref filter) = languages_lower
87 && !filter.iter().any(|f| f == lang)
88 {
89 continue;
90 }
91
92 files.push(path.to_path_buf());
93 }
94
95 files.sort();
96 Ok(())
97}