/** * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict */ import objectEntries from '../polyfills/objectEntries'; import defineToJSON from '../jsutils/defineToJSON'; import defineToStringTag from '../jsutils/defineToStringTag'; import instanceOf from '../jsutils/instanceOf'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import keyMap from '../jsutils/keyMap'; import mapValue from '../jsutils/mapValue'; import type { ObjMap } from '../jsutils/ObjMap'; import { Kind } from '../language/kinds'; import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped'; import type { ScalarTypeDefinitionNode, ObjectTypeDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, UnionTypeDefinitionNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, InputObjectTypeDefinitionNode, ScalarTypeExtensionNode, ObjectTypeExtensionNode, InterfaceTypeExtensionNode, UnionTypeExtensionNode, EnumTypeExtensionNode, InputObjectTypeExtensionNode, OperationDefinitionNode, FieldNode, FragmentDefinitionNode, ValueNode, } from '../language/ast'; import type { GraphQLSchema } from './schema'; import type { MaybePromise } from '../jsutils/MaybePromise'; // Predicates & Assertions /** * These are all of the possible kinds of types. */ export type GraphQLType = | GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList | GraphQLNonNull; export function isType(type: mixed): boolean %checks { return ( isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type) || isListType(type) || isNonNullType(type) ); } export function assertType(type: mixed): GraphQLType { invariant(isType(type), `Expected ${inspect(type)} to be a GraphQL type.`); return type; } /** * There are predicates for each kind of GraphQL type. */ declare function isScalarType(type: mixed): boolean %checks(type instanceof GraphQLScalarType); // eslint-disable-next-line no-redeclare export function isScalarType(type) { return instanceOf(type, GraphQLScalarType); } export function assertScalarType(type: mixed): GraphQLScalarType { invariant( isScalarType(type), `Expected ${inspect(type)} to be a GraphQL Scalar type.`, ); return type; } declare function isObjectType(type: mixed): boolean %checks(type instanceof GraphQLObjectType); // eslint-disable-next-line no-redeclare export function isObjectType(type) { return instanceOf(type, GraphQLObjectType); } export function assertObjectType(type: mixed): GraphQLObjectType { invariant( isObjectType(type), `Expected ${inspect(type)} to be a GraphQL Object type.`, ); return type; } declare function isInterfaceType(type: mixed): boolean %checks(type instanceof GraphQLInterfaceType); // eslint-disable-next-line no-redeclare export function isInterfaceType(type) { return instanceOf(type, GraphQLInterfaceType); } export function assertInterfaceType(type: mixed): GraphQLInterfaceType { invariant( isInterfaceType(type), `Expected ${inspect(type)} to be a GraphQL Interface type.`, ); return type; } declare function isUnionType(type: mixed): boolean %checks(type instanceof GraphQLUnionType); // eslint-disable-next-line no-redeclare export function isUnionType(type) { return instanceOf(type, GraphQLUnionType); } export function assertUnionType(type: mixed): GraphQLUnionType { invariant( isUnionType(type), `Expected ${inspect(type)} to be a GraphQL Union type.`, ); return type; } declare function isEnumType(type: mixed): boolean %checks(type instanceof GraphQLEnumType); // eslint-disable-next-line no-redeclare export function isEnumType(type) { return instanceOf(type, GraphQLEnumType); } export function assertEnumType(type: mixed): GraphQLEnumType { invariant( isEnumType(type), `Expected ${inspect(type)} to be a GraphQL Enum type.`, ); return type; } declare function isInputObjectType(type: mixed): boolean %checks(type instanceof GraphQLInputObjectType); // eslint-disable-next-line no-redeclare export function isInputObjectType(type) { return instanceOf(type, GraphQLInputObjectType); } export function assertInputObjectType(type: mixed): GraphQLInputObjectType { invariant( isInputObjectType(type), `Expected ${inspect(type)} to be a GraphQL Input Object type.`, ); return type; } declare function isListType(type: mixed): boolean %checks(type instanceof GraphQLList); // eslint-disable-next-line no-redeclare export function isListType(type) { return instanceOf(type, GraphQLList); } export function assertListType(type: mixed): GraphQLList { invariant( isListType(type), `Expected ${inspect(type)} to be a GraphQL List type.`, ); return type; } declare function isNonNullType(type: mixed): boolean %checks(type instanceof GraphQLNonNull); // eslint-disable-next-line no-redeclare export function isNonNullType(type) { return instanceOf(type, GraphQLNonNull); } export function assertNonNullType(type: mixed): GraphQLNonNull { invariant( isNonNullType(type), `Expected ${inspect(type)} to be a GraphQL Non-Null type.`, ); return type; } /** * These types may be used as input types for arguments and directives. */ export type GraphQLInputType = | GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList | GraphQLNonNull< | GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList, >; export function isInputType(type: mixed): boolean %checks { return ( isScalarType(type) || isEnumType(type) || isInputObjectType(type) || (isWrappingType(type) && isInputType(type.ofType)) ); } export function assertInputType(type: mixed): GraphQLInputType { invariant( isInputType(type), `Expected ${inspect(type)} to be a GraphQL input type.`, ); return type; } /** * These types may be used as output types as the result of fields. */ export type GraphQLOutputType = | GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLList | GraphQLNonNull< | GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLList, >; export function isOutputType(type: mixed): boolean %checks { return ( isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || (isWrappingType(type) && isOutputType(type.ofType)) ); } export function assertOutputType(type: mixed): GraphQLOutputType { invariant( isOutputType(type), `Expected ${inspect(type)} to be a GraphQL output type.`, ); return type; } /** * These types may describe types which may be leaf values. */ export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; export function isLeafType(type: mixed): boolean %checks { return isScalarType(type) || isEnumType(type); } export function assertLeafType(type: mixed): GraphQLLeafType { invariant( isLeafType(type), `Expected ${inspect(type)} to be a GraphQL leaf type.`, ); return type; } /** * These types may describe the parent context of a selection set. */ export type GraphQLCompositeType = | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType; export function isCompositeType(type: mixed): boolean %checks { return isObjectType(type) || isInterfaceType(type) || isUnionType(type); } export function assertCompositeType(type: mixed): GraphQLCompositeType { invariant( isCompositeType(type), `Expected ${inspect(type)} to be a GraphQL composite type.`, ); return type; } /** * These types may describe the parent context of a selection set. */ export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; export function isAbstractType(type: mixed): boolean %checks { return isInterfaceType(type) || isUnionType(type); } export function assertAbstractType(type: mixed): GraphQLAbstractType { invariant( isAbstractType(type), `Expected ${inspect(type)} to be a GraphQL abstract type.`, ); return type; } /** * List Type Wrapper * * A list is a wrapping type which points to another type. * Lists are often created within the context of defining the fields of * an object type. * * Example: * * const PersonType = new GraphQLObjectType({ * name: 'Person', * fields: () => ({ * parents: { type: GraphQLList(PersonType) }, * children: { type: GraphQLList(PersonType) }, * }) * }) * */ declare class GraphQLList<+T: GraphQLType> { +ofType: T; static (ofType: T): GraphQLList; // Note: constructors cannot be used for covariant types. Drop the "new". constructor(ofType: GraphQLType): void; } // eslint-disable-next-line no-redeclare export function GraphQLList(ofType) { if (this instanceof GraphQLList) { this.ofType = assertType(ofType); } else { return new GraphQLList(ofType); } } // Need to cast through any to alter the prototype. (GraphQLList.prototype: any).toString = function toString() { return '[' + String(this.ofType) + ']'; }; defineToJSON(GraphQLList); /** * Non-Null Type Wrapper * * A non-null is a wrapping type which points to another type. * Non-null types enforce that their values are never null and can ensure * an error is raised if this ever occurs during a request. It is useful for * fields which you can make a strong guarantee on non-nullability, for example * usually the id field of a database row will never be null. * * Example: * * const RowType = new GraphQLObjectType({ * name: 'Row', * fields: () => ({ * id: { type: GraphQLNonNull(GraphQLString) }, * }) * }) * * Note: the enforcement of non-nullability occurs within the executor. */ declare class GraphQLNonNull<+T: GraphQLNullableType> { +ofType: T; static (ofType: T): GraphQLNonNull; // Note: constructors cannot be used for covariant types. Drop the "new". constructor(ofType: GraphQLType): void; } // eslint-disable-next-line no-redeclare export function GraphQLNonNull(ofType) { if (this instanceof GraphQLNonNull) { this.ofType = assertNullableType(ofType); } else { return new GraphQLNonNull(ofType); } } // Need to cast through any to alter the prototype. (GraphQLNonNull.prototype: any).toString = function toString() { return String(this.ofType) + '!'; }; defineToJSON(GraphQLNonNull); /** * These types wrap and modify other types */ export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; export function isWrappingType(type: mixed): boolean %checks { return isListType(type) || isNonNullType(type); } export function assertWrappingType(type: mixed): GraphQLWrappingType { invariant( isWrappingType(type), `Expected ${inspect(type)} to be a GraphQL wrapping type.`, ); return type; } /** * These types can all accept null as a value. */ export type GraphQLNullableType = | GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList; export function isNullableType(type: mixed): boolean %checks { return isType(type) && !isNonNullType(type); } export function assertNullableType(type: mixed): GraphQLNullableType { invariant( isNullableType(type), `Expected ${inspect(type)} to be a GraphQL nullable type.`, ); return type; } /* eslint-disable no-redeclare */ declare function getNullableType(type: void | null): void; declare function getNullableType(type: T): T; declare function getNullableType(type: GraphQLNonNull): T; export function getNullableType(type) { /* eslint-enable no-redeclare */ if (type) { return isNonNullType(type) ? type.ofType : type; } } /** * These named types do not include modifiers like List or NonNull. */ export type GraphQLNamedType = | GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType; export function isNamedType(type: mixed): boolean %checks { return ( isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type) ); } export function assertNamedType(type: mixed): GraphQLNamedType { invariant( isNamedType(type), `Expected ${inspect(type)} to be a GraphQL named type.`, ); return type; } /* eslint-disable no-redeclare */ declare function getNamedType(type: void | null): void; declare function getNamedType(type: GraphQLType): GraphQLNamedType; export function getNamedType(type) { /* eslint-enable no-redeclare */ if (type) { let unwrappedType = type; while (isWrappingType(unwrappedType)) { unwrappedType = unwrappedType.ofType; } return unwrappedType; } } /** * Used while defining GraphQL types to allow for circular references in * otherwise immutable type definitions. */ export type Thunk<+T> = (() => T) | T; function resolveThunk<+T>(thunk: Thunk): T { // $FlowFixMe(>=0.90.0) return typeof thunk === 'function' ? thunk() : thunk; } /** * Scalar Type Definition * * The leaf values of any request and input values to arguments are * Scalars (or Enums) and are defined with a name and a series of functions * used to parse input from ast or variables and to ensure validity. * * If a type's serialize function does not return a value (i.e. it returns * `undefined`) then an error will be raised and a `null` value will be returned * in the response. If the serialize function returns `null`, then no error will * be included in the response. * * Example: * * const OddType = new GraphQLScalarType({ * name: 'Odd', * serialize(value) { * if (value % 2 === 1) { * return value; * } * } * }); * */ export class GraphQLScalarType { name: string; description: ?string; serialize: GraphQLScalarSerializer<*>; parseValue: GraphQLScalarValueParser<*>; parseLiteral: GraphQLScalarLiteralParser<*>; astNode: ?ScalarTypeDefinitionNode; extensionASTNodes: ?$ReadOnlyArray; constructor(config: GraphQLScalarTypeConfig<*, *>): void { this.name = config.name; this.description = config.description; this.serialize = config.serialize; this.parseValue = config.parseValue || (value => value); this.parseLiteral = config.parseLiteral || valueFromASTUntyped; this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes; invariant(typeof config.name === 'string', 'Must provide name.'); invariant( typeof config.serialize === 'function', `${this.name} must provide "serialize" function. If this custom Scalar ` + 'is also used as an input type, ensure "parseValue" and "parseLiteral" ' + 'functions are also provided.', ); if (config.parseValue || config.parseLiteral) { invariant( typeof config.parseValue === 'function' && typeof config.parseLiteral === 'function', `${this.name} must provide both "parseValue" and "parseLiteral" ` + 'functions.', ); } } toString(): string { return this.name; } } // Conditionally apply `[Symbol.toStringTag]` if `Symbol`s are supported defineToStringTag(GraphQLScalarType); defineToJSON(GraphQLScalarType); export type GraphQLScalarSerializer = (value: mixed) => ?TExternal; export type GraphQLScalarValueParser = (value: mixed) => ?TInternal; export type GraphQLScalarLiteralParser = ( valueNode: ValueNode, variables: ?ObjMap, ) => ?TInternal; export type GraphQLScalarTypeConfig = {| name: string, description?: ?string, // Serializes an internal value to include in a response. serialize: GraphQLScalarSerializer, // Parses an externally provided value to use as an input. parseValue?: GraphQLScalarValueParser, // Parses an externally provided literal value to use as an input. parseLiteral?: GraphQLScalarLiteralParser, astNode?: ?ScalarTypeDefinitionNode, extensionASTNodes?: ?$ReadOnlyArray, |}; /** * Object Type Definition * * Almost all of the GraphQL types you define will be object types. Object types * have a name, but most importantly describe their fields. * * Example: * * const AddressType = new GraphQLObjectType({ * name: 'Address', * fields: { * street: { type: GraphQLString }, * number: { type: GraphQLInt }, * formatted: { * type: GraphQLString, * resolve(obj) { * return obj.number + ' ' + obj.street * } * } * } * }); * * When two types need to refer to each other, or a type needs to refer to * itself in a field, you can use a function expression (aka a closure or a * thunk) to supply the fields lazily. * * Example: * * const PersonType = new GraphQLObjectType({ * name: 'Person', * fields: () => ({ * name: { type: GraphQLString }, * bestFriend: { type: PersonType }, * }) * }); * */ export class GraphQLObjectType { name: string; description: ?string; astNode: ?ObjectTypeDefinitionNode; extensionASTNodes: ?$ReadOnlyArray; isTypeOf: ?GraphQLIsTypeOfFn<*, *>; _fields: Thunk>; _interfaces: Thunk>; constructor(config: GraphQLObjectTypeConfig<*, *>): void { this.name = config.name; this.description = config.description; this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes; this.isTypeOf = config.isTypeOf; this._fields = defineFieldMap.bind(undefined, config); this._interfaces = defineInterfaces.bind(undefined, config); invariant(typeof config.name === 'string', 'Must provide name.'); invariant( config.isTypeOf == null || typeof config.isTypeOf === 'function', `${this.name} must provide "isTypeOf" as a function, ` + `but got: ${inspect(config.isTypeOf)}.`, ); } getFields(): GraphQLFieldMap<*, *> { if (typeof this._fields === 'function') { this._fields = this._fields(); } return this._fields; } getInterfaces(): Array { if (typeof this._interfaces === 'function') { this._interfaces = this._interfaces(); } return this._interfaces; } toString(): string { return this.name; } } // Conditionally apply `[Symbol.toStringTag]` if `Symbol`s are supported defineToStringTag(GraphQLObjectType); defineToJSON(GraphQLObjectType); function defineInterfaces( config: GraphQLObjectTypeConfig<*, *>, ): Array { const interfaces = resolveThunk(config.interfaces) || []; invariant( Array.isArray(interfaces), `${config.name} interfaces must be an Array or a function which returns ` + 'an Array.', ); return interfaces; } function defineFieldMap( config: | GraphQLObjectTypeConfig | GraphQLInterfaceTypeConfig, ): GraphQLFieldMap { const fieldMap = resolveThunk(config.fields) || {}; invariant( isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a ` + 'function which returns such an object.', ); return mapValue(fieldMap, (fieldConfig, fieldName) => { invariant( isPlainObj(fieldConfig), `${config.name}.${fieldName} field config must be an object`, ); invariant( !fieldConfig.hasOwnProperty('isDeprecated'), `${config.name}.${fieldName} should provide "deprecationReason" ` + 'instead of "isDeprecated".', ); invariant( fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', `${config.name}.${fieldName} field resolver must be a function if ` + `provided, but got: ${inspect(fieldConfig.resolve)}.`, ); const argsConfig = fieldConfig.args || {}; invariant( isPlainObj(argsConfig), `${config.name}.${fieldName} args must be an object with argument ` + 'names as keys.', ); const args = objectEntries(argsConfig).map(([argName, arg]) => ({ name: argName, description: arg.description === undefined ? null : arg.description, type: arg.type, defaultValue: arg.defaultValue, astNode: arg.astNode, })); return { ...fieldConfig, isDeprecated: Boolean(fieldConfig.deprecationReason), name: fieldName, args, }; }); } function isPlainObj(obj) { return obj && typeof obj === 'object' && !Array.isArray(obj); } export type GraphQLObjectTypeConfig = {| name: string, interfaces?: Thunk>, fields: Thunk>, isTypeOf?: ?GraphQLIsTypeOfFn, description?: ?string, astNode?: ?ObjectTypeDefinitionNode, extensionASTNodes?: ?$ReadOnlyArray, |}; export type GraphQLTypeResolver = ( value: TSource, context: TContext, info: GraphQLResolveInfo, ) => MaybePromise; export type GraphQLIsTypeOfFn = ( source: TSource, context: TContext, info: GraphQLResolveInfo, ) => MaybePromise; export type GraphQLFieldResolver< TSource, TContext, TArgs = { [argument: string]: any }, > = ( source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo, ) => mixed; export type GraphQLResolveInfo = {| +fieldName: string, +fieldNodes: $ReadOnlyArray, +returnType: GraphQLOutputType, +parentType: GraphQLObjectType, +path: ResponsePath, +schema: GraphQLSchema, +fragments: ObjMap, +rootValue: mixed, +operation: OperationDefinitionNode, +variableValues: { [variable: string]: mixed }, |}; export type ResponsePath = {| +prev: ResponsePath | void, +key: string | number, |}; export type GraphQLFieldConfig< TSource, TContext, TArgs = { [argument: string]: any }, > = {| type: GraphQLOutputType, args?: GraphQLFieldConfigArgumentMap, resolve?: GraphQLFieldResolver, subscribe?: GraphQLFieldResolver, deprecationReason?: ?string, description?: ?string, astNode?: ?FieldDefinitionNode, |}; export type GraphQLFieldConfigArgumentMap = ObjMap; export type GraphQLArgumentConfig = {| type: GraphQLInputType, defaultValue?: mixed, description?: ?string, astNode?: ?InputValueDefinitionNode, |}; export type GraphQLFieldConfigMap = ObjMap< GraphQLFieldConfig, >; export type GraphQLField< TSource, TContext, TArgs = { [argument: string]: any }, > = { name: string, description: ?string, type: GraphQLOutputType, args: Array, resolve?: GraphQLFieldResolver, subscribe?: GraphQLFieldResolver, isDeprecated?: boolean, deprecationReason?: ?string, astNode?: ?FieldDefinitionNode, }; export type GraphQLArgument = { name: string, type: GraphQLInputType, defaultValue?: mixed, description?: ?string, astNode?: ?InputValueDefinitionNode, }; export function isRequiredArgument(arg: GraphQLArgument): boolean %checks { return isNonNullType(arg.type) && arg.defaultValue === undefined; } export type GraphQLFieldMap = ObjMap< GraphQLField, >; /** * Interface Type Definition * * When a field can return one of a heterogeneous set of types, a Interface type * is used to describe what types are possible, what fields are in common across * all types, as well as a function to determine which type is actually used * when the field is resolved. * * Example: * * const EntityType = new GraphQLInterfaceType({ * name: 'Entity', * fields: { * name: { type: GraphQLString } * } * }); * */ export class GraphQLInterfaceType { name: string; description: ?string; astNode: ?InterfaceTypeDefinitionNode; extensionASTNodes: ?$ReadOnlyArray; resolveType: ?GraphQLTypeResolver<*, *>; _fields: Thunk>; constructor(config: GraphQLInterfaceTypeConfig<*, *>): void { this.name = config.name; this.description = config.description; this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes; this.resolveType = config.resolveType; this._fields = defineFieldMap.bind(undefined, config); invariant(typeof config.name === 'string', 'Must provide name.'); invariant( config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`, ); } getFields(): GraphQLFieldMap<*, *> { if (typeof this._fields === 'function') { this._fields = this._fields(); } return this._fields; } toString(): string { return this.name; } } // Conditionally apply `[Symbol.toStringTag]` if `Symbol`s are supported defineToStringTag(GraphQLInterfaceType); defineToJSON(GraphQLInterfaceType); export type GraphQLInterfaceTypeConfig = {| name: string, fields: Thunk>, /** * Optionally provide a custom type resolver function. If one is not provided, * the default implementation will call `isTypeOf` on each implementing * Object type. */ resolveType?: ?GraphQLTypeResolver, description?: ?string, astNode?: ?InterfaceTypeDefinitionNode, extensionASTNodes?: ?$ReadOnlyArray, |}; /** * Union Type Definition * * When a field can return one of a heterogeneous set of types, a Union type * is used to describe what types are possible as well as providing a function * to determine which type is actually used when the field is resolved. * * Example: * * const PetType = new GraphQLUnionType({ * name: 'Pet', * types: [ DogType, CatType ], * resolveType(value) { * if (value instanceof Dog) { * return DogType; * } * if (value instanceof Cat) { * return CatType; * } * } * }); * */ export class GraphQLUnionType { name: string; description: ?string; astNode: ?UnionTypeDefinitionNode; extensionASTNodes: ?$ReadOnlyArray; resolveType: ?GraphQLTypeResolver<*, *>; _types: Thunk>; constructor(config: GraphQLUnionTypeConfig<*, *>): void { this.name = config.name; this.description = config.description; this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes; this.resolveType = config.resolveType; this._types = defineTypes.bind(undefined, config); invariant(typeof config.name === 'string', 'Must provide name.'); invariant( config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`, ); } getTypes(): Array { if (typeof this._types === 'function') { this._types = this._types(); } return this._types; } toString(): string { return this.name; } } // Conditionally apply `[Symbol.toStringTag]` if `Symbol`s are supported defineToStringTag(GraphQLUnionType); defineToJSON(GraphQLUnionType); function defineTypes( config: GraphQLUnionTypeConfig<*, *>, ): Array { const types = resolveThunk(config.types) || []; invariant( Array.isArray(types), 'Must provide Array of types or a function which returns ' + `such an array for Union ${config.name}.`, ); return types; } export type GraphQLUnionTypeConfig = {| name: string, types: Thunk>, /** * Optionally provide a custom type resolver function. If one is not provided, * the default implementation will call `isTypeOf` on each implementing * Object type. */ resolveType?: ?GraphQLTypeResolver, description?: ?string, astNode?: ?UnionTypeDefinitionNode, extensionASTNodes?: ?$ReadOnlyArray, |}; /** * Enum Type Definition * * Some leaf values of requests and input values are Enums. GraphQL serializes * Enum values as strings, however internally Enums can be represented by any * kind of type, often integers. * * Example: * * const RGBType = new GraphQLEnumType({ * name: 'RGB', * values: { * RED: { value: 0 }, * GREEN: { value: 1 }, * BLUE: { value: 2 } * } * }); * * Note: If a value is not provided in a definition, the name of the enum value * will be used as its internal value. */ export class GraphQLEnumType /* */ { name: string; description: ?string; astNode: ?EnumTypeDefinitionNode; extensionASTNodes: ?$ReadOnlyArray; _values: Array */>; _valueLookup: Map; _nameLookup: ObjMap; constructor(config: GraphQLEnumTypeConfig /* */): void { this.name = config.name; this.description = config.description; this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes; this._values = defineEnumValues(this, config.values); this._valueLookup = new Map( this._values.map(enumValue => [enumValue.value, enumValue]), ); this._nameLookup = keyMap(this._values, value => value.name); invariant(typeof config.name === 'string', 'Must provide name.'); } getValues(): Array */> { return this._values; } getValue(name: string): ?GraphQLEnumValue { return this._nameLookup[name]; } serialize(value: mixed /* T */): ?string { const enumValue = this._valueLookup.get(value); if (enumValue) { return enumValue.name; } } parseValue(value: mixed): ?any /* T */ { if (typeof value === 'string') { const enumValue = this.getValue(value); if (enumValue) { return enumValue.value; } } } parseLiteral(valueNode: ValueNode, _variables: ?ObjMap): ?any /* T */ { // Note: variables will be resolved to a value before calling this function. if (valueNode.kind === Kind.ENUM) { const enumValue = this.getValue(valueNode.value); if (enumValue) { return enumValue.value; } } } toString(): string { return this.name; } } // Conditionally apply `[Symbol.toStringTag]` if `Symbol`s are supported defineToStringTag(GraphQLEnumType); defineToJSON(GraphQLEnumType); function defineEnumValues( type: GraphQLEnumType, valueMap: GraphQLEnumValueConfigMap /* */, ): Array */> { invariant( isPlainObj(valueMap), `${type.name} values must be an object with value names as keys.`, ); return objectEntries(valueMap).map(([valueName, value]) => { invariant( isPlainObj(value), `${type.name}.${valueName} must refer to an object with a "value" key ` + `representing an internal value but got: ${inspect(value)}.`, ); invariant( !value.hasOwnProperty('isDeprecated'), `${type.name}.${valueName} should provide "deprecationReason" instead ` + 'of "isDeprecated".', ); return { name: valueName, description: value.description, isDeprecated: Boolean(value.deprecationReason), deprecationReason: value.deprecationReason, astNode: value.astNode, value: value.hasOwnProperty('value') ? value.value : valueName, }; }); } export type GraphQLEnumTypeConfig /* */ = {| name: string, values: GraphQLEnumValueConfigMap /* */, description?: ?string, astNode?: ?EnumTypeDefinitionNode, extensionASTNodes?: ?$ReadOnlyArray, |}; export type GraphQLEnumValueConfigMap /* */ = ObjMap */>; export type GraphQLEnumValueConfig /* */ = {| value?: any /* T */, deprecationReason?: ?string, description?: ?string, astNode?: ?EnumValueDefinitionNode, |}; export type GraphQLEnumValue /* */ = { name: string, description: ?string, isDeprecated?: boolean, deprecationReason: ?string, astNode?: ?EnumValueDefinitionNode, value: any /* T */, }; /** * Input Object Type Definition * * An input object defines a structured collection of fields which may be * supplied to a field argument. * * Using `NonNull` will ensure that a value must be provided by the query * * Example: * * const GeoPoint = new GraphQLInputObjectType({ * name: 'GeoPoint', * fields: { * lat: { type: GraphQLNonNull(GraphQLFloat) }, * lon: { type: GraphQLNonNull(GraphQLFloat) }, * alt: { type: GraphQLFloat, defaultValue: 0 }, * } * }); * */ export class GraphQLInputObjectType { name: string; description: ?string; astNode: ?InputObjectTypeDefinitionNode; extensionASTNodes: ?$ReadOnlyArray; _fields: Thunk; constructor(config: GraphQLInputObjectTypeConfig): void { this.name = config.name; this.description = config.description; this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes; this._fields = defineInputFieldMap.bind(undefined, config); invariant(typeof config.name === 'string', 'Must provide name.'); } getFields(): GraphQLInputFieldMap { if (typeof this._fields === 'function') { this._fields = this._fields(); } return this._fields; } toString(): string { return this.name; } } // Conditionally apply `[Symbol.toStringTag]` if `Symbol`s are supported defineToStringTag(GraphQLInputObjectType); defineToJSON(GraphQLInputObjectType); function defineInputFieldMap( config: GraphQLInputObjectTypeConfig, ): GraphQLInputFieldMap { const fieldMap = resolveThunk(config.fields) || {}; invariant( isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a ` + 'function which returns such an object.', ); return mapValue(fieldMap, (fieldConfig, fieldName) => { invariant( !fieldConfig.hasOwnProperty('resolve'), `${config.name}.${fieldName} field has a resolve property, but ` + 'Input Types cannot define resolvers.', ); return { ...fieldConfig, name: fieldName }; }); } export type GraphQLInputObjectTypeConfig = {| name: string, fields: Thunk, description?: ?string, astNode?: ?InputObjectTypeDefinitionNode, extensionASTNodes?: ?$ReadOnlyArray, |}; export type GraphQLInputFieldConfig = {| type: GraphQLInputType, defaultValue?: mixed, description?: ?string, astNode?: ?InputValueDefinitionNode, |}; export type GraphQLInputFieldConfigMap = ObjMap; export type GraphQLInputField = { name: string, type: GraphQLInputType, defaultValue?: mixed, description?: ?string, astNode?: ?InputValueDefinitionNode, }; export function isRequiredInputField( field: GraphQLInputField, ): boolean %checks { return isNonNullType(field.type) && field.defaultValue === undefined; } export type GraphQLInputFieldMap = ObjMap;