Skip to main content

ontocore_plugin/
protocol.rs

1use ontocore_core::{
2    validate_workspace_scope, Diagnostic, DiagnosticCode, DiagnosticSeverity, SourceLocation,
3};
4use serde::{Deserialize, Serialize};
5use std::path::{Path, PathBuf};
6
7/// JSON wire format returned by subprocess plugins on stdout.
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9pub struct PluginOutput {
10    #[serde(default)]
11    pub diagnostics: Vec<PluginDiagnosticWire>,
12    #[serde(default)]
13    pub output_paths: Vec<String>,
14    #[serde(default)]
15    pub logs: Option<String>,
16    #[serde(default)]
17    pub exit_message: Option<String>,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct PluginDiagnosticWire {
22    pub code: String,
23    pub severity: String,
24    pub message: String,
25    pub file: String,
26    #[serde(default)]
27    pub line: Option<u64>,
28    #[serde(default)]
29    pub column: Option<u64>,
30    #[serde(default)]
31    pub entity_iri: Option<String>,
32}
33
34impl PluginDiagnosticWire {
35    pub fn into_diagnostic(self, plugin_id: &str, workspace: &Path) -> Diagnostic {
36        let requested = PathBuf::from(&self.file);
37        let (file, message) = match validate_workspace_scope(&requested, workspace) {
38            Ok(file) => (file, self.message),
39            Err(err) => (
40                workspace.to_path_buf(),
41                format!(
42                    "{} (rejected plugin diagnostic file path '{}': {})",
43                    self.message, self.file, err
44                ),
45            ),
46        };
47        Diagnostic {
48            code: DiagnosticCode::PluginViolation,
49            severity: match self.severity.as_str() {
50                "error" => DiagnosticSeverity::Error,
51                "warning" => DiagnosticSeverity::Warning,
52                _ => DiagnosticSeverity::Info,
53            },
54            message,
55            file,
56            range: SourceLocation {
57                line: self.line,
58                column: self.column,
59                start_byte: None,
60                end_byte: None,
61            },
62            entity_iri: self.entity_iri,
63            quick_fix: None,
64            plugin_id: Some(plugin_id.to_string()),
65            plugin_code: Some(self.code),
66        }
67    }
68}
69
70pub fn plugin_diagnostic(
71    plugin_id: &str,
72    code: &str,
73    severity: DiagnosticSeverity,
74    message: impl Into<String>,
75    file: PathBuf,
76    entity_iri: Option<String>,
77) -> Diagnostic {
78    Diagnostic {
79        code: DiagnosticCode::PluginViolation,
80        severity,
81        message: message.into(),
82        file,
83        range: SourceLocation::default(),
84        entity_iri,
85        quick_fix: None,
86        plugin_id: Some(plugin_id.to_string()),
87        plugin_code: Some(code.to_string()),
88    }
89}