rem_interface/
vscode.rs

1use serde::{Deserialize, Serialize};
2
3/// Bump this on breaking changes to the format. At the stage there shouldn't
4/// ever be any :D
5pub const SCHEMA_NAME: &str = "rem-interface";
6pub const SCHEMA_VERSION: u32 = 1;
7
8/// Top-level envelope every CLI command prints once to STDOUT (single JSON object).
9#[derive(Debug, Serialize, Deserialize)]
10pub struct Envelope<T> {
11    pub schema: Schema,
12    pub op: Operation,
13    pub ok: bool,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub data: Option<T>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub error: Option<RemError>,
18    #[serde(default, skip_serializing_if = "Vec::is_empty")]
19    pub diagnostics: Vec<Diagnostic>,
20    #[serde(default, skip_serializing_if = "Vec::is_empty")]
21    pub timings: Vec<Timing>,
22    #[serde(default, skip_serializing_if = "serde_json::Map::is_empty")]
23    pub meta: serde_json::Map<String, serde_json::Value>,
24}
25
26#[derive(Debug, Serialize, Deserialize)]
27pub struct Schema {
28    pub name: String,
29    pub version: u32,
30}
31
32#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
33#[serde(rename_all = "snake_case")]
34pub enum Operation {
35    Extract,
36    Repair,
37    Verify,
38}
39
40/// Current extraction payload: (extracted function, callsite replacement).
41#[derive(Debug, Serialize, Deserialize)]
42pub struct ExtractData {
43    pub extracted_fn: String,
44    pub callsite: String,
45}
46
47#[derive(Debug, Serialize, Deserialize)]
48pub struct RemError {
49    /// Stable, machine-readable code (extension switches on this).
50    pub code: String,
51    /// Human-readable message (for UI).
52    pub message: String,
53    /// Optional extra info, e.g., assists, spans, raw tool errors.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub details: Option<serde_json::Value>,
56}
57
58#[derive(Debug, Serialize, Deserialize)]
59pub struct Diagnostic {
60    pub file: Option<String>,
61    pub range: Option<Range>,
62    pub severity: Severity,
63    pub message: String,
64    #[serde(default, skip_serializing_if = "Vec::is_empty")]
65    pub related: Vec<RelatedInformation>,
66}
67
68#[derive(Debug, Serialize, Deserialize)]
69pub struct Range {
70    pub start: u32,
71    pub end: u32,
72}
73
74#[derive(Debug, Serialize, Deserialize)]
75pub struct RelatedInformation {
76    pub file: Option<String>,
77    pub range: Option<Range>,
78    pub message: String,
79}
80
81#[derive(Debug, Serialize, Deserialize)]
82#[serde(rename_all = "snake_case")]
83pub enum Severity {
84    Error,
85    Warning,
86    Info,
87}
88
89#[derive(Debug, Serialize, Deserialize)]
90pub struct Timing {
91    pub name: String,
92    pub nanos: u128,
93}
94
95pub fn ok_extract(extracted_fn: String, callsite: String, timings: Vec<Timing>) -> Envelope<ExtractData> {
96    Envelope {
97        schema: Schema { name: SCHEMA_NAME.to_string(), version: SCHEMA_VERSION },
98        op: Operation::Extract,
99        ok: true,
100        data: Some(ExtractData { extracted_fn, callsite }),
101        error: None,
102        diagnostics: vec![],
103        timings,
104        meta: Default::default(),
105    }
106}
107
108pub fn err_extract(error: RemError, diagnostics: Vec<Diagnostic>) -> Envelope<ExtractData> {
109    Envelope {
110        schema: Schema { name: SCHEMA_NAME.to_string(), version: SCHEMA_VERSION },
111        op: Operation::Extract,
112        ok: false,
113        data: None,
114        error: Some(error),
115        diagnostics,
116        timings: vec![],
117        meta: Default::default(),
118    }
119}