lib/url/mailto.ex

defmodule URL.Mailto do
  @moduledoc """
  Parses a `mailto` URL
  """
  import NimbleParsec
  import URL.ParseHelpers.{Core, Mailto, Unwrap}
  alias URL.ParseHelpers.Params

  @type t() :: %__MODULE__{
          to: [binary(), ...],
          params: map()
        }

  defstruct to: nil, params: %{}

  @doc """
  Parse a URI with the `:scheme` of "tel"

  ## Example

      iex> mailto = URI.parse("mailto:user@%E7%B4%8D%E8%B1%86.example.org?subject=Test&body=NATTO")
      iex> URL.Mailto.parse(mailto)
      {:ok,
       %URL.Mailto{
         to: ["user@納豆.example.org"],
         params: %{"body" => "NATTO", "subject" => "Test"}
       }}

  """
  @spec parse(URI.t()) :: {:ok, __MODULE__.t()} | {:error, {module(), binary()}}
  def parse(%URI{scheme: "mailto", path: path, query: query}) do
    with {:ok, mailto} <- unwrap(parse_mailto(path)),
         {:ok, [params]} <- unwrap(URL.parse_query(query)) do
      mailto
      |> structify(__MODULE__)
      |> Map.put(:params, params)
      |> Params.wrap(:ok)
    end
  end

  defparsecp(
    :parse_mailto,
    optional(to())
  )
end