Skip to main content

driven/cli/
validate.rs

1//! Validate command - validate rules
2
3use crate::{Result, RuleSet, validation};
4use std::path::Path;
5
6/// Validate command handler
7#[derive(Debug)]
8pub struct ValidateCommand;
9
10impl ValidateCommand {
11    /// Run validation
12    pub fn run(rules_path: &Path) -> Result<()> {
13        let spinner = super::create_spinner("Loading and validating rules...");
14
15        // Load rules
16        let rule_set = RuleSet::load(rules_path)?;
17        let rules = rule_set.as_unified();
18
19        // Validate
20        let result = validation::validate(&rules)?;
21
22        spinner.finish_and_clear();
23
24        // Display results
25        if result.is_valid() {
26            super::print_success("All rules are valid!");
27        } else {
28            super::print_error(&format!(
29                "Validation failed: {} errors, {} warnings",
30                result.error_count(),
31                result.warning_count()
32            ));
33        }
34
35        // Show lint issues
36        if !result.lint_issues.is_empty() {
37            println!();
38            println!("📋 Lint Issues:");
39            for issue in &result.lint_issues {
40                let prefix = match issue.severity {
41                    validation::LintSeverity::Error => "  ❌",
42                    validation::LintSeverity::Warning => "  âš ī¸",
43                    validation::LintSeverity::Info => "  â„šī¸",
44                };
45                println!("{} {}", prefix, issue.message);
46                if let Some(suggestion) = &issue.suggestion {
47                    println!("     💡 {}", suggestion);
48                }
49            }
50        }
51
52        // Show conflicts
53        if !result.conflicts.is_empty() {
54            println!();
55            println!("âš”ī¸ Conflicts:");
56            for conflict in &result.conflicts {
57                println!("  ❌ {}", conflict.description);
58                for rule in &conflict.rules {
59                    println!("     - {}", rule);
60                }
61                if let Some(suggestion) = &conflict.suggestion {
62                    println!("     💡 {}", suggestion);
63                }
64            }
65        }
66
67        // Show coverage gaps
68        if !result.coverage_gaps.is_empty() {
69            println!();
70            println!("📭 Coverage Gaps:");
71            for gap in &result.coverage_gaps {
72                println!("  âš ī¸ {}", gap);
73            }
74        }
75
76        if result.is_valid() {
77            Ok(())
78        } else {
79            Err(crate::DrivenError::Validation(format!(
80                "{} errors found",
81                result.error_count()
82            )))
83        }
84    }
85
86    /// Run validation in strict mode
87    pub fn run_strict(rules_path: &Path) -> Result<()> {
88        let result = Self::run(rules_path);
89
90        // In strict mode, warnings also fail
91        if result.is_ok() {
92            let rule_set = RuleSet::load(rules_path)?;
93            let rules = rule_set.as_unified();
94            let validation_result = validation::validate(&rules)?;
95
96            if validation_result.warning_count() > 0 {
97                return Err(crate::DrivenError::Validation(format!(
98                    "{} warnings in strict mode",
99                    validation_result.warning_count()
100                )));
101            }
102        }
103
104        result
105    }
106}