import * as GraphQL from "graphql" ; import { DocumentDefinitionTuple , FragmentMap , FieldNodeWithSelectionSet , GetObjectId , Variables , GetObjectToIdResult , ResponseObject , ResolveType } from "./types" ; export function getDocumentDefinitions ( definitions ) { let operationDefinition = undefined ; const fragmentMap = { } ; for ( const definition of definitions ) { switch ( definition . kind ) { case "OperationDefinition" : operationDefinition = definition ; break ; case "FragmentDefinition" : fragmentMap [ definition . name . value ] = definition ; break ; default : throw new Error ( "This is not an executable document" ) ; } } const rootFieldNode = { kind : "Field" , name : { kind : "Name" , value : "data" } , selectionSet : { kind : "SelectionSet" , selections : operationDefinition ! . selectionSet . selections } } ; return [ fragmentMap , rootFieldNode ] ; } export function expandFragments ( resolveType , obj , selectionNodes , fragmentMap ) { const fieldNodes = [ ] ; for ( const selectionNode of selectionNodes ) { switch ( selectionNode . kind ) { case "Field" : fieldNodes . push ( selectionNode ) ; break ; case "InlineFragment" : { const fragmentTypeName = selectionNode . typeCondition && selectionNode . typeCondition . name . value ; const objTypeName = resolveType ( obj ) ; if ( fragmentTypeName === objTypeName ) { fieldNodes . push ( ... expandFragments ( resolveType , obj , selectionNode . selectionSet . selections , fragmentMap ) ) ; } break ; } case "FragmentSpread" : { const fragment = fragmentMap [ selectionNode . name . value ] ; const fragmentTypeName = fragment . typeCondition && fragment . typeCondition . name . value ; const objTypeName = resolveType ( obj ) ; if ( fragmentTypeName === objTypeName ) { fieldNodes . push ( ... expandFragments ( resolveType , obj , fragment . selectionSet . selections , fragmentMap ) ) ; } break ; } default : throw new Error ( "Unknown selection node field kind: " + ( selectionNode as any ) . kind ) ; } } return fieldNodes ; } function resolveValueNode ( valueNode , variables ) { switch ( valueNode . kind ) { case "Variable" : return variables ! [ valueNode . name . value ] ; case "NullValue" : return null ; case "ListValue" : return valueNode . values . map ( f => resolveValueNode ( f , variables ) ) ; case "ObjectValue" : const valueObject = { } ; for ( const field of valueNode . fields ) { valueObject [ field . name . value ] = resolveValueNode ( field . value , variables ) ; } return valueObject ; default : return valueNode . value ; } } export function fieldNameWithArguments ( fieldNode , variables ) { const argumentsObject = { } ; for ( const argumentNode of fieldNode . arguments ! ) { argumentsObject [ argumentNode . name . value ] = resolveValueNode ( argumentNode . value , variables ) ; } const hashedArgs = JSON . stringify ( argumentsObject ) ; return fieldNode . name . value + "(" + hashedArgs + ")" ; } export const defaultGetObjectId = ( object ) : GetObjectToIdResult => { return object . id === undefined ? undefined : `${ object . __typename }:${ object . id }` ; } ; export const defaultResolveType = ( object ) : string => { if ( object . __typename === undefined ) { throw new Error ( "__typename cannot be undefined." ) ; } return object . __typename ; } ; /**
 * Evaluates  @skip and @include directives on field
 * and returns true if the node should be included.
 */ export function shouldIncludeField ( directives , variables = { } ) { let finalInclude = true ; for ( const directive of directives ) { let directiveInclude = true ; if ( directive . name . value === "skip" || directive . name . value === "include" ) { if ( directive . arguments ) { for ( const arg of directive . arguments ) { if ( arg . name . value === "if" ) { let argValue ; if ( arg . value . kind === "Variable" ) { argValue = variables && ! ! variables [ arg . value . name . value ] ; } else if ( arg . value . kind === "BooleanValue" ) { argValue = arg . value . value ; } else { throw new Error ( `The if argument must be of type Boolean!, found '${ arg . value . kind }'` ) ; } const argInclude = directive . name . value === "include" ? argValue : ! argValue ; directiveInclude = directiveInclude && argInclude ; } } } finalInclude = finalInclude && directiveInclude ; } } return finalInclude ; }