From 84af0f7a6031ea37947945da893a50bf92fa5c34 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sun, 25 Feb 2024 16:38:18 +0530 Subject: [PATCH] feat: include support for json5 encoding JSON5 is a superset of JSON, which includes support for trailing commas, extra whitespaces, comments, and an expanded set of numbers. This commit adds mainly decoding support for json5, in `@lune/serde`. Encoding "support" is also included, but isn't a practical use-case. * Expanded `EncodeDecodeFormat` to have a `Json5` variant * Handled JSON5 decoding using `serde_json5` crate * Matched JSON5 encoding alongside JSON --- Cargo.lock | 74 ++++++++++++++++++++++++ Cargo.toml | 1 + src/lune/builtins/serde/encode_decode.rs | 13 ++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 324c99d..6beb2e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1134,6 +1134,7 @@ dependencies = [ "rustyline", "serde", "serde_json", + "serde_json5", "serde_yaml", "thiserror", "tokio", @@ -1394,6 +1395,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pest_meta" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project" version = "1.1.3" @@ -1992,6 +2038,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_json5" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a6b754515e1a7bd79fc2edeaecee526fc80cb3a918607e5ca149225a3a9586" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.5" @@ -2052,6 +2109,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -2568,6 +2636,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-bidi" version = "0.3.14" diff --git a/Cargo.toml b/Cargo.toml index 9a07893..547934f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ async-compression = { version = "0.4", features = [ ] } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } +serde_json5 = { version = "0.1.0" } serde_yaml = "0.9" toml = { version = "0.8", features = ["preserve_order"] } diff --git a/src/lune/builtins/serde/encode_decode.rs b/src/lune/builtins/serde/encode_decode.rs index 1f83ce4..3fde280 100644 --- a/src/lune/builtins/serde/encode_decode.rs +++ b/src/lune/builtins/serde/encode_decode.rs @@ -17,6 +17,7 @@ const LUA_DESERIALIZE_OPTIONS: LuaDeserializeOptions = LuaDeserializeOptions::ne #[derive(Debug, Clone, Copy)] pub enum EncodeDecodeFormat { Json, + Json5, Yaml, Toml, } @@ -26,13 +27,14 @@ impl<'lua> FromLua<'lua> for EncodeDecodeFormat { if let LuaValue::String(s) = &value { match s.to_string_lossy().to_ascii_lowercase().trim() { "json" => Ok(Self::Json), + "json5" => Ok(Self::Json5), "yaml" => Ok(Self::Yaml), "toml" => Ok(Self::Toml), kind => Err(LuaError::FromLuaConversionError { from: value.type_name(), to: "EncodeDecodeFormat", message: Some(format!( - "Invalid format '{kind}', valid formats are: json, yaml, toml" + "Invalid format '{kind}', valid formats are: json, json5, yaml, toml" )), }), } @@ -59,7 +61,10 @@ impl EncodeDecodeConfig { value: LuaValue<'lua>, ) -> LuaResult> { let bytes = match self.format { - EncodeDecodeFormat::Json => { + // Encoding to Json5 is impractical, since it only includes support for + // things like trailing commas, comments, etc. which provide convenience + // for humans + EncodeDecodeFormat::Json | EncodeDecodeFormat::Json5 => { let serialized: JsonValue = lua.from_value_with(value, LUA_DESERIALIZE_OPTIONS)?; if self.pretty { serde_json::to_vec_pretty(&serialized).into_lua_err()? @@ -97,6 +102,10 @@ impl EncodeDecodeConfig { let value: JsonValue = serde_json::from_slice(bytes).into_lua_err()?; lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS) } + EncodeDecodeFormat::Json5 => { + let value: JsonValue = serde_json5::from_slice(bytes).into_lua_err()?; + lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS) + } EncodeDecodeFormat::Yaml => { let value: YamlValue = serde_yaml::from_slice(bytes).into_lua_err()?; lua.to_value_with(&value, LUA_SERIALIZE_OPTIONS)