jsi 0.7.0 → 0.8.0

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -1
  3. data/CHANGELOG.md +15 -0
  4. data/README.md +19 -18
  5. data/jsi.gemspec +2 -3
  6. data/lib/jsi/base/mutability.rb +44 -0
  7. data/lib/jsi/base/node.rb +199 -34
  8. data/lib/jsi/base.rb +412 -228
  9. data/lib/jsi/jsi_coder.rb +18 -16
  10. data/lib/jsi/metaschema_node/bootstrap_schema.rb +57 -23
  11. data/lib/jsi/metaschema_node.rb +138 -107
  12. data/lib/jsi/ptr.rb +59 -37
  13. data/lib/jsi/schema/application/child_application/draft04.rb +0 -1
  14. data/lib/jsi/schema/application/child_application/draft06.rb +0 -1
  15. data/lib/jsi/schema/application/child_application/draft07.rb +0 -1
  16. data/lib/jsi/schema/application/child_application.rb +0 -25
  17. data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -1
  18. data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -1
  19. data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -1
  20. data/lib/jsi/schema/application/inplace_application/ref.rb +1 -1
  21. data/lib/jsi/schema/application/inplace_application/someof.rb +1 -1
  22. data/lib/jsi/schema/application/inplace_application.rb +0 -27
  23. data/lib/jsi/schema/draft04.rb +0 -1
  24. data/lib/jsi/schema/draft06.rb +0 -1
  25. data/lib/jsi/schema/draft07.rb +0 -1
  26. data/lib/jsi/schema/ref.rb +44 -18
  27. data/lib/jsi/schema/schema_ancestor_node.rb +65 -56
  28. data/lib/jsi/schema/validation/contains.rb +1 -1
  29. data/lib/jsi/schema/validation/draft04/minmax.rb +2 -0
  30. data/lib/jsi/schema/validation/draft04.rb +0 -2
  31. data/lib/jsi/schema/validation/draft06.rb +0 -2
  32. data/lib/jsi/schema/validation/draft07.rb +0 -2
  33. data/lib/jsi/schema/validation/items.rb +3 -3
  34. data/lib/jsi/schema/validation/pattern.rb +1 -1
  35. data/lib/jsi/schema/validation/properties.rb +4 -4
  36. data/lib/jsi/schema/validation/ref.rb +1 -1
  37. data/lib/jsi/schema/validation.rb +0 -2
  38. data/lib/jsi/schema.rb +405 -194
  39. data/lib/jsi/schema_classes.rb +196 -127
  40. data/lib/jsi/schema_registry.rb +66 -17
  41. data/lib/jsi/schema_set.rb +76 -30
  42. data/lib/jsi/simple_wrap.rb +2 -7
  43. data/lib/jsi/util/private/attr_struct.rb +28 -14
  44. data/lib/jsi/util/private/memo_map.rb +75 -0
  45. data/lib/jsi/util/private.rb +73 -92
  46. data/lib/jsi/util/typelike.rb +28 -28
  47. data/lib/jsi/util.rb +120 -36
  48. data/lib/jsi/validation/error.rb +4 -0
  49. data/lib/jsi/validation/result.rb +18 -32
  50. data/lib/jsi/version.rb +1 -1
  51. data/lib/jsi.rb +67 -25
  52. data/lib/schemas/json-schema.org/draft-04/schema.rb +159 -4
  53. data/lib/schemas/json-schema.org/draft-06/schema.rb +161 -4
  54. data/lib/schemas/json-schema.org/draft-07/schema.rb +188 -4
  55. metadata +19 -5
  56. data/lib/jsi/metaschema.rb +0 -6
  57. data/lib/jsi/schema/validation/core.rb +0 -39
@@ -4,9 +4,21 @@ module JSI
4
4
  # a node in a document which may contain a schema somewhere within is extended with SchemaAncestorNode, for
5
5
  # tracking things necessary for a schema to function correctly
