json_schemer 2.3.0 → 2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5ec5b8e547dc3a64b134054ec80b0f40cf9453cba4cce430995e6ae165a6e07
4
- data.tar.gz: 943423f15ba47e7b8ecc5fbf3d1b566679c43e84e3d70bbc4e0f47f126e4275f
3
+ metadata.gz: 04dbbf738ea9253437566fb50075ee7603fd0b536324181aebb0573c32c7f7bc
4
+ data.tar.gz: 29337d5892b33a2f74e435370986f059d7dd9762352bea610e7668dca3171e09
5
5
  SHA512:
6
- metadata.gz: 43c26354e594ae3219e0edd22e18b6d89a64b6cbad6bc4ac3e85750ccc128c3827d7aa38b1dc0d48a232c733250467939eaa8d6049ab8d34c75f5a0ac6f0e715
7
- data.tar.gz: eced2c5592c64adfffb89923d28a363494f09bdd87202233706baa24ad4067e8240a85120a29eb2145b70a5f9bbf85e3a7f2f71fbdd1a89a74bc2cc6e3a243ed
6
+ metadata.gz: 90f1510bcc40ad9500904453dee34434b91ef45b8ab7d8be84dc728aae4d4c1a4556037f1ae8b48595198529973fe2d1e5c20a64e5aeb9871cd6fddd23636268
7
+ data.tar.gz: c7e8a861d8f763d5248d79d486d8b253b9f81e40952e896d53b7dad84bdd5197a70224008e79de5cf5b6e7a3e9a8e646bd8af4188ae6a87c4a7ac9011998f36f
@@ -6,7 +6,7 @@ jobs:
6
6
  fail-fast: false
7
7
  matrix:
8
8
  os: [ubuntu-latest, windows-latest, macos-latest]
9
- ruby: [2.7, 3.0, 3.1, 3.2, 3.3, head, jruby, jruby-head, truffleruby, truffleruby-head]
9
+ ruby: [2.7, 3.0, 3.1, 3.2, 3.3, 3.4, head, jruby, jruby-head, truffleruby, truffleruby-head]
10
10
  exclude:
11
11
  - os: ubuntu-latest
12
12
  ruby: head
