json_schema 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- @uri_map = {}
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 lookup_pointer(uri, pointer)
37
- @uri_map[uri][:pointer_map][pointer]
18
+ def each
19
+ @schema_map.each { |k, v| yield(k, v) }
38
20
  end
39
21
 
40
22
  def lookup_uri(uri)
41
- if @uri_map[uri]
42
- @uri_map[uri][:schema]
43
- else
44
- nil
45
- end
23
+ @schema_map[uri]
46
24
  end
47
25
  end
48
26
  end
@@ -182,7 +182,7 @@ module JsonSchema
182
182
 
183
183
  if l["targetSchema"]
184
184
  link.target_schema =
185
- parse_data(l["schema"], schema, "links/#{i}/targetSchema")
185
+ parse_data(l["targetSchema"], schema, "links/#{i}/targetSchema")
186
186
  end
187
187
 
188
188
  link
@@ -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
- @schema = schema
10
- @store = options[:store] ||= DocumentStore.new
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
- @store.add_uri_reference("/", schema)
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 resolve_pointer(ref_schema, uri_path, resolved_schema)
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
- # we've already evaluated this precise URI/pointer combination before
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
- # parse a new schema and use the same parent node
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.to_s)
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.path)
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, "/", @schema)
176
+ resolve_pointer(ref_schema, @schema)
128
177
  end
129
178
  end
130
179
 
131
- def resolve_uri(ref_schema, uri_path)
132
- if schema = @store.lookup_uri(uri_path)
133
- resolve_pointer(ref_schema, uri_path, 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: #{uri_path}.}
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
- @store.add_uri_reference(schema.uri, schema)
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
- # traverse child schemas only if they're the original copy
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
- assert store.lookup_uri("/")
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 "#/properties/app/properties/name", schema.pointer
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: