Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Dygalo <dmitry@dygalo.dev>
  • Loading branch information
Stranger6667 committed Feb 5, 2025
1 parent 5dad3ab commit 6e69092
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 137 deletions.
69 changes: 43 additions & 26 deletions crates/jsonschema-referencing/src/specification/draft201909.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,52 @@ use serde_json::Value;

use crate::{resource::InnerResourcePtr, segments::Segment, Error, Resolver, Segments};

use super::subresources::SubresourceIterator;
use super::subresources::{SubIterBranch, SubresourceIterator};

pub(crate) fn subresources_of(contents: &Value) -> SubresourceIterator<'_> {
match contents.as_object() {
Some(schema) => Box::new(schema.iter().flat_map(|(key, value)| match key.as_str() {
"additionalItems"
| "additionalProperties"
| "contains"
| "contentSchema"
| "else"
| "if"
| "not"
| "propertyNames"
| "then"
| "unevaluatedItems"
| "unevaluatedProperties" => {
Box::new(std::iter::once(value)) as SubresourceIterator<'_>
fn object_iter<'a>((key, value): (&'a String, &'a Value)) -> SubIterBranch<'a> {
match key.as_str() {
// For these keys, yield the value once.
"additionalItems"
| "additionalProperties"
| "contains"
| "contentSchema"
| "else"
| "if"
| "not"
| "propertyNames"
| "then"
| "unevaluatedItems"
| "unevaluatedProperties" => SubIterBranch::Once(value),
// For these keys, if the value is an array, iterate over its items.
"allOf" | "anyOf" | "oneOf" => {
if let Some(arr) = value.as_array() {
SubIterBranch::Array(arr.iter())
} else {
SubIterBranch::Empty
}
"allOf" | "anyOf" | "oneOf" => Box::new(value.as_array().into_iter().flatten()),
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
Box::new(value.as_object().into_iter().flat_map(|o| o.values()))
}
// For these keys, if the value is an object, iterate over its values.
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
if let Some(obj) = value.as_object() {
SubIterBranch::Object(obj.values())
} else {
SubIterBranch::Empty
}
"items" => match value {
Value::Array(arr) => Box::new(arr.iter()) as SubresourceIterator<'_>,
_ => Box::new(std::iter::once(value)),
},
_ => Box::new(std::iter::empty()),
})),
None => Box::new(std::iter::empty()),
}
// For "items": if it's an array, iterate over its items; otherwise, yield the value once.
"items" => match value {
Value::Array(arr) => SubIterBranch::Array(arr.iter()),
_ => SubIterBranch::Once(value),
},
// For any other key, yield nothing.
_ => SubIterBranch::Empty,
}
}

pub(crate) fn subresources_of(contents: &Value) -> SubresourceIterator<'_> {
match contents.as_object() {
Some(schema) => SubresourceIterator::Object(schema.iter().flat_map(object_iter)),
None => SubresourceIterator::Empty,
}
}

Expand Down
79 changes: 53 additions & 26 deletions crates/jsonschema-referencing/src/specification/draft4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,62 @@ use serde_json::Value;

use crate::{resource::InnerResourcePtr, Error, Resolver, Segments};

use super::subresources::{self, SubresourceIterator};
use super::subresources::{self, SubIterBranch, SubresourceIterator};

fn object_iter<'a>((key, value): (&'a String, &'a Value)) -> SubIterBranch<'a> {
match key.as_str() {
// For "items": if it’s an array, iterate over it; otherwise, yield one element.
"items" => match value {
Value::Array(arr) => SubIterBranch::Array(arr.iter()),
_ => SubIterBranch::Once(value),
},
// For "allOf", "anyOf", "oneOf", "prefixItems": if the value is an array, iterate over it.
"allOf" | "anyOf" | "oneOf" | "prefixItems" => {
if let Some(arr) = value.as_array() {
SubIterBranch::Array(arr.iter())
} else {
SubIterBranch::Empty
}
}
// For "$defs", "definitions", "dependentSchemas", "patternProperties", "properties":
// if the value is an object, iterate over its values.
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
if let Some(obj) = value.as_object() {
SubIterBranch::Object(obj.values())
} else {
SubIterBranch::Empty
}
}
// For "dependencies": if the value is an object, iterate over its values filtered to only those that are objects.
"dependencies" => {
if let Some(obj) = value.as_object() {
SubIterBranch::FilteredObject(obj.values())
} else {
SubIterBranch::Empty
}
}
// For "additionalItems" and "additionalProperties", only if the value is an object.
"additionalItems" | "additionalProperties" if value.is_object() => {
SubIterBranch::Once(value)
}
// For other keys that were originally in the “single element” group:
"contains"
| "contentSchema"
| "else"
| "if"
| "propertyNames"
| "not"
| "then"
| "unevaluatedItems"
| "unevaluatedProperties" => SubIterBranch::Once(value),
_ => SubIterBranch::Empty,
}
}

