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

caliban.parsing.parsers.Parsers.scala Maven / Gradle / Ivy

The newest version!
package caliban.parsing.parsers

import caliban.InputValue
import caliban.parsing.ParsedDocument
import caliban.parsing.adt.Definition.ExecutableDefinition._
import caliban.parsing.adt.Definition.TypeSystemDefinition.DirectiveLocation._
import caliban.parsing.adt.Definition.TypeSystemDefinition.TypeDefinition._
import caliban.parsing.adt.Definition.TypeSystemDefinition._
import caliban.parsing.adt.Definition.TypeSystemExtension.TypeExtension._
import caliban.parsing.adt.Definition.TypeSystemExtension._
import caliban.parsing.adt.Definition._
import caliban.parsing.adt.Type._
import caliban.parsing.adt._
import fastparse._

import scala.annotation.nowarn

@nowarn("msg=NoWhitespace") // False positive warning in Scala 2.12.x
object Parsers extends SelectionParsers {
  def argumentDefinition(implicit ev: P[Any]): P[InputValueDefinition]        =
    (stringValue.? ~ name ~ ":" ~ type_ ~ defaultValue.? ~ directives.?).map {
      case (description, name, type_, defaultValue, directives) =>
        InputValueDefinition(description.map(_.value), name, type_, defaultValue, directives.getOrElse(Nil))
    }
  def argumentDefinitions(implicit ev: P[Any]): P[List[InputValueDefinition]] =
    ("(" ~/ argumentDefinition.rep ~ ")").map(_.toList)

  def fieldDefinition(implicit ev: P[Any]): P[FieldDefinition] =
    (stringValue.? ~ name ~ argumentDefinitions.? ~ ":" ~ type_ ~ directives.?).map {
      case (description, name, args, type_, directives) =>
        FieldDefinition(description.map(_.value), name, args.getOrElse(Nil), type_, directives.getOrElse(Nil))
    }

  def variableDefinitions(implicit ev: P[Any]): P[List[VariableDefinition]] =
    ("(" ~/ variableDefinition.rep ~ ")").map(_.toList)

  def variableDefinition(implicit ev: P[Any]): P[VariableDefinition] =
    (variableValue ~ ":" ~/ type_ ~ defaultValue.? ~ directives).map { case (v, t, default, dirs) =>
      VariableDefinition(v.name, t, default, dirs)
    }
  def defaultValue(implicit ev: P[Any]): P[InputValue]               = "=" ~/ value

  def operationType(implicit ev: P[Any]): P[OperationType] =
    StringIn("query", "mutation", "subscription").!.map {
      case "query"        => OperationType.Query
      case "mutation"     => OperationType.Mutation
      case "subscription" => OperationType.Subscription
    }

  def operationDefinition(implicit ev: P[Any]): P[OperationDefinition] =
    (operationType ~/ name.? ~ variableDefinitions.? ~ directives ~ selectionSet).map {
      case (operationType, name, variableDefinitions, directives, selection) =>
        OperationDefinition(operationType, name, variableDefinitions.getOrElse(Nil), directives, selection)
    } | selectionSet.map(selection => OperationDefinition(OperationType.Query, None, Nil, Nil, selection))

  def fragmentDefinition(implicit ev: P[Any]): P[FragmentDefinition] =
    ("fragment" ~/ fragmentName ~ typeCondition ~ directives ~ selectionSet).map {
      case (name, typeCondition, dirs, sel) => FragmentDefinition(name, typeCondition, dirs, sel)
    }

  def objectTypeDefinition(implicit ev: P[Any]): P[ObjectTypeDefinition] =
    (stringValue.? ~ "type" ~/ name ~ implements.? ~ directives.? ~ "{" ~ fieldDefinition.rep ~ "}").map {
      case (description, name, implements, directives, fields) =>
        ObjectTypeDefinition(
          description.map(_.value),
          name,
          implements.getOrElse(Nil),
          directives.getOrElse(Nil),
          fields.toList
        )
    }

  def implements(implicit ev: P[Any]): P[List[NamedType]] =
    ("implements" ~ ("&".? ~ namedType) ~ ("&" ~ namedType).rep).map { case (head, tail) =>
      head :: tail.toList
    }

  def interfaceTypeDefinition(implicit ev: P[Any]): P[InterfaceTypeDefinition] =
    (stringValue.? ~ "interface" ~/ name ~ implements.? ~ directives.? ~ "{" ~ fieldDefinition.rep ~ "}").map {
      case (description, name, implements, directives, fields) =>
        InterfaceTypeDefinition(
          description.map(_.value),
          name,
          implements.getOrElse(Nil),
          directives.getOrElse(Nil),
          fields.toList
        )
    }

