Default values for schemas
This commit is contained in:
parent
2b20e8dae8
commit
8e4809f123
@ -25,7 +25,7 @@ use serde_json::{Map, Value};
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_codes,
|
error_codes,
|
||||||
schemas::{
|
schemas::{
|
||||||
json_schema::{export_type, JsonSchemaBevyType},
|
json_schema::{JsonSchemaBevyType, TypeRegistrySchemaReader},
|
||||||
open_rpc::OpenRpcDocument,
|
open_rpc::OpenRpcDocument,
|
||||||
},
|
},
|
||||||
BrpError, BrpResult,
|
BrpError, BrpResult,
|
||||||
@ -1245,7 +1245,8 @@ pub fn export_registry_types(In(params): In<Option<Value>>, world: &World) -> Br
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (id, schema) = export_type(type_reg, extra_info);
|
let id = type_reg.type_id();
|
||||||
|
let schema = types.export_type_json_schema_for_id(id, extra_info)?;
|
||||||
|
|
||||||
if !filter.type_limit.with.is_empty()
|
if !filter.type_limit.with.is_empty()
|
||||||
&& !filter
|
&& !filter
|
||||||
@ -1265,7 +1266,7 @@ pub fn export_registry_types(In(params): In<Option<Value>>, world: &World) -> Br
|
|||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some((id.to_string(), schema))
|
Some((type_reg.type_info().type_path().into(), schema))
|
||||||
})
|
})
|
||||||
.collect::<HashMap<String, JsonSchemaBevyType>>();
|
.collect::<HashMap<String, JsonSchemaBevyType>>();
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
//! Module with JSON Schema type for Bevy Registry Types.
|
//! Module with JSON Schema type for Bevy Registry Types.
|
||||||
//! It tries to follow this standard: <https://json-schema.org/specification>
|
//! It tries to follow this standard: <https://json-schema.org/specification>
|
||||||
use alloc::borrow::Cow;
|
|
||||||
use bevy_platform::collections::HashMap;
|
use bevy_platform::collections::HashMap;
|
||||||
use bevy_reflect::{GetTypeRegistration, Reflect, TypeRegistration, TypeRegistry};
|
use bevy_reflect::{
|
||||||
|
prelude::ReflectDefault, serde::ReflectSerializer, GetTypeRegistration, Reflect,
|
||||||
|
TypeRegistration, TypeRegistry,
|
||||||
|
};
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@ -19,33 +21,48 @@ pub trait TypeRegistrySchemaReader {
|
|||||||
&self,
|
&self,
|
||||||
extra_info: &SchemaTypesMetadata,
|
extra_info: &SchemaTypesMetadata,
|
||||||
) -> Option<JsonSchemaBevyType> {
|
) -> Option<JsonSchemaBevyType> {
|
||||||
self.export_type_json_schema_for_id(extra_info, TypeId::of::<T>())
|
self.export_type_json_schema_for_id(TypeId::of::<T>(), extra_info)
|
||||||
}
|
}
|
||||||
/// Export type JSON Schema.
|
/// Export type JSON Schema.
|
||||||
fn export_type_json_schema_for_id(
|
fn export_type_json_schema_for_id(
|
||||||
&self,
|
&self,
|
||||||
extra_info: &SchemaTypesMetadata,
|
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
|
extra_info: &SchemaTypesMetadata,
|
||||||
) -> Option<JsonSchemaBevyType>;
|
) -> Option<JsonSchemaBevyType>;
|
||||||
|
|
||||||
|
/// Try to get default value for type id.
|
||||||
|
fn try_get_default_value_for_type_id(&self, type_id: TypeId) -> Option<Value>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRegistrySchemaReader for TypeRegistry {
|
impl TypeRegistrySchemaReader for TypeRegistry {
|
||||||
fn export_type_json_schema_for_id(
|
fn export_type_json_schema_for_id(
|
||||||
&self,
|
&self,
|
||||||
extra_info: &SchemaTypesMetadata,
|
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
|
extra_info: &SchemaTypesMetadata,
|
||||||
) -> Option<JsonSchemaBevyType> {
|
) -> Option<JsonSchemaBevyType> {
|
||||||
let type_reg = self.get(type_id)?;
|
let type_reg = self.get(type_id)?;
|
||||||
Some((type_reg, extra_info).into())
|
let mut schema: JsonSchemaBevyType = (type_reg, extra_info).into();
|
||||||
}
|
schema.default_value = self.try_get_default_value_for_type_id(type_id);
|
||||||
}
|
|
||||||
|
|
||||||
/// Exports schema info for a given type
|
Some(schema)
|
||||||
pub fn export_type(
|
}
|
||||||
reg: &TypeRegistration,
|
|
||||||
metadata: &SchemaTypesMetadata,
|
fn try_get_default_value_for_type_id(&self, type_id: TypeId) -> Option<Value> {
|
||||||
) -> (Cow<'static, str>, JsonSchemaBevyType) {
|
let type_reg = self.get(type_id)?;
|
||||||
(reg.type_info().type_path().into(), (reg, metadata).into())
|
let default_data = type_reg.data::<ReflectDefault>()?;
|
||||||
|
let default = default_data.default();
|
||||||
|
let serializer = ReflectSerializer::new(&*default, self);
|
||||||
|
let value_object = serde_json::to_value(serializer)
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| v.as_object().cloned())?;
|
||||||
|
if value_object.len() == 1 {
|
||||||
|
if let Some((_, value)) = value_object.into_iter().next() {
|
||||||
|
return Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(&TypeRegistration, &SchemaTypesMetadata)> for JsonSchemaBevyType {
|
impl From<(&TypeRegistration, &SchemaTypesMetadata)> for JsonSchemaBevyType {
|
||||||
@ -58,7 +75,6 @@ impl From<(&TypeRegistration, &SchemaTypesMetadata)> for JsonSchemaBevyType {
|
|||||||
return JsonSchemaBevyType::default();
|
return JsonSchemaBevyType::default();
|
||||||
};
|
};
|
||||||
typed_schema.reflect_types = metadata.get_registered_reflect_types(reg);
|
typed_schema.reflect_types = metadata.get_registered_reflect_types(reg);
|
||||||
|
|
||||||
*typed_schema
|
*typed_schema
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,6 +191,9 @@ pub struct JsonSchemaBevyType {
|
|||||||
/// Type description
|
/// Type description
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
/// Default value for the schema.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default, rename = "default")]
|
||||||
|
pub default_value: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents different types of JSON Schema values that can be used in schema definitions.
|
/// Represents different types of JSON Schema values that can be used in schema definitions.
|
||||||
@ -361,6 +380,21 @@ mod tests {
|
|||||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
fn export_type<T: GetTypeRegistration + 'static>() -> JsonSchemaBevyType {
|
||||||
|
let atr = AppTypeRegistry::default();
|
||||||
|
{
|
||||||
|
let mut register = atr.write();
|
||||||
|
register.register::<T>();
|
||||||
|
}
|
||||||
|
let type_registry = atr.read();
|
||||||
|
let Some(schema) =
|
||||||
|
type_registry.export_type_json_schema::<T>(&SchemaTypesMetadata::default())
|
||||||
|
else {
|
||||||
|
panic!("Failed to export JSON schema for Foo");
|
||||||
|
};
|
||||||
|
schema
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reflect_export_struct() {
|
fn reflect_export_struct() {
|
||||||
#[derive(Reflect, Resource, Default, Deserialize, Serialize)]
|
#[derive(Reflect, Resource, Default, Deserialize, Serialize)]
|
||||||
@ -370,26 +404,7 @@ mod tests {
|
|||||||
#[reflect(@10..=15i16)]
|
#[reflect(@10..=15i16)]
|
||||||
b: Option<i16>,
|
b: Option<i16>,
|
||||||
}
|
}
|
||||||
|
let schema = export_type::<Foo>();
|
||||||
let atr = AppTypeRegistry::default();
|
|
||||||
{
|
|
||||||
let mut register = atr.write();
|
|
||||||
register.register::<Foo>();
|
|
||||||
}
|
|
||||||
let type_registry = atr.read();
|
|
||||||
let foo_registration = type_registry
|
|
||||||
.get(TypeId::of::<Foo>())
|
|
||||||
.expect("SHOULD BE REGISTERED")
|
|
||||||
.clone();
|
|
||||||
// for field in foo_registration
|
|
||||||
// .type_info()
|
|
||||||
// .as_struct()
|
|
||||||
// .expect("msg")
|
|
||||||
// .iter()
|
|
||||||
// {
|
|
||||||
// eprintln!("{}: {:#?}", field.name(), field.build_schema_type_info());
|
|
||||||
// }
|
|
||||||
let (_, schema) = export_type(&foo_registration, &SchemaTypesMetadata::default());
|
|
||||||
|
|
||||||
eprintln!("{}", serde_json::to_string_pretty(&schema).expect("msg"));
|
eprintln!("{}", serde_json::to_string_pretty(&schema).expect("msg"));
|
||||||
assert!(
|
assert!(
|
||||||
@ -421,18 +436,7 @@ mod tests {
|
|||||||
#[default]
|
#[default]
|
||||||
NoValue,
|
NoValue,
|
||||||
}
|
}
|
||||||
|
let schema = export_type::<EnumComponent>();
|
||||||
let atr = AppTypeRegistry::default();
|
|
||||||
{
|
|
||||||
let mut register = atr.write();
|
|
||||||
register.register::<EnumComponent>();
|
|
||||||
}
|
|
||||||
let type_registry = atr.read();
|
|
||||||
let foo_registration = type_registry
|
|
||||||
.get(TypeId::of::<EnumComponent>())
|
|
||||||
.expect("SHOULD BE REGISTERED")
|
|
||||||
.clone();
|
|
||||||
let (_, schema) = export_type(&foo_registration, &SchemaTypesMetadata::default());
|
|
||||||
eprintln!("{}", serde_json::to_string_pretty(&schema).expect("msg"));
|
eprintln!("{}", serde_json::to_string_pretty(&schema).expect("msg"));
|
||||||
assert!(
|
assert!(
|
||||||
schema.reflect_types.contains(&"Component".to_owned()),
|
schema.reflect_types.contains(&"Component".to_owned()),
|
||||||
@ -457,18 +461,7 @@ mod tests {
|
|||||||
#[default]
|
#[default]
|
||||||
NoValue,
|
NoValue,
|
||||||
}
|
}
|
||||||
|
let schema = export_type::<EnumComponent>();
|
||||||
let atr = AppTypeRegistry::default();
|
|
||||||
{
|
|
||||||
let mut register = atr.write();
|
|
||||||
register.register::<EnumComponent>();
|
|
||||||
}
|
|
||||||
let type_registry = atr.read();
|
|
||||||
let foo_registration = type_registry
|
|
||||||
.get(TypeId::of::<EnumComponent>())
|
|
||||||
.expect("SHOULD BE REGISTERED")
|
|
||||||
.clone();
|
|
||||||
let (_, schema) = export_type(&foo_registration, &SchemaTypesMetadata::default());
|
|
||||||
assert!(
|
assert!(
|
||||||
!schema.reflect_types.contains(&"Component".to_owned()),
|
!schema.reflect_types.contains(&"Component".to_owned()),
|
||||||
"Should not be a component"
|
"Should not be a component"
|
||||||
@ -512,11 +505,9 @@ mod tests {
|
|||||||
let mut metadata = SchemaTypesMetadata::default();
|
let mut metadata = SchemaTypesMetadata::default();
|
||||||
metadata.map_type_data::<ReflectCustomData>("CustomData");
|
metadata.map_type_data::<ReflectCustomData>("CustomData");
|
||||||
let type_registry = atr.read();
|
let type_registry = atr.read();
|
||||||
let foo_registration = type_registry
|
let schema = type_registry
|
||||||
.get(TypeId::of::<EnumComponent>())
|
.export_type_json_schema::<EnumComponent>(&metadata)
|
||||||
.expect("SHOULD BE REGISTERED")
|
.expect("Failed to export");
|
||||||
.clone();
|
|
||||||
let (_, schema) = export_type(&foo_registration, &metadata);
|
|
||||||
assert!(
|
assert!(
|
||||||
!metadata.has_type_data::<ReflectComponent>(&schema.reflect_types),
|
!metadata.has_type_data::<ReflectComponent>(&schema.reflect_types),
|
||||||
"Should not be a component"
|
"Should not be a component"
|
||||||
@ -543,17 +534,7 @@ mod tests {
|
|||||||
#[reflect(Component, Default, Serialize, Deserialize)]
|
#[reflect(Component, Default, Serialize, Deserialize)]
|
||||||
struct TupleStructType(usize, i32);
|
struct TupleStructType(usize, i32);
|
||||||
|
|
||||||
let atr = AppTypeRegistry::default();
|
let schema = export_type::<TupleStructType>();
|
||||||
{
|
|
||||||
let mut register = atr.write();
|
|
||||||
register.register::<TupleStructType>();
|
|
||||||
}
|
|
||||||
let type_registry = atr.read();
|
|
||||||
let foo_registration = type_registry
|
|
||||||
.get(TypeId::of::<TupleStructType>())
|
|
||||||
.expect("SHOULD BE REGISTERED")
|
|
||||||
.clone();
|
|
||||||
let (_, schema) = export_type(&foo_registration, &SchemaTypesMetadata::default());
|
|
||||||
assert!(
|
assert!(
|
||||||
schema.reflect_types.contains(&"Component".to_owned()),
|
schema.reflect_types.contains(&"Component".to_owned()),
|
||||||
"Should be a component"
|
"Should be a component"
|
||||||
@ -575,17 +556,7 @@ mod tests {
|
|||||||
a: u16,
|
a: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
let atr = AppTypeRegistry::default();
|
let schema = export_type::<Foo>();
|
||||||
{
|
|
||||||
let mut register = atr.write();
|
|
||||||
register.register::<Foo>();
|
|
||||||
}
|
|
||||||
let type_registry = atr.read();
|
|
||||||
let foo_registration = type_registry
|
|
||||||
.get(TypeId::of::<Foo>())
|
|
||||||
.expect("SHOULD BE REGISTERED")
|
|
||||||
.clone();
|
|
||||||
let (_, schema) = export_type(&foo_registration, &SchemaTypesMetadata::default());
|
|
||||||
let schema_as_value = serde_json::to_value(&schema).expect("Should serialize");
|
let schema_as_value = serde_json::to_value(&schema).expect("Should serialize");
|
||||||
eprintln!("{:#?}", &schema_as_value);
|
eprintln!("{:#?}", &schema_as_value);
|
||||||
let value = json!({
|
let value = json!({
|
||||||
@ -597,6 +568,9 @@ mod tests {
|
|||||||
"Resource",
|
"Resource",
|
||||||
"Default",
|
"Default",
|
||||||
],
|
],
|
||||||
|
"default": {
|
||||||
|
"a": 0
|
||||||
|
},
|
||||||
"kind": "Struct",
|
"kind": "Struct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user