UNPKG

7 kBJavaScriptView Raw
1function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _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 *
10 */
11import { forEach, isCollection } from 'iterall';
12import objectValues from '../polyfills/objectValues';
13import inspect from '../jsutils/inspect';
14import isInvalid from '../jsutils/isInvalid';
15import orList from '../jsutils/orList';
16import suggestionList from '../jsutils/suggestionList';
17import { GraphQLError } from '../error/GraphQLError';
18import { isScalarType, isEnumType, isInputObjectType, isListType, isNonNullType } from '../type/definition';
19
20/**
21 * Coerces a JavaScript value given a GraphQL Type.
22 *
23 * Returns either a value which is valid for the provided type or a list of
24 * encountered coercion errors.
25 *
26 */
27export function coerceValue(value, type, blameNode, path) {
28 // A value must be provided if the type is non-null.
29 if (isNonNullType(type)) {
30 if (value == null) {
31 return ofErrors([coercionError("Expected non-nullable type ".concat(inspect(type), " not to be null"), blameNode, path)]);
32 }
33
34 return coerceValue(value, type.ofType, blameNode, path);
35 }
36
37 if (value == null) {
38 // Explicitly return the value null.
39 return ofValue(null);
40 }
41
42 if (isScalarType(type)) {
43 // Scalars determine if a value is valid via parseValue(), which can
44 // throw to indicate failure. If it throws, maintain a reference to
45 // the original error.
46 try {
47 var parseResult = type.parseValue(value);
48
49 if (isInvalid(parseResult)) {
50 return ofErrors([coercionError("Expected type ".concat(type.name), blameNode, path)]);
51 }
52
53 return ofValue(parseResult);
54 } catch (error) {
55 return ofErrors([coercionError("Expected type ".concat(type.name), blameNode, path, error.message, error)]);
56 }
57 }
58
59 if (isEnumType(type)) {
60 if (typeof value === 'string') {
61 var enumValue = type.getValue(value);
62
63 if (enumValue) {
64 return ofValue(enumValue.value);
65 }
66 }
67
68 var suggestions = suggestionList(String(value), type.getValues().map(function (enumValue) {
69 return enumValue.name;
70 }));
71 var didYouMean = suggestions.length !== 0 ? "did you mean ".concat(orList(suggestions), "?") : undefined;
72 return ofErrors([coercionError("Expected type ".concat(type.name), blameNode, path, didYouMean)]);
73 }
74
75 if (isListType(type)) {
76 var itemType = type.ofType;
77
78 if (isCollection(value)) {
79 var errors;
80 var coercedValue = [];
81 forEach(value, function (itemValue, index) {
82 var coercedItem = coerceValue(itemValue, itemType, blameNode, atPath(path, index));
83
84 if (coercedItem.errors) {
85 errors = add(errors, coercedItem.errors);
86 } else if (!errors) {
87 coercedValue.push(coercedItem.value);
88 }
89 });
90 return errors ? ofErrors(errors) : ofValue(coercedValue);
91 } // Lists accept a non-list value as a list of one.
92
93
94 var coercedItem = coerceValue(value, itemType, blameNode);
95 return coercedItem.errors ? coercedItem : ofValue([coercedItem.value]);
96 }
97
98 if (isInputObjectType(type)) {
99 if (_typeof(value) !== 'object') {
100 return ofErrors([coercionError("Expected type ".concat(type.name, " to be an object"), blameNode, path)]);
101 }
102
103 var _errors;
104
105 var _coercedValue = {};
106 var fields = type.getFields(); // Ensure every defined field is valid.
107
108 var _iteratorNormalCompletion = true;
109 var _didIteratorError = false;
110 var _iteratorError = undefined;
111
112 try {
113 for (var _iterator = objectValues(fields)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
114 var field = _step.value;
115 var fieldValue = value[field.name];
116
117 if (isInvalid(fieldValue)) {
118 if (!isInvalid(field.defaultValue)) {
119 _coercedValue[field.name] = field.defaultValue;
120 } else if (isNonNullType(field.type)) {
121 _errors = add(_errors, coercionError("Field ".concat(printPath(atPath(path, field.name)), " of required ") + "type ".concat(inspect(field.type), " was not provided"), blameNode));
122 }
123 } else {
124 var coercedField = coerceValue(fieldValue, field.type, blameNode, atPath(path, field.name));
125
126 if (coercedField.errors) {
127 _errors = add(_errors, coercedField.errors);
128 } else if (!_errors) {
129 _coercedValue[field.name] = coercedField.value;
130 }
131 }
132 } // Ensure every provided field is defined.
133
134 } catch (err) {
135 _didIteratorError = true;
136 _iteratorError = err;
137 } finally {
138 try {
139 if (!_iteratorNormalCompletion && _iterator.return != null) {
140 _iterator.return();
141 }
142 } finally {
143 if (_didIteratorError) {
144 throw _iteratorError;
145 }
146 }
147 }
148
149 var _arr = Object.keys(value);
150
151 for (var _i = 0; _i < _arr.length; _i++) {
152 var fieldName = _arr[_i];
153
154 if (!fields[fieldName]) {
155 var _suggestions = suggestionList(fieldName, Object.keys(fields));
156
157 var _didYouMean = _suggestions.length !== 0 ? "did you mean ".concat(orList(_suggestions), "?") : undefined;
158
159 _errors = add(_errors, coercionError("Field \"".concat(fieldName, "\" is not defined by type ").concat(type.name), blameNode, path, _didYouMean));
160 }
161 }
162
163 return _errors ? ofErrors(_errors) : ofValue(_coercedValue);
164 }
165 /* istanbul ignore next */
166
167
168 throw new Error("Unexpected type: ".concat(type, "."));
169}
170
171function ofValue(value) {
172 return {
173 errors: undefined,
174 value: value
175 };
176}
177
178function ofErrors(errors) {
179 return {
180 errors: errors,
181 value: undefined
182 };
183}
184
185function add(errors, moreErrors) {
186 return (errors || []).concat(moreErrors);
187}
188
189function atPath(prev, key) {
190 return {
191 prev: prev,
192 key: key
193 };
194}
195
196function coercionError(message, blameNode, path, subMessage, originalError) {
197 var pathStr = printPath(path); // Return a GraphQLError instance
198
199 return new GraphQLError(message + (pathStr ? ' at ' + pathStr : '') + (subMessage ? '; ' + subMessage : '.'), blameNode, undefined, undefined, undefined, originalError);
200} // Build a string describing the path into the value where the error was found
201
202
203function printPath(path) {
204 var pathStr = '';
205 var currentPath = path;
206
207 while (currentPath) {
208 pathStr = (typeof currentPath.key === 'string' ? '.' + currentPath.key : '[' + String(currentPath.key) + ']') + pathStr;
209 currentPath = currentPath.prev;
210 }
211
212 return pathStr ? 'value' + pathStr : '';
213}
\No newline at end of file