From 0792de404c303f043fd007d5da640b0c8a0a8934 Mon Sep 17 00:00:00 2001 From: Santiago Fraire Date: Wed, 24 Apr 2024 09:24:00 +0200 Subject: [PATCH] feat: add tag to token and add support for json-schema BREAKING CHANGE: The serialized output is no longer like ``` {"Ingredient": {"name": "foo", "amount": "1", "unit": "gr"}} ``` but instead ``` {"token": "Ingredient", "name": "foo", "amount": "1", "unit": "gr"} ``` --- Cargo.lock | 42 ++++++++++++++++++++++++++++++ crates/recipe-parser/Cargo.toml | 6 +++++ crates/recipe-parser/src/parser.rs | 40 ++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 3262431..61b599f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,6 +140,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -306,6 +312,7 @@ name = "recipe-parser" version = "0.5.0" dependencies = [ "rstest", + "schemars", "serde", "serde_json", "winnow", @@ -392,6 +399,30 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "semver" version = "1.0.22" @@ -418,6 +449,17 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.116" diff --git a/crates/recipe-parser/Cargo.toml b/crates/recipe-parser/Cargo.toml index 5444994..f0ff455 100644 --- a/crates/recipe-parser/Cargo.toml +++ b/crates/recipe-parser/Cargo.toml @@ -12,6 +12,7 @@ homepage = { workspace = true } categories = ["command-line-interface", "parser-implementations"] [dependencies] +schemars = { version = "0.8.16", optional = true } serde = { version = "1", features = ["derive"], optional = true } winnow = "0.6.6" @@ -23,4 +24,9 @@ serde_json = "1.0" path = "src/lib.rs" [features] + +# Adds serde Serialize implementation to Token serde = ["dep:serde"] + +# Add JsonSchema generation for Token +schemars = ["dep:schemars"] diff --git a/crates/recipe-parser/src/parser.rs b/crates/recipe-parser/src/parser.rs index d332081..abf1001 100644 --- a/crates/recipe-parser/src/parser.rs +++ b/crates/recipe-parser/src/parser.rs @@ -194,6 +194,9 @@ fn parse_backstory<'a>(input: &mut Input<'a>) -> PResult<&'a str> { #[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +// if you use `zod` for example, using a tag makes it easy to use an undiscriminated union +#[cfg_attr(feature = "serde", serde(tag = "token"))] pub enum Token<'a> { Metadata { key: &'a str, @@ -553,4 +556,41 @@ mod test { assert_eq!(expected, fmt_recipe); println!("{:?}", recipe); } + + #[test] + #[cfg(feature = "serde")] + fn test_token_serialization_works() { + let token = Token::Ingredient { + name: "quinoa", + quantity: Some("200"), + unit: Some("gr"), + }; + + let serialized = serde_json::to_string(&token).expect("failed to serialize"); + println!("{}", serialized); + } + + #[test] + #[cfg(feature = "serde")] + fn test_token_serialization_creates_right_payload() { + let token = Token::Ingredient { + name: "quinoa", + quantity: Some("200"), + unit: Some("gr"), + }; + + let serialized = serde_json::to_string(&token).expect("failed to serialize"); + assert_eq!( + serialized, + r#"{"token":"Ingredient","name":"quinoa","quantity":"200","unit":"gr"}"# + ); + } + + #[test] + #[cfg(feature = "schemars")] + fn test_token_json_schema_generation() { + use schemars::schema_for; + let schema = schema_for!(Token); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); + } }