defmodule Absinthe.Phase.Document.Validation.LoneAnonymousOperation do @moduledoc """ Validates document to ensure that only one operation is provided without a name. """ alias Absinthe.{Blueprint, Phase} use Absinthe.Phase use Absinthe.Phase.Validation @doc """ Run the validation. """ @spec run(Blueprint.t, Keyword.t) :: Phase.result_t def run(input, _options \\ []) do result = Blueprint.prewalk(input, &handle_node/1) {:ok, result} end # Find the root and check for multiple anonymous operations @spec handle_node(Blueprint.node_t) :: Blueprint.node_t defp handle_node(%Blueprint{} = node) do ops = process(node.operations) %{node | operations: ops} end defp handle_node(node) do node end @spec process([Blueprint.Document.Operation.t]) :: [Blueprint.Document.Operation.t] defp process(operations) do do_process(operations, length(operations)) end @spec do_process([Blueprint.Document.Operation.t], integer) :: [Blueprint.Document.Operation.t] defp do_process(operations, count) when count < 2 do operations end defp do_process(operations, _) do Enum.map(operations, fn %{name: nil} = op -> flag_invalid(op, :bad_name) |> put_error(error(op)) other -> other end) end # Generate the error for the node @spec error(Blueprint.node_t) :: Phase.Error.t defp error(node) do Phase.Error.new( __MODULE__, "This anonymous operation must be the only defined operation.", node.source_location ) end end