json_schemer 1.0.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -6
  3. data/CHANGELOG.md +25 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +137 -14
  6. data/json_schemer.gemspec +1 -1
  7. data/lib/json_schemer/draft201909/meta.rb +335 -0
  8. data/lib/json_schemer/draft201909/vocab/applicator.rb +104 -0
  9. data/lib/json_schemer/draft201909/vocab/core.rb +45 -0
  10. data/lib/json_schemer/draft201909/vocab.rb +31 -0
  11. data/lib/json_schemer/draft202012/meta.rb +361 -0
  12. data/lib/json_schemer/draft202012/vocab/applicator.rb +382 -0
  13. data/lib/json_schemer/draft202012/vocab/content.rb +44 -0
  14. data/lib/json_schemer/draft202012/vocab/core.rb +154 -0
  15. data/lib/json_schemer/draft202012/vocab/format_annotation.rb +31 -0
  16. data/lib/json_schemer/draft202012/vocab/format_assertion.rb +29 -0
  17. data/lib/json_schemer/draft202012/vocab/meta_data.rb +30 -0
  18. data/lib/json_schemer/draft202012/vocab/unevaluated.rb +94 -0
  19. data/lib/json_schemer/draft202012/vocab/validation.rb +286 -0
  20. data/lib/json_schemer/draft202012/vocab.rb +103 -0
  21. data/lib/json_schemer/draft4/meta.rb +155 -0
  22. data/lib/json_schemer/draft4/vocab/validation.rb +39 -0
  23. data/lib/json_schemer/draft4/vocab.rb +18 -0
  24. data/lib/json_schemer/draft6/meta.rb +161 -0
  25. data/lib/json_schemer/draft6/vocab.rb +16 -0
  26. data/lib/json_schemer/draft7/meta.rb +178 -0
  27. data/lib/json_schemer/draft7/vocab/validation.rb +69 -0
  28. data/lib/json_schemer/draft7/vocab.rb +30 -0
  29. data/lib/json_schemer/errors.rb +1 -0
  30. data/lib/json_schemer/format/duration.rb +23 -0
  31. data/lib/json_schemer/format/json_pointer.rb +18 -0
  32. data/lib/json_schemer/format.rb +52 -26
  33. data/lib/json_schemer/keyword.rb +41 -0
  34. data/lib/json_schemer/location.rb +25 -0
  35. data/lib/json_schemer/openapi.rb +40 -0
  36. data/lib/json_schemer/openapi30/document.rb +1673 -0
  37. data/lib/json_schemer/openapi30/meta.rb +26 -0
  38. data/lib/json_schemer/openapi30/vocab/base.rb +18 -0
  39. data/lib/json_schemer/openapi30/vocab.rb +12 -0
  40. data/lib/json_schemer/openapi31/document.rb +1559 -0
  41. data/lib/json_schemer/openapi31/meta.rb +128 -0
  42. data/lib/json_schemer/openapi31/vocab/base.rb +89 -0
  43. data/lib/json_schemer/openapi31/vocab.rb +18 -0
  44. data/lib/json_schemer/output.rb +55 -0
  45. data/lib/json_schemer/result.rb +168 -0
  46. data/lib/json_schemer/schema.rb +390 -0
  47. data/lib/json_schemer/version.rb +1 -1
  48. data/lib/json_schemer.rb +197 -24
  49. metadata +42 -10
  50. data/lib/json_schemer/schema/base.rb +0 -677
  51. data/lib/json_schemer/schema/draft4.json +0 -149
  52. data/lib/json_schemer/schema/draft4.rb +0 -44
  53. data/lib/json_schemer/schema/draft6.json +0 -155
  54. data/lib/json_schemer/schema/draft6.rb +0 -25
  55. data/lib/json_schemer/schema/draft7.json +0 -172
  56. data/lib/json_schemer/schema/draft7.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '03538ce8b7525466940396aecbfffeac23f2f942af4e11023ea370d73045ec8b'
