@@ -45,6 +45,11 @@ defmodule Schematic do
4545 }
4646 end
4747
48+ defmodule Error do
49+ @ moduledoc false
50+ defstruct [ ]
51+ end
52+
4853 @ doc """
4954 Specifies that the data can be **any**thing.
5055
@@ -276,12 +281,14 @@ defmodule Schematic do
276281 @ doc """
277282 Specifies that the data is a list whose items unify to the given schematic.
278283
284+ Lists whose elements do not unify return a list of `:ok` and `:error` tuples.
285+
279286 ## Usage
280287
281288 ```elixir
282289 iex> schematic = list(oneof([str(), int()]))
283290 iex> {:ok, ["one", 2, "three"]} = unify(schematic, ["one", 2, "three"])
284- iex> {:error, "expected a list of either a string or an integer"} = unify(schematic, ["one", 2, :three])
291+ iex> {:error, [ok: "one", ok: 2, error: "expected either a string or an integer"] } = unify(schematic, ["one", 2, :three])
285292 ```
286293 """
287294 @ spec list ( t ( ) | lazy_schematic ( ) | literal ( ) ) :: t ( )
@@ -304,21 +311,18 @@ defmodule Schematic do
304311 unify:
305312 telemetry_wrap ( :list , % { } , fn input , dir ->
306313 if is_list ( input ) do
307- Enum . reduce_while ( input , { :ok , [ ] } , fn el , { :ok , acc } ->
314+ Enum . map_reduce ( input , [ ] , fn el , acc ->
308315 case schematic . ( ) . unify . ( el , dir ) do
309- { :ok , output } ->
310- { :cont , { :ok , [ output | acc ] } }
311-
312- { :error , _error } ->
313- { :halt , { :error , ~s| expected #{ message . ( ) } | } }
316+ { :ok , output } -> { output , [ { :ok , output } | acc ] }
317+ { :error , error } -> { % Error { } , [ { :error , error } | acc ] }
314318 end
315319 end )
316- |> then ( fn
317- { :ok , result } ->
318- { :ok , Enum . reverse ( result ) }
319-
320- error ->
321- error
320+ |> then ( fn { result , errors } ->
321+ if % Error { } in result do
322+ { :error , Enum . reverse ( errors ) }
323+ else
324+ { :ok , result }
325+ end
322326 end )
323327 else
324328 { :error , ~s| expected a list| }
0 commit comments