Repository: GREsau/schemars
Pull request #79 (2021-04-05 15:10:01)

Fix deriving JsonSchema inside macro
Fix for #66 


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4033b69..e1c60c5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Changelog
 
+## [0.8.3] - **In-dev**
+### Fixed:
+- Fix deriving JsonSchema on types defined inside macros (https://github.com/GREsau/schemars/issues/66 / https://github.com/GREsau/schemars/pull/79)
+
 ## [0.8.2] - 2021-03-27
 ### Added:
 - Enable generating a schema from any serializable value using `schema_for_value!(...)` macro or `SchemaGenerator::root_schema_for_value()`/`SchemaGenerator::into_root_schema_for_value()` methods (https://github.com/GREsau/schemars/pull/75)
diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs
index a5cf2ca..3b25d05 100644
--- a/schemars_derive/src/schema_exprs.rs
+++ b/schemars_derive/src/schema_exprs.rs
@@ -390,32 +390,36 @@ fn expr_for_struct(
 
     let mut type_defs = Vec::new();
 
-    let properties: Vec<_> = property_fields.into_iter().map(|field| {
-        let name = field.name();
-        let default = field_default_expr(field, set_container_default.is_some());
+    let properties: Vec<_> = property_fields
+        .into_iter()
+        .map(|field| {
+            let name = field.name();
+            let default = field_default_expr(field, set_container_default.is_some());
 
-        let required = match default {
-            Some(_) => quote!(false),
-            None => quote!(true),
-        };
+            let required = match default {
+                Some(_) => quote!(false),
+                None => quote!(true),
+            };
 
-        let metadata = &SchemaMetadata {
-            read_only: field.serde_attrs.skip_deserializing(),
-            write_only: field.serde_attrs.skip_serializing(),
-            default,
-            ..SchemaMetadata::from_attrs(&field.attrs)
-        };
+            let metadata = &SchemaMetadata {
+                read_only: field.serde_attrs.skip_deserializing(),
+                write_only: field.serde_attrs.skip_serializing(),
+                default,
+                ..SchemaMetadata::from_attrs(&field.attrs)
+            };
 
-        let (ty, type_def) = type_for_schema(field, type_defs.len());
-        if let Some(type_def) = type_def {
-            type_defs.push(type_def);
-        }
+            let (ty, type_def) = type_for_schema(field, type_defs.len());
+            if let Some(type_def) = type_def {
+                type_defs.push(type_def);
+            }
 
-        quote_spanned! {ty.span()=>
-            <#ty as schemars::JsonSchema>::add_schema_as_property(gen, &mut schema_object, #name.to_owned(), #metadata, #required);
-        }
+            let args = quote!(gen, &mut schema_object, #name.to_owned(), #metadata, #required);
 
-    }).collect();
+            quote_spanned! {ty.span()=>
+                <#ty as schemars::JsonSchema>::add_schema_as_property(#args);
+            }
+        })
+        .collect();
 
     let flattens: Vec<_> = flattened_fields
         .into_iter()


Test patch:
diff --git a/schemars/tests/expected/macro_built_struct.json b/schemars/tests/expected/macro_built_struct.json
new file mode 100644
index 0000000..811eae3
--- /dev/null
+++ b/schemars/tests/expected/macro_built_struct.json
@@ -0,0 +1,20 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "A",
+  "type": "object",
+  "required": [
+    "v",
+    "x"
+  ],
+  "properties": {
+    "x": {
+      "type": "integer",
+      "format": "uint8",
+      "minimum": 0.0
+    },
+    "v": {
+      "type": "integer",
+      "format": "int32"
+    }
+  }
+}
\ No newline at end of file
diff --git a/schemars/tests/macro.rs b/schemars/tests/macro.rs
new file mode 100644
index 0000000..0ed39d7
--- /dev/null
+++ b/schemars/tests/macro.rs
@@ -0,0 +1,22 @@
+mod util;
+use schemars::JsonSchema;
+use util::*;
+
+macro_rules! build_struct {
+    (
+        $id:ident { $($t:tt)* }
+    ) => {
+        #[derive(Debug, JsonSchema)]
+        pub struct $id {
+            x: u8,
+            $($t)*
+        }
+    };
+}
+
+build_struct!(A { v: i32 });
+
+#[test]
+fn macro_built_struct() -> TestResult {
+    test_default_generated_schema::<A>("macro_built_struct")
+}