Packages
absinthe
1.7.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/absinthe/blueprint/transform.ex
defmodule Absinthe.Blueprint.Transform do
@moduledoc false
alias Absinthe.Blueprint
@doc """
Apply `fun` to a node, then walk to its children and do the same
"""
@spec prewalk(
Blueprint.node_t(),
(Blueprint.node_t() -> Blueprint.node_t() | {:halt, Blueprint.node_t()})
) :: Blueprint.node_t()
def prewalk(node, fun) when is_function(fun, 1) do
{node, _} =
prewalk(node, nil, fn x, nil ->
case fun.(x) do
{:halt, x} -> {:halt, x, nil}
x -> {x, nil}
end
end)
node
end
@doc """
Same as `prewalk/2` but takes and returns an accumulator
The supplied function must be arity 2.
"""
@spec prewalk(
Blueprint.node_t(),
acc,
(Blueprint.node_t(), acc ->
{Blueprint.node_t(), acc} | {:halt, Blueprint.node_t(), acc})
) :: {Blueprint.node_t(), acc}
when acc: var
def prewalk(node, acc, fun) when is_function(fun, 2) do
walk(node, acc, fun, &pass/2)
end
@doc """
Apply `fun` to all children of a node, then apply `fun` to node
"""
@spec postwalk(Blueprint.node_t(), (Blueprint.node_t() -> Blueprint.node_t())) ::
Blueprint.node_t()
def postwalk(node, fun) when is_function(fun, 1) do
{node, _} = postwalk(node, nil, fn x, nil -> {fun.(x), nil} end)
node
end
@doc """
Same as `postwalk/2` but takes and returns an accumulator
"""
@spec postwalk(Blueprint.node_t(), acc, (Blueprint.node_t(), acc -> {Blueprint.node_t(), acc})) ::
{Blueprint.node_t(), acc}
when acc: var
def postwalk(node, acc, fun) when is_function(fun, 2) do
walk(node, acc, &pass/2, fun)
end
defp pass(x, acc), do: {x, acc}
nodes_with_children = %{
Blueprint => [:fragments, :operations, :schema_definitions, :directives],
Blueprint.Directive => [:arguments],
Blueprint.Document.Field => [:selections, :arguments, :directives],
Blueprint.Document.Operation => [:selections, :variable_definitions, :directives],
Blueprint.TypeReference.List => [:of_type],
Blueprint.TypeReference.NonNull => [:of_type],
Blueprint.Document.Fragment.Inline => [:selections, :directives],
Blueprint.Document.Fragment.Named => [:selections, :directives],
Blueprint.Document.Fragment.Spread => [:directives],
Blueprint.Document.VariableDefinition => [:type, :default_value, :directives],
Blueprint.Input.Argument => [:input_value],
Blueprint.Input.Field => [:input_value],
Blueprint.Input.Object => [:fields],
Blueprint.Input.List => [:items],
Blueprint.Input.RawValue => [:content],
Blueprint.Input.Value => [:normalized],
Blueprint.Schema.DirectiveDefinition => [:directives, :arguments],
Blueprint.Schema.EnumTypeDefinition => [:directives, :values],
Blueprint.Schema.EnumValueDefinition => [:directives],
Blueprint.Schema.FieldDefinition => [:type, :arguments, :directives],
Blueprint.Schema.InputObjectTypeDefinition => [:fields, :directives],
Blueprint.Schema.InputValueDefinition => [:type, :default_value, :directives],
Blueprint.Schema.InterfaceTypeDefinition => [:interfaces, :fields, :directives],
Blueprint.Schema.ObjectTypeDefinition => [:interfaces, :fields, :directives],
Blueprint.Schema.ScalarTypeDefinition => [:directives],
Blueprint.Schema.SchemaDefinition => [:directive_definitions, :type_definitions, :directives],
Blueprint.Schema.UnionTypeDefinition => [:directives, :types]
}
@spec walk(
Blueprint.node_t(),
acc,
(Blueprint.node_t(), acc ->
{Blueprint.node_t(), acc} | {:halt, Blueprint.node_t(), acc}),
(Blueprint.node_t(), acc -> {Blueprint.node_t(), acc})
) :: {Blueprint.node_t(), acc}
when acc: var
def walk(blueprint, acc, pre, post)
def walk(nodes, acc, pre, post) when is_list(nodes) do
Enum.map_reduce(nodes, acc, &walk(&1, &2, pre, post))
end
def walk(node, acc, pre, post) do
{node, acc} =
case pre.(node, acc) do
{:halt, node, acc} ->
{node, acc}
{node, acc} ->
maybe_walk_children(node, acc, pre, post)
end
post.(node, acc)
end
for {node_name, children} <- nodes_with_children do
def maybe_walk_children(%unquote(node_name){} = node, acc, pre, post) do
node_with_children(node, unquote(children), acc, pre, post)
end
end
def maybe_walk_children(node, acc, _, _) do
{node, acc}
end
defp node_with_children(node, children, acc, pre, post) do
walk_children(node, children, acc, pre, post)
end
defp walk_children(node, children, acc, pre, post) do
Enum.reduce(children, {node, acc}, fn child_key, {node, acc} ->
{children, acc} =
node
|> Map.fetch!(child_key)
|> walk(acc, pre, post)
{Map.put(node, child_key, children), acc}
end)
end
end