pub(crate) fn subresources_of(contents: &Value) -> SubresourceIterator<'_> {
match contents.as_object() {
Some(schema) => Box::new(schema.iter().flat_map(|(key, value)| {
match key.as_str() {
"not" => Box::new(std::iter::once(value)) as SubresourceIterator<'_>,
"allOf" | "anyOf" | "oneOf" => Box::new(value.as_array().into_iter().flatten()),
"definitions" | "patternProperties" | "properties" => {
Box::new(value.as_object().into_iter().flat_map(|o| o.values()))
}
"items" => match value {
Value::Array(arr) => Box::new(arr.iter()) as SubresourceIterator<'_>,
_ => Box::new(std::iter::once(value)),
},
"dependencies" => Box::new(
value
.as_object()
.into_iter()
.flat_map(|o| o.values())
.filter(|v| v.is_object()),
),
"additionalItems" | "additionalProperties" if value.is_object() => {
Box::new(std::iter::once(value))
}
_ => Box::new(std::iter::empty()),
}
})),
None => Box::new(std::iter::empty()),
Some(schema) => SubresourceIterator::Object(schema.iter().flat_map(object_iter)),
None => SubresourceIterator::Empty,
}
}

Expand Down
64 changes: 37 additions & 27 deletions crates/jsonschema-referencing/src/specification/draft6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,46 @@ use serde_json::Value;

use crate::{resource::InnerResourcePtr, Error, Resolver, Segments};

use super::subresources::{self, SubresourceIterator};
use super::subresources::{self, SubIterBranch, SubresourceIterator};

fn object_iter<'a>((key, value): (&'a String, &'a Value)) -> SubIterBranch<'a> {
match key.as_str() {
"additionalItems" | "additionalProperties" | "contains" | "not" | "propertyNames" => {
SubIterBranch::Once(value)
}
"allOf" | "anyOf" | "oneOf" => {
if let Some(arr) = value.as_array() {
SubIterBranch::Array(arr.iter())
} else {
SubIterBranch::Empty
}
}
"definitions" | "patternProperties" | "properties" => {
if let Some(obj) = value.as_object() {
SubIterBranch::Object(obj.values())
} else {
SubIterBranch::Empty
}
}
"items" => match value {
Value::Array(arr) => SubIterBranch::Array(arr.iter()),
_ => SubIterBranch::Once(value),
},
"dependencies" => {
if let Some(obj) = value.as_object() {
SubIterBranch::FilteredObject(obj.values())
} else {
SubIterBranch::Empty
}
}
_ => SubIterBranch::Empty,
}
}

pub(crate) fn subresources_of(contents: &Value) -> SubresourceIterator<'_> {
match contents.as_object() {
Some(schema) => Box::new(schema.iter().flat_map(|(key, value)| {
match key.as_str() {
"additionalItems"
| "additionalProperties"
| "contains"
| "not"
| "propertyNames" => Box::new(std::iter::once(value)) as SubresourceIterator<'_>,
"allOf" | "anyOf" | "oneOf" => Box::new(value.as_array().into_iter().flatten()),
"definitions" | "patternProperties" | "properties" => {
Box::new(value.as_object().into_iter().flat_map(|o| o.values()))
}
"items" => match value {
Value::Array(arr) => Box::new(arr.iter()) as SubresourceIterator<'_>,
_ => Box::new(std::iter::once(value)),
},
"dependencies" => Box::new(
value
.as_object()
.into_iter()
.flat_map(|o| o.values())
.filter(|v| v.is_object()),
),
_ => Box::new(std::iter::empty()),
}
})),
None => Box::new(std::iter::empty()),
Some(schema) => SubresourceIterator::Object(schema.iter().flat_map(object_iter)),
None => SubresourceIterator::Empty,
}
}

