All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.language.NodeTraverser Maven / Gradle / Ivy

There is a newer version: 230521-nf-execution
Show newest version
package graphql.language;

import graphql.PublicApi;
import graphql.util.SimpleTraverserContext;
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 {


    /**
     * Used by depthFirst to indicate via {@link TraverserContext#getVar(Class)} if the visit happens inside the ENTER or LEAVE phase.
     */
    public enum LeaveOrEnter {
        LEAVE,
        ENTER
    }

    private final Map, Object> rootVars;
    private final Function> getChildren;

    public NodeTraverser(Map, Object> rootVars, Function> getChildren) {
        this.rootVars = rootVars;
        this.getChildren = getChildren;
    }

    public NodeTraverser() {
        this(Collections.emptyMap(), Node::getChildren);
    }


    /**
     * depthFirst traversal with a enter/leave phase.
     *
     * @param nodeVisitor
     * @param root
     */
    public void depthFirst(NodeVisitor nodeVisitor, Node root) {
        depthFirst(nodeVisitor, Collections.singleton(root));
    }

    /**
     * depthFirst traversal with a enter/leave phase.
     *
     * @param nodeVisitor
     * @param roots
     */
    public void depthFirst(NodeVisitor nodeVisitor, Collection roots) {
        TraverserVisitor nodeTraverserVisitor = new TraverserVisitor() {

            @Override
            public TraversalControl enter(TraverserContext context) {
                context.setVar(LeaveOrEnter.class, LeaveOrEnter.ENTER);
                return context.thisNode().accept(context, nodeVisitor);
            }

            @Override
            public TraversalControl leave(TraverserContext context) {
                context.setVar(LeaveOrEnter.class, LeaveOrEnter.LEAVE);
                return context.thisNode().accept(context, nodeVisitor);
            }

        };
        doTraverse(roots, nodeTraverserVisitor);
    }

    /**
     * Version of {@link #preOrder(NodeVisitor, Collection)} with one root.
     *
     * @param nodeVisitor
     * @param root
     */
    public void preOrder(NodeVisitor nodeVisitor, Node root) {
        preOrder(nodeVisitor, Collections.singleton(root));
    }

    /**
     * Pre-Order traversal: This is a specialized version of depthFirst with only the enter phase.
     *
     * @param nodeVisitor
     * @param roots
     */
    public void preOrder(NodeVisitor nodeVisitor, Collection roots) {
        TraverserVisitor nodeTraverserVisitor = new TraverserVisitor() {

            @Override
            public TraversalControl enter(TraverserContext context) {
                context.setVar(LeaveOrEnter.class, LeaveOrEnter.ENTER);
                return context.thisNode().accept(context, nodeVisitor);
            }

            @Override
            public TraversalControl leave(TraverserContext context) {
                return TraversalControl.CONTINUE;
            }

        };
        doTraverse(roots, nodeTraverserVisitor);

    }

    /**
     * Version of {@link #postOrder(NodeVisitor, Collection)} with one root.
     *
     * @param nodeVisitor
     * @param root
     */
    public void postOrder(NodeVisitor nodeVisitor, Node root) {
        postOrder(nodeVisitor, Collections.singleton(root));
    }

    /**
     * Post-Order traversal: This is a specialized version of depthFirst with only the leave phase.
     *
     * @param nodeVisitor
     * @param roots
     */
    public void postOrder(NodeVisitor nodeVisitor, Collection roots) {
        TraverserVisitor nodeTraverserVisitor = new TraverserVisitor() {

            @Override
            public TraversalControl enter(TraverserContext context) {
                return TraversalControl.CONTINUE;
            }

            @Override
            public TraversalControl leave(TraverserContext context) {
                context.setVar(LeaveOrEnter.class, LeaveOrEnter.LEAVE);
                return context.thisNode().accept(context, nodeVisitor);
            }

        };
        doTraverse(roots, nodeTraverserVisitor);
    }

    private void doTraverse(Collection roots, TraverserVisitor traverserVisitor) {
        Traverser nodeTraverser = Traverser.depthFirst(this.getChildren);
        nodeTraverser.rootVars(rootVars);
        nodeTraverser.traverse(roots, traverserVisitor);
    }

    @SuppressWarnings("TypeParameterUnusedInFormals")
    public static  T oneVisitWithResult(Node node, NodeVisitor nodeVisitor) {
        SimpleTraverserContext context = new SimpleTraverserContext<>(node);
        node.accept(context, nodeVisitor);
        return (T) context.getResult();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy