Skip to main content

varar_core/
diagnostics.rs

1//! Diagnostics produced by the planner — port of the subset of `diagnostics.ts`
2//! that `Plan` needs / `Diagnostics.java`.
3
4use crate::span::Span;
5
6/// Diagnostic severity. Only `Error` is constructed today.
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum Severity {
9    Error,
10    Warning,
11    Info,
12}
13
14/// The closed set of diagnostic codes the planner produces. `Ord` follows the
15/// Java enum's declaration order (ordinal), matching its sort semantics.
16#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
17pub enum DiagnosticCode {
18    AmbiguousMatch,
19    ErrorFenceWithoutStep,
20    Drift,
21    /// Reference blocks (ADR 0016): a link that resolves to no oath, to a
22    /// section with no steps, to a chain that reaches itself, or to an anchor
23    /// that names more than one heading.
24    ReferenceNotFound,
25    ReferenceEmpty,
26    ReferenceCycle,
27    AmbiguousAnchor,
28}
29
30/// One diagnostic: its code, severity, and the source span it points at.
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub struct Diagnostic {
33    pub code: DiagnosticCode,
34    pub severity: Severity,
35    pub span: Span,
36}
37
38/// Builds an `ambiguous-match` diagnostic pointing at `span`.
39pub fn ambiguous_match(span: Span) -> Diagnostic {
40    Diagnostic {
41        code: DiagnosticCode::AmbiguousMatch,
42        severity: Severity::Error,
43        span,
44    }
45}
46
47/// Builds an `error-fence-without-step` diagnostic pointing at `span`.
48pub fn error_fence_without_step(span: Span) -> Diagnostic {
49    Diagnostic {
50        code: DiagnosticCode::ErrorFenceWithoutStep,
51        severity: Severity::Error,
52        span,
53    }
54}
55
56/// A reference block (ADR 0016) points at an oath the workspace does not hold.
57/// Never prose: a link-only block that resolves to nothing has no other
58/// reading, so it fails the run rather than degrading silently.
59pub fn reference_not_found(span: Span) -> Diagnostic {
60    Diagnostic {
61        code: DiagnosticCode::ReferenceNotFound,
62        severity: Severity::Error,
63        span,
64    }
65}
66
67/// The referenced document exists but the section contributes no steps — a
68/// mistyped anchor, or a section that is pure prose.
69pub fn reference_empty(span: Span) -> Diagnostic {
70    Diagnostic {
71        code: DiagnosticCode::ReferenceEmpty,
72        severity: Severity::Error,
73        span,
74    }
75}
76
77/// References nest to any depth, so a chain that reaches a section already on
78/// it is reported rather than recursed into.
79pub fn reference_cycle(span: Span) -> Diagnostic {
80    Diagnostic {
81        code: DiagnosticCode::ReferenceCycle,
82        severity: Severity::Error,
83        span,
84    }
85}
86
87/// The anchor names more than one heading in the target document (two headings
88/// slugify identically), so the reference could mean either section. Reported
89/// rather than guessed: rename the headings so each has an anchor of its own.
90pub fn ambiguous_anchor(span: Span) -> Diagnostic {
91    Diagnostic {
92        code: DiagnosticCode::AmbiguousAnchor,
93        severity: Severity::Error,
94        span,
95    }
96}