diff options
Diffstat (limited to 'alarm/node_modules/graphql/utilities/valueFromAST.js.flow')
-rw-r--r-- | alarm/node_modules/graphql/utilities/valueFromAST.js.flow | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/alarm/node_modules/graphql/utilities/valueFromAST.js.flow b/alarm/node_modules/graphql/utilities/valueFromAST.js.flow new file mode 100644 index 0000000..23d5588 --- /dev/null +++ b/alarm/node_modules/graphql/utilities/valueFromAST.js.flow @@ -0,0 +1,164 @@ +// @flow strict +import objectValues from '../polyfills/objectValues'; + +import type { ObjMap } from '../jsutils/ObjMap'; +import keyMap from '../jsutils/keyMap'; +import inspect from '../jsutils/inspect'; +import invariant from '../jsutils/invariant'; + +import type { ValueNode } from '../language/ast'; +import { Kind } from '../language/kinds'; + +import type { GraphQLInputType } from '../type/definition'; +import { + isLeafType, + isInputObjectType, + isListType, + isNonNullType, +} from '../type/definition'; + +/** + * Produces a JavaScript value given a GraphQL Value AST. + * + * A GraphQL type must be provided, which will be used to interpret different + * GraphQL Value literals. + * + * Returns `undefined` when the value could not be validly coerced according to + * the provided type. + * + * | GraphQL Value | JSON Value | + * | -------------------- | ------------- | + * | Input Object | Object | + * | List | Array | + * | Boolean | Boolean | + * | String | String | + * | Int / Float | Number | + * | Enum Value | Mixed | + * | NullValue | null | + * + */ +export function valueFromAST( + valueNode: ?ValueNode, + type: GraphQLInputType, + variables?: ?ObjMap<mixed>, +): mixed | void { + if (!valueNode) { + // When there is no node, then there is also no value. + // Importantly, this is different from returning the value null. + return; + } + + if (valueNode.kind === Kind.VARIABLE) { + const variableName = valueNode.name.value; + if (variables == null || variables[variableName] === undefined) { + // No valid return value. + return; + } + const variableValue = variables[variableName]; + if (variableValue === null && isNonNullType(type)) { + return; // Invalid: intentionally return no value. + } + // Note: This does no further checking that this variable is correct. + // This assumes that this query has been validated and the variable + // usage here is of the correct type. + return variableValue; + } + + if (isNonNullType(type)) { + if (valueNode.kind === Kind.NULL) { + return; // Invalid: intentionally return no value. + } + return valueFromAST(valueNode, type.ofType, variables); + } + + if (valueNode.kind === Kind.NULL) { + // This is explicitly returning the value null. + return null; + } + + if (isListType(type)) { + const itemType = type.ofType; + if (valueNode.kind === Kind.LIST) { + const coercedValues = []; + for (const itemNode of valueNode.values) { + if (isMissingVariable(itemNode, variables)) { + // If an array contains a missing variable, it is either coerced to + // null or if the item type is non-null, it considered invalid. + if (isNonNullType(itemType)) { + return; // Invalid: intentionally return no value. + } + coercedValues.push(null); + } else { + const itemValue = valueFromAST(itemNode, itemType, variables); + if (itemValue === undefined) { + return; // Invalid: intentionally return no value. + } + coercedValues.push(itemValue); + } + } + return coercedValues; + } + const coercedValue = valueFromAST(valueNode, itemType, variables); + if (coercedValue === undefined) { + return; // Invalid: intentionally return no value. + } + return [coercedValue]; + } + + if (isInputObjectType(type)) { + if (valueNode.kind !== Kind.OBJECT) { + return; // Invalid: intentionally return no value. + } + const coercedObj = Object.create(null); + const fieldNodes = keyMap(valueNode.fields, (field) => field.name.value); + for (const field of objectValues(type.getFields())) { + const fieldNode = fieldNodes[field.name]; + if (!fieldNode || isMissingVariable(fieldNode.value, variables)) { + if (field.defaultValue !== undefined) { + coercedObj[field.name] = field.defaultValue; + } else if (isNonNullType(field.type)) { + return; // Invalid: intentionally return no value. + } + continue; + } + const fieldValue = valueFromAST(fieldNode.value, field.type, variables); + if (fieldValue === undefined) { + return; // Invalid: intentionally return no value. + } + coercedObj[field.name] = fieldValue; + } + return coercedObj; + } + + // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618') + if (isLeafType(type)) { + // Scalars and Enums fulfill parsing a literal value via parseLiteral(). + // Invalid values represent a failure to parse correctly, in which case + // no value is returned. + let result; + try { + result = type.parseLiteral(valueNode, variables); + } catch (_error) { + return; // Invalid: intentionally return no value. + } + if (result === undefined) { + return; // Invalid: intentionally return no value. + } + return result; + } + + // istanbul ignore next (Not reachable. All possible input types have been considered) + invariant(false, 'Unexpected input type: ' + inspect((type: empty))); +} + +// Returns true if the provided valueNode is a variable which is not defined +// in the set of variables. +function isMissingVariable( + valueNode: ValueNode, + variables: ?ObjMap<mixed>, +): boolean { + return ( + valueNode.kind === Kind.VARIABLE && + (variables == null || variables[valueNode.name.value] === undefined) + ); +} |