Expand Down
81 changes: 51 additions & 30 deletions crates/jsonschema-referencing/src/specification/draft7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,60 @@ use serde_json::Value;

use crate::{resource::InnerResourcePtr, Error, Resolver, Segments};

use super::subresources::{self, SubresourceIterator};
use super::subresources::{self, SubIterBranch, SubresourceIterator};

fn object_iter<'a>((key, value): (&'a String, &'a Value)) -> SubIterBranch<'a> {
match key.as_str() {
// For these keys, yield the value once.
"additionalItems"
| "additionalProperties"
| "contains"
| "else"
| "if"
| "not"
| "propertyNames"
| "then" => SubIterBranch::Once(value),
// For these keys, if the value is an array, iterate over its items.
"allOf" | "anyOf" | "oneOf" => {
if let Some(arr) = value.as_array() {
// In the old draft, flatten() was used.
// Here we simply iterate over the array.
SubIterBranch::Array(arr.iter())
} else {
SubIterBranch::Empty
}
}
// For these keys, if the value is an object, iterate over its values.
"definitions" | "patternProperties" | "properties" => {
if let Some(obj) = value.as_object() {
// flat_map in the old draft: iterate over the object's values.
SubIterBranch::Object(obj.values())
} else {
SubIterBranch::Empty
}
}
// For "items": if it's an array, iterate over its items; otherwise, yield the value once.
"items" => match value {
Value::Array(arr) => SubIterBranch::Array(arr.iter()),
_ => SubIterBranch::Once(value),
},
// For "dependencies": if the value is an object, iterate over its values filtered to only those that are objects.
"dependencies" => {
if let Some(obj) = value.as_object() {
SubIterBranch::FilteredObject(obj.values())
} else {
SubIterBranch::Empty
}
}
// For any other key, yield nothing.
_ => SubIterBranch::Empty,
}
}

pub(crate) fn subresources_of(contents: &Value) -> SubresourceIterator<'_> {
match contents.as_object() {
Some(schema) => Box::new(schema.iter().flat_map(|(key, value)| {
match key.as_str() {
"additionalItems"
| "additionalProperties"
| "contains"
| "else"
| "if"
| "not"
| "propertyNames"
| "then" => Box::new(std::iter::once(value)) as SubresourceIterator<'_>,
"allOf" | "anyOf" | "oneOf" => Box::new(value.as_array().into_iter().flatten()),
"definitions" | "patternProperties" | "properties" => {
Box::new(value.as_object().into_iter().flat_map(|o| o.values()))
}
"items" => match value {
Value::Array(arr) => Box::new(arr.iter()) as SubresourceIterator<'_>,
_ => Box::new(std::iter::once(value)),
},
"dependencies" => Box::new(
value
.as_object()
.into_iter()
.flat_map(|o| o.values())
.filter(|v| v.is_object()),
),
_ => Box::new(std::iter::empty()),
}
})),
None => Box::new(std::iter::empty()),
Some(schema) => SubresourceIterator::Object(schema.iter().flat_map(object_iter)),
None => SubresourceIterator::Empty,
}
}

Expand Down
6 changes: 1 addition & 5 deletions crates/jsonschema-referencing/src/specification/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ impl Draft {
Draft::Draft201909 | Draft::Draft202012 => ids::dollar_id(contents),
}
}
#[must_use]
pub fn subresources_of<'a>(
self,
contents: &'a Value,
) -> Box<dyn Iterator<Item = &'a Value> + 'a> {
pub fn subresources_of(self, contents: &Value) -> impl Iterator<Item = &Value> {
match self {
Draft::Draft4 => draft4::subresources_of(contents),
Draft::Draft6 => draft6::subresources_of(contents),
Expand Down
Loading

0 comments on commit 6e69092

Please # to comment.