zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

transform.ex (4902B)


      1 defmodule Absinthe.Blueprint.Transform do
      2   @moduledoc false
      3 
      4   alias Absinthe.Blueprint
      5 
      6   @doc """
      7   Apply `fun` to a node, then walk to its children and do the same
      8   """
      9   @spec prewalk(
     10           Blueprint.node_t(),
     11           (Blueprint.node_t() -> Blueprint.node_t() | {:halt, Blueprint.node_t()})
     12         ) :: Blueprint.node_t()
     13   def prewalk(node, fun) when is_function(fun, 1) do
     14     {node, _} =
     15       prewalk(node, nil, fn x, nil ->
     16         case fun.(x) do
     17           {:halt, x} -> {:halt, x, nil}
     18           x -> {x, nil}
     19         end
     20       end)
     21 
     22     node
     23   end
     24 
     25   @doc """
     26   Same as `prewalk/2` but takes and returns an accumulator
     27 
     28   The supplied function must be arity 2.
     29   """
     30   @spec prewalk(
     31           Blueprint.node_t(),
     32           acc,
     33           (Blueprint.node_t(), acc ->
     34              {Blueprint.node_t(), acc} | {:halt, Blueprint.node_t(), acc})
     35         ) :: {Blueprint.node_t(), acc}
     36         when acc: var
     37   def prewalk(node, acc, fun) when is_function(fun, 2) do
     38     walk(node, acc, fun, &pass/2)
     39   end
     40 
     41   @doc """
     42   Apply `fun` to all children of a node, then apply `fun` to node
     43   """
     44   @spec postwalk(Blueprint.node_t(), (Blueprint.node_t() -> Blueprint.node_t())) ::
     45           Blueprint.node_t()
     46   def postwalk(node, fun) when is_function(fun, 1) do
     47     {node, _} = postwalk(node, nil, fn x, nil -> {fun.(x), nil} end)
     48     node
     49   end
     50 
     51   @doc """
     52   Same as `postwalk/2` but takes and returns an accumulator
     53   """
     54   @spec postwalk(Blueprint.node_t(), acc, (Blueprint.node_t(), acc -> {Blueprint.node_t(), acc})) ::
     55           {Blueprint.node_t(), acc}
     56         when acc: var
     57   def postwalk(node, acc, fun) when is_function(fun, 2) do
     58     walk(node, acc, &pass/2, fun)
     59   end
     60 
     61   defp pass(x, acc), do: {x, acc}
     62 
     63   nodes_with_children = %{
     64     Blueprint => [:fragments, :operations, :schema_definitions, :directives],
     65     Blueprint.Directive => [:arguments],
     66     Blueprint.Document.Field => [:selections, :arguments, :directives],
     67     Blueprint.Document.Operation => [:selections, :variable_definitions, :directives],
     68     Blueprint.TypeReference.List => [:of_type],
     69     Blueprint.TypeReference.NonNull => [:of_type],
     70     Blueprint.Document.Fragment.Inline => [:selections, :directives],
     71     Blueprint.Document.Fragment.Named => [:selections, :directives],
     72     Blueprint.Document.Fragment.Spread => [:directives],
     73     Blueprint.Document.VariableDefinition => [:type, :default_value, :directives],
     74     Blueprint.Input.Argument => [:input_value],
     75     Blueprint.Input.Field => [:input_value],
     76     Blueprint.Input.Object => [:fields],
     77     Blueprint.Input.List => [:items],
     78     Blueprint.Input.RawValue => [:content],
     79     Blueprint.Input.Value => [:normalized],
     80     Blueprint.Schema.DirectiveDefinition => [:directives, :arguments],
     81     Blueprint.Schema.EnumTypeDefinition => [:directives, :values],
     82     Blueprint.Schema.EnumValueDefinition => [:directives],
     83     Blueprint.Schema.FieldDefinition => [:type, :arguments, :directives],
     84     Blueprint.Schema.InputObjectTypeDefinition => [:fields, :directives],
     85     Blueprint.Schema.InputValueDefinition => [:type, :default_value, :directives],
     86     Blueprint.Schema.InterfaceTypeDefinition => [:interfaces, :fields, :directives],
     87     Blueprint.Schema.ObjectTypeDefinition => [:interfaces, :fields, :directives],
     88     Blueprint.Schema.ScalarTypeDefinition => [:directives],
     89     Blueprint.Schema.SchemaDefinition => [:directive_definitions, :type_definitions, :directives],
     90     Blueprint.Schema.UnionTypeDefinition => [:directives, :types]
     91   }
     92 
     93   @spec walk(
     94           Blueprint.node_t(),
     95           acc,
     96           (Blueprint.node_t(), acc ->
     97              {Blueprint.node_t(), acc} | {:halt, Blueprint.node_t(), acc}),
     98           (Blueprint.node_t(), acc -> {Blueprint.node_t(), acc})
     99         ) :: {Blueprint.node_t(), acc}
    100         when acc: var
    101   def walk(blueprint, acc, pre, post)
    102 
    103   def walk(nodes, acc, pre, post) when is_list(nodes) do
    104     Enum.map_reduce(nodes, acc, &walk(&1, &2, pre, post))
    105   end
    106 
    107   def walk(node, acc, pre, post) do
    108     {node, acc} =
    109       case pre.(node, acc) do
    110         {:halt, node, acc} ->
    111           {node, acc}
    112 
    113         {node, acc} ->
    114           maybe_walk_children(node, acc, pre, post)
    115       end
    116 
    117     post.(node, acc)
    118   end
    119 
    120   for {node_name, children} <- nodes_with_children do
    121     def maybe_walk_children(%unquote(node_name){} = node, acc, pre, post) do
    122       node_with_children(node, unquote(children), acc, pre, post)
    123     end
    124   end
    125 
    126   def maybe_walk_children(node, acc, _, _) do
    127     {node, acc}
    128   end
    129 
    130   defp node_with_children(node, children, acc, pre, post) do
    131     walk_children(node, children, acc, pre, post)
    132   end
    133 
    134   defp walk_children(node, children, acc, pre, post) do
    135     Enum.reduce(children, {node, acc}, fn child_key, {node, acc} ->
    136       {children, acc} =
    137         node
    138         |> Map.fetch!(child_key)
    139         |> walk(acc, pre, post)
    140 
    141       {Map.put(node, child_key, children), acc}
    142     end)
    143   end
    144 end