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.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -4
  3. data/CHANGELOG.md +19 -0
  4. data/LICENSE.md +2 -3
  5. data/README.md +87 -43
  6. data/docs/{glossary.md → Glossary.md} +84 -52
  7. data/jsi.gemspec +1 -1
  8. data/lib/jsi/base/mutability.rb +48 -0
  9. data/lib/jsi/base/node.rb +66 -52
  10. data/lib/jsi/base.rb +592 -176
  11. data/lib/jsi/jsi_coder.rb +4 -2
  12. data/lib/jsi/metaschema_node/bootstrap_schema.rb +118 -59
  13. data/lib/jsi/metaschema_node.rb +244 -154
  14. data/lib/jsi/ptr.rb +45 -17
  15. data/lib/jsi/ref.rb +197 -0
  16. data/lib/jsi/registry.rb +311 -0
  17. data/lib/jsi/schema/cxt/child_application.rb +35 -0
  18. data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
  19. data/lib/jsi/schema/cxt.rb +80 -0
  20. data/lib/jsi/schema/dialect.rb +137 -0
  21. data/lib/jsi/schema/draft04.rb +113 -5
  22. data/lib/jsi/schema/draft06.rb +123 -5
  23. data/lib/jsi/schema/draft07.rb +157 -5
  24. data/lib/jsi/schema/draft202012.rb +303 -0
  25. data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
  26. data/lib/jsi/schema/element.rb +69 -0
  27. data/lib/jsi/schema/elements/anchor.rb +13 -0
  28. data/lib/jsi/schema/elements/array_validation.rb +82 -0
  29. data/lib/jsi/schema/elements/comment.rb +10 -0
  30. data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
  31. data/lib/jsi/schema/elements/contains.rb +59 -0
  32. data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
  33. data/lib/jsi/schema/elements/content_encoding.rb +10 -0
  34. data/lib/jsi/schema/elements/content_media_type.rb +10 -0
  35. data/lib/jsi/schema/elements/content_schema.rb +16 -0
  36. data/lib/jsi/schema/elements/default.rb +11 -0
  37. data/lib/jsi/schema/elements/definitions.rb +19 -0
  38. data/lib/jsi/schema/elements/dependencies.rb +99 -0
  39. data/lib/jsi/schema/elements/dependent_required.rb +49 -0
  40. data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
  41. data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
  42. data/lib/jsi/schema/elements/enum.rb +26 -0
  43. data/lib/jsi/schema/elements/examples.rb +10 -0
  44. data/lib/jsi/schema/elements/format.rb +10 -0
  45. data/lib/jsi/schema/elements/id.rb +30 -0
  46. data/lib/jsi/schema/elements/if_then_else.rb +82 -0
  47. data/lib/jsi/schema/elements/info_bool.rb +10 -0
  48. data/lib/jsi/schema/elements/info_string.rb +10 -0
  49. data/lib/jsi/schema/elements/items.rb +93 -0
  50. data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
  51. data/lib/jsi/schema/elements/not.rb +31 -0
  52. data/lib/jsi/schema/elements/numeric.rb +137 -0
  53. data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
  54. data/lib/jsi/schema/elements/object_validation.rb +55 -0
  55. data/lib/jsi/schema/elements/pattern.rb +35 -0
  56. data/lib/jsi/schema/elements/properties.rb +145 -0
  57. data/lib/jsi/schema/elements/property_names.rb +48 -0
  58. data/lib/jsi/schema/elements/ref.rb +62 -0
  59. data/lib/jsi/schema/elements/required.rb +34 -0
  60. data/lib/jsi/schema/elements/self.rb +24 -0
  61. data/lib/jsi/schema/elements/some_of.rb +180 -0
  62. data/lib/jsi/schema/elements/string_validation.rb +57 -0
  63. data/lib/jsi/schema/elements/type.rb +43 -0
  64. data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
  65. data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
  66. data/lib/jsi/schema/elements/xschema.rb +10 -0
  67. data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
  68. data/lib/jsi/schema/elements.rb +101 -0
  69. data/lib/jsi/schema/issue.rb +3 -4
  70. data/lib/jsi/schema/schema_ancestor_node.rb +105 -52
  71. data/lib/jsi/schema/vocabulary.rb +36 -0
  72. data/lib/jsi/schema.rb +598 -383
  73. data/lib/jsi/schema_classes.rb +195 -141
  74. data/lib/jsi/schema_set.rb +85 -128
  75. data/lib/jsi/set.rb +23 -0
  76. data/lib/jsi/simple_wrap.rb +14 -17
  77. data/lib/jsi/struct.rb +57 -0
  78. data/lib/jsi/uri.rb +40 -0
  79. data/lib/jsi/util/private/memo_map.rb +9 -13
  80. data/lib/jsi/util/private.rb +59 -31
  81. data/lib/jsi/util/typelike.rb +19 -60
  82. data/lib/jsi/util.rb +53 -34
  83. data/lib/jsi/validation/error.rb +45 -2
  84. data/lib/jsi/validation/result.rb +121 -90
  85. data/lib/jsi/validation.rb +1 -6
  86. data/lib/jsi/version.rb +1 -1
  87. data/lib/jsi.rb +170 -36
  88. data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +62 -0
  89. data/lib/schemas/json-schema.org/draft-04/schema.rb +60 -109
  90. data/lib/schemas/json-schema.org/draft-06/schema.rb +53 -108
  91. data/lib/schemas/json-schema.org/draft-07/schema.rb +63 -127
  92. data/readme.rb +4 -4
  93. data/{resources}/schemas/2020-12_strict.json +19 -0
  94. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
  95. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
  96. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
  97. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
  98. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
  99. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
  100. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
  101. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
  102. data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
  103. metadata +73 -52
  104. data/lib/jsi/metaschema.rb +0 -6
  105. data/lib/jsi/schema/application/child_application/contains.rb +0 -25
  106. data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
  107. data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
  108. data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
  109. data/lib/jsi/schema/application/child_application/items.rb +0 -18
  110. data/lib/jsi/schema/application/child_application/properties.rb +0 -25
  111. data/lib/jsi/schema/application/child_application.rb +0 -13
  112. data/lib/jsi/schema/application/draft04.rb +0 -8
  113. data/lib/jsi/schema/application/draft06.rb +0 -8
  114. data/lib/jsi/schema/application/draft07.rb +0 -8
  115. data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
  116. data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
  117. data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
  118. data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
  119. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
  120. data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
  121. data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
  122. data/lib/jsi/schema/application/inplace_application.rb +0 -14
  123. data/lib/jsi/schema/application.rb +0 -12
  124. data/lib/jsi/schema/ref.rb +0 -183
  125. data/lib/jsi/schema/validation/array.rb +0 -69
  126. data/lib/jsi/schema/validation/contains.rb +0 -25
  127. data/lib/jsi/schema/validation/dependencies.rb +0 -49
  128. data/lib/jsi/schema/validation/draft04/minmax.rb +0 -91
  129. data/lib/jsi/schema/validation/draft04.rb +0 -110
  130. data/lib/jsi/schema/validation/draft06.rb +0 -120
  131. data/lib/jsi/schema/validation/draft07.rb +0 -157
  132. data/lib/jsi/schema/validation/enum.rb +0 -25
  133. data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
  134. data/lib/jsi/schema/validation/items.rb +0 -54
  135. data/lib/jsi/schema/validation/not.rb +0 -20
  136. data/lib/jsi/schema/validation/numeric.rb +0 -121
  137. data/lib/jsi/schema/validation/object.rb +0 -45
  138. data/lib/jsi/schema/validation/pattern.rb +0 -34
  139. data/lib/jsi/schema/validation/properties.rb +0 -101
  140. data/lib/jsi/schema/validation/property_names.rb +0 -32
  141. data/lib/jsi/schema/validation/ref.rb +0 -40
  142. data/lib/jsi/schema/validation/required.rb +0 -27
  143. data/lib/jsi/schema/validation/someof.rb +0 -90
  144. data/lib/jsi/schema/validation/string.rb +0 -47
  145. data/lib/jsi/schema/validation/type.rb +0 -49
  146. data/lib/jsi/schema/validation.rb +0 -49
  147. data/lib/jsi/schema_registry.rb +0 -190
  148. 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
