Skip to content

Commit b1f418c

Browse files
committed
wip
Signed-off-by: Dmitry Dygalo <dmitry@dygalo.dev>
1 parent 437f7fb commit b1f418c

File tree

9 files changed

+1168
-169
lines changed

9 files changed

+1168
-169
lines changed

crates/jsonschema-referencing/src/registry.rs

Lines changed: 269 additions & 21 deletions
Large diffs are not rendered by default.

crates/jsonschema-referencing/src/specification/draft201909.rs

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,66 @@
11
use serde_json::{Map, Value};
22

33
use crate::{
4-
specification::{BorrowedReferenceSlots, Draft},
4+
specification::{BorrowedReferenceSlots, Draft, OwnedObjectGate, OwnedScratchChild},
55
Error, JsonPointerNode, Resolver, ResourceRef, Segments,
66
};
77

88
use super::subresources::{self, SubresourceIteratorInner};
99

10+
pub(crate) fn owned_object_gate_map(schema: &Map<String, Value>) -> OwnedObjectGate<'_> {
11+
let mut id = None;
12+
let mut has_anchor = false;
13+
let mut ref_ = None;
14+
let mut schema_ref = None;
15+
let mut has_children = false;
16+
17+
for (key, value) in schema {
18+
match key.as_str() {
19+
"$id" => id = value.as_str(),
20+
"$anchor" => has_anchor |= value.as_str().is_some(),
21+
"$ref" => ref_ = value.as_str(),
22+
"$schema" => schema_ref = value.as_str(),
23+
"additionalItems"
24+
| "additionalProperties"
25+
| "contains"
26+
| "contentSchema"
27+
| "else"
28+
| "if"
29+
| "not"
30+
| "propertyNames"
31+
| "then"
32+
| "unevaluatedItems"
33+
| "unevaluatedProperties" => has_children = true,
34+
"allOf" | "anyOf" | "oneOf" => {
35+
has_children |= value.as_array().is_some_and(|items| !items.is_empty());
36+
}
37+
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
38+
has_children |= value.as_object().is_some_and(|items| !items.is_empty());
39+
}
40+
"items" => {
41+
has_children |= match value {
42+
Value::Array(items) => !items.is_empty(),
43+
_ => true,
44+
};
45+
}
46+
"dependencies" => {
47+
has_children |= value
48+
.as_object()
49+
.is_some_and(|items| items.values().any(Value::is_object));
50+
}
51+
_ => {}
52+
}
53+
}
54+
55+
OwnedObjectGate {
56+
id,
57+
has_anchor,
58+
ref_,
59+
schema: schema_ref,
60+
has_children,
61+
}
62+
}
63+
1064
pub(crate) fn scan_borrowed_object_into_scratch_map<'a>(
1165
schema: &'a Map<String, Value>,
1266
draft: Draft,
@@ -75,6 +129,105 @@ pub(crate) fn scan_borrowed_object_into_scratch_map<'a>(
75129
}
76130
}
77131

132+
pub(crate) fn scan_owned_object_into_scratch_map<'a>(
133+
schema: &'a Map<String, Value>,
134+
draft: Draft,
135+
references: &mut BorrowedReferenceSlots<'a>,
136+
children: &mut Vec<OwnedScratchChild<'a>>,
137+
) -> (Option<&'a str>, bool) {
138+
let mut id = None;
139+
let mut has_anchor = false;
140+
141+
for (key, value) in schema {
142+
match key.as_str() {
143+
"$id" => id = value.as_str(),
144+
"$anchor" => has_anchor |= value.as_str().is_some(),
145+
"$ref" => {
146+
if let Some(reference) = value.as_str() {
147+
references.ref_ = Some(reference);
148+
}
149+
}
150+
"$schema" => {
151+
if let Some(reference) = value.as_str() {
152+
references.schema = Some(reference);
153+
}
154+
}
155+
"additionalItems"
156+
| "additionalProperties"
157+
| "contains"
158+
| "contentSchema"
159+
| "else"
160+
| "if"
161+
| "not"
162+
| "propertyNames"
163+
| "then"
164+
| "unevaluatedItems"
165+
| "unevaluatedProperties" => {
166+
children.push(OwnedScratchChild::key(
167+
key.as_str(),
168+
value,
169+
draft.detect(value),
170+
));
171+
}
172+
"allOf" | "anyOf" | "oneOf" => {
173+
if let Some(arr) = value.as_array() {
174+
for (index, item) in arr.iter().enumerate() {
175+
children.push(OwnedScratchChild::key_index(
176+
key.as_str(),
177+
index,
178+
item,
179+
draft.detect(item),
180+
));
181+
}
182+
}
183+
}
184+
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
185+
if let Some(obj) = value.as_object() {
186+
for (child_key, child_value) in obj {
187+
children.push(OwnedScratchChild::key_key(
188+
key.as_str(),
189+
child_key.as_str(),
190+
child_value,
191+
draft.detect(child_value),
192+
));
193+
}
194+
}
195+
}
196+
"items" => match value {
197+
Value::Array(arr) => {
198+
for (index, item) in arr.iter().enumerate() {
199+
children.push(OwnedScratchChild::key_index(
200+
"items",
201+
index,
202+
item,
203+
draft.detect(item),
204+
));
205+
}
206+
}
207+
_ => children.push(OwnedScratchChild::key("items", value, draft.detect(value))),
208+
},
209+
"dependencies" => {
210+
if let Some(obj) = value.as_object() {
211+
for (child_key, child_value) in obj {
212+
if !child_value.is_object() {
213+
continue;
214+
}
215+
children.push(OwnedScratchChild::key_key(
216+
key.as_str(),
217+
child_key.as_str(),
218+
child_value,
219+
draft.detect(child_value),
220+
));
221+
}
222+
}
223+
}
224+
_ => {}
225+
}
226+
}
227+
228+
(id, has_anchor)
229+
}
230+
78231
pub(crate) fn walk_borrowed_subresources_map<'a, E, F>(
79232
schema: &'a Map<String, Value>,
80233
draft: Draft,

crates/jsonschema-referencing/src/specification/draft4.rs

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,69 @@
11
use serde_json::{Map, Value};
22

33
use crate::{
4-
specification::{BorrowedReferenceSlots, Draft},
4+
specification::{BorrowedReferenceSlots, Draft, OwnedObjectGate, OwnedScratchChild},
55
Error, JsonPointerNode, Resolver, ResourceRef, Segments,
66
};
77

88
use super::subresources::{self, SubresourceIteratorInner};
99

10+
pub(crate) fn owned_object_gate_map(schema: &Map<String, Value>) -> OwnedObjectGate<'_> {
11+
let mut raw_id = None;
12+
let mut ref_ = None;
13+
let mut schema_ref = None;
14+
let mut has_children = false;
15+
16+
for (key, value) in schema {
17+
match key.as_str() {
18+
"id" => raw_id = value.as_str(),
19+
"$ref" => ref_ = value.as_str(),
20+
"$schema" => schema_ref = value.as_str(),
21+
"additionalItems" | "additionalProperties" => has_children |= value.is_object(),
22+
"contains"
23+
| "contentSchema"
24+
| "else"
25+
| "if"
26+
| "not"
27+
| "propertyNames"
28+
| "then"
29+
| "unevaluatedItems"
30+
| "unevaluatedProperties" => has_children = true,
31+
"allOf" | "anyOf" | "oneOf" | "prefixItems" => {
32+
has_children |= value.as_array().is_some_and(|items| !items.is_empty());
33+
}
34+
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
35+
has_children |= value.as_object().is_some_and(|items| !items.is_empty());
36+
}
37+
"items" => {
38+
has_children |= match value {
39+
Value::Array(items) => !items.is_empty(),
40+
_ => true,
41+
};
42+
}
43+
"dependencies" => {
44+
has_children |= value
45+
.as_object()
46+
.is_some_and(|items| items.values().any(Value::is_object));
47+
}
48+
_ => {}
49+
}
50+
}
51+
52+
let has_anchor = raw_id.is_some_and(|id| id.starts_with('#'));
53+
let id = match raw_id {
54+
Some(id) if !has_anchor && ref_.is_none() => Some(id),
55+
_ => None,
56+
};
57+
58+
OwnedObjectGate {
59+
id,
60+
has_anchor,
61+
ref_,
62+
schema: schema_ref,
63+
has_children,
64+
}
65+
}
66+
1067
pub(crate) fn scan_borrowed_object_into_scratch_map<'a>(
1168
schema: &'a Map<String, Value>,
1269
draft: Draft,
@@ -84,6 +141,115 @@ pub(crate) fn scan_borrowed_object_into_scratch_map<'a>(
84141
}
85142
}
86143

144+
pub(crate) fn scan_owned_object_into_scratch_map<'a>(
145+
schema: &'a Map<String, Value>,
146+
draft: Draft,
147+
references: &mut BorrowedReferenceSlots<'a>,
148+
children: &mut Vec<OwnedScratchChild<'a>>,
149+
) -> (Option<&'a str>, bool) {
150+
let mut raw_id = None;
151+
let mut has_ref = false;
152+
153+
for (key, value) in schema {
154+
match key.as_str() {
155+
"id" => raw_id = value.as_str(),
156+
"$ref" => {
157+
if let Some(reference) = value.as_str() {
158+
has_ref = true;
159+
references.ref_ = Some(reference);
160+
}
161+
}
162+
"$schema" => {
163+
if let Some(reference) = value.as_str() {
164+
references.schema = Some(reference);
165+
}
166+
}
167+
"additionalItems" | "additionalProperties" if value.is_object() => {
168+
children.push(OwnedScratchChild::key(
169+
key.as_str(),
170+
value,
171+
draft.detect(value),
172+
));
173+
}
174+
"contains"
175+
| "contentSchema"
176+
| "else"
177+
| "if"
178+
| "not"
179+
| "propertyNames"
180+
| "then"
181+
| "unevaluatedItems"
182+
| "unevaluatedProperties" => {
183+
children.push(OwnedScratchChild::key(
184+
key.as_str(),
185+
value,
186+
draft.detect(value),
187+
));
188+
}
189+
"allOf" | "anyOf" | "oneOf" | "prefixItems" => {
190+
if let Some(arr) = value.as_array() {
191+
for (index, item) in arr.iter().enumerate() {
192+
children.push(OwnedScratchChild::key_index(
193+
key.as_str(),
194+
index,
195+
item,
196+
draft.detect(item),
197+
));
198+
}
199+
}
200+
}
201+
"$defs" | "definitions" | "dependentSchemas" | "patternProperties" | "properties" => {
202+
if let Some(obj) = value.as_object() {
203+
for (child_key, child_value) in obj {
204+
children.push(OwnedScratchChild::key_key(
205+
key.as_str(),
206+
child_key.as_str(),
207+
child_value,
208+
draft.detect(child_value),
209+
));
210+
}
211+
}
212+
}
213+
"items" => match value {
214+
Value::Array(arr) => {
215+
for (index, item) in arr.iter().enumerate() {
216+
children.push(OwnedScratchChild::key_index(
217+
"items",
218+
index,
219+
item,
220+
draft.detect(item),
221+
));
222+
}
223+
}
224+
_ => children.push(OwnedScratchChild::key("items", value, draft.detect(value))),
225+
},
226+
"dependencies" => {
227+
if let Some(obj) = value.as_object() {
228+
for (child_key, child_value) in obj {
229+
if !child_value.is_object() {
230+
continue;
231+
}
232+
children.push(OwnedScratchChild::key_key(
233+
key.as_str(),
234+
child_key.as_str(),
235+
child_value,
236+
draft.detect(child_value),
237+
));
238+
}
239+
}
240+
}
241+
_ => {}
242+
}
243+
}
244+
245+
let has_anchor = raw_id.is_some_and(|id| id.starts_with('#'));
246+
let id = match raw_id {
247+
Some(id) if !has_anchor && !has_ref => Some(id),
248+
_ => None,
249+
};
250+
(id, has_anchor)
251+
}
252+
87253
pub(crate) fn walk_borrowed_subresources_map<'a, E, F>(
88254
schema: &'a Map<String, Value>,
89255
draft: Draft,

0 commit comments

Comments
 (0)