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

sangria.validation.rules.KnownDirectives.scala Maven / Gradle / Ivy

package sangria.validation.rules

import language.postfixOps

import sangria.ast.{AstNode, OperationType}
import sangria.schema.DirectiveLocation

import sangria.ast
import sangria.ast.AstVisitorCommand._
import sangria.validation._

/**
 * Known directives
 *
 * A GraphQL document is only valid if all `@directives` are known by the
 * schema and legally positioned.
 */
class KnownDirectives extends ValidationRule {
   override def visitor(ctx: ValidationContext) = new AstValidatingVisitor {
     override val onEnter: ValidationVisit = {
       case ast.Directive(name, _, _, pos) ⇒
         ctx.schema.directivesByName.get(name) match {
           case None ⇒
             Left(Vector(UnknownDirectiveViolation(name, ctx.sourceMapper, pos.toList)))
           case Some(dir) ⇒
             getCorrectLocation(ctx.typeInfo.ancestors) match {
               case None ⇒
                 Left(Vector(MisplacedDirectiveViolation(name, None, ctx.sourceMapper, pos.toList)))
               case Some((correctLocation, hint)) if !dir.locations.contains(correctLocation) ⇒
                 Left(Vector(MisplacedDirectiveViolation(name, Some(hint), ctx.sourceMapper, pos.toList)))
               case _ ⇒ Right(Continue)
             }
         }
     }

     def getCorrectLocation(ancestors: Seq[AstNode]): Option[(DirectiveLocation.Value, String)] = ancestors.drop(1).head match {
       case op: ast.OperationDefinition if op.operationType == OperationType.Query ⇒
         Some(DirectiveLocation.Query → "query operation")
       case op: ast.OperationDefinition if op.operationType == OperationType.Mutation ⇒
         Some(DirectiveLocation.Mutation → "mutation operation")
       case op: ast.OperationDefinition if op.operationType == OperationType.Subscription ⇒
          Some(DirectiveLocation.Subscription → "subscription operation")

       case _: ast.Field ⇒ Some(DirectiveLocation.Field → "field")
       case _: ast.FragmentDefinition ⇒ Some(DirectiveLocation.FragmentDefinition → "fragment definition")
       case _: ast.FragmentSpread ⇒ Some(DirectiveLocation.FragmentSpread → "fragment spread")
       case _: ast.InlineFragment ⇒ Some(DirectiveLocation.InlineFragment → "inline fragment")

       case _: ast.SchemaDefinition ⇒ Some(DirectiveLocation.Schema → "schema definition")
       case _: ast.ScalarTypeDefinition ⇒ Some(DirectiveLocation.Scalar → "scalar type definition")
       case _: ast.ObjectTypeDefinition ⇒ Some(DirectiveLocation.Object → "object type definition")
       case _: ast.FieldDefinition ⇒ Some(DirectiveLocation.FieldDefinition → "field definition")
       case _: ast.InterfaceTypeDefinition ⇒ Some(DirectiveLocation.Interface → "interface definition")
       case _: ast.UnionTypeDefinition ⇒ Some(DirectiveLocation.Union → "union definition")
       case _: ast.EnumTypeDefinition ⇒ Some(DirectiveLocation.Enum → "enum definition")
       case _: ast.EnumValueDefinition ⇒ Some(DirectiveLocation.EnumValue → "enum value definition")
       case _: ast.InputObjectTypeDefinition ⇒ Some(DirectiveLocation.InputObject → "input object type definition")
       case _: ast.InputValueDefinition ⇒
         ancestors.drop(2).head match {
           case _: ast.InputObjectTypeDefinition ⇒ Some(DirectiveLocation.InputFieldDefinition → "input field definition")
           case x ⇒ Some(DirectiveLocation.ArgumentDefinition → "argument definition")
         }

       case _ ⇒ None
     }
   }
 }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy