simple_json_schema 0.1.3 → 0.1.4

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: fd9171c82ee82f6182b25f9e8cb4d6f139dce7ff84d66131a9ea50c3c9728197
4
- data.tar.gz: 4b9fbb3fe5dc2101a66dfe70a46d11d368ecd7811aa7056f18c1d4dc91f27b7d
3
+ metadata.gz: 8bfd995209a8432bc92730f10961b61d8d9e0d1e3cd1aaf06432d76654dd7d66
4
+ data.tar.gz: 043f347f1c497be224fcefdd153b23bb16024410d8d8865555c6dd752d28a2f2
5
5
  SHA512:
6
- metadata.gz: 557d9a88155358cffb6e13e2b4ca2b9036ad2d38f60f61ab4692080f72a4d19028d63981a4cb965aeb735def558d2b2697d00cb057577c93769200ee7f78e916
7
- data.tar.gz: 8f57abf5721f17ff7695c5372554b1c35a6e91b273e85b3becffdbfda225e677130dc2eae5761e1d5fc269b5d9f5936f981a9eeb427e10a745e3b97dad99a2a7
6
+ metadata.gz: 016b1db271f0eada2ef8dd65ccc2eaf89294685231fe6645578b8959e20011a6418e9176333c6b1ff9f9f455d309cc232177a7b1958f7e9f84fc88994b668b77
7
+ data.tar.gz: 3c8e6f11c651ccd1537eaf5ecfb010125f837568bce1d9b07bfebd431ad5eb09c7760e8f43b1ffb62c24977276e3b9959372b2152c012a23e19f17aa81c766a2
@@ -7,7 +7,6 @@ AllCops:
7
7
  SuggestExtensions: false
8
8
  TargetRubyVersion: 2.6
9
9
  Exclude:
10
- - bin/**/*
11
10
  - vendor/ruby/**/*
12
11
  - .irbrc
13
12
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_json_schema (0.1.3)
4
+ simple_json_schema (0.1.4)
5
5
  activesupport (~> 6.0)
6
6
  addressable (~> 2.7)
