json_skooma 0.1.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.
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