dependabot-hex 0.107.13 → 0.107.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/helpers/deps/jason/.fetch +0 -0
- data/helpers/deps/jason/.hex +2 -0
- data/helpers/deps/jason/CHANGELOG.md +60 -0
- data/helpers/deps/jason/LICENSE +13 -0
- data/helpers/deps/jason/README.md +179 -0
- data/helpers/deps/jason/hex_metadata.config +20 -0
- data/helpers/deps/jason/lib/codegen.ex +158 -0
- data/helpers/deps/jason/lib/decoder.ex +657 -0
- data/helpers/deps/jason/lib/encode.ex +630 -0
- data/helpers/deps/jason/lib/encoder.ex +216 -0
- data/helpers/deps/jason/lib/formatter.ex +253 -0
- data/helpers/deps/jason/lib/fragment.ex +11 -0
- data/helpers/deps/jason/lib/helpers.ex +90 -0
- data/helpers/deps/jason/lib/jason.ex +228 -0
- data/helpers/deps/jason/mix.exs +92 -0
- metadata +18 -3
@@ -0,0 +1,216 @@
|
|
1
|
+
defprotocol Jason.Encoder do
|
2
|
+
@moduledoc """
|
3
|
+
Protocol controlling how a value is encoded to JSON.
|
4
|
+
|
5
|
+
## Deriving
|
6
|
+
|
7
|
+
The protocol allows leveraging the Elixir's `@derive` feature
|
8
|
+
to simplify protocol implementation in trivial cases. Accepted
|
9
|
+
options are:
|
10
|
+
|
11
|
+
* `:only` - encodes only values of specified keys.
|
12
|
+
* `:except` - encodes all struct fields except specified keys.
|
13
|
+
|
14
|
+
By default all keys except the `:__struct__` key are encoded.
|
15
|
+
|
16
|
+
## Example
|
17
|
+
|
18
|
+
Let's assume a presence of the following struct:
|
19
|
+
|
20
|
+
defmodule Test do
|
21
|
+
defstruct [:foo, :bar, :baz]
|
22
|
+
end
|
23
|
+
|
24
|
+
If we were to call `@derive Jason.Encoder` just before `defstruct`,
|
25
|
+
an implementaion similar to the follwing implementation would be generated:
|
26
|
+
|
27
|
+
defimpl Jason.Encoder, for: Test do
|
28
|
+
def encode(value, opts) do
|
29
|
+
Jason.Encode.map(Map.take(value, [:foo, :bar, :baz]), opts)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
If we called `@derive {Jason.Encoder, only: [:foo]}`, an implementation
|
34
|
+
similar to the following implementation would be genrated:
|
35
|
+
|
36
|
+
defimpl Jason.Encoder, for: Test do
|
37
|
+
def encode(value, opts) do
|
38
|
+
Jason.Encode.map(Map.take(value, [:foo]), opts)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
If we called `@derive {Jason.Encoder, except: [:foo]}`, an implementation
|
43
|
+
similar to the following implementation would be generated:
|
44
|
+
|
45
|
+
defimpl Jason.Encoder, for: Test do
|
46
|
+
def encode(value, opts) do
|
47
|
+
Jason.Encode.map(Map.take(value, [:bar, :baz]), opts)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
The actually generated implementations are more efficient computing some data
|
52
|
+
during compilation similar to the macros from the `Jason.Helpers` module.
|
53
|
+
|
54
|
+
## Explicit implementation
|
55
|
+
|
56
|
+
If you wish to implement the protocol fully yourself, it is advised to
|
57
|
+
use functions from the `Jason.Encode` module to do the actual iodata
|
58
|
+
generation - they are highly optimized and verified to always produce
|
59
|
+
valid JSON.
|
60
|
+
"""
|
61
|
+
|
62
|
+
@type t :: term
|
63
|
+
@type opts :: Jason.Encode.opts()
|
64
|
+
|
65
|
+
@fallback_to_any true
|
66
|
+
|
67
|
+
@doc """
|
68
|
+
Encodes `value` to JSON.
|
69
|
+
|
70
|
+
The argument `opts` is opaque - it can be passed to various functions in
|
71
|
+
`Jason.Encode` (or to the protocol function itself) for encoding values to JSON.
|
72
|
+
"""
|
73
|
+
@spec encode(t, opts) :: iodata
|
74
|
+
def encode(value, opts)
|
75
|
+
end
|
76
|
+
|
77
|
+
defimpl Jason.Encoder, for: Any do
|
78
|
+
defmacro __deriving__(module, struct, opts) do
|
79
|
+
fields = fields_to_encode(struct, opts)
|
80
|
+
kv = Enum.map(fields, &{&1, generated_var(&1, __MODULE__)})
|
81
|
+
escape = quote(do: escape)
|
82
|
+
encode_map = quote(do: encode_map)
|
83
|
+
encode_args = [escape, encode_map]
|
84
|
+
kv_iodata = Jason.Codegen.build_kv_iodata(kv, encode_args)
|
85
|
+
|
86
|
+
quote do
|
87
|
+
defimpl Jason.Encoder, for: unquote(module) do
|
88
|
+
require Jason.Helpers
|
89
|
+
|
90
|
+
def encode(%{unquote_splicing(kv)}, {unquote(escape), unquote(encode_map)}) do
|
91
|
+
unquote(kv_iodata)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# The same as Macro.var/2 except it sets generated: true
|
98
|
+
defp generated_var(name, context) do
|
99
|
+
{name, [generated: true], context}
|
100
|
+
end
|
101
|
+
|
102
|
+
def encode(%_{} = struct, _opts) do
|
103
|
+
raise Protocol.UndefinedError,
|
104
|
+
protocol: @protocol,
|
105
|
+
value: struct,
|
106
|
+
description: """
|
107
|
+
Jason.Encoder protocol must always be explicitly implemented.
|
108
|
+
|
109
|
+
If you own the struct, you can derive the implementation specifying \
|
110
|
+
which fields should be encoded to JSON:
|
111
|
+
|
112
|
+
@derive {Jason.Encoder, only: [....]}
|
113
|
+
defstruct ...
|
114
|
+
|
115
|
+
It is also possible to encode all fields, although this should be \
|
116
|
+
used carefully to avoid accidentally leaking private information \
|
117
|
+
when new fields are added:
|
118
|
+
|
119
|
+
@derive Jason.Encoder
|
120
|
+
defstruct ...
|
121
|
+
|
122
|
+
Finally, if you don't own the struct you want to encode to JSON, \
|
123
|
+
you may use Protocol.derive/3 placed outside of any module:
|
124
|
+
|
125
|
+
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
|
126
|
+
Protocol.derive(Jason.Encoder, NameOfTheStruct)
|
127
|
+
"""
|
128
|
+
end
|
129
|
+
|
130
|
+
def encode(value, _opts) do
|
131
|
+
raise Protocol.UndefinedError,
|
132
|
+
protocol: @protocol,
|
133
|
+
value: value,
|
134
|
+
description: "Jason.Encoder protocol must always be explicitly implemented"
|
135
|
+
end
|
136
|
+
|
137
|
+
defp fields_to_encode(struct, opts) do
|
138
|
+
cond do
|
139
|
+
only = Keyword.get(opts, :only) ->
|
140
|
+
only
|
141
|
+
|
142
|
+
except = Keyword.get(opts, :except) ->
|
143
|
+
Map.keys(struct) -- [:__struct__ | except]
|
144
|
+
|
145
|
+
true ->
|
146
|
+
Map.keys(struct) -- [:__struct__]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# The following implementations are formality - they are already covered
|
152
|
+
# by the main encoding mechanism in Jason.Encode, but exist mostly for
|
153
|
+
# documentation purposes and if anybody had the idea to call the protocol directly.
|
154
|
+
|
155
|
+
defimpl Jason.Encoder, for: Atom do
|
156
|
+
def encode(atom, opts) do
|
157
|
+
Jason.Encode.atom(atom, opts)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
defimpl Jason.Encoder, for: Integer do
|
162
|
+
def encode(integer, _opts) do
|
163
|
+
Jason.Encode.integer(integer)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
defimpl Jason.Encoder, for: Float do
|
168
|
+
def encode(float, _opts) do
|
169
|
+
Jason.Encode.float(float)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
defimpl Jason.Encoder, for: List do
|
174
|
+
def encode(list, opts) do
|
175
|
+
Jason.Encode.list(list, opts)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
defimpl Jason.Encoder, for: Map do
|
180
|
+
def encode(map, opts) do
|
181
|
+
Jason.Encode.map(map, opts)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
defimpl Jason.Encoder, for: BitString do
|
186
|
+
def encode(binary, opts) when is_binary(binary) do
|
187
|
+
Jason.Encode.string(binary, opts)
|
188
|
+
end
|
189
|
+
|
190
|
+
def encode(bitstring, _opts) do
|
191
|
+
raise Protocol.UndefinedError,
|
192
|
+
protocol: @protocol,
|
193
|
+
value: bitstring,
|
194
|
+
description: "cannot encode a bitstring to JSON"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
defimpl Jason.Encoder, for: [Date, Time, NaiveDateTime, DateTime] do
|
199
|
+
def encode(value, _opts) do
|
200
|
+
[?\", @for.to_iso8601(value), ?\"]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
defimpl Jason.Encoder, for: Decimal do
|
205
|
+
def encode(value, _opts) do
|
206
|
+
# silence the xref warning
|
207
|
+
decimal = Decimal
|
208
|
+
[?\", decimal.to_string(value), ?\"]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
defimpl Jason.Encoder, for: Jason.Fragment do
|
213
|
+
def encode(%{encode: encode}, opts) do
|
214
|
+
encode.(opts)
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,253 @@
|
|
1
|
+
defmodule Jason.Formatter do
|
2
|
+
@moduledoc ~S"""
|
3
|
+
Pretty-printing and minimizing functions for JSON-encoded data.
|
4
|
+
|
5
|
+
Input is required to be in an 8-bit-wide encoding such as UTF-8 or Latin-1
|
6
|
+
in `t:iodata/0` format. Input must ve valid JSON, invalid JSON may produce
|
7
|
+
unexpected results or errors.
|
8
|
+
"""
|
9
|
+
|
10
|
+
@type opts :: [
|
11
|
+
{:indent, iodata}
|
12
|
+
| {:line_separator, iodata}
|
13
|
+
| {:record_separator, iodata}
|
14
|
+
| {:after_colon, iodata}
|
15
|
+
]
|
16
|
+
|
17
|
+
import Record
|
18
|
+
defrecordp :opts, [:indent, :line, :record, :colon]
|
19
|
+
|
20
|
+
@doc ~S"""
|
21
|
+
Pretty-prints JSON-encoded `input`.
|
22
|
+
|
23
|
+
`input` may contain multiple JSON objects or arrays, optionally separated
|
24
|
+
by whitespace (e.g., one object per line). Objects in output will be
|
25
|
+
separated by newlines. No trailing newline is emitted.
|
26
|
+
|
27
|
+
## Options
|
28
|
+
|
29
|
+
* `:indent` - used for nested objects and arrays (default: two spaces - `" "`);
|
30
|
+
* `:line_separator` - used in nested objects (default: `"\n"`);
|
31
|
+
* `:record_separator` - separates root-level objects and arrays
|
32
|
+
(default is the value for `:line_separator` option);
|
33
|
+
* `:after_colon` - printed after a colon inside objects (default: one space - `" "`).
|
34
|
+
|
35
|
+
## Examples
|
36
|
+
|
37
|
+
iex> Jason.Formatter.pretty_print(~s|{"a":{"b": [1, 2]}}|)
|
38
|
+
~s|{
|
39
|
+
"a": {
|
40
|
+
"b": [
|
41
|
+
1,
|
42
|
+
2
|
43
|
+
]
|
44
|
+
}
|
45
|
+
}|
|
46
|
+
|
47
|
+
"""
|
48
|
+
@spec pretty_print(iodata, opts) :: binary
|
49
|
+
def pretty_print(input, opts \\ []) do
|
50
|
+
input
|
51
|
+
|> pretty_print_to_iodata(opts)
|
52
|
+
|> IO.iodata_to_binary()
|
53
|
+
end
|
54
|
+
|
55
|
+
@doc ~S"""
|
56
|
+
Pretty-prints JSON-encoded `input` and returns iodata.
|
57
|
+
|
58
|
+
This function should be preferred to `pretty_print/2`, if the pretty-printed
|
59
|
+
JSON will be handed over to one of the IO functions or sent
|
60
|
+
over the socket. The Erlang runtime is able to leverage vectorised
|
61
|
+
writes and avoid allocating a continuous buffer for the whole
|
62
|
+
resulting string, lowering memory use and increasing performance.
|
63
|
+
"""
|
64
|
+
@spec pretty_print_to_iodata(iodata, opts) :: iodata
|
65
|
+
def pretty_print_to_iodata(input, opts \\ []) do
|
66
|
+
opts = parse_opts(opts, " ", "\n", nil, " ")
|
67
|
+
|
68
|
+
depth = :first
|
69
|
+
empty = false
|
70
|
+
|
71
|
+
{output, _state} = pp_iodata(input, [], depth, empty, opts)
|
72
|
+
|
73
|
+
output
|
74
|
+
end
|
75
|
+
|
76
|
+
@doc ~S"""
|
77
|
+
Minimizes JSON-encoded `input`.
|
78
|
+
|
79
|
+
`input` may contain multiple JSON objects or arrays, optionally
|
80
|
+
separated by whitespace (e.g., one object per line). Minimized
|
81
|
+
output will contain one object per line. No trailing newline is emitted.
|
82
|
+
|
83
|
+
## Options
|
84
|
+
|
85
|
+
* `:record_separator` - controls the string used as newline (default: `"\n"`).
|
86
|
+
|
87
|
+
## Examples
|
88
|
+
|
89
|
+
iex> Jason.Formatter.minimize(~s|{ "a" : "b" , "c": \n\n 2}|)
|
90
|
+
~s|{"a":"b","c":2}|
|
91
|
+
|
92
|
+
"""
|
93
|
+
@spec minimize(iodata, opts) :: binary
|
94
|
+
def minimize(input, opts \\ []) do
|
95
|
+
input
|
96
|
+
|> minimize_to_iodata(opts)
|
97
|
+
|> IO.iodata_to_binary()
|
98
|
+
end
|
99
|
+
|
100
|
+
@doc ~S"""
|
101
|
+
Minimizes JSON-encoded `input` and returns iodata.
|
102
|
+
|
103
|
+
This function should be preferred to `minimize/2`, if the minimized
|
104
|
+
JSON will be handed over to one of the IO functions or sent
|
105
|
+
over the socket. The Erlang runtime is able to leverage vectorised
|
106
|
+
writes and avoid allocating a continuous buffer for the whole
|
107
|
+
resulting string, lowering memory use and increasing performance.
|
108
|
+
"""
|
109
|
+
@spec minimize_to_iodata(iodata, opts) :: iodata
|
110
|
+
def minimize_to_iodata(input, opts) do
|
111
|
+
record = Keyword.get(opts, :record_separator, "\n")
|
112
|
+
opts = opts(indent: "", line: "", record: record, colon: "")
|
113
|
+
|
114
|
+
depth = :first
|
115
|
+
empty = false
|
116
|
+
|
117
|
+
{output, _state} = pp_iodata(input, [], depth, empty, opts)
|
118
|
+
|
119
|
+
output
|
120
|
+
end
|
121
|
+
|
122
|
+
defp parse_opts([{option, value} | opts], indent, line, record, colon) do
|
123
|
+
value = IO.iodata_to_binary(value)
|
124
|
+
case option do
|
125
|
+
:indent -> parse_opts(opts, value, line, record, colon)
|
126
|
+
:record_separator -> parse_opts(opts, indent, line, value, colon)
|
127
|
+
:after_colon -> parse_opts(opts, indent, line, record, value)
|
128
|
+
:line_separator -> parse_opts(opts, indent, value, record || value, colon)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
defp parse_opts([], indent, line, record, colon) do
|
133
|
+
opts(indent: indent, line: line, record: record || line, colon: colon)
|
134
|
+
end
|
135
|
+
|
136
|
+
for depth <- 1..16 do
|
137
|
+
defp tab(" ", unquote(depth)), do: unquote(String.duplicate(" ", depth))
|
138
|
+
end
|
139
|
+
|
140
|
+
defp tab("", _), do: ""
|
141
|
+
defp tab(indent, depth), do: List.duplicate(indent, depth)
|
142
|
+
|
143
|
+
defp pp_iodata(<<>>, output_acc, depth, empty, opts) do
|
144
|
+
{output_acc, &pp_iodata(&1, &2, depth, empty, opts)}
|
145
|
+
end
|
146
|
+
|
147
|
+
defp pp_iodata(<<byte, rest::binary>>, output_acc, depth, empty, opts) do
|
148
|
+
pp_byte(byte, rest, output_acc, depth, empty, opts)
|
149
|
+
end
|
150
|
+
|
151
|
+
defp pp_iodata([], output_acc, depth, empty, opts) do
|
152
|
+
{output_acc, &pp_iodata(&1, &2, depth, empty, opts)}
|
153
|
+
end
|
154
|
+
|
155
|
+
defp pp_iodata([byte | rest], output_acc, depth, empty, opts) when is_integer(byte) do
|
156
|
+
pp_byte(byte, rest, output_acc, depth, empty, opts)
|
157
|
+
end
|
158
|
+
|
159
|
+
defp pp_iodata([head | tail], output_acc, depth, empty, opts) do
|
160
|
+
{output_acc, cont} = pp_iodata(head, output_acc, depth, empty, opts)
|
161
|
+
cont.(tail, output_acc)
|
162
|
+
end
|
163
|
+
|
164
|
+
defp pp_byte(byte, rest, output, depth, empty, opts) when byte in ' \n\r\t' do
|
165
|
+
pp_iodata(rest, output, depth, empty, opts)
|
166
|
+
end
|
167
|
+
|
168
|
+
defp pp_byte(byte, rest, output, depth, empty, opts) when byte in '{[' do
|
169
|
+
{out, depth} =
|
170
|
+
cond do
|
171
|
+
depth == :first -> {byte, 1}
|
172
|
+
depth == 0 -> {[opts(opts, :record), byte], 1}
|
173
|
+
empty -> {[opts(opts, :line), tab(opts(opts, :indent), depth), byte], depth + 1}
|
174
|
+
true -> {byte, depth + 1}
|
175
|
+
end
|
176
|
+
|
177
|
+
empty = true
|
178
|
+
pp_iodata(rest, [output, out], depth, empty, opts)
|
179
|
+
end
|
180
|
+
|
181
|
+
defp pp_byte(byte, rest, output, depth, true = _empty, opts) when byte in '}]' do
|
182
|
+
empty = false
|
183
|
+
depth = depth - 1
|
184
|
+
pp_iodata(rest, [output, byte], depth, empty, opts)
|
185
|
+
end
|
186
|
+
|
187
|
+
defp pp_byte(byte, rest, output, depth, false = empty, opts) when byte in '}]' do
|
188
|
+
depth = depth - 1
|
189
|
+
out = [opts(opts, :line), tab(opts(opts, :indent), depth), byte]
|
190
|
+
pp_iodata(rest, [output, out], depth, empty, opts)
|
191
|
+
end
|
192
|
+
|
193
|
+
defp pp_byte(byte, rest, output, depth, _empty, opts) when byte in ',' do
|
194
|
+
empty = false
|
195
|
+
out = [byte, opts(opts, :line), tab(opts(opts, :indent), depth)]
|
196
|
+
pp_iodata(rest, [output, out], depth, empty, opts)
|
197
|
+
end
|
198
|
+
|
199
|
+
defp pp_byte(byte, rest, output, depth, empty, opts) when byte in ':' do
|
200
|
+
out = [byte, opts(opts, :colon)]
|
201
|
+
pp_iodata(rest, [output, out], depth, empty, opts)
|
202
|
+
end
|
203
|
+
|
204
|
+
defp pp_byte(byte, rest, output, depth, empty, opts) do
|
205
|
+
out = if empty, do: [opts(opts, :line), tab(opts(opts, :indent), depth), byte], else: byte
|
206
|
+
empty = false
|
207
|
+
|
208
|
+
if byte == ?" do
|
209
|
+
pp_string(rest, [output, out], _in_bs = false, &pp_iodata(&1, &2, depth, empty, opts))
|
210
|
+
else
|
211
|
+
pp_iodata(rest, [output, out], depth, empty, opts)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
defp pp_string(<<>>, output_acc, in_bs, cont) do
|
216
|
+
{output_acc, &pp_string(&1, &2, in_bs, cont)}
|
217
|
+
end
|
218
|
+
|
219
|
+
defp pp_string(binary, output_acc, true = _in_bs, cont) when is_binary(binary) do
|
220
|
+
<<byte, rest::binary>> = binary
|
221
|
+
pp_string(rest, [output_acc, byte], false, cont)
|
222
|
+
end
|
223
|
+
|
224
|
+
defp pp_string(binary, output_acc, false = _in_bs, cont) when is_binary(binary) do
|
225
|
+
case :binary.match(binary, ["\"", "\\"]) do
|
226
|
+
:nomatch ->
|
227
|
+
{[output_acc | binary], &pp_string(&1, &2, false, cont)}
|
228
|
+
{pos, 1} ->
|
229
|
+
{head, tail} = :erlang.split_binary(binary, pos + 1)
|
230
|
+
case :binary.at(binary, pos) do
|
231
|
+
?\\ -> pp_string(tail, [output_acc | head], true, cont)
|
232
|
+
?" -> cont.(tail, [output_acc | head])
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
defp pp_string([], output_acc, in_bs, cont) do
|
238
|
+
{output_acc, &pp_string(&1, &2, in_bs, cont)}
|
239
|
+
end
|
240
|
+
|
241
|
+
defp pp_string([byte | rest], output_acc, in_bs, cont) when is_integer(byte) do
|
242
|
+
cond do
|
243
|
+
in_bs -> pp_string(rest, [output_acc, byte], false, cont)
|
244
|
+
byte == ?" -> cont.(rest, [output_acc, byte])
|
245
|
+
true -> pp_string(rest, [output_acc, byte], byte == ?\\, cont)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
defp pp_string([head | tail], output_acc, in_bs, cont) do
|
250
|
+
{output_acc, cont} = pp_string(head, output_acc, in_bs, cont)
|
251
|
+
cont.(tail, output_acc)
|
252
|
+
end
|
253
|
+
end
|