Skip to content

Commit

Permalink
Support multiple globs (fixes #35)
Browse files Browse the repository at this point in the history
  • Loading branch information
AMDmi3 committed Feb 12, 2024
1 parent eaa9290 commit b29e63a
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 6 deletions.
71 changes: 66 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,64 @@
use crate::ruleset::{Glob, Regex, Rule, Ruleset};
use serde::{Deserialize, Serialize};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize};
use std::fs;
use std::path::{Path, PathBuf};

struct OptionalStringSequenceVisitor;

impl<'de> serde::de::Visitor<'de> for OptionalStringSequenceVisitor {
type Value = Option<Vec<String>>;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("string with whitespace separated values or sequence of strings")
}

fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let res: Vec<_> = s.split_whitespace().map(|s| s.to_string()).collect();
if res.is_empty() {
Err(E::custom("empty string not allowed"))
} else {
Ok(Some(res))
}
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut res = Vec::with_capacity(seq.size_hint().unwrap_or(0));

while let Some(value) = seq.next_element::<String>()? {
res.push(value);
}

if res.is_empty() {
Err(A::Error::custom("empty sequence not allowed"))
} else {
Ok(Some(res))
}
}
}

fn deserialize_optional_string_sequence<'de, D>(
deserializer: D,
) -> Result<Option<Vec<String>>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(OptionalStringSequenceVisitor)
}

#[derive(Deserialize, Serialize, PartialEq, Debug)]
struct ParsedRule {
pub title: String,
pub files: Option<String>,
pub nofiles: Option<String>,
#[serde(default, deserialize_with = "deserialize_optional_string_sequence")]
pub files: Option<Vec<String>>,
#[serde(default, deserialize_with = "deserialize_optional_string_sequence")]
pub nofiles: Option<Vec<String>>,
#[serde(rename(serialize = "match", deserialize = "match"))]
pub pattern: Option<String>,
}
Expand Down Expand Up @@ -63,8 +114,18 @@ impl Config {
.into_iter()
.map(|parsed_rule| Rule {
title: parsed_rule.title,
globs: parsed_rule.files.map(|g| vec![Glob::new(&g).unwrap()]),
antiglobs: parsed_rule.nofiles.map(|g| vec![Glob::new(&g).unwrap()]),
globs: parsed_rule.files.map(|patterns| {
patterns
.iter()
.map(|pattern| Glob::new(&pattern).unwrap())
.collect()
}),
antiglobs: parsed_rule.nofiles.map(|patterns| {
patterns
.iter()
.map(|pattern| Glob::new(&pattern).unwrap())
.collect()
}),
regex: parsed_rule.pattern.map(|p| Regex::new(&p).unwrap()),
})
.collect::<Vec<_>>(),
Expand Down
40 changes: 39 additions & 1 deletion tests/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ fn glob_scope() {
}

#[test]
#[ignore]
fn multiple_globs() {
TestCase::new()
.add_file("a.py", "")
Expand All @@ -128,6 +127,23 @@ fn multiple_globs() {
",
)
.assert_matches(vec!["a.py", "a.txt", "a.rs"]);

TestCase::new()
.add_file("README", "")
.run_with_rule(
"
- title: nofiles should not match if any pattern matches
nofiles: 'README README.txt'
",
)
.assert_matches(vec![])
.run_with_rule(
"
- title: nofiles should match if neither pattern matches
nofiles: 'README.txt README.md'
",
)
.assert_matches(vec![""]);
}

#[test]
Expand All @@ -149,3 +165,25 @@ fn nofiles() {
)
.assert_matches(vec![]);
}

#[test]
#[should_panic]
fn empty_globs_string() {
TestCase::new().run_with_rule(
"
- title: nofiles which matches
files: ' '
",
);
}

#[test]
#[should_panic]
fn empty_globs_seq() {
TestCase::new().run_with_rule(
"
- title: nofiles which matches
files: []
",
);
}

0 comments on commit b29e63a

Please sign in to comment.