from __future__ import annotations from dataclasses import dataclass, field from pathlib import Path from typing import Any @dataclass(frozen=True) class Declaration: path: Path data: dict[str, Any] @property def kind(self) -> str: return str(self.data.get("kind", "")) @property def id(self) -> str: return str(self.data.get("metadata", {}).get("id", "")) @property def spec(self) -> dict[str, Any]: spec = self.data.get("spec", {}) return spec if isinstance(spec, dict) else {} @property def metadata(self) -> dict[str, Any]: meta = self.data.get("metadata", {}) return meta if isinstance(meta, dict) else {} @dataclass(frozen=True) class Diagnostic: severity: str code: str message: str path: Path | None = None def format(self) -> str: prefix = f"{self.severity} {self.code}" if self.path is not None: return f"{prefix} {self.path}: {self.message}" return f"{prefix}: {self.message}" @dataclass class ValidationReport: diagnostics: list[Diagnostic] = field(default_factory=list) @property def errors(self) -> list[Diagnostic]: return [d for d in self.diagnostics if d.severity == "ERROR"] @property def warnings(self) -> list[Diagnostic]: return [d for d in self.diagnostics if d.severity == "WARN"] def add(self, severity: str, code: str, message: str, path: Path | None = None) -> None: self.diagnostics.append(Diagnostic(severity, code, message, path)) def summary(self) -> str: return ( f"Validation complete: {len(self.errors)} error(s), " f"{len(self.warnings)} warning(s)" )