6
6
  module Schema::SchemaAncestorNode
7
+ if Util::LAST_ARGUMENT_AS_KEYWORD_PARAMETERS
8
+ def initialize(*)
9
+ super
10
+ jsi_schema_ancestor_node_initialize
11
+ end
12
+ else
13
+ def initialize(*, **)
14
+ super
15
+ jsi_schema_ancestor_node_initialize
16
+ end
17
+ end
18
+
7
19
  # the base URI used to resolve the ids of schemas at or below this JSI.
8
20
  # this is always an absolute URI (with no fragment).
9
- # this may be the absolute schema URI of a parent schema or the URI from which the document was retrieved.
21
+ # This may be the absolute schema URI of an ancestor schema or the URI from which the document was retrieved.
10
22
  # @api private
11
23
  # @return [Addressable::URI, nil]
12
24
  attr_reader :jsi_schema_base_uri
@@ -14,25 +26,27 @@ module JSI
14
26
  # resources which are ancestors of this JSI in the document. this does not include self.
15
27
  # @api private
16
28
  # @return [Array<JSI::Schema>]
17
- def jsi_schema_resource_ancestors
18
- return @jsi_schema_resource_ancestors if instance_variable_defined?(:@jsi_schema_resource_ancestors)
19
- Util::EMPTY_ARY
20
- end
29
+ attr_reader :jsi_schema_resource_ancestors
30
+
31
+ # See {SchemaSet#new_jsi} param `schema_registry`
32
+ # @return [SchemaRegistry]
33
+ attr_reader(:jsi_schema_registry)
21
34
 
22
35
  # the URI of the resource containing this node.
23
36
  # this is always an absolute URI (with no fragment).
24
- # if this node is a schema with an id, this is its absolute URI; otherwise a parent resource's URI,
37
+ # If this node is a schema with an id, this is its absolute URI; otherwise an ancestor resource's URI,
25
38
  # or nil if not contained by a resource with a URI.
26
39
  # @return [Addressable::URI, nil]
27
40
  def jsi_resource_ancestor_uri
28
41
  (is_a?(Schema) && schema_absolute_uri) || jsi_schema_base_uri
29
42
  end
30
43
 
31
- # a schema at or below this node with the given anchor.
44
+ # The schema at or below this node with the given anchor.
45
+ # If no schema has that anchor (or multiple schemas do, incorrectly), nil.
32
46
  #
33
47
  # @return [JSI::Schema, nil]
34
48
  def jsi_anchor_subschema(anchor)
35
- subschemas = jsi_anchor_subschemas_map[anchor: anchor]
49
+ subschemas = @anchor_subschemas_map[anchor: anchor]
36
50
  if subschemas.size == 1
37
51
  subschemas.first
38
52
  else
@@ -40,74 +54,69 @@ module JSI
40
54
  end
41
55
  end
42
56
 
43
- # schemas at or below node with the given anchor.
57
+ # All schemas at or below this node with the given anchor.
44
58
  #
45
- # @return [Array<JSI::Schema>]
59
+ # @return [Set<JSI::Schema>]
46
60
  def jsi_anchor_subschemas(anchor)
47
- jsi_anchor_subschemas_map[anchor: anchor]
61
+ @anchor_subschemas_map[anchor: anchor]
48
62
  end
49
63
 
50
64
  private
51
65
 
52
- def jsi_document=(jsi_document)
53
- @jsi_document = jsi_document
66
+ def jsi_schema_ancestor_node_initialize
67
+ @anchor_subschemas_map = jsi_memomap(&method(:jsi_anchor_subschemas_compute))
54
68
  end
55
69
 
70
+ attr_writer :jsi_document
71
+
56
72
  def jsi_ptr=(jsi_ptr)
57
- raise(Bug, "jsi_ptr not #{Ptr}: #{jsi_ptr.inspect}") unless jsi_ptr.is_a?(Ptr)
73
+ #chkbug raise(Bug, "jsi_ptr not #{Ptr}: #{jsi_ptr}") unless jsi_ptr.is_a?(Ptr)
58
74
  @jsi_ptr = jsi_ptr
