Skip to main content

jellyflow_runtime/rules/
diagnostic.rs

1use serde::{Deserialize, Serialize};
2
3use jellyflow_core::core::{EdgeId, NodeId, PortId, SymbolId};
4use jellyflow_core::ops::GraphOp;
5
6/// Diagnostic severity.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum DiagnosticSeverity {
10    /// Informational note.
11    Info,
12    /// Warning.
13    Warning,
14    /// Error.
15    Error,
16}
17
18/// Diagnostic target.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
20#[serde(tag = "kind", rename_all = "snake_case")]
21pub enum DiagnosticTarget {
22    /// Graph-level diagnostic.
23    Graph,
24    /// Node-level diagnostic.
25    Node { id: NodeId },
26    /// Port-level diagnostic.
27    Port { id: PortId },
28    /// Edge-level diagnostic.
29    Edge { id: EdgeId },
30    /// Symbol-level diagnostic.
31    Symbol { id: SymbolId },
32}
33
34/// A diagnostic produced by validation or connection planning.
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct Diagnostic {
37    /// Stable machine key (for filtering/suppression).
38    pub key: String,
39    /// Severity.
40    pub severity: DiagnosticSeverity,
41    /// Target element.
42    pub target: DiagnosticTarget,
43    /// Human-readable message.
44    pub message: String,
45    /// Optional suggested fixes expressed as graph ops.
46    #[serde(default, skip_serializing_if = "Vec::is_empty")]
47    pub fixes: Vec<GraphOp>,
48}
49
50impl Diagnostic {
51    pub fn error(
52        key: impl Into<String>,
53        target: DiagnosticTarget,
54        message: impl Into<String>,
55    ) -> Self {
56        Self {
57            key: key.into(),
58            severity: DiagnosticSeverity::Error,
59            target,
60            message: message.into(),
61            fixes: Vec::new(),
62        }
63    }
64}