json_skooma 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +22 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +107 -0
  5. data/data/draft-2019-09/README.md +60 -0
  6. data/data/draft-2019-09/hyper-schema.json +26 -0
  7. data/data/draft-2019-09/links.json +91 -0
  8. data/data/draft-2019-09/meta/applicator.json +56 -0
  9. data/data/draft-2019-09/meta/content.json +17 -0
  10. data/data/draft-2019-09/meta/core.json +57 -0
  11. data/data/draft-2019-09/meta/format.json +14 -0
  12. data/data/draft-2019-09/meta/hyper-schema.json +29 -0
  13. data/data/draft-2019-09/meta/meta-data.json +37 -0
  14. data/data/draft-2019-09/meta/validation.json +98 -0
  15. data/data/draft-2019-09/output/hyper-schema.json +62 -0
  16. data/data/draft-2019-09/output/schema.json +86 -0
  17. data/data/draft-2019-09/output/verbose-example.json +130 -0
  18. data/data/draft-2019-09/schema.json +42 -0
  19. data/data/draft-2020-12/README.md +89 -0
  20. data/data/draft-2020-12/adr/README.md +15 -0
  21. data/data/draft-2020-12/archive/hyper-schema.json +28 -0
  22. data/data/draft-2020-12/archive/links.json +93 -0
  23. data/data/draft-2020-12/archive/meta/hyper-schema.json +30 -0
  24. data/data/draft-2020-12/hyper-schema.json +27 -0
  25. data/data/draft-2020-12/links.json +85 -0
  26. data/data/draft-2020-12/meta/applicator.json +48 -0
  27. data/data/draft-2020-12/meta/content.json +17 -0
  28. data/data/draft-2020-12/meta/core.json +51 -0
  29. data/data/draft-2020-12/meta/format-annotation.json +14 -0
  30. data/data/draft-2020-12/meta/format-assertion.json +14 -0
  31. data/data/draft-2020-12/meta/hyper-schema.json +29 -0
  32. data/data/draft-2020-12/meta/meta-data.json +37 -0
  33. data/data/draft-2020-12/meta/unevaluated.json +15 -0
  34. data/data/draft-2020-12/meta/validation.json +98 -0
  35. data/data/draft-2020-12/output/hyper-schema.json +62 -0
  36. data/data/draft-2020-12/output/schema.json +96 -0
  37. data/data/draft-2020-12/output/verbose-example.json +130 -0
  38. data/data/draft-2020-12/schema.json +58 -0
  39. data/lib/json_skooma/dialects/draft201909.rb +137 -0
  40. data/lib/json_skooma/dialects/draft202012.rb +146 -0
  41. data/lib/json_skooma/formatters.rb +135 -0
  42. data/lib/json_skooma/inflector.rb +13 -0
  43. data/lib/json_skooma/json_node.rb +100 -0
  44. data/lib/json_skooma/json_pointer.rb +79 -0
  45. data/lib/json_skooma/json_schema.rb +176 -0
  46. data/lib/json_skooma/keywords/applicator/additional_properties.rb +37 -0
  47. data/lib/json_skooma/keywords/applicator/all_of.rb +25 -0
  48. data/lib/json_skooma/keywords/applicator/any_of.rb +26 -0
  49. data/lib/json_skooma/keywords/applicator/contains.rb +31 -0
  50. data/lib/json_skooma/keywords/applicator/dependent_schemas.rb +35 -0
  51. data/lib/json_skooma/keywords/applicator/else.rb +22 -0
  52. data/lib/json_skooma/keywords/applicator/if.rb +17 -0
  53. data/lib/json_skooma/keywords/applicator/items.rb +36 -0
  54. data/lib/json_skooma/keywords/applicator/not.rb +19 -0
  55. data/lib/json_skooma/keywords/applicator/one_of.rb +35 -0
  56. data/lib/json_skooma/keywords/applicator/pattern_properties.rb +46 -0
  57. data/lib/json_skooma/keywords/applicator/prefix_items.rb +31 -0
  58. data/lib/json_skooma/keywords/applicator/properties.rb +34 -0
  59. data/lib/json_skooma/keywords/applicator/property_names.rb +25 -0
  60. data/lib/json_skooma/keywords/applicator/then.rb +22 -0
  61. data/lib/json_skooma/keywords/base.rb +74 -0
  62. data/lib/json_skooma/keywords/base_annotation.rb +12 -0
  63. data/lib/json_skooma/keywords/content/content_encoding.rb +12 -0
  64. data/lib/json_skooma/keywords/content/content_media_type.rb +12 -0
  65. data/lib/json_skooma/keywords/content/content_schema.rb +19 -0
  66. data/lib/json_skooma/keywords/core/anchor.rb +22 -0
  67. data/lib/json_skooma/keywords/core/comment.rb +12 -0
  68. data/lib/json_skooma/keywords/core/defs.rb +13 -0
  69. data/lib/json_skooma/keywords/core/dynamic_anchor.rb +22 -0
  70. data/lib/json_skooma/keywords/core/dynamic_ref.rb +67 -0
  71. data/lib/json_skooma/keywords/core/id.rb +28 -0
  72. data/lib/json_skooma/keywords/core/ref.rb +35 -0
  73. data/lib/json_skooma/keywords/core/schema.rb +26 -0
  74. data/lib/json_skooma/keywords/core/vocabulary.rb +34 -0
  75. data/lib/json_skooma/keywords/draft_2019_09/additional_items.rb +40 -0
  76. data/lib/json_skooma/keywords/draft_2019_09/items.rb +41 -0
  77. data/lib/json_skooma/keywords/draft_2019_09/recursive_anchor.rb +12 -0
  78. data/lib/json_skooma/keywords/draft_2019_09/recursive_ref.rb +46 -0
  79. data/lib/json_skooma/keywords/draft_2019_09/unevaluated_items.rb +56 -0
  80. data/lib/json_skooma/keywords/format_annotation/format.rb +27 -0
  81. data/lib/json_skooma/keywords/meta_data/default.rb +11 -0
  82. data/lib/json_skooma/keywords/meta_data/deprecated.rb +11 -0
  83. data/lib/json_skooma/keywords/meta_data/description.rb +11 -0
  84. data/lib/json_skooma/keywords/meta_data/examples.rb +11 -0
  85. data/lib/json_skooma/keywords/meta_data/read_only.rb +11 -0
  86. data/lib/json_skooma/keywords/meta_data/title.rb +11 -0
  87. data/lib/json_skooma/keywords/meta_data/write_only.rb +11 -0
  88. data/lib/json_skooma/keywords/unevaluated/unevaluated_items.rb +59 -0
  89. data/lib/json_skooma/keywords/unevaluated/unevaluated_properties.rb +43 -0
  90. data/lib/json_skooma/keywords/unknown.rb +21 -0
  91. data/lib/json_skooma/keywords/validation/const.rb +17 -0
  92. data/lib/json_skooma/keywords/validation/dependent_required.rb +24 -0
  93. data/lib/json_skooma/keywords/validation/enum.rb +19 -0
  94. data/lib/json_skooma/keywords/validation/exclusive_maximum.rb +18 -0
  95. data/lib/json_skooma/keywords/validation/exclusive_minimum.rb +18 -0
  96. data/lib/json_skooma/keywords/validation/max_contains.rb +24 -0
  97. data/lib/json_skooma/keywords/validation/max_items.rb +18 -0
  98. data/lib/json_skooma/keywords/validation/max_length.rb +18 -0
  99. data/lib/json_skooma/keywords/validation/max_properties.rb +18 -0
  100. data/lib/json_skooma/keywords/validation/maximum.rb +18 -0
  101. data/lib/json_skooma/keywords/validation/min_contains.rb +31 -0
  102. data/lib/json_skooma/keywords/validation/min_items.rb +18 -0
  103. data/lib/json_skooma/keywords/validation/min_length.rb +18 -0
  104. data/lib/json_skooma/keywords/validation/min_properties.rb +18 -0
  105. data/lib/json_skooma/keywords/validation/minimum.rb +18 -0
  106. data/lib/json_skooma/keywords/validation/multiple_of.rb +20 -0
  107. data/lib/json_skooma/keywords/validation/pattern.rb +23 -0
  108. data/lib/json_skooma/keywords/validation/required.rb +19 -0
  109. data/lib/json_skooma/keywords/validation/type.rb +26 -0
  110. data/lib/json_skooma/keywords/validation/unique_items.rb +20 -0
  111. data/lib/json_skooma/keywords/value_schemas.rb +87 -0
  112. data/lib/json_skooma/memoizable.rb +21 -0
  113. data/lib/json_skooma/metaschema.rb +32 -0
  114. data/lib/json_skooma/registry.rb +130 -0
  115. data/lib/json_skooma/result.rb +125 -0
  116. data/lib/json_skooma/sources.rb +55 -0
  117. data/lib/json_skooma/validators/base.rb +31 -0
  118. data/lib/json_skooma/validators/date.rb +18 -0
  119. data/lib/json_skooma/validators/date_time.rb +24 -0
  120. data/lib/json_skooma/validators/duration.rb +25 -0
  121. data/lib/json_skooma/validators/email.rb +36 -0
  122. data/lib/json_skooma/validators/hostname.rb +17 -0
  123. data/lib/json_skooma/validators/idn_email.rb +30 -0
  124. data/lib/json_skooma/validators/idn_hostname.rb +15 -0
  125. data/lib/json_skooma/validators/ipv4.rb +20 -0
  126. data/lib/json_skooma/validators/ipv6.rb +16 -0
  127. data/lib/json_skooma/validators/iri.rb +47 -0
  128. data/lib/json_skooma/validators/iri_reference.rb +15 -0
  129. data/lib/json_skooma/validators/json_pointer.rb +19 -0
  130. data/lib/json_skooma/validators/regex.rb +15 -0
  131. data/lib/json_skooma/validators/relative_json_pointer.rb +18 -0
  132. data/lib/json_skooma/validators/time.rb +32 -0
  133. data/lib/json_skooma/validators/uri.rb +60 -0
  134. data/lib/json_skooma/validators/uri_reference.rb +15 -0
  135. data/lib/json_skooma/validators/uri_template.rb +26 -0
  136. data/lib/json_skooma/validators/uuid.rb +15 -0
  137. data/lib/json_skooma/validators.rb +17 -0
  138. data/lib/json_skooma/version.rb +5 -0
  139. data/lib/json_skooma/vocabulary.rb +12 -0
  140. data/lib/json_skooma.rb +39 -0
  141. metadata +244 -0
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Draft201909
6
+ class UnevaluatedItems < Base
7
+ self.key = "unevaluatedItems"
8
+ self.instance_types = %w[array]
9
+ self.value_schema = :schema
10
+ self.depends_on = %w[
11
+ items additionalItems
12
+ if then else allOf anyOf oneOf not
13
+ ]
14
+
15
+ def evaluate(instance, result)
16
+ last_evaluated_item = -1
17
+
18
+ result.parent.collect_annotations(instance, "items") do |i|
19
+ next result.discard if i == true
20
+
21
+ last_evaluated_item = i if i > last_evaluated_item
22
+ end
23
+
24
+ result.parent.collect_annotations(instance, "additionalItems") do |i|
25
+ next result.discard if i == true
26
+ end
27
+
28
+ result.parent.collect_annotations(instance, "unevaluatedItems") do |i|
29
+ next result.discard if i == true
30
+ end
31
+
32
+ annotation = nil
33
+ error = []
34
+
35
+ instance.each_with_index do |item, index|
36
+ next if last_evaluated_item >= index
37
+
38
+ if json.evaluate(item, result).passed?
39
+ annotation = true
40
+ else
41
+ error << index
42
+ # reset to passed for the next iteration
43
+ result.success
44
+ end
45
+ end
46
+
47
+ if error.any?
48
+ result.failure(error)
49
+ else
50
+ result.annotate(annotation)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module FormatAnnotation
6
+ class Format < Base
7
+ self.key = "format"
8
+
9
+ def initialize(parent_schema, value)
10
+ super
11
+ if parent_schema.registry.format_enabled?(value)
12
+ @validator = Validators.validators[value]
13
+ end
14
+ end
15
+
16
+ def evaluate(instance, result)
17
+ result.annotate(json)
18
+ return result.skip_assertion unless @validator&.assert?(instance)
19
+
20
+ @validator.call(instance)
21
+ rescue Validators::FormatError => e
22
+ result.failure("The instance is invalid against the #{json.value} format: #{e}")
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class Default < BaseAnnotation
7
+ self.key = "default"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class Deprecated < BaseAnnotation
7
+ self.key = "deprecated"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class Description < BaseAnnotation
7
+ self.key = "description"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class Examples < BaseAnnotation
7
+ self.key = "examples"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class ReadOnly < BaseAnnotation
7
+ self.key = "readOnly"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class Title < BaseAnnotation
7
+ self.key = "title"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module MetaData
6
+ class WriteOnly < BaseAnnotation
7
+ self.key = "writeOnly"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Unevaluated
6
+ class UnevaluatedItems < Base
7
+ self.key = "unevaluatedItems"
8
+ self.instance_types = %w[array]
9
+ self.value_schema = :schema
10
+ self.depends_on = %w[
11
+ prefixItems items contains
12
+ if then else allOf anyOf oneOf not
13
+ ]
14
+
15
+ def evaluate(instance, result)
16
+ last_evaluated_item = -1
17
+
18
+ result.parent.collect_annotations(instance, "prefixItems") do |i|
19
+ next result.discard if i == true
20
+
21
+ last_evaluated_item = i if i > last_evaluated_item
22
+ end
23
+
24
+ result.parent.collect_annotations(instance, "items") do |i|
25
+ next result.discard if i == true
26
+ end
27
+
28
+ result.parent.collect_annotations(instance, "unevaluatedItems") do |i|
29
+ next result.discard if i == true
30
+ end
31
+
32
+ contains_indices = Set.new
33
+ result.parent.collect_annotations(instance, "contains") { |i| contains_indices += Set.new(i) }
34
+ annotation = nil
35
+ error = []
36
+
37
+ instance.each_with_index do |item, index|
38
+ next if last_evaluated_item >= index
39
+ next if contains_indices.include?(index)
40
+
41
+ if json.evaluate(item, result).passed?
42
+ annotation = true
43
+ else
44
+ error << index
45
+ # reset to passed for the next iteration
46
+ result.success
47
+ end
48
+ end
49
+
50
+ if error.any?
51
+ result.failure(error)
52
+ else
53
+ result.annotate(annotation)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Unevaluated
6
+ class UnevaluatedProperties < Base
7
+ self.key = "unevaluatedProperties"
8
+ self.instance_types = %w[object]
9
+ self.value_schema = :schema
10
+ self.depends_on = %w[
11
+ properties patternProperties additionalProperties
12
+ if then else dependentSchemas allOf anyOf oneOf not
13
+ ]
14
+
15
+ def evaluate(instance, result)
16
+ evaluated_names = Set.new
17
+ result.parent.collect_annotations(instance, "properties") { |name| evaluated_names += Set.new(name) }
18
+ result.parent.collect_annotations(instance, "patternProperties") { |name| evaluated_names += Set.new(name) }
19
+ result.parent.collect_annotations(instance, "additionalProperties") { |name| evaluated_names += Set.new(name) }
20
+ result.parent.collect_annotations(instance, "unevaluatedProperties") { |name| evaluated_names += Set.new(name) }
21
+
22
+ annotation = []
23
+ error = []
24
+ instance.each do |name, item|
25
+ next if evaluated_names.include?(name)
26
+
27
+ if json.evaluate(item, result).passed?
28
+ annotation << name
29
+ else
30
+ error << name
31
+ # reset to success for the next iteration
32
+ result.success
33
+ end
34
+ end
35
+
36
+ return result.failure(error) if error.any?
37
+
38
+ result.annotate(annotation)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Unknown
6
+ class << self
7
+ def [](key)
8
+ @unknown_keywords ||= {}
9
+ @unknown_keywords[key] ||= Class.new(Keywords::Base) do
10
+ self.key = key
11
+
12
+ def evaluate(instance, result)
13
+ result.annotate(json.value)
14
+ result.skip_assertion
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class Const < Base
7
+ self.key = "const"
8
+
9
+ def evaluate(instance, result)
10
+ return if instance == json
11
+
12
+ result.failure("The instance value #{instance.value.inspect} must be equal to the defined constant #{json.value.inspect}")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class DependentRequired < Base
7
+ self.key = "dependentRequired"
8
+ self.instance_types = "object"
9
+
10
+ def evaluate(instance, result)
11
+ missing = {}
12
+ json.each do |name, dependents|
13
+ next unless instance.key?(name)
14
+
15
+ missing_deps = dependents.reject { |dep| instance.key?(dep) }
16
+ missing[name] = missing_deps if missing_deps.any?
17
+ end
18
+
19
+ result.failure("The object is missing dependent properties #{missing}") if missing.any?
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class Enum < Base
7
+ self.key = "enum"
8
+
9
+ def evaluate(instance, result)
10
+ return if json.include?(instance)
11
+
12
+ result.failure(
13
+ "The instance value #{instance.value.inspect} must be equal to one of the elements in the defined enumeration: #{json.value}"
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class ExclusiveMaximum < Base
7
+ self.key = "exclusiveMaximum"
8
+ self.instance_types = "number"
9
+
10
+ def evaluate(instance, result)
11
+ if instance >= json
12
+ result.failure("The value must be less than #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class ExclusiveMinimum < Base
7
+ self.key = "exclusiveMinimum"
8
+ self.instance_types = "number"
9
+
10
+ def evaluate(instance, result)
11
+ if instance <= json
12
+ result.failure("The value must be greater than #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MaxContains < Base
7
+ self.key = "maxContains"
8
+ self.instance_types = %w[array]
9
+ self.depends_on = %w[contains]
10
+
11
+ def evaluate(instance, result)
12
+ contains = result.sibling(instance, "contains")
13
+ return if contains.nil?
14
+
15
+ if contains.annotation && contains.annotation.length > json
16
+ result.failure(
17
+ "The array has too many elements matching the contains subschema (maximum #{json.value})"
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MaxItems < Base
7
+ self.key = "maxItems"
8
+ self.instance_types = "array"
9
+
10
+ def evaluate(instance, result)
11
+ if instance.length > json
12
+ result.failure("The array has too many elements (maximum #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MaxLength < Base
7
+ self.key = "maxLength"
8
+ self.instance_types = "string"
9
+
10
+ def evaluate(instance, result)
11
+ if instance.length > json
12
+ result.failure("The text is too long (maximum #{json.value} characters))")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MaxProperties < Base
7
+ self.key = "maxProperties"
8
+ self.instance_types = "object"
9
+
10
+ def evaluate(instance, result)
11
+ if instance.length > json
12
+ result.failure("The object has too many properties (maximum #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class Maximum < Base
7
+ self.key = "maximum"
8
+ self.instance_types = "number"
9
+
10
+ def evaluate(instance, result)
11
+ if instance > json
12
+ result.failure("The value may not be greater than #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MinContains < Base
7
+ self.key = "minContains"
8
+ self.instance_types = %w[array]
9
+ self.depends_on = %w[contains maxContains]
10
+
11
+ def evaluate(instance, result)
12
+ contains = result.sibling(instance, "contains")
13
+ return if contains.nil?
14
+
15
+ contains_count = contains.annotation&.count || 0
16
+
17
+ valid = contains_count >= json
18
+
19
+ if valid && !contains.valid?
20
+ max_contains = result.sibling(instance, "maxContains")
21
+ contains.success if !max_contains || max_contains.valid?
22
+ end
23
+
24
+ return if valid
25
+
26
+ result.failure("The array has too few elements matching the `contains` subschema (minimum #{json.value})")
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MinItems < Base
7
+ self.key = "minItems"
8
+ self.instance_types = "array"
9
+
10
+ def evaluate(instance, result)
11
+ if instance.length < json
12
+ result.failure("The array has too few elements (minimum #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MinLength < Base
7
+ self.key = "minLength"
8
+ self.instance_types = "string"
9
+
10
+ def evaluate(instance, result)
11
+ if instance.length < json
12
+ result.failure("The text is too short (minimum #{json.value} characters))")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class MinProperties < Base
7
+ self.key = "minProperties"
8
+ self.instance_types = "object"
9
+
10
+ def evaluate(instance, result)
11
+ if instance.length < json
12
+ result.failure("The object has too few properties (minimum #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class Minimum < Base
7
+ self.key = "minimum"
8
+ self.instance_types = "number"
9
+
10
+ def evaluate(instance, result)
11
+ if instance < json
12
+ result.failure("The value may not be less than #{json.value})")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+
5
+ module JSONSkooma
6
+ module Keywords
7
+ module Validation
8
+ class MultipleOf < Base
9
+ self.key = "multipleOf"
10
+ self.instance_types = "number"
11
+
12
+ def evaluate(instance, result)
13
+ if BigDecimal(instance.value.to_s).modulo(BigDecimal(json.value.to_s)).nonzero?
14
+ result.failure("The value must be a multiple of #{json.value}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class Pattern < Base
7
+ self.key = "pattern"
8
+ self.instance_types = %w[string]
9
+
10
+ def initialize(parent_schema, value)
11
+ super
12
+ @regexp = Regexp.new(value)
13
+ end
14
+
15
+ def evaluate(instance, result)
16
+ return if @regexp.match(instance)
17
+
18
+ result.failure("The text must match the regular expression #{json.value}")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONSkooma
4
+ module Keywords
5
+ module Validation
6
+ class Required < Base
7
+ self.key = "required"
8
+ self.instance_types = "object"
9
+
10
+ def evaluate(instance, result)
11
+ missing_keys = json - instance.keys
12
+ return if missing_keys.empty?
13
+
14
+ result.failure("The object is missing required properties #{json.value}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end