mirror of
https://github.com/valitydev/jesse.git
synced 2024-11-06 09:35:23 +00:00
Merge remote-tracking branch 'jamesaimonetti/spec03-ref' into json-references
This commit is contained in:
commit
f34852794b
@ -27,6 +27,7 @@
|
||||
, get_allowed_errors/1
|
||||
, get_current_path/1
|
||||
, get_current_schema/1
|
||||
, get_original_schema/1
|
||||
, get_default_schema_ver/1
|
||||
, get_error_handler/1
|
||||
, get_error_list/1
|
||||
@ -35,11 +36,17 @@
|
||||
, set_allowed_errors/2
|
||||
, set_current_schema/2
|
||||
, set_error_list/2
|
||||
, find_schema/2
|
||||
]).
|
||||
|
||||
-export_type([ state/0
|
||||
]).
|
||||
|
||||
%% Includes
|
||||
-include("jesse_schema_validator.hrl").
|
||||
|
||||
-define(schema_loader_fun, fun jesse_database:read/1).
|
||||
|
||||
%% Internal datastructures
|
||||
-record( state
|
||||
, { original_schema :: jesse:json_term()
|
||||
@ -49,14 +56,12 @@
|
||||
, error_list :: list()
|
||||
, error_handler :: fun((#state{}) -> list() | no_return())
|
||||
, default_schema_ver :: atom()
|
||||
, schema_loader_fun :: fun((binary()) -> {ok, jesse:json_term()} | jesse:json_term() | ?not_found)
|
||||
}
|
||||
).
|
||||
|
||||
-opaque state() :: #state{}.
|
||||
|
||||
%% Includes
|
||||
-include("jesse_schema_validator.hrl").
|
||||
|
||||
%%% API
|
||||
%% @doc Adds `Property' to the `current_path' in `State'.
|
||||
-spec add_to_path(State :: state(), Property :: binary()) -> state().
|
||||
@ -79,6 +84,11 @@ get_current_path(#state{current_path = CurrentPath}) ->
|
||||
get_current_schema(#state{current_schema = CurrentSchema}) ->
|
||||
CurrentSchema.
|
||||
|
||||
%% @doc Getter for `original_schema'.
|
||||
-spec get_original_schema(State :: state()) -> jesse:json_term().
|
||||
get_original_schema(#state{original_schema = OriginalSchema}) ->
|
||||
OriginalSchema.
|
||||
|
||||
%% @doc Getter for `default_schema_ver'.
|
||||
-spec get_default_schema_ver(State :: state()) -> binary().
|
||||
get_default_schema_ver(#state{default_schema_ver = SchemaVer}) ->
|
||||
@ -113,6 +123,10 @@ new(JsonSchema, Options) ->
|
||||
, Options
|
||||
, ?default_schema_ver
|
||||
),
|
||||
LoaderFun = proplists:get_value( schema_loader_fun
|
||||
, Options
|
||||
, ?schema_loader_fun
|
||||
),
|
||||
#state{ current_schema = JsonSchema
|
||||
, current_path = []
|
||||
, original_schema = JsonSchema
|
||||
@ -120,6 +134,7 @@ new(JsonSchema, Options) ->
|
||||
, error_list = []
|
||||
, error_handler = ErrorHandler
|
||||
, default_schema_ver = DefaultSchemaVer
|
||||
, schema_loader_fun = LoaderFun
|
||||
}.
|
||||
|
||||
%% @doc Removes the last element from `current_path' in `State'.
|
||||
@ -146,6 +161,20 @@ set_current_schema(State, NewSchema) ->
|
||||
set_error_list(State, ErrorList) ->
|
||||
State#state{error_list = ErrorList}.
|
||||
|
||||
%% @doc Find a schema based on URI
|
||||
-spec find_schema(State :: state(), SchemaURI :: binary()) -> jesse:json_term() | ?not_found.
|
||||
find_schema(#state{schema_loader_fun=LoaderFun}, SchemaURI) ->
|
||||
try LoaderFun(SchemaURI) of
|
||||
{ok, Schema} -> Schema;
|
||||
Schema ->
|
||||
case jesse_lib:is_json_object(Schema) of
|
||||
true -> Schema;
|
||||
false -> ?not_found
|
||||
end
|
||||
catch
|
||||
_:_ -> ?not_found
|
||||
end.
|
||||
|
||||
%%% Local Variables:
|
||||
%%% erlang-indent-level: 2
|
||||
%%% End:
|
||||
|
@ -185,6 +185,9 @@ check_value(Value, [{?DISALLOW, Disallow} | Attrs], State) ->
|
||||
check_value(Value, [{?EXTENDS, Extends} | Attrs], State) ->
|
||||
NewState = check_extends(Value, Extends, State),
|
||||
check_value(Value, Attrs, NewState);
|
||||
check_value(Value, [{?_REF, RefSchemaURI} | Attrs], State) ->
|
||||
NewState = check_ref(Value, RefSchemaURI, State),
|
||||
check_value(Value, Attrs, NewState);
|
||||
check_value(_Value, [], State) ->
|
||||
State;
|
||||
check_value(Value, [_Attr | Attrs], State) ->
|
||||
@ -861,6 +864,35 @@ check_extends_array(Value, Extends, State) ->
|
||||
, Extends
|
||||
).
|
||||
|
||||
%% @private
|
||||
check_ref(Value, <<"#", LocalPath/binary>> = RefSchemaURI, State) ->
|
||||
Keys = binary:split(LocalPath, <<"/">>, ['global']),
|
||||
OriginalSchema = jesse_state:get_original_schema(State),
|
||||
|
||||
case local_schema(OriginalSchema, Keys) of
|
||||
?not_found -> handle_schema_invalid({'schema_unsupported', RefSchemaURI}, State);
|
||||
LocalSchema -> check_ref_schema(Value, LocalSchema, State)
|
||||
end;
|
||||
check_ref(Value, RefSchemaURI, State) ->
|
||||
case jesse_state:find_schema(State, RefSchemaURI) of
|
||||
?not_found -> handle_schema_invalid({'schema_unsupported', RefSchemaURI}, State);
|
||||
RefSchema -> check_ref_schema(Value, RefSchema, State)
|
||||
end.
|
||||
|
||||
%% @private
|
||||
check_ref_schema(Value, RefSchema, State) ->
|
||||
TmpState = check_value(Value, unwrap(RefSchema), set_current_schema(State, RefSchema)),
|
||||
set_current_schema(TmpState, get_current_schema(State)).
|
||||
|
||||
local_schema(Schema, []) -> Schema;
|
||||
local_schema(Schema, [<<>> | Keys]) -> local_schema(Schema, Keys);
|
||||
local_schema(Schema, [Key | Keys]) ->
|
||||
SubSchema = get_value(Key, Schema),
|
||||
case jesse_lib:is_json_object(SubSchema) of
|
||||
true -> local_schema(SubSchema, Keys);
|
||||
false -> ?not_found
|
||||
end.
|
||||
|
||||
%%=============================================================================
|
||||
%% @doc Returns `true' if given values (instance) are equal, otherwise `false'
|
||||
%% is returned.
|
||||
|
@ -43,7 +43,7 @@
|
||||
, pattern/1
|
||||
, patternProperties/1
|
||||
, properties/1
|
||||
%% , ref/1
|
||||
, ref/1
|
||||
, required/1
|
||||
, type/1
|
||||
, uniqueItems/1
|
||||
@ -78,7 +78,7 @@ all() ->
|
||||
, pattern
|
||||
, patternProperties
|
||||
, properties
|
||||
%% , ref
|
||||
, ref
|
||||
, required
|
||||
, type
|
||||
, uniqueItems
|
||||
@ -177,11 +177,10 @@ properties(Config) ->
|
||||
Specs = ?config(Key, Config),
|
||||
ok = run_tests(Specs).
|
||||
|
||||
%% not implemented yet
|
||||
%% ref(Config) ->
|
||||
%% Key = "ref",
|
||||
%% Specs = ?config(Key, Config),
|
||||
%% ok = run_tests(Specs).
|
||||
ref(Config) ->
|
||||
Key = "ref",
|
||||
Specs = ?config(Key, Config),
|
||||
ok = run_tests(Specs).
|
||||
|
||||
required(Config) ->
|
||||
Key = "required",
|
||||
|
Loading…
Reference in New Issue
Block a user