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