@@ -24,6 +24,7 @@ defmodule ExJsonSchema.Schema do
2424 alias ExJsonSchema.Schema.Draft7
2525 alias ExJsonSchema.Schema.Root
2626 alias ExJsonSchema.Validator
27+ alias ExJsonSchema.Schema.Ref
2728
2829 @ type ref_path :: [ :root | String . t ( ) ]
2930 @ type resolved :: ExJsonSchema . data ( ) | % { String . t ( ) => ( Root . t ( ) -> { Root . t ( ) , resolved } ) | ref_path } | true | false
@@ -61,24 +62,18 @@ defmodule ExJsonSchema.Schema do
6162
6263 @ spec get_fragment ( Root . t ( ) , ref_path | ExJsonSchema . json_path ( ) ) ::
6364 { :ok , resolved } | invalid_reference_error | no_return
64- def get_fragment ( root = % Root { } , path ) when is_binary ( path ) do
65- case resolve_ref ( root , path ) do
66- { :ok , { _root , ref } } -> get_fragment ( root , ref )
67- error -> error
68- end
65+ def get_fragment ( root = % Root { } , ref ) when is_binary ( ref ) do
66+ get_fragment ( root , Ref . from_string ( ref , root ) )
6967 end
7068
71- def get_fragment ( % Root { schema: schema , refs: refs } , [ :root | path ] = ref ) do
72- case Map . get ( refs , ref_to_string ( ref ) ) do
73- nil -> do_get_fragment ( schema , path , ref )
74- schema -> { :ok , schema }
75- end
76- end
69+ def get_fragment ( % Root { schema: schema , refs: refs } , % Ref { location: location , fragment: fragment } = ref ) do
70+ case Map . get ( refs , to_string ( ref ) ) do
71+ nil ->
72+ schema = if Ref . local? ( ref ) , do: schema , else: refs [ location ]
73+ do_get_fragment ( schema , fragment , ref )
7774
78- def get_fragment ( % Root { refs: refs } , [ url | path ] = ref ) when is_binary ( url ) do
79- case Map . get ( refs , ref_to_string ( ref ) ) do
80- nil -> do_get_fragment ( refs [ url ] , path , ref )
81- schema -> { :ok , schema }
75+ schema ->
76+ { :ok , schema }
8277 end
8378 end
8479
@@ -91,8 +86,8 @@ defmodule ExJsonSchema.Schema do
9186 end
9287
9388 @ spec get_ref_schema ( Root . t ( ) , [ :root | String . t ( ) ] ) :: ExJsonSchema . data ( ) | no_return
94- def get_ref_schema ( % Root { schema: schema } , [ : root | path ] = ref ) do
95- case get_ref_schema_with_schema ( schema , path , ref ) do
89+ def get_ref_schema ( % Root { schema: schema } , % Ref { location: : root, fragment: fragment } = ref ) do
90+ case get_ref_schema_with_schema ( schema , fragment , ref ) do
9691 { :error , error } ->
9792 raise InvalidSchemaError , message: error
9893
@@ -101,8 +96,8 @@ defmodule ExJsonSchema.Schema do
10196 end
10297 end
10398
104- def get_ref_schema ( % Root { refs: refs } , [ url | path ] = ref ) when is_binary ( url ) do
105- case get_ref_schema_with_schema ( refs [ url ] , path , ref ) do
99+ def get_ref_schema ( % Root { refs: refs } , % Ref { location: url , fragment: fragment } = ref ) when is_binary ( url ) do
100+ case get_ref_schema_with_schema ( refs [ url ] , fragment , ref ) do
106101 { :error , error } ->
107102 raise InvalidSchemaError , message: error
108103
@@ -137,16 +132,16 @@ defmodule ExJsonSchema.Schema do
137132 defp resolve_refs ( % Root { } = root , schema ) when is_map ( schema ) do
138133 schema
139134 |> Enum . reduce ( root , fn
140- { "$ref" , [ :root | _ ] } , root ->
135+ { "$ref" , % Ref { } = ref } , root ->
136+ root =
137+ case Ref . cached? ( ref , root ) do
138+ true -> root
139+ false -> resolve_and_cache_remote_schema ( root , ref )
140+ end
141+
142+ get_fragment! ( root , ref )
141143 root
142144
143- { "$ref" , ref } , root when is_list ( ref ) ->
144- if local_ref? ( root , ref ) do
145- root
146- else
147- resolve_and_cache_remote_schema ( root , ref )
148- end
149-
150145 { _ , value } , root when is_map ( value ) ->
151146 resolve_refs ( root , value )
152147
@@ -161,10 +156,6 @@ defmodule ExJsonSchema.Schema do
161156
162157 defp resolve_refs ( % Root { } = root , _ ) , do: root
163158
164- defp local_ref? ( % Root { refs: refs } , [ url | _ ] = ref ) do
165- Map . has_key? ( refs , url ) || Map . has_key? ( refs , ref_to_string ( ref ) )
166- end
167-
168159 defp schema_version! ( schema_url ) do
169160 case schema_module ( schema_url , :error ) do
170161 :error -> raise ( UnsupportedSchemaVersionError )
@@ -253,71 +244,17 @@ defmodule ExJsonSchema.Schema do
253244
254245 scoped_ref =
255246 case URI . parse ( scope ) do
256- % URI { host: nil } -> ref
257- scope_uri -> URI . merge ( scope_uri , ref_uri ) |> to_string ( )
247+ % URI { host: nil } -> ref_uri
248+ scope_uri -> URI . merge ( scope_uri , ref_uri )
258249 end
250+ |> to_string ( )
259251
260- { root , path } = resolve_ref! ( root , scoped_ref )
261- { root , { "$ref" , path } }
252+ { root , { "$ref" , Ref . from_string ( scoped_ref , root ) } }
262253 end
263254
264255 defp resolve_property ( root , tuple , _ ) when is_tuple ( tuple ) , do: { root , tuple }
265256
266- defp resolve_ref ( % Root { location: location } = root , "#" ) do
267- { :ok , { root , [ location ] } }
268- end
269-
270- defp resolve_ref ( root , ref ) do
271- [ url | anchor ] = String . split ( ref , "#" )
272- ref_path = validate_ref_path ( anchor , ref )
273- { root , path } = root_and_path_for_url ( root , ref_path , url )
274-
275- { :ok , { root , path } }
276- # case get_fragment(root, path) do
277- # {:ok, _schema} -> {:ok, {root, path}}
278- # error -> error
279- # end
280- end
281-
282- defp resolve_ref! ( root , ref ) do
283- case resolve_ref ( root , ref ) do
284- { :ok , result } -> result
285- { :error , :invalid_reference } -> raise_invalid_reference_error ( ref )
286- end
287- end
288-
289- defp validate_ref_path ( [ ] , _ ) , do: nil
290- defp validate_ref_path ( [ "" ] , _ ) , do: nil
291- defp validate_ref_path ( [ fragment ] , _ ) when is_binary ( fragment ) , do: fragment
292- defp validate_ref_path ( _ , ref ) , do: raise_invalid_reference_error ( ref )
293-
294- defp root_and_path_for_url ( % Root { location: location } = root , fragment , "" ) do
295- { root , [ location | relative_path ( fragment ) ] }
296- end
297-
298- defp root_and_path_for_url ( root , fragment , url ) do
299- # root = resolve_and_cache_remote_schema(root, url)
300- { root , [ url | relative_path ( fragment ) ] }
301- end
302-
303- defp relative_path ( nil ) , do: [ ]
304- defp relative_path ( fragment ) , do: relative_ref_path ( fragment )
305-
306- defp relative_ref_path ( ref ) do
307- keys = unescaped_ref_segments ( ref )
308-
309- Enum . map ( keys , fn key ->
310- case key =~ ~r/ ^\d +$/ do
311- true ->
312- String . to_integer ( key )
313-
314- false ->
315- key
316- end
317- end )
318- end
319-
320- defp resolve_and_cache_remote_schema ( root , [ url | _ ] ) do
257+ defp resolve_and_cache_remote_schema ( root , % Ref { location: url } ) do
321258 remote_schema = remote_schema ( url )
322259 resolve_remote_schema ( root , url , remote_schema )
323260 end
@@ -388,18 +325,6 @@ defmodule ExJsonSchema.Schema do
388325 not Map . has_key? ( schema , "additionalItems" )
389326 end
390327
391- defp unescaped_ref_segments ( ref ) do
392- ref
393- |> String . split ( "/" )
394- |> Enum . reject ( & ( & 1 == "" ) )
395- |> Enum . map ( fn segment ->
396- segment
397- |> String . replace ( "~0" , "~" )
398- |> String . replace ( "~1" , "/" )
399- |> URI . decode ( )
400- end )
401- end
402-
403328 defp meta_schema? ( % { "id" => "http://json-schema.org/" <> _ } ) , do: true
404329 defp meta_schema? ( % { "$id" => "http://json-schema.org/" <> _ } ) , do: true
405330 defp meta_schema? ( _ ) , do: false
@@ -420,7 +345,7 @@ defmodule ExJsonSchema.Schema do
420345 end
421346
422347 defp get_ref_schema_with_schema ( nil , _ , ref ) do
423- { :error , "reference #{ ref_to_string ( ref ) } could not be resolved" }
348+ { :error , "reference #{ to_string ( ref ) } could not be resolved" }
424349 end
425350
426351 defp get_ref_schema_with_schema ( schema , [ ] , _ ) do
@@ -439,13 +364,10 @@ defmodule ExJsonSchema.Schema do
439364 |> get_ref_schema_with_schema ( path , ref )
440365 end
441366
442- defp ref_to_string ( [ :root | path ] ) , do: "##{ path } "
443- defp ref_to_string ( [ url | path ] ) , do: url <> "#" <> Enum . join ( path , "/" )
444-
445367 @ spec raise_invalid_reference_error ( any ) :: no_return
446368 def raise_invalid_reference_error ( ref ) when is_binary ( ref ) ,
447369 do: raise ( InvalidReferenceError , message: "invalid reference #{ ref } " )
448370
449371 def raise_invalid_reference_error ( ref ) ,
450- do: ref |> ref_to_string |> raise_invalid_reference_error
372+ do: ref |> to_string ( ) |> raise_invalid_reference_error
451373end
0 commit comments