UNPKG

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