use serde::{Deserialize, Serialize};
use super::{Diagnostic, Severity};
use crate::{DPCS_SPEC_VERSION, VERSION};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct ValidationReport {
pub diagnostics: Vec<Diagnostic>,
}
impl ValidationReport {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, diagnostic: Diagnostic) {
self.diagnostics.push(diagnostic);
}
pub fn extend(&mut self, other: ValidationReport) {
self.diagnostics.extend(other.diagnostics);
}
pub fn is_valid(&self) -> bool {
!self
.diagnostics
.iter()
.any(|d| d.severity == Severity::Error)
}
pub fn errors(&self) -> impl Iterator<Item = &Diagnostic> {
self.diagnostics
.iter()
.filter(|d| d.severity == Severity::Error)
}
pub fn warnings(&self) -> impl Iterator<Item = &Diagnostic> {
self.diagnostics
.iter()
.filter(|d| d.severity == Severity::Warning)
}
pub fn informations(&self) -> impl Iterator<Item = &Diagnostic> {
self.diagnostics
.iter()
.filter(|d| d.severity == Severity::Information)
}
pub fn error_count(&self) -> usize {
self.errors().count()
}
pub fn warning_count(&self) -> usize {
self.warnings().count()
}
pub fn information_count(&self) -> usize {
self.informations().count()
}
pub fn sort_deterministic(&mut self) {
self.diagnostics.sort_by(|a, b| {
a.id.cmp(&b.id)
.then_with(|| a.object_ref.cmp(&b.object_ref))
.then_with(|| a.message.cmp(&b.message))
});
}
pub fn into_diagnostic_report(
self,
artifact_id: Option<String>,
processing_result: ProcessingResult,
) -> DiagnosticReport {
DiagnosticReport {
processing_result,
artifact_id,
implementation: ImplementationMetadata::dpcs_default(),
diagnostics: self.diagnostics,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub enum ProcessingResult {
Valid,
Invalid,
}
impl ProcessingResult {
pub fn from_report(report: &ValidationReport) -> Self {
if report.is_valid() {
Self::Valid
} else {
Self::Invalid
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct ImplementationMetadata {
pub name: String,
pub version: String,
pub dpcs_spec_version: String,
}
impl ImplementationMetadata {
pub fn dpcs_default() -> Self {
Self {
name: "dpcs".to_owned(),
version: VERSION.to_owned(),
dpcs_spec_version: DPCS_SPEC_VERSION.to_owned(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticReport {
pub processing_result: ProcessingResult,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub artifact_id: Option<String>,
pub implementation: ImplementationMetadata,
pub diagnostics: Vec<Diagnostic>,
}
impl DiagnosticReport {
pub fn from_validation(report: ValidationReport, artifact_id: Option<String>) -> Self {
let processing_result = ProcessingResult::from_report(&report);
report.into_diagnostic_report(artifact_id, processing_result)
}
pub fn is_valid(&self) -> bool {
self.processing_result == ProcessingResult::Valid
}
}