ontocore_plugin/
protocol.rs1use ontocore_core::{
2 validate_workspace_scope, Diagnostic, DiagnosticCode, DiagnosticSeverity, SourceLocation,
3};
4use serde::{Deserialize, Serialize};
5use std::path::{Path, PathBuf};
6
7#[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 #[serde(default)]
20 pub view_html: Option<String>,
21 #[serde(default)]
23 pub violations: Vec<String>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct PluginDiagnosticWire {
28 pub code: String,
29 pub severity: String,
30 pub message: String,
31 pub file: String,
32 #[serde(default)]
33 pub line: Option<u64>,
34 #[serde(default)]
35 pub column: Option<u64>,
36 #[serde(default)]
37 pub entity_iri: Option<String>,
38}
39
40impl PluginDiagnosticWire {
41 pub fn into_diagnostic(self, plugin_id: &str, workspace: &Path) -> Diagnostic {
42 let requested = PathBuf::from(&self.file);
43 let (file, message) = match validate_workspace_scope(&requested, workspace) {
44 Ok(file) => (file, self.message),
45 Err(err) => (
46 workspace.to_path_buf(),
47 format!(
48 "{} (rejected plugin diagnostic file path '{}': {})",
49 self.message, self.file, err
50 ),
51 ),
52 };
53 Diagnostic {
54 code: DiagnosticCode::PluginViolation,
55 severity: match self.severity.as_str() {
56 "error" => DiagnosticSeverity::Error,
57 "warning" => DiagnosticSeverity::Warning,
58 _ => DiagnosticSeverity::Info,
59 },
60 message,
61 file,
62 range: SourceLocation {
63 line: self.line,
64 column: self.column,
65 start_byte: None,
66 end_byte: None,
67 },
68 entity_iri: self.entity_iri,
69 quick_fix: None,
70 plugin_id: Some(plugin_id.to_string()),
71 plugin_code: Some(self.code),
72 }
73 }
74}
75
76pub fn jail_output_paths(
77 plugin_id: &str,
78 workspace: &Path,
79 mut output: PluginOutput,
80) -> PluginOutput {
81 let mut jailed = Vec::new();
82 for p in output.output_paths.drain(..) {
83 let requested = PathBuf::from(&p);
84 match validate_workspace_scope(&requested, workspace) {
85 Ok(path) => jailed.push(path.display().to_string()),
86 Err(err) => output
87 .violations
88 .push(format!("rejected plugin output path '{p}' for {plugin_id}: {err}")),
89 }
90 }
91 output.output_paths = jailed;
92 output
93}
94
95pub fn plugin_diagnostic(
96 plugin_id: &str,
97 code: &str,
98 severity: DiagnosticSeverity,
99 message: impl Into<String>,
100 file: PathBuf,
101 entity_iri: Option<String>,
102) -> Diagnostic {
103 Diagnostic {
104 code: DiagnosticCode::PluginViolation,
105 severity,
106 message: message.into(),
107 file,
108 range: SourceLocation::default(),
109 entity_iri,
110 quick_fix: None,
111 plugin_id: Some(plugin_id.to_string()),
112 plugin_code: Some(code.to_string()),
113 }
114}