Current section

Files

Jump to
absinthe lib absinthe phase document validation no_undefined_variables.ex
Raw

lib/absinthe/phase/document/validation/no_undefined_variables.ex

defmodule Absinthe.Phase.Document.Validation.NoUndefinedVariables do
@moduledoc false
# Validates document to ensure that the only variables that are used in a
# document are defined on the operation.
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, input.operations))
{:ok, result}
end
def handle_node(%Blueprint.Input.Variable{} = node, operations) do
errors = for op <- operations do
for var <- op.variable_uses, var.name == node.name do
if Enum.find(op.variable_definitions, &(&1.name == var.name)) do
[]
else
[error(node, op)]
end
end
end
|> List.flatten
node = %{node | errors: errors ++ node.errors}
case errors do
[] ->
node
_ ->
flag_invalid(node, :no_definition)
end
end
def handle_node(node, _) do
node
end
# Generate the error for the node
@spec error(Blueprint.Input.Variable.t, Blueprint.Document.Operation.t) :: Phase.Error.t
defp error(node, operation) do
%Phase.Error{
phase: __MODULE__,
message: error_message(node.name, operation.name),
locations: [node.source_location, operation.source_location],
}
end
@doc """
Generate an error message for an undefined variable.
"""
@spec error_message(String.t, nil | String.t) :: String.t
def error_message(name, nil) do
~s(Variable "#{name}" is not defined.)
end
def error_message(name, operation_name) do
~s(Variable "#{name}" is not defined by operation "#{operation_name}".)
end
end