diff --git a/schemars/src/json_schema_impls/array.rs b/schemars/src/json_schema_impls/array.rs index b14ca55..0ed1469 100644 --- a/schemars/src/json_schema_impls/array.rs +++ b/schemars/src/json_schema_impls/array.rs @@ -1,7 +1,6 @@ use crate::gen::SchemaGenerator; use crate::schema::*; -use crate::{JsonSchema, Map, Result}; -use serde_json::json; +use crate::{JsonSchema, Result}; // Does not require T: JsonSchema. impl JsonSchema for [T; 0] { @@ -12,11 +11,12 @@ impl JsonSchema for [T; 0] { } fn json_schema(_: &mut SchemaGenerator) -> Result { - let mut extensions = Map::new(); - extensions.insert("maxItems".to_owned(), json!(0)); Ok(SchemaObject { instance_type: Some(InstanceType::Array.into()), - extensions, + array: ArrayValidation { + max_items: Some(0), + ..Default::default() + }, ..Default::default() } .into()) @@ -34,13 +34,14 @@ macro_rules! array_impls { } fn json_schema(gen: &mut SchemaGenerator) -> Result { - let mut extensions = Map::new(); - extensions.insert("minItems".to_owned(), json!($len)); - extensions.insert("maxItems".to_owned(), json!($len)); Ok(SchemaObject { instance_type: Some(InstanceType::Array.into()), - items: Some(gen.subschema_for::()?.into()), - extensions, + array: ArrayValidation { + items: Some(gen.subschema_for::()?.into()), + max_items: Some($len), + min_items: Some($len), + ..Default::default() + }, ..Default::default() }.into()) } @@ -69,9 +70,12 @@ mod tests { schema.instance_type, Some(SingleOrVec::from(InstanceType::Array)) ); - assert_eq!(schema.extensions.get("minItems"), Some(&json!(8))); - assert_eq!(schema.extensions.get("maxItems"), Some(&json!(8))); - assert_eq!(schema.items, Some(SingleOrVec::from(schema_for::()))); + assert_eq!( + schema.array.items, + Some(SingleOrVec::from(schema_for::())) + ); + assert_eq!(schema.array.max_items, Some(8)); + assert_eq!(schema.array.min_items, Some(8)); } // SomeStruct does not implement JsonSchema @@ -84,6 +88,6 @@ mod tests { schema.instance_type, Some(SingleOrVec::from(InstanceType::Array)) ); - assert_eq!(schema.extensions.get("maxItems"), Some(&json!(0))); + assert_eq!(schema.array.max_items, Some(0)); } } diff --git a/schemars/src/json_schema_impls/maps.rs b/schemars/src/json_schema_impls/maps.rs index e823ad1..c344b6c 100644 --- a/schemars/src/json_schema_impls/maps.rs +++ b/schemars/src/json_schema_impls/maps.rs @@ -1,7 +1,6 @@ use crate::gen::{BoolSchemas, SchemaGenerator}; use crate::schema::*; -use crate::{JsonSchema, Map, Result}; -use serde_json::json; +use crate::{JsonSchema, Result}; macro_rules! map_impl { ($($desc:tt)+) => { @@ -20,18 +19,18 @@ macro_rules! map_impl { let subschema = gen.subschema_for::()?; let json_schema_bool = gen.settings().bool_schemas == BoolSchemas::AdditionalPropertiesOnly && subschema == gen.schema_for_any(); - let mut extensions = Map::new(); - extensions.insert( - "additionalProperties".to_owned(), + let additional_properties = if json_schema_bool { - json!(true) + true.into() } else { - json!(subschema) - } - ); + subschema.into() + }; Ok(SchemaObject { instance_type: Some(InstanceType::Object.into()), - extensions, + object: ObjectValidation { + additional_properties: Some(Box::new(additional_properties)), + ..Default::default() + }, ..Default::default() }.into()) } @@ -62,10 +61,10 @@ mod tests { schema.instance_type, Some(SingleOrVec::from(InstanceType::Object)) ); - assert_eq!( - schema.extensions.get("additionalProperties"), - Some(&json!(true)) - ); + let additional_properties = schema.object + .additional_properties + .expect("additionalProperties field present"); + assert_eq!(*additional_properties, Schema::Bool(true)); } } @@ -80,10 +79,10 @@ mod tests { schema.instance_type, Some(SingleOrVec::from(InstanceType::Object)) ); - assert_eq!( - schema.extensions.get("additionalProperties"), - Some(&json!(Schema::Object(Default::default()))) - ); + let additional_properties = schema.object + .additional_properties + .expect("additionalProperties field present"); + assert_eq!(*additional_properties, Schema::Object(Default::default())); } #[test] @@ -102,10 +101,10 @@ mod tests { schema.instance_type, Some(SingleOrVec::from(InstanceType::Object)) ); - assert_eq!( - schema.extensions.get("additionalProperties"), - Some(&json!(schema_for::())) - ); + let additional_properties = schema.object + .additional_properties + .expect("additionalProperties field present"); + assert_eq!(*additional_properties, schema_for::()); } } } diff --git a/schemars/src/json_schema_impls/primitives.rs b/schemars/src/json_schema_impls/primitives.rs index 6576737..44b9d36 100644 --- a/schemars/src/json_schema_impls/primitives.rs +++ b/schemars/src/json_schema_impls/primitives.rs @@ -1,7 +1,6 @@ use crate::gen::SchemaGenerator; use crate::schema::*; -use crate::{JsonSchema, Map, Result}; -use serde_json::json; +use crate::{JsonSchema, Result}; macro_rules! simple_impl { ($type:tt => $instance_type:ident) => { @@ -57,12 +56,13 @@ impl JsonSchema for char { } fn json_schema(_: &mut SchemaGenerator) -> Result { - let mut extensions = Map::new(); - extensions.insert("minLength".to_owned(), json!(1)); - extensions.insert("maxLength".to_owned(), json!(1)); Ok(SchemaObject { instance_type: Some(InstanceType::String.into()), - extensions, + string: StringValidation { + min_length: Some(1), + max_length: Some(1), + ..Default::default() + }, ..Default::default() } .into()) diff --git a/schemars/src/json_schema_impls/sequences.rs b/schemars/src/json_schema_impls/sequences.rs index b5d493f..a55b812 100644 --- a/schemars/src/json_schema_impls/sequences.rs +++ b/schemars/src/json_schema_impls/sequences.rs @@ -17,7 +17,10 @@ macro_rules! seq_impl { fn json_schema(gen: &mut SchemaGenerator) -> Result { Ok(SchemaObject { instance_type: Some(InstanceType::Array.into()), - items: Some(gen.subschema_for::()?.into()), + array: ArrayValidation { + items: Some(gen.subschema_for::()?.into()), + ..Default::default() + }, ..Default::default() }.into()) } diff --git a/schemars/src/json_schema_impls/tuple.rs b/schemars/src/json_schema_impls/tuple.rs index 987a748..f90dfd4 100644 --- a/schemars/src/json_schema_impls/tuple.rs +++ b/schemars/src/json_schema_impls/tuple.rs @@ -1,7 +1,6 @@ use crate::gen::SchemaGenerator; use crate::schema::*; -use crate::{JsonSchema, Map, Result}; -use serde_json::json; +use crate::{JsonSchema, Result}; macro_rules! tuple_impls { ($($len:expr => ($($name:ident)+))+) => { @@ -14,16 +13,17 @@ macro_rules! tuple_impls { } fn json_schema(gen: &mut SchemaGenerator) -> Result { - let mut extensions = Map::new(); - extensions.insert("minItems".to_owned(), json!($len)); - extensions.insert("maxItems".to_owned(), json!($len)); let items = vec![ $(gen.subschema_for::<$name>()?),+ ]; Ok(SchemaObject { instance_type: Some(InstanceType::Array.into()), - items: Some(items.into()), - extensions, + array: ArrayValidation { + items: Some(items.into()), + max_items: Some($len), + min_items: Some($len), + ..Default::default() + }, ..Default::default() }.into()) } @@ -64,14 +64,14 @@ mod tests { schema.instance_type, Some(SingleOrVec::from(InstanceType::Array)) ); - assert_eq!(schema.extensions.get("minItems"), Some(&json!(2))); - assert_eq!(schema.extensions.get("maxItems"), Some(&json!(2))); assert_eq!( - schema.items, + schema.array.items, Some(SingleOrVec::Vec(vec![ schema_for::(), schema_for::() ])) ); + assert_eq!(schema.array.max_items, Some(2)); + assert_eq!(schema.array.min_items, Some(2)); } } diff --git a/schemars/src/schema.rs b/schemars/src/schema.rs index 1cc637c..f6a78a2 100644 --- a/schemars/src/schema.rs +++ b/schemars/src/schema.rs @@ -43,9 +43,6 @@ impl Schema { id: s1.id.or(s2.id), title: s1.title.or(s2.title), description: s1.description.or(s2.description), - items: s1.items.or(s2.items), - properties: extend(s1.properties, s2.properties), - required: extend(s1.required, s2.required), definitions: extend(s1.definitions, s2.definitions), extensions: extend(s1.extensions, s2.extensions), // TODO do the following make sense? @@ -56,6 +53,38 @@ impl Schema { any_of: s1.any_of.or(s2.any_of), one_of: s1.one_of.or(s2.one_of), not: s1.not.or(s2.not), + if_schema: s1.if_schema.or(s2.if_schema), + then_schema: s1.then_schema.or(s2.then_schema), + else_schema: s1.else_schema.or(s2.else_schema), + number: NumberValidation { + multiple_of: s1.number.multiple_of.or(s2.number.multiple_of), + maximum: s1.number.maximum.or(s2.number.maximum), + exclusive_maximum: s1.number.exclusive_maximum.or(s2.number.exclusive_maximum), + minimum: s1.number.minimum.or(s2.number.minimum), + exclusive_minimum: s1.number.exclusive_minimum.or(s2.number.exclusive_minimum), + }, + string: StringValidation { + max_length: s1.string.max_length.or(s2.string.max_length), + min_length: s1.string.min_length.or(s2.string.min_length), + pattern: s1.string.pattern.or(s2.string.pattern), + }, + array: ArrayValidation { + items: s1.array.items.or(s2.array.items), + additional_items: s1.array.additional_items.or(s2.array.additional_items), + max_items: s1.array.max_items.or(s2.array.max_items), + min_items: s1.array.min_items.or(s2.array.min_items), + unique_items: s1.array.unique_items.or(s2.array.unique_items), + contains: s1.array.contains.or(s2.array.contains), + }, + object: ObjectValidation { + max_properties: s1.object.max_properties.or(s2.object.max_properties), + min_properties: s1.object.min_properties.or(s2.object.min_properties), + required: extend(s1.object.required, s2.object.required), + properties: extend(s1.object.properties, s2.object.properties), + pattern_properties: extend(s1.object.pattern_properties, s2.object.pattern_properties), + additional_properties: s1.object.additional_properties.or(s2.object.additional_properties), + property_names: s1.object.property_names.or(s2.object.property_names), + }, })) } @@ -111,12 +140,6 @@ pub struct SchemaObject { #[serde(rename = "enum", skip_serializing_if = "Option::is_none")] pub enum_values: Option>, #[serde(skip_serializing_if = "Option::is_none")] - pub items: Option>, - #[serde(skip_serializing_if = "Map::is_empty")] - pub properties: Map, - #[serde(skip_serializing_if = "Set::is_empty")] - pub required: Set, - #[serde(skip_serializing_if = "Option::is_none")] pub all_of: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub any_of: Option>, @@ -124,12 +147,88 @@ pub struct SchemaObject { pub one_of: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub not: Option>, + #[serde(rename = "if", skip_serializing_if = "Option::is_none")] + pub if_schema: Option>, + #[serde(rename = "then", skip_serializing_if = "Option::is_none")] + pub then_schema: Option>, + #[serde(rename = "else", skip_serializing_if = "Option::is_none")] + pub else_schema: Option>, #[serde(skip_serializing_if = "Map::is_empty")] pub definitions: Map, #[serde(flatten)] + pub number: NumberValidation, + #[serde(flatten)] + pub string: StringValidation, + #[serde(flatten)] + pub array: ArrayValidation, + #[serde(flatten)] + pub object: ObjectValidation, + #[serde(flatten)] pub extensions: Map, } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)] +#[serde(rename_all = "camelCase", default)] +pub struct NumberValidation { + #[serde(skip_serializing_if = "Option::is_none")] + pub multiple_of: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub maximum: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub exclusive_maximum: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub minimum: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub exclusive_minimum: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)] +#[serde(rename_all = "camelCase", default)] +pub struct StringValidation { + #[serde(skip_serializing_if = "Option::is_none")] + pub max_length: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub min_length: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub pattern: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)] +#[serde(rename_all = "camelCase", default)] +pub struct ArrayValidation { + #[serde(skip_serializing_if = "Option::is_none")] + pub items: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_items: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_items: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub min_items: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub unique_items: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub contains: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)] +#[serde(rename_all = "camelCase", default)] +pub struct ObjectValidation { + #[serde(skip_serializing_if = "Option::is_none")] + pub max_properties: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub min_properties: Option, + #[serde(skip_serializing_if = "Set::is_empty")] + pub required: Set, + #[serde(skip_serializing_if = "Map::is_empty")] + pub properties: Map, + #[serde(skip_serializing_if = "Map::is_empty")] + pub pattern_properties: Map, + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_properties: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub property_names: Option>, +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema)] #[serde(rename_all = "camelCase")] pub enum InstanceType { diff --git a/schemars/tests/expected/schema-openapi3.json b/schemars/tests/expected/schema-openapi3.json index 77aaaa3..82f5f04 100644 --- a/schemars/tests/expected/schema-openapi3.json +++ b/schemars/tests/expected/schema-openapi3.json @@ -26,14 +26,14 @@ }, "Ref": { "type": "object", + "required": [ + "$ref" + ], "properties": { "$ref": { "type": "string" } - }, - "required": [ - "$ref" - ] + } }, "Schema": { "anyOf": [ @@ -59,6 +59,34 @@ "type": "string", "nullable": true }, + "additionalItems": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, + "additionalProperties": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, "allOf": { "type": "array", "items": { @@ -73,6 +101,20 @@ }, "nullable": true }, + "contains": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, "definitions": { "type": "object", "additionalProperties": { @@ -83,15 +125,53 @@ "type": "string", "nullable": true }, + "else": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, "enum": { "type": "array", "items": {}, "nullable": true }, + "exclusiveMaximum": { + "type": "number", + "format": "double", + "nullable": true + }, + "exclusiveMinimum": { + "type": "number", + "format": "double", + "nullable": true + }, "format": { "type": "string", "nullable": true }, + "if": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, "items": { "anyOf": [ { @@ -106,6 +186,51 @@ ], "nullable": true }, + "maxItems": { + "type": "integer", + "format": "uint32", + "nullable": true + }, + "maxLength": { + "type": "integer", + "format": "uint32", + "nullable": true + }, + "maxProperties": { + "type": "integer", + "format": "uint32", + "nullable": true + }, + "maximum": { + "type": "number", + "format": "double", + "nullable": true + }, + "minItems": { + "type": "integer", + "format": "uint32", + "nullable": true + }, + "minLength": { + "type": "integer", + "format": "uint32", + "nullable": true + }, + "minProperties": { + "type": "integer", + "format": "uint32", + "nullable": true + }, + "minimum": { + "type": "number", + "format": "double", + "nullable": true + }, + "multipleOf": { + "type": "number", + "format": "double", + "nullable": true + }, "not": { "anyOf": [ { @@ -127,18 +252,56 @@ }, "nullable": true }, + "pattern": { + "type": "string", + "nullable": true + }, + "patternProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Schema" + } + }, "properties": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Schema" } }, + "propertyNames": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, "required": { "type": "array", "items": { "type": "string" } }, + "then": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/Ref" + }, + { + "$ref": "#/components/schemas/SchemaObject" + } + ], + "nullable": true + }, "title": { "type": "string", "nullable": true @@ -156,6 +319,10 @@ } ], "nullable": true + }, + "uniqueItems": { + "type": "boolean", + "nullable": true } }, "additionalProperties": true diff --git a/schemars/tests/expected/schema.json b/schemars/tests/expected/schema.json index 8bce3f4..10eaf9f 100644 --- a/schemars/tests/expected/schema.json +++ b/schemars/tests/expected/schema.json @@ -26,14 +26,14 @@ }, "Ref": { "type": "object", + "required": [ + "$ref" + ], "properties": { "$ref": { "type": "string" } - }, - "required": [ - "$ref" - ] + } }, "Schema": { "anyOf": [ @@ -71,6 +71,26 @@ } ] }, + "additionalItems": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, "allOf": { "anyOf": [ { @@ -97,6 +117,16 @@ } ] }, + "contains": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, "definitions": { "type": "object", "additionalProperties": { @@ -113,6 +143,16 @@ } ] }, + "else": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, "enum": { "anyOf": [ { @@ -124,6 +164,28 @@ } ] }, + "exclusiveMaximum": { + "anyOf": [ + { + "type": "number", + "format": "double" + }, + { + "type": "null" + } + ] + }, + "exclusiveMinimum": { + "anyOf": [ + { + "type": "number", + "format": "double" + }, + { + "type": "null" + } + ] + }, "format": { "anyOf": [ { @@ -134,6 +196,16 @@ } ] }, + "if": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, "items": { "anyOf": [ { @@ -144,6 +216,105 @@ } ] }, + "maxItems": { + "anyOf": [ + { + "type": "integer", + "format": "uint32" + }, + { + "type": "null" + } + ] + }, + "maxLength": { + "anyOf": [ + { + "type": "integer", + "format": "uint32" + }, + { + "type": "null" + } + ] + }, + "maxProperties": { + "anyOf": [ + { + "type": "integer", + "format": "uint32" + }, + { + "type": "null" + } + ] + }, + "maximum": { + "anyOf": [ + { + "type": "number", + "format": "double" + }, + { + "type": "null" + } + ] + }, + "minItems": { + "anyOf": [ + { + "type": "integer", + "format": "uint32" + }, + { + "type": "null" + } + ] + }, + "minLength": { + "anyOf": [ + { + "type": "integer", + "format": "uint32" + }, + { + "type": "null" + } + ] + }, + "minProperties": { + "anyOf": [ + { + "type": "integer", + "format": "uint32" + }, + { + "type": "null" + } + ] + }, + "minimum": { + "anyOf": [ + { + "type": "number", + "format": "double" + }, + { + "type": "null" + } + ] + }, + "multipleOf": { + "anyOf": [ + { + "type": "number", + "format": "double" + }, + { + "type": "null" + } + ] + }, "not": { "anyOf": [ { @@ -167,18 +338,54 @@ } ] }, + "pattern": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "patternProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Schema" + } + }, "properties": { "type": "object", "additionalProperties": { "$ref": "#/definitions/Schema" } }, + "propertyNames": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, "required": { "type": "array", "items": { "type": "string" } }, + "then": { + "anyOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "type": "null" + } + ] + }, "title": { "anyOf": [ { @@ -198,6 +405,16 @@ "type": "null" } ] + }, + "uniqueItems": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ] } }, "additionalProperties": true diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 7ef1e26..f5875da 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -142,15 +142,18 @@ fn schema_for_external_tagged_enum<'a>( let sub_schema = schema_for_untagged_enum_variant(variant, cattrs); wrap_schema_fields(quote! { instance_type: Some(schemars::schema::InstanceType::Object.into()), - properties: { - let mut props = schemars::Map::new(); - props.insert(#name.to_owned(), #sub_schema); - props - }, - required: { - let mut required = schemars::Set::new(); - required.insert(#name.to_owned()); - required + object: schemars::schema::ObjectValidation { + properties: { + let mut props = schemars::Map::new(); + props.insert(#name.to_owned(), #sub_schema); + props + }, + required: { + let mut required = schemars::Set::new(); + required.insert(#name.to_owned()); + required + }, + ..Default::default() }, }) })); @@ -173,15 +176,18 @@ fn schema_for_internal_tagged_enum<'a>( }); let schema = wrap_schema_fields(quote! { instance_type: Some(schemars::schema::InstanceType::Object.into()), - properties: { - let mut props = schemars::Map::new(); - props.insert(#tag_name.to_owned(), #type_schema); - props - }, - required: { - let mut required = schemars::Set::new(); - required.insert(#tag_name.to_owned()); - required + object: schemars::schema::ObjectValidation { + properties: { + let mut props = schemars::Map::new(); + props.insert(#tag_name.to_owned(), #type_schema); + props + }, + required: { + let mut required = schemars::Set::new(); + required.insert(#tag_name.to_owned()); + required + }, + ..Default::default() }, }); if is_unit_variant(&variant) { @@ -262,15 +268,18 @@ fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream let schema = wrap_schema_fields(quote! { instance_type: Some(schemars::schema::InstanceType::Object.into()), - properties: { - let mut props = schemars::Map::new(); - #(#recurse)* - props - }, - required: { - let mut required = schemars::Set::new(); - #(required.insert(#required.to_owned());)* - required + object: schemars::schema::ObjectValidation { + properties: { + let mut props = schemars::Map::new(); + #(#recurse)* + props + }, + required: { + let mut required = schemars::Set::new(); + #(required.insert(#required.to_owned());)* + required + }, + ..Default::default() }, }); @@ -300,10 +309,10 @@ fn get_json_schema_type(field: &Field) -> Box { let se_with_segments = without_last_element(field.attrs.serialize_with(), "serialize"); if de_with_segments == se_with_segments { if let Some(expr_path) = de_with_segments { - return Box::from(expr_path); + return Box::new(expr_path); } } - Box::from(field.ty.clone()) + Box::new(field.ty.clone()) } fn without_last_element(path: Option<&syn::ExprPath>, last: &str) -> Option {