import { didYouMean } from '../../jsutils/didYouMean' ; import { inspect } from '../../jsutils/inspect' ; import { keyMap } from '../../jsutils/keyMap' ; import { suggestionList } from '../../jsutils/suggestionList' ; import { GraphQLError } from '../../error/GraphQLError' ; import type { ValueNode } from '../../language/ast' ; import { print } from '../../language/printer' ; import type { ASTVisitor } from '../../language/visitor' ; import { getNamedType , getNullableType , isInputObjectType , isLeafType , isListType , isNonNullType , isRequiredInputField , } from '../../type/definition' ; import type { ValidationContext } from '../ValidationContext' ; /**
 * Value literals of correct type
 *
 * A GraphQL document is only valid if all value literals are of the type
 * expected at their position.
 *
 * See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type
 */ export function ValuesOfCorrectTypeRule ( context ) { return { ListValue ( node ) { const type = getNullableType ( context . getParentInputType ( ) ) ; if ( ! isListType ( type ) ) { isValidValueNode ( context , node ) ; return false ; } } , ObjectValue ( node ) { const type = getNamedType ( context . getInputType ( ) ) ; if ( ! isInputObjectType ( type ) ) { isValidValueNode ( context , node ) ; return false ; } const fieldNodeMap = keyMap ( node . fields , ( field ) => field . name . value ) ; for ( const fieldDef of Object . values ( type . getFields ( ) ) ) { const fieldNode = fieldNodeMap [ fieldDef . name ] ; if ( ! fieldNode && isRequiredInputField ( fieldDef ) ) { const typeStr = inspect ( fieldDef . type ) ; context . reportError ( new GraphQLError ( `Field "${ type . name }.${ fieldDef . name }" of required type "${ typeStr }" was not provided.` , node ) ) ; } } } , ObjectField ( node ) { const parentType = getNamedType ( context . getParentInputType ( ) ) ; const fieldType = context . getInputType ( ) ; if ( ! fieldType && isInputObjectType ( parentType ) ) { const suggestions = suggestionList ( node . name . value , Object . keys ( parentType . getFields ( ) ) ) ; context . reportError ( new GraphQLError ( `Field "${ node . name . value }" is not defined by type "${ parentType . name }".` + didYouMean ( suggestions ) , node ) ) ; } } , NullValue ( node ) { const type = context . getInputType ( ) ; if ( isNonNullType ( type ) ) { context . reportError ( new GraphQLError ( `Expected value of type "${ inspect ( type ) }", found ${ print ( node ) }.` , node ) ) ; } } , EnumValue : ( node ) => isValidValueNode ( context , node ) , IntValue : ( node ) => isValidValueNode ( context , node ) , FloatValue : ( node ) => isValidValueNode ( context , node ) , StringValue : ( node ) => isValidValueNode ( context , node ) , BooleanValue : ( node ) => isValidValueNode ( context , node ) , } ; } /**
 * Any value literal may be a valid representation of a Scalar, depending on
 * that scalar type.
 */ function isValidValueNode ( context , node ) { const locationType = context . getInputType ( ) ; if ( ! locationType ) { return ; } const type = getNamedType ( locationType ) ; if ( ! isLeafType ( type ) ) { const typeStr = inspect ( locationType ) ; context . reportError ( new GraphQLError ( `Expected value of type "${ typeStr }", found ${ print ( node ) }.` , node ) ) ; return ; } try { const parseResult = type . parseLiteral ( node , undefined ) ; if ( parseResult === undefined ) { const typeStr = inspect ( locationType ) ; context . reportError ( new GraphQLError ( `Expected value of type "${ typeStr }", found ${ print ( node ) }.` , node ) ) ; } } catch ( error ) { const typeStr = inspect ( locationType ) ; if ( error instanceof GraphQLError ) { context . reportError ( error ) ; } else { context . reportError ( new GraphQLError ( `Expected value of type "${ typeStr }", found ${ print ( node ) }; ` + error . message , node , undefined , undefined , undefined , error ) ) ; } } }