UNPKG

@dillonkearns/elm-graphql

Version:

<img src="https://cdn.jsdelivr.net/gh/martimatix/logo-graphqelm/logo.svg" alt="dillonearns/elm-graphql logo" width="40%" align="right">

118 lines (103 loc) 3.37 kB
/** * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import { print } from '../language/printer'; import type { ValueNode, ListValueNode, ObjectValueNode } from '../language/ast'; import * as Kind from '../language/kinds'; import { GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from '../type/definition'; import type { GraphQLInputType } from '../type/definition'; import invariant from '../jsutils/invariant'; import keyMap from '../jsutils/keyMap'; /** * Utility for validators which determines if a value literal node is valid * given an input type. * * Note that this only validates literal values, variables are assumed to * provide values of the correct type. */ export function isValidLiteralValue( type: GraphQLInputType, valueNode: ValueNode ): Array<string> { // A value must be provided if the type is non-null. if (type instanceof GraphQLNonNull) { if (!valueNode || (valueNode.kind === Kind.NULL)) { return [ `Expected "${String(type)}", found null.` ]; } return isValidLiteralValue(type.ofType, valueNode); } if (!valueNode || (valueNode.kind === Kind.NULL)) { return []; } // This function only tests literals, and assumes variables will provide // values of the correct type. if (valueNode.kind === Kind.VARIABLE) { return []; } // Lists accept a non-list value as a list of one. if (type instanceof GraphQLList) { const itemType = type.ofType; if (valueNode.kind === Kind.LIST) { return (valueNode: ListValueNode).values.reduce((acc, item, index) => { const errors = isValidLiteralValue(itemType, item); return acc.concat(errors.map(error => `In element #${index}: ${error}` )); }, []); } return isValidLiteralValue(itemType, valueNode); } // Input objects check each defined field and look for undefined fields. if (type instanceof GraphQLInputObjectType) { if (valueNode.kind !== Kind.OBJECT) { return [ `Expected "${type.name}", found not an object.` ]; } const fields = type.getFields(); const errors = []; // Ensure every provided field is defined. const fieldNodes = (valueNode: ObjectValueNode).fields; fieldNodes.forEach(providedFieldNode => { if (!fields[providedFieldNode.name.value]) { errors.push( `In field "${providedFieldNode.name.value}": Unknown field.` ); } }); // Ensure every defined field is valid. const fieldNodeMap = keyMap(fieldNodes, fieldNode => fieldNode.name.value); Object.keys(fields).forEach(fieldName => { const result = isValidLiteralValue( fields[fieldName].type, fieldNodeMap[fieldName] && fieldNodeMap[fieldName].value ); errors.push(...(result.map(error => `In field "${fieldName}": ${error}` ))); }); return errors; } invariant( type instanceof GraphQLScalarType || type instanceof GraphQLEnumType, 'Must be input type' ); // Scalars determine if a literal values is valid. if (!type.isValidLiteral(valueNode)) { return [ `Expected type "${type.name}", found ${print(valueNode)}.` ]; } return []; }