directives_must_be_valid.ex (2297B)
1 defmodule Absinthe.Phase.Schema.Validation.DirectivesMustBeValid do 2 @moduledoc false 3 4 use Absinthe.Phase 5 alias Absinthe.Blueprint 6 7 @spec_link "https://spec.graphql.org/draft/#sec-Type-System.Directives" 8 @directive_locations Absinthe.Introspection.DirectiveLocation.values() 9 10 @doc """ 11 Run the validation. 12 """ 13 def run(bp, _) do 14 bp = Blueprint.prewalk(bp, &handle_schemas/1) 15 {:ok, bp} 16 end 17 18 defp handle_schemas(%Blueprint.Schema.SchemaDefinition{} = schema) do 19 directive_definitions = Enum.map(schema.directive_definitions, &validate_directive(&1)) 20 {:halt, %{schema | directive_definitions: directive_definitions}} 21 end 22 23 defp handle_schemas(obj) do 24 obj 25 end 26 27 defp validate_directive(%Blueprint.Schema.DirectiveDefinition{locations: []} = directive) do 28 directive |> put_error(error_locations_absent(directive)) 29 end 30 31 defp validate_directive(%Blueprint.Schema.DirectiveDefinition{locations: locations} = directive) do 32 Enum.reduce(locations, directive, fn location, directive -> 33 validate_location(directive, location) 34 end) 35 end 36 37 defp validate_location(directive, location) when location in @directive_locations do 38 directive 39 end 40 41 defp validate_location(directive, location) do 42 directive |> put_error(error_unknown_directive_location(directive, location)) 43 end 44 45 defp error_unknown_directive_location(directive, location) do 46 %Absinthe.Phase.Error{ 47 message: explanation(directive, location), 48 locations: [directive.__reference__.location], 49 phase: __MODULE__, 50 extra: %{ 51 location: location 52 } 53 } 54 end 55 56 defp error_locations_absent(directive) do 57 %Absinthe.Phase.Error{ 58 message: explanation(directive), 59 locations: [directive.__reference__.location], 60 phase: __MODULE__ 61 } 62 end 63 64 defp explanation(directive, location) do 65 """ 66 Directive "#{directive.name}" must use a valid DirectiveLocation 67 68 Found: #{inspect(location)} 69 70 Expected one/multiple of: #{inspect(@directive_locations)} 71 72 Reference: #{@spec_link} 73 """ 74 end 75 76 defp explanation(directive) do 77 """ 78 Directive "#{directive.name}" must set DirectiveLocations 79 80 Expected one/multiple of: #{inspect(@directive_locations)} 81 82 Reference: #{@spec_link} 83 """ 84 end 85 end