use super::templates::*;
use super::config::*;
use crate::error::{OptimError, Result};
#[derive(Debug, Default)]
pub struct TemplateValidator {
rules: Vec<ValidationRule>,
}
#[derive(Debug, Clone)]
pub struct ValidationRule {
pub name: String,
pub description: String,
pub validator: fn(&PluginTemplate) -> ValidationResult,
pub mandatory: bool,
}
#[derive(Debug, Clone)]
pub struct ValidationResult {
pub passed: bool,
pub message: String,
pub severity: ValidationSeverity,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValidationSeverity {
Info,
Warning,
Error,
Critical,
}
#[derive(Debug)]
pub struct ValidationReport {
pub template_id: String,
pub overall_result: bool,
pub rule_results: Vec<ValidationResult>,
pub timestamp: chrono::DateTime<chrono::Utc>,
}
impl TemplateValidator {
pub fn new() -> Self {
let mut validator = Self {
rules: Vec::new(),
};
validator.add_default_rules();
validator
}
pub fn add_rule(&mut self, rule: ValidationRule) {
self.rules.push(rule);
}
pub fn validate(&self, template: &PluginTemplate) -> ValidationReport {
let mut rule_results = Vec::new();
let mut overall_result = true;
for rule in &self.rules {
let result = (rule.validator)(template);
if rule.mandatory && !result.passed {
overall_result = false;
}
rule_results.push(result);
}
ValidationReport {
template_id: template.metadata.id.clone(),
overall_result,
rule_results,
timestamp: chrono::Utc::now(),
}
}
fn add_default_rules(&mut self) {
self.add_rule(ValidationRule {
name: "template_id".to_string(),
description: "Template ID must be non-empty and valid".to_string(),
validator: |template| {
if template.metadata.id.is_empty() {
ValidationResult {
passed: false,
message: "Template ID cannot be empty".to_string(),
severity: ValidationSeverity::Error,
}
} else {
ValidationResult {
passed: true,
message: "Template ID is valid".to_string(),
severity: ValidationSeverity::Info,
}
}
},
mandatory: true,
});
self.add_rule(ValidationRule {
name: "template_name".to_string(),
description: "Template name must be non-empty".to_string(),
validator: |template| {
if template.structure.name.is_empty() {
ValidationResult {
passed: false,
message: "Template name cannot be empty".to_string(),
severity: ValidationSeverity::Error,
}
} else {
ValidationResult {
passed: true,
message: "Template name is valid".to_string(),
severity: ValidationSeverity::Info,
}
}
},
mandatory: true,
});
self.add_rule(ValidationRule {
name: "description".to_string(),
description: "Template should have a meaningful description".to_string(),
validator: |template| {
if template.structure.description.len() < 20 {
ValidationResult {
passed: false,
message: "Template description should be at least 20 characters".to_string(),
severity: ValidationSeverity::Warning,
}
} else {
ValidationResult {
passed: true,
message: "Template description is adequate".to_string(),
severity: ValidationSeverity::Info,
}
}
},
mandatory: false,
});
self.add_rule(ValidationRule {
name: "author".to_string(),
description: "Template should have author information".to_string(),
validator: |template| {
if template.metadata.author.is_empty() {
ValidationResult {
passed: false,
message: "Template should have author information".to_string(),
severity: ValidationSeverity::Warning,
}
} else {
ValidationResult {
passed: true,
message: "Template has author information".to_string(),
severity: ValidationSeverity::Info,
}
}
},
mandatory: false,
});
}
}
impl ValidationReport {
pub fn errors(&self) -> Vec<&ValidationResult> {
self.rule_results
.iter()
.filter(|r| !r.passed && matches!(r.severity, ValidationSeverity::Error | ValidationSeverity::Critical))
.collect()
}
pub fn warnings(&self) -> Vec<&ValidationResult> {
self.rule_results
.iter()
.filter(|r| matches!(r.severity, ValidationSeverity::Warning))
.collect()
}
pub fn is_valid(&self) -> bool {
self.overall_result
}
}