  def inputObjectTypeDefinition(implicit ev: P[Any]): P[InputObjectTypeDefinition] =
    (stringValue.? ~ "input" ~/ name ~ directives.? ~ ("{" ~ argumentDefinition.rep ~ "}").?).map {
      case (description, name, directives, fields) =>
        InputObjectTypeDefinition(
          description.map(_.value),
          name,
          directives = directives.getOrElse(Nil),
          fields = fields.fold(List[InputValueDefinition]())(_.toList)
        )
    }

  def enumValueDefinition(implicit ev: P[Any]): P[EnumValueDefinition] =
    (stringValue.? ~ name ~ directives.?).map { case (description, enumValue, directives) =>
      EnumValueDefinition(description.map(_.value), enumValue, directives.getOrElse(Nil))
    }

  def enumName(implicit ev: P[Any]): P[String] = name.filter(s => s != "true" && s != "false" && s != "null")

  def enumTypeDefinition(implicit ev: P[Any]): P[EnumTypeDefinition] =
    (stringValue.? ~ "enum" ~/ enumName ~ directives.? ~ ("{" ~ enumValueDefinition.rep ~ "}").?).map {
      case (description, name, directives, enumValuesDefinition) =>
        EnumTypeDefinition(
          description.map(_.value),
          name,
          directives = directives.getOrElse(Nil),
          enumValuesDefinition.fold(List[EnumValueDefinition]())(_.toList)
        )
    }

  def unionTypeDefinition(implicit ev: P[Any]): P[UnionTypeDefinition] =
    (stringValue.? ~ "union" ~/ name ~ directives.? ~ "=" ~ ("|".? ~ namedType) ~ ("|" ~ namedType).rep).map {
      case (description, name, directives, m, ms) =>
        UnionTypeDefinition(description.map(_.value), name, directives.getOrElse(Nil), (m :: ms.toList).map(_.name))
    }

  def scalarTypeDefinition(implicit ev: P[Any]): P[ScalarTypeDefinition] =
    (stringValue.? ~ "scalar" ~/ name ~ directives.?).map { case (description, name, directives) =>
      ScalarTypeDefinition(description.map(_.value), name, directives.getOrElse(Nil))
    }

  def rootOperationTypeDefinition(implicit ev: P[Any]): P[(OperationType, NamedType)] =
    operationType ~ ":" ~ namedType

  def schemaDefinition(implicit ev: P[Any]): P[SchemaDefinition] =
    (stringValue.? ~ "schema" ~/ directives.? ~ "{" ~ rootOperationTypeDefinition.rep ~ "}").map {
      case (description, directives, ops) =>
        val opsMap = ops.toMap
        SchemaDefinition(
          directives.getOrElse(Nil),
          opsMap.get(OperationType.Query).map(_.name),
          opsMap.get(OperationType.Mutation).map(_.name),
          opsMap.get(OperationType.Subscription).map(_.name),
          description.map(_.value)
        )
    }

  def schemaExtensionWithOptionalDirectivesAndOperations(implicit ev: P[Any]): P[SchemaExtension] =
    (directives.? ~ "{" ~ rootOperationTypeDefinition.rep ~ "}").map { case (directives, ops) =>
      val opsMap = ops.toMap
      SchemaExtension(
        directives.getOrElse(Nil),
        opsMap.get(OperationType.Query).map(_.name),
        opsMap.get(OperationType.Mutation).map(_.name),
        opsMap.get(OperationType.Subscription).map(_.name)
      )
    }

  def schemaExtensionWithDirectives(implicit ev: P[Any]): P[SchemaExtension] =
    directives.map(SchemaExtension(_, None, None, None))

  def schemaExtension(implicit ev: P[Any]): P[SchemaExtension] =
    "extend schema" ~/ (NoCut(schemaExtensionWithOptionalDirectivesAndOperations) | schemaExtensionWithDirectives)

  def scalarTypeExtension(implicit ev: P[Any]): P[ScalarTypeExtension] =
    ("extend scalar" ~/ name ~ directives).map { case (name, directives) =>
      ScalarTypeExtension(name, directives)
    }

  def objectTypeExtensionWithOptionalInterfacesOptionalDirectivesAndFields(implicit
    ev: P[Any]
  ): P[ObjectTypeExtension] =
    (name ~ implements.? ~ directives.? ~ "{" ~ fieldDefinition.rep ~ "}").map {
      case (name, implements, directives, fields) =>
        ObjectTypeExtension(
          name,
          implements.getOrElse(Nil),
          directives.getOrElse(Nil),
          fields.toList
        )
    }

