uses.ex (2331B)
1 defmodule Absinthe.Phase.Document.Uses do 2 @moduledoc false 3 4 # Tracks uses of: 5 # - Variables 6 # - Fragments 7 8 use Absinthe.Phase 9 alias Absinthe.Blueprint 10 11 @typep acc_t :: %{ 12 fragments_available: [Blueprint.Document.Fragment.Named.t()], 13 fragments: [Blueprint.Document.Fragment.Named.Use.t()], 14 variables: [Blueprint.Input.Variable.Use.t()] 15 } 16 17 @spec run(Blueprint.t(), Keyword.t()) :: {:ok, Blueprint.t()} 18 def run(input, _options \\ []) do 19 ops = Enum.map(input.operations, &add_uses(&1, input)) 20 node = %{input | operations: ops} 21 {:ok, node} 22 end 23 24 @spec add_uses(Blueprint.Document.Operation.t(), Blueprint.t()) :: 25 Blueprint.Document.Operation.t() 26 defp add_uses(%Blueprint.Document.Operation{} = node, doc) do 27 acc = %{ 28 fragments_available: doc.fragments, 29 fragments: [], 30 variables: [] 31 } 32 33 {_, acc} = Blueprint.prewalk(node, acc, &handle_use/2) 34 35 %{ 36 node 37 | fragment_uses: acc.fragments ++ node.fragment_uses, 38 variable_uses: acc.variables ++ node.variable_uses 39 } 40 end 41 42 @spec handle_use(Blueprint.node_t(), acc_t) :: {Blueprint.node_t(), acc_t} 43 defp handle_use(%Blueprint.Document.Fragment.Spread{} = node, acc) do 44 if uses?(acc.fragments, node) do 45 {node, acc} 46 else 47 target_fragment = Enum.find(acc.fragments_available, &(&1.name == node.name)) 48 49 if target_fragment do 50 acc = acc |> put_use(target_fragment) 51 {_, acc} = Blueprint.prewalk(target_fragment, acc, &handle_use/2) 52 {node, acc} 53 else 54 {node, acc} 55 end 56 end 57 end 58 59 defp handle_use(%Blueprint.Input.Variable{} = node, acc) do 60 {node, put_use(acc, node)} 61 end 62 63 defp handle_use(node, acc) do 64 {node, acc} 65 end 66 67 @spec uses?([Blueprint.use_t()], Blueprint.Document.Fragment.Spread.t()) :: boolean 68 defp uses?(list, node) do 69 Enum.find(list, &(&1.name == node.name)) 70 end 71 72 @spec put_use(acc_t, Blueprint.node_t()) :: acc_t 73 defp put_use(acc, %Blueprint.Input.Variable{} = node) do 74 ref = Blueprint.Input.Variable.to_use(node) 75 update_in(acc.variables, &[ref | &1]) 76 end 77 78 defp put_use(acc, %Blueprint.Document.Fragment.Named{} = node) do 79 ref = Blueprint.Document.Fragment.Named.to_use(node) 80 update_in(acc.fragments, &[ref | &1]) 81 end 82 end