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;