json-schema 3.0.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +15 -1
- data/lib/json-schema/attribute.rb +13 -14
- data/lib/json-schema/attributes/additionalitems.rb +1 -0
- data/lib/json-schema/attributes/additionalproperties.rb +3 -6
- data/lib/json-schema/attributes/allof.rb +6 -4
- data/lib/json-schema/attributes/anyof.rb +2 -2
- data/lib/json-schema/attributes/dependencies.rb +1 -0
- data/lib/json-schema/attributes/disallow.rb +2 -1
- data/lib/json-schema/attributes/enum.rb +2 -2
- data/lib/json-schema/attributes/extends.rb +6 -6
- data/lib/json-schema/attributes/format.rb +2 -1
- data/lib/json-schema/attributes/formats/date.rb +1 -0
- data/lib/json-schema/attributes/formats/date_time.rb +2 -1
- data/lib/json-schema/attributes/formats/date_time_v4.rb +1 -0
- data/lib/json-schema/attributes/formats/uri.rb +1 -0
- data/lib/json-schema/attributes/items.rb +1 -0
- data/lib/json-schema/attributes/limits/numeric.rb +1 -1
- data/lib/json-schema/attributes/maxdecimal.rb +1 -1
- data/lib/json-schema/attributes/not.rb +2 -2
- data/lib/json-schema/attributes/oneof.rb +2 -4
- data/lib/json-schema/attributes/patternproperties.rb +1 -0
- data/lib/json-schema/attributes/properties.rb +7 -7
- data/lib/json-schema/attributes/properties_v4.rb +1 -1
- data/lib/json-schema/attributes/propertynames.rb +23 -0
- data/lib/json-schema/attributes/ref.rb +7 -7
- data/lib/json-schema/attributes/required.rb +3 -2
- data/lib/json-schema/attributes/type.rb +3 -2
- data/lib/json-schema/attributes/type_v4.rb +1 -1
- data/lib/json-schema/errors/validation_error.rb +4 -5
- data/lib/json-schema/schema/reader.rb +2 -0
- data/lib/json-schema/schema/validator.rb +3 -3
- data/lib/json-schema/schema.rb +3 -4
- data/lib/json-schema/util/array_set.rb +1 -1
- data/lib/json-schema/util/uri.rb +7 -7
- data/lib/json-schema/util/uuid.rb +227 -226
- data/lib/json-schema/validator.rb +97 -84
- data/lib/json-schema/validators/draft1.rb +21 -23
- data/lib/json-schema/validators/draft2.rb +22 -24
- data/lib/json-schema/validators/draft3.rb +26 -28
- data/lib/json-schema/validators/draft4.rb +34 -36
- data/lib/json-schema/validators/draft6.rb +36 -37
- data/lib/json-schema/validators/hyper-draft1.rb +2 -3
- data/lib/json-schema/validators/hyper-draft2.rb +2 -3
- data/lib/json-schema/validators/hyper-draft3.rb +2 -3
- data/lib/json-schema/validators/hyper-draft4.rb +2 -3
- data/lib/json-schema/validators/hyper-draft6.rb +2 -3
- data/lib/json-schema.rb +2 -2
- data/resources/draft-06.json +12 -12
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b6a5072f20570ae4262df13648a1b637b5db2c02cf881c2728277ea5a203f6d
|
4
|
+
data.tar.gz: 4b92633224b1338d58918e7a2d2f5d3e117fee03409455d6f47ea51c8bef7b18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b5301a03a3fb7d3a43c275858df22d41cface2a465ff2fcfda28c9528f491e6a8f302fbbf52232de68e31d6a32540b9ad8a392fab82ec2b2113980e83119b72
|
7
|
+
data.tar.gz: 16f57a870e6b75280f5376d57785ad94500cbfd50bc3ea9ba01df486d0938c36907114780bacfc4860359e73d7adf87ce5c73205ef52ebea1f829b64d7630906
|
data/README.md
CHANGED
@@ -9,7 +9,8 @@
|
|
9
9
|
|
10
10
|
This library is intended to provide Ruby with an interface for validating JSON
|
11
11
|
objects against a JSON schema conforming to [JSON Schema Draft
|
12
|
-
|
12
|
+
6](https://tools.ietf.org/html/draft-wright-json-schema-01). Legacy support for
|
13
|
+
[JSON Schema Draft 4](http://tools.ietf.org/html/draft-zyp-json-schema-04),
|
13
14
|
[JSON Schema Draft 3](http://tools.ietf.org/html/draft-zyp-json-schema-03),
|
14
15
|
[JSON Schema Draft 2](http://tools.ietf.org/html/draft-zyp-json-schema-02), and
|
15
16
|
[JSON Schema Draft 1](http://tools.ietf.org/html/draft-zyp-json-schema-01) is
|
@@ -240,6 +241,19 @@ JSON::Validator.validate(schema, { "a" => 1 }, :parse_data => false)
|
|
240
241
|
# => false
|
241
242
|
JSON::Validator.validate(schema, '{ "a": 1 }', :parse_data => false)
|
242
243
|
|
244
|
+
#
|
245
|
+
# with the `:parse_integer` option set to false, the integer value given as string will not be parsed.
|
246
|
+
#
|
247
|
+
|
248
|
+
# => true
|
249
|
+
JSON::Validator.validate({type: "integer"}, "23")
|
250
|
+
# => false
|
251
|
+
JSON::Validator.validate({type: "integer"}, "23", parse_integer: false)
|
252
|
+
# => true
|
253
|
+
JSON::Validator.validate({type: "string"}, "123", parse_integer: false)
|
254
|
+
# => false
|
255
|
+
JSON::Validator.validate({type: "string"}, "123")
|
256
|
+
|
243
257
|
#
|
244
258
|
# with the `:json` option, the json must be an unparsed json text (not a hash, a uri or a file path)
|
245
259
|
#
|
@@ -3,8 +3,7 @@ require 'json-schema/errors/validation_error'
|
|
3
3
|
module JSON
|
4
4
|
class Schema
|
5
5
|
class Attribute
|
6
|
-
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
-
end
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {}); end
|
8
7
|
|
9
8
|
def self.build_fragment(fragments)
|
10
9
|
"#/#{fragments.join('/')}"
|
@@ -24,14 +23,14 @@ module JSON
|
|
24
23
|
end
|
25
24
|
|
26
25
|
TYPE_CLASS_MAPPINGS = {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
'string' => String,
|
27
|
+
'number' => Numeric,
|
28
|
+
'integer' => Integer,
|
29
|
+
'boolean' => [TrueClass, FalseClass],
|
30
|
+
'object' => Hash,
|
31
|
+
'array' => Array,
|
32
|
+
'null' => NilClass,
|
33
|
+
'any' => Object,
|
35
34
|
}
|
36
35
|
|
37
36
|
def self.data_valid_for_type?(data, type)
|
@@ -41,11 +40,11 @@ module JSON
|
|
41
40
|
|
42
41
|
# Lookup Schema type of given class instance
|
43
42
|
def self.type_of_data(data)
|
44
|
-
type,
|
43
|
+
type, = TYPE_CLASS_MAPPINGS.map { |k, v| [k, v] }.sort_by do |(_, v)|
|
45
44
|
-Array(v).map { |klass| klass.ancestors.size }.max
|
46
|
-
|
47
|
-
Array(v).any? { |klass| data.
|
48
|
-
|
45
|
+
end.find do |(_, v)|
|
46
|
+
Array(v).any? { |klass| data.is_a?(klass) }
|
47
|
+
end
|
49
48
|
type
|
50
49
|
end
|
51
50
|
end
|
@@ -19,6 +19,7 @@ module JSON
|
|
19
19
|
additional_items_schema = JSON::Schema.new(schema['additionalItems'], current_schema.uri, validator)
|
20
20
|
data.each_with_index do |item, i|
|
21
21
|
next if i < schema['items'].length
|
22
|
+
|
22
23
|
additional_items_schema.validate(item, fragments + [i.to_s], processor, options)
|
23
24
|
end
|
24
25
|
end
|
@@ -33,11 +33,9 @@ module JSON
|
|
33
33
|
extra_properties = extra_properties - schema['properties'].keys
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
extra_properties.reject! { |prop| regexp.match(prop) }
|
40
|
-
end
|
36
|
+
schema['patternProperties']&.each_key do |key|
|
37
|
+
regexp = Regexp.new(key)
|
38
|
+
extra_properties.reject! { |prop| regexp.match(prop) }
|
41
39
|
end
|
42
40
|
|
43
41
|
if extended_schemas = schema['extends']
|
@@ -52,7 +50,6 @@ module JSON
|
|
52
50
|
|
53
51
|
extra_properties
|
54
52
|
end
|
55
|
-
|
56
53
|
end
|
57
54
|
end
|
58
55
|
end
|
@@ -7,18 +7,20 @@ module JSON
|
|
7
7
|
# Create an hash to hold errors that are generated during validation
|
8
8
|
errors = Hash.new { |hsh, k| hsh[k] = [] }
|
9
9
|
valid = true
|
10
|
+
message = nil
|
10
11
|
|
11
12
|
current_schema.schema['allOf'].each_with_index do |element, schema_index|
|
12
|
-
schema = JSON::Schema.new(element,current_schema.uri,validator)
|
13
|
+
schema = JSON::Schema.new(element, current_schema.uri, validator)
|
13
14
|
|
14
15
|
# We're going to add a little cruft here to try and maintain any validation errors that occur in the allOf
|
15
16
|
# We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto an error array
|
16
17
|
pre_validation_error_count = validation_errors(processor).count
|
17
18
|
|
18
19
|
begin
|
19
|
-
schema.validate(data,fragments,processor,options)
|
20
|
-
rescue ValidationError
|
20
|
+
schema.validate(data, fragments, processor, options)
|
21
|
+
rescue ValidationError => e
|
21
22
|
valid = false
|
23
|
+
message = e.message
|
22
24
|
end
|
23
25
|
|
24
26
|
diff = validation_errors(processor).count - pre_validation_error_count
|
@@ -29,7 +31,7 @@ module JSON
|
|
29
31
|
end
|
30
32
|
|
31
33
|
if !valid || !errors.empty?
|
32
|
-
message
|
34
|
+
message ||= "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match all of the required schemas"
|
33
35
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
34
36
|
validation_errors(processor).last.sub_errors = errors
|
35
37
|
end
|
@@ -11,14 +11,14 @@ module JSON
|
|
11
11
|
original_data = data.is_a?(Hash) ? data.clone : data
|
12
12
|
|
13
13
|
current_schema.schema['anyOf'].each_with_index do |element, schema_index|
|
14
|
-
schema = JSON::Schema.new(element,current_schema.uri,validator)
|
14
|
+
schema = JSON::Schema.new(element, current_schema.uri, validator)
|
15
15
|
|
16
16
|
# We're going to add a little cruft here to try and maintain any validation errors that occur in the anyOf
|
17
17
|
# We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto a union error
|
18
18
|
pre_validation_error_count = validation_errors(processor).count
|
19
19
|
|
20
20
|
begin
|
21
|
-
schema.validate(data,fragments,processor,options)
|
21
|
+
schema.validate(data, fragments, processor, options)
|
22
22
|
valid = true
|
23
23
|
rescue ValidationError
|
24
24
|
# We don't care that these schemas don't validate - we only care that one validated
|
@@ -26,6 +26,7 @@ module JSON
|
|
26
26
|
|
27
27
|
def self.validate_dependency(schema, data, property, value, fragments, processor, attribute, options)
|
28
28
|
return if data.key?(value.to_s)
|
29
|
+
|
29
30
|
message = "The property '#{build_fragment(fragments)}' has a property '#{property}' that depends on a missing property '#{value}'"
|
30
31
|
validation_error(processor, message, fragments, schema, attribute, options[:record_errors])
|
31
32
|
end
|
@@ -5,7 +5,8 @@ module JSON
|
|
5
5
|
class DisallowAttribute < Attribute
|
6
6
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
7
|
return unless type = validator.attributes['type']
|
8
|
-
|
8
|
+
|
9
|
+
type.validate(current_schema, data, fragments, processor, validator, options.merge(disallow: true))
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -7,14 +7,14 @@ module JSON
|
|
7
7
|
enum = current_schema.schema['enum']
|
8
8
|
return if enum.include?(data)
|
9
9
|
|
10
|
-
values = enum.map
|
10
|
+
values = enum.map do |val|
|
11
11
|
case val
|
12
12
|
when nil then 'null'
|
13
13
|
when Array then 'array'
|
14
14
|
when Hash then 'object'
|
15
15
|
else val.to_s
|
16
16
|
end
|
17
|
-
|
17
|
+
end.join(', ')
|
18
18
|
|
19
19
|
message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match one of the following values: #{values}"
|
20
20
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
@@ -8,7 +8,7 @@ module JSON
|
|
8
8
|
schemas = current_schema.schema['extends']
|
9
9
|
schemas = [schemas] if !schemas.is_a?(Array)
|
10
10
|
schemas.each do |s|
|
11
|
-
uri,schema = get_extended_uri_and_schema(s, current_schema, validator)
|
11
|
+
uri, schema = get_extended_uri_and_schema(s, current_schema, validator)
|
12
12
|
if schema
|
13
13
|
schema.validate(data, fragments, processor, options)
|
14
14
|
elsif uri
|
@@ -22,15 +22,15 @@ module JSON
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.get_extended_uri_and_schema(s, current_schema, validator)
|
25
|
-
uri,schema = nil,nil
|
25
|
+
uri, schema = nil, nil
|
26
26
|
|
27
27
|
if s.is_a?(Hash)
|
28
28
|
uri = current_schema.uri
|
29
29
|
if s['$ref']
|
30
|
-
ref_uri,ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator)
|
30
|
+
ref_uri, ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator)
|
31
31
|
if ref_schema
|
32
32
|
if s.size == 1 # Check if anything else apart from $ref
|
33
|
-
uri,schema = ref_uri,ref_schema
|
33
|
+
uri, schema = ref_uri, ref_schema
|
34
34
|
else
|
35
35
|
s = s.dup
|
36
36
|
s.delete '$ref'
|
@@ -38,10 +38,10 @@ module JSON
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
schema ||= JSON::Schema.new(s,uri,validator)
|
41
|
+
schema ||= JSON::Schema.new(s, uri, validator)
|
42
42
|
end
|
43
43
|
|
44
|
-
[uri,schema]
|
44
|
+
[uri, schema]
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -5,9 +5,10 @@ module JSON
|
|
5
5
|
class FormatAttribute < Attribute
|
6
6
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
7
|
return unless data_valid_for_type?(data, current_schema.schema['type'])
|
8
|
+
|
8
9
|
format = current_schema.schema['format'].to_s
|
9
10
|
validator = validator.formats[format]
|
10
|
-
validator
|
11
|
+
validator&.validate(current_schema, data, fragments, processor, validator, options)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
@@ -10,12 +10,13 @@ module JSON
|
|
10
10
|
if data.is_a?(String)
|
11
11
|
error_message = "The property '#{build_fragment(fragments)}' must be a date/time in the ISO-8601 format of YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss.ssZ"
|
12
12
|
if (m = REGEXP.match(data))
|
13
|
-
parts = data.split(
|
13
|
+
parts = data.split('T')
|
14
14
|
|
15
15
|
begin
|
16
16
|
Date.parse(parts[0])
|
17
17
|
rescue ArgumentError => e
|
18
18
|
raise e unless e.message == 'invalid date'
|
19
|
+
|
19
20
|
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
20
21
|
return
|
21
22
|
end
|
@@ -5,6 +5,7 @@ module JSON
|
|
5
5
|
class DateTimeV4Format < FormatAttribute
|
6
6
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
7
|
return unless data.is_a?(String)
|
8
|
+
|
8
9
|
DateTime.rfc3339(data)
|
9
10
|
rescue ArgumentError
|
10
11
|
error_message = "The property '#{build_fragment(fragments)}' must be a valid RFC3339 date/time string"
|
@@ -6,6 +6,7 @@ module JSON
|
|
6
6
|
class UriFormat < FormatAttribute
|
7
7
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
8
8
|
return unless data.is_a?(String)
|
9
|
+
|
9
10
|
error_message = "The property '#{build_fragment(fragments)}' must be a valid URI"
|
10
11
|
begin
|
11
12
|
JSON::Util::URI.parse(data)
|
@@ -9,7 +9,7 @@ module JSON
|
|
9
9
|
|
10
10
|
def self.error_message(schema)
|
11
11
|
exclusivity = exclusive?(schema) ? 'exclusively' : 'inclusively'
|
12
|
-
format(
|
12
|
+
format('did not have a %s value of %s, %s', limit_name, limit(schema), exclusivity)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -7,7 +7,7 @@ module JSON
|
|
7
7
|
return unless data.is_a?(Numeric)
|
8
8
|
|
9
9
|
max_decimal_places = current_schema.schema['maxDecimal']
|
10
|
-
s = data.to_s.split(
|
10
|
+
s = data.to_s.split('.')[1]
|
11
11
|
if s && s.length > max_decimal_places
|
12
12
|
message = "The property '#{build_fragment(fragments)}' had more decimal places than the allowed #{max_decimal_places}"
|
13
13
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
@@ -4,12 +4,12 @@ module JSON
|
|
4
4
|
class Schema
|
5
5
|
class NotAttribute < Attribute
|
6
6
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
-
schema = JSON::Schema.new(current_schema.schema['not'],current_schema.uri,validator)
|
7
|
+
schema = JSON::Schema.new(current_schema.schema['not'], current_schema.uri, validator)
|
8
8
|
failed = true
|
9
9
|
errors_copy = processor.validation_errors.clone
|
10
10
|
|
11
11
|
begin
|
12
|
-
schema.validate(data,fragments,processor,options)
|
12
|
+
schema.validate(data, fragments, processor, options)
|
13
13
|
# If we're recording errors, we don't throw an exception. Instead, check the errors array length
|
14
14
|
if options[:record_errors] && errors_copy.length != processor.validation_errors.length
|
15
15
|
processor.validation_errors.replace(errors_copy)
|
@@ -15,10 +15,10 @@ module JSON
|
|
15
15
|
valid = false
|
16
16
|
|
17
17
|
one_of.each_with_index do |element, schema_index|
|
18
|
-
schema = JSON::Schema.new(element,current_schema.uri,validator)
|
18
|
+
schema = JSON::Schema.new(element, current_schema.uri, validator)
|
19
19
|
pre_validation_error_count = validation_errors(processor).count
|
20
20
|
begin
|
21
|
-
schema.validate(data,fragments,processor,options)
|
21
|
+
schema.validate(data, fragments, processor, options)
|
22
22
|
success_data = data.is_a?(Hash) ? data.clone : data
|
23
23
|
valid = true
|
24
24
|
rescue ValidationError
|
@@ -35,8 +35,6 @@ module JSON
|
|
35
35
|
data = original_data
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
38
|
if validation_error_count == one_of.length - 1
|
41
39
|
data = success_data
|
42
40
|
return
|
@@ -12,6 +12,7 @@ module JSON
|
|
12
12
|
# Check each key in the data hash to see if it matches the regex
|
13
13
|
data.each do |key, value|
|
14
14
|
next unless regexp.match(key)
|
15
|
+
|
15
16
|
schema = JSON::Schema.new(property_schema, current_schema.uri, validator)
|
16
17
|
schema.validate(data[key], fragments + [key], processor, options)
|
17
18
|
end
|
@@ -4,7 +4,7 @@ module JSON
|
|
4
4
|
class Schema
|
5
5
|
class PropertiesAttribute < Attribute
|
6
6
|
def self.required?(schema, options)
|
7
|
-
schema.fetch('required') { options[:
|
7
|
+
schema.fetch('required') { options[:allPropertiesRequired] }
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
@@ -15,9 +15,9 @@ module JSON
|
|
15
15
|
property = property.to_s
|
16
16
|
|
17
17
|
if !data.key?(property) &&
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
options[:insert_defaults] &&
|
19
|
+
property_schema.has_key?('default') &&
|
20
|
+
!property_schema['readonly']
|
21
21
|
default = property_schema['default']
|
22
22
|
data[property] = default.is_a?(Hash) ? default.clone : default
|
23
23
|
end
|
@@ -33,8 +33,8 @@ module JSON
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# When
|
37
|
-
return unless options[:
|
36
|
+
# When noAdditionalProperties is true, ensure no undefined properties exist in the data
|
37
|
+
return unless options[:noAdditionalProperties] == true && !schema.key?('additionalProperties')
|
38
38
|
|
39
39
|
diff = data.select do |k, v|
|
40
40
|
k = k.to_s
|
@@ -55,7 +55,7 @@ module JSON
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
unless diff.empty?
|
59
59
|
properties = diff.keys.join(', ')
|
60
60
|
message = "The property '#{build_fragment(fragments)}' contained undefined properties: '#{properties}'"
|
61
61
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
@@ -6,7 +6,7 @@ module JSON
|
|
6
6
|
# draft4 relies on its own RequiredAttribute validation at a higher level, rather than
|
7
7
|
# as an attribute of individual properties.
|
8
8
|
def self.required?(schema, options)
|
9
|
-
options[:
|
9
|
+
options[:allPropertiesRequired] == true
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class PropertyNames < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Hash)
|
8
|
+
|
9
|
+
propnames = current_schema.schema['propertyNames']
|
10
|
+
|
11
|
+
if propnames.is_a?(Hash)
|
12
|
+
schema = JSON::Schema.new(propnames, current_schema.uri, validator)
|
13
|
+
data.each_key do |key|
|
14
|
+
schema.validate(key, fragments + [key], processor, options)
|
15
|
+
end
|
16
|
+
elsif propnames == false && data.any?
|
17
|
+
message = "The property '#{build_fragment(fragments)}' contains additional properties #{data.keys.inspect} outside of the schema when none are allowed"
|
18
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -6,7 +6,7 @@ module JSON
|
|
6
6
|
class Schema
|
7
7
|
class RefAttribute < Attribute
|
8
8
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
9
|
-
uri,schema = get_referenced_uri_and_schema(current_schema.schema, current_schema, validator)
|
9
|
+
uri, schema = get_referenced_uri_and_schema(current_schema.schema, current_schema, validator)
|
10
10
|
|
11
11
|
if schema
|
12
12
|
schema.validate(data, fragments, processor, options)
|
@@ -20,19 +20,19 @@ module JSON
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.get_referenced_uri_and_schema(s, current_schema, validator)
|
23
|
-
uri,schema = nil,nil
|
23
|
+
uri, schema = nil, nil
|
24
24
|
|
25
25
|
temp_uri = JSON::Util::URI.normalize_ref(s['$ref'], current_schema.uri)
|
26
26
|
|
27
27
|
# Grab the parent schema from the schema list
|
28
|
-
schema_key = temp_uri.to_s.split(
|
28
|
+
schema_key = temp_uri.to_s.split('#')[0] + '#'
|
29
29
|
|
30
30
|
ref_schema = JSON::Validator.schema_for_uri(schema_key)
|
31
31
|
|
32
32
|
if ref_schema
|
33
33
|
# Perform fragment resolution to retrieve the appropriate level for the schema
|
34
34
|
target_schema = ref_schema.schema
|
35
|
-
fragments = JSON::Util::URI.parse(JSON::Util::URI.unescape_uri(temp_uri)).fragment.split(
|
35
|
+
fragments = JSON::Util::URI.parse(JSON::Util::URI.unescape_uri(temp_uri)).fragment.split('/')
|
36
36
|
fragment_path = ''
|
37
37
|
fragments.each do |fragment|
|
38
38
|
if fragment && fragment != ''
|
@@ -44,17 +44,17 @@ module JSON
|
|
44
44
|
end
|
45
45
|
fragment_path = fragment_path + "/#{fragment}"
|
46
46
|
if target_schema.nil?
|
47
|
-
raise SchemaError
|
47
|
+
raise SchemaError, "The fragment '#{fragment_path}' does not exist on schema #{ref_schema.uri.to_s}"
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
# We have the schema finally, build it and validate!
|
53
53
|
uri = temp_uri
|
54
|
-
schema = JSON::Schema.new(target_schema,temp_uri,validator)
|
54
|
+
schema = JSON::Schema.new(target_schema, temp_uri, validator)
|
55
55
|
end
|
56
56
|
|
57
|
-
[uri,schema]
|
57
|
+
[uri, schema]
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -11,11 +11,12 @@ module JSON
|
|
11
11
|
|
12
12
|
schema['required'].each do |property, property_schema|
|
13
13
|
next if data.has_key?(property.to_s)
|
14
|
+
|
14
15
|
prop_defaults = options[:insert_defaults] &&
|
15
16
|
defined_properties &&
|
16
17
|
defined_properties[property] &&
|
17
|
-
!defined_properties[property][
|
18
|
-
!defined_properties[property][
|
18
|
+
!defined_properties[property]['default'].nil? &&
|
19
|
+
!defined_properties[property]['readonly']
|
19
20
|
|
20
21
|
if !prop_defaults
|
21
22
|
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
@@ -25,14 +25,14 @@ module JSON
|
|
25
25
|
valid = data_valid_for_type?(data, type)
|
26
26
|
elsif type.is_a?(Hash) && union
|
27
27
|
# Validate as a schema
|
28
|
-
schema = JSON::Schema.new(type,current_schema.uri,validator)
|
28
|
+
schema = JSON::Schema.new(type, current_schema.uri, validator)
|
29
29
|
|
30
30
|
# We're going to add a little cruft here to try and maintain any validation errors that occur in this union type
|
31
31
|
# We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto a union error
|
32
32
|
pre_validation_error_count = validation_errors(processor).count
|
33
33
|
|
34
34
|
begin
|
35
|
-
schema.validate(data,fragments,processor,options.merge(:
|
35
|
+
schema.validate(data, fragments, processor, options.merge(disallow: false))
|
36
36
|
valid = true
|
37
37
|
rescue ValidationError
|
38
38
|
# We don't care that these schemas don't validate - we only care that one validated
|
@@ -51,6 +51,7 @@ module JSON
|
|
51
51
|
|
52
52
|
if options[:disallow]
|
53
53
|
return if !valid
|
54
|
+
|
54
55
|
message = "The property '#{build_fragment(fragments)}' matched one or more of the following types: #{list_types(types)}"
|
55
56
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
56
57
|
elsif !valid
|
@@ -19,7 +19,7 @@ module JSON
|
|
19
19
|
build_fragment(fragments),
|
20
20
|
type_of_data(data),
|
21
21
|
union ? 'one or more of the following types' : 'the following type',
|
22
|
-
types
|
22
|
+
types,
|
23
23
|
)
|
24
24
|
|
25
25
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module JSON
|
2
2
|
class Schema
|
3
3
|
class ValidationError < StandardError
|
4
|
-
INDENT =
|
4
|
+
INDENT = ' '
|
5
5
|
attr_accessor :fragments, :schema, :failed_attribute, :sub_errors, :message
|
6
6
|
|
7
7
|
def initialize(message, fragments, failed_attribute, schema)
|
@@ -27,12 +27,11 @@ module JSON
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def to_hash
|
30
|
-
base = {:
|
30
|
+
base = { schema: @schema.uri, fragment: ::JSON::Schema::Attribute.build_fragment(fragments), message: message_with_schema, failed_attribute: @failed_attribute.to_s.split(':').last.split('Attribute').first }
|
31
31
|
if !@sub_errors.empty?
|
32
|
-
base[:errors] = @sub_errors.
|
32
|
+
base[:errors] = @sub_errors.each_with_object({}) do |(subschema, errors), hsh|
|
33
33
|
subschema_sym = subschema.downcase.gsub(/\W+/, '_').to_sym
|
34
|
-
hsh[subschema_sym] = Array(errors).map{|e| e.to_hash}
|
35
|
-
hsh
|
34
|
+
hsh[subschema_sym] = Array(errors).map { |e| e.to_hash }
|
36
35
|
end
|
37
36
|
end
|
38
37
|
base
|
@@ -28,6 +28,7 @@ module JSON
|
|
28
28
|
# a schema should not be read.
|
29
29
|
class ReadRefused < ReadError
|
30
30
|
private
|
31
|
+
|
31
32
|
def error_message
|
32
33
|
"Read of #{type_string} at #{location} refused"
|
33
34
|
end
|
@@ -36,6 +37,7 @@ module JSON
|
|
36
37
|
# Raised by {JSON::Schema::Reader} when an attempt to read a schema fails
|
37
38
|
class ReadFailed < ReadError
|
38
39
|
private
|
40
|
+
|
39
41
|
def error_message
|
40
42
|
"Read of #{type_string} at #{location} failed"
|
41
43
|
end
|
@@ -4,7 +4,7 @@ module JSON
|
|
4
4
|
attr_accessor :attributes, :formats, :uri, :names
|
5
5
|
attr_reader :default_formats
|
6
6
|
|
7
|
-
def initialize
|
7
|
+
def initialize
|
8
8
|
@attributes = {}
|
9
9
|
@formats = {}
|
10
10
|
@default_formats = {}
|
@@ -14,13 +14,13 @@ module JSON
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def extend_schema_definition(schema_uri)
|
17
|
-
warn
|
17
|
+
warn '[DEPRECATION NOTICE] The preferred way to extend a Validator is by subclassing, rather than #extend_schema_definition. This method will be removed in version >= 3.'
|
18
18
|
validator = JSON::Validator.validator_for_uri(schema_uri)
|
19
19
|
@attributes.merge!(validator.attributes)
|
20
20
|
end
|
21
21
|
|
22
22
|
def validate(current_schema, data, fragments, processor, options = {})
|
23
|
-
current_schema.schema.each do |attr_name,attribute|
|
23
|
+
current_schema.schema.each do |attr_name, attribute|
|
24
24
|
if @attributes.has_key?(attr_name.to_s)
|
25
25
|
@attributes[attr_name.to_s].validate(current_schema, data, fragments, processor, self, options)
|
26
26
|
end
|