Missing definitions handling
This commit is contained in:
parent
23ca435e73
commit
0ff3201c3c
@ -3,8 +3,7 @@
|
||||
use alloc::borrow::Cow;
|
||||
use bevy_platform::collections::HashMap;
|
||||
use bevy_reflect::{
|
||||
prelude::ReflectDefault, serde::ReflectSerializer, GetTypeRegistration, Reflect,
|
||||
TypeRegistration, TypeRegistry,
|
||||
prelude::ReflectDefault, serde::ReflectSerializer, GetTypeRegistration, Reflect, TypeRegistry,
|
||||
};
|
||||
use core::any::TypeId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -44,7 +43,26 @@ impl TypeRegistrySchemaReader for TypeRegistry {
|
||||
extra_info: &SchemaTypesMetadata,
|
||||
) -> Option<JsonSchemaBevyType> {
|
||||
let type_reg = self.get(type_id)?;
|
||||
let mut schema: JsonSchemaBevyType = (type_reg, extra_info).try_into().ok()?;
|
||||
|
||||
let mut definition = TypeInformation::from(type_reg)
|
||||
.to_schema_type_info_with_metadata(extra_info)
|
||||
.to_definition();
|
||||
for missing in &definition.missing_definitions {
|
||||
let reg_option = self.get(*missing);
|
||||
if let Some(reg) = reg_option {
|
||||
let missing_schema =
|
||||
TypeInformation::from(reg).to_schema_type_info_with_metadata(extra_info);
|
||||
let mis_def = missing_schema.to_definition();
|
||||
definition.definitions.extend(mis_def.definitions);
|
||||
if let Some(missing_id) = mis_def.id {
|
||||
if !definition.definitions.contains_key(&missing_id) {
|
||||
definition.definitions.insert(missing_id, missing_schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut schema: JsonSchemaBevyType = definition.into();
|
||||
schema.reflect_type_data = extra_info.get_registered_reflect_types(type_reg);
|
||||
schema.schema = Some(SchemaMarker.into());
|
||||
schema.default_value = self.try_get_default_value_for_type_id(type_id);
|
||||
|
||||
@ -69,38 +87,6 @@ impl TypeRegistrySchemaReader for TypeRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type for invalid JSON Schema conversions.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum InvalidJsonSchema {
|
||||
/// The type cannot be converted to a valid JSON Schema.
|
||||
InvalidType,
|
||||
}
|
||||
|
||||
impl TryFrom<(&TypeRegistration, &SchemaTypesMetadata)> for JsonSchemaBevyType {
|
||||
type Error = InvalidJsonSchema;
|
||||
|
||||
fn try_from(value: (&TypeRegistration, &SchemaTypesMetadata)) -> Result<Self, Self::Error> {
|
||||
let (reg, metadata) = value;
|
||||
// if let Some(s) = reg.data::<ReflectJsonSchema>() {
|
||||
// return Ok(s.0.clone());
|
||||
// }
|
||||
let mut schema: JsonSchemaBevyType = TypeInformation::from(reg)
|
||||
.to_schema_type_info_with_metadata(metadata)
|
||||
.to_definition()
|
||||
.into();
|
||||
schema.reflect_type_data = metadata.get_registered_reflect_types(reg);
|
||||
Ok(schema)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&TypeRegistration> for JsonSchemaBevyType {
|
||||
type Error = InvalidJsonSchema;
|
||||
|
||||
fn try_from(value: &TypeRegistration) -> Result<Self, Self::Error> {
|
||||
(value, &SchemaTypesMetadata::default()).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifies the JSON Schema version used in the schema.
|
||||
#[derive(Deserialize, Serialize, Debug, Reflect, PartialEq, Clone)]
|
||||
pub struct SchemaMarker;
|
||||
|
@ -1071,6 +1071,9 @@ pub struct SchemaDefinition {
|
||||
pub schema: JsonSchemaBevyType,
|
||||
/// The properties of the schema.
|
||||
pub definitions: HashMap<TypeReferenceId, SchemaTypeInfo>,
|
||||
/// Missing definitions of the schema.
|
||||
/// Could be the case for the types that are stored as generic arguments.
|
||||
pub missing_definitions: Vec<TypeId>,
|
||||
}
|
||||
|
||||
impl From<SchemaDefinition> for JsonSchemaBevyType {
|
||||
@ -1237,11 +1240,13 @@ impl SchemaTypeInfo {
|
||||
pub fn to_definition(&self) -> SchemaDefinition {
|
||||
let mut id: Option<TypeReferenceId> = self.ty_info.try_get_type_reference_id();
|
||||
let mut definitions: HashMap<TypeReferenceId, SchemaTypeInfo> = HashMap::new();
|
||||
let mut missing_definitions: Vec<TypeId> = Vec::new();
|
||||
if let Some(custom_schema) = &self.ty_info.try_get_custom_schema() {
|
||||
return SchemaDefinition {
|
||||
id,
|
||||
schema: custom_schema.0.clone(),
|
||||
definitions,
|
||||
missing_definitions,
|
||||
};
|
||||
}
|
||||
let range = self.get_range();
|
||||
@ -1298,7 +1303,9 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema: _,
|
||||
definitions: field_definitions,
|
||||
missing_definitions: key_missing_definitions,
|
||||
} = key.to_definition();
|
||||
missing_definitions.extend(key_missing_definitions);
|
||||
if let Some(id) = id {
|
||||
definitions.insert(id, key.clone());
|
||||
definitions.extend(field_definitions);
|
||||
@ -1310,7 +1317,10 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema: _,
|
||||
definitions: field_definitions,
|
||||
missing_definitions: value_missing_definitions,
|
||||
} = value.to_definition();
|
||||
|
||||
missing_definitions.extend(value_missing_definitions);
|
||||
if let Some(id) = id {
|
||||
definitions.insert(id, value.clone());
|
||||
definitions.extend(field_definitions);
|
||||
@ -1405,6 +1415,7 @@ impl SchemaTypeInfo {
|
||||
..Default::default()
|
||||
},
|
||||
definitions: HashMap::new(),
|
||||
missing_definitions,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1430,7 +1441,9 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema: _,
|
||||
definitions: field_definitions,
|
||||
missing_definitions: field_missing_definitions,
|
||||
} = field_schema.to_definition();
|
||||
missing_definitions.extend(field_missing_definitions);
|
||||
definitions.extend(field_definitions);
|
||||
let Some(id) = id else { continue };
|
||||
if !definitions.contains_key(&id) {
|
||||
@ -1450,7 +1463,9 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema: new_schema_type,
|
||||
definitions: field_definitions,
|
||||
missing_definitions: field_missing_definitions,
|
||||
} = field_schema.to_definition();
|
||||
missing_definitions.extend(field_missing_definitions);
|
||||
definitions.extend(field_definitions);
|
||||
if let Some(id) = id {
|
||||
definitions.insert(id.clone(), field_schema);
|
||||
@ -1519,8 +1534,10 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema: _,
|
||||
definitions: field_definitions,
|
||||
missing_definitions: field_missing_definitions,
|
||||
} = field_schema.to_definition();
|
||||
definitions.extend(field_definitions);
|
||||
missing_definitions.extend(field_missing_definitions);
|
||||
let Some(id) = id else { continue };
|
||||
if !definitions.contains_key(&id) {
|
||||
definitions.insert(id, field_schema);
|
||||
@ -1546,7 +1563,9 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema: _,
|
||||
definitions: field_definitions,
|
||||
missing_definitions: field_missing_definitions,
|
||||
} = items_schema.to_definition();
|
||||
missing_definitions.extend(field_missing_definitions);
|
||||
definitions.extend(field_definitions);
|
||||
if let Some(id) = id {
|
||||
definitions.insert(id, items_schema);
|
||||
@ -1561,7 +1580,8 @@ impl SchemaTypeInfo {
|
||||
ty_info: TypeInformation::Type(Box::new(*generic.ty())),
|
||||
..(**schema_type_info).clone()
|
||||
};
|
||||
let definition = schema_optional.to_definition();
|
||||
missing_definitions.push(generic.type_id());
|
||||
let definition = schema_optional.clone().to_definition();
|
||||
definitions.extend(definition.definitions);
|
||||
schema.ref_type = None;
|
||||
schema.schema_type = None;
|
||||
@ -1570,7 +1590,7 @@ impl SchemaTypeInfo {
|
||||
schema_type: Some(SchemaTypeVariant::Single(SchemaType::Null)),
|
||||
..Default::default()
|
||||
}),
|
||||
Box::new(definition.schema),
|
||||
Box::new(schema_optional.to_ref_schema()),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1578,6 +1598,7 @@ impl SchemaTypeInfo {
|
||||
id,
|
||||
schema,
|
||||
definitions,
|
||||
missing_definitions,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1813,10 +1834,12 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
pub(super) mod tests {
|
||||
use bevy_ecs::{component::Component, name::Name};
|
||||
use bevy_ecs::{component::Component, name::Name, reflect::AppTypeRegistry};
|
||||
use bevy_platform::collections::HashMap;
|
||||
use bevy_reflect::GetTypeRegistration;
|
||||
|
||||
use crate::schemas::json_schema::TypeRegistrySchemaReader;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Validate a JSON schema against a set of valid and invalid instances.
|
||||
@ -1962,7 +1985,7 @@ pub(super) mod tests {
|
||||
serde_json::json!({"a": 5555,"b": 5555}),
|
||||
],
|
||||
);
|
||||
let atr = bevy_ecs::reflect::AppTypeRegistry::default();
|
||||
let atr = AppTypeRegistry::default();
|
||||
{
|
||||
let mut register = atr.write();
|
||||
register.register::<bevy_math::Vec3>();
|
||||
@ -2078,6 +2101,33 @@ pub(super) mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn optional_tests() {
|
||||
#[derive(Reflect, Default, Deserialize, Serialize)]
|
||||
pub struct ArrayComponent {
|
||||
pub array: [u8; 3],
|
||||
}
|
||||
let atr = AppTypeRegistry::default();
|
||||
{
|
||||
let mut register = atr.write();
|
||||
register.register::<ArrayComponent>();
|
||||
register.register::<Option<ArrayComponent>>();
|
||||
}
|
||||
let type_registry = atr.read();
|
||||
let schema = type_registry
|
||||
.export_type_json_schema::<Option<ArrayComponent>>(&Default::default())
|
||||
.expect("Failed to export type JSON schema");
|
||||
validate::<Option<ArrayComponent>>(
|
||||
schema,
|
||||
&[None, Some(ArrayComponent { array: [5, 1, 9] })],
|
||||
&[
|
||||
serde_json::json!({"array": [1, 2, 3]}),
|
||||
serde_json::Value::Null,
|
||||
],
|
||||
&[serde_json::json!({"array": [1999, 2, 3]})],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reflect_struct_with_array() {
|
||||
#[derive(Reflect, Default, Deserialize, Serialize)]
|
||||
|
Loading…
Reference in New Issue
Block a user