1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! The unified [`Diagnostic`] type shared by the parser, AST validation, and the
//! serialize/HTML pre-validation.
use alloc::string::String;
use crate::{ast::NodePath, span::Span};
/// How serious a [`Diagnostic`] is.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum DiagnosticSeverity {
/// A non-fatal issue; tolerant parsing continues.
Warning,
/// A hard error, such as a malformed directive or an invalid AST.
Error,
}
/// A machine-readable category for a [`Diagnostic`].
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum DiagnosticCode {
/// A directive name was malformed.
InvalidDirectiveName,
/// A container directive (`:::name`) was never closed.
UnclosedDirectiveContainer,
/// A directive attribute without a valid name was dropped.
InvalidDirectiveAttribute,
/// AST validation failure (an invalid or unsupported node shape), the single
/// code used by `Document::validate` and by serialize/HTML pre-validation.
InvalidDocument,
}
/// A single diagnostic across every domain — parser, AST validation, and the
/// serialize/HTML pre-validation that wraps it. `span` is optional because a
/// hand-built AST node may carry no source location.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Diagnostic {
/// How serious the issue is.
pub severity: DiagnosticSeverity,
/// The machine-readable category.
pub code: DiagnosticCode,
/// The source location, if known.
pub span: Option<Span>,
/// The path of the node a validation diagnostic is about, in the document
/// validated; `None` for a parser diagnostic.
pub path: Option<NodePath>,
/// A human-readable description.
pub message: String,
}
impl Diagnostic {
/// A parser diagnostic, which always carries a source span.
pub fn new(
severity: DiagnosticSeverity,
code: DiagnosticCode,
span: Span,
message: impl Into<String>,
) -> Self {
Self {
severity,
code,
span: Some(span),
path: None,
message: message.into(),
}
}
/// An AST-validation diagnostic (`Error` severity, `InvalidDocument` code),
/// whose span is optional because a hand-built node may lack one.
pub fn invalid(span: Option<Span>, message: impl Into<String>) -> Self {
Self {
severity: DiagnosticSeverity::Error,
code: DiagnosticCode::InvalidDocument,
span,
path: None,
message: message.into(),
}
}
}