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
33
.github/workflows/main.yml
vendored
Normal file
33
.github/workflows/main.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: EUnit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Test on OTP ${{ matrix.otp_version }} and ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
# important to check a pre-23 version that still uses nodetool
|
||||
# plus 23 once it is released
|
||||
otp_version: [22.3.2]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: gleam-lang/setup-erlang@v1.0.0
|
||||
with:
|
||||
otp-version: ${{ matrix.otp_version }}
|
||||
|
||||
- name: compile
|
||||
run: rebar3 compile
|
||||
|
||||
- name: test
|
||||
run: rebar3 eunit
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
.rebar3
|
||||
.eunit
|
||||
deps
|
||||
ebin
|
||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -1,10 +0,0 @@
|
|||
language: erlang
|
||||
script: rebar compile && rebar skip_deps=true eunit
|
||||
otp_release:
|
||||
- 22.0.7
|
||||
- 21.3.3
|
||||
- 20.3
|
||||
- 19.3
|
||||
- 18.3
|
||||
- 17.5
|
||||
- R16B03-1
|
|
@ -1,3 +1,8 @@
|
|||
v3.0
|
||||
|
||||
* drop support for OTP versions before 17.0
|
||||
* remove definition options for disabling maps globally, `{return_maps, false}` is still an accepted option to `decode/2`
|
||||
|
||||
v2.8.2
|
||||
|
||||
* enable `debug_info` for rebar3
|
||||
|
|
92
README.md
92
README.md
|
@ -1,23 +1,17 @@
|
|||
# jsx (v2.9.0) #
|
||||
# jsx (v3.0.0) #
|
||||
|
||||
|
||||
an erlang application for consuming, producing and manipulating [json][json].
|
||||
inspired by [yajl][yajl]
|
||||
|
||||
**jsx** is built via [rebar3][rebar3], [rebar][rebar] or [mix][mix] and continuous integration testing provided courtesy [travis-ci][travis]
|
||||
**jsx** is built via [rebar3][rebar3]
|
||||
|
||||
current status: [](http://travis-ci.org/talentdeficit/jsx)
|
||||
current status: 
|
||||
|
||||
**jsx** is released under the terms of the [MIT][MIT] license
|
||||
|
||||
copyright 2010-2016 alisdair sullivan
|
||||
|
||||
## really important note ##
|
||||
|
||||
there are a few changes for users upgrading from 1.x. see [CHANGES.md](CHANGES.md)
|
||||
for the overview or [migrating from 1.x](#migrating) for the details
|
||||
|
||||
|
||||
## index ##
|
||||
|
||||
* [quickstart](#quickstart)
|
||||
|
@ -39,7 +33,6 @@ for the overview or [migrating from 1.x](#migrating) for the details
|
|||
- [`prettify/1`](#prettify1)
|
||||
- [`is_json/1,2`](#is_json12)
|
||||
- [`is_term/1,2`](#is_term12)
|
||||
- [`maps_support/0`](#maps_support0)
|
||||
* [callback exports](#callback_exports)
|
||||
- [`Module:init/1`](#moduleinit1)
|
||||
- [`Module:handle_event/2`](#modulehandle_event2)
|
||||
|
@ -55,7 +48,7 @@ Add to `rebar.config`
|
|||
{erl_opts, [debug_info]}.
|
||||
{deps, [
|
||||
...
|
||||
{jsx, {git, "https://github.com/talentdeficit/jsx.git", {branch, "v2.8.0"}}}
|
||||
{jsx, "~> 3.0"}
|
||||
]}.
|
||||
...
|
||||
```
|
||||
|
@ -65,19 +58,15 @@ Add to `rebar.config`
|
|||
```bash
|
||||
$ rebar3 compile
|
||||
$ rebar3 eunit
|
||||
$ rebar compile
|
||||
$ rebar eunit
|
||||
$ mix compile
|
||||
$ mix eunit
|
||||
```
|
||||
|
||||
#### to convert a utf8 binary containing a json string into an erlang term ####
|
||||
|
||||
```erlang
|
||||
1> jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>).
|
||||
[{<<"library">>,<<"jsx">>},{<<"awesome">>,true}]
|
||||
2> jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, [return_maps]).
|
||||
1> jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, []).
|
||||
#{<<"awesome">> => true,<<"library">> => <<"jsx">>}
|
||||
2> jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, [{return_maps, false}]).
|
||||
[{<<"library">>,<<"jsx">>},{<<"awesome">>,true}]
|
||||
3> jsx:decode(<<"[\"a\",\"list\",\"of\",\"words\"]">>).
|
||||
[<<"a">>, <<"list">>, <<"of">>, <<"words">>]
|
||||
```
|
||||
|
@ -85,10 +74,10 @@ $ mix eunit
|
|||
#### to convert an erlang term into a utf8 binary containing a json string ####
|
||||
|
||||
```erlang
|
||||
1> jsx:encode([{<<"library">>,<<"jsx">>},{<<"awesome">>,true}]).
|
||||
<<"{\"library\": \"jsx\", \"awesome\": true}">>
|
||||
2> jsx:encode(#{<<"library">> => <<"jsx">>, <<"awesome">> => true}).
|
||||
1> jsx:encode(#{<<"library">> => <<"jsx">>, <<"awesome">> => true}).
|
||||
<<"{\"awesome\":true,\"library\":\"jsx\"}">>
|
||||
2> jsx:encode([{<<"library">>,<<"jsx">>},{<<"awesome">>,true}]).
|
||||
<<"{\"library\": \"jsx\", \"awesome\": true}">>
|
||||
3> jsx:encode([<<"a">>, <<"list">>, <<"of">>, <<"words">>]).
|
||||
<<"[\"a\",\"list\",\"of\",\"words\"]">>
|
||||
```
|
||||
|
@ -132,13 +121,6 @@ false
|
|||
}">>
|
||||
```
|
||||
|
||||
#### to compile **jsx** so that it always decodes json objects to maps ####
|
||||
|
||||
```bash
|
||||
$ JSX_FORCE_MAPS rebar3 compile
|
||||
$ JSX_FORCE_MAPS mix compile
|
||||
```
|
||||
|
||||
## description ##
|
||||
|
||||
|
||||
|
@ -172,29 +154,6 @@ quotes but must end with single quotes and must escape any single quotes they co
|
|||
json and **jsx** only recognize escape sequences as outlined in the json spec. it just
|
||||
ignores bad escape sequences leaving them in strings unaltered
|
||||
|
||||
|
||||
### migrating from 1.x ###
|
||||
|
||||
if you're migrating from jsx v1.x to v2.x in most cases you won't need to
|
||||
make any changes to your code
|
||||
|
||||
support for otp 17.0's new map type is now enabled by default when compiling
|
||||
via rebar for any release that supports them. jsx should still compile cleanly for
|
||||
earlier releases without any user intervention
|
||||
|
||||
if you used any of `replaced_bad_utf8`, `single_quoted_strings`, `comments`,
|
||||
`ignored_bad_escapes` or `relax` you can simply omit them from your calls to jsx,
|
||||
they are all enabled by default now. if you want stricter parsing see the new
|
||||
[`strict` options](#option) available
|
||||
|
||||
if you were using jsx to parse partial json using it's streaming features it is now
|
||||
disabled by default. you'll need to pass the `stream` option to calls to jsx functions
|
||||
to reenable it
|
||||
|
||||
support for `pre_encode` and `post_decode` has been removed. they were fragile and hard
|
||||
to understand and they prevented evolution of the encoding and decoding code
|
||||
|
||||
|
||||
### json <-> erlang mapping ###
|
||||
|
||||
**json** | **erlang**
|
||||
|
@ -261,18 +220,7 @@ see below | `datetime()`
|
|||
|
||||
* objects
|
||||
|
||||
json objects are represented by erlang proplists. json maps may also be
|
||||
encoded to json and optionally decoded to maps (via the `return_maps`
|
||||
option)
|
||||
|
||||
the empty object has the special representation `[{}]` to differentiate it
|
||||
from the empty list. ambiguities like `[true, false]` prevent the use of
|
||||
the shorthand form of property lists using atoms as properties so all
|
||||
properties must be tuples. all keys must be encoded as in `string` or as
|
||||
atoms or integers (which will be escaped and converted to binaries for
|
||||
presentation to handlers). values should be valid json values. repeated
|
||||
keys are tolerated in json text decoded to erlang terms but are not allowed
|
||||
in erlang terms encoded to json
|
||||
json objects are represented by erlang maps.
|
||||
|
||||
* datetime
|
||||
|
||||
|
@ -533,9 +481,8 @@ new atoms to the atom table and will result in a `badarg` error if the atom
|
|||
does not exist. `attempt_atom` will convert keys to atoms when they exist,
|
||||
and leave them as binary otherwise
|
||||
|
||||
the option `return_maps` will attempt to return objects as maps instead of
|
||||
proplists. this option has no effect when used with releases that do not
|
||||
support maps
|
||||
the option `{return_maps, false}` will return objects as proplists instead
|
||||
of maps.
|
||||
|
||||
raises a `badarg` error exception if input is not valid json
|
||||
|
||||
|
@ -650,17 +597,6 @@ returns true if input is a valid erlang representation of json, false if not
|
|||
|
||||
what exactly constitutes valid json may be altered via [options](#option)
|
||||
|
||||
|
||||
#### `maps_support/0` ####
|
||||
|
||||
```erlang
|
||||
maps_support() -> true | false
|
||||
```
|
||||
|
||||
if **jsx** was compiled with map support enabled returns `true`, else
|
||||
`false`
|
||||
|
||||
|
||||
## callback exports ##
|
||||
|
||||
the following functions should be exported from a **jsx** callback module
|
||||
|
@ -753,8 +689,6 @@ jsx wouldn't be what it is without the contributions of [Paul J. Davis](https://
|
|||
[yajl]: http://lloyd.github.com/yajl
|
||||
[MIT]: http://www.opensource.org/licenses/mit-license.html
|
||||
[rebar3]: https://rebar3.org
|
||||
[rebar]: https://github.com/rebar/rebar
|
||||
[mix]: http://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html
|
||||
[meck]: https://github.com/eproxus/meck
|
||||
[rfc4627]: http://tools.ietf.org/html/rfc4627
|
||||
[travis]: https://travis-ci.org/
|
||||
|
|
43
mix.exs
43
mix.exs
|
@ -1,43 +0,0 @@
|
|||
defmodule JSX.Mixfile do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :jsx,
|
||||
version: "2.11.0",
|
||||
description: "an erlang application for consuming, producing and manipulating json. inspired by yajl",
|
||||
deps: deps(Mix.env),
|
||||
package: package(),
|
||||
language: :erlang,
|
||||
erlc_options: opts(Mix.env)
|
||||
]
|
||||
end
|
||||
|
||||
defp opts(:dev), do: [d: :TEST] ++ opts(:prod)
|
||||
defp opts(_) do
|
||||
force_maps = case System.get_env("JSX_FORCE_MAPS") do
|
||||
nil -> []
|
||||
_ -> [d: :maps_always]
|
||||
end
|
||||
[:debug_info, d: :maps_support] ++ force_maps
|
||||
end
|
||||
|
||||
defp deps(_), do: [{:mixunit, "~> 0.9.2", only: :dev}]
|
||||
|
||||
defp package do
|
||||
[
|
||||
files: [
|
||||
"CHANGES.md",
|
||||
"LICENSE",
|
||||
"mix.exs",
|
||||
"rebar.config",
|
||||
"rebar.config.script",
|
||||
"README.md",
|
||||
"src"
|
||||
],
|
||||
contributors: ["alisdair sullivan"],
|
||||
links: %{"github" => "https://github.com/talentdeficit/jsx"},
|
||||
licenses: ["MIT"]
|
||||
]
|
||||
end
|
||||
end
|
1
mix.lock
1
mix.lock
|
@ -1 +0,0 @@
|
|||
%{"mixunit": {:hex, :mixunit, "0.9.2"}}
|
|
@ -1,15 +0,0 @@
|
|||
Def0 = case erlang:is_builtin(erlang, binary_to_integer, 1) andalso
|
||||
erlang:is_builtin(erlang, binary_to_float, 1) of
|
||||
true -> [];
|
||||
false -> [{d, no_binary_to_whatever}]
|
||||
end,
|
||||
Def1 = case erlang:is_builtin(erlang, is_map, 1) of
|
||||
true -> [{d, maps_support}|Def0];
|
||||
false -> Def0
|
||||
end,
|
||||
Defs = case os:getenv("JSX_FORCE_MAPS") of
|
||||
false -> Def1;
|
||||
_ -> [{d, maps_always}|Def1]
|
||||
end,
|
||||
lists:keystore(erl_opts, 1, CONFIG,
|
||||
{erl_opts, proplists:get_value(erl_opts, CONFIG, []) ++ Defs}).
|
|
@ -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