jsi-dev 0.0.0.pre.commonmarker

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +8 -0
  3. data/CHANGELOG.md +101 -0
  4. data/LICENSE.md +613 -0
  5. data/README.md +303 -0
  6. data/docs/glossary.md +281 -0
  7. data/jsi.gemspec +30 -0
  8. data/lib/jsi/base/node.rb +373 -0
  9. data/lib/jsi/base.rb +738 -0
  10. data/lib/jsi/jsi_coder.rb +92 -0
  11. data/lib/jsi/metaschema.rb +6 -0
  12. data/lib/jsi/metaschema_node/bootstrap_schema.rb +126 -0
  13. data/lib/jsi/metaschema_node.rb +262 -0
  14. data/lib/jsi/ptr.rb +314 -0
  15. data/lib/jsi/schema/application/child_application/contains.rb +25 -0
  16. data/lib/jsi/schema/application/child_application/draft04.rb +21 -0
  17. data/lib/jsi/schema/application/child_application/draft06.rb +28 -0
  18. data/lib/jsi/schema/application/child_application/draft07.rb +28 -0
  19. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  20. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  21. data/lib/jsi/schema/application/child_application.rb +13 -0
  22. data/lib/jsi/schema/application/draft04.rb +8 -0
  23. data/lib/jsi/schema/application/draft06.rb +8 -0
  24. data/lib/jsi/schema/application/draft07.rb +8 -0
  25. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  26. data/lib/jsi/schema/application/inplace_application/draft04.rb +25 -0
  27. data/lib/jsi/schema/application/inplace_application/draft06.rb +26 -0
  28. data/lib/jsi/schema/application/inplace_application/draft07.rb +32 -0
  29. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  30. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  31. data/lib/jsi/schema/application/inplace_application/someof.rb +44 -0
  32. data/lib/jsi/schema/application/inplace_application.rb +14 -0
  33. data/lib/jsi/schema/application.rb +12 -0
  34. data/lib/jsi/schema/draft04.rb +13 -0
  35. data/lib/jsi/schema/draft06.rb +13 -0
  36. data/lib/jsi/schema/draft07.rb +13 -0
  37. data/lib/jsi/schema/issue.rb +36 -0
  38. data/lib/jsi/schema/ref.rb +183 -0
  39. data/lib/jsi/schema/schema_ancestor_node.rb +122 -0
  40. data/lib/jsi/schema/validation/array.rb +69 -0
  41. data/lib/jsi/schema/validation/const.rb +20 -0
  42. data/lib/jsi/schema/validation/contains.rb +25 -0
  43. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  44. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  45. data/lib/jsi/schema/validation/draft04.rb +110 -0
  46. data/lib/jsi/schema/validation/draft06.rb +120 -0
  47. data/lib/jsi/schema/validation/draft07.rb +157 -0
  48. data/lib/jsi/schema/validation/enum.rb +25 -0
  49. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  50. data/lib/jsi/schema/validation/items.rb +54 -0
  51. data/lib/jsi/schema/validation/not.rb +20 -0
  52. data/lib/jsi/schema/validation/numeric.rb +121 -0
  53. data/lib/jsi/schema/validation/object.rb +45 -0
  54. data/lib/jsi/schema/validation/pattern.rb +34 -0
  55. data/lib/jsi/schema/validation/properties.rb +101 -0
  56. data/lib/jsi/schema/validation/property_names.rb +32 -0
  57. data/lib/jsi/schema/validation/ref.rb +40 -0
  58. data/lib/jsi/schema/validation/required.rb +27 -0
  59. data/lib/jsi/schema/validation/someof.rb +90 -0
  60. data/lib/jsi/schema/validation/string.rb +47 -0
  61. data/lib/jsi/schema/validation/type.rb +49 -0
  62. data/lib/jsi/schema/validation.rb +49 -0
  63. data/lib/jsi/schema.rb +792 -0
  64. data/lib/jsi/schema_classes.rb +357 -0
  65. data/lib/jsi/schema_registry.rb +190 -0
  66. data/lib/jsi/schema_set.rb +219 -0
  67. data/lib/jsi/simple_wrap.rb +26 -0
  68. data/lib/jsi/util/private/attr_struct.rb +130 -0
  69. data/lib/jsi/util/private/memo_map.rb +75 -0
  70. data/lib/jsi/util/private.rb +202 -0
  71. data/lib/jsi/util/typelike.rb +225 -0
  72. data/lib/jsi/util.rb +227 -0
  73. data/lib/jsi/validation/error.rb +34 -0
  74. data/lib/jsi/validation/result.rb +212 -0
  75. data/lib/jsi/validation.rb +15 -0
  76. data/lib/jsi/version.rb +5 -0
  77. data/lib/jsi.rb +105 -0
  78. data/lib/schemas/json-schema.org/draft-04/schema.rb +169 -0
  79. data/lib/schemas/json-schema.org/draft-06/schema.rb +171 -0
  80. data/lib/schemas/json-schema.org/draft-07/schema.rb +198 -0
  81. data/readme.rb +138 -0
  82. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  83. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  84. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  85. metadata +155 -0
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::MultipleOf
5
+ # @private
6
+ def internal_validate_multipleOf(result_builder)
7
+ if keyword?('multipleOf')
8
+ value = schema_content['multipleOf']
9
+ # The value of "multipleOf" MUST be a number, strictly greater than 0.
10
+ if value.is_a?(Numeric) && value > 0
11
+ # A numeric instance is valid only if division by this keyword's value results in an integer.
12
+ if result_builder.instance.is_a?(Numeric)
13
+ if result_builder.instance.is_a?(Integer) && value.is_a?(Integer)
14
+ valid = result_builder.instance % value == 0
15
+ else
16
+ quotient = result_builder.instance / value
17
+ if quotient.finite?
18
+ valid = quotient % 1.0 == 0.0
19
+ else
20
+ valid = BigDecimal(result_builder.instance, Float::DIG) % BigDecimal(value, Float::DIG) == 0
21
+ end
22
+ end
23
+ result_builder.validate(
24
+ valid,
25
+ 'instance is not a multiple of `multipleOf` value',
26
+ keyword: 'multipleOf',
27
+ )
28
+ end
29
+ else
30
+ result_builder.schema_error('`multipleOf` is not a number greater than 0', 'multipleOf')
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ module Schema::Validation::MinMax
37
+ # @private
38
+ def internal_validate_maximum(result_builder)
39
+ if keyword?('maximum')
40
+ value = schema_content['maximum']
41
+ # The value of "maximum" MUST be a number, representing an inclusive upper limit for a numeric instance.
42
+ if value.is_a?(Numeric)
43
+ # If the instance is a number, then this keyword validates only if the instance is less than or
44
+ # exactly equal to "maximum".
45
+ if result_builder.instance.is_a?(Numeric)
46
+ result_builder.validate(
47
+ result_builder.instance <= value,
48
+ 'instance is not less than or equal to `maximum` value',
49
+ keyword: 'maximum',
50
+ )
51
+ end
52
+ else
53
+ result_builder.schema_error('`maximum` is not a number', 'maximum')
54
+ end
55
+ end
56
+ end
57
+
58
+ # @private
59
+ def internal_validate_exclusiveMaximum(result_builder)
60
+ if keyword?('exclusiveMaximum')
61
+ value = schema_content['exclusiveMaximum']
62
+ # The value of "exclusiveMaximum" MUST be number, representing an exclusive upper limit for a numeric instance.
63
+ if value.is_a?(Numeric)
64
+ # If the instance is a number, then the instance is valid only if it has a value strictly less than
65
+ # (not equal to) "exclusiveMaximum".
66
+ if result_builder.instance.is_a?(Numeric)
67
+ result_builder.validate(
68
+ result_builder.instance < value,
69
+ 'instance is not less than `exclusiveMaximum` value',
70
+ keyword: 'exclusiveMaximum',
71
+ )
72
+ end
73
+ else
74
+ result_builder.schema_error('`exclusiveMaximum` is not a number', 'exclusiveMaximum')
75
+ end
76
+ end
77
+ end
78
+
79
+ # @private
80
+ def internal_validate_minimum(result_builder)
81
+ if keyword?('minimum')
82
+ value = schema_content['minimum']
83
+ # The value of "minimum" MUST be a number, representing an inclusive lower limit for a numeric instance.
84
+ if value.is_a?(Numeric)
85
+ # If the instance is a number, then this keyword validates only if the instance is greater than or
86
+ # exactly equal to "minimum".
87
+ if result_builder.instance.is_a?(Numeric)
88
+ result_builder.validate(
89
+ result_builder.instance >= value,
90
+ 'instance is not greater than or equal to `minimum` value',
91
+ keyword: 'minimum',
92
+ )
93
+ end
94
+ else
95
+ result_builder.schema_error('`minimum` is not a number', 'minimum')
96
+ end
97
+ end
98
+ end
99
+
100
+ # @private
101
+ def internal_validate_exclusiveMinimum(result_builder)
102
+ if keyword?('exclusiveMinimum')
103
+ value = schema_content['exclusiveMinimum']
104
+ # The value of "exclusiveMinimum" MUST be number, representing an exclusive lower limit for a numeric instance.
105
+ if value.is_a?(Numeric)
106
+ # If the instance is a number, then the instance is valid only if it has a value strictly greater
107
+ # than (not equal to) "exclusiveMinimum".
108
+ if result_builder.instance.is_a?(Numeric)
109
+ result_builder.validate(
110
+ result_builder.instance > value,
111
+ 'instance is not greater than `exclusiveMinimum` value',
112
+ keyword: 'exclusiveMinimum',
113
+ )
114
+ end
115
+ else
116
+ result_builder.schema_error('`exclusiveMinimum` is not a number', 'exclusiveMinimum')
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::MinMaxProperties
5
+ # @private
6
+ def internal_validate_maxProperties(result_builder)
7
+ if keyword?('maxProperties')
8
+ value = schema_content['maxProperties']
9
+ # The value of this keyword MUST be a non-negative integer.
10
+ if internal_integer?(value) && value >= 0
11
+ if result_builder.instance.respond_to?(:to_hash)
12
+ # An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
13
+ result_builder.validate(
14
+ result_builder.instance.size <= value,
15
+ 'instance object contains more properties than `maxProperties` value',
16
+ keyword: 'maxProperties',
17
+ )
18
+ end
19
+ else
20
+ result_builder.schema_error('`maxProperties` is not a non-negative integer', 'maxProperties')
21
+ end
22
+ end
23
+ end
24
+
25
+ # @private
26
+ def internal_validate_minProperties(result_builder)
27
+ if keyword?('minProperties')
28
+ value = schema_content['minProperties']
29
+ # The value of this keyword MUST be a non-negative integer.
30
+ if internal_integer?(value) && value >= 0
31
+ if result_builder.instance.respond_to?(:to_hash)
32
+ # An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword.
33
+ result_builder.validate(
34
+ result_builder.instance.size >= value,
35
+ 'instance object contains fewer properties than `minProperties` value',
36
+ keyword: 'minProperties',
37
+ )
38
+ end
39
+ else
40
+ result_builder.schema_error('`minProperties` is not a non-negative integer', 'minProperties')
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::Pattern
5
+ # @private
6
+ def internal_validate_pattern(result_builder)
7
+ if keyword?('pattern')
8
+ value = schema_content['pattern']
9
+ # The value of this keyword MUST be a string.
10
+ if value.respond_to?(:to_str)
11
+ if result_builder.instance.respond_to?(:to_str)
12
+ begin
13
+ # This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression
14
+ # dialect.
15
+ # TODO
16
+ regexp = Regexp.new(value)
17
+ # A string instance is considered valid if the regular expression matches the instance
18
+ # succssfully. Recall: regular expressions are not implicitly anchored.
19
+ result_builder.validate(
20
+ regexp.match(result_builder.instance),
21
+ 'instance string does not match `pattern` regular expression value',
22
+ keyword: 'pattern',
23
+ )
24
+ rescue RegexpError => e
25
+ result_builder.schema_error(-"`pattern` is not a valid regular expression: #{e.message}", 'pattern')
26
+ end
27
+ end
28
+ else
29
+ result_builder.schema_error('`pattern` is not a string', 'pattern')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::Properties
5
+ # @private
6
+ def internal_validate_properties(result_builder)
7
+ evaluated_property_names = Set[]
8
+
9
+ if keyword?('properties')
10
+ value = schema_content['properties']
11
+ # The value of "properties" MUST be an object. Each value of this object MUST be a valid JSON Schema.
12
+ if value.respond_to?(:to_hash)
13
+ # Validation succeeds if, for each name that appears in both the instance and as a name within this
14
+ # keyword's value, the child instance for that name successfully validates against the corresponding
15
+ # schema.
16
+ if result_builder.instance.respond_to?(:to_hash)
17
+ results = {}
18
+ result_builder.instance.keys.each do |property_name|
19
+ if value.key?(property_name)
20
+ evaluated_property_names << property_name
21
+ results[property_name] = result_builder.child_subschema_validate(
22
+ property_name,
23
+ ['properties', property_name],
24
+ )
25
+ end
26
+ end
27
+ result_builder.validate(
28
+ results.values.all?(&:valid?),
29
+ 'instance object properties are not all valid against corresponding `properties` schema values',
30
+ keyword: 'properties',
31
+ results: results.values,
32
+ )
33
+ end
34
+ else
35
+ result_builder.schema_error('`properties` is not an object', 'properties')
36
+ end
37
+ end
38
+
39
+ if keyword?('patternProperties')
40
+ value = schema_content['patternProperties']
41
+ # The value of "patternProperties" MUST be an object. Each property name of this object SHOULD be a
42
+ # valid regular expression, according to the ECMA 262 regular expression dialect. Each property value
43
+ # of this object MUST be a valid JSON Schema.
44
+ if value.respond_to?(:to_hash)
45
+ # Validation succeeds if, for each instance name that matches any regular expressions that appear as
46
+ # a property name in this keyword's value, the child instance for that name successfully validates
47
+ # against each schema that corresponds to a matching regular expression.
48
+ if result_builder.instance.respond_to?(:to_hash)
49
+ results = {}
50
+ result_builder.instance.keys.each do |property_name|
51
+ value.keys.each do |value_property_pattern|
52
+ begin
53
+ # TODO ECMA 262
54
+ if value_property_pattern.respond_to?(:to_str) && Regexp.new(value_property_pattern).match(property_name.to_s)
55
+ evaluated_property_names << property_name
56
+ results[property_name] = result_builder.child_subschema_validate(
57
+ property_name,
58
+ ['patternProperties', value_property_pattern],
59
+ )
60
+ end
61
+ rescue ::RegexpError
62
+ result_builder.schema_error("`patternProperties` key #{property_name.inspect} is not a valid regular expression: #{e.message}", 'patternProperties')
63
+ end
64
+ end
65
+ end
66
+ result_builder.validate(
67
+ results.values.all?(&:valid?),
68
+ 'instance object properties are not all valid against corresponding `patternProperties` schema values',
69
+ keyword: 'patternProperties',
70
+ results: results.values,
71
+ )
72
+ end
73
+ else
74
+ result_builder.schema_error('`patternProperties` is not an object', 'patternProperties')
75
+ end
76
+ end
77
+
78
+ if keyword?('additionalProperties')
79
+ value = schema_content['additionalProperties']
80
+ # The value of "additionalProperties" MUST be a valid JSON Schema.
81
+ if result_builder.instance.respond_to?(:to_hash)
82
+ results = {}
83
+ result_builder.instance.keys.each do |property_name|
84
+ if !evaluated_property_names.include?(property_name)
85
+ results[property_name] = result_builder.child_subschema_validate(
86
+ property_name,
87
+ ['additionalProperties'],
88
+ )
89
+ end
90
+ end.compact
91
+ result_builder.validate(
92
+ results.values.all?(&:valid?),
93
+ 'instance object additional properties are not all valid against `additionalProperties` schema value',
94
+ keyword: 'additionalProperties',
95
+ results: results.values,
96
+ )
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::PropertyNames
5
+ # @private
6
+ def internal_validate_propertyNames(result_builder)
7
+ if keyword?('propertyNames')
8
+ # The value of "propertyNames" MUST be a valid JSON Schema.
9
+ #
10
+ # If the instance is an object, this keyword validates if every property name in the instance
11
+ # validates against the provided schema. Note the property name that the schema is testing will
12
+ # always be a string.
13
+ if result_builder.instance.respond_to?(:to_hash)
14
+ results = {}
15
+ result_builder.instance.keys.each do |property_name|
16
+ results[property_name] = subschema(['propertyNames']).internal_validate_instance(
17
+ Ptr[],
18
+ property_name,
19
+ validate_only: result_builder.validate_only,
20
+ )
21
+ end
22
+ result_builder.validate(
23
+ results.values.all?(&:valid?),
24
+ 'instance object property names are not all valid against `propertyNames` schema value',
25
+ keyword: 'propertyNames',
26
+ results: results.values,
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::Ref
5
+ # @private
6
+ # @param throw_result [Boolean] if a $ref is present, whether to throw the result being built after
7
+ # validating the $ref, bypassing subsequent keyword validation
8
+ def internal_validate_ref(result_builder, throw_result: false)
9
+ if keyword?('$ref')
10
+ value = schema_content['$ref']
11
+
12
+ if value.respond_to?(:to_str)
13
+ schema_ref = self.schema_ref
14
+
15
+ if result_builder.visited_refs.include?(schema_ref)
16
+ result_builder.schema_error('self-referential schema structure', '$ref')
17
+ else
18
+ ref_result = schema_ref.deref_schema.internal_validate_instance(
19
+ result_builder.instance_ptr,
20
+ result_builder.instance_document,
21
+ validate_only: result_builder.validate_only,
22
+ visited_refs: result_builder.visited_refs + [schema_ref],
23
+ )
24
+ result_builder.validate(
25
+ ref_result.valid?,
26
+ 'instance is not valid against the schema referenced by `$ref` value',
27
+ keyword: '$ref',
28
+ results: [ref_result],
29
+ )
30
+ if throw_result
31
+ throw(:jsi_validation_result, result_builder.result)
32
+ end
33
+ end
34
+ else
35
+ result_builder.schema_error("`$ref` is not a string", '$ref')
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::Required
5
+ # @private
6
+ def internal_validate_required(result_builder)
7
+ if keyword?('required')
8
+ value = schema_content['required']
9
+ # The value of this keyword MUST be an array. Elements of this array, if any, MUST be strings, and MUST be unique.
10
+ if value.respond_to?(:to_ary)
11
+ if result_builder.instance.respond_to?(:to_hash)
12
+ # An object instance is valid against this keyword if every item in the array is the name of a property in the instance.
13
+ missing_required = value.reject { |property_name| result_builder.instance.key?(property_name) }
14
+ # TODO include missing required property names in the validation error
15
+ result_builder.validate(
16
+ missing_required.empty?,
17
+ 'instance object does not contain all property names specified by `required` value',
18
+ keyword: 'required',
19
+ )
20
+ end
21
+ else
22
+ result_builder.schema_error('`required` is not an array', 'required')
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::AllOf
5
+ # @private
6
+ def internal_validate_allOf(result_builder)
7
+ if keyword?('allOf')
8
+ value = schema_content['allOf']
9
+ # This keyword's value MUST be a non-empty array. Each item of the array MUST be a valid JSON Schema.
10
+ if value.respond_to?(:to_ary)
11
+ # An instance validates successfully against this keyword if it validates successfully against all
12
+ # schemas defined by this keyword's value.
13
+ allOf_results = value.each_index.map do |i|
14
+ result_builder.inplace_subschema_validate(['allOf', i])
15
+ end
16
+ result_builder.validate(
17
+ allOf_results.all?(&:valid?),
18
+ 'instance is not valid against all schemas specified by `allOf` value',
19
+ keyword: 'allOf',
20
+ results: allOf_results,
21
+ )
22
+ else
23
+ result_builder.schema_error('`allOf` is not an array', 'allOf')
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ module Schema::Validation::AnyOf
30
+ # @private
31
+ def internal_validate_anyOf(result_builder)
32
+ if keyword?('anyOf')
33
+ value = schema_content['anyOf']
34
+ # This keyword's value MUST be a non-empty array. Each item of the array MUST be a valid JSON Schema.
35
+ if value.respond_to?(:to_ary)
36
+ # An instance validates successfully against this keyword if it validates successfully against at
37
+ # least one schema defined by this keyword's value.
38
+ # Note that when annotations are being collected, all subschemas MUST be examined so that
39
+ # annotations are collected from each subschema that validates successfully.
40
+ anyOf_results = value.each_index.map do |i|
41
+ result_builder.inplace_subschema_validate(['anyOf', i])
42
+ end
43
+ result_builder.validate(
44
+ anyOf_results.any?(&:valid?),
45
+ 'instance is not valid against any schemas specified by `anyOf` value',
46
+ keyword: 'anyOf',
47
+ results: anyOf_results,
48
+ )
49
+ else
50
+ result_builder.schema_error('`anyOf` is not an array', 'anyOf')
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ module Schema::Validation::OneOf
57
+ # @private
58
+ def internal_validate_oneOf(result_builder)
59
+ if keyword?('oneOf')
60
+ value = schema_content['oneOf']
61
+ # This keyword's value MUST be a non-empty array. Each item of the array MUST be a valid JSON Schema.
62
+ if value.respond_to?(:to_ary)
63
+ # An instance validates successfully against this keyword if it validates successfully against
64
+ # exactly one schema defined by this keyword's value.
65
+ oneOf_results = value.each_index.map do |i|
66
+ result_builder.inplace_subschema_validate(['oneOf', i])
67
+ end
68
+ if oneOf_results.none?(&:valid?)
69
+ result_builder.validate(
70
+ false,
71
+ 'instance is not valid against any schemas specified by `oneOf` value',
72
+ keyword: 'oneOf',
73
+ results: oneOf_results,
74
+ )
75
+ else
76
+ # TODO better info on what schemas passed/failed validation
77
+ result_builder.validate(
78
+ oneOf_results.select(&:valid?).size == 1,
79
+ 'instance is valid against more than one schema specified by `oneOf` value',
80
+ keyword: 'oneOf',
81
+ results: oneOf_results,
82
+ )
83
+ end
84
+ else
85
+ result_builder.schema_error('`oneOf` is not an array', 'oneOf')
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::StringLength
5
+ # @private
6
+ def internal_validate_maxLength(result_builder)
7
+ if keyword?('maxLength')
8
+ value = schema_content['maxLength']
9
+ # The value of this keyword MUST be a non-negative integer.
10
+ if internal_integer?(value) && value >= 0
11
+ if result_builder.instance.respond_to?(:to_str)
12
+ # A string instance is valid against this keyword if its length is less than, or equal to, the
13
+ # value of this keyword.
14
+ result_builder.validate(
15
+ result_builder.instance.to_str.length <= value,
16
+ 'instance string length is not less than or equal to `maxLength` value',
17
+ keyword: 'maxLength',
18
+ )
19
+ end
20
+ else
21
+ result_builder.schema_error('`maxLength` is not a non-negative integer', 'maxLength')
22
+ end
23
+ end
24
+ end
25
+
26
+ # @private
27
+ def internal_validate_minLength(result_builder)
28
+ if keyword?('minLength')
29
+ value = schema_content['minLength']
30
+ # The value of this keyword MUST be a non-negative integer.
31
+ if internal_integer?(value) && value >= 0
32
+ if result_builder.instance.respond_to?(:to_str)
33
+ # A string instance is valid against this keyword if its length is greater than, or equal to, the
34
+ # value of this keyword.
35
+ result_builder.validate(
36
+ result_builder.instance.to_str.length >= value,
37
+ 'instance string length is not greater than or equal to `minLength` value',
38
+ keyword: 'minLength',
39
+ )
40
+ end
41
+ else
42
+ result_builder.schema_error('`minLength` is not a non-negative integer', 'minLength')
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation::Type
5
+ # @private
6
+ def internal_validate_type(result_builder)
7
+ if keyword?('type')
8
+ value = schema_content['type']
9
+ instance = result_builder.instance
10
+ # The value of this keyword MUST be either a string or an array. If it is an array, elements of
11
+ # the array MUST be strings and MUST be unique.
12
+ if value.respond_to?(:to_str) || value.respond_to?(:to_ary)
13
+ types = value.respond_to?(:to_str) ? [value] : value
14
+ matched_type = types.each_with_index.any? do |type, i|
15
+ if type.respond_to?(:to_str)
16
+ case type.to_str
17
+ when 'null'
18
+ instance == nil
19
+ when 'boolean'
20
+ instance == true || instance == false
21
+ when 'object'
22
+ instance.respond_to?(:to_hash)
23
+ when 'array'
24
+ instance.respond_to?(:to_ary)
25
+ when 'string'
26
+ instance.respond_to?(:to_str)
27
+ when 'number'
28
+ instance.is_a?(Numeric)
29
+ when 'integer'
30
+ internal_integer?(instance)
31
+ else
32
+ result_builder.schema_error("`type` is not one of: null, boolean, object, array, string, number, or integer", 'type')
33
+ end
34
+ else
35
+ result_builder.schema_error("`type` is not a string at index #{i}", 'type')
36
+ end
37
+ end
38
+ result_builder.validate(
39
+ matched_type,
40
+ 'instance type does not match `type` value',
41
+ keyword: 'type',
42
+ )
43
+ else
44
+ result_builder.schema_error('`type` is not a string or array', 'type')
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Schema::Validation
5
+ autoload :Draft04, 'jsi/schema/validation/draft04'
6
+ autoload :Draft06, 'jsi/schema/validation/draft06'
7
+ autoload :Draft07, 'jsi/schema/validation/draft07'
8
+
9
+ # ref application
10
+ autoload :Ref, 'jsi/schema/validation/ref'
11
+
12
+ # inplace subschema application
13
+ autoload :AllOf, 'jsi/schema/validation/someof'
14
+ autoload :AnyOf, 'jsi/schema/validation/someof'
15
+ autoload :OneOf, 'jsi/schema/validation/someof'
16
+ autoload :IfThenElse, 'jsi/schema/validation/ifthenelse'
17
+
18
+ # child subschema application
19
+ autoload :Items, 'jsi/schema/validation/items'
20
+ autoload :Contains, 'jsi/schema/validation/contains'
21
+ autoload :Properties, 'jsi/schema/validation/properties'
22
+
23
+ # property names subschema application
24
+ autoload :PropertyNames, 'jsi/schema/validation/property_names'
25
+
26
+ # any type validation
27
+ autoload :Type, 'jsi/schema/validation/type'
28
+ autoload :Enum, 'jsi/schema/validation/enum'
29
+ autoload :Const, 'jsi/schema/validation/const'
30
+ autoload :Not, 'jsi/schema/validation/not'
31
+
32
+ # object validation
33
+ autoload :Required, 'jsi/schema/validation/required'
34
+ autoload :Dependencies, 'jsi/schema/validation/dependencies'
35
+ autoload :MinMaxProperties, 'jsi/schema/validation/object'
36
+
37
+ # array validation
38
+ autoload :ArrayLength, 'jsi/schema/validation/array'
39
+ autoload :UniqueItems, 'jsi/schema/validation/array'
40
+
41
+ # string validation
42
+ autoload :StringLength, 'jsi/schema/validation/string'
43
+ autoload :Pattern, 'jsi/schema/validation/pattern'
44
+
45
+ # numeric validation
46
+ autoload :MultipleOf, 'jsi/schema/validation/numeric'
47
+ autoload :MinMax, 'jsi/schema/validation/numeric'
48
+ end
49
+ end