weimo_wdf/diagnostic.rs
1use serde::Serialize;
2
3/// A single structured validation failure.
4///
5/// Diagnostics are data, not formatted strings: map `code` to UI behavior,
6/// `path` to the offending node (as JSON-pointer-like segments), and `message`
7/// to a user-facing message. All diagnostics produced by this crate have
8/// `severity == "error"` in v0.1.
9///
10/// `source` names the layer that rejected the input: `"wdf"` for the model
11/// and validator, `"markdown"`, `"prosemirror"` or `"apple"` for an adapter.
12#[derive(Clone, Debug, PartialEq, Serialize)]
13pub struct Diagnostic {
14 /// Layer that produced the failure: `wdf`, `markdown`, `prosemirror`, `apple`.
15 pub source: String,
16 /// Stable machine-readable code, e.g. `wdf.unsupported_mark`.
17 pub code: String,
18 /// Always `"error"` in v0.1.
19 pub severity: String,
20 /// JSON-pointer-like path to the offending value; may be empty.
21 pub path: Vec<serde_json::Value>,
22 /// Human-readable explanation.
23 pub message: String,
24}
25
26impl Diagnostic {
27 /// Creates an error diagnostic; attach a path with [`Diagnostic::at`].
28 pub fn error(source: &str, code: &str, message: impl Into<String>) -> Self {
29 Self {
30 source: source.to_string(),
31 code: code.to_string(),
32 severity: "error".to_string(),
33 path: vec![],
34 message: message.into(),
35 }
36 }
37
38 /// Sets the JSON path of the offending value.
39 pub fn at(mut self, path: Vec<serde_json::Value>) -> Self {
40 self.path = path;
41 self
42 }
43}
44
45/// All failures for one input; empty means the input is valid.
46pub type Diagnostics = Vec<Diagnostic>;