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.
- checksums.yaml +4 -4
- data/.yardopts +6 -1
- data/CHANGELOG.md +15 -0
- data/README.md +19 -18
- data/jsi.gemspec +2 -3
- data/lib/jsi/base/mutability.rb +44 -0
- data/lib/jsi/base/node.rb +199 -34
- data/lib/jsi/base.rb +412 -228
- data/lib/jsi/jsi_coder.rb +18 -16
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +57 -23
- data/lib/jsi/metaschema_node.rb +138 -107
- data/lib/jsi/ptr.rb +59 -37
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -1
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -1
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -1
- data/lib/jsi/schema/application/child_application.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -1
- data/lib/jsi/schema/application/inplace_application/ref.rb +1 -1
- data/lib/jsi/schema/application/inplace_application/someof.rb +1 -1
- data/lib/jsi/schema/application/inplace_application.rb +0 -27
- data/lib/jsi/schema/draft04.rb +0 -1
- data/lib/jsi/schema/draft06.rb +0 -1
- data/lib/jsi/schema/draft07.rb +0 -1
- data/lib/jsi/schema/ref.rb +44 -18
- data/lib/jsi/schema/schema_ancestor_node.rb +65 -56
- data/lib/jsi/schema/validation/contains.rb +1 -1
- data/lib/jsi/schema/validation/draft04/minmax.rb +2 -0
- data/lib/jsi/schema/validation/draft04.rb +0 -2
- data/lib/jsi/schema/validation/draft06.rb +0 -2
- data/lib/jsi/schema/validation/draft07.rb +0 -2
- data/lib/jsi/schema/validation/items.rb +3 -3
- data/lib/jsi/schema/validation/pattern.rb +1 -1
- data/lib/jsi/schema/validation/properties.rb +4 -4
- data/lib/jsi/schema/validation/ref.rb +1 -1
- data/lib/jsi/schema/validation.rb +0 -2
- data/lib/jsi/schema.rb +405 -194
- data/lib/jsi/schema_classes.rb +196 -127
- data/lib/jsi/schema_registry.rb +66 -17
- data/lib/jsi/schema_set.rb +76 -30
- data/lib/jsi/simple_wrap.rb +2 -7
- data/lib/jsi/util/private/attr_struct.rb +28 -14
- data/lib/jsi/util/private/memo_map.rb +75 -0
- data/lib/jsi/util/private.rb +73 -92
- data/lib/jsi/util/typelike.rb +28 -28
- data/lib/jsi/util.rb +120 -36
- data/lib/jsi/validation/error.rb +4 -0
- data/lib/jsi/validation/result.rb +18 -32
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +67 -25
- data/lib/schemas/json-schema.org/draft-04/schema.rb +159 -4
- data/lib/schemas/json-schema.org/draft-06/schema.rb +161 -4
- data/lib/schemas/json-schema.org/draft-07/schema.rb +188 -4
- metadata +19 -5
- data/lib/jsi/metaschema.rb +0 -6
- 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
|
-
#
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
#
|
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
|
-
#
|
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 =
|
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 [
|
59
|
+
# @return [Set<JSI::Schema>]
|
46
60
|
def jsi_anchor_subschemas(anchor)
|
47
|
-
|
61
|
+
@anchor_subschemas_map[anchor: anchor]
|
48
62
|
end
|
49
63
|
|
50
64
|
private
|
51
65
|
|
52
|
-
def
|
53
|
-
@
|
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
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
106
|
-
|
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
|
-
|
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']
|
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
|
@@ -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]
|
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']
|
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']
|
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
|
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 =
|
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')
|