import { didYouMean } from '../jsutils/didYouMean' ; import { inspect } from '../jsutils/inspect' ; import { invariant } from '../jsutils/invariant' ; import { isIterableObject } from '../jsutils/isIterableObject' ; import { isObjectLike } from '../jsutils/isObjectLike' ; import type { Path } from '../jsutils/Path' ; import { addPath , pathToArray } from '../jsutils/Path' ; import { printPathArray } from '../jsutils/printPathArray' ; import { suggestionList } from '../jsutils/suggestionList' ; import { GraphQLError } from '../error/GraphQLError' ; import type { GraphQLInputType } from '../type/definition' ; import { isInputObjectType , isLeafType , isListType , isNonNullType , } from '../type/definition' ; type OnErrorCB = ( path : ReadonlyArray < string | number > , invalidValue : unknown , error : GraphQLError ) => void ; /**
 * Coerces a JavaScript value given a GraphQL Input Type.
 */ export function coerceInputValue ( inputValue , type , onError = defaultOnError ) { return coerceInputValueImpl ( inputValue , type , onError , undefined ) ; } function defaultOnError ( path , invalidValue , error ) { let errorPrefix = 'Invalid value ' + inspect ( invalidValue ) ; if ( path . length > 0 ) { errorPrefix += ` at "value${ printPathArray ( path ) }"` ; } error . message = errorPrefix + ': ' + error . message ; throw error ; } function coerceInputValueImpl ( inputValue , type , onError , path ) { if ( isNonNullType ( type ) ) { if ( inputValue != null ) { return coerceInputValueImpl ( inputValue , type . ofType , onError , path ) ; } onError ( pathToArray ( path ) , inputValue , new GraphQLError ( `Expected non-nullable type "${ inspect ( type ) }" not to be null.` ) ) ; return ; } if ( inputValue == null ) { return null ; } if ( isListType ( type ) ) { const itemType = type . ofType ; if ( isIterableObject ( inputValue ) ) { return Array . from ( inputValue , ( itemValue , index ) => { const itemPath = addPath ( path , index , undefined ) ; return coerceInputValueImpl ( itemValue , itemType , onError , itemPath ) ; } ) ; } return [ coerceInputValueImpl ( inputValue , itemType , onError , path ) ] ; } if ( isInputObjectType ( type ) ) { if ( ! isObjectLike ( inputValue ) ) { onError ( pathToArray ( path ) , inputValue , new GraphQLError ( `Expected type "${ type . name }" to be an object.` ) ) ; return ; } const coercedValue = { } ; const fieldDefs = type . getFields ( ) ; for ( const field of Object . values ( fieldDefs ) ) { const fieldValue = inputValue [ field . name ] ; if ( fieldValue === undefined ) { if ( field . defaultValue !== undefined ) { coercedValue [ field . name ] = field . defaultValue ; } else if ( isNonNullType ( field . type ) ) { const typeStr = inspect ( field . type ) ; onError ( pathToArray ( path ) , inputValue , new GraphQLError ( `Field "${ field . name }" of required type "${ typeStr }" was not provided.` ) ) ; } continue ; } coercedValue [ field . name ] = coerceInputValueImpl ( fieldValue , field . type , onError , addPath ( path , field . name , type . name ) ) ; } for ( const fieldName of Object . keys ( inputValue ) ) { if ( ! fieldDefs [ fieldName ] ) { const suggestions = suggestionList ( fieldName , Object . keys ( type . getFields ( ) ) ) ; onError ( pathToArray ( path ) , inputValue , new GraphQLError ( `Field "${ fieldName }" is not defined by type "${ type . name }".` + didYouMean ( suggestions ) ) ) ; } } return coercedValue ; } if ( isLeafType ( type ) ) { let parseResult ; try { parseResult = type . parseValue ( inputValue ) ; } catch ( error ) { if ( error instanceof GraphQLError ) { onError ( pathToArray ( path ) , inputValue , error ) ; } else { onError ( pathToArray ( path ) , inputValue , new GraphQLError ( `Expected type "${ type . name }". ` + error . message , undefined , undefined , undefined , undefined , error ) ) ; } return ; } if ( parseResult === undefined ) { onError ( pathToArray ( path ) , inputValue , new GraphQLError ( `Expected type "${ type . name }".` ) ) ; } return parseResult ; } invariant ( false , 'Unexpected input type: ' + inspect ( type ) ) ; }