- include Util::Virtual
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
- # a structure used to build a Result. virtual base class.
21
- class Builder
16
+ # context to build a Validation::Result
17
+ class Builder < Schema::Cxt
22
18
  def instance
23
- instance_ptr.evaluate(instance_document)
24
- end
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 other_result [JSI::Validation::Result]
65
- # @return [void]
66
- def merge_schema_issues(other_result)
67
- unless validate_only
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
- nil
52
+ validate(*a, **kw,
53
+ results: results,
54
+ )
72
55
  end
73
- end
74
56
 
75
- def builder(schema, instance_ptr, instance_document, validate_only, visited_refs)
76
- self.class::Builder.new(
77
- result: self,
78
- schema: schema,
79
- instance_ptr: instance_ptr,
80
- instance_document: instance_document,
81
- validate_only: validate_only,
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
- # :nocov:
90
- virtual_method
91
- # :nocov:
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 FullResult < Result
96
+ class Result::Full < Result
99
97
  # @private
100
98
  class Builder < Result::Builder
101
99
  def validate(
102
100
  valid,
103
- message,
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
- results.each { |res| result.validation_errors.merge(res.validation_errors) }
110
- result.validation_errors << Validation::Error.new({
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
- def schema_issue(level, message, keyword = nil)
121
- result.schema_issues << Schema::Issue.new({
122
- level: level,
123
- message: message,
124
- keyword: keyword,
125
- schema: schema,
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
- def initialize
131
- @validation_errors = Set.new
132
- @schema_issues = Set.new
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
- attr_reader :validation_errors
136
- attr_reader :schema_issues
146
+ # @return [Set]
147
+ attr_reader(:evaluated_tokens)
137
148
 
138
149
  def valid?
139
- validation_errors.empty?
150
+ nested_validation_errors.empty?
140
151
  end
141
152
 
142
153
  def freeze
143
- @validation_errors.each(&:freeze)
144
- @schema_issues.each(&:freeze)
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?(FullResult)
152
- raise(TypeError, "not a #{FullResult.name}: #{result.pretty_inspect.chomp}")
153
- end
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 +(result)
160
- FullResult.new.merge(self).merge(result)
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
- validation_errors: validation_errors,
169
- schema_issues: schema_issues,
170
- }
178
+ nested_validation_errors: nested_validation_errors,
179
+ evaluated_tokens: evaluated_tokens,
180
+ }.freeze
171
181
  end
172
182
  end
173
183
 
174
- # a result indicating only whether an instance is valid against its schemas
175
- class ValidityResult < Result
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
- message,
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
- def initialize(valid)
195
- @valid = valid
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
- @valid
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
- valid: valid?,
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
@@ -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 = ValidityResult.new(false).freeze
8
+ INVALID = Result::Invalid.new.freeze
14
9
  end
15
10
  end
data/lib/jsi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSI
4
- VERSION = "0.0.8".freeze
4
+ VERSION = "0.0.9".freeze
5
5
  end
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 :Metaschema, 'jsi/metaschema'
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 :SchemaRegistry, 'jsi/schema_registry'
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 :JSONSchemaOrgDraft04, 'schemas/json-schema.org/draft-04/schema'
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
- # @return (see JSI::Schema::DescribesSchema#new_schema_module)
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, &block).jsi_schema_module
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 document as a JSI Metaschema.
121
+ # Instantiates the given metaschema_document as a MetaSchemaNode.
63
122
  #
64
- # @param metaschema_document an object to be instantiated as a JSI Metaschema
65
- # @param schema_implementation_modules (see MetaschemaNode#initialize)
66
- # @return [JSI::MetaschemaNode + JSI::DescribesSchema + JSI::Schema]
67
- def self.new_metaschema(metaschema_document,
68
- schema_implementation_modules:
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
- MetaschemaNode.new(metaschema_document,
71
- schema_implementation_modules: schema_implementation_modules,
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
- # Instantiates the given document as a JSI Metaschema, passing all params to
76
- # {new_metaschema}, and returns its {Schema#jsi_schema_module JSI Schema Module}.
171
+ # `JSI.registry` is the default {JSI::Registry} in which schemas are registered and from
172
+ # which they resolve references.
77
173
  #
78
- # @return [Module + JSI::SchemaModule::DescribesSchemaModule + JSI::SchemaModule]
79
- def self.new_metaschema_module(metaschema_document, **kw)
80
- new_metaschema(metaschema_document, **kw).jsi_schema_module
174
+ # @return [Registry]
175
+ def self.registry
176
+ @registry
81
177
  end
82
178
 
83
- # `JSI.schema_registry` is the default {JSI::SchemaRegistry} in which schemas are registered and from
84
- # which they resolve references.
85
- #
86
- # @return [JSI::SchemaRegistry]
179
+ # @deprecated after v0.8
87
180
  def self.schema_registry
88
- @schema_registry
181
+ @registry
89
182
  end
90
183
 
91
- # @param schema_registry [JSI::SchemaRegistry]
92
- def self.schema_registry=(schema_registry)
93
- @schema_registry = schema_registry
184
+ # @param registry [Registry]
185
+ def self.registry=(registry)
186
+ @registry = registry
94
187
  end
95
188
 
96
- DEFAULT_SCHEMA_REGISTRY = SchemaRegistry.new.tap do |schema_registry|
97
- schema_registry.autoload_uri("http://json-schema.org/draft-04/schema") { JSI::JSONSchemaDraft04.schema }
98
- schema_registry.autoload_uri("http://json-schema.org/draft-06/schema") { JSI::JSONSchemaDraft06.schema }
99
- schema_registry.autoload_uri("http://json-schema.org/draft-07/schema") { JSI::JSONSchemaDraft07.schema }
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.schema_registry = DEFAULT_SCHEMA_REGISTRY.dup
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