json_schema 0.0.14 → 0.0.15
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.
@@ -7,42 +7,20 @@ module JsonSchema
|
|
7
7
|
# reference to the top-level schema before doing anything else.
|
8
8
|
class DocumentStore
|
9
9
|
def initialize
|
10
|
-
@
|
11
|
-
end
|
12
|
-
|
13
|
-
def add_pointer_reference(uri, path, schema)
|
14
|
-
raise "can't add nil URI" if uri.nil?
|
15
|
-
|
16
|
-
if !@uri_map[uri][:pointer_map].key?(path)
|
17
|
-
@uri_map[uri][:pointer_map][path] = schema
|
18
|
-
end
|
10
|
+
@schema_map = {}
|
19
11
|
end
|
20
12
|
|
21
13
|
def add_uri_reference(uri, schema)
|
22
14
|
raise "can't add nil URI" if uri.nil?
|
23
|
-
|
24
|
-
# Children without an ID keep the same URI as their parents. So since we
|
25
|
-
# traverse trees from top to bottom, just keep the first reference.
|
26
|
-
if !@uri_map.key?(uri)
|
27
|
-
@uri_map[uri] = {
|
28
|
-
pointer_map: {
|
29
|
-
JsonReference.reference("#").to_s => schema
|
30
|
-
},
|
31
|
-
schema: schema
|
32
|
-
}
|
33
|
-
end
|
15
|
+
@schema_map[uri] = schema
|
34
16
|
end
|
35
17
|
|
36
|
-
def
|
37
|
-
@
|
18
|
+
def each
|
19
|
+
@schema_map.each { |k, v| yield(k, v) }
|
38
20
|
end
|
39
21
|
|
40
22
|
def lookup_uri(uri)
|
41
|
-
|
42
|
-
@uri_map[uri][:schema]
|
43
|
-
else
|
44
|
-
nil
|
45
|
-
end
|
23
|
+
@schema_map[uri]
|
46
24
|
end
|
47
25
|
end
|
48
26
|
end
|
data/lib/json_schema/parser.rb
CHANGED
@@ -3,13 +3,22 @@ require "set"
|
|
3
3
|
module JsonSchema
|
4
4
|
class ReferenceExpander
|
5
5
|
attr_accessor :errors
|
6
|
+
attr_accessor :store
|
6
7
|
|
7
8
|
def expand(schema, options = {})
|
8
|
-
@errors
|
9
|
-
@
|
10
|
-
@
|
9
|
+
@errors = []
|
10
|
+
@local_store = DocumentStore.new
|
11
|
+
@schema = schema
|
12
|
+
@schema_paths = {}
|
13
|
+
@store = options[:store] || DocumentStore.new
|
14
|
+
@uri = URI.parse(schema.uri)
|
15
|
+
|
16
|
+
@store.each do |uri, store_schema|
|
17
|
+
build_schema_paths(uri, store_schema)
|
18
|
+
end
|
11
19
|
|
12
|
-
|
20
|
+
# we run #to_s on lookup for URIs; the #to_s of nil is ""
|
21
|
+
build_schema_paths("", schema)
|
13
22
|
|
14
23
|
traverse_schema(schema)
|
15
24
|
|
@@ -31,6 +40,34 @@ module JsonSchema
|
|
31
40
|
|
32
41
|
private
|
33
42
|
|
43
|
+
def add_reference(schema)
|
44
|
+
uri = URI.parse(schema.uri)
|
45
|
+
if uri.absolute?
|
46
|
+
@store.add_uri_reference(schema.uri, schema)
|
47
|
+
else
|
48
|
+
@local_store.add_uri_reference(schema.uri, schema)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_schema_paths(uri, schema)
|
53
|
+
return if schema.reference
|
54
|
+
|
55
|
+
paths = @schema_paths[uri] ||= {}
|
56
|
+
paths[schema.pointer] = schema
|
57
|
+
|
58
|
+
schema_children(schema).each do |subschema|
|
59
|
+
build_schema_paths(uri, subschema)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Also insert alternate tree for schema's custom URI. O(crazy).
|
63
|
+
if schema.uri != uri
|
64
|
+
fragment, parent = schema.fragment, schema.parent
|
65
|
+
schema.fragment, schema.parent = "#", nil
|
66
|
+
build_schema_paths(schema.uri, schema)
|
67
|
+
schema.fragment, schema.parent = fragment, parent
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
34
71
|
def dereference(ref_schema, ref_stack)
|
35
72
|
ref = ref_schema.reference
|
36
73
|
|
@@ -69,11 +106,23 @@ module JsonSchema
|
|
69
106
|
true
|
70
107
|
end
|
71
108
|
|
72
|
-
def
|
109
|
+
def lookup_pointer(uri, pointer)
|
110
|
+
paths = @schema_paths[uri.to_s] ||= {}
|
111
|
+
paths[pointer]
|
112
|
+
end
|
113
|
+
|
114
|
+
def lookup_reference(uri)
|
115
|
+
if uri.absolute?
|
116
|
+
@store.lookup_uri(uri.to_s)
|
117
|
+
else
|
118
|
+
@local_store.lookup_uri(uri.to_s)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def resolve_pointer(ref_schema, resolved_schema)
|
73
123
|
ref = ref_schema.reference
|
74
124
|
|
75
|
-
|
76
|
-
if !(new_schema = @store.lookup_pointer(uri_path, ref.pointer.to_s))
|
125
|
+
if !(new_schema = lookup_pointer(ref.uri, ref.pointer))
|
77
126
|
data = JsonPointer.evaluate(resolved_schema.data, ref.pointer)
|
78
127
|
|
79
128
|
# couldn't resolve pointer within known schema; that's an error
|
@@ -83,18 +132,17 @@ module JsonSchema
|
|
83
132
|
return
|
84
133
|
end
|
85
134
|
|
86
|
-
#
|
135
|
+
# Parse a new schema and use the same parent node. Basically this is
|
136
|
+
# exclusively for the case of a reference that needs to be
|
137
|
+
# de-referenced again to be resolved.
|
138
|
+
# TODO: Fix to never parse.
|
87
139
|
new_schema = Parser.new.parse(data, ref_schema.parent)
|
88
|
-
|
89
|
-
# add the reference into our document store right away; it will
|
90
|
-
# eventually be fully expanded
|
91
|
-
@store.add_pointer_reference(uri_path, ref.pointer.to_s, new_schema)
|
140
|
+
build_schema_paths(ref.uri, resolved_schema)
|
92
141
|
else
|
93
142
|
# insert a clone record so that the expander knows to expand it when
|
94
143
|
# the schema traversal is finished
|
95
144
|
new_schema.clones << ref_schema
|
96
145
|
end
|
97
|
-
|
98
146
|
new_schema
|
99
147
|
end
|
100
148
|
|
@@ -107,7 +155,7 @@ module JsonSchema
|
|
107
155
|
# allow resolution if something we've already parsed has claimed the
|
108
156
|
# full URL
|
109
157
|
if @store.lookup_uri(uri.to_s)
|
110
|
-
resolve_uri(ref_schema, uri
|
158
|
+
resolve_uri(ref_schema, uri)
|
111
159
|
else
|
112
160
|
message =
|
113
161
|
%{Reference resolution over #{scheme} is not currently supported.}
|
@@ -116,23 +164,24 @@ module JsonSchema
|
|
116
164
|
end
|
117
165
|
# absolute
|
118
166
|
elsif uri && uri.path[0] == "/"
|
119
|
-
resolve_uri(ref_schema, uri
|
167
|
+
resolve_uri(ref_schema, uri)
|
120
168
|
# relative
|
121
169
|
elsif uri
|
122
170
|
# build an absolute path using the URI of the current schema
|
171
|
+
# TODO: fix this. References don't get URIs which might be an error.
|
123
172
|
schema_uri = ref_schema.uri.chomp("/")
|
124
|
-
resolve_uri(ref_schema, schema_uri + "/" + uri.path)
|
173
|
+
resolve_uri(ref_schema, URI.parse(schema_uri + "/" + uri.path))
|
125
174
|
# just a JSON Pointer -- resolve against schema root
|
126
175
|
else
|
127
|
-
resolve_pointer(ref_schema,
|
176
|
+
resolve_pointer(ref_schema, @schema)
|
128
177
|
end
|
129
178
|
end
|
130
179
|
|
131
|
-
def resolve_uri(ref_schema,
|
132
|
-
if schema =
|
133
|
-
resolve_pointer(ref_schema,
|
180
|
+
def resolve_uri(ref_schema, uri)
|
181
|
+
if schema = lookup_reference(uri)
|
182
|
+
resolve_pointer(ref_schema, schema)
|
134
183
|
else
|
135
|
-
message = %{Couldn't resolve URI: #{
|
184
|
+
message = %{Couldn't resolve URI: #{uri.to_s}.}
|
136
185
|
@errors << SchemaError.new(ref_schema, message)
|
137
186
|
nil
|
138
187
|
end
|
@@ -195,15 +244,14 @@ module JsonSchema
|
|
195
244
|
end
|
196
245
|
|
197
246
|
def traverse_schema(schema)
|
198
|
-
|
247
|
+
add_reference(schema)
|
199
248
|
|
200
249
|
schema_children(schema).each do |subschema|
|
201
250
|
if subschema.reference && !subschema.expanded?
|
202
251
|
dereference(subschema, [])
|
203
252
|
end
|
204
253
|
|
205
|
-
|
206
|
-
if subschema.expanded? && subschema.original?
|
254
|
+
if !subschema.reference
|
207
255
|
traverse_schema(subschema)
|
208
256
|
end
|
209
257
|
end
|
@@ -22,7 +22,7 @@ describe JsonSchema::ReferenceExpander do
|
|
22
22
|
it "takes a document store" do
|
23
23
|
store = JsonSchema::DocumentStore.new
|
24
24
|
expand(store: store)
|
25
|
-
|
25
|
+
assert_equal store, @expander.store
|
26
26
|
end
|
27
27
|
|
28
28
|
it "will expand anyOf" do
|
@@ -155,7 +155,7 @@ describe JsonSchema::ReferenceExpander do
|
|
155
155
|
|
156
156
|
# the *reference* schema should have expanded a pointer
|
157
157
|
schema = @schema.properties["app"].properties["name"]
|
158
|
-
assert_equal "#/
|
158
|
+
assert_equal "#/definitions/app/properties/name", schema.pointer
|
159
159
|
end
|
160
160
|
|
161
161
|
# clones are special in that they retain their original pointer despite where
|