59
75
  end
60
76
 
61
77
  def jsi_schema_base_uri=(jsi_schema_base_uri)
62
- if jsi_schema_base_uri
63
- unless jsi_schema_base_uri.respond_to?(:to_str)
64
- raise(TypeError, "jsi_schema_base_uri must be string or Addressable::URI; got: #{jsi_schema_base_uri.inspect}")
65
- end
66
- @jsi_schema_base_uri = Addressable::URI.parse(jsi_schema_base_uri).freeze
67
- unless @jsi_schema_base_uri.absolute? && !@jsi_schema_base_uri.fragment
68
- raise(ArgumentError, "jsi_schema_base_uri must be an absolute URI with no fragment; got: #{jsi_schema_base_uri.inspect}")
69
- end
70
- else
71
- @jsi_schema_base_uri = nil
72
- end
78
+ #chkbug raise(Bug) if jsi_schema_base_uri && !jsi_schema_base_uri.is_a?(Addressable::URI)
79
+ #chkbug raise(Bug) if jsi_schema_base_uri && !jsi_schema_base_uri.absolute?
80
+ #chkbug raise(Bug) if jsi_schema_base_uri && jsi_schema_base_uri.fragment
81
+
82
+ @jsi_schema_base_uri = jsi_schema_base_uri
73
83
  end
74
84
 
75
85
  def jsi_schema_resource_ancestors=(jsi_schema_resource_ancestors)
76
- if jsi_schema_resource_ancestors
77
- unless jsi_schema_resource_ancestors.respond_to?(:to_ary)
78
- raise(TypeError, "jsi_schema_resource_ancestors must be an array; got: #{jsi_schema_resource_ancestors.inspect}")
79
- end
80
- jsi_schema_resource_ancestors.each { |a| Schema.ensure_schema(a) }
81
- # sanity check the ancestors are in order
82
- last_anc_ptr = nil
83
- jsi_schema_resource_ancestors.each do |anc|
84
- if last_anc_ptr.nil?
85
- # pass
86
- elsif last_anc_ptr == anc.jsi_ptr
87
- raise(Bug, "duplicate ancestors in #{jsi_schema_resource_ancestors.pretty_inspect}")
88
- elsif !last_anc_ptr.contains?(anc.jsi_ptr)
89
- raise(Bug, "ancestor ptr #{anc.jsi_ptr} not contained by previous: #{last_anc_ptr} in #{jsi_schema_resource_ancestors.pretty_inspect}")
90
- end
91
- if anc.jsi_ptr == jsi_ptr
92
- raise(Bug, "ancestor is self")
93
- elsif !anc.jsi_ptr.contains?(jsi_ptr)
94
- raise(Bug, "ancestor does not contain self")
95
- end
96
- last_anc_ptr = anc.jsi_ptr
97
- end
98
-
99
- @jsi_schema_resource_ancestors = jsi_schema_resource_ancestors.to_ary.freeze
100
- else
101
- @jsi_schema_resource_ancestors = Util::EMPTY_ARY
102
- end
86
+ #chkbug raise(Bug) unless jsi_schema_resource_ancestors.respond_to?(:to_ary)
87
+ #chkbug jsi_schema_resource_ancestors.each { |a| Schema.ensure_schema(a) }
88
+ #chkbug # sanity check the ancestors are in order
89
+ #chkbug last_anc_ptr = nil
90
+ #chkbug jsi_schema_resource_ancestors.each do |anc|
91
+ #chkbug if last_anc_ptr.nil?
92
+ #chkbug # pass
93
+ #chkbug elsif last_anc_ptr == anc.jsi_ptr
94
+ #chkbug raise(Bug, "duplicate ancestors in #{jsi_schema_resource_ancestors.pretty_inspect}")
95
+ #chkbug elsif !last_anc_ptr.contains?(anc.jsi_ptr)
96
+ #chkbug raise(Bug, "ancestor ptr #{anc.jsi_ptr} not contained by previous: #{last_anc_ptr} in #{jsi_schema_resource_ancestors.pretty_inspect}")
97
+ #chkbug end
98
+ #chkbug if anc.jsi_ptr == jsi_ptr
99
+ #chkbug raise(Bug, "ancestor is self")
100
+ #chkbug elsif !anc.jsi_ptr.ancestor_of?(jsi_ptr)
101
+ #chkbug raise(Bug, "ancestor does not contain self")
102
+ #chkbug end
103
+ #chkbug last_anc_ptr = anc.jsi_ptr
104
+ #chkbug end
105
+
106
+ @jsi_schema_resource_ancestors = jsi_schema_resource_ancestors
103
107
  end
