jsi-dev 0.0.0.pre.kramdown
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.
- 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
|