json-schema 2.8.1 → 6.1.0
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 +55 -11
- data/lib/json-schema/attribute.rb +15 -16
- data/lib/json-schema/attributes/additionalitems.rb +1 -0
- data/lib/json-schema/attributes/additionalproperties.rb +4 -7
- data/lib/json-schema/attributes/allof.rb +33 -6
- data/lib/json-schema/attributes/anyof.rb +4 -4
- data/lib/json-schema/attributes/const.rb +15 -0
- data/lib/json-schema/attributes/dependencies.rb +1 -0
- data/lib/json-schema/attributes/disallow.rb +2 -1
- data/lib/json-schema/attributes/divisibleby.rb +1 -1
- data/lib/json-schema/attributes/enum.rb +3 -3
- data/lib/json-schema/attributes/extends.rb +10 -8
- data/lib/json-schema/attributes/format.rb +2 -1
- data/lib/json-schema/attributes/formats/custom.rb +5 -7
- data/lib/json-schema/attributes/formats/date.rb +2 -1
- data/lib/json-schema/attributes/formats/date_time.rb +4 -3
- data/lib/json-schema/attributes/formats/date_time_v4.rb +2 -1
- data/lib/json-schema/attributes/formats/ip.rb +3 -3
- data/lib/json-schema/attributes/formats/time.rb +1 -1
- data/lib/json-schema/attributes/formats/uri.rb +2 -1
- data/lib/json-schema/attributes/items.rb +1 -0
- data/lib/json-schema/attributes/limit.rb +2 -2
- data/lib/json-schema/attributes/limits/numeric.rb +1 -1
- data/lib/json-schema/attributes/maxdecimal.rb +2 -2
- data/lib/json-schema/attributes/not.rb +2 -2
- data/lib/json-schema/attributes/oneof.rb +9 -11
- data/lib/json-schema/attributes/pattern.rb +1 -1
- data/lib/json-schema/attributes/patternproperties.rb +2 -1
- data/lib/json-schema/attributes/properties.rb +10 -10
- data/lib/json-schema/attributes/properties_v4.rb +2 -2
- data/lib/json-schema/attributes/propertynames.rb +23 -0
- data/lib/json-schema/attributes/ref.rb +19 -18
- data/lib/json-schema/attributes/required.rb +6 -5
- data/lib/json-schema/attributes/type.rb +11 -10
- data/lib/json-schema/attributes/type_v4.rb +3 -3
- data/lib/json-schema/attributes/uniqueitems.rb +1 -1
- data/lib/json-schema/errors/validation_error.rb +10 -10
- data/lib/json-schema/schema/reader.rb +4 -2
- data/lib/json-schema/schema/validator.rb +4 -4
- data/lib/json-schema/schema.rb +13 -14
- data/lib/json-schema/util/array_set.rb +2 -4
- data/lib/json-schema/util/uri.rb +100 -77
- data/lib/json-schema/util/uuid.rb +204 -226
- data/lib/json-schema/validator.rb +173 -156
- 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 -36
- 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 +3 -3
- data/resources/draft-06.json +12 -12
- metadata +60 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e9686db47d231f89e17854471084e1dfe27b365df2e5be5e04a98ef27d05cbcf
|
|
4
|
+
data.tar.gz: 5f6e77d40b284308ed64d630e292d57797c0c156bdc8ebaafa12acc3ffcfba7f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bdb9e93be56be04160b301dd200684b20495ffd3326d12dd2ca2014eb6f3bfc667f61ba1a3f61bdb5f39cab20a0edbf509a7efd84cb52ac728219b88c1ad4b61
|
|
7
|
+
data.tar.gz: b62696183483862807c53bcc9ccbf831206800dda4e26f03de0da0f12f556e36a6e01083c853100348f7f9f96c13607d1e7600af41436ceb01eb4ca4966b56a3
|
data/README.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
[](https://travis-ci.org/ruby-json-schema/json-schema)
|
|
3
|
-
[](https://codeclimate.com/github/ruby-json-schema/json-schema)
|
|
1
|
+
# Ruby JSON Schema Validator
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
[](https://github.com/voxpupuli/json-schema/blob/master/LICENSE.md)
|
|
4
|
+
[](https://github.com/voxpupuli/json-schema/actions/workflows/test.yml)
|
|
5
|
+
[](https://github.com/voxpupuli/json-schema/actions/workflows/release.yml)
|
|
6
|
+
[](https://rubygems.org/gems/json-schema)
|
|
7
|
+
[](https://rubygems.org/gems/json-schema)
|
|
8
|
+
[](#transfer-notice)
|
|
7
9
|
|
|
8
10
|
This library is intended to provide Ruby with an interface for validating JSON
|
|
9
11
|
objects against a JSON schema conforming to [JSON Schema Draft
|
|
10
|
-
|
|
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),
|
|
11
14
|
[JSON Schema Draft 3](http://tools.ietf.org/html/draft-zyp-json-schema-03),
|
|
12
15
|
[JSON Schema Draft 2](http://tools.ietf.org/html/draft-zyp-json-schema-02), and
|
|
13
16
|
[JSON Schema Draft 1](http://tools.ietf.org/html/draft-zyp-json-schema-01) is
|
|
@@ -17,7 +20,7 @@ Additional Resources
|
|
|
17
20
|
--------------------
|
|
18
21
|
|
|
19
22
|
- [Google Groups](https://groups.google.com/forum/#!forum/ruby-json-schema)
|
|
20
|
-
- #
|
|
23
|
+
- #voxpupuli on irc.libera.chat
|
|
21
24
|
|
|
22
25
|
Version 2.0.0 Upgrade Notes
|
|
23
26
|
---------------------------
|
|
@@ -27,6 +30,14 @@ default**, so schemas that do not declare a validator using the `$schema`
|
|
|
27
30
|
keyword will use Draft-04 now instead of Draft-03. This is the reason for the
|
|
28
31
|
major version upgrade.
|
|
29
32
|
|
|
33
|
+
Version 3.0.0 Upgrade Notes
|
|
34
|
+
---------------------------
|
|
35
|
+
|
|
36
|
+
All individual changes are documented in the CHANGELOG.md. The biggest change
|
|
37
|
+
is that the new version only supports Ruby 2.5 and newer. Take a look into the
|
|
38
|
+
gemspec file to see the currently supported Ruby version and also
|
|
39
|
+
`.github/workflows/test.yml` to see the Ruby versions we test on.
|
|
40
|
+
|
|
30
41
|
Installation
|
|
31
42
|
------------
|
|
32
43
|
|
|
@@ -39,8 +50,8 @@ gem install json-schema
|
|
|
39
50
|
From the git repo:
|
|
40
51
|
|
|
41
52
|
```sh
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
gem build json-schema.gemspec
|
|
54
|
+
gem install json-schema-*.gem
|
|
44
55
|
```
|
|
45
56
|
|
|
46
57
|
Validation
|
|
@@ -69,7 +80,7 @@ that the `$schema` attribute takes precedence over the `:version` option during
|
|
|
69
80
|
parsing and validation.
|
|
70
81
|
|
|
71
82
|
For further information on json schema itself refer to <a
|
|
72
|
-
href="
|
|
83
|
+
href="https://json-schema.org/understanding-json-schema">Understanding
|
|
73
84
|
JSON Schema</a>.
|
|
74
85
|
|
|
75
86
|
Basic Usage
|
|
@@ -166,7 +177,7 @@ JSON::Validator.validate(schema, [{"a" => 1}, {"a" => 2}, {"a" => 3}])
|
|
|
166
177
|
JSON::Validator.fully_validate(schema, { "a" => "taco" }, :errors_as_objects => true)
|
|
167
178
|
|
|
168
179
|
#
|
|
169
|
-
# with the `:strict` option, all properties are
|
|
180
|
+
# with the `:strict` option, all properties are considered to have `"required": true` and all objects `"additionalProperties": false`
|
|
170
181
|
#
|
|
171
182
|
|
|
172
183
|
# => true
|
|
@@ -230,6 +241,19 @@ JSON::Validator.validate(schema, { "a" => 1 }, :parse_data => false)
|
|
|
230
241
|
# => false
|
|
231
242
|
JSON::Validator.validate(schema, '{ "a": 1 }', :parse_data => false)
|
|
232
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
|
+
|
|
233
257
|
#
|
|
234
258
|
# with the `:json` option, the json must be an unparsed json text (not a hash, a uri or a file path)
|
|
235
259
|
#
|
|
@@ -472,3 +496,23 @@ value is of the correct datatype (e.g., an instance value is validated to be an
|
|
|
472
496
|
integer or a float in the case of 'utc-millisec').
|
|
473
497
|
|
|
474
498
|
Additionally, JSON::Validator does not handle any json hyperschema attributes.
|
|
499
|
+
|
|
500
|
+
# Transfer Notice
|
|
501
|
+
|
|
502
|
+
This plugin was originally authored by [Iain Beeston](https://github.com/iainbeeston).
|
|
503
|
+
The maintainer preferred that [Vox Pupuli](https://voxpupuli.org/) take ownership of the module for future improvement and maintenance.
|
|
504
|
+
Existing pull requests and issues were transferred, please fork and continue to contribute [here](https://github.com/voxpupuli/json-schema).
|
|
505
|
+
|
|
506
|
+
# License
|
|
507
|
+
|
|
508
|
+
This gem is licensed under the [MIT license](LICENSE.md).
|
|
509
|
+
|
|
510
|
+
## Release information
|
|
511
|
+
|
|
512
|
+
To make a new release, please do:
|
|
513
|
+
* update the version in VERSION.yml
|
|
514
|
+
* Install gems with `bundle install --with release --path .vendor`
|
|
515
|
+
* generate the changelog with `bundle exec rake changelog`
|
|
516
|
+
* Check if the new version matches the closed issues/PRs in the changelog
|
|
517
|
+
* Create a PR with it
|
|
518
|
+
* After it got merged, push a tag. GitHub actions will do the actual release to rubygems and GitHub Packages
|
|
@@ -3,15 +3,14 @@ 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('/')}"
|
|
11
10
|
end
|
|
12
11
|
|
|
13
|
-
def self.validation_error(processor, message, fragments, current_schema, failed_attribute, record_errors)
|
|
14
|
-
error = ValidationError.new(message, fragments, failed_attribute, current_schema)
|
|
12
|
+
def self.validation_error(processor, message, fragments, current_schema, failed_attribute, record_errors, properties = [])
|
|
13
|
+
error = ValidationError.new(message, fragments, failed_attribute, current_schema, properties)
|
|
15
14
|
if record_errors
|
|
16
15
|
processor.validation_error(error)
|
|
17
16
|
else
|
|
@@ -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
|
|
@@ -30,14 +30,12 @@ module JSON
|
|
|
30
30
|
schema = current_schema.schema
|
|
31
31
|
|
|
32
32
|
if schema['properties']
|
|
33
|
-
extra_properties
|
|
33
|
+
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,29 +7,56 @@ 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
|
-
|
|
20
|
-
|
|
20
|
+
# Cannot raise if noAdditionalProperties is true, we need to
|
|
21
|
+
# evaluate each sub schema within the allOf, before raising.
|
|
22
|
+
if options[:noAdditionalProperties] == true
|
|
23
|
+
schema.validate(data, fragments, processor, options.merge(record_errors: true))
|
|
24
|
+
else
|
|
25
|
+
schema.validate(data, fragments, processor, options)
|
|
26
|
+
end
|
|
27
|
+
rescue ValidationError => e
|
|
21
28
|
valid = false
|
|
29
|
+
message = e.message
|
|
22
30
|
end
|
|
23
31
|
|
|
24
32
|
diff = validation_errors(processor).count - pre_validation_error_count
|
|
33
|
+
|
|
25
34
|
while diff > 0
|
|
26
|
-
diff
|
|
35
|
+
diff -= 1
|
|
27
36
|
errors["allOf ##{schema_index}"].push(validation_errors(processor).pop)
|
|
28
37
|
end
|
|
29
38
|
end
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
# Find any properties that are missing across all subschemas.
|
|
41
|
+
common_missing_properties = {}
|
|
42
|
+
if options[:noAdditionalProperties] == true && !errors.empty?
|
|
43
|
+
all_property_errors = errors.values.flatten.map(&:properties)
|
|
44
|
+
common_missing_properties = (all_property_errors.first || []).to_set
|
|
45
|
+
|
|
46
|
+
all_property_errors[1..].each do |curr_property_errors|
|
|
47
|
+
common_missing_properties &= curr_property_errors.to_set
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# PropertiesV4Attribute represents errors that would indicate an
|
|
52
|
+
# additional property was detected. If we filter these out, we should
|
|
53
|
+
# be left with errors that are not dependent on any other sub schema.
|
|
54
|
+
non_missing_property_errors = errors.values.flatten.reject do |error|
|
|
55
|
+
error.failed_attribute == JSON::Schema::PropertiesV4Attribute
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if !valid || !non_missing_property_errors.empty? || !common_missing_properties.empty?
|
|
59
|
+
message ||= "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match all of the required schemas"
|
|
33
60
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
|
34
61
|
validation_errors(processor).last.sub_errors = errors
|
|
35
62
|
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
|
|
@@ -27,7 +27,7 @@ module JSON
|
|
|
27
27
|
diff = validation_errors(processor).count - pre_validation_error_count
|
|
28
28
|
valid = false if diff > 0
|
|
29
29
|
while diff > 0
|
|
30
|
-
diff
|
|
30
|
+
diff -= 1
|
|
31
31
|
errors["anyOf ##{schema_index}"].push(validation_errors(processor).pop)
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -36,7 +36,7 @@ module JSON
|
|
|
36
36
|
data = original_data
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
unless valid
|
|
40
40
|
message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match one or more of the required schemas"
|
|
41
41
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
|
42
42
|
validation_errors(processor).last.sub_errors = errors
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'json-schema/attribute'
|
|
2
|
+
|
|
3
|
+
module JSON
|
|
4
|
+
class Schema
|
|
5
|
+
class ConstAttribute < Attribute
|
|
6
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
7
|
+
const_value = current_schema.schema['const']
|
|
8
|
+
unless const_value == data
|
|
9
|
+
message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match constant '#{const_value}'"
|
|
10
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -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,7 +7,7 @@ module JSON
|
|
|
7
7
|
'divisibleBy'
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
10
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
11
11
|
return unless data.is_a?(Numeric)
|
|
12
12
|
|
|
13
13
|
factor = current_schema.schema[keyword]
|
|
@@ -3,18 +3,18 @@ require 'json-schema/attribute'
|
|
|
3
3
|
module JSON
|
|
4
4
|
class Schema
|
|
5
5
|
class EnumAttribute < Attribute
|
|
6
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
6
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
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])
|
|
@@ -6,13 +6,13 @@ module JSON
|
|
|
6
6
|
class ExtendsAttribute < Attribute
|
|
7
7
|
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
|
8
8
|
schemas = current_schema.schema['extends']
|
|
9
|
-
schemas = [schemas]
|
|
9
|
+
schemas = [schemas] unless 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
|
|
15
|
-
message = "The extended schema '#{uri
|
|
15
|
+
message = "The extended schema '#{uri}' cannot be found"
|
|
16
16
|
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
|
17
17
|
else
|
|
18
18
|
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
|
@@ -22,15 +22,17 @@ module JSON
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def self.get_extended_uri_and_schema(s, current_schema, validator)
|
|
25
|
-
uri
|
|
25
|
+
uri = nil
|
|
26
|
+
schema = nil
|
|
26
27
|
|
|
27
28
|
if s.is_a?(Hash)
|
|
28
29
|
uri = current_schema.uri
|
|
29
30
|
if s['$ref']
|
|
30
|
-
ref_uri,ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator)
|
|
31
|
+
ref_uri, ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator)
|
|
31
32
|
if ref_schema
|
|
32
33
|
if s.size == 1 # Check if anything else apart from $ref
|
|
33
|
-
uri
|
|
34
|
+
uri = ref_uri
|
|
35
|
+
schema = ref_schema
|
|
34
36
|
else
|
|
35
37
|
s = s.dup
|
|
36
38
|
s.delete '$ref'
|
|
@@ -38,10 +40,10 @@ module JSON
|
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
|
-
schema ||= JSON::Schema.new(s,uri,validator)
|
|
43
|
+
schema ||= JSON::Schema.new(s, uri, validator)
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
[uri,schema]
|
|
46
|
+
[uri, schema]
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
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
|
|
@@ -8,13 +8,11 @@ module JSON
|
|
|
8
8
|
@validation_proc = validation_proc
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def validate(current_schema, data, fragments, processor,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
self.class.validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
|
17
|
-
end
|
|
11
|
+
def validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
12
|
+
@validation_proc.call data
|
|
13
|
+
rescue JSON::Schema::CustomFormatError => e
|
|
14
|
+
message = "The property '#{self.class.build_fragment(fragments)}' #{e.message}"
|
|
15
|
+
self.class.validation_error(processor, message, fragments, current_schema, self.class, options[:record_errors])
|
|
18
16
|
end
|
|
19
17
|
end
|
|
20
18
|
end
|
|
@@ -5,7 +5,7 @@ module JSON
|
|
|
5
5
|
class DateFormat < FormatAttribute
|
|
6
6
|
REGEXP = /\A\d{4}-\d{2}-\d{2}\z/
|
|
7
7
|
|
|
8
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
8
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
9
9
|
if data.is_a?(String)
|
|
10
10
|
error_message = "The property '#{build_fragment(fragments)}' must be a date in the format of YYYY-MM-DD"
|
|
11
11
|
if REGEXP.match(data)
|
|
@@ -13,6 +13,7 @@ module JSON
|
|
|
13
13
|
Date.parse(data)
|
|
14
14
|
rescue ArgumentError => e
|
|
15
15
|
raise e unless e.message == 'invalid date'
|
|
16
|
+
|
|
16
17
|
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
|
17
18
|
end
|
|
18
19
|
else
|
|
@@ -3,19 +3,20 @@ require 'json-schema/attributes/format'
|
|
|
3
3
|
module JSON
|
|
4
4
|
class Schema
|
|
5
5
|
class DateTimeFormat < FormatAttribute
|
|
6
|
-
REGEXP = /\A\d{4}-\d{2}-\d{2}T(\d{2}):(\d{2}):(\d{2})([
|
|
6
|
+
REGEXP = /\A\d{4}-\d{2}-\d{2}T(\d{2}):(\d{2}):(\d{2})([.,]\d+)?(Z|[+-](\d{2})(:?\d{2})?)?\z/
|
|
7
7
|
|
|
8
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
8
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
9
9
|
# Timestamp in restricted ISO-8601 YYYY-MM-DDThh:mm:ssZ with optional decimal fraction of the second
|
|
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
|
|
@@ -3,8 +3,9 @@ require 'json-schema/attributes/format'
|
|
|
3
3
|
module JSON
|
|
4
4
|
class Schema
|
|
5
5
|
class DateTimeV4Format < FormatAttribute
|
|
6
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
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"
|
|
@@ -5,16 +5,16 @@ require 'socket'
|
|
|
5
5
|
module JSON
|
|
6
6
|
class Schema
|
|
7
7
|
class IPFormat < FormatAttribute
|
|
8
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
8
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
9
9
|
return unless data.is_a?(String)
|
|
10
10
|
|
|
11
11
|
begin
|
|
12
12
|
ip = IPAddr.new(data)
|
|
13
13
|
rescue ArgumentError => e
|
|
14
|
-
raise e unless e.message
|
|
14
|
+
raise e unless e.message.start_with?('invalid address')
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
family = ip_version == 6 ? Socket::AF_INET6 : Socket::AF_INET
|
|
17
|
+
family = (ip_version == 6) ? Socket::AF_INET6 : Socket::AF_INET
|
|
18
18
|
unless ip && ip.family == family
|
|
19
19
|
error_message = "The property '#{build_fragment(fragments)}' must be a valid IPv#{ip_version} address"
|
|
20
20
|
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
|
@@ -5,7 +5,7 @@ module JSON
|
|
|
5
5
|
class TimeFormat < FormatAttribute
|
|
6
6
|
REGEXP = /\A(\d{2}):(\d{2}):(\d{2})\z/
|
|
7
7
|
|
|
8
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
8
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
9
9
|
if data.is_a?(String)
|
|
10
10
|
error_message = "The property '#{build_fragment(fragments)}' must be a time in the format of hh:mm:ss"
|
|
11
11
|
if (m = REGEXP.match(data))
|
|
@@ -4,8 +4,9 @@ require 'json-schema/errors/uri_error'
|
|
|
4
4
|
module JSON
|
|
5
5
|
class Schema
|
|
6
6
|
class UriFormat < FormatAttribute
|
|
7
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
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)
|
|
@@ -3,7 +3,7 @@ require 'json-schema/attribute'
|
|
|
3
3
|
module JSON
|
|
4
4
|
class Schema
|
|
5
5
|
class LimitAttribute < Attribute
|
|
6
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
6
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
7
7
|
schema = current_schema.schema
|
|
8
8
|
return unless data.is_a?(acceptable_type) && invalid?(schema, value(data))
|
|
9
9
|
|
|
@@ -28,7 +28,7 @@ module JSON
|
|
|
28
28
|
schema[limit_name]
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def self.exclusive?(
|
|
31
|
+
def self.exclusive?(_schema)
|
|
32
32
|
false
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -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
|
|
@@ -3,11 +3,11 @@ require 'json-schema/attribute'
|
|
|
3
3
|
module JSON
|
|
4
4
|
class Schema
|
|
5
5
|
class MaxDecimalAttribute < Attribute
|
|
6
|
-
def self.validate(current_schema, data, fragments, processor,
|
|
6
|
+
def self.validate(current_schema, data, fragments, processor, _validator, options = {})
|
|
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])
|