class GraphQL::Language::Visitor

@see GraphQL::Language::StaticVisitor for a faster visitor that doesn’t support modifying the document
# => 3
visitor.count
# Check the result
visitor.visit
# Run it
visitor = NameCounter.new(document, “name”)
# Initialize a visitor
end
end
super
# Continue visiting subfields:
end
@count += 1
if node.name == @field_name
# if this field matches our search, increment the counter
def on_field(node, parent)
attr_reader :count
end
@count = 0
@field_name = field_name
super(document)
def initialize(document, field_name)
class NameCounter < GraphQL::Language::Visitor
@example Create a visitor counting certain field names
Depth-first traversal through the tree, calling hooks at each stop.

def self.make_visit_methods(ast_node_class)

We don't use `alias` here because it breaks `super`
def self.make_visit_methods(ast_node_class)
  node_method = ast_node_class.visit_method
  children_of_type = ast_node_class.children_of_type
  child_visit_method = :"#{node_method}_children"
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
    # The default implementation for visiting an AST node.
    # It doesn't _do_ anything, but it continues to visiting the node's children.
    # To customize this hook, override one of its make_visit_methods (or the base method?)
    # in your subclasses.
    #
    # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
    # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
    # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
    def #{node_method}(node, parent)
      if node.equal?(DELETE_NODE)
        # This might be passed to `super(DELETE_NODE, ...)`
        # by a user hook, don't want to keep visiting in that case.
        [node, parent]
      else
        new_node = node
        #{
          if method_defined?(child_visit_method)
            "new_node = #{child_visit_method}(new_node)"
          elsif children_of_type
            children_of_type.map do |child_accessor, child_class|
              "node.#{child_accessor}.each do |child_node|
                new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
                # Reassign `node` in case the child hook makes a modification
                if new_child_and_node.is_a?(Array)
                  new_node = new_child_and_node[1]
                end
              end"
            end.join("\n")
          else
            ""
          end
        }
        if new_node.equal?(node)
          [node, parent]
        else
          [new_node, parent]
        end
      end
    end
    def #{node_method}_with_modifications(node, parent)
      new_node_and_new_parent = #{node_method}(node, parent)
      apply_modifications(node, parent, new_node_and_new_parent)
    end
  RUBY
end

def apply_modifications(node, parent, new_node_and_new_parent)

def apply_modifications(node, parent, new_node_and_new_parent)
  if new_node_and_new_parent.is_a?(Array)
    new_node = new_node_and_new_parent[0]
    new_parent = new_node_and_new_parent[1]
    if new_node.is_a?(Nodes::AbstractNode) && !node.equal?(new_node)
      # The user-provided hook returned a new node.
      new_parent = new_parent && new_parent.replace_child(node, new_node)
      return new_node, new_parent
    elsif new_node.equal?(DELETE_NODE)
      # The user-provided hook requested to remove this node
      new_parent = new_parent && new_parent.delete_child(node)
      return nil, new_parent
    elsif new_node_and_new_parent.none? { |n| n == nil || n.class < Nodes::AbstractNode }
      # The user-provided hook returned an array of who-knows-what
      # return nil here to signify that no changes should be made
      nil
    else
      new_node_and_new_parent
    end
  else
    # The user-provided hook didn't make any modifications.
    # In fact, the hook might have returned who-knows-what, so
    # ignore the return value and use the original values.
    new_node_and_new_parent
  end
end

def initialize(document)

def initialize(document)
  @document = document
  @result = nil
end

def on_argument_children(new_node)

def on_argument_children(new_node)
  new_node.children.each do |value_node|
    new_child_and_node = case value_node
    when Language::Nodes::VariableIdentifier
      on_variable_identifier_with_modifications(value_node, new_node)
    when Language::Nodes::InputObject
      on_input_object_with_modifications(value_node, new_node)
    when Language::Nodes::Enum
      on_enum_with_modifications(value_node, new_node)
    when Language::Nodes::NullValue
      on_null_value_with_modifications(value_node, new_node)
    else
      raise ArgumentError, "Invariant: unexpected argument value node #{value_node.class} (#{value_node.inspect})"
    end
    # Reassign `node` in case the child hook makes a modification
    if new_child_and_node.is_a?(Array)
      new_node = new_child_and_node[1]
    end
  end
  new_node
end

def on_document_children(document_node)

def on_document_children(document_node)
  new_node = document_node
  document_node.children.each do |child_node|
    visit_method = :"#{child_node.visit_method}_with_modifications"
    new_child_and_node = public_send(visit_method, child_node, new_node)
    # Reassign `node` in case the child hook makes a modification
    if new_child_and_node.is_a?(Array)
      new_node = new_child_and_node[1]
    end
  end
  new_node
end

def on_field_children(new_node)

def on_field_children(new_node)
  new_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop
    new_child_and_node = on_argument_with_modifications(arg_node, new_node)
    # Reassign `node` in case the child hook makes a modification
    if new_child_and_node.is_a?(Array)
      new_node = new_child_and_node[1]
    end
  end
  new_node = visit_directives(new_node)
  new_node = visit_selections(new_node)
  new_node
end

def on_fragment_definition_children(new_node)

def on_fragment_definition_children(new_node)
  new_node = visit_directives(new_node)
  new_node = visit_selections(new_node)
  new_node
end

def on_operation_definition_children(new_node)

def on_operation_definition_children(new_node)
  new_node.variables.each do |arg_node|
    new_child_and_node = on_variable_definition_with_modifications(arg_node, new_node)
    # Reassign `node` in case the child hook makes a modification
    if new_child_and_node.is_a?(Array)
      new_node = new_child_and_node[1]
    end
  end
  new_node = visit_directives(new_node)
  new_node = visit_selections(new_node)
  new_node
end

def visit

Returns:
  • (void) -
def visit
  # `@document` may be any kind of node:
  visit_method = :"#{@document.visit_method}_with_modifications"
  result = public_send(visit_method, @document, nil)
  @result = if result.is_a?(Array)
    result.first
  else
    # The node wasn't modified
    @document
  end
end

def visit_directives(new_node)

def visit_directives(new_node)
  new_node.directives.each do |dir_node|
    new_child_and_node = on_directive_with_modifications(dir_node, new_node)
    # Reassign `node` in case the child hook makes a modification
    if new_child_and_node.is_a?(Array)
      new_node = new_child_and_node[1]
    end
  end
  new_node
end

def visit_selections(new_node)

def visit_selections(new_node)
  new_node.selections.each do |selection|
    new_child_and_node = case selection
    when GraphQL::Language::Nodes::Field
      on_field_with_modifications(selection, new_node)
    when GraphQL::Language::Nodes::InlineFragment
      on_inline_fragment_with_modifications(selection, new_node)
    when GraphQL::Language::Nodes::FragmentSpread
      on_fragment_spread_with_modifications(selection, new_node)
    else
      raise ArgumentError, "Invariant: unexpected field selection #{selection.class} (#{selection.inspect})"
    end
    # Reassign `node` in case the child hook makes a modification
    if new_child_and_node.is_a?(Array)
      new_node = new_child_and_node[1]
    end
  end
  new_node
end