jsi-dev 0.0.8 → 0.0.9
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 +4 -4
- data/.yardopts +3 -4
- data/CHANGELOG.md +19 -0
- data/LICENSE.md +2 -3
- data/README.md +87 -43
- data/docs/{glossary.md → Glossary.md} +84 -52
- data/jsi.gemspec +1 -1
- data/lib/jsi/base/mutability.rb +48 -0
- data/lib/jsi/base/node.rb +66 -52
- data/lib/jsi/base.rb +592 -176
- data/lib/jsi/jsi_coder.rb +4 -2
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +118 -59
- data/lib/jsi/metaschema_node.rb +244 -154
- data/lib/jsi/ptr.rb +45 -17
- data/lib/jsi/ref.rb +197 -0
- data/lib/jsi/registry.rb +311 -0
- data/lib/jsi/schema/cxt/child_application.rb +35 -0
- data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
- data/lib/jsi/schema/cxt.rb +80 -0
- data/lib/jsi/schema/dialect.rb +137 -0
- data/lib/jsi/schema/draft04.rb +113 -5
- data/lib/jsi/schema/draft06.rb +123 -5
- data/lib/jsi/schema/draft07.rb +157 -5
- data/lib/jsi/schema/draft202012.rb +303 -0
- data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
- data/lib/jsi/schema/element.rb +69 -0
- data/lib/jsi/schema/elements/anchor.rb +13 -0
- data/lib/jsi/schema/elements/array_validation.rb +82 -0
- data/lib/jsi/schema/elements/comment.rb +10 -0
- data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
- data/lib/jsi/schema/elements/contains.rb +59 -0
- data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
- data/lib/jsi/schema/elements/content_encoding.rb +10 -0
- data/lib/jsi/schema/elements/content_media_type.rb +10 -0
- data/lib/jsi/schema/elements/content_schema.rb +16 -0
- data/lib/jsi/schema/elements/default.rb +11 -0
- data/lib/jsi/schema/elements/definitions.rb +19 -0
- data/lib/jsi/schema/elements/dependencies.rb +99 -0
- data/lib/jsi/schema/elements/dependent_required.rb +49 -0
- data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
- data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
- data/lib/jsi/schema/elements/enum.rb +26 -0
- data/lib/jsi/schema/elements/examples.rb +10 -0
- data/lib/jsi/schema/elements/format.rb +10 -0
- data/lib/jsi/schema/elements/id.rb +30 -0
- data/lib/jsi/schema/elements/if_then_else.rb +82 -0
- data/lib/jsi/schema/elements/info_bool.rb +10 -0
- data/lib/jsi/schema/elements/info_string.rb +10 -0
- data/lib/jsi/schema/elements/items.rb +93 -0
- data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
- data/lib/jsi/schema/elements/not.rb +31 -0
- data/lib/jsi/schema/elements/numeric.rb +137 -0
- data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
- data/lib/jsi/schema/elements/object_validation.rb +55 -0
- data/lib/jsi/schema/elements/pattern.rb +35 -0
- data/lib/jsi/schema/elements/properties.rb +145 -0
- data/lib/jsi/schema/elements/property_names.rb +48 -0
- data/lib/jsi/schema/elements/ref.rb +62 -0
- data/lib/jsi/schema/elements/required.rb +34 -0
- data/lib/jsi/schema/elements/self.rb +24 -0
- data/lib/jsi/schema/elements/some_of.rb +180 -0
- data/lib/jsi/schema/elements/string_validation.rb +57 -0
- data/lib/jsi/schema/elements/type.rb +43 -0
- data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
- data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
- data/lib/jsi/schema/elements/xschema.rb +10 -0
- data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
- data/lib/jsi/schema/elements.rb +101 -0
- data/lib/jsi/schema/issue.rb +3 -4
- data/lib/jsi/schema/schema_ancestor_node.rb +105 -52
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +598 -383
- data/lib/jsi/schema_classes.rb +195 -141
- data/lib/jsi/schema_set.rb +85 -128
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +14 -17
- data/lib/jsi/struct.rb +57 -0
- data/lib/jsi/uri.rb +40 -0
- data/lib/jsi/util/private/memo_map.rb +9 -13
- data/lib/jsi/util/private.rb +59 -31
- data/lib/jsi/util/typelike.rb +19 -60
- data/lib/jsi/util.rb +53 -34
- data/lib/jsi/validation/error.rb +45 -2
- data/lib/jsi/validation/result.rb +121 -90
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +170 -36
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +62 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +60 -109
- data/lib/schemas/json-schema.org/draft-06/schema.rb +53 -108
- data/lib/schemas/json-schema.org/draft-07/schema.rb +63 -127
- data/readme.rb +4 -4
- data/{resources}/schemas/2020-12_strict.json +19 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
- metadata +73 -52
- data/lib/jsi/metaschema.rb +0 -6
- data/lib/jsi/schema/application/child_application/contains.rb +0 -25
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
- data/lib/jsi/schema/application/child_application/items.rb +0 -18
- data/lib/jsi/schema/application/child_application/properties.rb +0 -25
- data/lib/jsi/schema/application/child_application.rb +0 -13
- data/lib/jsi/schema/application/draft04.rb +0 -8
- data/lib/jsi/schema/application/draft06.rb +0 -8
- data/lib/jsi/schema/application/draft07.rb +0 -8
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
- data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
- data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
- data/lib/jsi/schema/application/inplace_application.rb +0 -14
- data/lib/jsi/schema/application.rb +0 -12
- data/lib/jsi/schema/ref.rb +0 -183
- data/lib/jsi/schema/validation/array.rb +0 -69
- data/lib/jsi/schema/validation/contains.rb +0 -25
- data/lib/jsi/schema/validation/dependencies.rb +0 -49
- data/lib/jsi/schema/validation/draft04/minmax.rb +0 -91
- data/lib/jsi/schema/validation/draft04.rb +0 -110
- data/lib/jsi/schema/validation/draft06.rb +0 -120
- data/lib/jsi/schema/validation/draft07.rb +0 -157
- data/lib/jsi/schema/validation/enum.rb +0 -25
- data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
- data/lib/jsi/schema/validation/items.rb +0 -54
- data/lib/jsi/schema/validation/not.rb +0 -20
- data/lib/jsi/schema/validation/numeric.rb +0 -121
- data/lib/jsi/schema/validation/object.rb +0 -45
- data/lib/jsi/schema/validation/pattern.rb +0 -34
- data/lib/jsi/schema/validation/properties.rb +0 -101
- data/lib/jsi/schema/validation/property_names.rb +0 -32
- data/lib/jsi/schema/validation/ref.rb +0 -40
- data/lib/jsi/schema/validation/required.rb +0 -27
- data/lib/jsi/schema/validation/someof.rb +0 -90
- data/lib/jsi/schema/validation/string.rb +0 -47
- data/lib/jsi/schema/validation/type.rb +0 -49
- data/lib/jsi/schema/validation.rb +0 -49
- data/lib/jsi/schema_registry.rb +0 -190
- data/lib/jsi/util/private/attr_struct.rb +0 -130
|
@@ -3,36 +3,21 @@
|
|
|
3
3
|
module JSI
|
|
4
4
|
module Validation
|
|
5
5
|
# a result of validating an instance against schemas which describe it.
|
|
6
|
-
# virtual base class.
|
|
7
6
|
class Result
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Builder = Util::AttrStruct[*%w(
|
|
7
|
+
Builder = Schema::Cxt.subclass(*%i(
|
|
11
8
|
result
|
|
12
|
-
schema
|
|
13
9
|
instance_ptr
|
|
14
10
|
instance_document
|
|
15
11
|
validate_only
|
|
16
12
|
visited_refs
|
|
17
|
-
)
|
|
13
|
+
))
|
|
18
14
|
|
|
19
15
|
# @private
|
|
20
|
-
#
|
|
21
|
-
class Builder
|
|
16
|
+
# context to build a Validation::Result
|
|
17
|
+
class Builder < Schema::Cxt
|
|
22
18
|
def instance
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def schema_issue(*_)
|
|
27
|
-
virtual_method
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def schema_error(message, keyword = nil)
|
|
31
|
-
schema_issue(:error, message, keyword)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def schema_warning(message, keyword = nil)
|
|
35
|
-
schema_issue(:warning, message, keyword)
|
|
19
|
+
return @instance if instance_variable_defined?(:@instance)
|
|
20
|
+
@instance = instance_ptr.evaluate(instance_document)
|
|
36
21
|
end
|
|
37
22
|
|
|
38
23
|
# @param subschema_ptr [JSI::Ptr, #to_ary]
|
|
@@ -44,7 +29,6 @@ module JSI
|
|
|
44
29
|
validate_only: validate_only,
|
|
45
30
|
visited_refs: visited_refs,
|
|
46
31
|
)
|
|
47
|
-
merge_schema_issues(subresult)
|
|
48
32
|
subresult
|
|
49
33
|
end
|
|
50
34
|
|
|
@@ -57,107 +41,133 @@ module JSI
|
|
|
57
41
|
instance_document,
|
|
58
42
|
validate_only: validate_only,
|
|
59
43
|
)
|
|
60
|
-
merge_schema_issues(subresult)
|
|
61
44
|
subresult
|
|
62
45
|
end
|
|
63
46
|
|
|
64
|
-
# @param
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# schema_issues are always merged from subschema results (not depending on validation results)
|
|
69
|
-
result.schema_issues.merge(other_result.schema_issues)
|
|
47
|
+
# @param results [Enumerable<Validation::Result>]
|
|
48
|
+
def inplace_results_validate(*a, results: , **kw)
|
|
49
|
+
results.select(&:valid?).each do |inplace_result|
|
|
50
|
+
result.evaluated_tokens.merge(inplace_result.evaluated_tokens)
|
|
70
51
|
end
|
|
71
|
-
|
|
52
|
+
validate(*a, **kw,
|
|
53
|
+
results: results,
|
|
54
|
+
)
|
|
72
55
|
end
|
|
73
|
-
end
|
|
74
56
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
result
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
visited_refs: visited_refs,
|
|
83
|
-
)
|
|
57
|
+
# @param child_results [Hash<Object, Validation::Result>] token => child result
|
|
58
|
+
def child_results_validate(*a, child_results: , **kw)
|
|
59
|
+
result.evaluated_tokens.merge(child_results.each_key.select { |t| child_results[t].valid? })
|
|
60
|
+
validate(*a, **kw,
|
|
61
|
+
results: child_results.each_value,
|
|
62
|
+
)
|
|
63
|
+
end
|
|
84
64
|
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class Result
|
|
68
|
+
include(Util::Pretty)
|
|
85
69
|
|
|
86
70
|
# is the instance valid against its schemas?
|
|
87
71
|
# @return [Boolean]
|
|
88
72
|
def valid?
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
#chkbug raise(NotImplementedError)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @raise [JSI::Invalid]
|
|
77
|
+
# @return [nil]
|
|
78
|
+
def valid!
|
|
79
|
+
raise(JSI::Invalid, self) if !valid?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def pretty_print(q)
|
|
83
|
+
pretty_print_valid(q)
|
|
92
84
|
end
|
|
93
85
|
|
|
94
86
|
include Util::FingerprintHash
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def pretty_print_valid(q, &block)
|
|
91
|
+
jsi_pp_object_group(q, [self.class.name, valid? ? "(VALID)" : "(INVALID)"].freeze, &block)
|
|
92
|
+
end
|
|
95
93
|
end
|
|
96
94
|
|
|
97
95
|
# a full result of validating an instance against its schemas, with each validation error
|
|
98
|
-
class
|
|
96
|
+
class Result::Full < Result
|
|
99
97
|
# @private
|
|
100
98
|
class Builder < Result::Builder
|
|
101
99
|
def validate(
|
|
102
100
|
valid,
|
|
103
|
-
|
|
101
|
+
message_key,
|
|
102
|
+
message_default,
|
|
104
103
|
keyword: nil,
|
|
105
|
-
results:
|
|
104
|
+
results: Util::EMPTY_ARY,
|
|
105
|
+
**additional
|
|
106
106
|
)
|
|
107
|
-
results.each { |res| result.schema_issues.merge(res.schema_issues) }
|
|
108
107
|
if !valid
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
message: message,
|
|
108
|
+
result.nested_validation_errors << Validation::Error.new({
|
|
109
|
+
message: JSI.t(message_key, default: message_default, **additional),
|
|
112
110
|
keyword: keyword,
|
|
111
|
+
additional: additional,
|
|
113
112
|
schema: schema,
|
|
114
113
|
instance_ptr: instance_ptr,
|
|
115
114
|
instance_document: instance_document,
|
|
115
|
+
nested_errors: results.map(&:nested_validation_errors).inject(Set[], &:merge).freeze,
|
|
116
116
|
})
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
119
121
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
class Result::Full
|
|
123
|
+
def initialize
|
|
124
|
+
@nested_validation_errors = Set.new
|
|
125
|
+
@evaluated_tokens = Set.new
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @return [Set<Validation::Error>]
|
|
129
|
+
attr_reader(:nested_validation_errors)
|
|
130
|
+
|
|
131
|
+
# @yield [Validation::Error]
|
|
132
|
+
def each_validation_error(&block)
|
|
133
|
+
return(to_enum(__method__)) if !block_given?
|
|
134
|
+
nested_validation_errors.each do |validation_error|
|
|
135
|
+
validation_error.each_validation_error(&block)
|
|
127
136
|
end
|
|
137
|
+
nil
|
|
128
138
|
end
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
# @deprecated after v0.8
|
|
141
|
+
# iterating (recursively) is better done with #each_validation_error
|
|
142
|
+
def validation_errors
|
|
143
|
+
each_validation_error.to_set
|
|
133
144
|
end
|
|
134
145
|
|
|
135
|
-
|
|
136
|
-
attr_reader
|
|
146
|
+
# @return [Set]
|
|
147
|
+
attr_reader(:evaluated_tokens)
|
|
137
148
|
|
|
138
149
|
def valid?
|
|
139
|
-
|
|
150
|
+
nested_validation_errors.empty?
|
|
140
151
|
end
|
|
141
152
|
|
|
142
153
|
def freeze
|
|
143
|
-
@
|
|
144
|
-
@
|
|
145
|
-
@validation_errors.freeze
|
|
146
|
-
@schema_issues.freeze
|
|
154
|
+
@nested_validation_errors.freeze
|
|
155
|
+
@evaluated_tokens.freeze
|
|
147
156
|
super
|
|
148
157
|
end
|
|
149
158
|
|
|
150
159
|
def merge(result)
|
|
151
|
-
unless result.is_a?(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
validation_errors.merge(result.validation_errors)
|
|
155
|
-
schema_issues.merge(result.schema_issues)
|
|
160
|
+
raise(TypeError, "not a #{Result::Full}: #{result.pretty_inspect.chomp}") unless result.is_a?(Result::Full)
|
|
161
|
+
nested_validation_errors.merge(result.nested_validation_errors)
|
|
162
|
+
evaluated_tokens.merge(result.evaluated_tokens)
|
|
156
163
|
self
|
|
157
164
|
end
|
|
158
165
|
|
|
159
|
-
def
|
|
160
|
-
|
|
166
|
+
def pretty_print(q)
|
|
167
|
+
pretty_print_valid(q) do
|
|
168
|
+
q.text('validation errors: ')
|
|
169
|
+
q.pp(nested_validation_errors)
|
|
170
|
+
end
|
|
161
171
|
end
|
|
162
172
|
|
|
163
173
|
# see {Util::Private::FingerprintHash}
|
|
@@ -165,38 +175,46 @@ module JSI
|
|
|
165
175
|
def jsi_fingerprint
|
|
166
176
|
{
|
|
167
177
|
class: self.class,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
178
|
+
nested_validation_errors: nested_validation_errors,
|
|
179
|
+
evaluated_tokens: evaluated_tokens,
|
|
180
|
+
}.freeze
|
|
171
181
|
end
|
|
172
182
|
end
|
|
173
183
|
|
|
174
|
-
#
|
|
175
|
-
class
|
|
184
|
+
# A result indicating validation success of an instance against a schema
|
|
185
|
+
class Result::Valid < Result
|
|
176
186
|
# @private
|
|
177
187
|
class Builder < Result::Builder
|
|
178
188
|
def validate(
|
|
179
189
|
valid,
|
|
180
|
-
|
|
190
|
+
message_key,
|
|
191
|
+
message_default,
|
|
181
192
|
keyword: nil,
|
|
182
|
-
results:
|
|
193
|
+
results: Util::EMPTY_ARY,
|
|
194
|
+
**additional
|
|
183
195
|
)
|
|
184
196
|
if !valid
|
|
185
197
|
throw(:jsi_validation_result, INVALID)
|
|
186
198
|
end
|
|
187
199
|
end
|
|
188
|
-
|
|
189
|
-
def schema_issue(*_)
|
|
190
|
-
# noop
|
|
191
|
-
end
|
|
192
200
|
end
|
|
201
|
+
end
|
|
193
202
|
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
class Result::Valid
|
|
204
|
+
def initialize
|
|
205
|
+
@evaluated_tokens = Set.new
|
|
196
206
|
end
|
|
197
207
|
|
|
208
|
+
# @return [Set]
|
|
209
|
+
attr_reader(:evaluated_tokens)
|
|
210
|
+
|
|
198
211
|
def valid?
|
|
199
|
-
|
|
212
|
+
true
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def freeze
|
|
216
|
+
@evaluated_tokens.freeze
|
|
217
|
+
super
|
|
200
218
|
end
|
|
201
219
|
|
|
202
220
|
# see {Util::Private::FingerprintHash}
|
|
@@ -204,8 +222,21 @@ module JSI
|
|
|
204
222
|
def jsi_fingerprint
|
|
205
223
|
{
|
|
206
224
|
class: self.class,
|
|
207
|
-
|
|
208
|
-
}
|
|
225
|
+
evaluated_tokens: evaluated_tokens,
|
|
226
|
+
}.freeze
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# A result indicating validation failure of an instance against a schema
|
|
231
|
+
class Result::Invalid < Result
|
|
232
|
+
def valid?
|
|
233
|
+
false
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# see {Util::Private::FingerprintHash}
|
|
237
|
+
# @api private
|
|
238
|
+
def jsi_fingerprint
|
|
239
|
+
self.class
|
|
209
240
|
end
|
|
210
241
|
end
|
|
211
242
|
end
|
data/lib/jsi/validation.rb
CHANGED
|
@@ -3,13 +3,8 @@
|
|
|
3
3
|
module JSI
|
|
4
4
|
module Validation
|
|
5
5
|
autoload :Error, 'jsi/validation/error'
|
|
6
|
-
|
|
7
6
|
autoload :Result, 'jsi/validation/result'
|
|
8
|
-
autoload :FullResult, 'jsi/validation/result'
|
|
9
|
-
autoload :ValidityResult, 'jsi/validation/result'
|
|
10
|
-
|
|
11
|
-
VALID = ValidityResult.new(true).freeze
|
|
12
7
|
|
|
13
|
-
INVALID =
|
|
8
|
+
INVALID = Result::Invalid.new.freeze
|
|
14
9
|
end
|
|
15
10
|
end
|
data/lib/jsi/version.rb
CHANGED
data/lib/jsi.rb
CHANGED
|
@@ -8,18 +8,61 @@ require "pathname"
|
|
|
8
8
|
require "bigdecimal"
|
|
9
9
|
require "addressable/uri"
|
|
10
10
|
|
|
11
|
-
module JSI
|
|
11
|
+
module JSI::Error
|
|
12
12
|
# generally put in code paths that are not expected to be valid control flow paths.
|
|
13
13
|
# rather a NotImplementedCorrectlyError. but that's too long.
|
|
14
14
|
#
|
|
15
15
|
# if you've found this class because JSI has raised this error, please open an issue with the backtrace
|
|
16
16
|
# and any context you can provide at https://github.com/notEthan/jsi/issues
|
|
17
17
|
class Bug < NotImplementedError
|
|
18
|
+
# implementation note: use `fail` with Bug instead of `raise` to avoid
|
|
19
|
+
# YARD's ExceptionHandler adding an inferred `@raise` tag for it.
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
# @private TODO remove, any ruby without this is already long EOL
|
|
21
23
|
FrozenError = Object.const_defined?(:FrozenError) ? ::FrozenError : Class.new(StandardError)
|
|
22
24
|
|
|
25
|
+
class BlockGivenError < ArgumentError
|
|
26
|
+
def initialize(msg = "Block given to a method that does not yield", *)
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# A reference or pointer cannot be resolved
|
|
32
|
+
class ResolutionError < StandardError
|
|
33
|
+
# @param msg [String, Array]
|
|
34
|
+
# @param uri [URI, nil]
|
|
35
|
+
def initialize(msg = nil, *a, uri: nil)
|
|
36
|
+
super([*msg].compact.join("\n"), *a)
|
|
37
|
+
@uri = JSI::Util.uri(uri, nnil: false)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [URI, nil]
|
|
41
|
+
attr_accessor(:uri)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# A URI does not meet some requirement where it is used - absent
|
|
45
|
+
# when it's required, relative when it must be absolute, etc.
|
|
46
|
+
class URIError < Addressable::URI::InvalidURIError
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# A schema instance is not valid against schemas that describe it
|
|
50
|
+
class Invalid < StandardError
|
|
51
|
+
# @param result [Validation::Result]
|
|
52
|
+
def initialize(result, *a, &b)
|
|
53
|
+
@result = result
|
|
54
|
+
super(result.pretty_inspect.chomp, *a, &b)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
attr_reader(:result)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module JSI
|
|
62
|
+
include(Error)
|
|
63
|
+
# include(Error) doesn't make its constants available in nested namespaces; fix
|
|
64
|
+
Error.constants.each { |n| const_set(n, const_get(n)) }
|
|
65
|
+
|
|
23
66
|
# @private
|
|
24
67
|
ROOT_PATH = Pathname.new(__FILE__).dirname.parent.expand_path
|
|
25
68
|
|
|
@@ -29,77 +72,168 @@ module JSI
|
|
|
29
72
|
# @private
|
|
30
73
|
SCHEMAS_PATH = RESOURCES_PATH.join('schemas')
|
|
31
74
|
|
|
75
|
+
DEFAULT_CONTENT_TO_IMMUTABLE = proc do |content|
|
|
76
|
+
Util.deep_to_frozen(content, not_implemented: proc do |instance|
|
|
77
|
+
raise(ArgumentError, [
|
|
78
|
+
"JSI does not know how to make the given instance immutable.",
|
|
79
|
+
"See new_jsi / new_schema `mutable` param and `to_immutable` configuration documentation for options.",
|
|
80
|
+
"https://www.rubydoc.info/gems/jsi/#{VERSION}/JSI/SchemaSet#new_jsi-instance_method",
|
|
81
|
+
"Given instance: #{instance.pretty_inspect.chomp}",
|
|
82
|
+
].join("\n"))
|
|
83
|
+
end)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
autoload(:URI, 'jsi/uri')
|
|
32
87
|
autoload :Util, 'jsi/util'
|
|
88
|
+
autoload(:Set, 'jsi/set')
|
|
89
|
+
autoload(:Struct, 'jsi/struct')
|
|
33
90
|
autoload :Ptr, 'jsi/ptr'
|
|
34
91
|
autoload :Schema, 'jsi/schema'
|
|
35
92
|
autoload :SchemaSet, 'jsi/schema_set'
|
|
36
93
|
autoload :Base, 'jsi/base'
|
|
37
|
-
autoload
|
|
38
|
-
autoload :MetaschemaNode, 'jsi/metaschema_node'
|
|
94
|
+
autoload(:MetaSchemaNode, 'jsi/metaschema_node')
|
|
39
95
|
autoload :SchemaModule, 'jsi/schema_classes'
|
|
40
96
|
autoload :SchemaClasses, 'jsi/schema_classes'
|
|
41
|
-
autoload
|
|
97
|
+
autoload(:Registry, 'jsi/registry')
|
|
98
|
+
autoload(:SchemaRegistry, 'jsi/registry')
|
|
99
|
+
autoload(:Ref, 'jsi/ref')
|
|
42
100
|
autoload :Validation, 'jsi/validation'
|
|
43
101
|
autoload :JSICoder, 'jsi/jsi_coder'
|
|
44
102
|
|
|
45
103
|
autoload :JSONSchemaDraft04, 'schemas/json-schema.org/draft-04/schema'
|
|
46
104
|
autoload :JSONSchemaDraft06, 'schemas/json-schema.org/draft-06/schema'
|
|
47
105
|
autoload :JSONSchemaDraft07, 'schemas/json-schema.org/draft-07/schema'
|
|
48
|
-
autoload
|
|
49
|
-
autoload :JSONSchemaOrgDraft06, 'schemas/json-schema.org/draft-06/schema'
|
|
50
|
-
autoload :JSONSchemaOrgDraft07, 'schemas/json-schema.org/draft-07/schema'
|
|
106
|
+
autoload(:JSONSchemaDraft202012, 'schemas/json-schema.org/draft/2020-12/schema')
|
|
51
107
|
|
|
52
108
|
autoload :SimpleWrap, 'jsi/simple_wrap'
|
|
53
109
|
|
|
54
110
|
# Instantiates the given schema content as a JSI Schema, passing all params to
|
|
55
111
|
# {JSI.new_schema}, and returns its {Schema#jsi_schema_module JSI Schema Module}.
|
|
56
112
|
#
|
|
57
|
-
# @
|
|
113
|
+
# @yield (see Schema::MetaSchema#new_schema_module)
|
|
114
|
+
# @return (see JSI::Schema::MetaSchema#new_schema_module)
|
|
58
115
|
def self.new_schema_module(schema_content, **kw, &block)
|
|
59
|
-
new_schema(schema_content, **kw
|
|
116
|
+
schema_jsi = new_schema(schema_content, **kw)
|
|
117
|
+
schema_jsi.jsi_schema_module_exec(&block) if block
|
|
118
|
+
schema_jsi.jsi_schema_module
|
|
60
119
|
end
|
|
61
120
|
|
|
62
|
-
# Instantiates the given
|
|
121
|
+
# Instantiates the given metaschema_document as a MetaSchemaNode.
|
|
63
122
|
#
|
|
64
|
-
# @
|
|
65
|
-
# @param
|
|
66
|
-
# @
|
|
67
|
-
|
|
68
|
-
|
|
123
|
+
# @api private
|
|
124
|
+
# @param metaschema_document
|
|
125
|
+
# @param conf_kw Passed to initialize a {MetaSchemaNode::Conf} for {Base#jsi_conf}.
|
|
126
|
+
# @return [MetaSchemaNode]
|
|
127
|
+
def self.new_metaschema_node(metaschema_document,
|
|
128
|
+
schema_documents: nil,
|
|
129
|
+
**conf_kw
|
|
69
130
|
)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
)
|
|
131
|
+
raise(BlockGivenError) if block_given?
|
|
132
|
+
|
|
133
|
+
conf = MetaSchemaNode::Conf.new(**conf_kw)
|
|
134
|
+
|
|
135
|
+
# need the metaschema_document root to be registered in the bootstrap_registry if...
|
|
136
|
+
register_bootstrap_metaschema =
|
|
137
|
+
# the root is a schema
|
|
138
|
+
conf.root_schema_ref == conf.metaschema_root_ref &&
|
|
139
|
+
# and the metaschema ref is not fragment-only
|
|
140
|
+
!conf.metaschema_root_ref.merge(fragment: nil).empty? &&
|
|
141
|
+
# and it's not already registered (I don't know that an externally supplied bootstrap_registry
|
|
142
|
+
# would ever need to register the meta-schema differently than this does, but allow for it)
|
|
143
|
+
(!conf.bootstrap_registry || !conf.bootstrap_registry.registered?(conf.metaschema_root_ref.merge(fragment: nil)))
|
|
144
|
+
|
|
145
|
+
if !conf.bootstrap_registry && (register_bootstrap_metaschema || schema_documents)
|
|
146
|
+
conf = conf.merge(bootstrap_registry: Registry.new)
|
|
147
|
+
end
|
|
148
|
+
if !conf.registry && (register_bootstrap_metaschema || schema_documents)
|
|
149
|
+
conf = conf.merge(registry: Registry.new)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
metaschema_document = conf.to_immutable.call(metaschema_document) if conf.to_immutable
|
|
153
|
+
schema_documents = schema_documents.map(&conf.to_immutable) if schema_documents && conf.to_immutable
|
|
154
|
+
|
|
155
|
+
to_register = []
|
|
156
|
+
to_register.concat(schema_documents) if schema_documents
|
|
157
|
+
to_register.push(metaschema_document) if register_bootstrap_metaschema
|
|
158
|
+
to_register.each do |document|
|
|
159
|
+
conf.bootstrap_registry.register_immediate(conf.dialect.bootstrap_schema(
|
|
160
|
+
jsi_document: document,
|
|
161
|
+
jsi_registry: conf.bootstrap_registry,
|
|
162
|
+
))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
MetaSchemaNode.new(
|
|
166
|
+
jsi_document: metaschema_document,
|
|
167
|
+
jsi_conf: conf,
|
|
168
|
+
).jsi_initialize_finish
|
|
73
169
|
end
|
|
74
170
|
|
|
75
|
-
#
|
|
76
|
-
#
|
|
171
|
+
# `JSI.registry` is the default {JSI::Registry} in which schemas are registered and from
|
|
172
|
+
# which they resolve references.
|
|
77
173
|
#
|
|
78
|
-
# @return [
|
|
79
|
-
def self.
|
|
80
|
-
|
|
174
|
+
# @return [Registry]
|
|
175
|
+
def self.registry
|
|
176
|
+
@registry
|
|
81
177
|
end
|
|
82
178
|
|
|
83
|
-
#
|
|
84
|
-
# which they resolve references.
|
|
85
|
-
#
|
|
86
|
-
# @return [JSI::SchemaRegistry]
|
|
179
|
+
# @deprecated after v0.8
|
|
87
180
|
def self.schema_registry
|
|
88
|
-
@
|
|
181
|
+
@registry
|
|
89
182
|
end
|
|
90
183
|
|
|
91
|
-
# @param
|
|
92
|
-
def self.
|
|
93
|
-
@
|
|
184
|
+
# @param registry [Registry]
|
|
185
|
+
def self.registry=(registry)
|
|
186
|
+
@registry = registry
|
|
94
187
|
end
|
|
95
188
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
189
|
+
DEFAULT_REGISTRY = Registry.new.tap do |registry|
|
|
190
|
+
registry.autoload_uri("http://json-schema.org/draft-04/schema") { JSI::JSONSchemaDraft04.schema }
|
|
191
|
+
registry.autoload_uri("http://json-schema.org/draft-06/schema") { JSI::JSONSchemaDraft06.schema }
|
|
192
|
+
registry.autoload_uri("http://json-schema.org/draft-07/schema") { JSI::JSONSchemaDraft07.schema }
|
|
193
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/schema") { JSI::JSONSchemaDraft202012.schema }
|
|
194
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/core") { JSI::JSONSchemaDraft202012::Core.schema }
|
|
195
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/applicator") { JSI::JSONSchemaDraft202012::Applicator.schema }
|
|
196
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/unevaluated") { JSI::JSONSchemaDraft202012::Unevaluated.schema }
|
|
197
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/validation") { JSI::JSONSchemaDraft202012::Validation.schema }
|
|
198
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/meta-data") { JSI::JSONSchemaDraft202012::MetaData.schema }
|
|
199
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/format-annotation") { JSI::JSONSchemaDraft202012::FormatAnnotation.schema }
|
|
200
|
+
registry.autoload_uri("https://json-schema.org/draft/2020-12/meta/content") { JSI::JSONSchemaDraft202012::Content.schema }
|
|
201
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/core") { JSI::Schema::Draft202012::Vocab::CORE }
|
|
202
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/unevaluated") { JSI::Schema::Draft202012::Vocab::UNEVALUATED }
|
|
203
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/format-annotation") { JSI::Schema::Draft202012::Vocab::FORMAT_ANNOTATION }
|
|
204
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/validation") { JSI::Schema::Draft202012::Vocab::VALIDATION }
|
|
205
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/content") { JSI::Schema::Draft202012::Vocab::CONTENT }
|
|
206
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/applicator") { JSI::Schema::Draft202012::Vocab::APPLICATOR }
|
|
207
|
+
registry.autoload_vocabulary_uri("https://json-schema.org/draft/2020-12/vocab/meta-data") { JSI::Schema::Draft202012::Vocab::METADATA }
|
|
208
|
+
registry.autoload_dialect_uri("http://json-schema.org/draft-04/schema") { Schema::Draft04::DIALECT }
|
|
209
|
+
registry.autoload_dialect_uri("http://json-schema.org/draft-06/schema") { Schema::Draft06::DIALECT }
|
|
210
|
+
registry.autoload_dialect_uri("http://json-schema.org/draft-07/schema") { Schema::Draft07::DIALECT }
|
|
211
|
+
registry.autoload_dialect_uri("https://json-schema.org/draft/2020-12/schema") { Schema::Draft202012::DIALECT }
|
|
100
212
|
end.freeze
|
|
101
213
|
|
|
102
|
-
self.
|
|
214
|
+
self.registry = DEFAULT_REGISTRY.dup
|
|
215
|
+
|
|
216
|
+
# translation
|
|
217
|
+
# @param key [String]
|
|
218
|
+
# @param default [String]
|
|
219
|
+
# @return [String]
|
|
220
|
+
def self.t(key, default: , **options)
|
|
221
|
+
translator.call(key, default: default, **options)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @return [#call]
|
|
225
|
+
def self.translator
|
|
226
|
+
@translator
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# e.g. `JSI.translator = I18n.method(:translate)`
|
|
230
|
+
# @param translator [#call]
|
|
231
|
+
def self.translator=(translator)
|
|
232
|
+
@translator = translator
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
DEFAULT_TRANSLATOR = proc { |_key, default: , **_| default }
|
|
236
|
+
self.translator = DEFAULT_TRANSLATOR
|
|
103
237
|
|
|
104
238
|
Schema # trigger autoload, ensure JSI methods (new_schema etc) defined in schema.rb load
|
|
105
239
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
path = SCHEMAS_PATH.join('json-schema.org/draft/2020-12')
|
|
5
|
+
metaschema_document = Util.json_parse_freeze(path.join('schema.json').read)
|
|
6
|
+
vocabulary_schema_documents = metaschema_document['allOf'].map do |schema|
|
|
7
|
+
Util.json_parse_freeze(path.join(schema['$ref'] + '.json').read)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
JSONSchemaDraft202012 = JSI.new_metaschema_node(metaschema_document,
|
|
11
|
+
dialect: Schema::Draft202012::DIALECT,
|
|
12
|
+
metaschema_root_ref: 'https://json-schema.org/draft/2020-12/schema',
|
|
13
|
+
schema_documents: vocabulary_schema_documents,
|
|
14
|
+
).jsi_schema_module
|
|
15
|
+
|
|
16
|
+
module JSONSchemaDraft202012
|
|
17
|
+
# @!parse extend JSI::SchemaModule::MetaSchemaModule
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def self.name_vocab_schemas(metaschema_module, namespace: metaschema_module)
|
|
21
|
+
find_module = proc { |uri| metaschema_module.schema.jsi_registry.find(uri).with_dynamic_scope_from(metaschema_module).jsi_schema_module }
|
|
22
|
+
namespace.const_set(:Core, find_module["https://json-schema.org/draft/2020-12/meta/core"])
|
|
23
|
+
namespace.const_set(:Applicator, find_module["https://json-schema.org/draft/2020-12/meta/applicator"])
|
|
24
|
+
namespace.const_set(:Unevaluated, find_module["https://json-schema.org/draft/2020-12/meta/unevaluated"])
|
|
25
|
+
namespace.const_set(:Validation, find_module["https://json-schema.org/draft/2020-12/meta/validation"])
|
|
26
|
+
namespace.const_set(:MetaData, find_module["https://json-schema.org/draft/2020-12/meta/meta-data"])
|
|
27
|
+
namespace.const_set(:FormatAnnotation, find_module["https://json-schema.org/draft/2020-12/meta/format-annotation"])
|
|
28
|
+
namespace.const_set(:Content, find_module["https://json-schema.org/draft/2020-12/meta/content"])
|
|
29
|
+
metaschema_module
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
name_vocab_schemas(self)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module JSONSchemaDraft202012::Core
|
|
36
|
+
end
|
|
37
|
+
module JSONSchemaDraft202012::Applicator
|
|
38
|
+
end
|
|
39
|
+
module JSONSchemaDraft202012::Unevaluated
|
|
40
|
+
end
|
|
41
|
+
module JSONSchemaDraft202012::Validation
|
|
42
|
+
end
|
|
43
|
+
module JSONSchemaDraft202012::MetaData
|
|
44
|
+
end
|
|
45
|
+
module JSONSchemaDraft202012::FormatAnnotation
|
|
46
|
+
end
|
|
47
|
+
module JSONSchemaDraft202012::Content
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module JSONSchemaDraft202012
|
|
51
|
+
# `$defs` property reader
|
|
52
|
+
# @return [Base + JSONSchemaDraft202012::Defs, nil]
|
|
53
|
+
def defs
|
|
54
|
+
self['$defs']
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def jsi_schema_module_connection_created(mod)
|
|
58
|
+
mod.define_singleton_method(:defs) { |**kw| self['$defs', **kw] }
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|