Skip to content

Commit ccffac7

Browse files
committed
Specify formats in meta schemas
And use the same code paths as custom formats. This fixes an issue where older drafts have access to formats that aren't in the specification.
1 parent 795a9b3 commit ccffac7

File tree

13 files changed

+198
-137
lines changed

13 files changed

+198
-137
lines changed

lib/json_schemer.rb

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ def draft202012
145145
@draft202012 ||= Schema.new(
146146
Draft202012::SCHEMA,
147147
:base_uri => Draft202012::BASE_URI,
148+
:formats => Draft202012::FORMATS,
148149
:ref_resolver => Draft202012::Meta::SCHEMAS.to_proc,
149150
:regexp_resolver => 'ecma'
150151
)
@@ -154,6 +155,7 @@ def draft201909
154155
@draft201909 ||= Schema.new(
155156
Draft201909::SCHEMA,
156157
:base_uri => Draft201909::BASE_URI,
158+
:formats => Draft201909::FORMATS,
157159
:ref_resolver => Draft201909::Meta::SCHEMAS.to_proc,
158160
:regexp_resolver => 'ecma'
159161
)
@@ -164,6 +166,7 @@ def draft7
164166
Draft7::SCHEMA,
165167
:vocabulary => { 'json-schemer://draft7' => true },
166168
:base_uri => Draft7::BASE_URI,
169+
:formats => Draft7::FORMATS,
167170
:regexp_resolver => 'ecma'
168171
)
169172
end
@@ -173,6 +176,7 @@ def draft6
173176
Draft6::SCHEMA,
174177
:vocabulary => { 'json-schemer://draft6' => true },
175178
:base_uri => Draft6::BASE_URI,
179+
:formats => Draft6::FORMATS,
176180
:regexp_resolver => 'ecma'
177181
)
178182
end
@@ -182,6 +186,7 @@ def draft4
182186
Draft4::SCHEMA,
183187
:vocabulary => { 'json-schemer://draft4' => true },
184188
:base_uri => Draft4::BASE_URI,
189+
:formats => Draft4::FORMATS,
185190
:regexp_resolver => 'ecma'
186191
)
187192
end
@@ -190,16 +195,9 @@ def openapi31
190195
@openapi31 ||= Schema.new(
191196
OpenAPI31::SCHEMA,
192197
:base_uri => OpenAPI31::BASE_URI,
198+
:formats => OpenAPI31::FORMATS,
193199
:ref_resolver => OpenAPI31::Meta::SCHEMAS.to_proc,
194-
:regexp_resolver => 'ecma',
195-
# https://spec.openapis.org/oas/latest.html#data-types
196-
:formats => {
197-
'int32' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 32 },
198-
'int64' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 64 },
199-
'float' => proc { |instance, _value| instance.is_a?(Float) },
200-
'double' => proc { |instance, _value| instance.is_a?(Float) },
201-
'password' => proc { |_instance, _value| true }
202-
}
200+
:regexp_resolver => 'ecma'
203201
)
204202
end
205203

@@ -211,17 +209,9 @@ def openapi30
211209
'json-schemer://openapi30' => true
212210
},
213211
:base_uri => OpenAPI30::BASE_URI,
212+
:formats => OpenAPI30::FORMATS,
214213
:ref_resolver => OpenAPI30::Meta::SCHEMAS.to_proc,
215-
:regexp_resolver => 'ecma',
216-
:formats => {
217-
'int32' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 32 },
218-
'int64' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 64 },
219-
'float' => proc { |instance, _value| instance.is_a?(Float) },
220-
'double' => proc { |instance, _value| instance.is_a?(Float) },
221-
'byte' => proc { |instance, _value| Format.decode_content_encoding(instance, 'base64').first },
222-
'binary' => proc { |instance, _value| instance.is_a?(String) && instance.encoding == Encoding::ASCII_8BIT },
223-
'password' => proc { |_instance, _value| true }
224-
}
214+
:regexp_resolver => 'ecma'
225215
)
226216
end
227217