  def objectTypeExtensionWithOptionalInterfacesAndDirectives(implicit ev: P[Any]): P[ObjectTypeExtension] =
    (name ~ implements.? ~ directives ~ !("{" ~ fieldDefinition.rep ~ "}")).map { case (name, implements, directives) =>
      ObjectTypeExtension(
        name,
        implements.getOrElse(Nil),
        directives,
        Nil
      )
    }

  def objectTypeExtensionWithInterfaces(implicit ev: P[Any]): P[ObjectTypeExtension] =
    (name ~ implements).map { case (name, implements) =>
      ObjectTypeExtension(
        name,
        implements,
        Nil,
        Nil
      )
    }

  def objectTypeExtension(implicit ev: P[Any]): P[ObjectTypeExtension] =
    "extend type" ~/ (
      NoCut(objectTypeExtensionWithOptionalInterfacesOptionalDirectivesAndFields) |
        NoCut(objectTypeExtensionWithOptionalInterfacesAndDirectives) |
        objectTypeExtensionWithInterfaces
    )

  def interfaceTypeExtensionWithOptionalDirectivesAndFields(implicit ev: P[Any]): P[InterfaceTypeExtension] =
    (name ~ directives.? ~ "{" ~ fieldDefinition.rep ~ "}").map { case (name, directives, fields) =>
      InterfaceTypeExtension(name, directives.getOrElse(Nil), fields.toList)
    }

  def interfaceTypeExtensionWithDirectives(implicit ev: P[Any]): P[InterfaceTypeExtension] =
    (name ~ directives).map { case (name, directives) =>
      InterfaceTypeExtension(name, directives, Nil)
    }

  def interfaceTypeExtension(implicit ev: P[Any]): P[InterfaceTypeExtension] =
    "extend interface" ~/ (
      NoCut(interfaceTypeExtensionWithOptionalDirectivesAndFields) |
        interfaceTypeExtensionWithDirectives
    )

  def unionTypeExtensionWithOptionalDirectivesAndUnionMembers(implicit ev: P[Any]): P[UnionTypeExtension] =
    (name ~ directives.? ~ "=" ~ ("|".? ~ namedType) ~ ("|" ~ namedType).rep).map { case (name, directives, m, ms) =>
      UnionTypeExtension(name, directives.getOrElse(Nil), (m :: ms.toList).map(_.name))
    }

  def unionTypeExtensionWithDirectives(implicit ev: P[Any]): P[UnionTypeExtension] =
    (name ~ directives).map { case (name, directives) =>
      UnionTypeExtension(name, directives, Nil)
    }

  def unionTypeExtension(implicit ev: P[Any]): P[UnionTypeExtension] =
    "extend union" ~/
      (NoCut(unionTypeExtensionWithOptionalDirectivesAndUnionMembers) | unionTypeExtensionWithDirectives)

  def enumTypeExtensionWithOptionalDirectivesAndValues(implicit ev: P[Any]): P[EnumTypeExtension] =
    (enumName ~ directives.? ~ "{" ~ enumValueDefinition.rep ~ "}").map {
      case (name, directives, enumValuesDefinition) =>
        EnumTypeExtension(name, directives.getOrElse(Nil), enumValuesDefinition.toList)
    }

  def enumTypeExtensionWithDirectives(implicit ev: P[Any]): P[EnumTypeExtension] =
    (enumName ~ directives).map { case (name, directives) =>
      EnumTypeExtension(name, directives, Nil)
    }

  def enumTypeExtension(implicit ev: P[Any]): P[EnumTypeExtension] =
    ("extend enum" ~/ (NoCut(enumTypeExtensionWithOptionalDirectivesAndValues) | enumTypeExtensionWithDirectives))

  def inputObjectTypeExtensionWithOptionalDirectivesAndFields(implicit ev: P[Any]): P[InputObjectTypeExtension] =
    (name ~ directives.? ~ "{" ~ argumentDefinition.rep ~ "}").map { case (name, directives, fields) =>
      InputObjectTypeExtension(name, directives.getOrElse(Nil), fields.toList)
    }

  def inputObjectTypeExtensionWithDirectives(implicit ev: P[Any]): P[InputObjectTypeExtension] =
    (name ~ directives).map { case (name, directives) =>
      InputObjectTypeExtension(name, directives, Nil)
    }

  def inputObjectTypeExtension(implicit ev: P[Any]): P[InputObjectTypeExtension] =
    "extend input" ~/ (
      NoCut(inputObjectTypeExtensionWithOptionalDirectivesAndFields) |
        inputObjectTypeExtensionWithDirectives
    )

