Skip to content

Commit

Permalink
Use default base URI for exclusive refs
Browse files Browse the repository at this point in the history
In drafts 7 and earlier, all keywords except `definitions` are ignored
when `$ref` is present. This includes `$id`, which means refs are
resolved using the schema's inherited base URI (default or parent).
Currently, when `$id` is present, the inherited base URI isn't being
registered as a ref resolution resource (with `ID_KEYWORD_CLASS.new`),
which causes JSON pointer ref resolution to fail. The fix here is to add
the exclusive ref case for the `ID_KEYWORD_CLASS.new` call.

The rest of the changes are from if/else cleanup.

Closes: #146
  • Loading branch information
davishmcclurg committed Oct 13, 2023
1 parent 4fafc60 commit e73f9fe
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 19 deletions.
37 changes: 18 additions & 19 deletions lib/json_schemer/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -329,28 +329,27 @@ def parse
VOCABULARY_KEYWORD_CLASS.new(vocabulary, self, '$vocabulary')
end

if root == self && (!value.is_a?(Hash) || !value.key?(meta_schema.id_keyword))
keywords = meta_schema.keywords
exclusive_ref = value.is_a?(Hash) && value.key?('$ref') && keywords.fetch('$ref').exclusive?

if root == self && (!value.is_a?(Hash) || !value.key?(meta_schema.id_keyword) || exclusive_ref)
ID_KEYWORD_CLASS.new(base_uri, self, meta_schema.id_keyword)
end

if value.is_a?(Hash)
keywords = meta_schema.keywords

if value.key?('$ref') && keywords.fetch('$ref').exclusive?
@parsed['$ref'] = keywords.fetch('$ref').new(value.fetch('$ref'), self, '$ref')
defs_keyword = meta_schema.defs_keyword
if value.key?(defs_keyword) && keywords.key?(defs_keyword)
@parsed[defs_keyword] = keywords.fetch(defs_keyword).new(value.fetch(defs_keyword), self, defs_keyword)
end
else
keyword_order = meta_schema.keyword_order
last = keywords.size

value.sort do |(keyword_a, _value_a), (keyword_b, _value_b)|
keyword_order.fetch(keyword_a, last) <=> keyword_order.fetch(keyword_b, last)
end.each do |keyword, value|
@parsed[keyword] ||= keywords.fetch(keyword, UNKNOWN_KEYWORD_CLASS).new(value, self, keyword)
end
if exclusive_ref
@parsed['$ref'] = keywords.fetch('$ref').new(value.fetch('$ref'), self, '$ref')
defs_keyword = meta_schema.defs_keyword
if value.key?(defs_keyword) && keywords.key?(defs_keyword)
@parsed[defs_keyword] = keywords.fetch(defs_keyword).new(value.fetch(defs_keyword), self, defs_keyword)
end
elsif value.is_a?(Hash)
keyword_order = meta_schema.keyword_order
last = keywords.size

value.sort do |(keyword_a, _value_a), (keyword_b, _value_b)|
keyword_order.fetch(keyword_a, last) <=> keyword_order.fetch(keyword_b, last)
end.each do |keyword, value|
@parsed[keyword] ||= keywords.fetch(keyword, UNKNOWN_KEYWORD_CLASS).new(value, self, keyword)
end
end

Expand Down
16 changes: 16 additions & 0 deletions test/ref_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,20 @@ def test_exclusive_ref_supports_definitions
assert(schema.valid?(1))
refute(schema.valid?('1'))
end

def test_exclusive_ref_supports_definitions_with_id_and_json_pointer
schema = JSONSchemer.schema({
'$schema' => 'http://json-schema.org/draft-07/schema#',
'$id' => 'https://example.com/schema',
'$ref' => '#/definitions/yah',
'definitions' => {
'yah' => {
'$id' => '#yah',
'type' => 'integer'
}
}
})
assert(schema.valid?(1))
refute(schema.valid?('1'))
end
end

0 comments on commit e73f9fe

Please sign in to comment.