4
- data.tar.gz: a06e7a91e8c851dffac5b9ecab91e47b6e89d46173abc8f95619dc4eca7f938d
3
+ metadata.gz: ed0173ca9146797b3576cf21870b4d7163ea05354912d0d0be21d6e89d54d16c
4
+ data.tar.gz: 1913f580bebb4d874be1a8d196a7b197156613b4240407855b9145fe03acf38b
5
5
  SHA512:
6
- metadata.gz: 87f3d572f430bc5b64f25ffc96bf5fcf979fa53eea9e0d325e6d0b853b4f653d2264e151ab312da4e472a02342eb162e9ffdfa3b06c3ec29fa09e39123412f3a
7
- data.tar.gz: fbbed8f04fea519b2264075051e64a7f6af2ade9b92600a490a2291065ed9a13eb15fb73cf356a0caff5ea3f63065d4c7a50ff93b293441273ed98708429cfe8
6
+ metadata.gz: 8ae6cbd519a54752d739192b3438c61abd81db1f11af409a48fe77b37205c395ca577f7fadbf2819134e942d5708d4a80a59f9d39c5e0e3d42a0144b78b70426
7
+ data.tar.gz: 216ac23667163998671a455298cc699a170452095acd0ef661b69a63a879f54d6c12f2676e5ab919472bd66794c6b7ab68687153f2c45ee7898e12be4ff7368c
@@ -19,9 +19,4 @@ jobs:
19
19
  with:
20
20
  ruby-version: ${{ matrix.ruby }}
21
21
  bundler-cache: true
