Skip to content

Commit

Permalink
Merge pull request #146 from paulo-ferraz-oliveira/feature/stricter_d…
Browse files Browse the repository at this point in the history
…ialyzer_analysis

Stricter dialyzer analysis
  • Loading branch information
tsloughter committed Sep 14, 2020
2 parents 894ec1e + 3a8f364 commit 7c7a69c
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 53 deletions.
15 changes: 15 additions & 0 deletions rebar.config
@@ -1,2 +1,17 @@
{edoc_opts, [{preprocess, true}]}.
{erl_opts, [debug_info]}.
{dialyzer, [
{warnings, [
unknown,
unmatched_returns,
error_handling,
underspecs
]}
]}.
{profiles, [
{test, [
{dialyzer, [
{plt_extra_apps, [eunit]}
]}
]}
]}.
32 changes: 17 additions & 15 deletions src/jsx.erl
Expand Up @@ -54,20 +54,20 @@

-type config() :: jsx_config:config().

-spec encode(Source::json_term()) -> json_text().
-spec encode(Source::json_term()) -> json_text() | {incomplete, encoder()}.

encode(Source) -> encode(Source, []).

-spec encode(Source::json_term(), Config::jsx_to_json:config()) -> json_text() | {incomplete, encoder()}.
-spec encode(Source::json_term(), Config::jsx_config:options()) -> json_text() | {incomplete, encoder()}.

encode(Source, Config) -> jsx_to_json:to_json(Source, Config).


-spec decode(Source::json_text()) -> json_term().
-spec decode(Source::json_text()) -> json_term() | {incomplete, decoder()}.

decode(Source) -> decode(Source, []).

-spec decode(Source::json_text(), Config::jsx_to_term:config()) -> json_term() | {incomplete, decoder()}.
-spec decode(Source::json_text(), Config::jsx_config:options()) -> json_term() | {incomplete, decoder()}.

decode(Source, Config) -> jsx_to_term:to_term(Source, Config).

Expand All @@ -76,7 +76,7 @@ decode(Source, Config) -> jsx_to_term:to_term(Source, Config).

format(Source) -> format(Source, []).

-spec format(Source::json_text(), Config::jsx_to_json:config()) -> json_text() | {incomplete, decoder()}.
-spec format(Source::json_text(), Config::jsx_config:options()) -> json_text().

format(Source, Config) -> jsx_to_json:format(Source, Config).

Expand All @@ -91,43 +91,44 @@ minify(Source) -> format(Source, []).
prettify(Source) -> format(Source, [space, {indent, 2}]).


-spec is_json(Source::any()) -> boolean().
-spec is_json(Source::binary()) -> boolean() | {incomplete, decoder()}.

is_json(Source) -> is_json(Source, []).

-spec is_json(Source::any(), Config::jsx_verify:config()) -> boolean() | {incomplete, decoder()}.
-spec is_json(Source::binary(), Config::jsx_config:options()) -> boolean() | {incomplete, decoder()}.

is_json(Source, Config) -> jsx_verify:is_json(Source, Config).


-spec is_term(Source::any()) -> boolean().
-spec is_term(Source::json_term() | end_stream | end_json) -> boolean() | {incomplete, encoder()}.

is_term(Source) -> is_term(Source, []).

-spec is_term(Source::any(), Config::jsx_verify:config()) -> boolean() | {incomplete, encoder()}.
-spec is_term(Source::json_term() | end_stream | end_json,
Config::jsx_config:options()) -> boolean() | {incomplete, encoder()}.

is_term(Source, Config) -> jsx_verify:is_term(Source, Config).


-spec consult(File::file:name_all()) -> list(json_term()).
-spec consult(File::file:name_all()) -> list(jsx_consult:json_value()).

consult(File) -> consult(File, []).

-spec consult(File::file:name_all(), Config::jsx_to_term:config()) -> list(json_term()).
-spec consult(File::file:name_all(), Config::jsx_consult:config()) -> list(jsx_consult:json_value()).