104
108
 
105
- def jsi_anchor_subschemas_map
106
- jsi_memomap(__method__) do |anchor: |
109
+ attr_writer(:jsi_schema_registry)
110
+
111
+ def jsi_anchor_subschemas_compute(anchor: )
107
112
  jsi_each_descendent_node.select do |node|
108
113
  node.is_a?(Schema) && node.respond_to?(:anchor) && node.anchor == anchor
109
- end.freeze
110
- end
114
+ end.to_set.freeze
115
+ end
116
+
117
+ # @return [Util::MemoMap]
118
+ def jsi_memomap(**options, &block)
119
+ jsi_memomap_class.new(**options, &block)
111
120
  end
112
121
  end
113
122
  end
@@ -10,7 +10,7 @@ module JSI
10
10
  if result_builder.instance.respond_to?(:to_ary)
11
11
  results = {}
12
12
  result_builder.instance.each_index do |i|
13
- results[i] = result_builder.child_subschema_validate(['contains'], [i])
13
+ results[i] = result_builder.child_subschema_validate(i, ['contains'])
14
14
  end
15
15
  result_builder.validate(
16
16
  results.values.any?(&:valid?),
@@ -10,6 +10,7 @@ module JSI
10
10
  unless [true, false].include?(value)
11
11
  result_builder.schema_error('`exclusiveMaximum` is not true or false', 'exclusiveMaximum')
12
12
  end
13
+ #> If "exclusiveMaximum" is present, "maximum" MUST also be present.
13
14
  if !keyword?('maximum')
14
15
  result_builder.schema_error('`exclusiveMaximum` has no effect without adjacent `maximum` keyword', 'exclusiveMaximum')
15
16
  end
@@ -53,6 +54,7 @@ module JSI
53
54
  unless [true, false].include?(value)
54
55
  result_builder.schema_error('`exclusiveMinimum` is not true or false', 'exclusiveMinimum')
55
56
  end
57
+ #> If "exclusiveMinimum" is present, "minimum" MUST also be present.
56
58
  if !keyword?('minimum')
57
59
  result_builder.schema_error('`exclusiveMinimum` has no effect without adjacent `minimum` keyword', 'exclusiveMinimum')
58
60
  end
@@ -4,8 +4,6 @@ module JSI
4
4
  module Schema::Validation::Draft04
5
5
  autoload :MinMax, 'jsi/schema/validation/draft04/minmax'
6
6
 
7
- include Schema::Validation::Core
8
-
9
7
  include Schema::Validation::Ref
10
8
 
11
9
  include Schema::Validation::MultipleOf
@@ -2,8 +2,6 @@
2
2
 
3
3
  module JSI
4
4
  module Schema::Validation::Draft06
5
- include Schema::Validation::Core
6
-
7
5
  include Schema::Validation::Ref
8
6
  include Schema::Validation::AllOf
9
7
  include Schema::Validation::AnyOf
@@ -2,8 +2,6 @@
2
2
 
3
3
  module JSI
4
4
  module Schema::Validation::Draft07
5
- include Schema::Validation::Core
6
-
7
5
  include Schema::Validation::Ref
8
6
 
9
7
  include Schema::Validation::Type
@@ -14,9 +14,9 @@ module JSI
14
14
  results = {}
15
15
  result_builder.instance.each_index do |i|
16
16
  if i < value.size
17
- results[i] = result_builder.child_subschema_validate(['items', i], [i])
17
+ results[i] = result_builder.child_subschema_validate(i, ['items', i])
18
18
  elsif keyword?('additionalItems')
19
- results[i] = result_builder.child_subschema_validate(['additionalItems'], [i])
19
+ results[i] = result_builder.child_subschema_validate(i, ['additionalItems'])
20
20
  end
21
21
  end
22
22
  result_builder.validate(
@@ -31,7 +31,7 @@ module JSI
31
31
  # against that schema.
32
32
  if result_builder.instance.respond_to?(:to_ary)
33
33
  results = result_builder.instance.each_index.map do |i|
34
- result_builder.child_subschema_validate(['items'], [i])
34
+ result_builder.child_subschema_validate(i, ['items'])
35
35
  end
36
36
  result_builder.validate(
37
37
  results.all?(&:valid?),
@@ -22,7 +22,7 @@ module JSI
22
22
  keyword: 'pattern',
23
23
  )
24
24
  rescue RegexpError => e
25
- result_builder.schema_error("`pattern` is not a valid regular expression: #{e.message}", 'pattern')
25
+ result_builder.schema_error(-"`pattern` is not a valid regular expression: #{e.message}", 'pattern')
26
26
  end
27
27
  end
28
28
  else
@@ -19,8 +19,8 @@ module JSI
19
19
  if value.key?(property_name)
20
20
  evaluated_property_names << property_name
21
21
  results[property_name] = result_builder.child_subschema_validate(
22
+ property_name,
22
23
  ['properties', property_name],
23
- [property_name],
24
24
  )
25
25
  end
26
26
  end
@@ -54,8 +54,8 @@ module JSI
54
54
  if value_property_pattern.respond_to?(:to_str) && Regexp.new(value_property_pattern).match(property_name.to_s)
55
55
  evaluated_property_names << property_name
56
56
  results[property_name] = result_builder.child_subschema_validate(
57
+ property_name,
57
58
  ['patternProperties', value_property_pattern],
58
- [property_name],
59
59
  )
60
60
  end
61
61
  rescue ::RegexpError
@@ -83,11 +83,11 @@ module JSI
83
83
  result_builder.instance.keys.each do |property_name|
84
84
  if !evaluated_property_names.include?(property_name)
85
85
  results[property_name] = result_builder.child_subschema_validate(
86
+ property_name,
86
87
  ['additionalProperties'],
87
- [property_name],
88
88
  )
89
89
  end
90
- end.compact
90
+ end
91
91
  result_builder.validate(
92
92
  results.values.all?(&:valid?),
93
93
  'instance object additional properties are not all valid against `additionalProperties` schema value',
@@ -10,7 +10,7 @@ module JSI
10
10
  value = schema_content['$ref']
11
11
 
12
12
  if value.respond_to?(:to_str)
13
- schema_ref = jsi_memoize(:ref) { Schema::Ref.new(value, self) }
13
+ schema_ref = self.schema_ref('$ref')
14
14
 
15
15
  if result_builder.visited_refs.include?(schema_ref)
16
16
  result_builder.schema_error('self-referential schema structure', '$ref')
@@ -2,8 +2,6 @@
2
2
 
3
3
  module JSI
4
4
  module Schema::Validation
5
- autoload :Core, 'jsi/schema/validation/core'
6
-
7
5
  autoload :Draft04, 'jsi/schema/validation/draft04'
8
6
  autoload :Draft06, 'jsi/schema/validation/draft06'
9
7
  autoload :Draft07, 'jsi/schema/validation/draft07'