unique_fragment_names.ex (1689B)
1 defmodule Absinthe.Phase.Document.Validation.UniqueFragmentNames do 2 @moduledoc false 3 4 # Validates document to ensure that all fragments have unique names. 5 6 alias Absinthe.{Blueprint, Phase} 7 8 use Absinthe.Phase 9 use Absinthe.Phase.Validation 10 11 @doc """ 12 Run the validation. 13 """ 14 @spec run(Blueprint.t(), Keyword.t()) :: Phase.result_t() 15 def run(input, _options \\ []) do 16 fragments = 17 for fragment <- input.fragments do 18 process(fragment, input.fragments) 19 end 20 21 result = %{input | fragments: fragments} 22 {:ok, result} 23 end 24 25 @spec process(Blueprint.Document.Fragment.Named.t(), [Blueprint.Document.Fragment.Named.t()]) :: 26 Blueprint.Document.Fragment.Named.t() 27 defp process(fragment, fragments) do 28 if duplicate?(fragments, fragment) do 29 fragment 30 |> flag_invalid(:duplicate_name) 31 |> put_error(error(fragment)) 32 else 33 fragment 34 end 35 end 36 37 # Whether a duplicate fragment is present 38 @spec duplicate?([Blueprint.Document.Fragment.Named.t()], Blueprint.Document.Fragment.Named.t()) :: 39 boolean 40 defp duplicate?(fragments, fragment) do 41 Enum.count(fragments, &(&1.name == fragment.name)) > 1 42 end 43 44 # Generate an error for a duplicate fragment. 45 @spec error(Blueprint.Document.Fragment.Named.t()) :: Phase.Error.t() 46 defp error(node) do 47 %Phase.Error{ 48 phase: __MODULE__, 49 message: error_message(node.name), 50 locations: [node.source_location] 51 } 52 end 53 54 @doc """ 55 Generate an error message for a duplicate fragment. 56 """ 57 @spec error_message(String.t()) :: String.t() 58 def error_message(name) do 59 ~s(There can only be one fragment named "#{name}".) 60 end 61 end