jsi 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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'