1var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 2 3/** 4 * Copyright (c) 2015-present, Facebook, Inc. 5 * 6 * This source code is licensed under the MIT license found in the 7 * LICENSE file in the root directory of this source tree. 8 * 9 * strict 10 */ 11 12import { forEach, isCollection } from 'iterall'; 13import isInvalid from '../jsutils/isInvalid'; 14import isNullish from '../jsutils/isNullish'; 15import orList from '../jsutils/orList'; 16import suggestionList from '../jsutils/suggestionList'; 17import { GraphQLError } from '../error'; 18 19import { isScalarType, isEnumType, isInputObjectType, isListType, isNonNullType } from '../type/definition'; 20 21 22/** 23 * Coerces a JavaScript value given a GraphQL Type. 24 * 25 * Returns either a value which is valid for the provided type or a list of 26 * encountered coercion errors. 27 * 28 */ 29export function coerceValue(value, type, blameNode, path) { 30 // A value must be provided if the type is non-null. 31 if (isNonNullType(type)) { 32 if (isNullish(value)) { 33 return ofErrors([coercionError('Expected non-nullable type ' + String(type) + ' not to be null', blameNode, path)]); 34 } 35 return coerceValue(value, type.ofType, blameNode, path); 36 } 37 38 if (isNullish(value)) { 39 // Explicitly return the value null. 40 return ofValue(null); 41 } 42 43 if (isScalarType(type)) { 44 // Scalars determine if a value is valid via parseValue(), which can 45 // throw to indicate failure. If it throws, maintain a reference to 46 // the original error. 47 try { 48 var parseResult = type.parseValue(value); 49 if (isInvalid(parseResult)) { 50 return ofErrors([coercionError('Expected type ' + type.name, blameNode, path)]); 51 } 52 return ofValue(parseResult); 53 } catch (error) { 54 return ofErrors([coercionError('Expected type ' + type.name, blameNode, path, error.message, error)]); 55 } 56 } 57 58 if (isEnumType(type)) { 59 if (typeof value === 'string') { 60 var enumValue = type.getValue(value); 61 if (enumValue) { 62 return ofValue(enumValue.value); 63 } 64 } 65 var suggestions = suggestionList(String(value), type.getValues().map(function (enumValue) { 66 return enumValue.name; 67 })); 68 var didYouMean = suggestions.length !== 0 ? 'did you mean ' + orList(suggestions) + '?' : undefined; 69 return ofErrors([coercionError('Expected type ' + type.name, blameNode, path, didYouMean)]); 70 } 71 72 if (isListType(type)) { 73 var itemType = type.ofType; 74 if (isCollection(value)) { 75 var _errors = void 0; 76 var coercedValue = []; 77 forEach(value, function (itemValue, index) { 78 var coercedItem = coerceValue(itemValue, itemType, blameNode, atPath(path, index)); 79 if (coercedItem.errors) { 80 _errors = add(_errors, coercedItem.errors); 81 } else if (!_errors) { 82 coercedValue.push(coercedItem.value); 83 } 84 }); 85 return _errors ? ofErrors(_errors) : ofValue(coercedValue); 86 } 87 // Lists accept a non-list value as a list of one. 88 var coercedItem = coerceValue(value, itemType, blameNode); 89 return coercedItem.errors ? coercedItem : ofValue([coercedItem.value]); 90 } 91 92 if (isInputObjectType(type)) { 93 if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object') { 94 return ofErrors([coercionError('Expected type ' + type.name + ' to be an object', blameNode, path)]); 95 } 96 var _errors2 = void 0; 97 var _coercedValue = {}; 98 var fields = type.getFields(); 99 100 // Ensure every defined field is valid. 101 for (var fieldName in fields) { 102 if (hasOwnProperty.call(fields, fieldName)) { 103 var field = fields[fieldName]; 104 var fieldValue = value[fieldName]; 105 if (isInvalid(fieldValue)) { 106 if (!isInvalid(field.defaultValue)) { 107 _coercedValue[fieldName] = field.defaultValue; 108 } else if (isNonNullType(field.type)) { 109 _errors2 = add(_errors2, coercionError('Field ' + printPath(atPath(path, fieldName)) + ' of required ' + ('type ' + String(field.type) + ' was not provided'), blameNode)); 110 } 111 } else { 112 var coercedField = coerceValue(fieldValue, field.type, blameNode, atPath(path, fieldName)); 113 if (coercedField.errors) { 114 _errors2 = add(_errors2, coercedField.errors); 115 } else if (!_errors2) { 116 _coercedValue[fieldName] = coercedField.value; 117 } 118 } 119 } 120 } 121 122 // Ensure every provided field is defined. 123 for (var _fieldName in value) { 124 if (hasOwnProperty.call(value, _fieldName)) { 125 if (!fields[_fieldName]) { 126 var _suggestions = suggestionList(_fieldName, Object.keys(fields)); 127 var _didYouMean = _suggestions.length !== 0 ? 'did you mean ' + orList(_suggestions) + '?' : undefined; 128 _errors2 = add(_errors2, coercionError('Field "' + _fieldName + '" is not defined by type ' + type.name, blameNode, path, _didYouMean)); 129 } 130 } 131 } 132 133 return _errors2 ? ofErrors(_errors2) : ofValue(_coercedValue); 134 } 135 136 /* istanbul ignore next */ 137 throw new Error('Unexpected type: ' + type + '.'); 138} 139 140function ofValue(value) { 141 return { errors: undefined, value: value }; 142} 143 144function ofErrors(errors) { 145 return { errors: errors, value: undefined }; 146} 147 148function add(errors, moreErrors) { 149 return (errors || []).concat(moreErrors); 150} 151 152function atPath(prev, key) { 153 return { prev: prev, key: key }; 154} 155 156function coercionError(message, blameNode, path, subMessage, originalError) { 157 var pathStr = printPath(path); 158 // Return a GraphQLError instance 159 return new GraphQLError(message + (pathStr ? ' at ' + pathStr : '') + (subMessage ? '; ' + subMessage : '.'), blameNode, undefined, undefined, undefined, originalError); 160} 161 162// Build a string describing the path into the value where the error was found 163function printPath(path) { 164 var pathStr = ''; 165 var currentPath = path; 166 while (currentPath) { 167 pathStr = (typeof currentPath.key === 'string' ? '.' + currentPath.key : '[' + String(currentPath.key) + ']') + pathStr; 168 currentPath = currentPath.prev; 169 } 170 return pathStr ? 'value' + pathStr : ''; 171} 172 173var hasOwnProperty = Object.prototype.hasOwnProperty;