Skip to main content

zenith_core/
diagnostics.rs

1//! Shared diagnostic types used across all Zenith validation passes.
2//!
3//! Diagnostics are collected without hard-failing — callers push them into a
4//! `Vec<Diagnostic>` and continue resolving what they can. `lib.rs` re-exports
5//! the most-used symbols at the crate root.
6
7use crate::ast::Span;
8
9/// The severity level of a [`Diagnostic`].
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub enum Severity {
12    /// A definite problem that prevents correct output.
13    Error,
14    /// A potential problem or version-relative issue; output may still be
15    /// produced.
16    Warning,
17    /// Informational note; does not block output.
18    Advisory,
19}
20
21/// A single structured diagnostic produced during validation or resolution.
22///
23/// Diagnostics carry a stable `code` that agents and tooling can key on, a
24/// human-readable `message`, an optional source `span`, and an optional
25/// `subject_id` naming the token (or future: node/style) the diagnostic is
26/// about.
27#[derive(Debug, Clone, PartialEq)]
28pub struct Diagnostic {
29    /// Stable dot-separated code, e.g. `"token.cyclic_reference"`.
30    pub code: String,
31    /// Severity classification.
32    pub severity: Severity,
33    /// Human-readable description.
34    pub message: String,
35    /// Source location, when available.
36    pub span: Option<Span>,
37    /// The token ID (or future: node/style ID) the diagnostic concerns.
38    pub subject_id: Option<String>,
39}
40
41impl Diagnostic {
42    /// Construct a new diagnostic with all fields explicit.
43    pub fn new(
44        code: impl Into<String>,
45        severity: Severity,
46        message: impl Into<String>,
47        span: Option<Span>,
48        subject_id: Option<String>,
49    ) -> Self {
50        Self {
51            code: code.into(),
52            severity,
53            message: message.into(),
54            span,
55            subject_id,
56        }
57    }
58
59    /// Shorthand for an [`Severity::Error`]-level diagnostic.
60    pub fn error(
61        code: impl Into<String>,
62        message: impl Into<String>,
63        span: Option<Span>,
64        subject_id: Option<String>,
65    ) -> Self {
66        Self::new(code, Severity::Error, message, span, subject_id)
67    }
68
69    /// Shorthand for a [`Severity::Warning`]-level diagnostic.
70    pub fn warning(
71        code: impl Into<String>,
72        message: impl Into<String>,
73        span: Option<Span>,
74        subject_id: Option<String>,
75    ) -> Self {
76        Self::new(code, Severity::Warning, message, span, subject_id)
77    }
78
79    /// Shorthand for an [`Severity::Advisory`]-level diagnostic.
80    pub fn advisory(
81        code: impl Into<String>,
82        message: impl Into<String>,
83        span: Option<Span>,
84        subject_id: Option<String>,
85    ) -> Self {
86        Self::new(code, Severity::Advisory, message, span, subject_id)
87    }
88}