1use std::path::{Path, PathBuf};
2
3use ignore::WalkBuilder;
4
5pub fn discover_files(path: &Path, extensions: &[String]) -> anyhow::Result<Vec<PathBuf>> {
6 if path.is_file() {
7 return Ok(vec![path.to_path_buf()]);
8 }
9
10 let mut files = Vec::new();
11 let walker = WalkBuilder::new(path).hidden(true).git_ignore(true).build();
12
13 for entry in walker {
14 let entry = entry?;
15 let entry_path = entry.path();
16 if entry_path.is_file()
17 && let Some(ext) = entry_path.extension().and_then(|ext| ext.to_str())
18 && extensions.iter().any(|candidate| candidate == ext)
19 {
20 files.push(entry_path.to_path_buf());
21 }
22 }
23
24 files.sort();
25 Ok(files)
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31 use std::fs;
32
33 #[test]
34 fn discovers_single_file() {
35 let dir = tempfile::tempdir().unwrap();
36 let file = dir.path().join("main.rs");
37 fs::write(&file, "fn main() {}").unwrap();
38
39 let result = discover_files(&file, &["rs".to_string()]).unwrap();
40 assert_eq!(result, vec![file]);
41 }
42
43 #[test]
44 fn discovers_files_in_directory() {
45 let dir = tempfile::tempdir().unwrap();
46 fs::write(dir.path().join("a.rs"), "").unwrap();
47 fs::write(dir.path().join("b.rs"), "").unwrap();
48 fs::write(dir.path().join("c.txt"), "").unwrap();
49
50 let result = discover_files(dir.path(), &["rs".to_string()]).unwrap();
51 assert_eq!(result.len(), 2);
52 assert!(result.iter().all(|path| path.extension().unwrap() == "rs"));
53 }
54}