  def directiveLocation(implicit ev: P[Any]): P[DirectiveLocation] =
    (
      StringIn(
        "QUERY",
        "MUTATION",
        "SUBSCRIPTION",
        "FIELD",
        "FRAGMENT_DEFINITION",
        "FRAGMENT_SPREAD",
        "INLINE_FRAGMENT",
        "SCHEMA",
        "SCALAR",
        "OBJECT",
        "FIELD_DEFINITION",
        "ARGUMENT_DEFINITION",
        "INTERFACE",
        "UNION",
        "ENUM",
        "ENUM_VALUE",
        "INPUT_OBJECT",
        "INPUT_FIELD_DEFINITION"
      ).!
    ).map {
      case "QUERY"                  => ExecutableDirectiveLocation.QUERY
      case "MUTATION"               => ExecutableDirectiveLocation.MUTATION
      case "SUBSCRIPTION"           => ExecutableDirectiveLocation.SUBSCRIPTION
      case "FIELD"                  => ExecutableDirectiveLocation.FIELD
      case "FRAGMENT_DEFINITION"    => ExecutableDirectiveLocation.FRAGMENT_DEFINITION
      case "FRAGMENT_SPREAD"        => ExecutableDirectiveLocation.FRAGMENT_SPREAD
      case "INLINE_FRAGMENT"        => ExecutableDirectiveLocation.INLINE_FRAGMENT
      case "SCHEMA"                 => TypeSystemDirectiveLocation.SCHEMA
      case "SCALAR"                 => TypeSystemDirectiveLocation.SCALAR
      case "OBJECT"                 => TypeSystemDirectiveLocation.OBJECT
      case "FIELD_DEFINITION"       => TypeSystemDirectiveLocation.FIELD_DEFINITION
      case "ARGUMENT_DEFINITION"    => TypeSystemDirectiveLocation.ARGUMENT_DEFINITION
      case "INTERFACE"              => TypeSystemDirectiveLocation.INTERFACE
      case "UNION"                  => TypeSystemDirectiveLocation.UNION
      case "ENUM"                   => TypeSystemDirectiveLocation.ENUM
      case "ENUM_VALUE"             => TypeSystemDirectiveLocation.ENUM_VALUE
      case "INPUT_OBJECT"           => TypeSystemDirectiveLocation.INPUT_OBJECT
      case "INPUT_FIELD_DEFINITION" => TypeSystemDirectiveLocation.INPUT_FIELD_DEFINITION
      case "VARIABLE_DEFINITION"    => TypeSystemDirectiveLocation.VARIABLE_DEFINITION
    }

  def directiveDefinition(implicit ev: P[Any]): P[DirectiveDefinition] =
    (
      stringValue.? ~ "directive @" ~/ name ~ argumentDefinitions.? ~ "repeatable".!.? ~ "on" ~ ("|".? ~ directiveLocation) ~ ("|" ~ directiveLocation).rep
    ).map { case (description, name, args, repeatable, firstLoc, otherLoc) =>
      DirectiveDefinition(
        description.map(_.value),
        name,
        args.getOrElse(Nil),
        repeatable.isDefined,
        otherLoc.toSet + firstLoc
      )
    }

  def typeDefinition(implicit ev: P[Any]): P[TypeDefinition] =
    objectTypeDefinition |
      interfaceTypeDefinition |
      inputObjectTypeDefinition |
      enumTypeDefinition |
      unionTypeDefinition |
      scalarTypeDefinition

  def typeSystemDefinition(implicit ev: P[Any]): P[TypeSystemDefinition] =
    typeDefinition | schemaDefinition | directiveDefinition

  def executableDefinition(implicit ev: P[Any]): P[ExecutableDefinition] =
    operationDefinition | fragmentDefinition

  def typeExtension(implicit ev: P[Any]): P[TypeExtension] =
    objectTypeExtension |
      interfaceTypeExtension |
      inputObjectTypeExtension |
      enumTypeExtension |
      unionTypeExtension |
      scalarTypeExtension

  def typeSystemExtension(implicit ev: P[Any]): P[TypeSystemExtension] =
    schemaExtension | typeExtension

  def definition(implicit ev: P[Any]): P[Definition] =
    executableDefinition | typeSystemDefinition | typeSystemExtension

  def document(implicit ev: P[Any]): P[ParsedDocument] =
    ((Start ~ executableDefinition.rep ~ End) | (Start ~ definition.rep ~ End)).map(seq => ParsedDocument(seq.toList))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy