diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index 31871e88f4..906406679d 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -359,9 +359,16 @@ pub struct BrpJsonSchemaQueryFilter { #[serde(skip_serializing_if = "Vec::is_empty", default)] pub with_crates: Vec, - /// Constrain resource by type + /// Constrain resource by data type. + /// Mapping of data types to their corresponding JSON schema types + /// is provided by the [`crate::schemas::SchemaTypesMetadata`] resource. #[serde(default)] pub type_limit: JsonSchemaTypeLimit, + + /// Add `one_of` field to the root of the schema. + /// It will allow to use the schema for validation values if they match the format used by the Bevy reflect serialization. + #[serde(default)] + pub meta_schemas_export: bool, } impl BrpJsonSchemaQueryFilter { @@ -402,12 +409,12 @@ impl JsonSchemaTypeLimit { } /// Check if the type limit should skip a type. - pub fn should_skip_type(&self, registered_types: &[Cow<'_, str>]) -> bool { + pub fn should_skip_type(&self, registered_types: &[&Cow<'_, str>]) -> bool { if !self.with.is_empty() && !self .with .iter() - .any(|c| registered_types.iter().any(|cc| c.eq(cc))) + .any(|c| registered_types.iter().any(|cc| c.eq(*cc))) { return true; } @@ -415,7 +422,7 @@ impl JsonSchemaTypeLimit { && self .without .iter() - .any(|c| registered_types.iter().any(|cc| c.eq(cc))) + .any(|c| registered_types.iter().any(|cc| c.eq(*cc))) { return true; } @@ -1411,15 +1418,15 @@ fn export_registry_types_typed( if filter.should_skip_for_crate(type_reg) { return None; } - if !filter.type_limit.is_empty() { - let registered_types = metadata.get_registered_reflect_types(type_reg); - if filter - .type_limit - .should_skip_type(registered_types.as_slice()) - { - return None; - } + let registered_types = metadata.get_registered_reflect_types(type_reg); + + if filter + .type_limit + .should_skip_type(registered_types.as_slice()) + { + return None; } + let type_id = type_reg.type_id(); let mut dep_ids = types.get_type_dependencies(type_id); dep_ids.insert(type_id); @@ -1437,35 +1444,37 @@ fn export_registry_types_typed( Some((schema_id, Box::new(schema))) }) .collect(); - schema.one_of = schema - .definitions - .iter() - .flat_map(|(id, schema)| { - if !schema.reflect_type_data.contains(&"Serialize".into()) - || !schema.reflect_type_data.contains(&"Deserialize".into()) - { - return None; - } - let schema = JsonSchemaBevyType { - properties: [( - schema.type_path.clone(), - JsonSchemaBevyType { - ref_type: Some(TypeReferencePath::definition(id.clone())), - description: schema.description.clone(), - ..Default::default() - } + if filter.meta_schemas_export { + schema.one_of = schema + .definitions + .iter() + .flat_map(|(id, schema)| { + if !schema.reflect_type_data.contains(&"Serialize".into()) + || !schema.reflect_type_data.contains(&"Deserialize".into()) + { + return None; + } + let schema = JsonSchemaBevyType { + properties: [( + schema.type_path.clone(), + JsonSchemaBevyType { + ref_type: Some(TypeReferencePath::definition((*id).clone())), + description: schema.description.clone(), + ..Default::default() + } + .into(), + )] .into(), - )] - .into(), - schema_type: Some(crate::schemas::json_schema::SchemaType::Object.into()), - additional_properties: Some(JsonSchemaVariant::BoolValue(false)), - description: schema.description.clone(), - reflect_type_data: schema.reflect_type_data.clone(), - ..Default::default() - }; - Some(schema.into()) - }) - .collect(); + schema_type: Some(crate::schemas::json_schema::SchemaType::Object.into()), + additional_properties: Some(JsonSchemaVariant::BoolValue(false)), + description: schema.description.clone(), + reflect_type_data: schema.reflect_type_data.clone(), + ..Default::default() + }; + Some(schema.into()) + }) + .collect(); + } Ok(schema) } @@ -1828,7 +1837,7 @@ mod tests { #[cfg(feature = "bevy_math")] fn export_schema_test() { #[derive(Reflect, Default, Deserialize, Serialize, Component)] - #[reflect(Component)] + #[reflect(Component, Serialize, Deserialize)] pub struct OtherStruct { /// FIELD DOC pub field: String, @@ -1836,18 +1845,18 @@ mod tests { } /// STRUCT DOC #[derive(Reflect, Default, Deserialize, Serialize, Component)] - #[reflect(Component)] + #[reflect(Component, Serialize, Deserialize)] pub struct SecondStruct; /// STRUCT DOC #[derive(Reflect, Default, Deserialize, Serialize, Component)] - #[reflect(Component)] + #[reflect(Component, Serialize, Deserialize)] pub struct ThirdStruct { pub array_strings: Vec, pub array_structs: [OtherStruct; 5], // pub map_strings: HashMap, } #[derive(Reflect, Default, Deserialize, Serialize, Component)] - #[reflect(Component)] + #[reflect(Component, Serialize, Deserialize)] pub struct NestedStruct { pub other: OtherStruct, pub second: SecondStruct, diff --git a/crates/bevy_remote/src/schemas/mod.rs b/crates/bevy_remote/src/schemas/mod.rs index f7b9bdba76..ce07ce932b 100644 --- a/crates/bevy_remote/src/schemas/mod.rs +++ b/crates/bevy_remote/src/schemas/mod.rs @@ -173,10 +173,10 @@ impl SchemaTypesMetadata { } /// Build reflect types list for a given type registration - pub fn get_registered_reflect_types(&self, reg: &TypeRegistration) -> Vec> { + pub fn get_registered_reflect_types(&self, reg: &TypeRegistration) -> Vec<&Cow<'static, str>> { self.type_data_map .iter() - .filter_map(|(id, name)| reg.data_by_id(*id).and(Some(name.clone()))) + .filter_map(|(id, name)| reg.data_by_id(*id).and(Some(name))) .collect() } diff --git a/crates/bevy_remote/src/schemas/reflect_info.rs b/crates/bevy_remote/src/schemas/reflect_info.rs index 23e695bfc1..6b3eedd7bb 100644 --- a/crates/bevy_remote/src/schemas/reflect_info.rs +++ b/crates/bevy_remote/src/schemas/reflect_info.rs @@ -1367,7 +1367,11 @@ impl TypeDefinitionBuilder for TypeRegistry { .map(|docs| docs.trim().replace("\n", "").into()); #[cfg(not(feature = "documentation"))] let description = None; - + let reflect_type_data = metadata + .get_registered_reflect_types(type_reg) + .iter() + .map(|c| Cow::Owned(c.to_string())) + .collect(); let mut schema = JsonSchemaBevyType { description, type_path, @@ -1380,7 +1384,7 @@ impl TypeDefinitionBuilder for TypeRegistry { exclusive_minimum: range.min.get_exclusive(), exclusive_maximum: range.max.get_exclusive(), schema_type: (&internal).into(), - reflect_type_data: metadata.get_registered_reflect_types(type_reg), + reflect_type_data, ..default() }; schema.schema_type = (&internal).into();