From 2943116c08eb127f57879acb74d838f1b99e6b92 Mon Sep 17 00:00:00 2001 From: Ola Backstrom Date: Thu, 19 Sep 2013 17:04:38 +0200 Subject: [PATCH 01/20] Added typespecs on all exported functions Made sure all exported types do have a typespec is useful in build scenarios where the erlang compile options [warnings_as_errors, warn_missing_spec] are used. A few type errors found by Dialyzer are corrected too. modified: src/jsx.erl modified: src/jsx_config.erl modified: src/jsx_config.hrl modified: src/jsx_decoder.erl modified: src/jsx_parser.erl modified: src/jsx_to_json.erl modified: src/jsx_to_term.erl modified: src/jsx_verify.erl --- src/jsx.erl | 13 +++++++++++++ src/jsx_config.erl | 8 +++++++- src/jsx_config.hrl | 4 +++- src/jsx_decoder.erl | 4 ++-- src/jsx_parser.erl | 10 +++++++--- src/jsx_to_json.erl | 7 +++++-- src/jsx_to_term.erl | 5 +++++ src/jsx_verify.erl | 7 ++++++- 8 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/jsx.erl b/src/jsx.erl index dbf072b..fe48bc5 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -63,8 +63,14 @@ encode(Source, Config) -> jsx_to_json:to_json(Source, Config). %% old api, alias for encode/x +-spec to_json(Source::json_term()) -> json_text() | {incomplete, encoder()}. +-spec to_json(Source::json_term(), Config::jsx_to_json:config()) -> json_text() | {incomplete, encoder()}. + to_json(Source) -> encode(Source, []). to_json(Source, Config) -> encode(Source, Config). + +-spec term_to_json(Source::json_term()) -> json_text() | {incomplete, encoder()}. +-spec term_to_json(Source::json_term(), Config::jsx_to_json:config()) -> json_text() | {incomplete, encoder()}. term_to_json(Source) -> encode(Source, []). term_to_json(Source, Config) -> encode(Source, Config). @@ -94,8 +100,15 @@ decode(Source, Config) -> jsx_to_term:to_term(Source, Config). %% old api, alias for to_term/x +-spec to_term(Source::json_text()) -> json_term() | {incomplete, decoder()}. +-spec to_term(Source::json_text(), Config::jsx_to_term:config()) -> json_term() | {incomplete, decoder()}. + to_term(Source) -> decode(Source, []). to_term(Source, Config) -> decode(Source, Config). + +-spec json_to_term(Source::json_text()) -> json_term() | {incomplete, decoder()}. +-spec json_to_term(Source::json_text(), Config::jsx_to_term:config()) -> json_term() | {incomplete, decoder()}. + json_to_term(Source) -> decode(Source, []). json_to_term(Source, Config) -> decode(Source, Config). diff --git a/src/jsx_config.erl b/src/jsx_config.erl index 9c90aec..2113330 100644 --- a/src/jsx_config.erl +++ b/src/jsx_config.erl @@ -35,9 +35,12 @@ %% parsing of jsx config +-spec parse_config(Config::proplists:proplist()) -> config(). + parse_config(Config) -> parse_config(Config, #config{}). + parse_config([], Config) -> Config; parse_config([replaced_bad_utf8|Rest], Config) -> @@ -101,6 +104,7 @@ parse_config([ignore_bad_escapes|Rest], Config) -> parse_config(Options, Config) -> erlang:error(badarg, [Options, Config]). +-spec config_to_list(Config::config()) -> proplists:proplist(). config_to_list(Config) -> lists:map( @@ -115,6 +119,7 @@ config_to_list(Config) -> ) ). +-spec valid_flags() -> [atom()]. valid_flags() -> [ @@ -141,6 +146,7 @@ valid_flags() -> ignore_bad_escapes %% ignored_bad_escapes ]. +-spec extract_config(Config::proplists:proplist()) -> proplists:proplist(). extract_config(Config) -> extract_parser_config(Config, []). @@ -305,4 +311,4 @@ config_to_list_test_() -> fake_error_handler(_, _, _) -> ok. --endif. \ No newline at end of file +-endif. diff --git a/src/jsx_config.hrl b/src/jsx_config.hrl index 642dcf5..52c3ac4 100644 --- a/src/jsx_config.hrl +++ b/src/jsx_config.hrl @@ -11,4 +11,6 @@ pre_encode = false, error_handler = false, incomplete_handler = false -}). \ No newline at end of file +}). + +-type config() :: #config{}. diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index 18ce26a..4908f4b 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -48,7 +48,7 @@ decoder(Handler, State, Config) -> Acc::any(), Stack::list(atom()), Config::jsx:config() - ) -> jsx:decoder(). + ) -> jsx:decoder() | {incomplete, _}. resume(Rest, State, Handler, Acc, Stack, Config) -> case State of @@ -2097,4 +2097,4 @@ custom_incomplete_handler_test_() -> ]. --endif. \ No newline at end of file +-endif. diff --git a/src/jsx_parser.erl b/src/jsx_parser.erl index 85492a6..f3affaa 100644 --- a/src/jsx_parser.erl +++ b/src/jsx_parser.erl @@ -36,12 +36,12 @@ parser(Handler, State, Config) -> %% resume allows continuation from interrupted decoding without having to explicitly export %% all states -spec resume( - Rest::binary(), + Rest::list(), %% was binary(), State::atom(), Handler::{atom(), any()}, Stack::list(atom()), Config::jsx:config() - ) -> jsx:parser(). + ) -> jsx:parser() | {incomplete, _}. resume(Rest, State, Handler, Stack, Config) -> case State of @@ -208,8 +208,12 @@ clean_string(Bin, Tokens, Handler, Stack, Config) -> %% for raw input +-spec init(proplists:proplist()) -> list(). + init([]) -> []. +-spec handle_event(Event::any(), Acc::list()) -> list(). + handle_event(end_json, State) -> lists:reverse(State); handle_event(Event, State) -> [Event] ++ State. @@ -313,4 +317,4 @@ raw_test_() -> ]. --endif. \ No newline at end of file +-endif. diff --git a/src/jsx_to_json.erl b/src/jsx_to_json.erl index 177a32c..7e5aaf2 100644 --- a/src/jsx_to_json.erl +++ b/src/jsx_to_json.erl @@ -34,6 +34,7 @@ }). -type config() :: list(). +-export_type([config/0]). -spec to_json(Source::any(), Config::config()) -> binary(). @@ -85,10 +86,12 @@ parse_config([], Config) -> -define(newline, <<"\n">>). +-type state() :: {any(), unicode:charlist(), #config{}}. +-spec init(Config::proplists:proplist()) -> state(). init(Config) -> {start, [], parse_config(Config)}. - +-spec handle_event(Event::any(), State::state()) -> state(). handle_event(Event, {start, Acc, Config}) -> case Event of @@ -304,4 +307,4 @@ handle_event_test_() -> ]. --endif. \ No newline at end of file +-endif. diff --git a/src/jsx_to_term.erl b/src/jsx_to_term.erl index 52bc724..fad898a 100644 --- a/src/jsx_to_term.erl +++ b/src/jsx_to_term.erl @@ -33,6 +33,8 @@ }). -type config() :: list(). +-export_type([config/0]). + -type json_value() :: list({binary(), json_value()}) | list(json_value()) @@ -72,9 +74,12 @@ parse_config([K|Rest] = Options, Config) -> parse_config([], Config) -> Config. +-type state() :: {[any()], #config{}}. +-spec init(Config::proplists:proplist()) -> state(). init(Config) -> {[[]], parse_config(Config)}. +-spec handle_event(Event::any(), State::state()) -> state(). handle_event(end_json, {[[Terms]], _Config}) -> Terms; diff --git a/src/jsx_verify.erl b/src/jsx_verify.erl index 90251b3..34c50e5 100644 --- a/src/jsx_verify.erl +++ b/src/jsx_verify.erl @@ -32,6 +32,7 @@ }). -type config() :: []. +-export_type([config/0]). -spec is_json(Source::binary(), Config::config()) -> true | false. @@ -72,10 +73,14 @@ parse_config([K|Rest] = Options, Config) -> parse_config([], Config) -> Config. +-type state() :: {#config{}, any()}. +-spec init(Config::proplists:proplist()) -> state(). init(Config) -> {parse_config(Config), []}. +-spec handle_event(Event::any(), State::state()) -> state(). + handle_event(end_json, _) -> true; handle_event(_, {Config, _} = State) when Config#config.repeated_keys == true -> State; @@ -165,4 +170,4 @@ handle_event_test_() -> ]. --endif. \ No newline at end of file +-endif. From 06bb658e35eb2fe9b12e516b2daa39b402f69383 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Fri, 20 Sep 2013 22:02:14 -0700 Subject: [PATCH 02/20] formatting fixes cleanup line spacing --- src/jsx.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jsx.erl b/src/jsx.erl index fe48bc5..cbde6b6 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -71,6 +71,7 @@ to_json(Source, Config) -> encode(Source, Config). -spec term_to_json(Source::json_term()) -> json_text() | {incomplete, encoder()}. -spec term_to_json(Source::json_term(), Config::jsx_to_json:config()) -> json_text() | {incomplete, encoder()}. + term_to_json(Source) -> encode(Source, []). term_to_json(Source, Config) -> encode(Source, Config). From 377b47fdfb740b335d749d101e628372e7987cc9 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Fri, 20 Sep 2013 22:03:36 -0700 Subject: [PATCH 03/20] formatting fixes fix line spacing issues --- src/jsx_config.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jsx_config.erl b/src/jsx_config.erl index 2113330..b13750b 100644 --- a/src/jsx_config.erl +++ b/src/jsx_config.erl @@ -40,7 +40,6 @@ parse_config(Config) -> parse_config(Config, #config{}). - parse_config([], Config) -> Config; parse_config([replaced_bad_utf8|Rest], Config) -> @@ -104,6 +103,7 @@ parse_config([ignore_bad_escapes|Rest], Config) -> parse_config(Options, Config) -> erlang:error(badarg, [Options, Config]). + -spec config_to_list(Config::config()) -> proplists:proplist(). config_to_list(Config) -> @@ -119,6 +119,7 @@ config_to_list(Config) -> ) ). + -spec valid_flags() -> [atom()]. valid_flags() -> @@ -146,6 +147,7 @@ valid_flags() -> ignore_bad_escapes %% ignored_bad_escapes ]. + -spec extract_config(Config::proplists:proplist()) -> proplists:proplist(). extract_config(Config) -> From 58fbbb3bee9e0554a356c7ab3e7a3d8b9daad512 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Fri, 20 Sep 2013 22:13:01 -0700 Subject: [PATCH 04/20] update contributors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff4d670..5e7ecc0 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ following events must be handled: ## acknowledgements ## -jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [dmitry kolesnikov](https://github.com/fogfish) and [emptytea](https://github.com/emptytea) +jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe) and [patrick gombert](https://github.com/patrickgombert) [json]: http://json.org [yajl]: http://lloyd.github.com/yajl From 41fc97cf7a487c835468d270c006396c3d956aa4 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Fri, 20 Sep 2013 22:16:05 -0700 Subject: [PATCH 05/20] added more contributors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e7ecc0..dcf73a9 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ following events must be handled: ## acknowledgements ## -jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe) and [patrick gombert](https://github.com/patrickgombert) +jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [devin torres](https://github.com/devinus), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe) and [patrick gombert](https://github.com/patrickgombert) [json]: http://json.org [yajl]: http://lloyd.github.com/yajl From d06b64e4bd962a072e429d2119eab492f930bbbd Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Tue, 29 Oct 2013 19:41:30 +0000 Subject: [PATCH 06/20] replace incorrect boolean shortcircuits in multibyte escaping --- src/jsx_decoder.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index 18ce26a..83d16f2 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -658,12 +658,12 @@ unescape(<<$u, $d, A, B, C, ?rsolidus, $u, W, X, Y, Z, Rest/binary>>, Handler, A false -> ?error(<<$u, $d, A, B, C, ?rsolidus, $u, W, X, Y, Z, Rest/binary>>, Handler, Acc, Stack, Config) end; unescape(<<$u, $d, A, B, C, ?rsolidus, Rest/binary>>, Handler, Acc, Stack, Config) - when (A == $8 orelse A == $9 orelse A == $a orelse A == $b) andalso + when (A == $8 orelse A == $9 orelse A == $a orelse A == $b), ?is_hex(B), ?is_hex(C) -> incomplete(string, <>, Handler, Acc, Stack, Config); unescape(<<$u, $d, A, B, C>>, Handler, Acc, Stack, Config) - when (A == $8 orelse A == $9 orelse A == $a orelse A == $b) andalso + when (A == $8 orelse A == $9 orelse A == $a orelse A == $b), ?is_hex(B), ?is_hex(C) -> incomplete(string, <>, Handler, Acc, Stack, Config); From 53e44d1a89323c2d2b27337bdc0e7afc12cd4e8f Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Tue, 29 Oct 2013 19:47:30 +0000 Subject: [PATCH 07/20] update CHANGES for 1.4.4 --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index a49bb21..a039824 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +v1.4.4 + +* typespec for `json_term/0` fixed +* incorrect boolean shortcircuiting fixed in multibyte escape processing + v1.4.3 * add empty rebar.config for mix build tool From 6b189d35d3ec22902f991c80155ede2c2ed6675d Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Tue, 29 Oct 2013 19:47:55 +0000 Subject: [PATCH 08/20] update to 1.4.4 --- README.md | 2 +- src/jsx.app.src | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff4d670..38fb0f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# jsx (v1.4.3) # +# jsx (v1.4.4) # an erlang application for consuming, producing and manipulating [json][json]. inspired by [yajl][yajl] diff --git a/src/jsx.app.src b/src/jsx.app.src index 3837287..b71593d 100644 --- a/src/jsx.app.src +++ b/src/jsx.app.src @@ -1,7 +1,7 @@ {application, jsx, [ {description, "a streaming, evented json parsing toolkit"}, - {vsn, "1.4.3"}, + {vsn, "1.4.4"}, {modules, [ jsx, jsx_encoder, From 30b136ce72f65f347b6d5a35db4ba7fb3d24aa03 Mon Sep 17 00:00:00 2001 From: Michael Truog Date: Fri, 22 Nov 2013 19:22:01 -0800 Subject: [PATCH 09/20] Fix dialyzer errors. --- src/jsx.erl | 6 ++++-- src/jsx_config.erl | 16 ++++++++++++++-- src/jsx_config.hrl | 25 ++++++++++++------------- src/jsx_decoder.erl | 4 ++-- src/jsx_encoder.erl | 2 +- src/jsx_parser.erl | 10 +++++----- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/jsx.erl b/src/jsx.erl index cbde6b6..918151e 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -34,13 +34,15 @@ -export([to_term/1, to_term/2]). -export_type([json_term/0, json_text/0, token/0]). --export_type([encoder/0, decoder/0, parser/0, internal_state/0]). +-export_type([config/0, encoder/0, decoder/0, parser/0, internal_state/0]). +-include("jsx_config.hrl"). -ifdef(TEST). -include("jsx_tests.hrl"). -endif. +-type config() :: #config{}. -type json_term() :: [{binary() | atom(), json_term()}] @@ -54,7 +56,6 @@ -type json_text() :: binary(). - -spec encode(Source::json_term()) -> json_text() | {incomplete, encoder()}. -spec encode(Source::json_term(), Config::jsx_to_json:config()) -> json_text() | {incomplete, encoder()}. @@ -178,3 +179,4 @@ resume(Term, {decoder, State, Handler, Acc, Stack}, Config) -> jsx_decoder:resume(Term, State, Handler, Acc, Stack, jsx_config:parse_config(Config)); resume(Term, {parser, State, Handler, Stack}, Config) -> jsx_parser:resume(Term, State, Handler, Stack, jsx_config:parse_config(Config)). + diff --git a/src/jsx_config.erl b/src/jsx_config.erl index b13750b..e5f8622 100644 --- a/src/jsx_config.erl +++ b/src/jsx_config.erl @@ -33,9 +33,21 @@ -include("jsx_config.hrl"). +-type handler_type(Handler) :: + fun((jsx:json_text() | end_stream | + jsx:json_term(), + {decoder, any(), module(), null | list(), list()} | + {parser, any(), module(), list()} | + {encoder, any(), module()}, + list({pre_encode, fun((any()) -> any())} | + {error_handler, Handler} | + {incomplete_handler, Handler} | + atom())) -> any()). +-type handler() :: handler_type(handler()). +-export_type([handler/0]). %% parsing of jsx config --spec parse_config(Config::proplists:proplist()) -> config(). +-spec parse_config(Config::proplists:proplist()) -> jsx:config(). parse_config(Config) -> parse_config(Config, #config{}). @@ -104,7 +116,7 @@ parse_config(Options, Config) -> erlang:error(badarg, [Options, Config]). --spec config_to_list(Config::config()) -> proplists:proplist(). +-spec config_to_list(Config::jsx:config()) -> proplists:proplist(). config_to_list(Config) -> lists:map( diff --git a/src/jsx_config.hrl b/src/jsx_config.hrl index 52c3ac4..baa1384 100644 --- a/src/jsx_config.hrl +++ b/src/jsx_config.hrl @@ -1,16 +1,15 @@ -record(config, { - replaced_bad_utf8 = false, - escaped_forward_slashes = false, - single_quoted_strings = false, - unescaped_jsonp = false, - comments = false, - escaped_strings = false, - dirty_strings = false, - ignored_bad_escapes = false, - explicit_end = false, - pre_encode = false, - error_handler = false, - incomplete_handler = false + replaced_bad_utf8 = false :: boolean(), + escaped_forward_slashes = false :: boolean(), + single_quoted_strings = false :: boolean(), + unescaped_jsonp = false :: boolean(), + comments = false :: boolean(), + escaped_strings = false :: boolean(), + dirty_strings = false :: boolean(), + ignored_bad_escapes = false :: boolean(), + explicit_end = false :: boolean(), + pre_encode = false :: false | fun((any()) -> any()), + error_handler = false :: false | jsx_config:handler(), + incomplete_handler = false :: false | jsx_config:handler() }). --type config() :: #config{}. diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index d4f5357..a94c08d 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -33,7 +33,7 @@ -export([decoder/3, resume/6]). --spec decoder(Handler::module(), State::any(), Config::jsx:config()) -> jsx:decoder(). +-spec decoder(Handler::module(), State::any(), Config::list()) -> jsx:decoder(). decoder(Handler, State, Config) -> fun(JSON) -> start(JSON, {Handler, Handler:init(State)}, [], jsx_config:parse_config(Config)) end. @@ -48,7 +48,7 @@ decoder(Handler, State, Config) -> Acc::any(), Stack::list(atom()), Config::jsx:config() - ) -> jsx:decoder() | {incomplete, _}. + ) -> jsx:decoder() | {incomplete, jsx:decoder()}. resume(Rest, State, Handler, Acc, Stack, Config) -> case State of diff --git a/src/jsx_encoder.erl b/src/jsx_encoder.erl index 05403d3..9d26464 100644 --- a/src/jsx_encoder.erl +++ b/src/jsx_encoder.erl @@ -25,7 +25,7 @@ -export([encoder/3]). --spec encoder(Handler::module(), State::any(), Config::jsx:config()) -> jsx:encoder(). +-spec encoder(Handler::module(), State::any(), Config::list()) -> jsx:encoder(). encoder(Handler, State, Config) -> fun(JSON) -> diff --git a/src/jsx_parser.erl b/src/jsx_parser.erl index f3affaa..4e6a9a0 100644 --- a/src/jsx_parser.erl +++ b/src/jsx_parser.erl @@ -27,7 +27,7 @@ -export([init/1, handle_event/2]). --spec parser(Handler::module(), State::any(), Config::jsx:config()) -> jsx:parser(). +-spec parser(Handler::module(), State::any(), Config::list()) -> jsx:parser(). parser(Handler, State, Config) -> fun(Tokens) -> value(Tokens, {Handler, Handler:init(State)}, [], jsx_config:parse_config(Config)) end. @@ -36,12 +36,12 @@ parser(Handler, State, Config) -> %% resume allows continuation from interrupted decoding without having to explicitly export %% all states -spec resume( - Rest::list(), %% was binary(), + Rest::jsx:token(), State::atom(), Handler::{atom(), any()}, Stack::list(atom()), Config::jsx:config() - ) -> jsx:parser() | {incomplete, _}. + ) -> jsx:parser() | {incomplete, jsx:parser()}. resume(Rest, State, Handler, Stack, Config) -> case State of @@ -82,8 +82,8 @@ incomplete(State, Handler, Stack, Config=#config{incomplete_handler=F}) -> F([], {parser, State, Handler, Stack}, jsx_config:config_to_list(Config)). -handle_event([], Handler, _Config) -> Handler; -handle_event([Event|Rest], Handler, Config) -> handle_event(Rest, handle_event(Event, Handler, Config), Config); +%handle_event([], Handler, _Config) -> Handler; +%handle_event([Event|Rest], Handler, Config) -> handle_event(Rest, handle_event(Event, Handler, Config), Config); handle_event(Event, {Handler, State}, _Config) -> {Handler, Handler:handle_event(Event, State)}. From e31e9c4daad0d78bddd1b4a585e304fdd2d9ad83 Mon Sep 17 00:00:00 2001 From: Michael Truog Date: Mon, 25 Nov 2013 09:30:04 -0800 Subject: [PATCH 10/20] Fix include file issue, when using eunit. --- src/jsx.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jsx.erl b/src/jsx.erl index 918151e..5b7c821 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -37,9 +37,10 @@ -export_type([config/0, encoder/0, decoder/0, parser/0, internal_state/0]). --include("jsx_config.hrl"). -ifdef(TEST). -include("jsx_tests.hrl"). +-else. +-include("jsx_config.hrl"). -endif. -type config() :: #config{}. From 216b97df550b2a2bfca78ae378e42a47f11274b6 Mon Sep 17 00:00:00 2001 From: Max Lapshin Date: Tue, 19 Nov 2013 14:05:51 +0400 Subject: [PATCH 11/20] handle jsx:encode([{key,value}]) --- src/jsx_encoder.erl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/jsx_encoder.erl b/src/jsx_encoder.erl index 9d26464..b854e8d 100644 --- a/src/jsx_encoder.erl +++ b/src/jsx_encoder.erl @@ -68,6 +68,8 @@ value(Int, {Handler, State}, _Config) when is_integer(Int) -> value(Literal, {Handler, State}, _Config) when Literal == true; Literal == false; Literal == null -> Handler:handle_event({literal, Literal}, State); +value(String, {Handler, State}, Config) when is_atom(String) -> + Handler:handle_event({string, clean_string(atom_to_binary(String,latin1), {Handler, State}, Config)}, State); value([{}], {Handler, State}, _Config) -> Handler:handle_event(end_object, Handler:handle_event(start_object, State)); value([], {Handler, State}, _Config) -> @@ -163,6 +165,7 @@ encode(Term, Config) -> start(Term, {jsx, []}, jsx_config:parse_config(Config)). pre_encoders_test_() -> Term = [ {<<"object">>, [ + {atomkey, atomvalue}, {<<"literals">>, [true, false, null]}, {<<"strings">>, [<<"foo">>, <<"bar">>, <<"baz">>]}, {<<"numbers">>, [1, 1.0, 1.0e0]} @@ -173,6 +176,7 @@ pre_encoders_test_() -> [ start_object, {key, <<"object">>}, start_object, + {key, <<"atomkey">>}, {string, <<"atomvalue">>}, {key, <<"literals">>}, start_array, {literal, true}, {literal, false}, {literal, null}, end_array, @@ -192,6 +196,7 @@ pre_encoders_test_() -> [ start_object, {key, <<"object">>}, start_object, + {key, <<"atomkey">>}, {string, <<"atomvalue">>}, {key, <<"literals">>}, start_array, end_array, {key, <<"strings">>}, start_array, end_array, {key, <<"numbers">>}, start_array, end_array, @@ -213,6 +218,7 @@ pre_encoders_test_() -> [ start_object, {key, <<"object">>}, start_object, + {key, <<"atomkey">>}, {literal, false}, {key, <<"literals">>}, start_array, {literal, false}, {literal, false}, {literal, false}, end_array, @@ -232,6 +238,7 @@ pre_encoders_test_() -> [ start_object, {key, <<"object">>}, start_object, + {key, <<"atomkey">>}, {string, <<"atomvalue">>}, {key, <<"literals">>}, start_array, {string, <<"true">>}, {string, <<"false">>}, {string, <<"null">>}, end_array, From 123965166a2283afd2e2b8dcdcc39b66e6020bf2 Mon Sep 17 00:00:00 2001 From: eskuat Date: Sun, 8 Dec 2013 00:18:29 +0700 Subject: [PATCH 12/20] Allow integer object keys when converting term to json i.e. automatic conversion from integer to binary. --- src/jsx_encoder.erl | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/jsx_encoder.erl b/src/jsx_encoder.erl index 9d26464..4bc0852 100644 --- a/src/jsx_encoder.erl +++ b/src/jsx_encoder.erl @@ -79,14 +79,14 @@ value(Term, Handler, Config) -> ?error(value, Term, Handler, Config). list_or_object([Term|Rest], {Handler, State}, Config) -> case pre_encode(Term, Config) of - {K, V} when is_atom(K); is_binary(K) -> + {K, V} when is_atom(K); is_binary(K); is_integer(K) -> object([{K, V}|Rest], {Handler, Handler:handle_event(start_object, State)}, Config) ; T -> list([T|Rest], {Handler, Handler:handle_event(start_array, State)}, Config) end. -object([{Key, Value}, Next|Rest], {Handler, State}, Config) when is_atom(Key); is_binary(Key) -> +object([{Key, Value}, Next|Rest], {Handler, State}, Config) when is_atom(Key); is_binary(Key); is_integer(Key) -> V = pre_encode(Value, Config), object( [pre_encode(Next, Config)|Rest], @@ -100,7 +100,7 @@ object([{Key, Value}, Next|Rest], {Handler, State}, Config) when is_atom(Key); i }, Config ); -object([{Key, Value}], {Handler, State}, Config) when is_atom(Key); is_binary(Key) -> +object([{Key, Value}], {Handler, State}, Config) when is_atom(Key); is_binary(Key); is_integer(Key) -> object( [], { @@ -128,6 +128,7 @@ pre_encode(Value, Config) -> (Config#config.pre_encode)(Value). fix_key(Key) when is_atom(Key) -> fix_key(atom_to_binary(Key, utf8)); +fix_key(Key) when is_integer(Key) -> fix_key(integer_to_binary(Key)); fix_key(Key) when is_binary(Key) -> Key. @@ -304,4 +305,22 @@ custom_error_handler_test_() -> )} ]. +integer_key_test_() -> + Term = [{123, [{456, 789}]}], + [ + {"basic integer keys", ?_assertEqual( + [ + start_object, + {key, <<"123">>}, + start_object, + {key, <<"456">>}, + {integer, 789}, + end_object, + end_object, + end_json + ], + encode(Term, []) + )} + ]. + -endif. From 71646247f9ac7d45b6b5f92ef9fdd5340caeb78d Mon Sep 17 00:00:00 2001 From: eskuat Date: Sun, 8 Dec 2013 02:36:01 +0700 Subject: [PATCH 13/20] Use of list_to_binary/integer_to_list for compat with earlier Erlang versions --- src/jsx_encoder.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsx_encoder.erl b/src/jsx_encoder.erl index 4bc0852..01afbb5 100644 --- a/src/jsx_encoder.erl +++ b/src/jsx_encoder.erl @@ -128,7 +128,7 @@ pre_encode(Value, Config) -> (Config#config.pre_encode)(Value). fix_key(Key) when is_atom(Key) -> fix_key(atom_to_binary(Key, utf8)); -fix_key(Key) when is_integer(Key) -> fix_key(integer_to_binary(Key)); +fix_key(Key) when is_integer(Key) -> fix_key(list_to_binary(integer_to_list(Key))); fix_key(Key) when is_binary(Key) -> Key. From 3f218774f17eb0e1cc70e9a5a58ee544aa53cf15 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:16:43 -0800 Subject: [PATCH 14/20] add eskuat to contributors section of README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ae355db..bd75ec1 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ following events must be handled: ## acknowledgements ## -jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [devin torres](https://github.com/devinus), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe) and [patrick gombert](https://github.com/patrickgombert) +jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [devin torres](https://github.com/devinus), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe), [patrick gombert](https://github.com/patrickgombert) and [eskuat](https://github.com/eskuat) [json]: http://json.org [yajl]: http://lloyd.github.com/yajl From cc9d05bbb6ac7490418b4a8d942658d28f3d2b00 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:18:24 -0800 Subject: [PATCH 15/20] document integers as keys change to api in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bd75ec1..767120e 100644 --- a/README.md +++ b/README.md @@ -211,9 +211,9 @@ real_json(_) -> erlang:error(badarg). 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 (which will be escaped - and converted to binaries for presentation to handlers). values should be - valid json values + 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 ### incomplete input ### From d7016c6cc5b63343d76f7252b98f167a8775b33d Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:20:30 -0800 Subject: [PATCH 16/20] add typespec changes and integer keys to CHANGES --- CHANGES.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index a039824..06c27b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +v1.4.5 + +* various fixes to typespecs uncovered by dialyzer +* allow integer keys during encoding + v1.4.4 * typespec for `json_term/0` fixed @@ -77,4 +82,4 @@ v1.0.2 v1.0.1 -* rebar fix \ No newline at end of file +* rebar fix From 8c826e7239b95d60c70bbb4dcbf26e1a7b6dcdfc Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:23:01 -0800 Subject: [PATCH 17/20] add max lapshin to contributors section of README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 767120e..fa59097 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ following events must be handled: ## acknowledgements ## -jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [devin torres](https://github.com/devinus), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe), [patrick gombert](https://github.com/patrickgombert) and [eskuat](https://github.com/eskuat) +jsx wouldn't be what it is without the contributions of [paul davis](https://github.com/davisp), [lloyd hilaiel](https://github.com/lloyd), [john engelhart](https://github.com/johnezang), [bob ippolito](https://github.com/etrepum), [fernando benavides](https://github.com/elbrujohalcon), [alex kropivny](https://github.com/amtal), [steve strong](https://github.com/srstrong), [michael truog](https://github.com/okeuday), [devin torres](https://github.com/devinus), [dmitry kolesnikov](https://github.com/fogfish), [emptytea](https://github.com/emptytea), [john daily](https://github.com/macintux), [ola bäckström](https://github.com/olabackstrom), [joseph crowe](https://github.com/JosephCrowe), [patrick gombert](https://github.com/patrickgombert), [eskuat](https://github.com/eskuat) and [max lapshin](https://github.com/maxlapshin) [json]: http://json.org [yajl]: http://lloyd.github.com/yajl From 1daab2afc1aa620ee3babbd88bde96d2959d06e4 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:29:38 -0800 Subject: [PATCH 18/20] include details of atoms as strings in README --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index fa59097..13e2af0 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ real_json(_) -> erlang:error(badarg). **json** | **erlang** --------------------------------|-------------------------------- `number` | `integer()` and `float()` -`string` | `binary()` +`string` | `binary()` and `atom()` `true`, `false` and `null` | `true`, `false` and `null` `array` | `[]` and `[JSON]` `object` | `[{}]` and `[{binary() OR atom(), JSON}]` @@ -166,7 +166,13 @@ real_json(_) -> erlang:error(badarg). * strings - the json [spec][rfc4627] is frustratingly vague on the exact details of json + all erlang strings are represented by **valid** `utf8` encoded binaries or + atoms. note that the atoms `true`, `false` and `null` will never be + automatically converted to strings as the json equivalent values take + precedence. when decoding json strings will always be presented as binaries, + never atoms + + the [json spec][rfc4627] is frustratingly vague on the exact details of json strings. json must be unicode, but no encoding is specified. javascript explicitly allows strings containing codepoints explicitly disallowed by unicode. json allows implementations to set limits on the content of @@ -178,7 +184,8 @@ real_json(_) -> erlang:error(badarg). the utf8 restriction means improperly paired surrogates are explicitly disallowed. `u+d800` to `u+dfff` are allowed, but only when they form valid - surrogate pairs. surrogates encountered otherwise result in errors + surrogate pairs. surrogates encountered otherwise result in errors. the + noncharacters will also result in errors json string escapes of the form `\uXXXX` will be converted to their equivalent codepoints during parsing. this means control characters and @@ -186,11 +193,6 @@ real_json(_) -> erlang:error(badarg). strings, but codepoints disallowed by the unicode spec will not be. in the interest of pragmatism there is an [option](#option) for looser parsing - all erlang strings are represented by **valid** `utf8` encoded binaries. the - encoder will check strings for conformance. noncharacters (like `u+ffff`) - are allowed in erlang utf8 encoded binaries, but not in strings passed to - the encoder (although, again, see [options](#option)) - this implementation performs no normalization on strings beyond that detailed here. be careful when comparing strings as equivalent strings may have different `utf8` encodings @@ -249,6 +251,7 @@ json_term() = [json_term()] | integer() | float() | binary() + | atom() ``` the erlang representation of json. binaries should be `utf8` encoded, or close From 9a36b774aee1b3a115a04caf7612ff6fed943cb5 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:30:26 -0800 Subject: [PATCH 19/20] include details of atoms as strings in CHANGES --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 06c27b6..438b7dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ v1.4.5 * various fixes to typespecs uncovered by dialyzer * allow integer keys during encoding +* convert atoms (other than `true`, `false` and `null`) to strings during encoding v1.4.4 From 123f8208d00c2df7b86df71732f428b720c71b98 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 12 Dec 2013 11:31:38 -0800 Subject: [PATCH 20/20] add atom to values allowed in to be encoded terms --- src/jsx.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jsx.erl b/src/jsx.erl index 5b7c821..80d2ef4 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -53,7 +53,8 @@ | null | integer() | float() - | binary(). + | binary() + | atom(). -type json_text() :: binary().