Skip to content

Commit

Permalink
Return parent base URI when resolving ids
Browse files Browse the repository at this point in the history
This is necessary because `$id` values are joined with the base URI when
the [instance is validated][0] as well as when [ref JSON pointers are
resolved][1]. This returns the parent base URI instead so that calling
`join_uri` later will generate the correct base URI. There's probably a
better way to do this but I get confused thinking it through.

This came up while working on adding support for draft 2019-09, which
has [tests][2] that caused issues. That's where I pulled these tests
from.

[0]: https://github.com/davishmcclurg/json_schemer/blob/c33c1b91ca831c01270cd7d14f927b8727022dee/lib/json_schemer/schema/base.rb#L137
[1]: https://github.com/davishmcclurg/json_schemer/blob/c33c1b91ca831c01270cd7d14f927b8727022dee/lib/json_schemer/schema/base.rb#L340
[2]: https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/b069ac352c3dc1fae71f6f177dafe97001c97920/tests/draft2019-09/refRemote.json#L101-L160
  • Loading branch information
davishmcclurg committed Jun 7, 2023
1 parent 85a3afa commit 5e957a9
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 7 deletions.
16 changes: 9 additions & 7 deletions lib/json_schemer/schema/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,10 @@ def validate_ref(instance, ref, &block)
child(resolve_ref(ref_uri), base_uri: ref_uri)
end

ref_schema, ref_schema_pointer = ref_object.ids[ref_uri] || [ref_object.root, '']
ref_schema, ref_schema_pointer, ref_parent_base_uri = ref_object.ids[ref_uri] || [ref_object.root, '', ref_uri]

ref_uri_pointer_parts = Hana::Pointer.parse(URI.decode_www_form_component(ref_uri_pointer))
schema, base_uri = ref_uri_pointer_parts.reduce([ref_schema, ref_uri]) do |(obj, uri), token|
schema, base_uri = ref_uri_pointer_parts.reduce([ref_schema, ref_parent_base_uri]) do |(obj, uri), token|
if obj.is_a?(Array)
[obj.fetch(token.to_i), uri]
else
Expand Down Expand Up @@ -646,16 +646,18 @@ def resolve_ids(schema, ids = {}, base_uri = @base_uri, pointer = '')
if schema.is_a?(Array)
schema.each_with_index { |subschema, index| resolve_ids(subschema, ids, base_uri, "#{pointer}/#{index}") }
elsif schema.is_a?(Hash)
uri = join_uri(base_uri, schema[id_keyword])
if schema.key?(id_keyword)
parent_base_uri = base_uri
base_uri = join_uri(base_uri, schema[id_keyword])
ids[base_uri] ||= [schema, pointer, parent_base_uri]
end
schema.each do |key, value|
case key
when id_keyword
ids[uri] ||= [schema, pointer]
when 'items', 'allOf', 'anyOf', 'oneOf', 'additionalItems', 'contains', 'additionalProperties', 'propertyNames', 'if', 'then', 'else', 'not'
resolve_ids(value, ids, uri, "#{pointer}/#{key}")
resolve_ids(value, ids, base_uri, "#{pointer}/#{key}")
when 'properties', 'patternProperties', 'definitions', 'dependencies'
value.each do |subkey, subvalue|
resolve_ids(subvalue, ids, uri, "#{pointer}/#{key}/#{subkey}")
resolve_ids(subvalue, ids, base_uri, "#{pointer}/#{key}/#{subkey}")
end
end
end
Expand Down
62 changes: 62 additions & 0 deletions test/ref_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,66 @@ def test_it_handles_windows_paths
refute(schema.valid?(1))
end
end

def test_it_handles_base_uri_change_folder
schema = JSONSchemer.schema(
{
'$id' => 'http://localhost:1234/draft2019-09/scope_change_defs1.json',
'type' => 'object',
'definitions' => {
'baz' => {
'$id' => 'baseUriChangeFolder/',
'type' => 'array',
'items' => {
'$ref' => 'folderInteger.json'
}
}
},
'properties' => {
'list' => {
'$ref' => 'baseUriChangeFolder/'
}
}
},
:ref_resolver => proc do |uri|
assert_equal(URI('http://localhost:1234/draft2019-09/baseUriChangeFolder/folderInteger.json'), uri)
'{ "type": "integer" }'
end
)
assert(schema.valid?({ 'list' => [1] }))
refute(schema.valid?({ 'list' => ['a'] }))
end

def test_it_handles_base_uri_change_folder_in_subschema
schema = JSONSchemer.schema(
{
'$id' => 'http://localhost:1234/draft2019-09/scope_change_defs2.json',
'type' => 'object',
'definitions' => {
'baz' => {
'$id' => 'baseUriChangeFolderInSubschema/',
'definitions' => {
'bar' => {
'type' => 'array',
'items' => {
'$ref' => 'folderInteger.json'
}
}
}
}
},
'properties' => {
'list' => {
'$ref' => 'baseUriChangeFolderInSubschema/#/definitions/bar'
}
}
},
:ref_resolver => proc do |uri|
assert_equal(URI('http://localhost:1234/draft2019-09/baseUriChangeFolderInSubschema/folderInteger.json'), uri)
'{ "type": "integer" }'
end
)
assert(schema.valid?({ 'list' => [1] }))
refute(schema.valid?({ 'list' => ['a'] }))
end
end

0 comments on commit 5e957a9

Please sign in to comment.