known_type_names.ex (1949B)
1 defmodule Absinthe.Phase.Validation.KnownTypeNames do 2 @moduledoc false 3 4 # Ensure type names actually exist in the schema. 5 # 6 # Type names show up for example in fragments: 7 # 8 # ``` 9 # fragment foo on Foo { 10 # name 11 # } 12 # ``` 13 14 alias Absinthe.{Blueprint, Phase} 15 alias Absinthe.Phase.Document.Validation.Utils 16 17 use Absinthe.Phase 18 use Absinthe.Phase.Validation 19 20 @doc """ 21 Run the validation. 22 """ 23 @spec run(Blueprint.t(), Keyword.t()) :: Phase.result_t() 24 def run(input, _options \\ []) do 25 result = Blueprint.postwalk(input, &handle_node(&1, input.schema)) 26 {:ok, result} 27 end 28 29 defp handle_node(%{type_condition: type, schema_node: nil} = node, _) when not is_nil(type) do 30 name = Blueprint.TypeReference.unwrap(type).name 31 32 node 33 |> flag_invalid(:bad_type_name) 34 |> put_error(error(node, name)) 35 end 36 37 defp handle_node(%Blueprint.Document.VariableDefinition{} = node, schema) do 38 name = Blueprint.TypeReference.unwrap(node.type).name 39 inner_schema_type = schema.__absinthe_lookup__(name) 40 41 if inner_schema_type do 42 node 43 else 44 suggestions = suggested_type_names(schema, name) 45 46 node 47 |> flag_invalid(:bad_type_name) 48 |> put_error(error(node, name, suggestions)) 49 end 50 end 51 52 defp handle_node(node, _) do 53 node 54 end 55 56 defp suggested_type_names(schema, name) do 57 schema 58 |> Absinthe.Schema.referenced_types() 59 |> Enum.map(& &1.name) 60 |> Absinthe.Utils.Suggestion.sort_list(name) 61 end 62 63 @spec error(Blueprint.node_t(), String.t()) :: Phase.Error.t() 64 defp error(node, name, suggestions \\ []) do 65 %Phase.Error{ 66 phase: __MODULE__, 67 message: message(name, suggestions), 68 locations: [node.source_location] 69 } 70 end 71 72 defp message(name, []) do 73 ~s(Unknown type "#{name}".) 74 end 75 76 defp message(name, suggestions) do 77 ~s(Unknown type "#{name}".) <> Utils.MessageSuggestions.suggest_message(suggestions) 78 end 79 end