     end
   end
 
-  @spec size(Schema.t(), map) :: result
-  defp size(%{min_properties: nil, max_properties: nil}, _map), do: :ok
-
-  defp size(%{min_properties: min, max_properties: max}, map) do
-    do_size(length(Map.keys(map)), min, max, map)
-  end
-
-  @spec do_size(number, number, number, map) :: result
-  defp do_size(len, min, _max, map) when not is_nil(min) and len < min do
-    {:error, %{min_properties: min, value: map}}
-  end
-
-  defp do_size(len, _min, max, map) when not is_nil(max) and len > max do
-    {:error, %{max_properties: max, value: map}}
+  @spec size(Schema.t(), map | keyword) :: result
+  defp size(%{min_properties: nil, max_properties: nil}, _value), do: :ok
+
+  defp size(%{min_properties: min, max_properties: max}, value) when is_map(value) do
+    do_size(length(Map.keys(value)), min, max, value)
+  end
+
+  defp size(%{min_properties: min, max_properties: max}, value) when is_list(value) do
+    do_size(length(value), min, max, value)
+  end
+
+  @spec do_size(number, number, number, map | keyword) :: result
+  defp do_size(len, min, _max, value) when not is_nil(min) and len < min do
+    {:error, %{min_properties: min, value: value}}
+  end
+
+  defp do_size(len, _min, max, value) when not is_nil(max) and len > max do
+    {:error, %{max_properties: max, value: value}}
   end
 
   defp do_size(_len, _min, _max, _map), do: :ok
 
-  @spec patterns(Schema.t(), map, keyword) :: {:ok, map} | {:error, map}
-  defp patterns(%{pattern_properties: nil}, map, _opts), do: {:ok, map}
+  @spec patterns(Schema.t(), map, keyword) :: :ok | {:error, map}
+  defp patterns(%{pattern_properties: nil}, _map, _opts), do: :ok
 
   defp patterns(%{pattern_properties: patterns}, map, opts) do
     props =

         :ok <- required(schema, value),
         :ok <- property_names(schema, value, opts),
         :ok <- dependencies(schema, value, opts),
         {:ok, patts_rest} <- patterns(schema, value, opts),
         {:ok, props_rest} <- properties(schema, value, opts),
         value <- intersection(props_rest, patts_rest),
         :ok <- additionals(schema, value, opts),
         do: :ok
  end

  defp validate_by(:keyword, schema, value, opts) do
    with :ok <- dependencies(schema, value, opts),
         value <- Enum.into(value, %{}),
         :ok <- size(schema, value),
         :ok <- keys(schema, value),
         :ok <- required(schema, value),
         :ok <- property_names(schema, value, opts),
         {:ok, patts_rest} <- patterns(schema, value, opts),
         {:ok, props_rest} <- properties(schema, value, opts),
         value <- intersection(props_rest, patts_rest),
         :ok <- additionals(schema, value, opts),
         do: :ok
  end



  defp custom_validator(_, _), do: :ok

  defp delete_properties(map, %{properties: nil}), do: map

  defp delete_properties(map, %{properties: properties}) do
    map
    |> Enum.filter(fn {key, _value} -> !Map.has_key?(properties, key) end)
    |> Enum.into(%{})
  end

  defp delete_patterns(map, %{pattern_properties: nil}), do: map

  defp delete_patterns(map, %{pattern_properties: patterns}) do
    patterns = Map.keys(patterns)

    map
    |> Enum.filter(fn {key, _value} -> !match_any?(patterns, key) end)
    |> Enum.into(%{})
  end

  defp match_any?(patterns, pattern) when is_atom(pattern) do
    match_any?(patterns, Atom.to_string(pattern))
  end

  defp match_any?(patterns, pattern) when is_binary(pattern) do
    Enum.any?(patterns, fn regex -> Regex.match?(regex, pattern) end)
  end

  defp collect(results) do
    Enum.reduce(results, :ok, fn
      :ok, :ok ->
        :ok

      {:error, reason}, :ok ->
        {:error, [reason]}

      :ok, {:error, _} = error ->
        error

      {:error, reason}, {:error, reasons} ->
        {:error, [reason | reasons]}
    end)
  end
end
