use super::parser::{parse_lino, split_pipe_list};
use super::BRAINSTORM_SEEDS_LINO;
#[derive(Debug, Clone, Default)]
pub struct BrainstormCategory {
pub slug: String,
pub intent: String,
pub detection_keywords: Vec<String>,
pub items: Vec<String>,
}
#[derive(Debug, Clone, Default)]
pub struct BrainstormSeeds {
pub triggers: Vec<String>,
pub categories: Vec<BrainstormCategory>,
}
impl BrainstormSeeds {
#[must_use]
pub fn matches_trigger(&self, normalized: &str) -> bool {
self.triggers
.iter()
.any(|trigger| !trigger.is_empty() && normalized.contains(trigger.as_str()))
}
#[must_use]
pub fn pick_category(&self, normalized: &str) -> Option<&BrainstormCategory> {
let keyworded = self.categories.iter().find(|category| {
category
.detection_keywords
.iter()
.any(|keyword| !keyword.is_empty() && normalized.contains(keyword.as_str()))
});
keyworded.or_else(|| {
self.categories
.iter()
.find(|category| category.detection_keywords.is_empty())
})
}
}
#[must_use]
pub fn brainstorm_seeds() -> BrainstormSeeds {
let tree = parse_lino(BRAINSTORM_SEEDS_LINO);
let mut seeds = BrainstormSeeds::default();
let Some(root) = tree.children.iter().find(|c| c.name == "brainstorm_seeds") else {
return seeds;
};
seeds.triggers = split_pipe_list(root.find_child_value("trigger"))
.into_iter()
.map(|t| t.to_lowercase())
.collect();
for entry in root.children.iter().filter(|c| c.name == "category") {
let slug = entry.id.clone();
if slug.is_empty() {
continue;
}
let detection_keywords = split_pipe_list(entry.find_child_value("detection_keywords"))
.into_iter()
.map(|k| k.to_lowercase())
.collect();
let items: Vec<String> = entry
.children
.iter()
.filter(|c| c.name == "item")
.map(|c| c.id.clone())
.filter(|s| !s.is_empty())
.collect();
if items.is_empty() {
continue;
}
seeds.categories.push(BrainstormCategory {
slug,
intent: entry.find_child_value("intent").to_string(),
detection_keywords,
items,
});
}
seeds
}