22
- - run: |
23
- mkdir -p tmp/gems
24
- gem build json_schemer.gemspec
25
- gem install --local --ignore-dependencies --no-document --install-dir tmp/gems json_schemer-*.gem
26
- rm json_schemer-*.gem
27
- bin/rake test
22
+ - run: bin/rake test
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0] - XXXX-XX-XX
4
+
5
+ For 2.0.0, much of the codebase was rewritten to simplify support for the two new JSON Schema draft versions (2019-09 and 2020-12). The major change is moving each keyword into its own class and organizing them into vocabularies. [Output formats](https://json-schema.org/draft/2020-12/json-schema-core.html#section-12) and [annotations](https://json-schema.org/draft/2020-12/json-schema-core.html#section-7.7) from the new drafts are also supported. The known breaking changes are listed below, but there may be others that haven't been identified.
6
+
7
+ ### Breaking Changes
8
+
9
+ - The default meta schema is now Draft 2020-12. Other meta schemas can be specified using `meta_schema`.
10
+ - Schemas use `json-schemer://schema` as the default base URI. Relative `$id` and `$ref` values are joined to the default base URI and are always absolute. For example, the schema `{ '$id' => 'foo', '$ref' => 'bar' }` uses `json-schemer://schema/foo` as the base URI and passes `json-schemer://schema/bar` to the ref resolver. For relative refs, `URI#path` can be used in the ref resolver to access the relative portion, ie: `URI('json-schemer://schema/bar').path => "/bar"`.
11
+ - Property validation hooks (`before_property_validation` and `after_property_validation`) run immediately before and after `properties` validation. Previously, `before_property_validation` ran before all "object" validations (`dependencies`, `patternProperties`, `additionalProperties`, etc) and `after_property_validation` was called after them.
12
+ - `insert_property_defaults` now inserts defaults in conditional subschemas when possible (if there's only one default or if there's only one unique default from a valid subtree).
13
+ - Error output
14
+ - Special characters in `schema_pointer` are no longer percent encoded (eg, `definitions/foo\"bar` instead of `/definitions/foo%22bar`)
15
+ - Keyword validation order changed so errors may be returned in a different order (eg, `items` errors before `contains`).
16
+ - Array `dependencies` return `"type": "dependencies"` errors instead of `"required"` and point to the schema that contains the `dependencies` keyword.
17
+ - `not` errors point to the schema that contains the `not` keyword (instead of the schema defined by the `not` keyword).
18
+ - Custom keyword errors are now always wrapped in regular error hashes. Returned strings are used to set `type`:
19
+ ```
20
+ >> JSONSchemer.schema({ 'x' => 'y' }, :keywords => { 'x' => proc { false } }).validate({}).to_a
21
+ => [{"data"=>{}, "data_pointer"=>"", "schema"=>{"x"=>"y"}, "schema_pointer"=>"", "root_schema"=>{"x"=>"y"}, "type"=>"x"}]
22
+ >> JSONSchemer.schema({ 'x' => 'y' }, :keywords => { 'x' => proc { 'wrong!' } }).validate({}).to_a
23
+ => [{"data"=>{}, "data_pointer"=>"", "schema"=>{"x"=>"y"}, "schema_pointer"=>"", "root_schema"=>{"x"=>"y"}, "type"=>"wrong!"}]
24
+ ```
25
+
26
+ [2.0.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.0.0
27
+
3
28
  ## [1.0.0] - 2023-05-26
4
29
 
5
30
  ### Breaking Changes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json_schemer (1.0.3)
4
+ json_schemer (2.0.0)
5
5
  hana (~> 1.3)
6
6
  regexp_parser (~> 2.0)
7
7
  simpleidn (~> 0.2)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # JSONSchemer
2
2
 
3
- JSON Schema validator. Supports drafts 4, 6, and 7.
3
+ JSON Schema validator. Supports drafts 4, 6, 7, 2019-09, 2020-12, OpenAPI 3.0, and OpenAPI 3.1.
4
4
 
5
5
  ## Installation
6
6
 
@@ -50,7 +50,8 @@ schemer.validate({ 'abc' => 10 }).to_a
50
50
  # "schema"=>{"type"=>"integer", "minimum"=>11},
51
51
  # "schema_pointer"=>"/properties/abc",
52
52
  # "root_schema"=>{"type"=>"object", "properties"=>{"abc"=>{"type"=>"integer", "minimum"=>11}}},
53
- # "type"=>"minimum"}]
53
+ # "type"=>"minimum",
54
+ # "error"=>"number at `/abc` is less than: 11"}]
54
55
 
55
56
  # default property values
56
57
 
@@ -82,27 +83,77 @@ schemer = JSONSchemer.schema(schema)
82
83
 
83
84
  # schema validation
84
85
 
85
- JSONSchemer.valid_schema?({ '$id' => '#valid' })
86
+ JSONSchemer.valid_schema?({ '$id' => 'valid' })
86
87
  # => true
87
88
 
88
- JSONSchemer.validate_schema({ '$id' => nil }).to_a
89
- # => [{"data"=>nil,
89
+ JSONSchemer.validate_schema({ '$id' => '#invalid' }).to_a
90
+ # => [{"data"=>"#invalid",
90
91
  # "data_pointer"=>"/$id",
91
- # "schema"=>{"type"=>"string", "format"=>"uri-reference"},
92
+ # "schema"=>{"$ref"=>"#/$defs/uriReferenceString", "$comment"=>"Non-empty fragments not allowed.", "pattern"=>"^[^#]*#?$"},
92
93
  # "schema_pointer"=>"/properties/$id",
93
94
  # "root_schema"=>{...meta schema},
94
- # "type"=>"string"}]
95
+ # "type"=>"pattern",
96
+ # "error"=>"string at `/$id` does not match pattern: ^[^#]*#?$"}]
95
97
 
96
- JSONSchemer.schema({ '$id' => '#valid' }).valid_schema?
98
+ JSONSchemer.schema({ '$id' => 'valid' }).valid_schema?
97
99
  # => true
98
100
 
99
- JSONSchemer.schema({ '$id' => nil }).validate_schema.to_a
100
- # => [{"data"=>nil,
101
+ JSONSchemer.schema({ '$id' => '#invalid' }).validate_schema.to_a
102
+ # => [{"data"=>"#invalid",
101
103
  # "data_pointer"=>"/$id",
102
- # "schema"=>{"type"=>"string", "format"=>"uri-reference"},
104
+ # "schema"=>{"$ref"=>"#/$defs/uriReferenceString", "$comment"=>"Non-empty fragments not allowed.", "pattern"=>"^[^#]*#?$"},
103
105
  # "schema_pointer"=>"/properties/$id",
104
106
  # "root_schema"=>{...meta schema},
105
- # "type"=>"string"}]
107
+ # "type"=>"pattern",
108
+ # "error"=>"string at `/$id` does not match pattern: ^[^#]*#?$"}]
109
+
110
+ # subschemas
111
+
112
+ schema = {
113
+ 'type' => 'integer',
114
+ '$defs' => {
115
+ 'foo' => {
116
+ 'type' => 'string'
117
+ }
118
+ }
119
+ }
120
+ schemer = JSONSchemer.schema(schema)
121
+
122
+ schemer.ref('#/$defs/foo').validate(1).to_a
123
+ # => [{"data"=>1,
124
+ # "data_pointer"=>"",
125
+ # "schema"=>{"type"=>"string"},
126
+ # "schema_pointer"=>"/$defs/foo",
127
+ # "root_schema"=>{"type"=>"integer", "$defs"=>{"foo"=>{"type"=>"string"}}},
128
+ # "type"=>"string",
129
+ # "error"=>"instance at root is not a string"}]
130
+
131
+ # schema bundling (https://json-schema.org/draft/2020-12/json-schema-core.html#section-9.3)
132
+
133
+ schema = {
134
+ '$id' => 'http://example.com/schema',
135
+ 'allOf' => [
136
+ { '$ref' => 'schema/one' },
137
+ { '$ref' => 'schema/two' }
138
+ ]
139
+ }
140
+ refs = {
141
+ URI('http://example.com/schema/one') => {
142
+ 'type' => 'integer'
143
+ },
144
+ URI('http://example.com/schema/two') => {
145
+ 'minimum' => 11
146
+ }
147
+ }
148
+ schemer = JSONSchemer.schema(schema, :ref_resolver => refs.to_proc)
149
+
150
+ schemer.bundle
151
+ # => {"$id"=>"http://example.com/schema",
152
+ # "allOf"=>[{"$ref"=>"schema/one"}, {"$ref"=>"schema/two"}],
153
+ # "$schema"=>"https://json-schema.org/draft/2020-12/schema",
154
+ # "$defs"=>
155
+ # {"http://example.com/schema/one"=>{"type"=>"integer", "$id"=>"http://example.com/schema/one", "$schema"=>"https://json-schema.org/draft/2020-12/schema"},
156
+ # "http://example.com/schema/two"=>{"minimum"=>11, "$id"=>"http://example.com/schema/two", "$schema"=>"https://json-schema.org/draft/2020-12/schema"}}}
106
157
  ```
107
158
 
108
159
  ## Options
@@ -111,7 +162,20 @@ JSONSchemer.schema({ '$id' => nil }).validate_schema.to_a
111
162
  JSONSchemer.schema(
112
163
  schema,
113
164
 
114
- # validate `format` (https://tools.ietf.org/html/draft-handrews-json-schema-validation-00#section-7)
165
+ # meta schema to use for vocabularies (keyword behavior) and schema validation
166
+ # String/JSONSchemer::Schema
167
+ # 'https://json-schema.org/draft/2020-12/schema': JSONSchemer.draft202012
168
+ # 'https://json-schema.org/draft/2019-09/schema': JSONSchemer.draft201909
169
+ # 'http://json-schema.org/draft-07/schema#': JSONSchemer.draft7
170
+ # 'http://json-schema.org/draft-06/schema#': JSONSchemer.draft6
171
+ # 'http://json-schema.org/draft-04/schema#': JSONSchemer.draft4
172
+ # 'http://json-schema.org/schema#': JSONSchemer.draft4
173
+ # 'https://spec.openapis.org/oas/3.1/dialect/base': JSONSchemer.openapi31
174
+ # 'json-schemer://openapi30/schema': JSONSchemer.openapi30
175
+ # default: JSONSchemer.draft202012
176
+ meta_schema: 'https://json-schema.org/draft/2020-12/schema',
177
+
178
+ # validate `format` (https://json-schema.org/draft/2020-12/json-schema-validation.html#section-7)
115
179
  # true/false
116
180
  # default: true
117
181
  format: true,
@@ -147,10 +211,69 @@ JSONSchemer.schema(
147
211
  # default: 'ruby'
148
212
  regexp_resolver: proc do |pattern|
149
213
  RE2::Regexp.new(pattern)
150
- end
214
+ end,
215
+
216
+ # output formatting (https://json-schema.org/draft/2020-12/json-schema-core.html#section-12)
217
+ # 'classic'/'flag'/'basic'/'detailed'/'verbose'
218
+ # default: 'classic'
219
+ output_format: 'basic',
220
+
221
+ # validate `readOnly`/`writeOnly` keywords (https://spec.openapis.org/oas/v3.0.3#fixed-fields-19)
222
+ # 'read'/'write'/nil
223
+ # default: nil
224
+ access_mode: 'read'
151
225
  )
152
226
  ```
153
227
 
228
+ ## OpenAPI
229
+
230
+ ```ruby
231
+ document = JSONSchemer.openapi({
232
+ 'openapi' => '3.1.0',
233
+ 'info' => {
234
+ 'title' => 'example'
235
+ },
236
+ 'components' => {
237
+ 'schemas' => {
238
+ 'example' => {
239
+ 'type' => 'integer'
240
+ }
241
+ }
242
+ }
243
+ })
244
+
245
+ # document validation using meta schema
246
+
247
+ document.valid?
248
+ # => false
249
+
250
+ document.validate.to_a
251
+ # => [{"data"=>{"title"=>"example"},
252
+ # "data_pointer"=>"/info",
253
+ # "schema"=>{...info schema},
254
+ # "schema_pointer"=>"/$defs/info",
255
+ # "root_schema"=>{...meta schema},
256
+ # "type"=>"required",
257
+ # "details"=>{"missing_keys"=>["version"]}},
258
+ # ...]
259
+
260
+ # data validation using schema by name (in `components/schemas`)
261
+
262
+ document.schema('example').valid?(1)
263
+ # => true
264
+
265
+ document.schema('example').valid?('one')
266
+ # => false
267
+
268
+ # data validation using schema by ref
269
+
270
+ document.ref('#/components/schemas/example').valid?(1)
271
+ # => true
272
+
273
+ document.ref('#/components/schemas/example').valid?('one')
274
+ # => false
275
+ ```
276
+
154
277
  ## CLI
155
278
 
156
279
  The `json_schemer` executable takes a JSON schema file as the first argument followed by one or more JSON data files to validate. If there are any validation errors, it outputs them and returns an error code.
data/json_schemer.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["David Harsha"]
10
10
  spec.email = ["davishmcclurg@gmail.com"]
11
11
 
12
- spec.summary = "JSON Schema validator. Supports drafts 4, 6, and 7."
12
+ spec.summary = "JSON Schema validator. Supports drafts 4, 6, 7, 2019-09, 2020-12, OpenAPI 3.0, and OpenAPI 3.1."
13
13
  spec.homepage = "https://github.com/davishmcclurg/json_schemer"
14
14
  spec.license = "MIT"
15
15
 
@@ -0,0 +1,335 @@
1
+ # frozen_string_literal: true
2
+ module JSONSchemer
3
+ module Draft201909
4
+ BASE_URI = URI('https://json-schema.org/draft/2019-09/schema')
5
+ SCHEMA = {
6
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
7
+ '$id' => 'https://json-schema.org/draft/2019-09/schema',
8
+ '$vocabulary' => {
9
+ 'https://json-schema.org/draft/2019-09/vocab/core' => true,
10
+ 'https://json-schema.org/draft/2019-09/vocab/applicator' => true,
11
+ 'https://json-schema.org/draft/2019-09/vocab/validation' => true,
12
+ 'https://json-schema.org/draft/2019-09/vocab/meta-data' => true,
13
+ 'https://json-schema.org/draft/2019-09/vocab/format' => false,
14
+ 'https://json-schema.org/draft/2019-09/vocab/content' => true
15
+ },
16
+ '$recursiveAnchor' => true,
17
+ 'title' => 'Core and Validation specifications meta-schema',
18
+ 'allOf' => [
19
+ {'$ref' => 'meta/core'},
20
+ {'$ref' => 'meta/applicator'},
21
+ {'$ref' => 'meta/validation'},
22
+ {'$ref' => 'meta/meta-data'},
23
+ {'$ref' => 'meta/format'},
24
+ {'$ref' => 'meta/content'}
25
+ ],
26
+ 'type' => ['object', 'boolean'],
27
+ 'properties' => {
28
+ 'definitions' => {
29
+ '$comment' => 'While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.',
30
+ 'type' => 'object',
31
+ 'additionalProperties' => { '$recursiveRef' => '#' },
32
+ 'default' => {}
33
+ },
34
+ 'dependencies' => {
35
+ '$comment' => '"dependencies" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to "dependentSchemas" and "dependentRequired"',
36
+ 'type' => 'object',
37
+ 'additionalProperties' => {
38
+ 'anyOf' => [
39
+ { '$recursiveRef' => '#' },
40
+ { '$ref' => 'meta/validation#/$defs/stringArray' }
41
+ ]
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ module Meta
48
+ CORE = {
49
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
50
+ '$id' => 'https://json-schema.org/draft/2019-09/meta/core',
51
+ '$vocabulary' => {
52
+ 'https://json-schema.org/draft/2019-09/vocab/core' => true
53
+ },
54
+ '$recursiveAnchor' => true,
55
+ 'title' => 'Core vocabulary meta-schema',
56
+ 'type' => ['object', 'boolean'],
57
+ 'properties' => {
58
+ '$id' => {
59
+ 'type' => 'string',
60
+ 'format' => 'uri-reference',
61
+ '$comment' => 'Non-empty fragments not allowed.',
62
+ 'pattern' => '^[^#]*#?$'
63
+ },
64
+ '$schema' => {
65
+ 'type' => 'string',
66
+ 'format' => 'uri'
67
+ },
68
+ '$anchor' => {
69
+ 'type' => 'string',
70
+ 'pattern' => '^[A-Za-z][-A-Za-z0-9.:_]*$'
71
+ },
72
+ '$ref' => {
73
+ 'type' => 'string',
74
+ 'format' => 'uri-reference'
75
+ },
76
+ '$recursiveRef' => {
77
+ 'type' => 'string',
78
+ 'format' => 'uri-reference'
79
+ },
80
+ '$recursiveAnchor' => {
81
+ 'type' => 'boolean',
82
+ 'default' => false
83
+ },
84
+ '$vocabulary' => {
85
+ 'type' => 'object',
86
+ 'propertyNames' => {
87
+ 'type' => 'string',
88
+ 'format' => 'uri'
89
+ },
90
+ 'additionalProperties' => {
91
+ 'type' => 'boolean'
92
+ }
93
+ },
94
+ '$comment' => {
95
+ 'type' => 'string'
96
+ },
97
+ '$defs' => {
98
+ 'type' => 'object',
99
+ 'additionalProperties' => { '$recursiveRef' => '#' },
100
+ 'default' => {}
101
+ }
102
+ }
103
+ }
104
+
105
+ APPLICATOR = {
106
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
107
+ '$id' => 'https://json-schema.org/draft/2019-09/meta/applicator',
108
+ '$vocabulary' => {
109
+ 'https://json-schema.org/draft/2019-09/vocab/applicator' => true
110
+ },
111
+ '$recursiveAnchor' => true,
112
+ 'title' => 'Applicator vocabulary meta-schema',
113
+ 'type' => ['object', 'boolean'],
114
+ 'properties' => {
115
+ 'additionalItems' => { '$recursiveRef' => '#' },
116
+ 'unevaluatedItems' => { '$recursiveRef' => '#' },
117
+ 'items' => {
118
+ 'anyOf' => [
119
+ { '$recursiveRef' => '#' },
120
+ { '$ref' => '#/$defs/schemaArray' }
121
+ ]
122
+ },
123
+ 'contains' => { '$recursiveRef' => '#' },
124
+ 'additionalProperties' => { '$recursiveRef' => '#' },
125
+ 'unevaluatedProperties' => { '$recursiveRef' => '#' },
126
+ 'properties' => {
127
+ 'type' => 'object',
128
+ 'additionalProperties' => { '$recursiveRef' => '#' },
129
+ 'default' => {}
130
+ },
131
+ 'patternProperties' => {
132
+ 'type' => 'object',
133
+ 'additionalProperties' => { '$recursiveRef' => '#' },
134
+ 'propertyNames' => { 'format' => 'regex' },
135
+ 'default' => {}
136
+ },
137
+ 'dependentSchemas' => {
138
+ 'type' => 'object',
139
+ 'additionalProperties' => {
140
+ '$recursiveRef' => '#'
141
+ }
142
+ },
143
+ 'propertyNames' => { '$recursiveRef' => '#' },
144
+ 'if' => { '$recursiveRef' => '#' },
145
+ 'then' => { '$recursiveRef' => '#' },
146
+ 'else' => { '$recursiveRef' => '#' },
147
+ 'allOf' => { '$ref' => '#/$defs/schemaArray' },
148
+ 'anyOf' => { '$ref' => '#/$defs/schemaArray' },
149
+ 'oneOf' => { '$ref' => '#/$defs/schemaArray' },
150
+ 'not' => { '$recursiveRef' => '#' }
151
+ },
152
+ '$defs' => {
153
+ 'schemaArray' => {
154
+ 'type' => 'array',
155
+ 'minItems' => 1,
156
+ 'items' => { '$recursiveRef' => '#' }
157
+ }
158
+ }
159
+ }
160
+
161
+ VALIDATION = {
162
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
163
+ '$id' => 'https://json-schema.org/draft/2019-09/meta/validation',
164
+ '$vocabulary' => {
165
+ 'https://json-schema.org/draft/2019-09/vocab/validation' => true
166
+ },
167
+ '$recursiveAnchor' => true,
168
+ 'title' => 'Validation vocabulary meta-schema',
169
+ 'type' => ['object', 'boolean'],
170
+ 'properties' => {
171
+ 'multipleOf' => {
172
+ 'type' => 'number',
173
+ 'exclusiveMinimum' => 0
174
+ },
175
+ 'maximum' => {
176
+ 'type' => 'number'
177
+ },
178
+ 'exclusiveMaximum' => {
179
+ 'type' => 'number'
180
+ },
181
+ 'minimum' => {
182
+ 'type' => 'number'
183
+ },
184
+ 'exclusiveMinimum' => {
185
+ 'type' => 'number'
186
+ },
187
+ 'maxLength' => { '$ref' => '#/$defs/nonNegativeInteger' },
188
+ 'minLength' => { '$ref' => '#/$defs/nonNegativeIntegerDefault0' },
189
+ 'pattern' => {
190
+ 'type' => 'string',
191
+ 'format' => 'regex'
192
+ },
193
+ 'maxItems' => { '$ref' => '#/$defs/nonNegativeInteger' },
194
+ 'minItems' => { '$ref' => '#/$defs/nonNegativeIntegerDefault0' },
195
+ 'uniqueItems' => {
196
+ 'type' => 'boolean',
197
+ 'default' => false
198
+ },
199
+ 'maxContains' => { '$ref' => '#/$defs/nonNegativeInteger' },
200
+ 'minContains' => {
201
+ '$ref' => '#/$defs/nonNegativeInteger',
202
+ 'default' => 1
203
+ },
204
+ 'maxProperties' => { '$ref' => '#/$defs/nonNegativeInteger' },
205
+ 'minProperties' => { '$ref' => '#/$defs/nonNegativeIntegerDefault0' },
206
+ 'required' => { '$ref' => '#/$defs/stringArray' },
207
+ 'dependentRequired' => {
208
+ 'type' => 'object',
209
+ 'additionalProperties' => {
210
+ '$ref' => '#/$defs/stringArray'
211
+ }
212
+ },
213
+ 'const' => true,
214
+ 'enum' => {
215
+ 'type' => 'array',
216
+ 'items' => true
217
+ },
218
+ 'type' => {
219
+ 'anyOf' => [
220
+ { '$ref' => '#/$defs/simpleTypes' },
221
+ {
222
+ 'type' => 'array',
223
+ 'items' => { '$ref' => '#/$defs/simpleTypes' },
224
+ 'minItems' => 1,
225
+ 'uniqueItems' => true
226
+ }
227
+ ]
228
+ }
229
+ },
230
+ '$defs' => {
231
+ 'nonNegativeInteger' => {
232
+ 'type' => 'integer',
233
+ 'minimum' => 0
234
+ },
235
+ 'nonNegativeIntegerDefault0' => {
236
+ '$ref' => '#/$defs/nonNegativeInteger',
237
+ 'default' => 0
238
+ },
239
+ 'simpleTypes' => {
240
+ 'enum' => [
241
+ 'array',
242
+ 'boolean',
243
+ 'integer',
244
+ 'null',
245
+ 'number',
246
+ 'object',
247
+ 'string'
248
+ ]
249
+ },
250
+ 'stringArray' => {
251
+ 'type' => 'array',
252
+ 'items' => { 'type' => 'string' },
253
+ 'uniqueItems' => true,
254
+ 'default' => []
255
+ }
256
+ }
257
+ }
258
+
259
+ META_DATA = {
260
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
261
+ '$id' => 'https://json-schema.org/draft/2019-09/meta/meta-data',
262
+ '$vocabulary' => {
263
+ 'https://json-schema.org/draft/2019-09/vocab/meta-data' => true
264
+ },
265
+ '$recursiveAnchor' => true,
266
+ 'title' => 'Meta-data vocabulary meta-schema',
267
+ 'type' => ['object', 'boolean'],
268
+ 'properties' => {
269
+ 'title' => {
270
+ 'type' => 'string'
271
+ },
272
+ 'description' => {
273
+ 'type' => 'string'
274
+ },
275
+ 'default' => true,
276
+ 'deprecated' => {
277
+ 'type' => 'boolean',
278
+ 'default' => false
279
+ },
280
+ 'readOnly' => {
281
+ 'type' => 'boolean',
282
+ 'default' => false
283
+ },
284
+ 'writeOnly' => {
285
+ 'type' => 'boolean',
286
+ 'default' => false
287
+ },
288
+ 'examples' => {
289
+ 'type' => 'array',
290
+ 'items' => true
291
+ }
292
+ }
293
+ }
294
+
295
+ FORMAT = {
296
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
297
+ '$id' => 'https://json-schema.org/draft/2019-09/meta/format',
298
+ '$vocabulary' => {
299
+ 'https://json-schema.org/draft/2019-09/vocab/format' => true
300
+ },
301
+ '$recursiveAnchor' => true,
302
+ 'title' => 'Format vocabulary meta-schema',
303
+ 'type' => ['object', 'boolean'],
304
+ 'properties' => {
305
+ 'format' => { 'type' => 'string' }
306
+ }
307
+ }
308
+
309
+ CONTENT = {
310
+ '$schema' => 'https://json-schema.org/draft/2019-09/schema',
311
+ '$id' => 'https://json-schema.org/draft/2019-09/meta/content',
312
+ '$vocabulary' => {
313
+ 'https://json-schema.org/draft/2019-09/vocab/content' => true
314
+ },
315
+ '$recursiveAnchor' => true,
316
+ 'title' => 'Content vocabulary meta-schema',
317
+ 'type' => ['object', 'boolean'],
318
+ 'properties' => {
319
+ 'contentMediaType' => { 'type' => 'string' },
320
+ 'contentEncoding' => { 'type' => 'string' },
321
+ 'contentSchema' => { '$recursiveRef' => '#' }
322
+ }
323
+ }
324
+
325
+ SCHEMAS = {
326
+ URI('https://json-schema.org/draft/2019-09/meta/core') => CORE,
327
+ URI('https://json-schema.org/draft/2019-09/meta/applicator') => APPLICATOR,
328
+ URI('https://json-schema.org/draft/2019-09/meta/validation') => VALIDATION,
329
+ URI('https://json-schema.org/draft/2019-09/meta/meta-data') => META_DATA,
330
+ URI('https://json-schema.org/draft/2019-09/meta/format') => FORMAT,
331
+ URI('https://json-schema.org/draft/2019-09/meta/content') => CONTENT
332
+ }
333
+ end
334
+ end
335
+ end