Use $defs
instead of definitions
in draft 2019-09
This also changes the strategy for running visitors on subschemas - it is now done eagerly, as soon as they're added to the definitions map.
This commit is contained in:
parent
22e89a5dd6
commit
95475ad1b4
5 changed files with 98 additions and 74 deletions
|
@ -75,7 +75,7 @@ impl SchemaSettings {
|
||||||
SchemaSettings {
|
SchemaSettings {
|
||||||
option_nullable: false,
|
option_nullable: false,
|
||||||
option_add_null_type: true,
|
option_add_null_type: true,
|
||||||
definitions_path: "#/definitions/".to_owned(),
|
definitions_path: "#/$defs/".to_owned(),
|
||||||
meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
|
meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
|
||||||
visitors: Vec::new(),
|
visitors: Vec::new(),
|
||||||
inline_subschemas: false,
|
inline_subschemas: false,
|
||||||
|
@ -253,7 +253,8 @@ impl SchemaGenerator {
|
||||||
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
||||||
self.definitions.insert(name.clone(), dummy);
|
self.definitions.insert(name.clone(), dummy);
|
||||||
|
|
||||||
let schema = self.json_schema_internal::<T>(id);
|
let mut schema = self.json_schema_internal::<T>(id);
|
||||||
|
Self::run_visitors(&mut schema, &mut self.settings.visitors);
|
||||||
|
|
||||||
self.definitions.insert(name, schema.to_value());
|
self.definitions.insert(name, schema.to_value());
|
||||||
}
|
}
|
||||||
|
@ -306,16 +307,12 @@ impl SchemaGenerator {
|
||||||
object.insert("$schema".into(), meta_schema.into());
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.definitions.is_empty() {
|
Self::add_definitions(
|
||||||
object.insert(
|
object,
|
||||||
"definitions".into(),
|
self.definitions.clone(),
|
||||||
serde_json::Value::Object(self.definitions.clone()),
|
&self.settings.definitions_path,
|
||||||
);
|
);
|
||||||
}
|
Self::run_visitors(&mut schema, &mut self.settings.visitors);
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
|
||||||
visitor.visit_schema(&mut schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
schema
|
schema
|
||||||
}
|
}
|
||||||
|
@ -337,16 +334,8 @@ impl SchemaGenerator {
|
||||||
object.insert("$schema".into(), meta_schema.into());
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.definitions.is_empty() {
|
Self::add_definitions(object, self.definitions, &self.settings.definitions_path);
|
||||||
object.insert(
|
Self::run_visitors(&mut schema, &mut self.settings.visitors);
|
||||||
"definitions".into(),
|
|
||||||
serde_json::Value::Object(self.definitions),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
|
||||||
visitor.visit_schema(&mut schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
schema
|
schema
|
||||||
}
|
}
|
||||||
|
@ -374,16 +363,12 @@ impl SchemaGenerator {
|
||||||
object.insert("$schema".into(), meta_schema.into());
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.definitions.is_empty() {
|
Self::add_definitions(
|
||||||
object.insert(
|
object,
|
||||||
"definitions".into(),
|
self.definitions.clone(),
|
||||||
serde_json::Value::Object(self.definitions.clone()),
|
&self.settings.definitions_path,
|
||||||
);
|
);
|
||||||
}
|
Self::run_visitors(&mut schema, &mut self.settings.visitors);
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
|
||||||
visitor.visit_schema(&mut schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(schema)
|
Ok(schema)
|
||||||
}
|
}
|
||||||
|
@ -411,16 +396,8 @@ impl SchemaGenerator {
|
||||||
object.insert("$schema".into(), meta_schema.into());
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.definitions.is_empty() {
|
Self::add_definitions(object, self.definitions, &self.settings.definitions_path);
|
||||||
object.insert(
|
Self::run_visitors(&mut schema, &mut self.settings.visitors);
|
||||||
"definitions".into(),
|
|
||||||
serde_json::Value::Object(self.definitions),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
|
||||||
visitor.visit_schema(&mut schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(schema)
|
Ok(schema)
|
||||||
}
|
}
|
||||||
|
@ -450,6 +427,51 @@ impl SchemaGenerator {
|
||||||
let pss = PendingSchemaState::new(self, id);
|
let pss = PendingSchemaState::new(self, id);
|
||||||
T::json_schema(pss.gen)
|
T::json_schema(pss.gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_definitions(
|
||||||
|
schema_object: &mut Map<String, Value>,
|
||||||
|
mut definitions: Map<String, Value>,
|
||||||
|
path: &str,
|
||||||
|
) {
|
||||||
|
if definitions.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = match Self::json_pointer(schema_object, path) {
|
||||||
|
Some(d) => d,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
target.append(&mut definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_pointer<'a>(
|
||||||
|
mut object: &'a mut Map<String, Value>,
|
||||||
|
pointer: &str,
|
||||||
|
) -> Option<&'a mut Map<String, Value>> {
|
||||||
|
let segments = pointer.strip_prefix("#/")?.strip_suffix('/')?.split('/');
|
||||||
|
|
||||||
|
for mut segment in segments {
|
||||||
|
let replaced: String;
|
||||||
|
if segment.contains('~') {
|
||||||
|
replaced = segment.replace("~1", "/").replace("~0", "~");
|
||||||
|
segment = &replaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
object = object
|
||||||
|
.entry(segment)
|
||||||
|
.or_insert(Value::Object(Map::default()))
|
||||||
|
.as_object_mut()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_visitors(schema: &mut Schema, visitors: &mut [Box<dyn GenVisitor>]) {
|
||||||
|
for visitor in visitors {
|
||||||
|
visitor.visit_schema(schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Visitor](Visitor) which implements additional traits required to be included in a [SchemaSettings].
|
/// A [Visitor](Visitor) which implements additional traits required to be included in a [SchemaSettings].
|
||||||
|
|
|
@ -78,7 +78,7 @@ pub fn visit_schema<V: Visitor + ?Sized>(v: &mut V, schema: &mut Schema) {
|
||||||
v.visit_schema(subschema)
|
v.visit_schema(subschema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"properties" | "patternProperties" | "definitions" | "$defs" => {
|
"properties" | "patternProperties" => {
|
||||||
if let Some(obj) = value.as_object_mut() {
|
if let Some(obj) = value.as_object_mut() {
|
||||||
for value in obj.values_mut() {
|
for value in obj.values_mut() {
|
||||||
if let Ok(subschema) = value.try_into() {
|
if let Ok(subschema) = value.try_into() {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
},
|
},
|
||||||
"my_unit": {
|
"my_unit": {
|
||||||
"description": "A unit struct instance",
|
"description": "A unit struct instance",
|
||||||
"$ref": "#/definitions/MyUnitStruct"
|
"$ref": "#/$defs/MyUnitStruct"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
"my_undocumented_bool",
|
"my_undocumented_bool",
|
||||||
"my_unit"
|
"my_unit"
|
||||||
],
|
],
|
||||||
"definitions": {
|
"$defs": {
|
||||||
"MyUnitStruct": {
|
"MyUnitStruct": {
|
||||||
"title": "A Unit",
|
"title": "A Unit",
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"inner": {
|
"inner": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/Inner"
|
"$ref": "#/$defs/Inner"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
"values",
|
"values",
|
||||||
"value"
|
"value"
|
||||||
],
|
],
|
||||||
"definitions": {
|
"$defs": {
|
||||||
"Inner": {
|
"Inner": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
"values",
|
"values",
|
||||||
"value"
|
"value"
|
||||||
],
|
],
|
||||||
"definitions": {
|
"components": {
|
||||||
|
"schemas": {
|
||||||
"Inner": {
|
"Inner": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
|
@ -58,3 +59,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue