use serde::{Deserialize, Serialize};
use stakpak_api::models::ListRuleBook;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RulebookConfig {
pub include: Option<Vec<String>>,
pub exclude: Option<Vec<String>>,
pub include_tags: Option<Vec<String>>,
pub exclude_tags: Option<Vec<String>>,
}
impl RulebookConfig {
pub fn filter_rulebooks(&self, rulebooks: Vec<ListRuleBook>) -> Vec<ListRuleBook> {
rulebooks
.into_iter()
.filter(|rulebook| self.should_keep(rulebook))
.collect()
}
fn should_keep(&self, rulebook: &ListRuleBook) -> bool {
self.matches_uri_filters(rulebook) && self.matches_tag_filters(rulebook)
}
fn matches_uri_filters(&self, rulebook: &ListRuleBook) -> bool {
self.matches_include_patterns(rulebook) && self.matches_exclude_patterns(rulebook)
}
fn matches_include_patterns(&self, rulebook: &ListRuleBook) -> bool {
match &self.include {
Some(patterns) if !patterns.is_empty() => patterns
.iter()
.any(|pattern| Self::matches_pattern(&rulebook.uri, pattern)),
_ => true,
}
}
fn matches_exclude_patterns(&self, rulebook: &ListRuleBook) -> bool {
match &self.exclude {
Some(patterns) if !patterns.is_empty() => !patterns
.iter()
.any(|pattern| Self::matches_pattern(&rulebook.uri, pattern)),
_ => true,
}
}
fn matches_tag_filters(&self, rulebook: &ListRuleBook) -> bool {
self.matches_include_tags(rulebook) && self.matches_exclude_tags(rulebook)
}
fn matches_include_tags(&self, rulebook: &ListRuleBook) -> bool {
match &self.include_tags {
Some(tags) if !tags.is_empty() => tags.iter().any(|tag| rulebook.tags.contains(tag)),
_ => true,
}
}
fn matches_exclude_tags(&self, rulebook: &ListRuleBook) -> bool {
match &self.exclude_tags {
Some(tags) if !tags.is_empty() => !tags.iter().any(|tag| rulebook.tags.contains(tag)),
_ => true,
}
}
pub(crate) fn matches_pattern(uri: &str, pattern: &str) -> bool {
if let Ok(glob_pattern) = glob::Pattern::new(pattern) {
glob_pattern.matches(uri)
} else {
uri == pattern
}
}
}