diff options
Diffstat (limited to 'school/node_modules/graphql/utilities/coerceInputValue.js.flow')
-rw-r--r-- | school/node_modules/graphql/utilities/coerceInputValue.js.flow | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/school/node_modules/graphql/utilities/coerceInputValue.js.flow b/school/node_modules/graphql/utilities/coerceInputValue.js.flow new file mode 100644 index 0000000..a42fa06 --- /dev/null +++ b/school/node_modules/graphql/utilities/coerceInputValue.js.flow @@ -0,0 +1,195 @@ +// @flow strict +import objectValues from '../polyfills/objectValues'; + +import type { Path } from '../jsutils/Path'; +import inspect from '../jsutils/inspect'; +import invariant from '../jsutils/invariant'; +import didYouMean from '../jsutils/didYouMean'; +import isObjectLike from '../jsutils/isObjectLike'; +import safeArrayFrom from '../jsutils/safeArrayFrom'; +import suggestionList from '../jsutils/suggestionList'; +import printPathArray from '../jsutils/printPathArray'; +import { addPath, pathToArray } from '../jsutils/Path'; + +import { GraphQLError } from '../error/GraphQLError'; + +import type { GraphQLInputType } from '../type/definition'; +import { + isLeafType, + isInputObjectType, + isListType, + isNonNullType, +} from '../type/definition'; + +type OnErrorCB = ( + path: $ReadOnlyArray<string | number>, + invalidValue: mixed, + error: GraphQLError, +) => void; + +/** + * Coerces a JavaScript value given a GraphQL Input Type. + */ +export function coerceInputValue( + inputValue: mixed, + type: GraphQLInputType, + onError: OnErrorCB = defaultOnError, +): mixed { + return coerceInputValueImpl(inputValue, type, onError); +} + +function defaultOnError( + path: $ReadOnlyArray<string | number>, + invalidValue: mixed, + error: GraphQLError, +): void { + let errorPrefix = 'Invalid value ' + inspect(invalidValue); + if (path.length > 0) { + errorPrefix += ` at "value${printPathArray(path)}"`; + } + error.message = errorPrefix + ': ' + error.message; + throw error; +} + +function coerceInputValueImpl( + inputValue: mixed, + type: GraphQLInputType, + onError: OnErrorCB, + path: Path | void, +): mixed { + if (isNonNullType(type)) { + if (inputValue != null) { + return coerceInputValueImpl(inputValue, type.ofType, onError, path); + } + onError( + pathToArray(path), + inputValue, + new GraphQLError( + `Expected non-nullable type "${inspect(type)}" not to be null.`, + ), + ); + return; + } + + if (inputValue == null) { + // Explicitly return the value null. + return null; + } + + if (isListType(type)) { + const itemType = type.ofType; + + const coercedList = safeArrayFrom(inputValue, (itemValue, index) => { + const itemPath = addPath(path, index, undefined); + return coerceInputValueImpl(itemValue, itemType, onError, itemPath); + }); + + if (coercedList != null) { + return coercedList; + } + + // Lists accept a non-list value as a list of one. + return [coerceInputValueImpl(inputValue, itemType, onError, path)]; + } + + if (isInputObjectType(type)) { + if (!isObjectLike(inputValue)) { + onError( + pathToArray(path), + inputValue, + new GraphQLError(`Expected type "${type.name}" to be an object.`), + ); + return; + } + + const coercedValue = {}; + const fieldDefs = type.getFields(); + + for (const field of objectValues(fieldDefs)) { + const fieldValue = inputValue[field.name]; + + if (fieldValue === undefined) { + if (field.defaultValue !== undefined) { + coercedValue[field.name] = field.defaultValue; + } else if (isNonNullType(field.type)) { + const typeStr = inspect(field.type); + onError( + pathToArray(path), + inputValue, + new GraphQLError( + `Field "${field.name}" of required type "${typeStr}" was not provided.`, + ), + ); + } + continue; + } + + coercedValue[field.name] = coerceInputValueImpl( + fieldValue, + field.type, + onError, + addPath(path, field.name, type.name), + ); + } + + // Ensure every provided field is defined. + for (const fieldName of Object.keys(inputValue)) { + if (!fieldDefs[fieldName]) { + const suggestions = suggestionList( + fieldName, + Object.keys(type.getFields()), + ); + onError( + pathToArray(path), + inputValue, + new GraphQLError( + `Field "${fieldName}" is not defined by type "${type.name}".` + + didYouMean(suggestions), + ), + ); + } + } + return coercedValue; + } + + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') + if (isLeafType(type)) { + let parseResult; + + // Scalars and Enums determine if a input value is valid via parseValue(), + // which can throw to indicate failure. If it throws, maintain a reference + // to the original error. + try { + parseResult = type.parseValue(inputValue); + } catch (error) { + if (error instanceof GraphQLError) { + onError(pathToArray(path), inputValue, error); + } else { + onError( + pathToArray(path), + inputValue, + new GraphQLError( + `Expected type "${type.name}". ` + error.message, + undefined, + undefined, + undefined, + undefined, + error, + ), + ); + } + return; + } + if (parseResult === undefined) { + onError( + pathToArray(path), + inputValue, + new GraphQLError(`Expected type "${type.name}".`), + ); + } + return parseResult; + } + + // istanbul ignore next (Not reachable. All possible input types have been considered) + invariant(false, 'Unexpected input type: ' + inspect((type: empty))); +} |