Skip to content

Commit

Permalink
Revert to allow any term in encodable type.
Browse files Browse the repository at this point in the history
* Moved the plain JSON types to the top.
* Added type `str` to have a complete set of plain JSON types.
* Refer to options either as encoder or decoder options.
* Renamed some types to include a clarifying enc_/dec_ prefix.
  • Loading branch information
azizk committed Mar 9, 2024
1 parent 53fe6ba commit 978b27b
Showing 1 changed file with 36 additions and 25 deletions.
61 changes: 36 additions & 25 deletions lib/jason.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,47 @@ defmodule Jason do

alias Jason.{Encode, Decoder, DecodeError, EncodeError, Formatter}

@typedoc "Encoding setting for string escapes."
@type escape :: :json | :unicode_safe | :html_safe | :javascript_safe
@typedoc "Encoding setting for maps."
@type maps :: :naive | :strict
@typedoc "Available encoding options."
@type encode_opt :: {:escape, escape} | {:maps, maps} | {:pretty, boolean | Formatter.opts()}
@typedoc "A plain JSON string."
@type str :: String.t()
@typedoc "A plain JSON object where keys can only be strings."
@type object :: %{optional(str) => value}
@typedoc "A plain JSON array with JSON element values."
@type array :: [value]
@typedoc "A plain JSON value. Meaningful for specs where it's certain that nothing else is contained."
@type value :: nil | str | number | boolean | array | object

@typedoc "Encoder setting for string escapes."
@type enc_escape :: :json | :unicode_safe | :html_safe | :javascript_safe
@typedoc "Encoder setting for maps."
@type enc_maps :: :naive | :strict
@typedoc "Available encoder options."
@type encode_opt ::
{:escape, enc_escape} | {:maps, enc_maps} | {:pretty, boolean | Formatter.opts()}

@typedoc "The type of the value returned by the custom decoder function."
@type map_key :: term
@type dec_map_key :: term
@typedoc "Decoding setting for map keys."
@type keys :: :atoms | :atoms! | :strings | :copy | (key :: String.t() -> map_key)
@type dec_keys :: :atoms | :atoms! | :strings | :copy | (key :: str -> dec_map_key)
@typedoc "Decoding setting for strings."
@type strings :: :reference | :copy
@type dec_strings :: :reference | :copy
@typedoc "Decoding setting for floats."
@type floats :: :native | :decimals
@type dec_floats :: :native | :decimals
@typedoc "Decoding setting for objects."
@type objects :: :maps | :ordered_objects
@type dec_objects :: :maps | :ordered_objects
@typedoc "Available decoding options."
@type decode_opt :: {:keys, keys} | {:strings, strings} | {:floats, floats} | {:objects, objects}
@type decode_opt ::
{:keys, dec_keys}
| {:strings, dec_strings}
| {:floats, dec_floats}
| {:objects, dec_objects}

@typedoc "A plain JSON object where keys can only be strings."
@type object :: %{String.t() => value}
@typedoc "A plain JSON array."
@type array :: [value]
@typedoc "A plain JSON value."
@type value :: nil | String.t() | number | boolean | array | object
@typedoc "A decoded JSON value where map keys can have any type."
@type decoded :: [decoded] | %{map_key => decoded} | value
@typedoc "The type of map keys that can be encoded."
@type encodable_key :: String.t() | number | atom | [encodable_key]
@typedoc "The types that can be encoded. Not included are: `tuple`s, `function`s, `reference`s, `port`s and `pid`s."
@type encodable :: String.t() | number | atom | [encodable] | %{encodable_key => encodable}
@type decoded :: value | [decoded] | %{optional(dec_map_key) => decoded}
@typedoc """
The types that can be encoded. In general it will be a JSON `t:value` but
it can be any `term` that has the `c:Jason.Encoder` protocol implemented.
"""
@type encodable :: value | term

@doc """
Parses a JSON value from `input` iodata.
Expand Down Expand Up @@ -152,7 +161,7 @@ defmodule Jason do
"""
@spec encode(encodable, [encode_opt]) ::
{:ok, String.t()} | {:error, EncodeError.t() | Exception.t()}
{:ok, str} | {:error, EncodeError.t() | Exception.t()}
def encode(input, opts \\ []) do
case do_encode(input, format_encode_opts(opts)) do
{:ok, result} -> {:ok, IO.iodata_to_binary(result)}
Expand All @@ -175,7 +184,7 @@ defmodule Jason do
** (Jason.EncodeError) invalid byte 0xFF in <<255>>
"""
@spec encode!(encodable, [encode_opt]) :: String.t() | no_return
@spec encode!(encodable, [encode_opt]) :: str | no_return
def encode!(input, opts \\ []) do
case do_encode(input, format_encode_opts(opts)) do
{:ok, result} -> IO.iodata_to_binary(result)
Expand Down Expand Up @@ -250,10 +259,12 @@ defmodule Jason do
Encode.encode(input, opts)
end

@spec format_encode_opts([encode_opt]) :: %{atom => any}
defp format_encode_opts(opts) do
Enum.into(opts, %{escape: :json, maps: :naive})
end

@spec format_decode_opts([encode_opt]) :: %{atom => any}
defp format_decode_opts(opts) do
Enum.into(opts, %{keys: :strings, strings: :reference, floats: :native, objects: :maps})
end
Expand Down

0 comments on commit 978b27b

Please sign in to comment.