lib/json_schemer/draft201909/meta.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
module JSONSchemer
33
module Draft201909
44
BASE_URI = URI('https://json-schema.org/draft/2019-09/schema')
5+
FORMATS = Draft202012::FORMATS
56
SCHEMA = {
67
'$schema' => 'https://json-schema.org/draft/2019-09/schema',
78
'$id' => 'https://json-schema.org/draft/2019-09/schema',

lib/json_schemer/draft202012/meta.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22
module JSONSchemer
33
module Draft202012
44
BASE_URI = URI('https://json-schema.org/draft/2020-12/schema')
5+
FORMATS = {
6+
'date-time' => Format::DATE_TIME,
7+
'date' => Format::DATE,
8+
'time' => Format::TIME,
9+
'duration' => Format::DURATION,
10+
'email' => Format::EMAIL,
11+
'idn-email' => Format::IDN_EMAIL,
12+
'hostname' => Format::HOSTNAME,
13+
'idn-hostname' => Format::IDN_HOSTNAME,
14+
'ipv4' => Format::IPV4,
15+
'ipv6' => Format::IPV6,
16+
'uri' => Format::URI,
17+
'uri-reference' => Format::URI_REFERENCE,
18+
'iri' => Format::IRI,
19+
'iri-reference' => Format::IRI_REFERENCE,
20+
'uuid' => Format::UUID,
21+
'uri-template' => Format::URI_TEMPLATE,
22+
'json-pointer' => Format::JSON_POINTER,
23+
'relative-json-pointer' => Format::RELATIVE_JSON_POINTER,
24+
'regex' => Format::REGEX
25+
}
526
SCHEMA = {
627
'$schema' => 'https://json-schema.org/draft/2020-12/schema',
728
'$id' => 'https://json-schema.org/draft/2020-12/schema',

lib/json_schemer/draft202012/vocab/format_annotation.rb

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,12 @@ module Draft202012
44
module Vocab
55
module FormatAnnotation
66
class Format < Keyword
7-
extend JSONSchemer::Format
8-
9-
DEFAULT_FORMAT = proc do |instance, value|
10-
!instance.is_a?(String) || valid_spec_format?(instance, value)
11-
rescue UnknownFormat
12-
true
13-
end
14-
157
def error(formatted_instance_location:, **)
168
"value at #{formatted_instance_location} does not match format: #{value}"
179
end
1810

1911
def parse
20-
root.format && root.formats.fetch(value) { root.meta_schema.formats.fetch(value, DEFAULT_FORMAT) }
12+
root.format && root.fetch_format(value, false)
2113
end
2214

2315
def validate(instance, instance_location, keyword_location, _context)

lib/json_schemer/draft202012/vocab/format_assertion.rb

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,12 @@ module Draft202012
44
module Vocab
55
module FormatAssertion
66
class Format < Keyword
7-
extend JSONSchemer::Format
8-
9-
DEFAULT_FORMAT = proc do |instance, value|
10-
!instance.is_a?(String) || valid_spec_format?(instance, value)
11-
end
12-
137
def error(formatted_instance_location:, **)
148
"value at #{formatted_instance_location} does not match format: #{value}"
159
end
1610

1711
def parse
18-
root.format && root.formats.fetch(value) { root.meta_schema.formats.fetch(value, DEFAULT_FORMAT) }
12+
root.format && root.fetch_format(value) { raise UnknownFormat, value }
1913
end
2014

2115
def validate(instance, instance_location, keyword_location, _context)

lib/json_schemer/draft4/meta.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
module JSONSchemer
33
module Draft4
44
BASE_URI = URI('http://json-schema.org/draft-04/schema#')
5+
FORMATS = Draft6::FORMATS.dup
6+
FORMATS.delete('uri-reference')
7+
FORMATS.delete('uri-template')
8+
FORMATS.delete('json-pointer')
59
SCHEMA = {
610
'id' => 'http://json-schema.org/draft-04/schema#',
711
'$schema' => 'http://json-schema.org/draft-04/schema#',

lib/json_schemer/draft6/meta.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
module JSONSchemer
33
module Draft6
44
BASE_URI = URI('http://json-schema.org/draft-06/schema#')
5+
FORMATS = Draft7::FORMATS.dup
6+
FORMATS.delete('date')
7+
FORMATS.delete('time')
8+
FORMATS.delete('idn-email')
9+
FORMATS.delete('idn-hostname')
10+
FORMATS.delete('iri')
11+
FORMATS.delete('iri-reference')
12+
FORMATS.delete('relative-json-pointer')
13+
FORMATS.delete('regex')
514
SCHEMA = {
615
'$schema' => 'http://json-schema.org/draft-06/schema#',
716
'$id' => 'http://json-schema.org/draft-06/schema#',

lib/json_schemer/draft7/meta.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
module JSONSchemer
33
module Draft7
44
BASE_URI = URI('http://json-schema.org/draft-07/schema#')
5+
FORMATS = Draft201909::FORMATS.dup
6+
FORMATS.delete('duration')
7+
FORMATS.delete('uuid')
58
SCHEMA = {
69
'$schema' => 'http://json-schema.org/draft-07/schema#',
710
'$id' => 'http://json-schema.org/draft-07/schema#',

0 commit comments

Comments
 (0)