drop support for versions before OTP-17 and bump to 3.0.0
This commit is contained in:
parent
1bbe8986c7
commit
fab436e1d5
14 changed files with 64 additions and 286 deletions
|
@ -1,7 +1,7 @@
|
|||
{application, jsx,
|
||||
[
|
||||
{description, "a streaming, evented json parsing toolkit"},
|
||||
{vsn, "2.11.0"},
|
||||
{vsn, "3.0.0"},
|
||||
{modules, [
|
||||
jsx,
|
||||
jsx_encoder,
|
||||
|
@ -18,11 +18,7 @@
|
|||
stdlib
|
||||
]},
|
||||
{env, []},
|
||||
{files, [
|
||||
"src",
|
||||
"rebar.config", "rebar.config.script", "rebar.lock"
|
||||
"README.md", "CHANGES.md", "LICENSE"
|
||||
]},
|
||||
|
||||
{licenses, ["MIT"]},
|
||||
{links, [{"Github", "https://github.com/talentdeficit/jsx"}]}
|
||||
]}.
|
||||
|
|
25
src/jsx.erl
25
src/jsx.erl
|
@ -29,7 +29,6 @@
|
|||
-export([consult/1, consult/2]).
|
||||
-export([encoder/3, decoder/3, parser/3]).
|
||||
-export([resume/3]).
|
||||
-export([maps_support/0]).
|
||||
|
||||
-export_type([json_term/0, json_text/0, token/0]).
|
||||
-export_type([encoder/0, decoder/0, parser/0, internal_state/0]).
|
||||
|
@ -42,18 +41,6 @@
|
|||
-export([init/1, handle_event/2]).
|
||||
-endif.
|
||||
|
||||
|
||||
-ifndef(maps_support).
|
||||
-type json_term() :: [{binary() | atom(), json_term()}] | [{},...]
|
||||
| [json_term()] | []
|
||||
| {with_tail, json_term(), binary()}
|
||||
| true | false | null
|
||||
| integer() | float()
|
||||
| binary() | atom()
|
||||
| calendar:datetime().
|
||||
-endif.
|
||||
|
||||
-ifdef(maps_support).
|
||||
-type json_term() :: [{binary() | atom(), json_term()}] | [{},...]
|
||||
| [json_term()] | []
|
||||
| {with_tail, json_term(), binary()}
|
||||
|
@ -62,7 +49,6 @@
|
|||
| integer() | float()
|
||||
| binary() | atom()
|
||||
| calendar:datetime().
|
||||
-endif.
|
||||
|
||||
-type json_text() :: binary().
|
||||
|
||||
|
@ -183,17 +169,6 @@ resume(Term, {decoder, State, Handler, Acc, Stack}, Config) ->
|
|||
resume(Term, {parser, State, Handler, Stack}, Config) ->
|
||||
jsx_parser:resume(Term, State, Handler, Stack, jsx_config:parse_config(Config)).
|
||||
|
||||
|
||||
-spec maps_support() -> boolean().
|
||||
|
||||
-ifndef(maps_support).
|
||||
maps_support() -> false.
|
||||
-endif.
|
||||
-ifdef(maps_support).
|
||||
maps_support() -> true.
|
||||
-endif.
|
||||
|
||||
|
||||
-ifdef(TEST).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
|
|
@ -35,18 +35,6 @@
|
|||
-type config() :: list().
|
||||
-export_type([config/0]).
|
||||
|
||||
-ifndef(maps_support).
|
||||
-type json_value() :: list(json_value())
|
||||
| list({binary() | atom(), json_value()})
|
||||
| true
|
||||
| false
|
||||
| null
|
||||
| integer()
|
||||
| float()
|
||||
| binary().
|
||||
-endif.
|
||||
|
||||
-ifdef(maps_support).
|
||||
-type json_value() :: list(json_value())
|
||||
| map()
|
||||
| true
|
||||
|
@ -55,15 +43,8 @@
|
|||
| integer()
|
||||
| float()
|
||||
| binary().
|
||||
-endif.
|
||||
|
||||
|
||||
-ifdef(maps_always).
|
||||
opts(Opts) -> [return_maps, multi_term] ++ Opts.
|
||||
-endif.
|
||||
-ifndef(maps_always).
|
||||
opts(Opts) -> [multi_term] ++ Opts.
|
||||
-endif.
|
||||
|
||||
-spec consult(File::file:name_all(), Config::config()) -> [json_value()].
|
||||
|
||||
|
|
|
@ -946,15 +946,8 @@ exp(_, N) -> {finish_float, N}.
|
|||
finish_number(Rest, Handler, Acc, Stack, Config) ->
|
||||
maybe_done(Rest, handle_event(format_number(Acc), Handler, Config), Stack, Config).
|
||||
|
||||
|
||||
-ifndef(no_binary_to_whatever).
|
||||
format_number({integer, Acc}) -> {integer, binary_to_integer(Acc)};
|
||||
format_number({float, Acc}) -> {float, binary_to_float(Acc)}.
|
||||
-else.
|
||||
format_number({integer, Acc}) -> {integer, list_to_integer(unicode:characters_to_list(Acc))};
|
||||
format_number({float, Acc}) -> {float, list_to_float(unicode:characters_to_list(Acc))}.
|
||||
-endif.
|
||||
|
||||
|
||||
true(<<$r, $u, $e, Rest/binary>>, Handler, Stack, Config) ->
|
||||
maybe_done(Rest, handle_event({literal, true}, Handler, Config), Stack, Config);
|
||||
|
@ -1882,26 +1875,26 @@ custom_incomplete_handler_test_() ->
|
|||
return_tail_test_() ->
|
||||
[
|
||||
{"return_tail with tail", ?_assertEqual(
|
||||
{with_tail,[{}],<<"3">>},
|
||||
{with_tail,#{},<<"3">>},
|
||||
jsx:decode(<<"{} 3">>, [return_tail])
|
||||
)},
|
||||
{"return_tail without tail", ?_assertEqual(
|
||||
{with_tail,[{}],<<"">>},
|
||||
{with_tail,#{},<<"">>},
|
||||
jsx:decode(<<"{}">>, [return_tail])
|
||||
)},
|
||||
{"return_tail with trimmed whitespace", ?_assertEqual(
|
||||
{with_tail,[{}],<<"">>},
|
||||
{with_tail,#{},<<"">>},
|
||||
jsx:decode(<<"{} ">>, [return_tail])
|
||||
)},
|
||||
{"return_tail and streaming", ?_assertEqual(
|
||||
{with_tail,[{}],<<"3">>},
|
||||
{with_tail,#{},<<"3">>},
|
||||
begin
|
||||
{incomplete, F} = jsx:decode(<<"{">>, [return_tail, stream]),
|
||||
F(<<"} 3">>)
|
||||
end
|
||||
)},
|
||||
{"return_tail and streaming", ?_assertEqual(
|
||||
{with_tail,[{}],<<"">>},
|
||||
{with_tail,#{},<<"">>},
|
||||
begin
|
||||
%% In case of infinite stream of objects a user does not know
|
||||
%% when to call F(end_stream).
|
||||
|
|
|
@ -39,17 +39,11 @@ encode(Term) -> encode(Term, ?MODULE).
|
|||
|
||||
-spec encode(Term::any(), EntryPoint::module()) -> any().
|
||||
|
||||
-ifndef(maps_support).
|
||||
encode(Term, EntryPoint) -> encode_(Term, EntryPoint).
|
||||
-endif.
|
||||
|
||||
-ifdef(maps_support).
|
||||
encode(Map, _EntryPoint) when is_map(Map), map_size(Map) < 1 ->
|
||||
[start_object, end_object];
|
||||
encode(Term, EntryPoint) when is_map(Term) ->
|
||||
[start_object] ++ unpack(Term, EntryPoint);
|
||||
encode(Term, EntryPoint) -> encode_(Term, EntryPoint).
|
||||
-endif.
|
||||
|
||||
encode_([], _EntryPoint) -> [start_array, end_array];
|
||||
encode_([{}], _EntryPoint) -> [start_object, end_object];
|
||||
|
@ -75,16 +69,11 @@ unhitch([V|Rest], EntryPoint) ->
|
|||
EntryPoint:encode(V, EntryPoint) ++ unhitch(Rest, EntryPoint);
|
||||
unhitch([], _) -> [end_array].
|
||||
|
||||
|
||||
-ifdef(maps_support).
|
||||
unpack(Map, EntryPoint) -> unpack(Map, maps:keys(Map), EntryPoint).
|
||||
|
||||
unpack(Map, [K|Rest], EntryPoint) when is_integer(K); is_binary(K); is_atom(K) ->
|
||||
[K] ++ EntryPoint:encode(maps:get(K, Map), EntryPoint) ++ unpack(Map, Rest, EntryPoint);
|
||||
unpack(_, [], _) -> [end_object].
|
||||
-endif.
|
||||
|
||||
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
|
|
@ -44,19 +44,6 @@
|
|||
-type config() :: list().
|
||||
-export_type([config/0]).
|
||||
|
||||
-ifndef(maps_support).
|
||||
-type json_value() :: list(json_value())
|
||||
| list({binary() | atom(), json_value()}) | [{},...]
|
||||
| {with_tail, json_value(), binary()}
|
||||
| true
|
||||
| false
|
||||
| null
|
||||
| integer()
|
||||
| float()
|
||||
| binary().
|
||||
-endif.
|
||||
|
||||
-ifdef(maps_support).
|
||||
-type json_value() :: list(json_value())
|
||||
| list({binary() | atom(), json_value()}) | [{},...]
|
||||
| {with_tail, json_value(), binary()}
|
||||
|
@ -67,19 +54,11 @@
|
|||
| integer()
|
||||
| float()
|
||||
| binary().
|
||||
-endif.
|
||||
|
||||
|
||||
-spec to_term(Source::binary(), Config::config()) -> json_value().
|
||||
|
||||
-ifdef(maps_always).
|
||||
to_term(Source, Config) when is_list(Config) ->
|
||||
(jsx:decoder(?MODULE, [return_maps] ++ Config, jsx_config:extract_config(Config)))(Source).
|
||||
-endif.
|
||||
-ifndef(maps_always).
|
||||
to_term(Source, Config) when is_list(Config) ->
|
||||
(jsx:decoder(?MODULE, Config, jsx_config:extract_config(Config)))(Source).
|
||||
-endif.
|
||||
|
||||
parse_config(Config) -> parse_config(Config, #config{}).
|
||||
|
||||
|
@ -166,41 +145,6 @@ format_key(Key, Config) ->
|
|||
|
||||
start_term(Config) when is_list(Config) -> {[], parse_config(Config)}.
|
||||
|
||||
|
||||
-ifndef(maps_support).
|
||||
%% allocate a new object on top of the stack
|
||||
start_object({Stack, Config}) -> {[{object, []}] ++ Stack, Config}.
|
||||
|
||||
|
||||
%% allocate a new array on top of the stack
|
||||
start_array({Stack, Config}) -> {[{array, []}] ++ Stack, Config}.
|
||||
|
||||
|
||||
%% finish an object or array and insert it into the parent object if it exists or
|
||||
%% return it if it is the root object
|
||||
finish({[{object, []}], Config}) -> {[{}], Config};
|
||||
finish({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config});
|
||||
finish({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config};
|
||||
finish({[{object, Pairs}|Rest], Config}) -> insert(lists:reverse(Pairs), {Rest, Config});
|
||||
finish({[{array, Values}], Config}) -> {lists:reverse(Values), Config};
|
||||
finish({[{array, Values}|Rest], Config}) -> insert(lists:reverse(Values), {Rest, Config});
|
||||
finish(_) -> erlang:error(badarg).
|
||||
|
||||
|
||||
%% insert a value when there's no parent object or array
|
||||
insert(Value, {[], Config}) -> {Value, Config};
|
||||
%% insert a key or value into an object or array, autodetects the 'right' thing
|
||||
insert(Key, {[{object, Pairs}|Rest], Config}) ->
|
||||
{[{object, Key, Pairs}] ++ Rest, Config};
|
||||
insert(Value, {[{object, Key, Pairs}|Rest], Config}) ->
|
||||
{[{object, [{Key, Value}] ++ Pairs}] ++ Rest, Config};
|
||||
insert(Value, {[{array, Values}|Rest], Config}) ->
|
||||
{[{array, [Value] ++ Values}] ++ Rest, Config};
|
||||
insert(_, _) -> erlang:error(badarg).
|
||||
-endif.
|
||||
|
||||
|
||||
-ifdef(maps_support).
|
||||
%% allocate a new object on top of the stack
|
||||
start_object({Stack, Config=#config{return_maps=true}}) ->
|
||||
{[{object, #{}}] ++ Stack, Config};
|
||||
|
@ -239,8 +183,6 @@ insert(Value, {[{object, Key, Pairs}|Rest], Config}) ->
|
|||
insert(Value, {[{array, Values}|Rest], Config}) ->
|
||||
{[{array, [Value] ++ Values}] ++ Rest, Config};
|
||||
insert(_, _) -> erlang:error(badarg).
|
||||
-endif.
|
||||
|
||||
|
||||
get_key({[{object, Key, _}|_], _}) -> Key;
|
||||
get_key(_) -> erlang:error(badarg).
|
||||
|
@ -368,7 +310,6 @@ rep_manipulation_test_() ->
|
|||
].
|
||||
|
||||
|
||||
-ifdef(maps_support).
|
||||
rep_manipulation_with_maps_test_() ->
|
||||
[
|
||||
{"allocate a new object on an empty stack", ?_assertEqual(
|
||||
|
@ -420,10 +361,10 @@ return_maps_test_() ->
|
|||
[
|
||||
{"an empty map", ?_assertEqual(
|
||||
#{},
|
||||
jsx:decode(<<"{}">>, [return_maps])
|
||||
jsx:decode(<<"{}">>, [])
|
||||
)},
|
||||
{"an empty map", ?_assertEqual(
|
||||
[{}],
|
||||
#{},
|
||||
jsx:decode(<<"{}">>, [])
|
||||
)},
|
||||
{"an empty map", ?_assertEqual(
|
||||
|
@ -432,18 +373,17 @@ return_maps_test_() ->
|
|||
)},
|
||||
{"a small map", ?_assertEqual(
|
||||
#{<<"awesome">> => true, <<"library">> => <<"jsx">>},
|
||||
jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, [return_maps])
|
||||
jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, [])
|
||||
)},
|
||||
{"a recursive map", ?_assertEqual(
|
||||
#{<<"key">> => #{<<"key">> => true}},
|
||||
jsx:decode(<<"{\"key\": {\"key\": true}}">>, [return_maps])
|
||||
jsx:decode(<<"{\"key\": {\"key\": true}}">>, [])
|
||||
)},
|
||||
{"a map inside a list", ?_assertEqual(
|
||||
[#{}],
|
||||
jsx:decode(<<"[{}]">>, [return_maps])
|
||||
jsx:decode(<<"[{}]">>, [])
|
||||
)}
|
||||
].
|
||||
-endif.
|
||||
|
||||
|
||||
handle_event_test_() ->
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue