import { devAssert } from '../jsutils/devAssert.js';
import { didYouMean } from '../jsutils/didYouMean.js';
import { identityFunc } from '../jsutils/identityFunc.js';
import { inspect } from '../jsutils/inspect.js';
import { instanceOf } from '../jsutils/instanceOf.js';
import { keyMap } from '../jsutils/keyMap.js';
import { keyValMap } from '../jsutils/keyValMap.js';
import { mapValue } from '../jsutils/mapValue.js';
import type { Maybe } from '../jsutils/Maybe.js';
import type { ObjMap } from '../jsutils/ObjMap.js';
import type { Path } from '../jsutils/Path.js';
import type { PromiseOrValue } from '../jsutils/PromiseOrValue.js';
import { suggestionList } from '../jsutils/suggestionList.js';
import { toObjMap } from '../jsutils/toObjMap.js';
import { GraphQLError } from '../error/GraphQLError.js';
import type {
EnumTypeDefinitionNode,
EnumTypeExtensionNode,
EnumValueDefinitionNode,
FieldDefinitionNode,
FieldNode,
FragmentDefinitionNode,
InputObjectTypeDefinitionNode,
InputObjectTypeExtensionNode,
InputValueDefinitionNode,
InterfaceTypeDefinitionNode,
InterfaceTypeExtensionNode,
ObjectTypeDefinitionNode,
ObjectTypeExtensionNode,
OperationDefinitionNode,
ScalarTypeDefinitionNode,
ScalarTypeExtensionNode,
UnionTypeDefinitionNode,
UnionTypeExtensionNode,
ValueNode,
} from '../language/ast.js';
import { Kind } from '../language/kinds.js';
import { print } from '../language/printer.js';
import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped.js';
import { assertEnumValueName, assertName } from './assertName.js';
import type { GraphQLSchema } from './schema.js';
export type GraphQLType = GraphQLNamedType | GraphQLWrappingType;
export function isType(type: unknown): type is GraphQLType {
return (
isScalarType(type) ||
isObjectType(type) ||
isInterfaceType(type) ||
isUnionType(type) ||
isEnumType(type) ||
isInputObjectType(type) ||
isListType(type) ||
isNonNullType(type)
);
}
export function assertType(type: unknown): GraphQLType {
if (!isType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`);
}
return type;
}
export function isScalarType(type: unknown): type is GraphQLScalarType {
return instanceOf(type, GraphQLScalarType);
}
export function assertScalarType(type: unknown): GraphQLScalarType {
if (!isScalarType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`);
}
return type;
}
export function isObjectType(type: unknown): type is GraphQLObjectType {
return instanceOf(type, GraphQLObjectType);
}
export function assertObjectType(type: unknown): GraphQLObjectType {
if (!isObjectType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`);
}
return type;
}
export function isInterfaceType(type: unknown): type is GraphQLInterfaceType {
return instanceOf(type, GraphQLInterfaceType);
}
export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
if (!isInterfaceType(type)) {
throw new Error(
`Expected ${inspect(type)} to be a GraphQL Interface type.`,
);
}
return type;
}
export function isUnionType(type: unknown): type is GraphQLUnionType {
return instanceOf(type, GraphQLUnionType);
}
export function assertUnionType(type: unknown): GraphQLUnionType {
if (!isUnionType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`);
}
return type;
}
export function isEnumType(type: unknown): type is GraphQLEnumType {
return instanceOf(type, GraphQLEnumType);
}
export function assertEnumType(type: unknown): GraphQLEnumType {
if (!isEnumType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`);
}
return type;
}
export function isInputObjectType(
type: unknown,
): type is GraphQLInputObjectType {
return instanceOf(type, GraphQLInputObjectType);
}
export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
if (!isInputObjectType(type)) {
throw new Error(
`Expected ${inspect(type)} to be a GraphQL Input Object type.`,
);
}
return type;
}
export function isListType(
type: GraphQLInputType,
): type is GraphQLList<GraphQLInputType>;
export function isListType(
type: GraphQLOutputType,
): type is GraphQLList<GraphQLOutputType>;
export function isListType(type: unknown): type is GraphQLList<GraphQLType>;
export function isListType(type: unknown): type is GraphQLList<GraphQLType> {
return instanceOf(type, GraphQLList);
}
export function assertListType(type: unknown): GraphQLList<GraphQLType> {
if (!isListType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`);
}
return type;
}
export function isNonNullType(
type: GraphQLInputType,
): type is GraphQLNonNull<GraphQLNullableInputType>;
export function isNonNullType(
type: GraphQLOutputType,
): type is GraphQLNonNull<GraphQLNullableOutputType>;
export function isNonNullType(
type: unknown,
): type is GraphQLNonNull<GraphQLNullableType>;
export function isNonNullType(
type: unknown,
): type is GraphQLNonNull<GraphQLNullableType> {
return instanceOf(type, GraphQLNonNull);
}
export function assertNonNullType(
type: unknown,
): GraphQLNonNull<GraphQLNullableType> {
if (!isNonNullType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`);
}
return type;
}
export type GraphQLNullableInputType =
| GraphQLNamedInputType
| GraphQLList<GraphQLInputType>;
export type GraphQLInputType =
| GraphQLNullableInputType
| GraphQLNonNull<GraphQLNullableInputType>;
export function isInputType(type: unknown): type is GraphQLInputType {
return (
isScalarType(type) ||
isEnumType(type) ||
isInputObjectType(type) ||
(isWrappingType(type) && isInputType(type.ofType))
);
}
export function assertInputType(type: unknown): GraphQLInputType {
if (!isInputType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`);
}
return type;
}
export type GraphQLNullableOutputType =
| GraphQLNamedOutputType
| GraphQLList<GraphQLOutputType>;
export type GraphQLOutputType =
| GraphQLNullableOutputType
| GraphQLNonNull<GraphQLNullableOutputType>;
export function isOutputType(type: unknown): type is GraphQLOutputType {
return (
isScalarType(type) ||
isObjectType(type) ||
isInterfaceType(type) ||
isUnionType(type) ||
isEnumType(type) ||
(isWrappingType(type) && isOutputType(type.ofType))
);
}
export function assertOutputType(type: unknown): GraphQLOutputType {
if (!isOutputType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`);
}
return type;
}
export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType;
export function isLeafType(type: unknown): type is GraphQLLeafType {
return isScalarType(type) || isEnumType(type);
}
export function assertLeafType(type: unknown): GraphQLLeafType {
if (!isLeafType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`);
}
return type;
}
export type GraphQLCompositeType =
| GraphQLObjectType
| GraphQLInterfaceType
| GraphQLUnionType;
export function isCompositeType(type: unknown): type is GraphQLCompositeType {
return isObjectType(type) || isInterfaceType(type) || isUnionType(type);
}
export function assertCompositeType(type: unknown): GraphQLCompositeType {
if (!isCompositeType(type)) {
throw new Error(
`Expected ${inspect(type)} to be a GraphQL composite type.`,
);
}
return type;
}
export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType;
export function isAbstractType(type: unknown): type is GraphQLAbstractType {
return isInterfaceType(type) || isUnionType(type);
}
export function assertAbstractType(type: unknown): GraphQLAbstractType {
if (!isAbstractType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`);
}
return type;
}
export class GraphQLList<T extends GraphQLType> {
readonly ofType: T;
constructor(ofType: T) {
this.ofType = ofType;
}
get [Symbol.toStringTag]() {
return 'GraphQLList';
}
toString(): string {
return '[' + String(this.ofType) + ']';
}
toJSON(): string {
return this.toString();
}
}
export class GraphQLNonNull<T extends GraphQLNullableType> {
readonly ofType: T;
constructor(ofType: T) {
this.ofType = ofType;
}
get [Symbol.toStringTag]() {
return 'GraphQLNonNull';
}
toString(): string {
return String(this.ofType) + '!';
}
toJSON(): string {
return this.toString();
}
}
export type GraphQLWrappingType =
| GraphQLList<GraphQLType>
| GraphQLNonNull<GraphQLNullableType>;
export function isWrappingType(type: unknown): type is GraphQLWrappingType {
return isListType(type) || isNonNullType(type);
}
export function assertWrappingType(type: unknown): GraphQLWrappingType {
if (!isWrappingType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`);
}
return type;
}
export type GraphQLNullableType = GraphQLNamedType | GraphQLList<GraphQLType>;
export function isNullableType(type: unknown): type is GraphQLNullableType {
return isType(type) && !isNonNullType(type);
}
export function assertNullableType(type: unknown): GraphQLNullableType {
if (!isNullableType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`);
}
return type;
}
export function getNullableType(type: undefined | null): void;
export function getNullableType<T extends GraphQLNullableType>(
type: T | GraphQLNonNull<T>,
): T;
export function getNullableType(
type: Maybe<GraphQLType>,
): GraphQLNullableType | undefined;
export function getNullableType(
type: Maybe<GraphQLType>,
): GraphQLNullableType | undefined {
if (type) {
return isNonNullType(type) ? type.ofType : type;
}
}
export type GraphQLNamedType = GraphQLNamedInputType | GraphQLNamedOutputType;
export type GraphQLNamedInputType =
| GraphQLScalarType
| GraphQLEnumType
| GraphQLInputObjectType;
export type GraphQLNamedOutputType =
| GraphQLScalarType
| GraphQLObjectType
| GraphQLInterfaceType
| GraphQLUnionType
| GraphQLEnumType;
export function isNamedType(type: unknown): type is GraphQLNamedType {
return (
isScalarType(type) ||
isObjectType(type) ||
isInterfaceType(type) ||
isUnionType(type) ||
isEnumType(type) ||
isInputObjectType(type)
);
}
export function assertNamedType(type: unknown): GraphQLNamedType {
if (!isNamedType(type)) {
throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`);
}
return type;
}
export function getNamedType(type: undefined | null): void;
export function getNamedType(type: GraphQLInputType): GraphQLNamedInputType;
export function getNamedType(type: GraphQLOutputType): GraphQLNamedOutputType;
export function getNamedType(type: GraphQLType): GraphQLNamedType;
export function getNamedType(
type: Maybe<GraphQLType>,
): GraphQLNamedType | undefined;
export function getNamedType(
type: Maybe<GraphQLType>,
): GraphQLNamedType | undefined {
if (type) {
let unwrappedType = type;
while (isWrappingType(unwrappedType)) {
unwrappedType = unwrappedType.ofType;
}
return unwrappedType;
}
}
export type ThunkReadonlyArray<T> = (() => ReadonlyArray<T>) | ReadonlyArray<T>;
export type ThunkObjMap<T> = (() => ObjMap<T>) | ObjMap<T>;
export function resolveReadonlyArrayThunk<T>(
thunk: ThunkReadonlyArray<T>,
): ReadonlyArray<T> {
return typeof thunk === 'function' ? thunk() : thunk;
}
export function resolveObjMapThunk<T>(thunk: ThunkObjMap<T>): ObjMap<T> {
return typeof thunk === 'function' ? thunk() : thunk;
}
export interface GraphQLScalarTypeExtensions {
[attributeName: string]: unknown;
}
export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
name: string;
description: Maybe<string>;
specifiedByURL: Maybe<string>;
serialize: GraphQLScalarSerializer<TExternal>;
parseValue: GraphQLScalarValueParser<TInternal>;
parseLiteral: GraphQLScalarLiteralParser<TInternal>;
extensions: Readonly<GraphQLScalarTypeExtensions>;
astNode: Maybe<ScalarTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<ScalarTypeExtensionNode>;
constructor(config: Readonly<GraphQLScalarTypeConfig<TInternal, TExternal>>) {
const parseValue =
config.parseValue ??
(identityFunc as GraphQLScalarValueParser<TInternal>);
this.name = assertName(config.name);
this.description = config.description;
this.specifiedByURL = config.specifiedByURL;
this.serialize =
config.serialize ?? (identityFunc as GraphQLScalarSerializer<TExternal>);
this.parseValue = parseValue;
this.parseLiteral =
config.parseLiteral ??
((node, variables) => parseValue(valueFromASTUntyped(node, variables)));
this.extensions = toObjMap(config.extensions);
this.astNode = config.astNode;
this.extensionASTNodes = config.extensionASTNodes ?? [];
if (config.parseLiteral) {
devAssert(
typeof config.parseValue === 'function' &&
typeof config.parseLiteral === 'function',
`${this.name} must provide both "parseValue" and "parseLiteral" functions.`,
);
}
}
get [Symbol.toStringTag]() {
return 'GraphQLScalarType';
}
toConfig(): GraphQLScalarTypeNormalizedConfig<TInternal, TExternal> {
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(): string {
return this.name;
}
toJSON(): string {
return this.toString();
}
}
export type GraphQLScalarSerializer<TExternal> = (
outputValue: unknown,
) => TExternal;
export type GraphQLScalarValueParser<TInternal> = (
inputValue: unknown,
) => TInternal;
export type GraphQLScalarLiteralParser<TInternal> = (
valueNode: ValueNode,
variables?: Maybe<ObjMap<unknown>>,
) => TInternal;
export interface GraphQLScalarTypeConfig<TInternal, TExternal> {
name: string;
description?: Maybe<string>;
specifiedByURL?: Maybe<string>;
serialize?: GraphQLScalarSerializer<TExternal> | undefined;
parseValue?: GraphQLScalarValueParser<TInternal> | undefined;
parseLiteral?: GraphQLScalarLiteralParser<TInternal> | undefined;
extensions?: Maybe<Readonly<GraphQLScalarTypeExtensions>>;
astNode?: Maybe<ScalarTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<ScalarTypeExtensionNode>>;
}
interface GraphQLScalarTypeNormalizedConfig<TInternal, TExternal>
extends GraphQLScalarTypeConfig<TInternal, TExternal> {
serialize: GraphQLScalarSerializer<TExternal>;
parseValue: GraphQLScalarValueParser<TInternal>;
parseLiteral: GraphQLScalarLiteralParser<TInternal>;
extensions: Readonly<GraphQLScalarTypeExtensions>;
extensionASTNodes: ReadonlyArray<ScalarTypeExtensionNode>;
}
export interface GraphQLObjectTypeExtensions<_TSource = any, _TContext = any> {
[attributeName: string]: unknown;
}
export class GraphQLObjectType<TSource = any, TContext = any> {
name: string;
description: Maybe<string>;
isTypeOf: Maybe<GraphQLIsTypeOfFn<TSource, TContext>>;
extensions: Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>;
astNode: Maybe<ObjectTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<ObjectTypeExtensionNode>;
private _fields: ThunkObjMap<GraphQLField<TSource, TContext>>;
private _interfaces: ThunkReadonlyArray<GraphQLInterfaceType>;
constructor(config: Readonly<GraphQLObjectTypeConfig<TSource, TContext>>) {
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.extensionASTNodes ?? [];
this._fields = () => defineFieldMap(config);
this._interfaces = () => defineInterfaces(config);
}
get [Symbol.toStringTag]() {
return 'GraphQLObjectType';
}
getFields(): GraphQLFieldMap<TSource, TContext> {
if (typeof this._fields === 'function') {
this._fields = this._fields();
}
return this._fields;
}
getInterfaces(): ReadonlyArray<GraphQLInterfaceType> {
if (typeof this._interfaces === 'function') {
this._interfaces = this._interfaces();
}
return this._interfaces;
}
toConfig(): GraphQLObjectTypeNormalizedConfig<TSource, TContext> {
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(): string {
return this.name;
}
toJSON(): string {
return this.toString();
}
}
function defineInterfaces(
config: Readonly<
GraphQLObjectTypeConfig<any, any> | GraphQLInterfaceTypeConfig<any, any>
>,
): ReadonlyArray<GraphQLInterfaceType> {
return resolveReadonlyArrayThunk(config.interfaces ?? []);
}
function defineFieldMap<TSource, TContext>(
config: Readonly<
| GraphQLObjectTypeConfig<TSource, TContext>
| GraphQLInterfaceTypeConfig<TSource, TContext>
>,
): GraphQLFieldMap<TSource, TContext> {
const fieldMap = resolveObjMapThunk(config.fields);
return mapValue(fieldMap, (fieldConfig, fieldName) => {
const argsConfig = fieldConfig.args ?? {};
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: GraphQLFieldConfigArgumentMap,
): ReadonlyArray<GraphQLArgument> {
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 fieldsToFieldsConfig<TSource, TContext>(
fields: GraphQLFieldMap<TSource, TContext>,
): GraphQLFieldConfigMap<TSource, TContext> {
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,
}));
}
export function argsToArgsConfig(
args: ReadonlyArray<GraphQLArgument>,
): GraphQLFieldConfigArgumentMap {
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 interface GraphQLObjectTypeConfig<TSource, TContext> {
name: string;
description?: Maybe<string>;
interfaces?: ThunkReadonlyArray<GraphQLInterfaceType> | undefined;
fields: ThunkObjMap<GraphQLFieldConfig<TSource, TContext>>;
isTypeOf?: Maybe<GraphQLIsTypeOfFn<TSource, TContext>>;
extensions?: Maybe<Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>>;
astNode?: Maybe<ObjectTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<ObjectTypeExtensionNode>>;
}
interface GraphQLObjectTypeNormalizedConfig<TSource, TContext>
extends GraphQLObjectTypeConfig<any, any> {
interfaces: ReadonlyArray<GraphQLInterfaceType>;
fields: GraphQLFieldConfigMap<any, any>;
extensions: Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>;
extensionASTNodes: ReadonlyArray<ObjectTypeExtensionNode>;
}
export type GraphQLTypeResolver<TSource, TContext> = (
value: TSource,
context: TContext,
info: GraphQLResolveInfo,
abstractType: GraphQLAbstractType,
) => PromiseOrValue<string | undefined>;
export type GraphQLIsTypeOfFn<TSource, TContext> = (
source: TSource,
context: TContext,
info: GraphQLResolveInfo,
) => PromiseOrValue<boolean>;
export type GraphQLFieldResolver<
TSource,
TContext,
TArgs = any,
TResult = unknown,
> = (
source: TSource,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo,
) => TResult;
export interface GraphQLResolveInfo {
readonly fieldName: string;
readonly fieldNodes: ReadonlyArray<FieldNode>;
readonly returnType: GraphQLOutputType;
readonly parentType: GraphQLObjectType;
readonly path: Path;
readonly schema: GraphQLSchema;
readonly fragments: ObjMap<FragmentDefinitionNode>;
readonly rootValue: unknown;
readonly operation: OperationDefinitionNode;
readonly variableValues: { [variable: string]: unknown };
}
export interface GraphQLFieldExtensions<_TSource, _TContext, _TArgs = any> {
[attributeName: string]: unknown;
}
export interface GraphQLFieldConfig<TSource, TContext, TArgs = any> {
description?: Maybe<string>;
type: GraphQLOutputType;
args?: GraphQLFieldConfigArgumentMap | undefined;
resolve?: GraphQLFieldResolver<TSource, TContext, TArgs> | undefined;
subscribe?: GraphQLFieldResolver<TSource, TContext, TArgs> | undefined;
deprecationReason?: Maybe<string>;
extensions?: Maybe<
Readonly<GraphQLFieldExtensions<TSource, TContext, TArgs>>
>;
astNode?: Maybe<FieldDefinitionNode>;
}
export type GraphQLFieldConfigArgumentMap = ObjMap<GraphQLArgumentConfig>;
export interface GraphQLArgumentExtensions {
[attributeName: string]: unknown;
}
export interface GraphQLArgumentConfig {
description?: Maybe<string>;
type: GraphQLInputType;
defaultValue?: unknown;
deprecationReason?: Maybe<string>;
extensions?: Maybe<Readonly<GraphQLArgumentExtensions>>;
astNode?: Maybe<InputValueDefinitionNode>;
}
export type GraphQLFieldConfigMap<TSource, TContext> = ObjMap<
GraphQLFieldConfig<TSource, TContext>
>;
export interface GraphQLField<TSource, TContext, TArgs = any> {
name: string;
description: Maybe<string>;
type: GraphQLOutputType;
args: ReadonlyArray<GraphQLArgument>;
resolve?: GraphQLFieldResolver<TSource, TContext, TArgs> | undefined;
subscribe?: GraphQLFieldResolver<TSource, TContext, TArgs> | undefined;
deprecationReason: Maybe<string>;
extensions: Readonly<GraphQLFieldExtensions<TSource, TContext, TArgs>>;
astNode: Maybe<FieldDefinitionNode>;
}
export interface GraphQLArgument {
name: string;
description: Maybe<string>;
type: GraphQLInputType;
defaultValue: unknown;
deprecationReason: Maybe<string>;
extensions: Readonly<GraphQLArgumentExtensions>;
astNode: Maybe<InputValueDefinitionNode>;
}
export function isRequiredArgument(arg: GraphQLArgument): boolean {
return isNonNullType(arg.type) && arg.defaultValue === undefined;
}
export type GraphQLFieldMap<TSource, TContext> = ObjMap<
GraphQLField<TSource, TContext>
>;
export interface GraphQLInterfaceTypeExtensions {
[attributeName: string]: unknown;
}
export class GraphQLInterfaceType {
name: string;
description: Maybe<string>;
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
extensions: Readonly<GraphQLInterfaceTypeExtensions>;
astNode: Maybe<InterfaceTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<InterfaceTypeExtensionNode>;
private _fields: ThunkObjMap<GraphQLField<any, any>>;
private _interfaces: ThunkReadonlyArray<GraphQLInterfaceType>;
constructor(config: Readonly<GraphQLInterfaceTypeConfig<any, any>>) {
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.extensionASTNodes ?? [];
this._fields = defineFieldMap.bind(undefined, config);
this._interfaces = defineInterfaces.bind(undefined, config);
}
get [Symbol.toStringTag]() {
return 'GraphQLInterfaceType';
}
getFields(): GraphQLFieldMap<any, any> {
if (typeof this._fields === 'function') {
this._fields = this._fields();
}
return this._fields;
}
getInterfaces(): ReadonlyArray<GraphQLInterfaceType> {
if (typeof this._interfaces === 'function') {
this._interfaces = this._interfaces();
}
return this._interfaces;
}
toConfig(): GraphQLInterfaceTypeNormalizedConfig {
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(): string {
return this.name;
}
toJSON(): string {
return this.toString();
}
}
export interface GraphQLInterfaceTypeConfig<TSource, TContext> {
name: string;
description?: Maybe<string>;
interfaces?: ThunkReadonlyArray<GraphQLInterfaceType> | undefined;
fields: ThunkObjMap<GraphQLFieldConfig<TSource, TContext>>;
resolveType?: Maybe<GraphQLTypeResolver<TSource, TContext>>;
extensions?: Maybe<Readonly<GraphQLInterfaceTypeExtensions>>;
astNode?: Maybe<InterfaceTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<InterfaceTypeExtensionNode>>;
}
export interface GraphQLInterfaceTypeNormalizedConfig
extends GraphQLInterfaceTypeConfig<any, any> {
interfaces: ReadonlyArray<GraphQLInterfaceType>;
fields: GraphQLFieldConfigMap<any, any>;
extensions: Readonly<GraphQLInterfaceTypeExtensions>;
extensionASTNodes: ReadonlyArray<InterfaceTypeExtensionNode>;
}
export interface GraphQLUnionTypeExtensions {
[attributeName: string]: unknown;
}
export class GraphQLUnionType {
name: string;
description: Maybe<string>;
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
extensions: Readonly<GraphQLUnionTypeExtensions>;
astNode: Maybe<UnionTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<UnionTypeExtensionNode>;
private _types: ThunkReadonlyArray<GraphQLObjectType>;
constructor(config: Readonly<GraphQLUnionTypeConfig<any, any>>) {
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.extensionASTNodes ?? [];
this._types = defineTypes.bind(undefined, config);
}
get [Symbol.toStringTag]() {
return 'GraphQLUnionType';
}
getTypes(): ReadonlyArray<GraphQLObjectType> {
if (typeof this._types === 'function') {
this._types = this._types();
}
return this._types;
}
toConfig(): GraphQLUnionTypeNormalizedConfig {
return {
name: this.name,
description: this.description,
types: this.getTypes(),
resolveType: this.resolveType,
extensions: this.extensions,
astNode: this.astNode,
extensionASTNodes: this.extensionASTNodes,
};
}
toString(): string {
return this.name;
}
toJSON(): string {
return this.toString();
}
}
function defineTypes(
config: Readonly<GraphQLUnionTypeConfig<unknown, unknown>>,
): ReadonlyArray<GraphQLObjectType> {
return resolveReadonlyArrayThunk(config.types);
}
export interface GraphQLUnionTypeConfig<TSource, TContext> {
name: string;
description?: Maybe<string>;
types: ThunkReadonlyArray<GraphQLObjectType>;
resolveType?: Maybe<GraphQLTypeResolver<TSource, TContext>>;
extensions?: Maybe<Readonly<GraphQLUnionTypeExtensions>>;
astNode?: Maybe<UnionTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<UnionTypeExtensionNode>>;
}
interface GraphQLUnionTypeNormalizedConfig
extends GraphQLUnionTypeConfig<any, any> {
types: ReadonlyArray<GraphQLObjectType>;
extensions: Readonly<GraphQLUnionTypeExtensions>;
extensionASTNodes: ReadonlyArray<UnionTypeExtensionNode>;
}
export interface GraphQLEnumTypeExtensions {
[attributeName: string]: unknown;
}
export class GraphQLEnumType /* <T> */ {
name: string;
description: Maybe<string>;
extensions: Readonly<GraphQLEnumTypeExtensions>;
astNode: Maybe<EnumTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<EnumTypeExtensionNode>;
private _values: ReadonlyArray<GraphQLEnumValue >;
private _valueLookup: ReadonlyMap<any , GraphQLEnumValue>;
private _nameLookup: ObjMap<GraphQLEnumValue>;
constructor(config: Readonly<GraphQLEnumTypeConfig >) {
this.name = assertName(config.name);
this.description = config.description;
this.extensions = toObjMap(config.extensions);
this.astNode = config.astNode;
this.extensionASTNodes = config.extensionASTNodes ?? [];
this._values = Object.entries(config.values).map(
([valueName, valueConfig]) => ({
name: assertEnumValueName(valueName),
description: valueConfig.description,
value: valueConfig.value !== undefined ? valueConfig.value : valueName,
deprecationReason: valueConfig.deprecationReason,
extensions: toObjMap(valueConfig.extensions),
astNode: valueConfig.astNode,
}),
);
this._valueLookup = new Map(
this._values.map((enumValue) => [enumValue.value, enumValue]),
);
this._nameLookup = keyMap(this._values, (value) => value.name);
}
get [Symbol.toStringTag]() {
return 'GraphQLEnumType';
}
getValues(): ReadonlyArray<GraphQLEnumValue > {
return this._values;
}
getValue(name: string): Maybe<GraphQLEnumValue> {
return this._nameLookup[name];
}
serialize(outputValue: unknown ): Maybe<string> {
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: unknown): Maybe<any> {
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: ValueNode,
_variables: Maybe<ObjMap<unknown>>,
): Maybe<any> {
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(): GraphQLEnumTypeNormalizedConfig {
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(): string {
return this.name;
}
toJSON(): string {
return this.toString();
}
}
function didYouMeanEnumValue(
enumType: GraphQLEnumType,
unknownValueStr: string,
): string {
const allNames = enumType.getValues().map((value) => value.name);
const suggestedValues = suggestionList(unknownValueStr, allNames);
return didYouMean('the enum value', suggestedValues);
}
export interface GraphQLEnumTypeConfig {
name: string;
description?: Maybe<string>;
values: GraphQLEnumValueConfigMap ;
extensions?: Maybe<Readonly<GraphQLEnumTypeExtensions>>;
astNode?: Maybe<EnumTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<EnumTypeExtensionNode>>;
}
interface GraphQLEnumTypeNormalizedConfig extends GraphQLEnumTypeConfig {
extensions: Readonly<GraphQLEnumTypeExtensions>;
extensionASTNodes: ReadonlyArray<EnumTypeExtensionNode>;
}
export type GraphQLEnumValueConfigMap =
ObjMap<GraphQLEnumValueConfig >;
export interface GraphQLEnumValueExtensions {
[attributeName: string]: unknown;
}
export interface GraphQLEnumValueConfig {
description?: Maybe<string>;
value?: any ;
deprecationReason?: Maybe<string>;
extensions?: Maybe<Readonly<GraphQLEnumValueExtensions>>;
astNode?: Maybe<EnumValueDefinitionNode>;
}
export interface GraphQLEnumValue {
name: string;
description: Maybe<string>;
value: any ;
deprecationReason: Maybe<string>;
extensions: Readonly<GraphQLEnumValueExtensions>;
astNode: Maybe<EnumValueDefinitionNode>;
}
export interface GraphQLInputObjectTypeExtensions {
[attributeName: string]: unknown;
}
export class GraphQLInputObjectType {
name: string;
description: Maybe<string>;
extensions: Readonly<GraphQLInputObjectTypeExtensions>;
astNode: Maybe<InputObjectTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<InputObjectTypeExtensionNode>;
private _fields: ThunkObjMap<GraphQLInputField>;
constructor(config: Readonly<GraphQLInputObjectTypeConfig>) {
this.name = assertName(config.name);
this.description = config.description;
this.extensions = toObjMap(config.extensions);
this.astNode = config.astNode;
this.extensionASTNodes = config.extensionASTNodes ?? [];
this._fields = defineInputFieldMap.bind(undefined, config);
}
get [Symbol.toStringTag]() {
return 'GraphQLInputObjectType';
}
getFields(): GraphQLInputFieldMap {
if (typeof this._fields === 'function') {
this._fields = this._fields();
}
return this._fields;
}
toConfig(): GraphQLInputObjectTypeNormalizedConfig {
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,
};
}
toString(): string {
return this.name;
}
toJSON(): string {
return this.toString();
}
}
function defineInputFieldMap(
config: Readonly<GraphQLInputObjectTypeConfig>,
): GraphQLInputFieldMap {
const fieldMap = resolveObjMapThunk(config.fields);
return mapValue(fieldMap, (fieldConfig, fieldName) => {
devAssert(
!('resolve' in fieldConfig),
`${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 interface GraphQLInputObjectTypeConfig {
name: string;
description?: Maybe<string>;
fields: ThunkObjMap<GraphQLInputFieldConfig>;
extensions?: Maybe<Readonly<GraphQLInputObjectTypeExtensions>>;
astNode?: Maybe<InputObjectTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<InputObjectTypeExtensionNode>>;
}
interface GraphQLInputObjectTypeNormalizedConfig
extends GraphQLInputObjectTypeConfig {
fields: GraphQLInputFieldConfigMap;
extensions: Readonly<GraphQLInputObjectTypeExtensions>;
extensionASTNodes: ReadonlyArray<InputObjectTypeExtensionNode>;
}
export interface GraphQLInputFieldExtensions {
[attributeName: string]: unknown;
}
export interface GraphQLInputFieldConfig {
description?: Maybe<string>;
type: GraphQLInputType;
defaultValue?: unknown;
deprecationReason?: Maybe<string>;
extensions?: Maybe<Readonly<GraphQLInputFieldExtensions>>;
astNode?: Maybe<InputValueDefinitionNode>;
}
export type GraphQLInputFieldConfigMap = ObjMap<GraphQLInputFieldConfig>;
export interface GraphQLInputField {
name: string;
description: Maybe<string>;
type: GraphQLInputType;
defaultValue: unknown;
deprecationReason: Maybe<string>;
extensions: Readonly<GraphQLInputFieldExtensions>;
astNode: Maybe<InputValueDefinitionNode>;
}
export function isRequiredInputField(field: GraphQLInputField): boolean {
return isNonNullType(field.type) && field.defaultValue === undefined;
}
export type GraphQLInputFieldMap = ObjMap<GraphQLInputField>;