use serde_json::{json, Value};
#[cfg(feature = "diff")]
#[cfg_attr(docsrs, doc(cfg(feature = "diff")))]
pub mod diff;
pub use crate::schema::NestedSchemaEntry;
pub trait JsonSchema {
fn json_schema(&self) -> Value;
fn is_required(&self) -> bool {
true
}
}
pub trait CollectNestedSchemas {
fn collect_nested_schemas(&self, _out: &mut Vec<NestedSchemaEntry>) {}
}
pub trait OpenApiParameterIn {
fn parameter_in() -> Option<&'static str> {
None
}
}
pub fn nullable_schema(inner: Value) -> Value {
let already_nullable = inner
.get("anyOf")
.and_then(Value::as_array)
.is_some_and(|items| items.iter().any(|i| i.get("type") == Some(&json!("null"))));
if already_nullable {
return inner;
}
json!({ "anyOf": [inner, { "type": "null" }] })
}
macro_rules! forward_inner_schema {
($( impl[$($g:tt)*] $t:ty, inner = $S:ident $(, where [$($w:tt)*])? ; )*) => {$(
impl<$($g)*> $crate::openapi::JsonSchema for $t
where
$S: $crate::schema::VldSchema + $crate::openapi::JsonSchema,
$($($w)*)?
{
fn json_schema(&self) -> serde_json::Value {
$crate::openapi::JsonSchema::json_schema(self.inner_schema())
}
fn is_required(&self) -> bool {
$crate::openapi::JsonSchema::is_required(self.inner_schema())
}
}
impl<$($g)*> $crate::openapi::CollectNestedSchemas for $t
where
$S: $crate::schema::VldSchema + $crate::openapi::CollectNestedSchemas,
$($($w)*)?
{
fn collect_nested_schemas(&self, out: &mut Vec<$crate::schema::NestedSchemaEntry>) {
$crate::openapi::CollectNestedSchemas::collect_nested_schemas(self.inner_schema(), out);
}
}
)*};
}
pub(crate) use forward_inner_schema;
macro_rules! collect_inner_schemas {
($( impl[$($g:tt)*] $t:ty, inner = $S:ident $(, where [$($w:tt)*])? ; )*) => {$(
impl<$($g)*> $crate::openapi::CollectNestedSchemas for $t
where
$S: $crate::schema::VldSchema + $crate::openapi::CollectNestedSchemas,
$($($w)*)?
{
fn collect_nested_schemas(&self, out: &mut Vec<$crate::schema::NestedSchemaEntry>) {
$crate::openapi::CollectNestedSchemas::collect_nested_schemas(self.inner_schema(), out);
}
}
)*};
}
pub(crate) use collect_inner_schemas;
pub fn to_openapi_document(name: &str, schema: &Value) -> Value {
to_openapi_document_multi(&[(name, schema.clone())])
}
pub fn to_openapi_document_multi(schemas: &[(&str, Value)]) -> Value {
let map: serde_json::Map<String, Value> = schemas
.iter()
.map(|(name, schema)| (name.to_string(), schema.clone()))
.collect();
json!({
"openapi": "3.1.0",
"info": { "title": "API", "version": "1.0.0" },
"paths": {},
"components": { "schemas": Value::Object(map) }
})
}