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

graphql.language.AstSorter Maven / Gradle / Ivy

package graphql.language;

import graphql.PublicApi;
import graphql.schema.idl.TypeInfo;
import graphql.util.TraversalControl;
import graphql.util.TraverserContext;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;

import static graphql.util.TreeTransformerUtil.changeNode;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.nullsLast;

/**
 * A class that helps you sort AST nodes
 */
@PublicApi
public class AstSorter {

    /**
     * This will sort nodes in specific orders and then alphabetically.
     *
     * The order is :
     * 
    *
  • Query operation definitions
  • *
  • Mutation operation definitions
  • *
  • Subscriptions operation definitions
  • *
  • Fragment definitions
  • *
  • Directive definitions
  • *
  • Schema definitions
  • *
  • Object Type definitions
  • *
  • Interface Type definitions
  • *
  • Union Type definitions
  • *
  • Enum Type definitions
  • *
  • Scalar Type definitions
  • *
  • Input Object Type definitions
  • *
* * After those groupings they will be sorted alphabetic. All arguments and directives on elements * will be sorted alphabetically by name. * * @param nodeToBeSorted the node to be sorted * @param of type {@link graphql.language.Node} * * @return a new sorted node (because {@link graphql.language.Node}s are immutable) */ public T sort(T nodeToBeSorted) { NodeVisitorStub visitor = new NodeVisitorStub() { @Override public TraversalControl visitDocument(Document node, TraverserContext context) { Document changedNode = node.transform(builder -> { List definitions = sort(node.getDefinitions(), comparingDefinitions()); builder.definitions(definitions); }); return changeNode(context, changedNode); } @Override public TraversalControl visitOperationDefinition(OperationDefinition node, TraverserContext context) { OperationDefinition changedNode = node.transform(builder -> { builder.variableDefinitions(sort(node.getVariableDefinitions(), comparing(VariableDefinition::getName))); builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.selectionSet(sortSelectionSet(node.getSelectionSet())); }); return changeNode(context, changedNode); } @Override public TraversalControl visitField(Field node, TraverserContext context) { Field changedNode = node.transform(builder -> { builder.arguments(sort(node.getArguments(), comparing(Argument::getName))); builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.selectionSet(sortSelectionSet(node.getSelectionSet())); }); return changeNode(context, changedNode); } @Override public TraversalControl visitFragmentDefinition(FragmentDefinition node, TraverserContext context) { FragmentDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.selectionSet(sortSelectionSet(node.getSelectionSet())); }); return changeNode(context, changedNode); } @Override public TraversalControl visitInlineFragment(InlineFragment node, TraverserContext context) { InlineFragment changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.selectionSet(sortSelectionSet(node.getSelectionSet())); }); return changeNode(context, changedNode); } @Override public TraversalControl visitFragmentSpread(FragmentSpread node, TraverserContext context) { FragmentSpread changedNode = node.transform(builder -> { List directives = sort(node.getDirectives(), comparing(Directive::getName)); builder.directives(directives); }); return changeNode(context, changedNode); } @Override public TraversalControl visitDirective(Directive node, TraverserContext context) { Directive changedNode = node.transform(builder -> { List arguments = sort(node.getArguments(), comparing(Argument::getName)); builder.arguments(arguments); }); return changeNode(context, changedNode); } @Override public TraversalControl visitObjectValue(ObjectValue node, TraverserContext context) { ObjectValue changedNode = node.transform(builder -> { List objectFields = sort(node.getObjectFields(), comparing(ObjectField::getName)); builder.objectFields(objectFields); }); return changeNode(context, changedNode); } // SDL classes here @Override public TraversalControl visitSchemaDefinition(SchemaDefinition node, TraverserContext context) { SchemaDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.operationTypeDefinitions(sort(node.getOperationTypeDefinitions(), comparing(OperationTypeDefinition::getName))); }); return changeNode(context, changedNode); } @Override public TraversalControl visitEnumTypeDefinition(EnumTypeDefinition node, TraverserContext context) { EnumTypeDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.enumValueDefinitions(sort(node.getEnumValueDefinitions(), comparing(EnumValueDefinition::getName))); }); return changeNode(context, changedNode); } @Override public TraversalControl visitScalarTypeDefinition(ScalarTypeDefinition node, TraverserContext context) { ScalarTypeDefinition changedNode = node.transform(builder -> { List directives = sort(node.getDirectives(), comparing(Directive::getName)); builder.directives(directives); }); return changeNode(context, changedNode); } @Override public TraversalControl visitInputObjectTypeDefinition(InputObjectTypeDefinition node, TraverserContext context) { InputObjectTypeDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.inputValueDefinitions(sort(node.getInputValueDefinitions(), comparing(InputValueDefinition::getName))); }); return changeNode(context, changedNode); } @Override public TraversalControl visitObjectTypeDefinition(ObjectTypeDefinition node, TraverserContext context) { ObjectTypeDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.implementz(sort(node.getImplements(), comparingTypes())); builder.fieldDefinitions(sort(node.getFieldDefinitions(), comparing(FieldDefinition::getName))); }); return changeNode(context, changedNode); } @Override public TraversalControl visitInterfaceTypeDefinition(InterfaceTypeDefinition node, TraverserContext context) { InterfaceTypeDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.implementz(sort(node.getImplements(), comparingTypes())); builder.definitions(sort(node.getFieldDefinitions(), comparing(FieldDefinition::getName))); }); return changeNode(context, changedNode); } @Override public TraversalControl visitUnionTypeDefinition(UnionTypeDefinition node, TraverserContext context) { UnionTypeDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.memberTypes(sort(node.getMemberTypes(), comparingTypes())); }); return changeNode(context, changedNode); } @Override public TraversalControl visitFieldDefinition(FieldDefinition node, TraverserContext context) { FieldDefinition changedNode = node.transform(builder -> { builder.directives(sort(node.getDirectives(), comparing(Directive::getName))); builder.inputValueDefinitions(sort(node.getInputValueDefinitions(), comparing(InputValueDefinition::getName))); }); return changeNode(context, changedNode); } @Override public TraversalControl visitInputValueDefinition(InputValueDefinition node, TraverserContext context) { InputValueDefinition changedNode = node.transform(builder -> { List directives = sort(node.getDirectives(), comparing(Directive::getName)); builder.directives(directives); }); return changeNode(context, changedNode); } @Override public TraversalControl visitDirectiveDefinition(DirectiveDefinition node, TraverserContext context) { DirectiveDefinition changedNode = node.transform(builder -> { builder.inputValueDefinitions(sort(node.getInputValueDefinitions(), comparing(InputValueDefinition::getName))); builder.directiveLocations(sort(node.getDirectiveLocations(), comparing(DirectiveLocation::getName))); }); return changeNode(context, changedNode); } }; AstTransformer astTransformer = new AstTransformer(); Node newDoc = astTransformer.transform(nodeToBeSorted, visitor); //noinspection unchecked return (T) newDoc; } private Comparator comparingTypes() { return comparing(type -> TypeInfo.typeInfo(type).getName()); } private Comparator comparingSelections() { Function byName = s -> { if (s instanceof FragmentSpread) { return ((FragmentSpread) s).getName(); } if (s instanceof Field) { return ((Field) s).getName(); } if (s instanceof InlineFragment) { TypeName typeCondition = ((InlineFragment) s).getTypeCondition(); return typeCondition == null ? "" : typeCondition.getName(); } return ""; }; Function byType = s -> { if (s instanceof Field) { return 1; } if (s instanceof FragmentSpread) { return 2; } if (s instanceof InlineFragment) { return 3; } return 4; }; return comparing(byType).thenComparing(comparing(byName)); } private Comparator comparingDefinitions() { Function byName = d -> { if (d instanceof OperationDefinition) { String name = ((OperationDefinition) d).getName(); return name == null ? "" : name; } if (d instanceof FragmentDefinition) { return ((FragmentDefinition) d).getName(); } if (d instanceof DirectiveDefinition) { return ((DirectiveDefinition) d).getName(); } if (d instanceof TypeDefinition) { return ((TypeDefinition) d).getName(); } return ""; }; Function byType = d -> { if (d instanceof OperationDefinition) { OperationDefinition.Operation operation = ((OperationDefinition) d).getOperation(); if (OperationDefinition.Operation.QUERY == operation || operation == null) { return 101; } if (OperationDefinition.Operation.MUTATION == operation) { return 102; } if (OperationDefinition.Operation.SUBSCRIPTION == operation) { return 104; } return 100; } if (d instanceof FragmentDefinition) { return 200; } // SDL if (d instanceof DirectiveDefinition) { return 300; } if (d instanceof SchemaDefinition) { return 400; } if (d instanceof TypeDefinition) { if (d instanceof ObjectTypeDefinition) { return 501; } if (d instanceof InterfaceTypeDefinition) { return 502; } if (d instanceof UnionTypeDefinition) { return 503; } if (d instanceof EnumTypeDefinition) { return 504; } if (d instanceof ScalarTypeDefinition) { return 505; } if (d instanceof InputObjectTypeDefinition) { return 506; } return 500; } return -1; }; return comparing(byType).thenComparing(byName); } private SelectionSet sortSelectionSet(SelectionSet selectionSet) { if (selectionSet == null) { return null; } List selections = sort(selectionSet.getSelections(), comparingSelections()); return selectionSet.transform(builder -> builder.selections(selections)); } private List sort(List items, Comparator comparing) { items = new ArrayList<>(items); items.sort(comparing); return items; } private > Comparator comparing( Function keyExtractor) { return Comparator.comparing(keyExtractor, nullsLast(naturalOrder())); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy