use super::TemplateRegistry;
use crate::{Result, parser::UnifiedRule};
#[derive(Debug)]
pub struct TemplateComposer<'a> {
registry: &'a TemplateRegistry,
}
impl<'a> TemplateComposer<'a> {
pub fn new(registry: &'a TemplateRegistry) -> Self {
Self { registry }
}
pub fn compose(&self, template_names: &[&str]) -> Result<Vec<UnifiedRule>> {
let mut rules = Vec::new();
for name in template_names {
if let Some(template) = self.registry.get(name) {
rules.extend(template.expand()?);
}
}
self.deduplicate(&mut rules);
Ok(rules)
}
pub fn compose_with_priority(&self, template_names: &[&str]) -> Result<Vec<UnifiedRule>> {
let mut all_rules: Vec<(usize, UnifiedRule)> = Vec::new();
for (priority, name) in template_names.iter().enumerate() {
if let Some(template) = self.registry.get(name) {
for rule in template.expand()? {
all_rules.push((priority, rule));
}
}
}
all_rules.sort_by_key(|(p, _)| std::cmp::Reverse(*p));
let rules: Vec<UnifiedRule> = all_rules.into_iter().map(|(_, r)| r).collect();
Ok(rules)
}
fn deduplicate(&self, rules: &mut Vec<UnifiedRule>) {
let mut seen_descriptions = std::collections::HashSet::new();
rules.retain(|rule| {
if let UnifiedRule::Standard { description, .. } = rule {
seen_descriptions.insert(description.clone())
} else {
true
}
});
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compose_empty() {
let registry = TemplateRegistry::new();
let composer = TemplateComposer::new(®istry);
let rules = composer.compose(&[]).unwrap();
assert!(rules.is_empty());
}
#[test]
fn test_compose_single() {
let registry = TemplateRegistry::new();
let composer = TemplateComposer::new(®istry);
let rules = composer.compose(&["architect"]).unwrap();
assert!(!rules.is_empty());
}
#[test]
fn test_compose_multiple() {
let registry = TemplateRegistry::new();
let composer = TemplateComposer::new(®istry);
let rules = composer
.compose(&["architect", "rust-idioms", "testing"])
.unwrap();
assert!(!rules.is_empty());
}
}