| import { devAssert } from '../jsutils/devAssert.mjs'; |
| import { didYouMean } from '../jsutils/didYouMean.mjs'; |
| import { identityFunc } from '../jsutils/identityFunc.mjs'; |
| import { inspect } from '../jsutils/inspect.mjs'; |
| import { instanceOf } from '../jsutils/instanceOf.mjs'; |
| import { isObjectLike } from '../jsutils/isObjectLike.mjs'; |
| import { keyMap } from '../jsutils/keyMap.mjs'; |
| import { keyValMap } from '../jsutils/keyValMap.mjs'; |
| import { mapValue } from '../jsutils/mapValue.mjs'; |
| import { suggestionList } from '../jsutils/suggestionList.mjs'; |
| import { toObjMap } from '../jsutils/toObjMap.mjs'; |
| import { GraphQLError } from '../error/GraphQLError.mjs'; |
| import { Kind } from '../language/kinds.mjs'; |
| import { print } from '../language/printer.mjs'; |
| import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped.mjs'; |
| import { assertEnumValueName, assertName } from './assertName.mjs'; |
| export function isType(type) { |
| return ( |
| isScalarType(type) || |
| isObjectType(type) || |
| isInterfaceType(type) || |
| isUnionType(type) || |
| isEnumType(type) || |
| isInputObjectType(type) || |
| isListType(type) || |
| isNonNullType(type) |
| ); |
| } |
| export function assertType(type) { |
| if (!isType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`); |
| } |
|
|
| return type; |
| } |
| /** |
| * There are predicates for each kind of GraphQL type. |
| */ |
|
|
| export function isScalarType(type) { |
| return instanceOf(type, GraphQLScalarType); |
| } |
| export function assertScalarType(type) { |
| if (!isScalarType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); |
| } |
|
|
| return type; |
| } |
| export function isObjectType(type) { |
| return instanceOf(type, GraphQLObjectType); |
| } |
| export function assertObjectType(type) { |
| if (!isObjectType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); |
| } |
|
|
| return type; |
| } |
| export function isInterfaceType(type) { |
| return instanceOf(type, GraphQLInterfaceType); |
| } |
| export function assertInterfaceType(type) { |
| if (!isInterfaceType(type)) { |
| throw new Error( |
| `Expected ${inspect(type)} to be a GraphQL Interface type.`, |
| ); |
| } |
|
|
| return type; |
| } |
| export function isUnionType(type) { |
| return instanceOf(type, GraphQLUnionType); |
| } |
| export function assertUnionType(type) { |
| if (!isUnionType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); |
| } |
|
|
| return type; |
| } |
| export function isEnumType(type) { |
| return instanceOf(type, GraphQLEnumType); |
| } |
| export function assertEnumType(type) { |
| if (!isEnumType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); |
| } |
|
|
| return type; |
| } |
| export function isInputObjectType(type) { |
| return instanceOf(type, GraphQLInputObjectType); |
| } |
| export function assertInputObjectType(type) { |
| if (!isInputObjectType(type)) { |
| throw new Error( |
| `Expected ${inspect(type)} to be a GraphQL Input Object type.`, |
| ); |
| } |
|
|
| return type; |
| } |
| export function isListType(type) { |
| return instanceOf(type, GraphQLList); |
| } |
| export function assertListType(type) { |
| if (!isListType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); |
| } |
|
|
| return type; |
| } |
| export function isNonNullType(type) { |
| return instanceOf(type, GraphQLNonNull); |
| } |
| export function assertNonNullType(type) { |
| if (!isNonNullType(type)) { |
| throw new Error(`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 function isInputType(type) { |
| return ( |
| isScalarType(type) || |
| isEnumType(type) || |
| isInputObjectType(type) || |
| (isWrappingType(type) && isInputType(type.ofType)) |
| ); |
| } |
| export function assertInputType(type) { |
| if (!isInputType(type)) { |
| throw new Error(`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 function isOutputType(type) { |
| return ( |
| isScalarType(type) || |
| isObjectType(type) || |
| isInterfaceType(type) || |
| isUnionType(type) || |
| isEnumType(type) || |
| (isWrappingType(type) && isOutputType(type.ofType)) |
| ); |
| } |
| export function assertOutputType(type) { |
| if (!isOutputType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`); |
| } |
|
|
| return type; |
| } |
| /** |
| * These types may describe types which may be leaf values. |
| */ |
|
|
| export function isLeafType(type) { |
| return isScalarType(type) || isEnumType(type); |
| } |
| export function assertLeafType(type) { |
| if (!isLeafType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`); |
| } |
|
|
| return type; |
| } |
| /** |
| * These types may describe the parent context of a selection set. |
| */ |
|
|
| export function isCompositeType(type) { |
| return isObjectType(type) || isInterfaceType(type) || isUnionType(type); |
| } |
| export function assertCompositeType(type) { |
| if (!isCompositeType(type)) { |
| throw new Error( |
| `Expected ${inspect(type)} to be a GraphQL composite type.`, |
| ); |
| } |
|
|
| return type; |
| } |
| /** |
| * These types may describe the parent context of a selection set. |
| */ |
|
|
| export function isAbstractType(type) { |
| return isInterfaceType(type) || isUnionType(type); |
| } |
| export function assertAbstractType(type) { |
| if (!isAbstractType(type)) { |
| throw new Error(`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: |
| * |
| * ```ts |
| * const PersonType = new GraphQLObjectType({ |
| * name: 'Person', |
| * fields: () => ({ |
| * parents: { type: new GraphQLList(PersonType) }, |
| * children: { type: new GraphQLList(PersonType) }, |
| * }) |
| * }) |
| * ``` |
| */ |
|
|
| export class GraphQLList { |
| constructor(ofType) { |
| isType(ofType) || |
| devAssert(false, `Expected ${inspect(ofType)} to be a GraphQL type.`); |
| this.ofType = ofType; |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLList'; |
| } |
|
|
| toString() { |
| return '[' + String(this.ofType) + ']'; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
| /** |
| * 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: |
| * |
| * ```ts |
| * const RowType = new GraphQLObjectType({ |
| * name: 'Row', |
| * fields: () => ({ |
| * id: { type: new GraphQLNonNull(GraphQLString) }, |
| * }) |
| * }) |
| * ``` |
| * Note: the enforcement of non-nullability occurs within the executor. |
| */ |
|
|
| export class GraphQLNonNull { |
| constructor(ofType) { |
| isNullableType(ofType) || |
| devAssert( |
| false, |
| `Expected ${inspect(ofType)} to be a GraphQL nullable type.`, |
| ); |
| this.ofType = ofType; |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLNonNull'; |
| } |
|
|
| toString() { |
| return String(this.ofType) + '!'; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
| /** |
| * These types wrap and modify other types |
| */ |
|
|
| export function isWrappingType(type) { |
| return isListType(type) || isNonNullType(type); |
| } |
| export function assertWrappingType(type) { |
| if (!isWrappingType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`); |
| } |
|
|
| return type; |
| } |
| /** |
| * These types can all accept null as a value. |
| */ |
|
|
| export function isNullableType(type) { |
| return isType(type) && !isNonNullType(type); |
| } |
| export function assertNullableType(type) { |
| if (!isNullableType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`); |
| } |
|
|
| return type; |
| } |
| export function getNullableType(type) { |
| if (type) { |
| return isNonNullType(type) ? type.ofType : type; |
| } |
| } |
| /** |
| * These named types do not include modifiers like List or NonNull. |
| */ |
|
|
| export function isNamedType(type) { |
| return ( |
| isScalarType(type) || |
| isObjectType(type) || |
| isInterfaceType(type) || |
| isUnionType(type) || |
| isEnumType(type) || |
| isInputObjectType(type) |
| ); |
| } |
| export function assertNamedType(type) { |
| if (!isNamedType(type)) { |
| throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`); |
| } |
|
|
| return type; |
| } |
| export function getNamedType(type) { |
| 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 function resolveReadonlyArrayThunk(thunk) { |
| return typeof thunk === 'function' ? thunk() : thunk; |
| } |
| export function resolveObjMapThunk(thunk) { |
| return typeof thunk === 'function' ? thunk() : thunk; |
| } |
| /** |
| * Custom extensions |
| * |
| * @remarks |
| * Use a unique identifier name for your extension, for example the name of |
| * your library or project. Do not use a shortened identifier as this increases |
| * the risk of conflicts. We recommend you add at most one extension field, |
| * an object which can contain all the values you need. |
| */ |
|
|
| /** |
| * 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 returns `null` or 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. It is always better to validate |
| * |
| * Example: |
| * |
| * ```ts |
| * const OddType = new GraphQLScalarType({ |
| * name: 'Odd', |
| * serialize(value) { |
| * if (!Number.isFinite(value)) { |
| * throw new Error( |
| * `Scalar "Odd" cannot represent "${value}" since it is not a finite number.`, |
| * ); |
| * } |
| * |
| * if (value % 2 === 0) { |
| * throw new Error(`Scalar "Odd" cannot represent "${value}" since it is even.`); |
| * } |
| * return value; |
| * } |
| * }); |
| * ``` |
| */ |
| export class GraphQLScalarType { |
| constructor(config) { |
| var _config$parseValue, |
| _config$serialize, |
| _config$parseLiteral, |
| _config$extensionASTN; |
|
|
| const parseValue = |
| (_config$parseValue = config.parseValue) !== null && |
| _config$parseValue !== void 0 |
| ? _config$parseValue |
| : identityFunc; |
| this.name = assertName(config.name); |
| this.description = config.description; |
| this.specifiedByURL = config.specifiedByURL; |
| this.serialize = |
| (_config$serialize = config.serialize) !== null && |
| _config$serialize !== void 0 |
| ? _config$serialize |
| : identityFunc; |
| this.parseValue = parseValue; |
| this.parseLiteral = |
| (_config$parseLiteral = config.parseLiteral) !== null && |
| _config$parseLiteral !== void 0 |
| ? _config$parseLiteral |
| : (node, variables) => parseValue(valueFromASTUntyped(node, variables)); |
| this.extensions = toObjMap(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN = config.extensionASTNodes) !== null && |
| _config$extensionASTN !== void 0 |
| ? _config$extensionASTN |
| : []; |
| config.specifiedByURL == null || |
| typeof config.specifiedByURL === 'string' || |
| devAssert( |
| false, |
| `${this.name} must provide "specifiedByURL" as a string, ` + |
| `but got: ${inspect(config.specifiedByURL)}.`, |
| ); |
| config.serialize == null || |
| typeof config.serialize === 'function' || |
| devAssert( |
| false, |
| `${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.parseLiteral) { |
| (typeof config.parseValue === 'function' && |
| typeof config.parseLiteral === 'function') || |
| devAssert( |
| false, |
| `${this.name} must provide both "parseValue" and "parseLiteral" functions.`, |
| ); |
| } |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLScalarType'; |
| } |
|
|
| toConfig() { |
| return { |
| name: this.name, |
| description: this.description, |
| specifiedByURL: this.specifiedByURL, |
| serialize: this.serialize, |
| parseValue: this.parseValue, |
| parseLiteral: this.parseLiteral, |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| }; |
| } |
|
|
| toString() { |
| return this.name; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
|
|
| /** |
| * 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: |
| * |
| * ```ts |
| * 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: |
| * |
| * ```ts |
| * const PersonType = new GraphQLObjectType({ |
| * name: 'Person', |
| * fields: () => ({ |
| * name: { type: GraphQLString }, |
| * bestFriend: { type: PersonType }, |
| * }) |
| * }); |
| * ``` |
| */ |
| export class GraphQLObjectType { |
| constructor(config) { |
| var _config$extensionASTN2; |
|
|
| this.name = assertName(config.name); |
| this.description = config.description; |
| this.isTypeOf = config.isTypeOf; |
| this.extensions = toObjMap(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN2 = config.extensionASTNodes) !== null && |
| _config$extensionASTN2 !== void 0 |
| ? _config$extensionASTN2 |
| : []; |
|
|
| this._fields = () => defineFieldMap(config); |
|
|
| this._interfaces = () => defineInterfaces(config); |
|
|
| config.isTypeOf == null || |
| typeof config.isTypeOf === 'function' || |
| devAssert( |
| false, |
| `${this.name} must provide "isTypeOf" as a function, ` + |
| `but got: ${inspect(config.isTypeOf)}.`, |
| ); |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLObjectType'; |
| } |
|
|
| getFields() { |
| if (typeof this._fields === 'function') { |
| this._fields = this._fields(); |
| } |
|
|
| return this._fields; |
| } |
|
|
| getInterfaces() { |
| if (typeof this._interfaces === 'function') { |
| this._interfaces = this._interfaces(); |
| } |
|
|
| return this._interfaces; |
| } |
|
|
| toConfig() { |
| return { |
| name: this.name, |
| description: this.description, |
| interfaces: this.getInterfaces(), |
| fields: fieldsToFieldsConfig(this.getFields()), |
| isTypeOf: this.isTypeOf, |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| }; |
| } |
|
|
| toString() { |
| return this.name; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
|
|
| function defineInterfaces(config) { |
| var _config$interfaces; |
|
|
| const interfaces = resolveReadonlyArrayThunk( |
| (_config$interfaces = config.interfaces) !== null && |
| _config$interfaces !== void 0 |
| ? _config$interfaces |
| : [], |
| ); |
| Array.isArray(interfaces) || |
| devAssert( |
| false, |
| `${config.name} interfaces must be an Array or a function which returns an Array.`, |
| ); |
| return interfaces; |
| } |
|
|
| function defineFieldMap(config) { |
| const fieldMap = resolveObjMapThunk(config.fields); |
| isPlainObj(fieldMap) || |
| devAssert( |
| false, |
| `${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) => { |
| var _fieldConfig$args; |
|
|
| isPlainObj(fieldConfig) || |
| devAssert( |
| false, |
| `${config.name}.${fieldName} field config must be an object.`, |
| ); |
| fieldConfig.resolve == null || |
| typeof fieldConfig.resolve === 'function' || |
| devAssert( |
| false, |
| `${config.name}.${fieldName} field resolver must be a function if ` + |
| `provided, but got: ${inspect(fieldConfig.resolve)}.`, |
| ); |
| const argsConfig = |
| (_fieldConfig$args = fieldConfig.args) !== null && |
| _fieldConfig$args !== void 0 |
| ? _fieldConfig$args |
| : {}; |
| isPlainObj(argsConfig) || |
| devAssert( |
| false, |
| `${config.name}.${fieldName} args must be an object with argument names as keys.`, |
| ); |
| return { |
| name: assertName(fieldName), |
| description: fieldConfig.description, |
| type: fieldConfig.type, |
| args: defineArguments(argsConfig), |
| resolve: fieldConfig.resolve, |
| subscribe: fieldConfig.subscribe, |
| deprecationReason: fieldConfig.deprecationReason, |
| extensions: toObjMap(fieldConfig.extensions), |
| astNode: fieldConfig.astNode, |
| }; |
| }); |
| } |
|
|
| export function defineArguments(config) { |
| return Object.entries(config).map(([argName, argConfig]) => ({ |
| name: assertName(argName), |
| description: argConfig.description, |
| type: argConfig.type, |
| defaultValue: argConfig.defaultValue, |
| deprecationReason: argConfig.deprecationReason, |
| extensions: toObjMap(argConfig.extensions), |
| astNode: argConfig.astNode, |
| })); |
| } |
|
|
| function isPlainObj(obj) { |
| return isObjectLike(obj) && !Array.isArray(obj); |
| } |
|
|
| function fieldsToFieldsConfig(fields) { |
| return mapValue(fields, (field) => ({ |
| description: field.description, |
| type: field.type, |
| args: argsToArgsConfig(field.args), |
| resolve: field.resolve, |
| subscribe: field.subscribe, |
| deprecationReason: field.deprecationReason, |
| extensions: field.extensions, |
| astNode: field.astNode, |
| })); |
| } |
| /** |
| * @internal |
| */ |
|
|
| export function argsToArgsConfig(args) { |
| return keyValMap( |
| args, |
| (arg) => arg.name, |
| (arg) => ({ |
| description: arg.description, |
| type: arg.type, |
| defaultValue: arg.defaultValue, |
| deprecationReason: arg.deprecationReason, |
| extensions: arg.extensions, |
| astNode: arg.astNode, |
| }), |
| ); |
| } |
| export function isRequiredArgument(arg) { |
| return isNonNullType(arg.type) && arg.defaultValue === undefined; |
| } |
|
|
| /** |
| * 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: |
| * |
| * ```ts |
| * const EntityType = new GraphQLInterfaceType({ |
| * name: 'Entity', |
| * fields: { |
| * name: { type: GraphQLString } |
| * } |
| * }); |
| * ``` |
| */ |
| export class GraphQLInterfaceType { |
| constructor(config) { |
| var _config$extensionASTN3; |
|
|
| this.name = assertName(config.name); |
| this.description = config.description; |
| this.resolveType = config.resolveType; |
| this.extensions = toObjMap(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN3 = config.extensionASTNodes) !== null && |
| _config$extensionASTN3 !== void 0 |
| ? _config$extensionASTN3 |
| : []; |
| this._fields = defineFieldMap.bind(undefined, config); |
| this._interfaces = defineInterfaces.bind(undefined, config); |
| config.resolveType == null || |
| typeof config.resolveType === 'function' || |
| devAssert( |
| false, |
| `${this.name} must provide "resolveType" as a function, ` + |
| `but got: ${inspect(config.resolveType)}.`, |
| ); |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLInterfaceType'; |
| } |
|
|
| getFields() { |
| if (typeof this._fields === 'function') { |
| this._fields = this._fields(); |
| } |
|
|
| return this._fields; |
| } |
|
|
| getInterfaces() { |
| if (typeof this._interfaces === 'function') { |
| this._interfaces = this._interfaces(); |
| } |
|
|
| return this._interfaces; |
| } |
|
|
| toConfig() { |
| return { |
| name: this.name, |
| description: this.description, |
| interfaces: this.getInterfaces(), |
| fields: fieldsToFieldsConfig(this.getFields()), |
| resolveType: this.resolveType, |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| }; |
| } |
|
|
| toString() { |
| return this.name; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
|
|
| /** |
| * 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: |
| * |
| * ```ts |
| * 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 { |
| constructor(config) { |
| var _config$extensionASTN4; |
|
|
| this.name = assertName(config.name); |
| this.description = config.description; |
| this.resolveType = config.resolveType; |
| this.extensions = toObjMap(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN4 = config.extensionASTNodes) !== null && |
| _config$extensionASTN4 !== void 0 |
| ? _config$extensionASTN4 |
| : []; |
| this._types = defineTypes.bind(undefined, config); |
| config.resolveType == null || |
| typeof config.resolveType === 'function' || |
| devAssert( |
| false, |
| `${this.name} must provide "resolveType" as a function, ` + |
| `but got: ${inspect(config.resolveType)}.`, |
| ); |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLUnionType'; |
| } |
|
|
| getTypes() { |
| if (typeof this._types === 'function') { |
| this._types = this._types(); |
| } |
|
|
| return this._types; |
| } |
|
|
| toConfig() { |
| return { |
| name: this.name, |
| description: this.description, |
| types: this.getTypes(), |
| resolveType: this.resolveType, |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| }; |
| } |
|
|
| toString() { |
| return this.name; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
|
|
| function defineTypes(config) { |
| const types = resolveReadonlyArrayThunk(config.types); |
| Array.isArray(types) || |
| devAssert( |
| false, |
| `Must provide Array of types or a function which returns such an array for Union ${config.name}.`, |
| ); |
| return types; |
| } |
|
|
| /** |
| * 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: |
| * |
| * ```ts |
| * 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 { |
| /* <T> */ |
| constructor(config) { |
| var _config$extensionASTN5; |
|
|
| this.name = assertName(config.name); |
| this.description = config.description; |
| this.extensions = toObjMap(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN5 = config.extensionASTNodes) !== null && |
| _config$extensionASTN5 !== void 0 |
| ? _config$extensionASTN5 |
| : []; |
| this._values = |
| typeof config.values === 'function' |
| ? config.values |
| : defineEnumValues(this.name, config.values); |
| this._valueLookup = null; |
| this._nameLookup = null; |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLEnumType'; |
| } |
|
|
| getValues() { |
| if (typeof this._values === 'function') { |
| this._values = defineEnumValues(this.name, this._values()); |
| } |
|
|
| return this._values; |
| } |
|
|
| getValue(name) { |
| if (this._nameLookup === null) { |
| this._nameLookup = keyMap(this.getValues(), (value) => value.name); |
| } |
|
|
| return this._nameLookup[name]; |
| } |
|
|
| serialize(outputValue) { |
| if (this._valueLookup === null) { |
| this._valueLookup = new Map( |
| this.getValues().map((enumValue) => [enumValue.value, enumValue]), |
| ); |
| } |
|
|
| const enumValue = this._valueLookup.get(outputValue); |
|
|
| if (enumValue === undefined) { |
| throw new GraphQLError( |
| `Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`, |
| ); |
| } |
|
|
| return enumValue.name; |
| } |
|
|
| parseValue(inputValue) /* T */ |
| { |
| if (typeof inputValue !== 'string') { |
| const valueStr = inspect(inputValue); |
| throw new GraphQLError( |
| `Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + |
| didYouMeanEnumValue(this, valueStr), |
| ); |
| } |
|
|
| const enumValue = this.getValue(inputValue); |
|
|
| if (enumValue == null) { |
| throw new GraphQLError( |
| `Value "${inputValue}" does not exist in "${this.name}" enum.` + |
| didYouMeanEnumValue(this, inputValue), |
| ); |
| } |
|
|
| return enumValue.value; |
| } |
|
|
| parseLiteral(valueNode, _variables) /* T */ |
| { |
| // Note: variables will be resolved to a value before calling this function. |
| if (valueNode.kind !== Kind.ENUM) { |
| const valueStr = print(valueNode); |
| throw new GraphQLError( |
| `Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + |
| didYouMeanEnumValue(this, valueStr), |
| { |
| nodes: valueNode, |
| }, |
| ); |
| } |
|
|
| const enumValue = this.getValue(valueNode.value); |
|
|
| if (enumValue == null) { |
| const valueStr = print(valueNode); |
| throw new GraphQLError( |
| `Value "${valueStr}" does not exist in "${this.name}" enum.` + |
| didYouMeanEnumValue(this, valueStr), |
| { |
| nodes: valueNode, |
| }, |
| ); |
| } |
|
|
| return enumValue.value; |
| } |
|
|
| toConfig() { |
| const values = keyValMap( |
| this.getValues(), |
| (value) => value.name, |
| (value) => ({ |
| description: value.description, |
| value: value.value, |
| deprecationReason: value.deprecationReason, |
| extensions: value.extensions, |
| astNode: value.astNode, |
| }), |
| ); |
| return { |
| name: this.name, |
| description: this.description, |
| values, |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| }; |
| } |
|
|
| toString() { |
| return this.name; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
|
|
| function didYouMeanEnumValue(enumType, unknownValueStr) { |
| const allNames = enumType.getValues().map((value) => value.name); |
| const suggestedValues = suggestionList(unknownValueStr, allNames); |
| return didYouMean('the enum value', suggestedValues); |
| } |
|
|
| function defineEnumValues(typeName, valueMap) { |
| isPlainObj(valueMap) || |
| devAssert( |
| false, |
| `${typeName} values must be an object with value names as keys.`, |
| ); |
| return Object.entries(valueMap).map(([valueName, valueConfig]) => { |
| isPlainObj(valueConfig) || |
| devAssert( |
| false, |
| `${typeName}.${valueName} must refer to an object with a "value" key ` + |
| `representing an internal value but got: ${inspect(valueConfig)}.`, |
| ); |
| return { |
| name: assertEnumValueName(valueName), |
| description: valueConfig.description, |
| value: valueConfig.value !== undefined ? valueConfig.value : valueName, |
| deprecationReason: valueConfig.deprecationReason, |
| extensions: toObjMap(valueConfig.extensions), |
| astNode: valueConfig.astNode, |
| }; |
| }); |
| } |
|
|
| /** |
| * 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: |
| * |
| * ```ts |
| * const GeoPoint = new GraphQLInputObjectType({ |
| * name: 'GeoPoint', |
| * fields: { |
| * lat: { type: new GraphQLNonNull(GraphQLFloat) }, |
| * lon: { type: new GraphQLNonNull(GraphQLFloat) }, |
| * alt: { type: GraphQLFloat, defaultValue: 0 }, |
| * } |
| * }); |
| * ``` |
| */ |
| export class GraphQLInputObjectType { |
| constructor(config) { |
| var _config$extensionASTN6, _config$isOneOf; |
|
|
| this.name = assertName(config.name); |
| this.description = config.description; |
| this.extensions = toObjMap(config.extensions); |
| this.astNode = config.astNode; |
| this.extensionASTNodes = |
| (_config$extensionASTN6 = config.extensionASTNodes) !== null && |
| _config$extensionASTN6 !== void 0 |
| ? _config$extensionASTN6 |
| : []; |
| this.isOneOf = |
| (_config$isOneOf = config.isOneOf) !== null && _config$isOneOf !== void 0 |
| ? _config$isOneOf |
| : false; |
| this._fields = defineInputFieldMap.bind(undefined, config); |
| } |
|
|
| get [Symbol.toStringTag]() { |
| return 'GraphQLInputObjectType'; |
| } |
|
|
| getFields() { |
| if (typeof this._fields === 'function') { |
| this._fields = this._fields(); |
| } |
|
|
| return this._fields; |
| } |
|
|
| toConfig() { |
| const fields = mapValue(this.getFields(), (field) => ({ |
| description: field.description, |
| type: field.type, |
| defaultValue: field.defaultValue, |
| deprecationReason: field.deprecationReason, |
| extensions: field.extensions, |
| astNode: field.astNode, |
| })); |
| return { |
| name: this.name, |
| description: this.description, |
| fields, |
| extensions: this.extensions, |
| astNode: this.astNode, |
| extensionASTNodes: this.extensionASTNodes, |
| isOneOf: this.isOneOf, |
| }; |
| } |
|
|
| toString() { |
| return this.name; |
| } |
|
|
| toJSON() { |
| return this.toString(); |
| } |
| } |
|
|
| function defineInputFieldMap(config) { |
| const fieldMap = resolveObjMapThunk(config.fields); |
| isPlainObj(fieldMap) || |
| devAssert( |
| false, |
| `${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) => { |
| !('resolve' in fieldConfig) || |
| devAssert( |
| false, |
| `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`, |
| ); |
| return { |
| name: assertName(fieldName), |
| description: fieldConfig.description, |
| type: fieldConfig.type, |
| defaultValue: fieldConfig.defaultValue, |
| deprecationReason: fieldConfig.deprecationReason, |
| extensions: toObjMap(fieldConfig.extensions), |
| astNode: fieldConfig.astNode, |
| }; |
| }); |
| } |
|
|
| export function isRequiredInputField(field) { |
| return isNonNullType(field.type) && field.defaultValue === undefined; |
| } |