Wrap comment lines at 100 chars
This commit is contained in:
parent
0672c862c8
commit
5d58a4d3f0
9 changed files with 147 additions and 92 deletions
|
@ -21,7 +21,8 @@ type CowStr = alloc::borrow::Cow<'static, str>;
|
||||||
/// Settings to customize how Schemas are generated.
|
/// Settings to customize how Schemas are generated.
|
||||||
///
|
///
|
||||||
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
/// If you rely on generated schemas conforming to draft 2020-12, consider using the [`SchemaSettings::draft2020_12()`] method.
|
/// If you rely on generated schemas conforming to draft 2020-12, consider using the
|
||||||
|
/// [`SchemaSettings::draft2020_12()`] method.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct SchemaSettings {
|
pub struct SchemaSettings {
|
||||||
|
@ -35,7 +36,8 @@ pub struct SchemaSettings {
|
||||||
///
|
///
|
||||||
/// Defaults to `true`.
|
/// Defaults to `true`.
|
||||||
pub option_add_null_type: bool,
|
pub option_add_null_type: bool,
|
||||||
/// A JSON pointer to the expected location of referenceable subschemas within the resulting root schema.
|
/// A JSON pointer to the expected location of referenceable subschemas within the resulting
|
||||||
|
/// root schema.
|
||||||
///
|
///
|
||||||
/// A single leading `#` and/or single trailing `/` are ignored.
|
/// A single leading `#` and/or single trailing `/` are ignored.
|
||||||
///
|
///
|
||||||
|
@ -57,7 +59,8 @@ pub struct SchemaSettings {
|
||||||
|
|
||||||
impl Default for SchemaSettings {
|
impl Default for SchemaSettings {
|
||||||
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
/// If you rely on generated schemas conforming to draft 2020-12, consider using the [`SchemaSettings::draft2020_12()`] method.
|
/// If you rely on generated schemas conforming to draft 2020-12, consider using the
|
||||||
|
/// [`SchemaSettings::draft2020_12()`] method.
|
||||||
fn default() -> SchemaSettings {
|
fn default() -> SchemaSettings {
|
||||||
SchemaSettings::draft2020_12()
|
SchemaSettings::draft2020_12()
|
||||||
}
|
}
|
||||||
|
@ -145,7 +148,8 @@ impl SchemaSettings {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the given transform to the list of [transforms](SchemaSettings::transforms) for these `SchemaSettings`.
|
/// Appends the given transform to the list of [transforms](SchemaSettings::transforms) for
|
||||||
|
/// these `SchemaSettings`.
|
||||||
pub fn with_transform(mut self, transform: impl Transform + Clone + 'static + Send) -> Self {
|
pub fn with_transform(mut self, transform: impl Transform + Clone + 'static + Send) -> Self {
|
||||||
self.transforms.push(Box::new(transform));
|
self.transforms.push(Box::new(transform));
|
||||||
self
|
self
|
||||||
|
@ -222,13 +226,15 @@ impl SchemaGenerator {
|
||||||
&self.settings
|
&self.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref` schema referencing `T`'s schema.
|
/// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref`
|
||||||
|
/// schema referencing `T`'s schema.
|
||||||
///
|
///
|
||||||
/// If `T` is not [inlined](JsonSchema::always_inline_schema), this will add `T`'s schema to this generator's definitions, and
|
/// If `T` is not [inlined](JsonSchema::always_inline_schema), this will add `T`'s schema to
|
||||||
/// return a `$ref` schema referencing that schema. Otherwise, this method behaves identically to [`JsonSchema::json_schema`].
|
/// this generator's definitions, and return a `$ref` schema referencing that schema.
|
||||||
|
/// Otherwise, this method behaves identically to [`JsonSchema::json_schema`].
|
||||||
///
|
///
|
||||||
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then
|
||||||
/// add them to the `SchemaGenerator`'s schema definitions.
|
/// this method will add them to the `SchemaGenerator`'s schema definitions.
|
||||||
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
||||||
let id = T::schema_id();
|
let id = T::schema_id();
|
||||||
let return_ref = !T::always_inline_schema()
|
let return_ref = !T::always_inline_schema()
|
||||||
|
@ -278,40 +284,44 @@ impl SchemaGenerator {
|
||||||
self.definitions.insert(name.into(), schema.to_value());
|
self.definitions.insert(name.into(), schema.to_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated.
|
/// Borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that
|
||||||
|
/// have been generated.
|
||||||
///
|
///
|
||||||
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the
|
||||||
/// themselves.
|
/// values are the schemas themselves.
|
||||||
pub fn definitions(&self) -> &JsonMap<String, Value> {
|
pub fn definitions(&self) -> &JsonMap<String, Value> {
|
||||||
&self.definitions
|
&self.definitions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutably borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated.
|
/// Mutably borrows the collection of all [non-inlined](JsonSchema::always_inline_schema)
|
||||||
|
/// schemas that have been generated.
|
||||||
///
|
///
|
||||||
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the
|
||||||
/// themselves.
|
/// values are the schemas themselves.
|
||||||
pub fn definitions_mut(&mut self) -> &mut JsonMap<String, Value> {
|
pub fn definitions_mut(&mut self) -> &mut JsonMap<String, Value> {
|
||||||
&mut self.definitions
|
&mut self.definitions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated,
|
/// Returns the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that
|
||||||
/// leaving an empty `Map` in its place.
|
/// have been generated, leaving an empty `Map` in its place.
|
||||||
///
|
///
|
||||||
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the
|
||||||
/// themselves.
|
/// values are the schemas themselves.
|
||||||
pub fn take_definitions(&mut self) -> JsonMap<String, Value> {
|
pub fn take_definitions(&mut self) -> JsonMap<String, Value> {
|
||||||
core::mem::take(&mut self.definitions)
|
core::mem::take(&mut self.definitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this `SchemaGenerator`.
|
/// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this
|
||||||
|
/// `SchemaGenerator`.
|
||||||
pub fn transforms_mut(&mut self) -> impl Iterator<Item = &mut dyn GenTransform> {
|
pub fn transforms_mut(&mut self) -> impl Iterator<Item = &mut dyn GenTransform> {
|
||||||
self.settings.transforms.iter_mut().map(Box::as_mut)
|
self.settings.transforms.iter_mut().map(Box::as_mut)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a JSON Schema for the type `T`.
|
/// Generates a JSON Schema for the type `T`.
|
||||||
///
|
///
|
||||||
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then
|
||||||
/// include them in the returned `Schema` at the [definitions path](SchemaSettings::definitions_path) (by default `"$defs"`).
|
/// this method will include them in the returned `Schema` at the [definitions
|
||||||
|
/// path](SchemaSettings::definitions_path) (by default `"$defs"`).
|
||||||
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
||||||
let mut schema = self.json_schema_internal::<T>(T::schema_id());
|
let mut schema = self.json_schema_internal::<T>(T::schema_id());
|
||||||
|
|
||||||
|
@ -333,8 +343,9 @@ impl SchemaGenerator {
|
||||||
|
|
||||||
/// Consumes `self` and generates a JSON Schema for the type `T`.
|
/// Consumes `self` and generates a JSON Schema for the type `T`.
|
||||||
///
|
///
|
||||||
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then
|
||||||
/// include them in the returned `Schema` at the [definitions path](SchemaSettings::definitions_path) (by default `"$defs"`).
|
/// this method will include them in the returned `Schema` at the [definitions
|
||||||
|
/// path](SchemaSettings::definitions_path) (by default `"$defs"`).
|
||||||
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Schema {
|
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Schema {
|
||||||
let mut schema = self.json_schema_internal::<T>(T::schema_id());
|
let mut schema = self.json_schema_internal::<T>(T::schema_id());
|
||||||
|
|
||||||
|
@ -357,8 +368,9 @@ impl SchemaGenerator {
|
||||||
|
|
||||||
/// Generates a JSON Schema for the given example value.
|
/// Generates a JSON Schema for the given example value.
|
||||||
///
|
///
|
||||||
/// If the value implements [`JsonSchema`], then prefer using the [`root_schema_for()`](Self::root_schema_for())
|
/// If the value implements [`JsonSchema`], then prefer using the
|
||||||
/// function which will generally produce a more precise schema, particularly when the value contains any enums.
|
/// [`root_schema_for()`](Self::root_schema_for()) function which will generally produce a
|
||||||
|
/// more precise schema, particularly when the value contains any enums.
|
||||||
///
|
///
|
||||||
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
|
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
|
||||||
pub fn root_schema_for_value<T: ?Sized + Serialize>(
|
pub fn root_schema_for_value<T: ?Sized + Serialize>(
|
||||||
|
@ -388,8 +400,9 @@ impl SchemaGenerator {
|
||||||
|
|
||||||
/// Consumes `self` and generates a JSON Schema for the given example value.
|
/// Consumes `self` and generates a JSON Schema for the given example value.
|
||||||
///
|
///
|
||||||
/// If the value implements [`JsonSchema`], then prefer using the [`into_root_schema_for()!`](Self::into_root_schema_for())
|
/// If the value implements [`JsonSchema`], then prefer using the
|
||||||
/// function which will generally produce a more precise schema, particularly when the value contains any enums.
|
/// [`into_root_schema_for()!`](Self::into_root_schema_for()) function which will generally
|
||||||
|
/// produce a more precise schema, particularly when the value contains any enums.
|
||||||
///
|
///
|
||||||
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
|
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
|
||||||
pub fn into_root_schema_for_value<T: ?Sized + Serialize>(
|
pub fn into_root_schema_for_value<T: ?Sized + Serialize>(
|
||||||
|
@ -511,9 +524,11 @@ fn json_pointer_mut<'a>(
|
||||||
Some(object)
|
Some(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`Transform`] which implements additional traits required to be included in a [`SchemaSettings`].
|
/// A [`Transform`] which implements additional traits required to be included in a
|
||||||
|
/// [`SchemaSettings`].
|
||||||
///
|
///
|
||||||
/// You will rarely need to use this trait directly as it is automatically implemented for any type which implements all of:
|
/// You will rarely need to use this trait directly as it is automatically implemented for any type
|
||||||
|
/// which implements all of:
|
||||||
/// - [`Transform`]
|
/// - [`Transform`]
|
||||||
/// - [`std::any::Any`] (implemented for all `'static` types)
|
/// - [`std::any::Any`] (implemented for all `'static` types)
|
||||||
/// - [`std::clone::Clone`]
|
/// - [`std::clone::Clone`]
|
||||||
|
@ -537,7 +552,8 @@ fn json_pointer_mut<'a>(
|
||||||
/// assert!(v.as_any().is::<MyTransform>());
|
/// assert!(v.as_any().is::<MyTransform>());
|
||||||
/// ```
|
/// ```
|
||||||
pub trait GenTransform: Transform + DynClone + Any + Send {
|
pub trait GenTransform: Transform + DynClone + Any + Send {
|
||||||
/// Upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as its concrete type.
|
/// Upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as
|
||||||
|
/// its concrete type.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// To remove a specific transform from an instance of `SchemaSettings`:
|
/// To remove a specific transform from an instance of `SchemaSettings`:
|
||||||
|
@ -556,7 +572,8 @@ pub trait GenTransform: Transform + DynClone + Any + Send {
|
||||||
/// ```
|
/// ```
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
/// Mutably upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as its concrete type.
|
/// Mutably upcasts this transform into an [`Any`], which can be used to inspect and manipulate
|
||||||
|
/// it as its concrete type.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// To modify a specific transform in an instance of `SchemaSettings`:
|
/// To modify a specific transform in an instance of `SchemaSettings`:
|
||||||
|
|
|
@ -109,7 +109,8 @@ pub mod r#gen {
|
||||||
/// assert_eq!(NonGenericType::schema_id(), <&mut NonGenericType>::schema_id());
|
/// assert_eq!(NonGenericType::schema_id(), <&mut NonGenericType>::schema_id());
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// But generic type parameters which may affect the generated schema should typically be included in the name/ID:
|
/// But generic type parameters which may affect the generated schema should typically be included
|
||||||
|
/// in the name/ID:
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::{SchemaGenerator, Schema, JsonSchema, json_schema};
|
/// use schemars::{SchemaGenerator, Schema, JsonSchema, json_schema};
|
||||||
/// use std::{borrow::Cow, marker::PhantomData};
|
/// use std::{borrow::Cow, marker::PhantomData};
|
||||||
|
@ -138,14 +139,14 @@ pub mod r#gen {
|
||||||
///
|
///
|
||||||
/// assert_eq!(<GenericType<i32>>::schema_id(), <&mut GenericType<&i32>>::schema_id());
|
/// assert_eq!(<GenericType<i32>>::schema_id(), <&mut GenericType<&i32>>::schema_id());
|
||||||
/// ```
|
/// ```
|
||||||
///
|
|
||||||
|
|
||||||
pub trait JsonSchema {
|
pub trait JsonSchema {
|
||||||
/// Whether JSON Schemas generated for this type should be included directly in parent schemas, rather than being
|
/// Whether JSON Schemas generated for this type should be included directly in parent schemas,
|
||||||
/// re-used where possible using the `$ref` keyword.
|
/// rather than being re-used where possible using the `$ref` keyword.
|
||||||
///
|
///
|
||||||
/// For trivial types (such as primitives), this should return `true`. For more complex types, it should return `false`.
|
/// For trivial types (such as primitives), this should return `true`. For more complex types,
|
||||||
/// For recursive types, this **must** return `false` to prevent infinite cycles when generating schemas.
|
/// it should return `false`. For recursive types, this **must** return `false` to prevent
|
||||||
|
/// infinite cycles when generating schemas.
|
||||||
///
|
///
|
||||||
/// By default, this returns `false`.
|
/// By default, this returns `false`.
|
||||||
fn always_inline_schema() -> bool {
|
fn always_inline_schema() -> bool {
|
||||||
|
@ -154,24 +155,27 @@ pub trait JsonSchema {
|
||||||
|
|
||||||
/// The name of the generated JSON Schema.
|
/// The name of the generated JSON Schema.
|
||||||
///
|
///
|
||||||
/// This is used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
|
/// This is used as the title for root schemas, and the key within the root's `definitions`
|
||||||
|
/// property for subschemas.
|
||||||
fn schema_name() -> Cow<'static, str>;
|
fn schema_name() -> Cow<'static, str>;
|
||||||
|
|
||||||
/// Returns a string that uniquely identifies the schema produced by this type.
|
/// Returns a string that uniquely identifies the schema produced by this type.
|
||||||
///
|
///
|
||||||
/// This does not have to be a human-readable string, and the value will not itself be included in generated schemas.
|
/// This does not have to be a human-readable string, and the value will not itself be included
|
||||||
/// If two types produce different schemas, then they **must** have different `schema_id()`s,
|
/// in generated schemas. If two types produce different schemas, then they **must** have
|
||||||
/// but two types that produce identical schemas should *ideally* have the same `schema_id()`.
|
/// different `schema_id()`s, but two types that produce identical schemas should *ideally*
|
||||||
|
/// have the same `schema_id()`.
|
||||||
///
|
///
|
||||||
/// The default implementation returns the same value as [`schema_name()`](JsonSchema::schema_name).
|
/// The default implementation returns the same value as
|
||||||
|
/// [`schema_name()`](JsonSchema::schema_name).
|
||||||
fn schema_id() -> Cow<'static, str> {
|
fn schema_id() -> Cow<'static, str> {
|
||||||
Self::schema_name()
|
Self::schema_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a JSON Schema for this type.
|
/// Generates a JSON Schema for this type.
|
||||||
///
|
///
|
||||||
/// If the returned schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
/// If the returned schema depends on any [non-inlined](JsonSchema::always_inline_schema)
|
||||||
/// add them to the [`SchemaGenerator`]'s schema definitions.
|
/// schemas, then this method will add them to the [`SchemaGenerator`]'s schema definitions.
|
||||||
///
|
///
|
||||||
/// This should not return a `$ref` schema.
|
/// This should not return a `$ref` schema.
|
||||||
fn json_schema(generator: &mut SchemaGenerator) -> Schema;
|
fn json_schema(generator: &mut SchemaGenerator) -> Schema;
|
||||||
|
|
|
@ -52,9 +52,10 @@ macro_rules! schema_for {
|
||||||
/// Generates a [`Schema`](crate::Schema) for the given example value using default settings.
|
/// Generates a [`Schema`](crate::Schema) for the given example value using default settings.
|
||||||
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
///
|
///
|
||||||
/// The value must implement [`Serialize`](serde::Serialize). If the value also implements [`JsonSchema`](crate::JsonSchema),
|
/// The value must implement [`Serialize`](serde::Serialize). If the value also implements
|
||||||
/// then prefer using the [`schema_for!(Type)`](schema_for) macro which will generally produce a more precise schema,
|
/// [`JsonSchema`](crate::JsonSchema), then prefer using the [`schema_for!(Type)`](schema_for) macro
|
||||||
/// particularly when the value contains any enums.
|
/// which will generally produce a more precise schema, particularly when the value contains any
|
||||||
|
/// enums.
|
||||||
///
|
///
|
||||||
/// If the `Serialize` implementation of the value decides to fail, this macro will panic.
|
/// If the `Serialize` implementation of the value decides to fail, this macro will panic.
|
||||||
/// For a non-panicking alternative, create a [`SchemaGenerator`](crate::SchemaGenerator) and use
|
/// For a non-panicking alternative, create a [`SchemaGenerator`](crate::SchemaGenerator) and use
|
||||||
|
@ -80,9 +81,11 @@ macro_rules! schema_for_value {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a [`Schema`](crate::Schema) from a JSON literal. This can either be a JSON object, or a boolean (`true` or `false`).
|
/// Construct a [`Schema`](crate::Schema) from a JSON literal. This can either be a JSON object, or
|
||||||
|
/// a boolean (`true` or `false`).
|
||||||
///
|
///
|
||||||
/// You can interpolate variables or expressions into a JSON object using the same rules as the [`serde_json::json`] macro.
|
/// You can interpolate variables or expressions into a JSON object using the same rules as the
|
||||||
|
/// [`serde_json::json`] macro.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -9,7 +9,8 @@ use serde_json::{Map, Value};
|
||||||
|
|
||||||
/// A JSON Schema.
|
/// A JSON Schema.
|
||||||
///
|
///
|
||||||
/// This wraps a JSON [`Value`] that must be either an [object](Value::Object) or a [bool](Value::Bool).
|
/// This wraps a JSON [`Value`] that must be either an [object](Value::Object) or a
|
||||||
|
/// [bool](Value::Bool).
|
||||||
///
|
///
|
||||||
/// A custom JSON schema can be created using the [`json_schema!`](crate::json_schema) macro:
|
/// A custom JSON schema can be created using the [`json_schema!`](crate::json_schema) macro:
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -20,8 +21,11 @@ use serde_json::{Map, Value};
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Because a `Schema` is a thin wrapper around a `Value`, you can also use [`TryFrom::try_from`]/[`TryInto::try_into`] to create a `Schema` from an existing `Value`.
|
/// Because a `Schema` is a thin wrapper around a `Value`, you can also use
|
||||||
/// This operation is fallible, because only [objects](Value::Object) and [bools](Value::Bool) can be converted in this way.
|
/// [`TryFrom::try_from`]/[`TryInto::try_into`] to create a `Schema` from an existing `Value`.
|
||||||
|
/// This operation is fallible, because only [objects](Value::Object) and [bools](Value::Bool) can
|
||||||
|
/// be converted in this way.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::{Schema, json_schema};
|
/// use schemars::{Schema, json_schema};
|
||||||
/// use serde_json::json;
|
/// use serde_json::json;
|
||||||
|
@ -42,10 +46,11 @@ use serde_json::{Map, Value};
|
||||||
///
|
///
|
||||||
/// let mut json_object = json!({"type": ["object", "null"]});
|
/// let mut json_object = json!({"type": ["object", "null"]});
|
||||||
/// let object_schema_mut: &mut Schema = (&mut json_object).try_into().unwrap();
|
/// let object_schema_mut: &mut Schema = (&mut json_object).try_into().unwrap();
|
||||||
///
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Similarly, you can use [`From`]/[`Into`] to (infallibly) create a `Schema` from an existing [`Map<String, Value>`] or [`bool`].
|
/// Similarly, you can use [`From`]/[`Into`] to (infallibly) create a `Schema` from an existing
|
||||||
|
/// [`Map<String, Value>`] or [`bool`].
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::{Schema, json_schema};
|
/// use schemars::{Schema, json_schema};
|
||||||
/// use serde_json::{Map, json};
|
/// use serde_json::{Map, json};
|
||||||
|
@ -101,12 +106,14 @@ impl Schema {
|
||||||
self.0.as_bool()
|
self.0.as_bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the `Schema`'s underlying JSON value is an object, borrows the object as a `Map` of properties.
|
/// If the `Schema`'s underlying JSON value is an object, borrows the object as a `Map` of
|
||||||
|
/// properties.
|
||||||
pub fn as_object(&self) -> Option<&Map<String, Value>> {
|
pub fn as_object(&self) -> Option<&Map<String, Value>> {
|
||||||
self.0.as_object()
|
self.0.as_object()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the `Schema`'s underlying JSON value is an object, mutably borrows the object as a `Map` of properties.
|
/// If the `Schema`'s underlying JSON value is an object, mutably borrows the object as a `Map`
|
||||||
|
/// of properties.
|
||||||
pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> {
|
pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> {
|
||||||
self.0.as_object_mut()
|
self.0.as_object_mut()
|
||||||
}
|
}
|
||||||
|
@ -124,10 +131,12 @@ impl Schema {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the `Schema` (if it wraps a bool value) into an equivalent object schema. Then mutably borrows the object as a `Map` of properties.
|
/// Converts the `Schema` (if it wraps a bool value) into an equivalent object schema. Then
|
||||||
|
/// mutably borrows the object as a `Map` of properties.
|
||||||
///
|
///
|
||||||
/// `true` is transformed into an empty schema `{}`, which successfully validates against all possible values.
|
/// `true` is transformed into an empty schema `{}`, which successfully validates against all
|
||||||
/// `false` is transformed into the schema `{"not": {}}`, which does not successfully validate against any value.
|
/// possible values. `false` is transformed into the schema `{"not": {}}`, which does not
|
||||||
|
/// successfully validate against any value.
|
||||||
#[allow(clippy::missing_panics_doc)]
|
#[allow(clippy::missing_panics_doc)]
|
||||||
pub fn ensure_object(&mut self) -> &mut Map<String, Value> {
|
pub fn ensure_object(&mut self) -> &mut Map<String, Value> {
|
||||||
if let Some(b) = self.as_bool() {
|
if let Some(b) = self.as_bool() {
|
||||||
|
@ -145,11 +154,13 @@ impl Schema {
|
||||||
|
|
||||||
/// Inserts a property into the schema, replacing any previous value.
|
/// Inserts a property into the schema, replacing any previous value.
|
||||||
///
|
///
|
||||||
/// If the schema wraps a bool value, it will first be converted into an equivalent object schema.
|
/// If the schema wraps a bool value, it will first be converted into an equivalent object
|
||||||
|
/// schema.
|
||||||
///
|
///
|
||||||
/// If the schema did not have this key present, `None` is returned.
|
/// If the schema did not have this key present, `None` is returned.
|
||||||
///
|
///
|
||||||
/// If the schema did have this key present, the value is updated, and the old value is returned.
|
/// If the schema did have this key present, the value is updated, and the old value is
|
||||||
|
/// returned.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -166,7 +177,8 @@ impl Schema {
|
||||||
self.ensure_object().insert(k, v)
|
self.ensure_object().insert(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the `Schema`'s underlying JSON value is an object, gets a reference to that object's value for the given key.
|
/// If the `Schema`'s underlying JSON value is an object, gets a reference to that object's
|
||||||
|
/// value for the given key.
|
||||||
///
|
///
|
||||||
/// This always returns `None` for bool schemas.
|
/// This always returns `None` for bool schemas.
|
||||||
///
|
///
|
||||||
|
@ -190,7 +202,8 @@ impl Schema {
|
||||||
self.0.as_object().and_then(|o| o.get(key))
|
self.0.as_object().and_then(|o| o.get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the `Schema`'s underlying JSON value is an object, removes and returns its value for the given key.
|
/// If the `Schema`'s underlying JSON value is an object, removes and returns its value for the
|
||||||
|
/// given key.
|
||||||
///
|
///
|
||||||
/// This always returns `None` for bool schemas, without modifying them.
|
/// This always returns `None` for bool schemas, without modifying them.
|
||||||
///
|
///
|
||||||
|
@ -202,7 +215,6 @@ impl Schema {
|
||||||
/// let mut schema = json_schema!({"type": "array"});
|
/// let mut schema = json_schema!({"type": "array"});
|
||||||
/// assert_eq!(schema.remove("type"), Some(json!("array")));
|
/// assert_eq!(schema.remove("type"), Some(json!("array")));
|
||||||
/// assert_eq!(schema, json_schema!({}));
|
/// assert_eq!(schema, json_schema!({}));
|
||||||
///
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn remove<Q>(&mut self, key: &Q) -> Option<Value>
|
pub fn remove<Q>(&mut self, key: &Q) -> Option<Value>
|
||||||
where
|
where
|
||||||
|
|
|
@ -117,11 +117,13 @@ use serde_json::{json, Map, Value};
|
||||||
pub trait Transform {
|
pub trait Transform {
|
||||||
/// Applies the transform to the given [`Schema`].
|
/// Applies the transform to the given [`Schema`].
|
||||||
///
|
///
|
||||||
/// When overriding this method, you may want to call the [`transform_subschemas`] function to also transform any subschemas.
|
/// When overriding this method, you may want to call the [`transform_subschemas`] function to
|
||||||
|
/// also transform any subschemas.
|
||||||
fn transform(&mut self, schema: &mut Schema);
|
fn transform(&mut self, schema: &mut Schema);
|
||||||
|
|
||||||
// Not public API
|
// Not public API
|
||||||
// Hack to enable implementing Debug on Box<dyn GenTransform> even though closures don't implement Debug
|
// Hack to enable implementing Debug on Box<dyn GenTransform> even though closures don't
|
||||||
|
// implement Debug
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn _debug_type_name(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn _debug_type_name(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.write_str(core::any::type_name::<Self>())
|
f.write_str(core::any::type_name::<Self>())
|
||||||
|
@ -167,7 +169,8 @@ pub fn transform_subschemas<T: Transform + ?Sized>(t: &mut T, schema: &mut Schem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Support `items` array even though this is not allowed in draft 2020-12 (see above comment)
|
// Support `items` array even though this is not allowed in draft 2020-12 (see above
|
||||||
|
// comment)
|
||||||
"items" => {
|
"items" => {
|
||||||
if let Some(array) = value.as_array_mut() {
|
if let Some(array) = value.as_array_mut() {
|
||||||
for value in array {
|
for value in array {
|
||||||
|
@ -220,9 +223,11 @@ pub(crate) fn transform_immediate_subschemas<T: Transform + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper struct that can wrap a non-recursive [`Transform`] (i.e. one that does not apply to subschemas) into a recursive one.
|
/// A helper struct that can wrap a non-recursive [`Transform`] (i.e. one that does not apply to
|
||||||
|
/// subschemas) into a recursive one.
|
||||||
///
|
///
|
||||||
/// Its implementation of `Transform` will first apply the inner transform to the "parent" schema, and then its subschemas (and their subschemas, and so on).
|
/// Its implementation of `Transform` will first apply the inner transform to the "parent" schema,
|
||||||
|
/// and then its subschemas (and their subschemas, and so on).
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -267,10 +272,12 @@ where
|
||||||
/// Replaces boolean JSON Schemas with equivalent object schemas.
|
/// Replaces boolean JSON Schemas with equivalent object schemas.
|
||||||
/// This also applies to subschemas.
|
/// This also applies to subschemas.
|
||||||
///
|
///
|
||||||
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support booleans as schemas.
|
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support booleans as
|
||||||
|
/// schemas.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReplaceBoolSchemas {
|
pub struct ReplaceBoolSchemas {
|
||||||
/// When set to `true`, a schema's `additionalProperties` property will not be changed from a boolean.
|
/// When set to `true`, a schema's `additionalProperties` property will not be changed from a
|
||||||
|
/// boolean.
|
||||||
pub skip_additional_properties: bool,
|
pub skip_additional_properties: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,10 +301,11 @@ impl Transform for ReplaceBoolSchemas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restructures JSON Schema objects so that the `$ref` property will never appear alongside any other properties.
|
/// Restructures JSON Schema objects so that the `$ref` property will never appear alongside any
|
||||||
/// This also applies to subschemas.
|
/// other properties. This also applies to subschemas.
|
||||||
///
|
///
|
||||||
/// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support other properties alongside `$ref`.
|
/// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support other properties
|
||||||
|
/// alongside `$ref`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RemoveRefSiblings;
|
pub struct RemoveRefSiblings;
|
||||||
|
|
||||||
|
@ -318,10 +326,11 @@ impl Transform for RemoveRefSiblings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the `examples` schema property and (if present) set its first value as the `example` property.
|
/// Removes the `examples` schema property and (if present) set its first value as the `example`
|
||||||
/// This also applies to subschemas.
|
/// property. This also applies to subschemas.
|
||||||
///
|
///
|
||||||
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `examples` property.
|
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `examples`
|
||||||
|
/// property.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SetSingleExample;
|
pub struct SetSingleExample;
|
||||||
|
|
||||||
|
@ -340,7 +349,8 @@ impl Transform for SetSingleExample {
|
||||||
/// Replaces the `const` schema property with a single-valued `enum` property.
|
/// Replaces the `const` schema property with a single-valued `enum` property.
|
||||||
/// This also applies to subschemas.
|
/// This also applies to subschemas.
|
||||||
///
|
///
|
||||||
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const` property.
|
/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const`
|
||||||
|
/// property.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReplaceConstValue;
|
pub struct ReplaceConstValue;
|
||||||
|
|
||||||
|
@ -357,9 +367,11 @@ impl Transform for ReplaceConstValue {
|
||||||
/// Rename the `prefixItems` schema property to `items`.
|
/// Rename the `prefixItems` schema property to `items`.
|
||||||
/// This also applies to subschemas.
|
/// This also applies to subschemas.
|
||||||
///
|
///
|
||||||
/// If the schema contains both `prefixItems` and `items`, then this additionally renames `items` to `additionalItems`.
|
/// If the schema contains both `prefixItems` and `items`, then this additionally renames `items` to
|
||||||
|
/// `additionalItems`.
|
||||||
///
|
///
|
||||||
/// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support the `prefixItems` property.
|
/// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support the `prefixItems`
|
||||||
|
/// property.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReplacePrefixItems;
|
pub struct ReplacePrefixItems;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ struct MyStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # A Unit
|
/// # A Unit
|
||||||
///
|
|
||||||
#[derive(JsonSchema)]
|
#[derive(JsonSchema)]
|
||||||
struct MyUnitStruct;
|
struct MyUnitStruct;
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,9 @@ impl CommonAttrs {
|
||||||
|
|
||||||
"extend" => {
|
"extend" => {
|
||||||
for ex in parse_extensions(meta, cx).into_iter().flatten() {
|
for ex in parse_extensions(meta, cx).into_iter().flatten() {
|
||||||
// This is O(n^2) but should be fine with the typically small number of extensions.
|
// This is O(n^2) but should be fine with the typically small number of
|
||||||
// If this does become a problem, it can be changed to use IndexMap, or a separate Map with cloned keys.
|
// extensions. If this does become a problem, it can be changed to use
|
||||||
|
// IndexMap, or a separate Map with cloned keys.
|
||||||
if self.extensions.iter().any(|e| e.0 == ex.key_str) {
|
if self.extensions.iter().any(|e| e.0 == ex.key_str) {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
ex.key_lit,
|
ex.key_lit,
|
||||||
|
|
|
@ -6,7 +6,8 @@ use syn::{Attribute, Data, Field, Meta, Variant};
|
||||||
|
|
||||||
use super::get_meta_items;
|
use super::get_meta_items;
|
||||||
|
|
||||||
// List of keywords that can appear in #[serde(...)]/#[schemars(...)] attributes which we want serde_derive_internals to parse for us.
|
// List of keywords that can appear in #[serde(...)]/#[schemars(...)] attributes which we want
|
||||||
|
// serde_derive_internals to parse for us.
|
||||||
pub(crate) static SERDE_KEYWORDS: &[&str] = &[
|
pub(crate) static SERDE_KEYWORDS: &[&str] = &[
|
||||||
"rename",
|
"rename",
|
||||||
"rename_all",
|
"rename_all",
|
||||||
|
@ -23,12 +24,15 @@ pub(crate) static SERDE_KEYWORDS: &[&str] = &[
|
||||||
"flatten",
|
"flatten",
|
||||||
"remote",
|
"remote",
|
||||||
"transparent",
|
"transparent",
|
||||||
// Special case - `bound` is removed from serde attrs, so is only respected when present in schemars attr.
|
// Special case - `bound` is removed from serde attrs, so is only respected when present in
|
||||||
|
// schemars attr.
|
||||||
"bound",
|
"bound",
|
||||||
// Special cases - `with`/`serialize_with` are passed to serde but not copied from schemars attrs to serde attrs.
|
// Special cases - `with`/`serialize_with` are passed to serde but not copied from schemars
|
||||||
// This is because we want to preserve any serde attribute's `serialize_with` value to determine whether the field's
|
// attrs to serde attrs. This is because we want to preserve any serde attribute's
|
||||||
// default value should be serialized. We also check the `with` value on schemars/serde attrs e.g. to support deriving
|
// `serialize_with` value to determine whether the field's default value should be
|
||||||
// JsonSchema on remote types, but we parse that ourselves rather than using serde_derive_internals.
|
// serialized. We also check the `with` value on schemars/serde attrs e.g. to support deriving
|
||||||
|
// JsonSchema on remote types, but we parse that ourselves rather than using
|
||||||
|
// serde_derive_internals.
|
||||||
"serialize_with",
|
"serialize_with",
|
||||||
"with",
|
"with",
|
||||||
];
|
];
|
||||||
|
|
|
@ -201,8 +201,11 @@ fn add_trait_bounds(cont: &mut Container) {
|
||||||
let where_clause = cont.generics.make_where_clause();
|
let where_clause = cont.generics.make_where_clause();
|
||||||
where_clause.predicates.extend(bounds.iter().cloned());
|
where_clause.predicates.extend(bounds.iter().cloned());
|
||||||
} else {
|
} else {
|
||||||
// No explicit trait bounds specified, assume the Rust convention of adding the trait to each type parameter
|
// No explicit trait bounds specified, assume the Rust convention of adding the trait to
|
||||||
// TODO consider also adding trait bound to associated types when used as fields - I think Serde does this?
|
// each type parameter
|
||||||
|
//
|
||||||
|
// TODO consider also adding trait bound to associated types
|
||||||
|
// when used as fields - I think Serde does this?
|
||||||
for param in &mut cont.generics.params {
|
for param in &mut cont.generics.params {
|
||||||
if let syn::GenericParam::Type(ref mut type_param) = *param {
|
if let syn::GenericParam::Type(ref mut type_param) = *param {
|
||||||
type_param.bounds.push(parse_quote!(schemars::JsonSchema));
|
type_param.bounds.push(parse_quote!(schemars::JsonSchema));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue