From 22298434f10e203bc1adb8eebfdfbfbff05db977 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 10 Jan 2023 03:31:41 -0600 Subject: [PATCH] jsonrpc: Skip serializing params if params are None (#5471) The JSONRPC spec says: > If present, parameters for the rpc call MUST be provided as a > Structured value https://www.jsonrpc.org/specification#parameter_structures (Where a "Structured value" is elsewhere defined as either a map or array.) This change skips the serialization of the `params` field for JSONRPC method calls and notifications if the `params` field is the `None` variant. This fixes compatibility with LSP servers which adhere closely to that part of the spec: `ocamllsp` in the wild. --- helix-lsp/src/jsonrpc.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/helix-lsp/src/jsonrpc.rs b/helix-lsp/src/jsonrpc.rs index 75ac9309b..69d02707e 100644 --- a/helix-lsp/src/jsonrpc.rs +++ b/helix-lsp/src/jsonrpc.rs @@ -170,6 +170,10 @@ impl Params { serde_json::from_value(value) .map_err(|err| Error::invalid_params(format!("Invalid params: {}.", err))) } + + pub fn is_none(&self) -> bool { + self == &Params::None + } } impl From for Value { @@ -187,7 +191,7 @@ impl From for Value { pub struct MethodCall { pub jsonrpc: Option, pub method: String, - #[serde(default = "default_params")] + #[serde(default = "default_params", skip_serializing_if = "Params::is_none")] pub params: Params, pub id: Id, } @@ -197,7 +201,7 @@ pub struct MethodCall { pub struct Notification { pub jsonrpc: Option, pub method: String, - #[serde(default = "default_params")] + #[serde(default = "default_params", skip_serializing_if = "Params::is_none")] pub params: Params, } @@ -334,6 +338,33 @@ fn notification_serialize() { ); } +#[test] +fn serialize_skip_none_params() { + use serde_json; + + let m = MethodCall { + jsonrpc: Some(Version::V2), + method: "shutdown".to_owned(), + params: Params::None, + id: Id::Num(1), + }; + + let serialized = serde_json::to_string(&m).unwrap(); + assert_eq!( + serialized, + r#"{"jsonrpc":"2.0","method":"shutdown","id":1}"# + ); + + let n = Notification { + jsonrpc: Some(Version::V2), + method: "exit".to_owned(), + params: Params::None, + }; + + let serialized = serde_json::to_string(&n).unwrap(); + assert_eq!(serialized, r#"{"jsonrpc":"2.0","method":"exit"}"#); +} + #[test] fn success_output_deserialize() { use serde_json;