jsi 0.2.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +36 -0
- data/LICENSE.md +613 -0
- data/README.md +153 -52
- data/lib/jsi/base.rb +485 -338
- data/lib/jsi/jsi_coder.rb +24 -18
- data/lib/jsi/metaschema.rb +7 -0
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +100 -0
- data/lib/jsi/metaschema_node.rb +245 -0
- data/lib/jsi/pathed_node.rb +49 -46
- data/lib/jsi/ptr.rb +292 -0
- data/lib/jsi/schema/application/child_application/contains.rb +16 -0
- data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
- data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
- data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
- data/lib/jsi/schema/application/child_application/items.rb +18 -0
- data/lib/jsi/schema/application/child_application/properties.rb +25 -0
- data/lib/jsi/schema/application/child_application.rb +40 -0
- data/lib/jsi/schema/application/draft04.rb +8 -0
- data/lib/jsi/schema/application/draft06.rb +8 -0
- data/lib/jsi/schema/application/draft07.rb +8 -0
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
- data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
- data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
- data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
- data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
- data/lib/jsi/schema/application/inplace_application/someof.rb +29 -0
- data/lib/jsi/schema/application/inplace_application.rb +46 -0
- data/lib/jsi/schema/application.rb +12 -0
- data/lib/jsi/schema/draft04.rb +14 -0
- data/lib/jsi/schema/draft06.rb +14 -0
- data/lib/jsi/schema/draft07.rb +14 -0
- data/lib/jsi/schema/issue.rb +36 -0
- data/lib/jsi/schema/ref.rb +159 -0
- data/lib/jsi/schema/schema_ancestor_node.rb +119 -0
- data/lib/jsi/schema/validation/array.rb +69 -0
- data/lib/jsi/schema/validation/const.rb +20 -0
- data/lib/jsi/schema/validation/contains.rb +25 -0
- data/lib/jsi/schema/validation/core.rb +39 -0
- data/lib/jsi/schema/validation/dependencies.rb +49 -0
- data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
- data/lib/jsi/schema/validation/draft04.rb +112 -0
- data/lib/jsi/schema/validation/draft06.rb +122 -0
- data/lib/jsi/schema/validation/draft07.rb +159 -0
- data/lib/jsi/schema/validation/enum.rb +25 -0
- data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
- data/lib/jsi/schema/validation/items.rb +54 -0
- data/lib/jsi/schema/validation/not.rb +20 -0
- data/lib/jsi/schema/validation/numeric.rb +121 -0
- data/lib/jsi/schema/validation/object.rb +45 -0
- data/lib/jsi/schema/validation/pattern.rb +34 -0
- data/lib/jsi/schema/validation/properties.rb +101 -0
- data/lib/jsi/schema/validation/property_names.rb +32 -0
- data/lib/jsi/schema/validation/ref.rb +40 -0
- data/lib/jsi/schema/validation/required.rb +27 -0
- data/lib/jsi/schema/validation/someof.rb +90 -0
- data/lib/jsi/schema/validation/string.rb +47 -0
- data/lib/jsi/schema/validation/type.rb +49 -0
- data/lib/jsi/schema/validation.rb +51 -0
- data/lib/jsi/schema.rb +528 -233
- data/lib/jsi/schema_classes.rb +238 -51
- data/lib/jsi/schema_registry.rb +141 -0
- data/lib/jsi/schema_set.rb +141 -0
- data/lib/jsi/simple_wrap.rb +8 -3
- data/lib/jsi/typelike_modules.rb +75 -68
- data/lib/jsi/util/attr_struct.rb +106 -0
- data/lib/jsi/util.rb +167 -64
- data/lib/jsi/validation/error.rb +34 -0
- data/lib/jsi/validation/result.rb +210 -0
- data/lib/jsi/validation.rb +15 -0
- data/lib/jsi/version.rb +3 -1
- data/lib/jsi.rb +72 -9
- data/lib/schemas/json-schema.org/draft-04/schema.rb +12 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +12 -0
- data/lib/schemas/json-schema.org/draft-07/schema.rb +12 -0
- data/readme.rb +138 -0
- data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
- data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
- data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
- metadata +80 -107
- data/.simplecov +0 -1
- data/LICENSE.txt +0 -21
- data/Rakefile.rb +0 -9
- data/jsi.gemspec +0 -31
- data/lib/jsi/base/to_rb.rb +0 -126
- data/lib/jsi/json/node.rb +0 -243
- data/lib/jsi/json/pointer.rb +0 -330
- data/lib/jsi/json-schema-fragments.rb +0 -59
- data/lib/jsi/json.rb +0 -8
- data/test/base_array_test.rb +0 -209
- data/test/base_hash_test.rb +0 -204
- data/test/base_test.rb +0 -422
- data/test/jsi_coder_test.rb +0 -85
- data/test/jsi_json_arraynode_test.rb +0 -150
- data/test/jsi_json_hashnode_test.rb +0 -132
- data/test/jsi_json_node_test.rb +0 -310
- data/test/jsi_json_pointer_test.rb +0 -106
- data/test/jsi_test.rb +0 -11
- data/test/jsi_typelike_as_json_test.rb +0 -53
- data/test/schema_test.rb +0 -196
- data/test/spreedly_openapi_test.rb +0 -8
- data/test/test_helper.rb +0 -63
- data/test/util_test.rb +0 -62
data/lib/jsi/ptr.rb
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
# a representation to work with JSON Pointer, as described by RFC 6901 https://tools.ietf.org/html/rfc6901
|
5
|
+
#
|
6
|
+
# a pointer is a sequence of tokens pointing to a node in a document.
|
7
|
+
class Ptr
|
8
|
+
class Error < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
# raised when attempting to parse a JSON Pointer string with invalid syntax
|
12
|
+
class PointerSyntaxError < Error
|
13
|
+
end
|
14
|
+
|
15
|
+
# raised when a pointer refers to a path in a document that could not be resolved
|
16
|
+
class ResolutionError < Error
|
17
|
+
end
|
18
|
+
|
19
|
+
# instantiates a pointer or returns the given pointer
|
20
|
+
# @param ary_ptr [#to_ary, JSI::Ptr] an array of tokens, or a pointer
|
21
|
+
# @return [JSI::Ptr]
|
22
|
+
def self.ary_ptr(ary_ptr)
|
23
|
+
if ary_ptr.is_a?(Ptr)
|
24
|
+
ary_ptr
|
25
|
+
else
|
26
|
+
new(ary_ptr)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# instantiates a pointer from the given tokens.
|
31
|
+
#
|
32
|
+
# JSI::Ptr[]
|
33
|
+
#
|
34
|
+
# instantes a root pointer.
|
35
|
+
#
|
36
|
+
# JSI::Ptr['a', 'b']
|
37
|
+
# JSI::Ptr['a']['b']
|
38
|
+
#
|
39
|
+
# are both ways to instantiate a pointer with tokens ['a', 'b']. the latter example chains the
|
40
|
+
# class .[] method with the instance #[] method.
|
41
|
+
#
|
42
|
+
# @param tokens any number of tokens
|
43
|
+
# @return [JSI::Ptr]
|
44
|
+
def self.[](*tokens)
|
45
|
+
new(tokens)
|
46
|
+
end
|
47
|
+
|
48
|
+
# parse a URI-escaped fragment and instantiate as a JSI::Ptr
|
49
|
+
#
|
50
|
+
# JSI::Ptr.from_fragment('/foo/bar')
|
51
|
+
# => JSI::Ptr["foo", "bar"]
|
52
|
+
#
|
53
|
+
# with URI escaping:
|
54
|
+
#
|
55
|
+
# JSI::Ptr.from_fragment('/foo%20bar')
|
56
|
+
# => JSI::Ptr["foo bar"]
|
57
|
+
#
|
58
|
+
# @param fragment [String] a fragment containing a pointer
|
59
|
+
# @return [JSI::Ptr]
|
60
|
+
# @raise [JSI::Ptr::PointerSyntaxError] when the fragment does not contain a pointer with
|
61
|
+
# valid pointer syntax
|
62
|
+
def self.from_fragment(fragment)
|
63
|
+
from_pointer(Addressable::URI.unescape(fragment))
|
64
|
+
end
|
65
|
+
|
66
|
+
# parse a pointer string and instantiate as a JSI::Ptr
|
67
|
+
#
|
68
|
+
# JSI::Ptr.from_pointer('/foo')
|
69
|
+
# => JSI::Ptr["foo"]
|
70
|
+
#
|
71
|
+
# JSI::Ptr.from_pointer('/foo~0bar/baz~1qux')
|
72
|
+
# => JSI::Ptr["foo~bar", "baz/qux"]
|
73
|
+
#
|
74
|
+
# @param pointer_string [String] a pointer string
|
75
|
+
# @return [JSI::Ptr]
|
76
|
+
# @raise [JSI::Ptr::PointerSyntaxError] when the pointer_string does not have valid pointer syntax
|
77
|
+
def self.from_pointer(pointer_string)
|
78
|
+
tokens = pointer_string.split('/', -1).map! do |piece|
|
79
|
+
piece.gsub('~1', '/').gsub('~0', '~')
|
80
|
+
end
|
81
|
+
if tokens[0] == ''
|
82
|
+
new(tokens[1..-1])
|
83
|
+
elsif tokens.empty?
|
84
|
+
new(tokens)
|
85
|
+
else
|
86
|
+
raise(PointerSyntaxError, "Invalid pointer syntax in #{pointer_string.inspect}: pointer must begin with /")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# initializes a JSI::Ptr from the given tokens.
|
91
|
+
#
|
92
|
+
# @param tokens [Array<Object>]
|
93
|
+
def initialize(tokens)
|
94
|
+
unless tokens.respond_to?(:to_ary)
|
95
|
+
raise(TypeError, "tokens must be an array. got: #{tokens.inspect}")
|
96
|
+
end
|
97
|
+
@tokens = tokens.to_ary.map(&:freeze).freeze
|
98
|
+
end
|
99
|
+
|
100
|
+
attr_reader :tokens
|
101
|
+
|
102
|
+
# @private @deprecated
|
103
|
+
alias_method :reference_tokens, :tokens
|
104
|
+
|
105
|
+
# takes a root json document and evaluates this pointer through the document, returning the value
|
106
|
+
# pointed to by this pointer.
|
107
|
+
#
|
108
|
+
# @param document [#to_ary, #to_hash] the document against which we will evaluate this pointer
|
109
|
+
# @param a arguments are passed to each invocation of `#[]`
|
110
|
+
# @return [Object] the content of the document pointed to by this pointer
|
111
|
+
# @raise [JSI::Ptr::ResolutionError] the document does not contain the path this pointer references
|
112
|
+
def evaluate(document, *a)
|
113
|
+
res = tokens.inject(document) do |value, token|
|
114
|
+
_, child = node_subscript_token_child(value, token, *a)
|
115
|
+
child
|
116
|
+
end
|
117
|
+
res
|
118
|
+
end
|
119
|
+
|
120
|
+
# the pointer string representation of this pointer
|
121
|
+
# @return [String]
|
122
|
+
def pointer
|
123
|
+
tokens.map { |t| '/' + t.to_s.gsub('~', '~0').gsub('/', '~1') }.join('')
|
124
|
+
end
|
125
|
+
|
126
|
+
# the fragment string representation of this pointer
|
127
|
+
# @return [String]
|
128
|
+
def fragment
|
129
|
+
Addressable::URI.escape(pointer)
|
130
|
+
end
|
131
|
+
|
132
|
+
# a URI consisting of a fragment containing this pointer's fragment string representation
|
133
|
+
# @return [Addressable::URI]
|
134
|
+
def uri
|
135
|
+
Addressable::URI.new(fragment: fragment)
|
136
|
+
end
|
137
|
+
|
138
|
+
# whether this pointer is empty, i.e. it has no tokens
|
139
|
+
# @return [Boolean]
|
140
|
+
def empty?
|
141
|
+
tokens.empty?
|
142
|
+
end
|
143
|
+
|
144
|
+
# whether this is a root pointer, indicated by an empty array of tokens
|
145
|
+
# @return [Boolean]
|
146
|
+
alias_method :root?, :empty?
|
147
|
+
|
148
|
+
# pointer to the parent of where this pointer points
|
149
|
+
# @return [JSI::Ptr]
|
150
|
+
# @raise [JSI::Ptr::Error] if this pointer has no parent (points to the root)
|
151
|
+
def parent
|
152
|
+
if root?
|
153
|
+
raise(Ptr::Error, "cannot access parent of root pointer: #{pretty_inspect.chomp}")
|
154
|
+
else
|
155
|
+
Ptr.new(tokens[0...-1])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# whether this pointer contains the other_ptr - that is, whether this pointer is an ancestor
|
160
|
+
# of `other_ptr`, a child pointer. `contains?` is inclusive; a pointer does contain itself.
|
161
|
+
# @return [Boolean]
|
162
|
+
def contains?(other_ptr)
|
163
|
+
self.tokens == other_ptr.tokens[0...self.tokens.size]
|
164
|
+
end
|
165
|
+
|
166
|
+
# part of this pointer relative to the given ancestor_ptr
|
167
|
+
# @return [JSI::Ptr]
|
168
|
+
# @raise [JSI::Ptr::Error] if the given ancestor_ptr is not an ancestor of this pointer
|
169
|
+
def ptr_relative_to(ancestor_ptr)
|
170
|
+
unless ancestor_ptr.contains?(self)
|
171
|
+
raise(Error, "ancestor_ptr #{ancestor_ptr.inspect} is not ancestor of #{inspect}")
|
172
|
+
end
|
173
|
+
Ptr.new(tokens[ancestor_ptr.tokens.size..-1])
|
174
|
+
end
|
175
|
+
|
176
|
+
# a pointer with the tokens of this one plus the given `ptr`'s.
|
177
|
+
# @param ptr [JSI::Ptr, #to_ary]
|
178
|
+
# @return [JSI::Ptr]
|
179
|
+
def +(ptr)
|
180
|
+
if ptr.is_a?(Ptr)
|
181
|
+
ptr_tokens = ptr.tokens
|
182
|
+
elsif ptr.respond_to?(:to_ary)
|
183
|
+
ptr_tokens = ptr
|
184
|
+
else
|
185
|
+
raise(TypeError, "ptr must be a JSI::Ptr or Array of tokens; got: #{ptr.inspect}")
|
186
|
+
end
|
187
|
+
Ptr.new(self.tokens + ptr_tokens)
|
188
|
+
end
|
189
|
+
|
190
|
+
# a pointer consisting of the first `n` of our tokens
|
191
|
+
# @param n [Integer]
|
192
|
+
# @return [JSI::Ptr]
|
193
|
+
# @raise [ArgumentError] if n is not between 0 and the size of our tokens
|
194
|
+
def take(n)
|
195
|
+
unless (0..tokens.size).include?(n)
|
196
|
+
raise(ArgumentError, "n not in range (0..#{tokens.size}): #{n.inspect}")
|
197
|
+
end
|
198
|
+
Ptr.new(tokens.take(n))
|
199
|
+
end
|
200
|
+
|
201
|
+
# appends the given token to this pointer's tokens and returns the result
|
202
|
+
#
|
203
|
+
# @param token [Object]
|
204
|
+
# @return [JSI::Ptr] pointer to a child node of this pointer with the given token
|
205
|
+
def [](token)
|
206
|
+
Ptr.new(tokens + [token])
|
207
|
+
end
|
208
|
+
|
209
|
+
# takes a document and a block. the block is yielded the content of the given document at this
|
210
|
+
# pointer's location. the block must result a modified copy of that content (and MUST NOT modify
|
211
|
+
# the object it is given). this modified copy of that content is incorporated into a modified copy
|
212
|
+
# of the given document, which is then returned. the structure and contents of the document outside
|
213
|
+
# the path pointed to by this pointer is not modified.
|
214
|
+
#
|
215
|
+
# @param document [Object] the document to apply this pointer to
|
216
|
+
# @yield [Object] the content this pointer applies to in the given document
|
217
|
+
# the block must result in the new content which will be placed in the modified document copy.
|
218
|
+
# @return [Object] a copy of the given document, with the content this pointer applies to
|
219
|
+
# replaced by the result of the block
|
220
|
+
def modified_document_copy(document, &block)
|
221
|
+
# we need to preserve the rest of the document, but modify the content at our path.
|
222
|
+
#
|
223
|
+
# this is actually a bit tricky. we can't modify the original document, obviously.
|
224
|
+
# we could do a deep copy, but that's expensive. instead, we make a copy of each array
|
225
|
+
# or hash in the path above the node we point to. this node's content is modified by the
|
226
|
+
# caller, and that is recursively merged up to the document root.
|
227
|
+
if empty?
|
228
|
+
Typelike.modified_copy(document, &block)
|
229
|
+
else
|
230
|
+
car = tokens[0]
|
231
|
+
cdr = Ptr.new(tokens[1..-1])
|
232
|
+
token, document_child = node_subscript_token_child(document, car)
|
233
|
+
modified_document_child = cdr.modified_document_copy(document_child, &block)
|
234
|
+
if modified_document_child.object_id == document_child.object_id
|
235
|
+
document
|
236
|
+
else
|
237
|
+
modified_document = document.respond_to?(:[]=) ? document.dup :
|
238
|
+
document.respond_to?(:to_hash) ? document.to_hash.dup :
|
239
|
+
document.respond_to?(:to_ary) ? document.to_ary.dup :
|
240
|
+
raise(Bug) # not possible; node_subscript_token_child would have raised
|
241
|
+
modified_document[token] = modified_document_child
|
242
|
+
modified_document
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# a string representation of this pointer
|
248
|
+
# @return [String]
|
249
|
+
def inspect
|
250
|
+
"#{self.class.name}[#{tokens.map(&:inspect).join(", ")}]"
|
251
|
+
end
|
252
|
+
|
253
|
+
alias_method :to_s, :inspect
|
254
|
+
|
255
|
+
# pointers are equal if the tokens are equal
|
256
|
+
def jsi_fingerprint
|
257
|
+
{class: Ptr, tokens: tokens}
|
258
|
+
end
|
259
|
+
include Util::FingerprintHash
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
def node_subscript_token_child(value, token, *a)
|
264
|
+
if value.respond_to?(:to_ary)
|
265
|
+
if token.is_a?(String) && token =~ /\A\d|[1-9]\d+\z/
|
266
|
+
token = token.to_i
|
267
|
+
elsif token == '-'
|
268
|
+
# per rfc6901, - refers "to the (nonexistent) member after the last array element" and is
|
269
|
+
# expected to raise an error condition.
|
270
|
+
raise(ResolutionError, "Invalid resolution: #{token.inspect} refers to a nonexistent element in array #{value.inspect}")
|
271
|
+
end
|
272
|
+
unless token.is_a?(Integer)
|
273
|
+
raise(ResolutionError, "Invalid resolution: #{token.inspect} is not an integer and cannot be resolved in array #{value.inspect}")
|
274
|
+
end
|
275
|
+
unless (0...(value.respond_to?(:size) ? value : value.to_ary).size).include?(token)
|
276
|
+
raise(ResolutionError, "Invalid resolution: #{token.inspect} is not a valid index of #{value.inspect}")
|
277
|
+
end
|
278
|
+
|
279
|
+
child = (value.respond_to?(:[]) ? value : value.to_ary)[token, *a]
|
280
|
+
elsif value.respond_to?(:to_hash)
|
281
|
+
unless (value.respond_to?(:key?) ? value : value.to_hash).key?(token)
|
282
|
+
raise(ResolutionError, "Invalid resolution: #{token.inspect} is not a valid key of #{value.inspect}")
|
283
|
+
end
|
284
|
+
|
285
|
+
child = (value.respond_to?(:[]) ? value : value.to_hash)[token, *a]
|
286
|
+
else
|
287
|
+
raise(ResolutionError, "Invalid resolution: #{token.inspect} cannot be resolved in #{value.inspect}")
|
288
|
+
end
|
289
|
+
[token, child]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication::Contains
|
5
|
+
# @private
|
6
|
+
def internal_applicate_contains(idx, instance, &block)
|
7
|
+
if schema_content.key?('contains')
|
8
|
+
contains_schema = subschema(['contains'])
|
9
|
+
|
10
|
+
if contains_schema.instance_valid?(instance[idx])
|
11
|
+
yield contains_schema
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication::Draft04
|
5
|
+
include Schema::Application::ChildApplication
|
6
|
+
include Schema::Application::ChildApplication::Items
|
7
|
+
include Schema::Application::ChildApplication::Properties
|
8
|
+
|
9
|
+
# @private
|
10
|
+
def internal_child_applicate_keywords(token, instance, &block)
|
11
|
+
if instance.respond_to?(:to_ary)
|
12
|
+
# 5.3.1. additionalItems and items
|
13
|
+
internal_applicate_items(token, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
if instance.respond_to?(:to_hash)
|
17
|
+
# 5.4.4. additionalProperties, properties and patternProperties
|
18
|
+
internal_applicate_properties(token, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication::Draft06
|
5
|
+
include Schema::Application::ChildApplication
|
6
|
+
include Schema::Application::ChildApplication::Items
|
7
|
+
include Schema::Application::ChildApplication::Contains
|
8
|
+
include Schema::Application::ChildApplication::Properties
|
9
|
+
|
10
|
+
# @private
|
11
|
+
def internal_child_applicate_keywords(token, instance, &block)
|
12
|
+
if instance.respond_to?(:to_ary)
|
13
|
+
# json-schema-validation 6.9. items
|
14
|
+
# json-schema-validation 6.10. additionalItems
|
15
|
+
internal_applicate_items(token, &block)
|
16
|
+
|
17
|
+
# json-schema-validation 6.14. contains
|
18
|
+
internal_applicate_contains(token, instance, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
if instance.respond_to?(:to_hash)
|
22
|
+
# json-schema-validation 6.18. properties
|
23
|
+
# json-schema-validation 6.19. patternProperties
|
24
|
+
# json-schema-validation 6.20. additionalProperties
|
25
|
+
internal_applicate_properties(token, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication::Draft07
|
5
|
+
include Schema::Application::ChildApplication
|
6
|
+
include Schema::Application::ChildApplication::Items
|
7
|
+
include Schema::Application::ChildApplication::Contains
|
8
|
+
include Schema::Application::ChildApplication::Properties
|
9
|
+
|
10
|
+
# @private
|
11
|
+
def internal_child_applicate_keywords(token, instance, &block)
|
12
|
+
if instance.respond_to?(:to_ary)
|
13
|
+
# 6.4.1. items
|
14
|
+
# 6.4.2. additionalItems
|
15
|
+
internal_applicate_items(token, &block)
|
16
|
+
|
17
|
+
# 6.4.6. contains
|
18
|
+
internal_applicate_contains(token, instance, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
if instance.respond_to?(:to_hash)
|
22
|
+
# 6.5.4. properties
|
23
|
+
# 6.5.5. patternProperties
|
24
|
+
# 6.5.6. additionalProperties
|
25
|
+
internal_applicate_properties(token, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication::Items
|
5
|
+
# @private
|
6
|
+
def internal_applicate_items(idx, &block)
|
7
|
+
if schema_content['items'].respond_to?(:to_ary)
|
8
|
+
if schema_content['items'].each_index.to_a.include?(idx)
|
9
|
+
yield subschema(['items', idx])
|
10
|
+
elsif schema_content.key?('additionalItems')
|
11
|
+
yield subschema(['additionalItems'])
|
12
|
+
end
|
13
|
+
elsif schema_content.key?('items')
|
14
|
+
yield subschema(['items'])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication::Properties
|
5
|
+
# @private
|
6
|
+
def internal_applicate_properties(property_name, &block)
|
7
|
+
apply_additional = true
|
8
|
+
if schema_content.key?('properties') && schema_content['properties'].respond_to?(:to_hash) && schema_content['properties'].key?(property_name)
|
9
|
+
apply_additional = false
|
10
|
+
yield subschema(['properties', property_name])
|
11
|
+
end
|
12
|
+
if schema_content['patternProperties'].respond_to?(:to_hash)
|
13
|
+
schema_content['patternProperties'].each_key do |pattern|
|
14
|
+
if pattern.respond_to?(:to_str) && property_name.to_s =~ Regexp.new(pattern) # TODO map pattern to ruby syntax
|
15
|
+
apply_additional = false
|
16
|
+
yield subschema(['patternProperties', pattern])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
if apply_additional && schema_content.key?('additionalProperties')
|
21
|
+
yield subschema(['additionalProperties'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::ChildApplication
|
5
|
+
autoload :Draft04, 'jsi/schema/application/child_application/draft04'
|
6
|
+
autoload :Draft06, 'jsi/schema/application/child_application/draft06'
|
7
|
+
autoload :Draft07, 'jsi/schema/application/child_application/draft07'
|
8
|
+
|
9
|
+
autoload :Items, 'jsi/schema/application/child_application/items'
|
10
|
+
autoload :Contains, 'jsi/schema/application/child_application/contains'
|
11
|
+
autoload :Properties, 'jsi/schema/application/child_application/properties'
|
12
|
+
|
13
|
+
# a set of child applicator subschemas of this schema which apply to the child of the given instance
|
14
|
+
# on the given token.
|
15
|
+
#
|
16
|
+
# @param token [Object] the array index or object property name for the child instance
|
17
|
+
# @param instance [Object] the instance to check any child applicators against
|
18
|
+
# @return [JSI::SchemaSet] child applicator subschemas of this schema for the given token
|
19
|
+
# of the instance
|
20
|
+
def child_applicator_schemas(token, instance)
|
21
|
+
SchemaSet.new(each_child_applicator_schema(token, instance))
|
22
|
+
end
|
23
|
+
|
24
|
+
# yields each child applicator subschema (from properties, items, etc.) which applies to the child of
|
25
|
+
# the given instance on the given token.
|
26
|
+
#
|
27
|
+
# @param (see #child_applicator_schemas)
|
28
|
+
# @yield [JSI::Schema]
|
29
|
+
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
30
|
+
def each_child_applicator_schema(token, instance, &block)
|
31
|
+
return to_enum(__method__, token, instance) unless block
|
32
|
+
|
33
|
+
if schema_content.respond_to?(:to_hash)
|
34
|
+
internal_child_applicate_keywords(token, instance, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::InplaceApplication::Dependencies
|
5
|
+
# @private
|
6
|
+
def internal_applicate_dependencies(instance, visited_refs, &block)
|
7
|
+
if schema_content.key?('dependencies')
|
8
|
+
value = schema_content['dependencies']
|
9
|
+
# This keyword's value MUST be an object. Each property specifies a dependency. Each dependency
|
10
|
+
# value MUST be an array or a valid JSON Schema.
|
11
|
+
if value.respond_to?(:to_hash)
|
12
|
+
value.each_pair do |property_name, dependency|
|
13
|
+
if dependency.respond_to?(:to_ary)
|
14
|
+
# noop: array-form dependencies has no inplace applicator schema
|
15
|
+
else
|
16
|
+
# If the dependency value is a subschema, and the dependency key is a
|
17
|
+
# property in the instance, the entire instance must validate against
|
18
|
+
# the dependency value.
|
19
|
+
if instance.respond_to?(:to_hash) && instance.key?(property_name)
|
20
|
+
subschema(['dependencies', property_name]).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::InplaceApplication::Draft04
|
5
|
+
include Schema::Application::InplaceApplication
|
6
|
+
include Schema::Application::InplaceApplication::Ref
|
7
|
+
include Schema::Application::InplaceApplication::Dependencies
|
8
|
+
include Schema::Application::InplaceApplication::SomeOf
|
9
|
+
|
10
|
+
# @private
|
11
|
+
def internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
12
|
+
internal_applicate_ref(instance, visited_refs, throw_done: true, &block)
|
13
|
+
|
14
|
+
# self is the first applicator schema if $ref has not short-circuited it
|
15
|
+
yield self
|
16
|
+
|
17
|
+
# 5.4.5. dependencies
|
18
|
+
internal_applicate_dependencies(instance, visited_refs, &block)
|
19
|
+
|
20
|
+
# 5.5.3. allOf
|
21
|
+
# 5.5.4. anyOf
|
22
|
+
# 5.5.5. oneOf
|
23
|
+
internal_applicate_someOf(instance, visited_refs, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::InplaceApplication::Draft06
|
5
|
+
include Schema::Application::InplaceApplication
|
6
|
+
include Schema::Application::InplaceApplication::Ref
|
7
|
+
include Schema::Application::InplaceApplication::Dependencies
|
8
|
+
include Schema::Application::InplaceApplication::SomeOf
|
9
|
+
|
10
|
+
# @private
|
11
|
+
def internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
12
|
+
# json-schema 8. Schema references with $ref
|
13
|
+
internal_applicate_ref(instance, visited_refs, throw_done: true, &block)
|
14
|
+
|
15
|
+
# self is the first applicator schema if $ref has not short-circuited it
|
16
|
+
yield self
|
17
|
+
|
18
|
+
# json-schema-validation 6.21. dependencies
|
19
|
+
internal_applicate_dependencies(instance, visited_refs, &block)
|
20
|
+
|
21
|
+
# json-schema-validation 6.26. allOf
|
22
|
+
# json-schema-validation 6.27. anyOf
|
23
|
+
# json-schema-validation 6.28. oneOf
|
24
|
+
internal_applicate_someOf(instance, visited_refs, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::InplaceApplication::Draft07
|
5
|
+
include Schema::Application::InplaceApplication
|
6
|
+
include Schema::Application::InplaceApplication::Ref
|
7
|
+
include Schema::Application::InplaceApplication::Dependencies
|
8
|
+
include Schema::Application::InplaceApplication::IfThenElse
|
9
|
+
include Schema::Application::InplaceApplication::SomeOf
|
10
|
+
|
11
|
+
# @private
|
12
|
+
def internal_inplace_applicate_keywords(instance, visited_refs, &block)
|
13
|
+
# json-schema 8. Schema references with $ref
|
14
|
+
internal_applicate_ref(instance, visited_refs, throw_done: true, &block)
|
15
|
+
|
16
|
+
# self is the first applicator schema if $ref has not short-circuited it
|
17
|
+
block.call(self)
|
18
|
+
|
19
|
+
# 6.5.7. dependencies
|
20
|
+
internal_applicate_dependencies(instance, visited_refs, &block)
|
21
|
+
|
22
|
+
# 6.6.1. if
|
23
|
+
# 6.6.2. then
|
24
|
+
# 6.6.3. else
|
25
|
+
internal_applicate_ifthenelse(instance, visited_refs, &block)
|
26
|
+
|
27
|
+
# 6.7.1. allOf
|
28
|
+
# 6.7.2. anyOf
|
29
|
+
# 6.7.3. oneOf
|
30
|
+
internal_applicate_someOf(instance, visited_refs, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::InplaceApplication::IfThenElse
|
5
|
+
# @private
|
6
|
+
def internal_applicate_ifthenelse(instance, visited_refs, &block)
|
7
|
+
if schema_content.key?('if')
|
8
|
+
if subschema(['if']).instance_valid?(instance)
|
9
|
+
if schema_content.key?('then')
|
10
|
+
subschema(['then']).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
11
|
+
end
|
12
|
+
else
|
13
|
+
if schema_content.key?('else')
|
14
|
+
subschema(['else']).each_inplace_applicator_schema(instance, visited_refs: visited_refs, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSI
|
4
|
+
module Schema::Application::InplaceApplication::Ref
|
5
|
+
# @private
|
6
|
+
def internal_applicate_ref(instance, visited_refs, throw_done: false, &block)
|
7
|
+
if schema_content['$ref'].respond_to?(:to_str)
|
8
|
+
ref = jsi_memoize(:ref) { Schema::Ref.new(schema_content['$ref'], self) }
|
9
|
+
unless visited_refs.include?(ref)
|
10
|
+
ref.deref_schema.each_inplace_applicator_schema(instance, visited_refs: visited_refs + [ref], &block)
|
11
|
+
if throw_done
|
12
|
+
throw(:jsi_application_done)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|