consult(File, Config) -> jsx_consult:consult(File, Config).


-type decoder() :: fun((json_text() | end_stream | end_json) -> any()).

-spec decoder(Handler::module(), State::any(), Config::list()) -> decoder().
-spec decoder(Handler::module(), State::any(), Config::jsx_config:options()) -> decoder().

decoder(Handler, State, Config) -> jsx_decoder:decoder(Handler, State, Config).


-type encoder() :: fun((json_term() | end_stream | end_json) -> any()).

-spec encoder(Handler::module(), State::any(), Config::list()) -> encoder().
-spec encoder(Handler::module(), State::any(), Config::jsx_config:options()) -> encoder().

encoder(Handler, State, Config) -> jsx_encoder:encoder(Handler, State, Config).

Expand Down Expand Up @@ -156,13 +157,14 @@ encoder(Handler, State, Config) -> jsx_encoder:encoder(Handler, State, Config).

-type parser() :: fun((token() | end_stream) -> any()).

-spec parser(Handler::module(), State::any(), Config::list()) -> parser().
-spec parser(Handler::module(), State::any(), Config::jsx_config:options()) -> parser().

parser(Handler, State, Config) -> jsx_parser:parser(Handler, State, Config).

-opaque internal_state() :: tuple().

-spec resume(Term::json_text() | token(), InternalState::internal_state(), Config::list()) -> any().
-spec resume(Term::json_text() | token(), InternalState::internal_state(),
Config::jsx_config:options()) -> jsx:decoder() | {incomplete, jsx:decoder()}.

resume(Term, {decoder, State, Handler, Acc, Stack}, Config) ->
jsx_decoder:resume(Term, State, Handler, Acc, Stack, jsx_config:parse_config(Config));
Expand Down
55 changes: 51 additions & 4 deletions src/jsx_config.erl
Expand Up @@ -49,8 +49,55 @@
-type config() :: #config{}.
-export_type([config/0]).

-type option() :: valid_flag()
| {valid_flag(), boolean()}
| {strict, [strict_option()]}
| {error_handler, fun((any(), any(), any()) -> ok)}
| {incomplete_handler, fun((any(), any(), any()) -> ok)}
| {return_maps, boolean()}
| {labels, label_option()}
| {space, non_neg_integer()}
| {indent, non_neg_integer()}
| {depth, non_neg_integer()}
| {newline, binary()}
| legacy_option()
| {legacy_option(), boolean()}.
-type legacy_option() :: strict_comments
| strict_commas
| strict_utf8
| strict_single_quotes
| strict_escapes
| strict_control_codes.

-type options() :: [option()].
-export_type([options/0]).

-type strict_option() :: comments
| trailing_commas
| utf8
| single_quotes
| escapes
| control_codes.
-type label_option() :: binary
| atom
| existing_atom
| attempt_atom.

-type valid_flag() :: escaped_forward_slashes
| escaped_strings
| unescaped_jsonp
| dirty_strings
| multi_term
| return_tail
| repeat_keys
| strict
| stream
| uescape
| error_handler
| incomplete_handler.

%% parsing of jsx config
-spec parse_config(Config::proplists:proplist()) -> config().
-spec parse_config(Config::options()) -> config().