data/CHANGELOG.md CHANGED
@@ -1,12 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.4.0] - 2025-02-01
4
+
5
+ ### Bug Fixes
6
+
7
+ - Store schema resource file URIs as strings to prevent conflicts: https://github.com/davishmcclurg/json_schemer/pull/189
8
+ - Require OpenAPI `discriminator` instances to be objects: https://github.com/davishmcclurg/json_schemer/pull/206
9
+ - Pass configuration options to subschemas: https://github.com/davishmcclurg/json_schemer/pull/208
10
+ - Check applicable instance types in OpenAPI `format` extensions: https://github.com/davishmcclurg/json_schemer/pull/209
11
+ - Use correct max values for OpenAPI `int32`/`int64` formats: https://github.com/davishmcclurg/json_schemer/commit/386c2a6fe089350c61775716643ef0600898060e
12
+
13
+ [2.4.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.4.0
14
+
3
15
  ## [2.3.0] - 2024-05-30
4
16
 
5
- ## Ruby Versions
17
+ ### Ruby Versions
6
18
 
7
19
  - Ruby 2.5 and 2.6 are no longer supported.
8
20
 
9
- ## Bug Fixes
21
+ ### Bug Fixes
10
22
 
11
23
  - Remove `base64` runtime dependency: https://github.com/davishmcclurg/json_schemer/pull/182
12
24
  - Relax `uuid` format validation: https://github.com/davishmcclurg/json_schemer/pull/183
@@ -15,7 +27,7 @@
15
27
 
16
28
  ## [2.2.0] - 2024-03-02
17
29
 
18
- ## Bug Fixes
30
+ ### Bug Fixes
19
31
 
20
32
  - Support symbol keys when accessing original instance: https://github.com/davishmcclurg/json_schemer/commit/d52c130e9967919c6cf1c9dbc3f0babfb8b01cf8
21
33
  - Support custom keywords in nested schemas: https://github.com/davishmcclurg/json_schemer/commit/93c85a5006981347c7e9a4c11b73c6bdb65d8ba2
@@ -24,7 +36,7 @@
24
36
  - Handle parse errors during schema validation: https://github.com/davishmcclurg/json_schemer/pull/171
25
37
  - Follow refs when finding default property values: https://github.com/davishmcclurg/json_schemer/pull/175
26
38
 
27
- ## Features
39
+ ### Features
28
40
 
29
41
  - Global configuration with `Configuration` object: https://github.com/davishmcclurg/json_schemer/pull/170
30
42
  - Symbol key property defaults with `insert_property_defaults: :symbol`: https://github.com/davishmcclurg/json_schemer/commit/a72473dc84199107ddedc8998950e5b82273232a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json_schemer (2.3.0)
4
+ json_schemer (2.4.0)
5
5
  bigdecimal
6
6
  hana (~> 1.3)
7
7
  regexp_parser (~> 2.0)
@@ -11,24 +11,24 @@ GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
13
  base64 (0.2.0)
14
- bigdecimal (3.1.8)
15
- bigdecimal (3.1.8-java)
16
- concurrent-ruby (1.2.2)
17
- csv (3.2.8)
18
- docile (1.4.0)
14
+ bigdecimal (3.1.9)
15
+ bigdecimal (3.1.9-java)
16
+ concurrent-ruby (1.3.5)
17
+ csv (3.3.2)
18
+ docile (1.4.1)
19
19
  hana (1.3.7)
20
- i18n (1.14.1)
20
+ i18n (1.14.6)
21
21
  concurrent-ruby (~> 1.0)
22
22
  i18n-debug (1.2.0)
23
23
  i18n (< 2)
24
- minitest (5.15.0)
25
- rake (13.1.0)
26
- regexp_parser (2.9.2)
24
+ minitest (5.25.4)
25
+ rake (13.2.1)
26
+ regexp_parser (2.10.0)
27
27
  simplecov (0.22.0)
28
28
  docile (~> 1.1)
29
29
  simplecov-html (~> 0.11)
30
30
  simplecov_json_formatter (~> 0.1)
31
- simplecov-html (0.12.3)
31
+ simplecov-html (0.13.1)
32
32
  simplecov_json_formatter (0.1.4)
33
33
  simpleidn (0.2.3)
34
34
 
@@ -38,7 +38,7 @@ PLATFORMS
38
38
 
39
39
  DEPENDENCIES
40
40
  base64
41
- bundler (~> 2.0)
41
+ bundler (~> 2.4.0)
42
42
  csv
43
43
  i18n
44
44
  i18n-debug
@@ -48,4 +48,4 @@ DEPENDENCIES
48
48
  simplecov (~> 0.22)
49
49
 
50
50
  BUNDLED WITH
51
- 2.3.27
51
+ 2.4.22
data/README.md CHANGED
@@ -95,18 +95,6 @@ JSONSchemer.validate_schema({ '$id' => '#invalid' }).to_a
95
95
  # "type"=>"pattern",
96
96
  # "error"=>"string at `/$id` does not match pattern: ^[^#]*#?$"}]
97
97
 
98
- JSONSchemer.schema({ '$id' => 'valid' }).valid_schema?
99
- # => true
100
-
101
- JSONSchemer.schema({ '$id' => '#invalid' }).validate_schema.to_a
102
- # => [{"data"=>"#invalid",
103
- # "data_pointer"=>"/$id",
104
- # "schema"=>{"$ref"=>"#/$defs/uriReferenceString", "$comment"=>"Non-empty fragments not allowed.", "pattern"=>"^[^#]*#?$"},
105
- # "schema_pointer"=>"/properties/$id",
106
- # "root_schema"=>{...meta schema},
107
- # "type"=>"pattern",
108
- # "error"=>"string at `/$id` does not match pattern: ^[^#]*#?$"}]
109
-
110
98
  # subschemas
111
99
 
112
100
  schema = {
data/json_schemer.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.required_ruby_version = '>= 2.7'
24
24
 
25
25
  spec.add_development_dependency "base64"
26
- spec.add_development_dependency "bundler", "~> 2.0"
26
+ spec.add_development_dependency "bundler", "~> 2.4.0"
27
27
  spec.add_development_dependency "rake", "~> 13.0"
28
28
  spec.add_development_dependency "minitest", "~> 5.0"
29
29
  spec.add_development_dependency "simplecov", "~> 0.22"
@@ -4,6 +4,10 @@ module JSONSchemer
4
4
  module Vocab
5
5
  module Validation
6
6
  class Type < Keyword
7
+ def self.valid_integer?(instance)
8
+ instance.is_a?(Numeric) && (instance.is_a?(Integer) || instance.floor == instance)
9
+ end
10
+
7
11
  def error(formatted_instance_location:, **)
8
12
  case value
9
13
  when 'null'
@@ -45,7 +49,7 @@ module JSONSchemer
45
49
  when 'number'
46
50
  instance.is_a?(Numeric)
47
51
  when 'integer'
48
- instance.is_a?(Numeric) && (instance.is_a?(Integer) || instance.floor == instance)
52
+ self.class.valid_integer?(instance)
49
53
  when 'string'
50
54
  instance.is_a?(String)
51
55
  when 'array'
@@ -4,9 +4,8 @@ module JSONSchemer
4
4
  module Vocab
5
5
  module Validation
6
6
  class Type < Draft202012::Vocab::Validation::Type
7
- private
8
- def valid_type(type, instance)
9
- type == 'integer' ? instance.is_a?(Integer) : super
7
+ def self.valid_integer?(instance)
8
+ instance.is_a?(Integer)
10
9
  end
11
10
  end
12
11
 
@@ -4,8 +4,10 @@ module JSONSchemer
4
4
  BASE_URI = URI('json-schemer://openapi30/schema')
5
5
  # https://spec.openapis.org/oas/v3.0.3#data-types
6
6
  FORMATS = OpenAPI31::FORMATS.merge(
7
- 'byte' => proc { |instance, _value| ContentEncoding::BASE64.call(instance).first },
8
- 'binary' => proc { |instance, _value| instance.is_a?(String) && instance.encoding == Encoding::BINARY },
7
+ 'int32' => proc { |instance, _format| !Draft4::Vocab::Validation::Type.valid_integer?(instance) || instance.floor.bit_length < 32 },
8
+ 'int64' => proc { |instance, _format| !Draft4::Vocab::Validation::Type.valid_integer?(instance) || instance.floor.bit_length < 64 },
9
+ 'byte' => proc { |instance, _value| !instance.is_a?(String) || ContentEncoding::BASE64.call(instance).first },
10
+ 'binary' => proc { |instance, _value| !instance.is_a?(String) || instance.encoding == Encoding::BINARY },
9
11
  'date' => Format::DATE
10
12
  )
11
13
  SCHEMA = {
@@ -4,10 +4,10 @@ module JSONSchemer
4
4
  BASE_URI = URI('https://spec.openapis.org/oas/3.1/dialect/base')
5
5
  # https://spec.openapis.org/oas/v3.1.0#data-types
6
6
  FORMATS = {
7
- 'int32' => proc { |instance, _format| instance.is_a?(Integer) && instance.bit_length <= 32 },
8
- 'int64' => proc { |instance, _format| instance.is_a?(Integer) && instance.bit_length <= 64 },
9
- 'float' => proc { |instance, _format| instance.is_a?(Float) },
10
- 'double' => proc { |instance, _format| instance.is_a?(Float) },
7
+ 'int32' => proc { |instance, _format| !Draft202012::Vocab::Validation::Type.valid_integer?(instance) || instance.floor.bit_length < 32 },
8
+ 'int64' => proc { |instance, _format| !Draft202012::Vocab::Validation::Type.valid_integer?(instance) || instance.floor.bit_length < 64 },
9
+ 'float' => proc { |instance, _format| !instance.is_a?(Numeric) || instance.is_a?(Float) },
10
+ 'double' => proc { |instance, _format| !instance.is_a?(Numeric) || instance.is_a?(Float) },
11
11
  'password' => proc { |_instance, _format| true }
12
12
  }
13
13
  SCHEMA = {
@@ -100,7 +100,7 @@ module JSONSchemer
100
100
  end
101
101
 
102
102
  def validate(instance, instance_location, keyword_location, context)
103
- return result(instance, instance_location, keyword_location, true) unless instance.is_a?(Hash)
103
+ return result(instance, instance_location, keyword_location, false) unless instance.is_a?(Hash)
104
104
 
105
105
  property_name = value.fetch('propertyName')
106
106
 
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module JSONSchemer
3
+ class Resources
4
+ def initialize
5
+ @resources = {}
6
+ end
7
+
8
+ def [](uri)
9
+ @resources[uri.to_s]
10
+ end
11
+
12
+ def []=(uri, resource)
13
+ @resources[uri.to_s] = resource
14
+ end
15
+
16
+ def fetch(uri)
17
+ @resources.fetch(uri.to_s)
18
+ end
19
+
20
+ def key?(uri)
21
+ @resources.key?(uri.to_s)
22
+ end
23
+ end
24
+ end
@@ -15,6 +15,7 @@ module JSONSchemer
15
15
  end
16
16
  end
17
17
 
18
+ extend Forwardable
18
19
  include Output
19
20
 
20
21
  SCHEMA_KEYWORD_CLASS = Draft202012::Vocab::Core::Schema
@@ -44,7 +45,8 @@ module JSONSchemer
44
45
 
45
46
  attr_accessor :base_uri, :meta_schema, :keywords, :keyword_order
46
47
  attr_reader :value, :parent, :root, :configuration, :parsed
47
- attr_reader :vocabulary, :format, :formats, :content_encodings, :content_media_types, :custom_keywords, :before_property_validation, :after_property_validation, :insert_property_defaults
48
+ def_delegators :@configuration, :vocabulary, :format, :formats, :content_encodings, :content_media_types, :before_property_validation, :after_property_validation, :insert_property_defaults
49
+ def_delegator :@configuration, :keywords, :custom_keywords
48
50
 
49
51
  def initialize(
50
52
  value,
@@ -75,24 +77,27 @@ module JSONSchemer
75
77
  @root = root
76
78
  @keyword = keyword
77
79
  @schema = self
78
- @configuration = configuration
79
80
  @base_uri = base_uri
80
81
  @meta_schema = meta_schema
81
- @vocabulary = vocabulary
82
- @format = format
83
- @formats = formats
84
- @content_encodings = content_encodings
85
- @content_media_types = content_media_types
86
- @custom_keywords = keywords
87
- @before_property_validation = Array(before_property_validation)
88
- @after_property_validation = Array(after_property_validation)
89
- @insert_property_defaults = insert_property_defaults
90
- @property_default_resolver = property_default_resolver
91
- @original_ref_resolver = ref_resolver
92
- @original_regexp_resolver = regexp_resolver
93
- @output_format = output_format
94
- @resolve_enumerators = resolve_enumerators
95
- @access_mode = access_mode
82
+ @configuration = Configuration.new(
83
+ :base_uri => base_uri,
84
+ :meta_schema => meta_schema,
85
+ :vocabulary => vocabulary,
86
+ :format => format,
87
+ :formats => formats,
88
+ :content_encodings => content_encodings,
89
+ :content_media_types => content_media_types,
90
+ :keywords => keywords,
91
+ :before_property_validation => Array(before_property_validation),
92
+ :after_property_validation => Array(after_property_validation),
93
+ :insert_property_defaults => insert_property_defaults,
94
+ :property_default_resolver => property_default_resolver,
95
+ :ref_resolver => ref_resolver,
96
+ :regexp_resolver => regexp_resolver,
97
+ :output_format => output_format,
98
+ :resolve_enumerators => resolve_enumerators,
99
+ :access_mode => access_mode
100
+ )
96
101
  @parsed = parse
97
102
  end
98
103
 
@@ -100,7 +105,7 @@ module JSONSchemer
100
105
  validate(instance, :output_format => 'flag', **options).fetch('valid')
101
106
  end
102
107
 
103
- def validate(instance, output_format: @output_format, resolve_enumerators: @resolve_enumerators, access_mode: @access_mode)
108
+ def validate(instance, output_format: @configuration.output_format, resolve_enumerators: @configuration.resolve_enumerators, access_mode: @configuration.access_mode)
104
109
  instance_location = Location.root
105
110
  context = Context.new(instance, [], nil, (!insert_property_defaults && output_format == 'flag'), access_mode)
106
111
  result = validate_instance(deep_stringify_keys(instance), instance_location, root_keyword_location, context)
@@ -328,7 +333,7 @@ module JSONSchemer
328
333
  end
329
334
 
330
335
  def resources
331
- @resources ||= { :lexical => {}, :dynamic => {} }
336
+ @resources ||= { :lexical => Resources.new, :dynamic => Resources.new }
332
337
  end
333
338
 
334
339
  def error(formatted_instance_location:, **options)
@@ -340,17 +345,17 @@ module JSONSchemer
340
345
  end
341
346
 
342
347
  def ref_resolver
343
- @ref_resolver ||= @original_ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : @original_ref_resolver
348
+ @ref_resolver ||= @configuration.ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : @configuration.ref_resolver
344
349
  end
345
350
 
346
351
  def regexp_resolver
347
- @regexp_resolver ||= case @original_regexp_resolver
352
+ @regexp_resolver ||= case @configuration.regexp_resolver
348
353
  when 'ecma'
349
354
  CachedResolver.new(&ECMA_REGEXP_RESOLVER)
350
355
  when 'ruby'
351
356
  CachedResolver.new(&RUBY_REGEXP_RESOLVER)
352
357
  else
353
- @original_regexp_resolver
358
+ @configuration.regexp_resolver
354
359
  end
355
360
  end
356
361
 
@@ -407,7 +412,11 @@ module JSONSchemer
407
412
  end
408
413
 
409
414
  def property_default_resolver
410
- @property_default_resolver ||= insert_property_defaults == :symbol ? SYMBOL_PROPERTY_DEFAULT_RESOLVER : DEFAULT_PROPERTY_DEFAULT_RESOLVER
415
+ @property_default_resolver ||= if @configuration.property_default_resolver
416
+ @configuration.property_default_resolver
417
+ else
418
+ insert_property_defaults == :symbol ? SYMBOL_PROPERTY_DEFAULT_RESOLVER : DEFAULT_PROPERTY_DEFAULT_RESOLVER
419
+ end
411
420
  end
412
421
 
413
422
  def resolve_enumerators!(output)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module JSONSchemer
3
- VERSION = '2.3.0'
3
+ VERSION = '2.4.0'
4
4
  end
data/lib/json_schemer.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'bigdecimal'
3
+ require 'forwardable'
3
4
  require 'ipaddr'
4
5
  require 'json'
5
6
  require 'net/http'
@@ -59,6 +60,7 @@ require 'json_schemer/openapi30/vocab/base'
59
60
  require 'json_schemer/openapi30/vocab'
60
61
  require 'json_schemer/openapi'
61
62
  require 'json_schemer/configuration'
63
+ require 'json_schemer/resources'
62
64
  require 'json_schemer/schema'
63
65
 
64
66
  module JSONSchemer
@@ -103,12 +105,16 @@ module JSONSchemer
103
105
 
104
106
  WINDOWS_URI_PATH_REGEX = /\A\/[a-z]:/i
105
107
 
108
+ # :nocov:
109
+ URI_PARSER = URI.const_defined?(:RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
110
+ # :nocov:
111
+
106
112
  FILE_URI_REF_RESOLVER = proc do |uri|
107
113
  raise InvalidFileURI, 'must use `file` scheme' unless uri.scheme == 'file'
108
114
  raise InvalidFileURI, 'cannot have a host (use `file:///`)' if uri.host && !uri.host.empty?
109
115
  path = uri.path
110
116
  path = path[1..-1] if path.match?(WINDOWS_URI_PATH_REGEX)
111
- JSON.parse(File.read(URI::DEFAULT_PARSER.unescape(path)))
117
+ JSON.parse(File.read(URI_PARSER.unescape(path)))
112
118
  end
113
119
 
114
120
  class << self
@@ -246,7 +252,7 @@ module JSONSchemer
246
252
  when String
247
253
  JSON.parse(schema)
248
254
  when Pathname
249
- base_uri = URI.parse(File.join('file:', URI::DEFAULT_PARSER.escape(schema.realpath.to_s)))
255
+ base_uri = URI.parse(File.join('file:', URI_PARSER.escape(schema.realpath.to_s)))
250
256
  options[:base_uri] = base_uri
251
257
  if options.key?(:ref_resolver)
252
258
  FILE_URI_REF_RESOLVER.call(base_uri)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_schemer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Harsha
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-05-30 00:00:00.000000000 Z
10
+ date: 2025-02-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: base64
@@ -30,14 +29,14 @@ dependencies:
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '2.0'
32
+ version: 2.4.0
34
33
  type: :development
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: '2.0'
39
+ version: 2.4.0
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: rake
43
42
  requirement: !ruby/object:Gem::Requirement
@@ -178,7 +177,6 @@ dependencies:
178
177
  - - "~>"
179
178
  - !ruby/object:Gem::Version
180
179
  version: '0.2'
181
- description:
182
180
  email:
183
181
  - davishmcclurg@gmail.com
184
182
  executables:
@@ -246,6 +244,7 @@ files:
246
244
  - lib/json_schemer/openapi31/vocab.rb
247
245
  - lib/json_schemer/openapi31/vocab/base.rb
248
246
  - lib/json_schemer/output.rb
247
+ - lib/json_schemer/resources.rb
249
248
  - lib/json_schemer/result.rb
250
249
  - lib/json_schemer/schema.rb
251
250
  - lib/json_schemer/version.rb
@@ -253,7 +252,6 @@ homepage: https://github.com/davishmcclurg/json_schemer
253
252
  licenses:
254
253
  - MIT
255
254
  metadata: {}
256
- post_install_message:
257
255
  rdoc_options: []
258
256
  require_paths:
259
257
  - lib
@@ -268,8 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
266
  - !ruby/object:Gem::Version
269
267
  version: '0'
270
268
  requirements: []
271
- rubygems_version: 3.5.3
272
- signing_key:
269
+ rubygems_version: 3.6.2
273
270
  specification_version: 4
274
271
  summary: JSON Schema validator. Supports drafts 4, 6, 7, 2019-09, 2020-12, OpenAPI
275
272
  3.0, and OpenAPI 3.1.