#![deny(missing_docs)]
#![deny(rustdoc::missing_doc_code_examples)]
mod extension;
#[cfg(feature = "regex")]
mod regex;
#[cfg(feature = "regex")]
pub use crate::regex::RegexFilter;
pub use extension::{ExtensionFilter, ExtensionsFilter};
use std::path::Path;
pub trait IgnorePath {
fn ignore<P: AsRef<Path>>(&self, path: P) -> bool;
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PathFilter {
Extension(ExtensionFilter),
Extensions(ExtensionsFilter),
#[cfg(feature = "regex")]
Regex(RegexFilter),
}
impl From<ExtensionFilter> for PathFilter {
fn from(value: ExtensionFilter) -> Self {
PathFilter::Extension(value)
}
}
impl From<ExtensionsFilter> for PathFilter {
fn from(value: ExtensionsFilter) -> Self {
PathFilter::Extensions(value)
}
}
#[cfg(feature = "regex")]
impl From<RegexFilter> for PathFilter {
fn from(value: RegexFilter) -> Self {
PathFilter::Regex(value)
}
}
impl PathFilter {
pub fn new_extension<S: AsRef<str>>(extension: S) -> Self {
ExtensionFilter::new(extension).into()
}
pub fn new_extensions<S, T>(extensions: T) -> Self
where
S: AsRef<str>,
T: AsRef<[S]>,
{
ExtensionsFilter::new(extensions).into()
}
}
#[cfg(feature = "regex")]
impl PathFilter {
pub fn new_regex(regex: ::regex::Regex) -> Self {
RegexFilter::new(regex).into()
}
}
impl IgnorePath for PathFilter {
fn ignore<P: AsRef<Path>>(&self, path: P) -> bool {
match self {
PathFilter::Extension(x) => x.ignore(path),
PathFilter::Extensions(x) => x.ignore(path),
#[cfg(feature = "regex")]
PathFilter::Regex(x) => x.ignore(path),
}
}
}
impl<T: AsRef<[PathFilter]>> IgnorePath for T {
fn ignore<P: AsRef<Path>>(&self, path: P) -> bool {
self.as_ref().iter().any(|filter| filter.ignore(&path))
}
}
#[cfg(test)]
mod tests {
use crate::PathFilter;
use std::path::Path;
#[cfg(feature = "regex")]
#[test]
fn regex_filter() {
use crate::IgnorePath;
use regex::Regex;
let filter = PathFilter::new_regex(Regex::new("^src/lib.rs$").unwrap());
assert!(matches!(filter, PathFilter::Regex(_)));
assert!(filter.ignore(Path::new("src/lib.rs")));
assert!(!filter.ignore(Path::new("src/Program.cs")));
}
#[test]
fn extension_filter() {
use crate::IgnorePath;
let filter = PathFilter::new_extension(".rs");
assert!(matches!(filter, PathFilter::Extension(_)));
assert!(filter.ignore(Path::new("test.rs")));
assert!(filter.ignore(Path::new("src/lib.rs")));
assert!(filter.ignore(Path::new("src/main.rs")));
assert!(!filter.ignore(Path::new("src/Program.cs")));
}
#[test]
fn extensions_filter() {
use crate::IgnorePath;
let filter = PathFilter::new_extensions([".rs", ".txt"]);
assert!(matches!(filter, PathFilter::Extensions(_)));
assert!(filter.ignore(Path::new("test.rs")));
assert!(filter.ignore(Path::new("src/lib.rs")));
assert!(filter.ignore(Path::new("src/main.rs")));
assert!(filter.ignore(Path::new("src/main.txt")));
assert!(!filter.ignore(Path::new("src/main.png")));
}
#[cfg(feature = "regex")]
#[test]
fn regex_extension_combined_filter() {
use crate::IgnorePath;
use regex::Regex;
let filters = vec![
PathFilter::new_regex(Regex::new("^src/lib.rs$").unwrap()),
PathFilter::new_extension(".cs"),
];
assert!(filters.ignore(Path::new("src/lib.rs")));
assert!(!filters.ignore(Path::new("src/main.cpp")));
assert!(filters.ignore(Path::new("test.cs")));
assert!(filters.ignore(Path::new("src/lib.rs")));
assert!(!filters.ignore(Path::new("src/main.rs")));
assert!(filters.ignore(Path::new("src/Program.cs")));
}
}