parse_config(Config) -> parse_config(Config, #config{}).

Expand Down Expand Up @@ -116,7 +163,7 @@ parse_strict(_Strict, _Rest, _Config) ->



-spec config_to_list(Config::config()) -> proplists:proplist().
-spec config_to_list(Config::config()) -> options().

config_to_list(Config) ->
reduce_config(lists:map(
Expand Down Expand Up @@ -153,7 +200,7 @@ reduce_config([Else|Input], Output, Strict) ->
reduce_config(Input, [Else] ++ Output, Strict).


-spec valid_flags() -> [atom()].
-spec valid_flags() -> [valid_flag(), ...].

valid_flags() ->
[
Expand All @@ -172,7 +219,7 @@ valid_flags() ->
].


-spec extract_config(Config::proplists:proplist()) -> proplists:proplist().
-spec extract_config(Config::options()) -> options().

extract_config(Config) ->
extract_parser_config(Config, []).
Expand Down
7 changes: 4 additions & 3 deletions src/jsx_consult.erl
Expand Up @@ -32,7 +32,7 @@
return_maps = false
}).

-type config() :: list().
-type config() :: proplists:proplist().
-export_type([config/0]).

-type json_value() :: list(json_value())
Expand All @@ -43,6 +43,7 @@
| integer()
| float()
| binary().
-export_type([json_value/0]).

opts(Opts) -> [return_maps, multi_term] ++ Opts.

Expand All @@ -61,8 +62,8 @@ consult(File, Config) when is_list(Config) ->
end.


-type state() :: {[], proplists:proplist(), {list(), #config{}}}.
-spec init(Config::proplists:proplist()) -> state().
-type state() :: {[], config(), {list(), #config{}}}.
-spec init(Config::config()) -> state().

init(Config) -> {[], Config, jsx_to_term:start_term(Config)}.

Expand Down
2 changes: 1 addition & 1 deletion src/jsx_decoder.erl
Expand Up @@ -32,7 +32,7 @@
-export([decoder/3, resume/6]).


-spec decoder(Handler::module(), State::any(), Config::list()) -> jsx:decoder().
-spec decoder(Handler::module(), State::any(), Config::jsx_config:options()) -> jsx:decoder().

decoder(Handler, State, Config) ->
fun(JSON) -> start(JSON, {Handler, Handler:init(State)}, [], jsx_config:parse_config(Config)) end.
Expand Down
6 changes: 3 additions & 3 deletions src/jsx_encoder.erl
Expand Up @@ -25,19 +25,19 @@

-export([encoder/3, encode/1, encode/2]).

-spec encoder(Handler::module(), State::any(), Config::list()) -> jsx:encoder().
-spec encoder(Handler::module(), State::any(), Config::jsx_config:options()) -> jsx:encoder().

encoder(Handler, State, Config) ->
Parser = jsx:parser(Handler, State, Config),
fun(Term) -> Parser(encode(Term) ++ [end_json]) end.


-spec encode(Term::any()) -> any().
-spec encode(Term::any()) -> [any(), ...].

encode(Term) -> encode(Term, ?MODULE).


-spec encode(Term::any(), EntryPoint::module()) -> any().
-spec encode(Term::any(), EntryPoint::module()) -> [any(), ...].

encode(Map, _EntryPoint) when is_map(Map), map_size(Map) < 1 ->
[start_object, end_object];
Expand Down
4 changes: 2 additions & 2 deletions src/jsx_parser.erl
Expand Up @@ -27,7 +27,7 @@
-export([init/1, handle_event/2]).


-spec parser(Handler::module(), State::any(), Config::list()) -> jsx:parser().
-spec parser(Handler::module(), State::any(), Config::jsx_config:options()) -> jsx:parser().

parser(Handler, State, Config) ->
fun(Tokens) -> value(Tokens, {Handler, Handler:init(State)}, [], jsx_config:parse_config(Config)) end.
Expand Down Expand Up @@ -630,7 +630,7 @@ to_hex(X) -> X + 48. %% ascii "1" is [49], "2" is [50], etc...


%% for raw input
-spec init(proplists:proplist()) -> list().
-spec init([]) -> [].

init([]) -> [].

Expand Down
11 changes: 5 additions & 6 deletions src/jsx_to_json.erl
Expand Up @@ -36,17 +36,16 @@
newline = <<$\n>>
}).

-type config() :: list().
-export_type([config/0]).
-type config() :: proplists:proplist().


-spec to_json(Source::any(), Config::config()) -> binary().
-spec to_json(Source::jsx:json_term(), Config::jsx_config:options()) -> binary().

to_json(Source, Config) when is_list(Config) ->
(jsx:encoder(?MODULE, Config, jsx_config:extract_config(Config ++ [escaped_strings])))(Source).


-spec format(Source::binary(), Config::config()) -> binary().
-spec format(Source::binary(), Config::jsx_config:options()) -> jsx:json_text().

format(Source, Config) when is_binary(Source) andalso is_list(Config) ->
(jsx:decoder(?MODULE, Config, jsx_config:extract_config(Config ++ [escaped_strings])))(Source);
Expand Down Expand Up @@ -91,7 +90,7 @@ parse_config([], Config) ->


-type state() :: {unicode:charlist(), #config{}}.
-spec init(Config::proplists:proplist()) -> state().
-spec init(Config::config()) -> state().

init(Config) -> {[], parse_config(Config)}.

Expand Down Expand Up @@ -390,7 +389,7 @@ custom_newline_test_() ->
[
{"single key object", ?_assert(
jsx:format(<<"{\"k\":\"v\"}">>, [space, {indent, 2}, {newline, <<$\r>>}])
=:= <<"{\r \"k\": \"v\"\r}">>)
=:= <<"{\r \"k\": \"v\"\r}">>)
}
].

Expand Down
20 changes: 4 additions & 16 deletions src/jsx_to_term.erl
Expand Up @@ -41,21 +41,9 @@
return_maps = false
}).

-type config() :: list().
-export_type([config/0]).

-type json_value() :: list(json_value())
| list({binary() | atom(), json_value()}) | [{},...]
| {with_tail, json_value(), binary()}
| map()
| true
| false
| null
| integer()
| float()
| binary().

-spec to_term(Source::binary(), Config::config()) -> json_value().
-type config() :: proplists:proplist().

-spec to_term(Source::binary(), Config::jsx_config:options()) -> jsx:json_term() | {incomplete, jsx:decoder()}.

to_term(Source, Config) when is_list(Config) ->
(jsx:decoder(?MODULE, [return_maps] ++ Config, jsx_config:extract_config(Config)))(Source).
Expand Down Expand Up @@ -87,7 +75,7 @@ parse_config([], Config) ->


-type state() :: {list(), #config{}}.
-spec init(Config::proplists:proplist()) -> state().
-spec init(Config::config()) -> state().

init(Config) -> start_term(Config).

Expand Down
8 changes: 5 additions & 3 deletions src/jsx_verify.erl
Expand Up @@ -26,16 +26,18 @@
-export([is_json/2, is_term/2]).
-export([init/1, handle_event/2]).

-type config() :: proplists:proplist().

-spec is_json(Source::binary(), Config::proplists:proplist()) -> true | false | {incomplete, jsx:decoder()}.
-spec is_json(Source::binary(), Config::jsx_config:options()) -> true | false | {incomplete, jsx:decoder()}.

is_json(Source, Config) when is_list(Config) ->
try (jsx:decoder(?MODULE, Config, jsx_config:extract_config(Config)))(Source)
catch error:badarg -> false
end.


-spec is_term(Source::any(), Config::proplists:proplist()) -> true | false | {incomplete, jsx:encoder()}.
-spec is_term(Source::jsx:json_term() | end_stream | end_json,
Config::jsx_config:options()) -> true | false | {incomplete, jsx:encoder()}.

is_term(Source, Config) when is_list(Config) ->
try (jsx:encoder(?MODULE, Config, jsx_config:extract_config(Config)))(Source)
Expand Down Expand Up @@ -68,7 +70,7 @@ parse_config([], Config) ->

%% we don't actually need any state for this
-type state() :: [].
-spec init(Config::proplists:proplist()) -> state().
-spec init(Config::config()) -> state().

init(Config) -> parse_config(Config).

Expand Down

0 comments on commit 7c7a69c

Please sign in to comment.