compare_changes/
lib.rs

1mod convert;
2mod path;
3
4#[derive(Debug)]
5pub enum Error {
6    Parse(Vec<String>), // convert to strings for simplicity
7    Regex(regex::Error),
8}
9
10impl From<regex::Error> for Error {
11    fn from(e: regex::Error) -> Self {
12        Error::Regex(e)
13    }
14}
15
16pub fn path_matches(path: &str, files: &[&str]) -> Result<Option<usize>, Error> {
17    if files.is_empty() {
18        return Ok(None);
19    }
20
21    // Remove leading '?', '+' since that's what GitHub does and also '!' because it's not meaningful when not part of a group
22    let pattern = match path.chars().next() {
23        Some(c) if matches!(c, '?' | '+' | '!') => &path[c.len_utf8()..],
24        _ => path,
25    };
26
27    // Parse the single path — map chumsky Rich errors to strings
28    let parsed_path = match path::parse(pattern) {
29        Ok(p) => p,
30        Err(errs) => {
31            let msgs = errs.into_iter().map(|e| e.to_string()).collect();
32            return Err(Error::Parse(msgs));
33        }
34    };
35
36    // Build regex from the parsed path — propagate compilation errors
37    let re = convert::path_to_regex(&parsed_path)?;
38
39    // Check if any file matches the compiled regex
40    Ok(files.iter().enumerate().find(|(_, file)| re.is_match(file)).map(|(i, _)| i))
41}