""" Base Validator Class Shared functionality for all validators. """ from abc import ABC, abstractmethod from pathlib import Path from typing import Any import yaml class BaseValidator(ABC): """Base class for architecture, security, and performance validators.""" def __init__(self, rules_dir: str, project_root: Path | None = None): self.rules_dir = rules_dir self.project_root = project_root or Path.cwd() self.rules: list[dict[str, Any]] = [] self.errors: list[dict[str, Any]] = [] self.warnings: list[dict[str, Any]] = [] def load_rules(self) -> None: """Load rules from YAML files.""" rules_path = self.project_root / self.rules_dir if not rules_path.exists(): print(f"Rules directory not found: {rules_path}") return for rule_file in rules_path.glob("*.yaml"): if rule_file.name.startswith("_"): continue # Skip main config with open(rule_file) as f: data = yaml.safe_load(f) if data and "rules" in data: self.rules.extend(data["rules"]) @abstractmethod def validate(self) -> bool: """Run validation. Returns True if passed.""" def add_error( self, rule_id: str, message: str, file: str = "", line: int = 0 ) -> None: """Add an error.""" self.errors.append( { "rule_id": rule_id, "message": message, "file": file, "line": line, "severity": "error", } ) def add_warning( self, rule_id: str, message: str, file: str = "", line: int = 0 ) -> None: """Add a warning.""" self.warnings.append( { "rule_id": rule_id, "message": message, "file": file, "line": line, "severity": "warning", } ) def add_info( self, rule_id: str, message: str, file: str = "", line: int = 0 ) -> None: """Add an informational note.""" self.warnings.append( { "rule_id": rule_id, "message": message, "file": file, "line": line, "severity": "info", } ) def print_results(self) -> None: """Print validation results.""" if not self.errors and not self.warnings: print(f"✅ All {self.rules_dir} rules passed!") return if self.errors: print(f"\n❌ {len(self.errors)} errors found:") for error in self.errors: print(f" [{error['rule_id']}] {error['message']}") if error["file"]: print(f" File: {error['file']}:{error['line']}") if self.warnings: print(f"\n⚠️ {len(self.warnings)} warnings:") for warning in self.warnings: print(f" [{warning['rule_id']}] {warning['message']}") if warning["file"]: print(f" File: {warning['file']}:{warning['line']}") def run(self) -> int: """Run validation and return exit code.""" self.load_rules() passed = self.validate() self.print_results() return 0 if passed else 1