dependabot-hex 0.119.0.beta1 → 0.119.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,216 +0,0 @@
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 implementation similar to the following 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 generated:
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
@@ -1,253 +0,0 @@
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