7
7
  ecma-re-validator (~> 0.3)
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![coverage report](https://gitlab.com/vliper/simple_json_schema/badges/master/coverage.svg)](https://gitlab.com/vliper/simple_json_schema/-/commits/master)
5
5
  [![Gem Version](https://badge.fury.io/rb/simple_json_schema.svg)](https://badge.fury.io/rb/simple_json_schema)
6
6
 
7
- This implementation of the JSON Schema validation is based on the [JSONSchemer](https://github.com/davishmcclurg/json_schemer) (whit is the recommended to be used), but only implement the Draft7, whit [limitations](https://gitlab.com/vliper/simple_json_schema/-/blob/master/spec/simple_json_schema/json_schema_test_suite_spec.rb#L15) and some feature embedded.
7
+ This implementation of the JSON Schema validation is based on the [JSONSchemer](https://github.com/davishmcclurg/json_schemer) (WHIT IS THE RECOMMENDED TO BE USED!), but only implement the Draft7, whit [limitations](https://gitlab.com/vliper/simple_json_schema/-/blob/master/spec/simple_json_schema/json_schema_test_suite_spec.rb#L26) and some feature embedded.
8
8
 
9
9
  # Installation
10
10
 
@@ -64,10 +64,18 @@ Whit options is possible to improve the behavior.
64
64
  | ---- | ----------- | ------- | -------------- |
65
65
  | after_property_validation | Call after validate a Property | nil | Proc to receive Scope object |
66
66
  | before_property_validation | Call before validate a Property | nil | Proc to receive Scope object |
67
- | cache | The object to do the cache for schema (future) and regex | {} per execution | any object whit implement fetch(name) { callback } |
67
+ | cache | The object to do the cache for schema ref and regex | Cache class per execution | any object whit implement fetch(name) { callback } |
68
68
  | cast | Cast the values | false | true/false |
69
69
  | insert_defaults | Insert the default property if not defined at the validation | false | true/false |
70
70
 
71
+ #### Extra attributes
72
+ Some extra implementations on types (THIS IS NOT ON THE DRAFT7 DEFINITION!)
73
+
74
+ | Type | Attribute | Description | Allowed values |
75
+ | string | required | Will evaluate the `blank?` concept on the string | true/false |
76
+ | integer | required | Will enforce value != 0 | true/false |
77
+ | number | required | Will enforce value != 0.0 | true/false |
78
+
71
79
  ## Development
72
80
 
73
81
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'pry-byebug'
6
+
7
+ require 'simple_json_schema'
8
+ require 'json'
9
+
10
+ if ARGV.size != 2
11
+ puts 'simple_json_schema <JSON_DATA> <JSON_SCHEMA>'
12
+ exit(1)
13
+ end
14
+
15
+ data = JSON.parse(ARGV[0])
16
+ schema = JSON.parse(ARGV[1])
17
+
18
+ valid = SimpleJSONSchema.valid(data, schema, resolver: proc do |uri|
19
+ if uri.host == 'localhost'
20
+ # Resolve localhost test schemas
21
+ path = Pathname.new(__dir__).join('..', 'spec', 'json-schema-test-suite', 'remotes', uri.path.delete_prefix('/'))
22
+ JSON.parse(path.read)
23
+ else
24
+ JSON.parse(::Net::HTTP.get(uri))
25
+ end
26
+ end)
27
+
28
+ if valid.empty?
29
+ puts 'valid!'
30
+ else
31
+ puts valid
32
+ end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'simple_json_schema/version'
4
4
 
5
+ require 'net/http'
6
+
5
7
  require 'active_support/core_ext/hash'
6
8
  require 'addressable/template'
7
9
  require 'ecma-re-validator'
@@ -17,10 +19,13 @@ require 'simple_json_schema/validators/number'
17
19
  require 'simple_json_schema/validators/string'
18
20
 
19
21
  require 'simple_json_schema/concerns/hash_acessor'
22
+ require 'simple_json_schema/uri_extender'
23
+ require 'simple_json_schema/cache'
20
24
  require 'simple_json_schema/checker'
21
25
  require 'simple_json_schema/items_helper'
22
26
  require 'simple_json_schema/properties_helper'
23
27
  require 'simple_json_schema/regex_helper'
28
+ require 'simple_json_schema/ref_helper'
24
29
  require 'simple_json_schema/scope'
25
30
  require 'simple_json_schema/validator'
26
31
 
@@ -31,6 +36,7 @@ module SimpleJSONSchema
31
36
  'http://json-schema.org/draft-07/schema#' => :draft7
32
37
  }.freeze
33
38
 
39
+ NET_HTTP_REF_RESOLVER = proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
34
40
  DEFAULT_SCHEMA = 'http://json-schema.org/draft-07/schema#'
35
41
 
36
42
  class << self
@@ -48,6 +54,8 @@ module SimpleJSONSchema
48
54
  scope = Scope.new(data: data, schema: schema, draft: draft_class(schema), options: options)
49
55
  Validator.validate(scope)
50
56
  scope.errors
57
+ rescue StandardError => e
58
+ scope.error(:invalid, exception: e.message)
51
59
  end
52
60
 
53
61
  private
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ class Cache
5
+ attr_reader :memory
6
+
7
+ def initialize
8
+ @memory = {}
9
+ end
10
+
11
+ def fetch(key)
12
+ memory[key] ||= yield
13
+ end
14
+ end
15
+ end
@@ -2,20 +2,24 @@
2
2
 
3
3
  module SimpleJSONSchema
4
4
  module Checker
5
+ JSON_POINTER_REGEX_STRING = '(\/([^~\/]|~[01])*)*'
6
+ JSON_POINTER_REGEX = /\A#{JSON_POINTER_REGEX_STRING}\z/.freeze
7
+ RELATIVE_JSON_POINTER_REGEX = /\A(0|[1-9]\d*)(#|#{JSON_POINTER_REGEX_STRING})?\z/.freeze
8
+
5
9
  class << self
6
10
  def at_value(scope, check, operation)
7
11
  over = scope[check]
8
- scope.error(check) if over && scope.value&.public_send(operation, over)
12
+ scope.error(check, fail_on: "#{operation} #{over}") if over && scope.value&.public_send(operation, over)
9
13
  end
10
14
 
11
15
  def at_size(scope, check, operation)
12
16
  over = scope[check]
13
- scope.error(check) if over && scope.value&.size&.public_send(operation, over)
17
+ scope.error(check, fail_on: "#{operation} #{over}") if over && scope.value&.size&.public_send(operation, over)
14
18
  end
15
19
 
16
- def required(scope)
20
+ def required_keys(scope)
17
21
  required = scope[:required]
18
- return unless required
22
+ return unless required.is_a?(Array)
19
23
 
20
24
  missing_keys = required - scope.value.keys
21
25
  scope.error(:required, missing_keys: missing_keys) if missing_keys.any?
@@ -36,6 +40,14 @@ module SimpleJSONSchema
36
40
 
37
41
  scope.error(:const) if scope.key?(:const) && scope[:const] != scope.value
38
42
  end
43
+
44
+ def json_pointer?(value)
45
+ JSON_POINTER_REGEX.match?(value)
46
+ end
47
+
48
+ def relative_json_pointer?(value)
49
+ RELATIVE_JSON_POINTER_REGEX.match?(value)
50
+ end
39
51
  end
40
52
  end
41
53
  end
@@ -3,7 +3,7 @@
3
3
  module SimpleJSONSchema
4
4
  module Concerns
5
5
  module HashAccessor
6
- def hash_accessor(hash_name, *accessors)
6
+ def hash_accessor(hash_name, accessors)
7
7
  define_method(hash_name) do
8
8
  instance_variable_get("@#{hash_name}") ||
9
9
  instance_variable_set("@#{hash_name}", {})
@@ -4,11 +4,25 @@ module SimpleJSONSchema
4
4
  module PropertiesHelper
5
5
  class << self
6
6
  def checkers(scope)
7
- Checker.required(scope)
7
+ Checker.required_keys(scope)
8
8
  Checker.at_size(scope, :maxProperties, :>)
9
9
  Checker.at_size(scope, :minProperties, :<)
10
10
  end
11
11
 
12
+ def each_dependency(scope)
13
+ dependencies = scope[:dependencies]
14
+ return unless dependencies.is_a?(Hash)
15
+
16
+ value = scope.value
17
+ return unless value.is_a?(Hash)
18
+
19
+ dependencies.each_key do |dependency|
20
+ next unless value.key?(dependency)
21
+
22
+ yield([:dependencies, dependency])
23
+ end
24
+ end
25
+
12
26
  def processe_defualt(scope)
13
27
  return unless scope.options[:insert_defaults] == true
14
28
 
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module RefHelper
5
+ INTEGER_REGEX = /\A-?\d+\Z/.freeze
6
+ POINTER_SPLIT = %r{(?<!\^)/}.freeze
7
+ POINTER_GSUB = %r{\^[/^]|~[01]}.freeze
8
+ POINTER_ESC = { '^/' => '/', '^^' => '^', '~0' => '~', '~1' => '/' }.freeze
9
+ RefPointer = Struct.new(:ref_paths, :segment, :segment_paths, :parent_uri, keyword_init: true)
10
+
11
+ class << self
12
+ def pointer(scope)
13
+ ref = scope[:$ref]
14
+ return nil if ref.nil?
15
+
16
+ if ref.start_with?('#')
17
+ local_ref(scope, ref[1..])
18
+ else
19
+ ref_uri = URIExtender.join_uri(scope.parent_uri, ref)
20
+ if (id = scope.loaded_ids[ref_uri.to_s])
21
+ return RefPointer.new(ref_paths: id[:schema_paths], segment: id[:schema], parent_uri: ref_uri)
22
+ end
23
+
24
+ uri_ref(scope, ref_uri)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def local_ref(scope, ref)
31
+ return RefPointer.new unless Checker.json_pointer?(ref)
32
+
33
+ paths, parent_uri = path_of_ref(scope.schema, ref)
34
+ RefPointer.new(ref_paths: paths, parent_uri: parent_uri || scope.parent_uri)
35
+ end
36
+
37
+ def uri_ref(scope, ref_uri)
38
+ segment = resolver_uri(scope, ref_uri)
39
+ reref_base(segment, scope.schema_paths)
40
+ segment_paths, parent_uri = path_of_ref(segment, ref_uri.fragment) if Checker.json_pointer?(ref_uri.fragment)
41
+
42
+ RefPointer.new(ref_paths: scope.schema_paths, segment: segment,
43
+ segment_paths: segment_paths || [], parent_uri: parent_uri || ref_uri)
44
+ end
45
+
46
+ def resolver_uri(scope, uri)
47
+ schema = scope.cache.fetch(uri.to_s) do
48
+ if (resolver = scope.options[:resolver]) && resolver.respond_to?(:call)
49
+ resolver.call(uri)
50
+ else
51
+ JSON.parse(::Net::HTTP.get(uri))
52
+ end
53
+ end
54
+
55
+ schema.is_a?(Hash) ? schema.with_indifferent_access : schema
56
+ end
57
+
58
+ def path_of_ref(schema, ref)
59
+ paths = decoded_ref(ref)
60
+ parent_uri = pointer_uri(schema, paths)
61
+ [paths, parent_uri]
62
+ end
63
+
64
+ def decoded_ref(pointer)
65
+ URI.decode_www_form_component(pointer).split(POINTER_SPLIT).map do |part|
66
+ if INTEGER_REGEX.match?(part)
67
+ part.to_i
68
+ else
69
+ part.gsub(POINTER_GSUB) { |m| POINTER_ESC[m] }
70
+ end
71
+ end.reject(&:blank?)
72
+ end
73
+
74
+ def pointer_uri(schema, paths)
75
+ uri_parts = nil
76
+
77
+ paths.reduce(schema) do |obj, token|
78
+ next obj.fetch(token.to_i) if obj.is_a?(Array)
79
+
80
+ if (obj_id = obj[:$id])
81
+ uri_parts ||= []
82
+ uri_parts << obj_id
83
+ end
84
+ obj.fetch(token)
85
+ end
86
+ uri_parts ? URI.join(*uri_parts) : nil
87
+ end
88
+
89
+ def reref_base(schema, paths)
90
+ return if schema.nil? || paths.empty?
91
+
92
+ nested_ref_replace_value(schema) do
93
+ "#/#{paths.join('/')}"
94
+ end
95
+ end
96
+
97
+ def nested_ref_replace_value(object, &block)
98
+ if object.respond_to?(:key?) && object.key?(:$ref) && object[:$ref].start_with?('#')
99
+ object[:$ref] = yield()
100
+ elsif object.respond_to?(:each)
101
+ r = nil
102
+ object.find { |*a| r = nested_ref_replace_value(a.last, &block) }
103
+ r
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -13,7 +13,7 @@ module SimpleJSONSchema
13
13
  String => 'string'
14
14
  }.freeze
15
15
 
16
- hash_accessor :scope, :data, :schema, :type, :draft, :data_paths, :schema_paths, :errors, :options
16
+ hash_accessor :scope, %i[data schema type draft data_paths schema_paths errors parent_uri ids options]
17
17
 
18
18
  def initialize(**args)
19
19
  scope.merge!(args)
@@ -21,15 +21,25 @@ module SimpleJSONSchema
21
21
  self.data_paths ||= []
22
22
  self.schema_paths ||= []
23
23
  self.errors ||= []
24
+ self.ids ||= {}
24
25
  self.options ||= {}
25
26
  self.type ||= evaluate_type
26
27
  end
27
28
 
28
29
  def path_to(data_path: nil, schema_path: nil, type: nil)
30
+ return self if data_path.nil? && schema_path.nil? && type.nil?
31
+
29
32
  new_data_paths = data_paths + [data_path].flatten.compact
30
33
  new_schema_paths = schema_paths + [schema_path].flatten.compact
31
34
 
32
- self.class.new(scope.merge(data_paths: new_data_paths, schema_paths: new_schema_paths, type: type))
35
+ merge(data_paths: new_data_paths, schema_paths: new_schema_paths, type: type)
36
+ end
37
+
38
+ def merge(data_paths: self.data_paths, schema_paths: self.schema_paths, type: nil, parent_uri: nil)
39
+ self.class.new(scope.merge(data_paths: data_paths,
40
+ schema_paths: schema_paths,
41
+ type: type,
42
+ parent_uri: parent_uri || URIExtender.join_uri(self.parent_uri, id)))
33
43
  end
34
44
 
35
45
  def replace_data(new_data)
@@ -53,6 +63,11 @@ module SimpleJSONSchema
53
63
  errors.push(error)
54
64
  end
55
65
 
66
+ def only_cache
67
+ self.options = { cache: cache }
68
+ self
69
+ end
70
+
56
71
  def value
57
72
  dig(data, data_paths)
58
73
  end
@@ -60,27 +75,15 @@ module SimpleJSONSchema
60
75
  def value=(new_value)
61
76
  return if errors.any? # only convert value until be invalid.
62
77
 
63
- *steps, leaf = data_paths
64
-
65
- if steps.empty?
66
- data[leaf] = new_value
67
- else
68
- data.dig(*steps)[leaf] = new_value
69
- end
78
+ replace(data, data_paths, new_value) { self.data = new_value }
70
79
  end
71
80
 
72
81
  def segment
73
- @segment ||= dig(schema, schema_paths)
74
- end
75
-
76
- def [](key)
77
- return unless segment.is_a?(Hash)
78
-
79
- segment[key]
82
+ dig(schema, schema_paths)
80
83
  end
81
84
 
82
- def key?(key)
83
- segment.is_a?(Hash) && segment.key?(key)
85
+ def segment=(new_segment)
86
+ replace(schema, schema_paths, new_segment) { self.schema = new_segment }
84
87
  end
85
88
 
86
89
  def segment?
@@ -92,8 +95,22 @@ module SimpleJSONSchema
92
95
  !(segment == true || segment.nil?)
93
96
  end
94
97
 
98
+ def id
99
+ self[:$id]
100
+ end
101
+
102
+ def [](key)
103
+ return unless segment.is_a?(Hash)
104
+
105
+ segment[key]
106
+ end
107
+
108
+ def key?(key)
109
+ segment.is_a?(Hash) && segment.key?(key)
110
+ end
111
+
95
112
  def cache
96
- options[:cache] ||= {}
113
+ options[:cache] ||= Cache.new
97
114
  end
98
115
 
99
116
  def around_hooks
@@ -102,11 +119,19 @@ module SimpleJSONSchema
102
119
  options[:after_property_validation]&.call(self)
103
120
  end
104
121
 
122
+ def loaded_ids
123
+ if ids.empty?
124
+ resolve_ids(ids, schema)
125
+ ids[:$loaded] = true
126
+ end
127
+ ids
128
+ end
129
+
105
130
  private
106
131
 
107
132
  def evaluate_type
108
133
  if key?(:type)
109
- segment[:type]
134
+ self[:type]
110
135
  else
111
136
  CLASS_TYPE_TRANSLATE[value.class]
112
137
  end
@@ -119,5 +144,34 @@ module SimpleJSONSchema
119
144
  rescue TypeError
120
145
  nil
121
146
  end
147
+
148
+ def replace(hash, paths, value)
149
+ *steps, leaf = paths
150
+
151
+ if steps.empty?
152
+ if leaf.nil?
153
+ yield if block_given?
154
+ else
155
+ hash[leaf] = value
156
+ end
157
+ else
158
+ hash.dig(*steps)[leaf] = value
159
+ end
160
+ end
161
+
162
+ def resolve_ids(ids, schema, parent_uri = nil, schema_paths = [])
163
+ case schema
164
+ when Array
165
+ schema.each_with_index { |subschema, index| resolve_ids(ids, subschema, parent_uri, schema_paths + [index]) }
166
+ when Hash
167
+ uri = URIExtender.join_uri(parent_uri, schema[:$id])
168
+
169
+ schema.each do |key, value|
170
+ ids[uri.to_s] = { schema: schema, schema_paths: schema_paths } if key == '$id' && uri != parent_uri
171
+
172
+ resolve_ids(ids, value, uri, schema_paths + [key])
173
+ end
174
+ end
175
+ end
122
176
  end
123
177
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module URIExtender
5
+ class << self
6
+ def join_uri(base, complement)
7
+ complement = URI.parse(complement) if complement
8
+
9
+ if base && complement
10
+ return complement if base.relative? && complement.relative?
11
+
12
+ URI.join(base, complement)
13
+ else
14
+ complement || base
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -13,10 +13,86 @@ module SimpleJSONSchema
13
13
  class << self
14
14
  def validate(scope)
15
15
  return unless scope.segment?
16
+ return if validate_ref(scope)
16
17
 
17
18
  Checker.enum(scope)
18
19
  Checker.const(scope)
19
20
 
21
+ validate_correlations(scope)
22
+ validate_by_type(scope)
23
+ end
24
+
25
+ private
26
+
27
+ def validate?(scope)
28
+ scope.errors = []
29
+
30
+ validate(scope.only_cache)
31
+ scope.errors.none?
32
+ end
33
+
34
+ def validate_ref(scope)
35
+ ref_pointer = RefHelper.pointer(scope)
36
+ return if ref_pointer.nil?
37
+
38
+ new_scope = scope.merge(schema_paths: ref_pointer.ref_paths, parent_uri: ref_pointer.parent_uri)
39
+ new_scope.segment = ref_pointer.segment unless ref_pointer.segment.nil?
40
+ validate(new_scope.path_to(schema_path: ref_pointer.segment_paths))
41
+ true
42
+ end
43
+
44
+ def validate_correlations(scope)
45
+ validate_all_of(scope)
46
+ validate_any_of(scope)
47
+ validate_one_of(scope)
48
+ validate_not(scope)
49
+ validate_if_then_else(scope)
50
+ end
51
+
52
+ def validate_all_of(scope)
53
+ scope[:allOf]&.each_index do |index|
54
+ validate(scope.path_to(schema_path: [:allOf, index]).only_cache)
55
+ end
56
+ end
57
+
58
+ def validate_any_of(scope)
59
+ any_of = scope[:anyOf]
60
+ return if any_of.nil?
61
+ return if any_of.each_index.any? { |index| validate?(scope.path_to(schema_path: [:anyOf, index])) }
62
+
63
+ any_of.each_index { |index| validate(scope.path_to(schema_path: [:anyOf, index]).only_cache) }
64
+ end
65
+
66
+ def validate_one_of(scope)
67
+ one_of = scope[:oneOf]
68
+ return if one_of.nil?
69
+
70
+ valid_count = one_of.each_index.count { |index| validate?(scope.path_to(schema_path: [:oneOf, index])) }
71
+
72
+ if valid_count > 1
73
+ scope.error(:oneOf)
74
+ elsif valid_count.zero?
75
+ one_of.each_index { |index| validate(scope.path_to(schema_path: [:oneOf, index]).only_cache) }
76
+ end
77
+ end
78
+
79
+ def validate_not(scope)
80
+ return unless scope.key?(:not)
81
+
82
+ scope.error(:not) if validate?(scope.path_to(schema_path: :not))
83
+ end
84
+
85
+ def validate_if_then_else(scope)
86
+ return unless scope.key?(:if)
87
+
88
+ if validate?(scope.path_to(schema_path: :if))
89
+ validate(scope.path_to(schema_path: :then)) if scope.key?(:then)
90
+ elsif scope.key?(:else)
91
+ validate(scope.path_to(schema_path: :else))
92
+ end
93
+ end
94
+
95
+ def validate_by_type(scope)
20
96
  case scope.type
21
97
  when 'object'
22
98
  valid_object(scope)
@@ -29,33 +105,37 @@ module SimpleJSONSchema
29
105
  end
30
106
  end
31
107
 
32
- private
33
-
34
- def validate?(scope)
35
- scope.errors = []
36
- scope.options = { cache: scope.cache }
37
-
38
- validate(scope)
39
- scope.errors.none?
40
- end
41
-
42
108
  def validate_base_types(scope)
43
109
  VALIDATORES[scope.type]&.valid(scope)
44
110
  end
45
111
 
46
112
  def valid_object(scope)
47
- value = scope.value
48
-
49
- return scope.error(:object) unless value.is_a?(Hash)
113
+ return scope.error(:object) unless scope.value.is_a?(Hash)
50
114
 
51
115
  PropertiesHelper.processe_defualt(scope)
52
116
  PropertiesHelper.checkers(scope)
53
117
 
118
+ valid_object_dependencies(scope)
119
+ valid_object_property_names(scope)
120
+ valid_object_properties(scope)
121
+ end
122
+
123
+ def valid_object_dependencies(scope)
124
+ PropertiesHelper.each_dependency(scope) do |schema_path|
125
+ new_scope = scope.path_to(schema_path: schema_path)
126
+ new_scope.segment = { required: new_scope.segment } if new_scope.segment.is_a?(Array)
127
+ validate(new_scope)
128
+ end
129
+ end
130
+
131
+ def valid_object_property_names(scope)
54
132
  PropertiesHelper.each_property_name(scope) do |property_name|
55
133
  validate(scope.path_to(schema_path: :propertyNames).replace_data(property_name))
56
134
  end
135
+ end
57
136
 
58
- value.each_key do |property_name|
137
+ def valid_object_properties(scope)
138
+ scope.value.each_key do |property_name|
59
139
  PropertiesHelper.map_property_schema_path(scope, property_name).each do |schema_path|
60
140
  new_scope = scope.path_to(schema_path: schema_path, data_path: property_name)
61
141
  new_scope.around_hooks do
@@ -8,9 +8,6 @@ module SimpleJSONSchema
8
8
  EMAIL_REGEX = /\A[^@\s]+@([\p{L}\d-]+\.)+[\p{L}\d\-]{2,}\z/i.freeze
9
9
  LABEL_REGEX_STRING = '[\p{L}\p{N}]([\p{L}\p{N}\-]*[\p{L}\p{N}])?'
10
10
  HOSTNAME_REGEX = /\A(#{LABEL_REGEX_STRING}\.)*#{LABEL_REGEX_STRING}\z/i.freeze
11
- JSON_POINTER_REGEX_STRING = '(\/([^~\/]|~[01])*)*'
12
- JSON_POINTER_REGEX = /\A#{JSON_POINTER_REGEX_STRING}\z/.freeze
13
- RELATIVE_JSON_POINTER_REGEX = /\A(0|[1-9]\d*)(#|#{JSON_POINTER_REGEX_STRING})?\z/.freeze
14
11
  DATE_TIME_OFFSET_REGEX = /(Z|[+\-]([01][0-9]|2[0-3]):[0-5][0-9])\z/i.freeze
15
12
  INVALID_QUERY_REGEX = /[[:space:]]/.freeze
16
13
  ASCII_REGEX = /[^[:ascii:]]/.freeze
@@ -57,9 +54,9 @@ module SimpleJSONSchema
57
54
  # when 'uri-template'
58
55
  # valid_uri_template?(value)
59
56
  when 'json-pointer'
60
- JSON_POINTER_REGEX.match?(value)
57
+ Checker.json_pointer?(value)
61
58
  when 'relative-json-pointer'
62
- RELATIVE_JSON_POINTER_REGEX.match?(value)
59
+ Checker.relative_json_pointer?(value)
63
60
  when 'regex'
64
61
  EcmaReValidator.valid?(value)
65
62
  end
@@ -9,6 +9,7 @@ module SimpleJSONSchema
9
9
  value = scope.value
10
10
 
11
11
  return scope.error(:string) unless value.is_a?(::String)
12
+ return scope.error(:blank) if scope[:required] == true && value.blank?
12
13
 
13
14
  Checker.at_size(scope, :maxLength, :>)
14
15
  Checker.at_size(scope, :minLength, :<)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleJSONSchema
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_json_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georgeo Rocco
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-22 00:00:00.000000000 Z
11
+ date: 2021-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -187,13 +187,17 @@ files:
187
187
  - Rakefile
188
188
  - bin/console
189
189
  - bin/setup
190
+ - bin/simple_json_schema
190
191
  - lib/simple_json_schema.rb
192
+ - lib/simple_json_schema/cache.rb
191
193
  - lib/simple_json_schema/checker.rb
192
194
  - lib/simple_json_schema/concerns/hash_acessor.rb
193
195
  - lib/simple_json_schema/items_helper.rb
194
196
  - lib/simple_json_schema/properties_helper.rb
197
+ - lib/simple_json_schema/ref_helper.rb
195
198
  - lib/simple_json_schema/regex_helper.rb
196
199
  - lib/simple_json_schema/scope.rb
200
+ - lib/simple_json_schema/uri_extender.rb
197
201
  - lib/simple_json_schema/validator.rb
198
202
  - lib/simple_json_schema/validators/base.rb
199
203
  - lib/simple_json_schema/validators/boolean.rb