neural_shared/scanner/
mod.rs

1//! File system scanner with .gitignore support
2
3use crate::Result;
4use ignore::WalkBuilder;
5use std::path::{Path, PathBuf};
6
7/// Scanner finds source files to analyze
8pub struct Scanner {
9    root: PathBuf,
10}
11
12impl Scanner {
13    /// Create a new scanner for the given root directory
14    pub fn new(root: impl AsRef<Path>) -> Self {
15        Self {
16            root: root.as_ref().to_path_buf(),
17        }
18    }
19
20    /// Scan for Python and TypeScript files
21    pub fn scan(&self) -> Result<Vec<PathBuf>> {
22        let mut files = Vec::new();
23
24        for result in WalkBuilder::new(&self.root)
25            .hidden(false) // Include hidden files
26            .git_ignore(true) // Respect .gitignore
27            .build()
28        {
29            let entry = result?;
30            let path = entry.path();
31
32            if self.is_supported_file(path) {
33                files.push(path.to_path_buf());
34            }
35        }
36
37        Ok(files)
38    }
39
40    /// Check if file is a supported language
41    fn is_supported_file(&self, path: &Path) -> bool {
42        if !path.is_file() {
43            return false;
44        }
45
46        path.extension()
47            .and_then(|ext| ext.to_str())
48            .map(|ext| matches!(ext, "py" | "ts" | "tsx" | "js" | "jsx"))
49            .unwrap_or(false)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_is_supported_file() {
59        use std::fs;
60        use tempfile::tempdir;
61
62        let dir = tempdir().unwrap();
63        let scanner = Scanner::new(dir.path());
64
65        // Create test files
66        let py_file = dir.path().join("test.py");
67        let ts_file = dir.path().join("test.ts");
68        let tsx_file = dir.path().join("test.tsx");
69        let rs_file = dir.path().join("test.rs");
70        let txt_file = dir.path().join("test.txt");
71
72        fs::write(&py_file, "").unwrap();
73        fs::write(&ts_file, "").unwrap();
74        fs::write(&tsx_file, "").unwrap();
75        fs::write(&rs_file, "").unwrap();
76        fs::write(&txt_file, "").unwrap();
77
78        assert!(scanner.is_supported_file(&py_file));
79        assert!(scanner.is_supported_file(&ts_file));
80        assert!(scanner.is_supported_file(&tsx_file));
81        assert!(!scanner.is_supported_file(&rs_file));
82        assert!(!scanner.is_supported_file(&txt_file));
83    }
84}