graphql.language.NodeTraverser Maven / Gradle / Ivy
package graphql.language;
import graphql.PublicApi;
import graphql.collect.ImmutableKit;
import graphql.util.DefaultTraverserContext;
import graphql.util.TraversalControl;
import graphql.util.Traverser;
import graphql.util.TraverserContext;
import graphql.util.TraverserVisitor;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* Lets you traverse a {@link Node} tree.
*/
@PublicApi
public class NodeTraverser {
private final Map, Object> rootVars;
private final Function super Node, ? extends List> getChildren;
public NodeTraverser(Map, Object> rootVars, Function super Node, ? extends List> getChildren) {
this.rootVars = rootVars;
this.getChildren = getChildren;
}
public NodeTraverser() {
this(ImmutableKit.emptyMap(), Node::getChildren);
}
/**
* depthFirst traversal with a enter/leave phase.
*
* @param nodeVisitor the visitor of the nodes
* @param root the root node
*
* @return the accumulation result of this traversal
*/
public Object depthFirst(NodeVisitor nodeVisitor, Node root) {
return depthFirst(nodeVisitor, Collections.singleton(root));
}
/**
* depthFirst traversal with a enter/leave phase.
*
* @param nodeVisitor the visitor of the nodes
* @param roots the root nodes
*
* @return the accumulation result of this traversal
*/
public Object depthFirst(NodeVisitor nodeVisitor, Collection extends Node> roots) {
TraverserVisitor nodeTraverserVisitor = new TraverserVisitor() {
@Override
public TraversalControl enter(TraverserContext context) {
return context.thisNode().accept(context, nodeVisitor);
}
@Override
public TraversalControl leave(TraverserContext context) {
return context.thisNode().accept(context, nodeVisitor);
}
};
return doTraverse(roots, nodeTraverserVisitor);
}
/**
* Version of {@link #preOrder(NodeVisitor, Collection)} with one root.
*
* @param nodeVisitor the visitor of the nodes
* @param root the root node
*
* @return the accumulation result of this traversal
*/
public Object preOrder(NodeVisitor nodeVisitor, Node root) {
return preOrder(nodeVisitor, Collections.singleton(root));
}
/**
* Pre-Order traversal: This is a specialized version of depthFirst with only the enter phase.
*
* @param nodeVisitor the visitor of the nodes
* @param roots the root nodes
*
* @return the accumulation result of this traversal
*/
public Object preOrder(NodeVisitor nodeVisitor, Collection extends Node> roots) {
TraverserVisitor nodeTraverserVisitor = new TraverserVisitor() {
@Override
public TraversalControl enter(TraverserContext context) {
return context.thisNode().accept(context, nodeVisitor);
}
@Override
public TraversalControl leave(TraverserContext context) {
return TraversalControl.CONTINUE;
}
};
return doTraverse(roots, nodeTraverserVisitor);
}
/**
* Version of {@link #postOrder(NodeVisitor, Collection)} with one root.
*
* @param nodeVisitor the visitor of the nodes
* @param root the root node
*
* @return the accumulation result of this traversal
*/
public Object postOrder(NodeVisitor nodeVisitor, Node root) {
return postOrder(nodeVisitor, Collections.singleton(root));
}
/**
* Post-Order traversal: This is a specialized version of depthFirst with only the leave phase.
*
* @param nodeVisitor the visitor of the nodes
* @param roots the root nodes
*
* @return the accumulation result of this traversal
*/
public Object postOrder(NodeVisitor nodeVisitor, Collection extends Node> roots) {
TraverserVisitor nodeTraverserVisitor = new TraverserVisitor() {
@Override
public TraversalControl enter(TraverserContext context) {
return TraversalControl.CONTINUE;
}
@Override
public TraversalControl leave(TraverserContext context) {
return context.thisNode().accept(context, nodeVisitor);
}
};
return doTraverse(roots, nodeTraverserVisitor);
}
private Object doTraverse(Collection extends Node> roots, TraverserVisitor traverserVisitor) {
Traverser nodeTraverser = Traverser.depthFirst(this.getChildren);
nodeTraverser.rootVars(rootVars);
return nodeTraverser.traverse(roots, traverserVisitor).getAccumulatedResult();
}
@SuppressWarnings("TypeParameterUnusedInFormals")
public static T oneVisitWithResult(Node node, NodeVisitor nodeVisitor) {
DefaultTraverserContext context = DefaultTraverserContext.simple(node);
node.accept(context, nodeVisitor);
return (T) context.getNewAccumulate();
}
}