UNPKG

graphql

Version:

A Query Language and Runtime which can target any service.

783 lines 26.6 kB
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 { keyMap } from "../jsutils/keyMap.mjs"; import { keyValMap } from "../jsutils/keyValMap.mjs"; import { mapValue } from "../jsutils/mapValue.mjs"; import { suggestionList } from "../jsutils/suggestionList.mjs"; import { toObjMapWithSymbols } 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; } const scalarSymbol = Symbol('Scalar'); export function isScalarType(type) { return instanceOf(type, scalarSymbol, GraphQLScalarType); } export function assertScalarType(type) { if (!isScalarType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); } return type; } const objectSymbol = Symbol('Object'); export function isObjectType(type) { return instanceOf(type, objectSymbol, GraphQLObjectType); } export function assertObjectType(type) { if (!isObjectType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); } return type; } const fieldSymbol = Symbol('Field'); export function isField(field) { return instanceOf(field, fieldSymbol, GraphQLField); } export function assertField(field) { if (!isField(field)) { throw new Error(`Expected ${inspect(field)} to be a GraphQL field.`); } return field; } const argumentSymbol = Symbol('Argument'); export function isArgument(arg) { return instanceOf(arg, argumentSymbol, GraphQLArgument); } export function assertArgument(arg) { if (!isArgument(arg)) { throw new Error(`Expected ${inspect(arg)} to be a GraphQL argument.`); } return arg; } const interfaceSymbol = Symbol('Interface'); export function isInterfaceType(type) { return instanceOf(type, interfaceSymbol, GraphQLInterfaceType); } export function assertInterfaceType(type) { if (!isInterfaceType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Interface type.`); } return type; } const unionSymbol = Symbol('Union'); export function isUnionType(type) { return instanceOf(type, unionSymbol, GraphQLUnionType); } export function assertUnionType(type) { if (!isUnionType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); } return type; } const enumSymbol = Symbol('Enum'); export function isEnumType(type) { return instanceOf(type, enumSymbol, GraphQLEnumType); } export function assertEnumType(type) { if (!isEnumType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); } return type; } const enumValueSymbol = Symbol('EnumValue'); export function isEnumValue(value) { return instanceOf(value, enumValueSymbol, GraphQLEnumValue); } export function assertEnumValue(value) { if (!isEnumValue(value)) { throw new Error(`Expected ${inspect(value)} to be a GraphQL Enum value.`); } return value; } const inputObjectSymbol = Symbol('InputObject'); export function isInputObjectType(type) { return instanceOf(type, inputObjectSymbol, GraphQLInputObjectType); } export function assertInputObjectType(type) { if (!isInputObjectType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Input Object type.`); } return type; } const inputFieldSymbol = Symbol('InputField'); export function isInputField(field) { return instanceOf(field, inputFieldSymbol, GraphQLInputField); } export function assertInputField(field) { if (!isInputField(field)) { throw new Error(`Expected ${inspect(field)} to be a GraphQL input field.`); } return field; } const listSymbol = Symbol('List'); export function isListType(type) { return instanceOf(type, listSymbol, GraphQLList); } export function assertListType(type) { if (!isListType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); } return type; } const nonNullSymbol = Symbol('NonNull'); export function isNonNullType(type) { return instanceOf(type, nonNullSymbol, GraphQLNonNull); } export function assertNonNullType(type) { if (!isNonNullType(type)) { throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`); } return type; } 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; } 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; } 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; } 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; } 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; } export class GraphQLList { constructor(ofType) { this.__kind = listSymbol; this.ofType = ofType; } get [Symbol.toStringTag]() { return 'GraphQLList'; } toString() { return '[' + String(this.ofType) + ']'; } toJSON() { return this.toString(); } } export class GraphQLNonNull { constructor(ofType) { this.__kind = nonNullSymbol; this.ofType = ofType; } get [Symbol.toStringTag]() { return 'GraphQLNonNull'; } toString() { return String(this.ofType) + '!'; } toJSON() { return this.toString(); } } 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; } 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; } } 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; } } export function resolveReadonlyArrayThunk(thunk) { return typeof thunk === 'function' ? thunk() : thunk; } export function resolveObjMapThunk(thunk) { return typeof thunk === 'function' ? thunk() : thunk; } export class GraphQLScalarType { constructor(config) { this.__kind = scalarSymbol; this.name = assertName(config.name); this.description = config.description; this.specifiedByURL = config.specifiedByURL; this.serialize = config.serialize ?? config.coerceOutputValue ?? identityFunc; this.parseValue = config.parseValue ?? config.coerceInputValue ?? identityFunc; this.parseLiteral = config.parseLiteral ?? ((node, variables) => this.coerceInputValue(valueFromASTUntyped(node, variables))); this.coerceOutputValue = config.coerceOutputValue ?? this.serialize; this.coerceInputValue = config.coerceInputValue ?? this.parseValue; this.coerceInputLiteral = config.coerceInputLiteral; this.valueToLiteral = config.valueToLiteral; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes ?? []; if (config.parseLiteral) { if (!(typeof config.parseValue === 'function' && typeof config.parseLiteral === 'function')) devAssert(false, `${this.name} must provide both "parseValue" and "parseLiteral" functions.`); } if (config.coerceInputLiteral) { if (!(typeof config.coerceInputValue === 'function' && typeof config.coerceInputLiteral === 'function')) devAssert(false, `${this.name} must provide both "coerceInputValue" and "coerceInputLiteral" 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, coerceOutputValue: this.coerceOutputValue, coerceInputValue: this.coerceInputValue, coerceInputLiteral: this.coerceInputLiteral, valueToLiteral: this.valueToLiteral, extensions: this.extensions, astNode: this.astNode, extensionASTNodes: this.extensionASTNodes, }; } toString() { return this.name; } toJSON() { return this.toString(); } } export class GraphQLObjectType { constructor(config) { this.__kind = objectSymbol; this.__kind = objectSymbol; this.name = assertName(config.name); this.description = config.description; this.isTypeOf = config.isTypeOf; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes ?? []; this._fields = (defineFieldMap).bind(undefined, this, config.fields); this._interfaces = defineInterfaces.bind(undefined, config.interfaces); } 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: mapValue(this.getFields(), (field) => field.toConfig()), isTypeOf: this.isTypeOf, extensions: this.extensions, astNode: this.astNode, extensionASTNodes: this.extensionASTNodes, }; } toString() { return this.name; } toJSON() { return this.toString(); } } function defineInterfaces(interfaces) { return resolveReadonlyArrayThunk(interfaces ?? []); } function defineFieldMap(parentType, fields) { const fieldMap = resolveObjMapThunk(fields); return mapValue(fieldMap, (fieldConfig, fieldName) => new GraphQLField(parentType, fieldName, fieldConfig)); } export class GraphQLField { constructor(parentType, name, config) { this.__kind = fieldSymbol; this.parentType = parentType; this.name = assertName(name); this.description = config.description; this.type = config.type; const argsConfig = config.args; this.args = argsConfig ? Object.entries(argsConfig).map(([argName, argConfig]) => new GraphQLArgument(this, argName, argConfig)) : []; this.resolve = config.resolve; this.subscribe = config.subscribe; this.deprecationReason = config.deprecationReason; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; } get [Symbol.toStringTag]() { return 'GraphQLField'; } toConfig() { return { description: this.description, type: this.type, args: keyValMap(this.args, (arg) => arg.name, (arg) => arg.toConfig()), resolve: this.resolve, subscribe: this.subscribe, deprecationReason: this.deprecationReason, extensions: this.extensions, astNode: this.astNode, }; } toString() { return `${this.parentType ?? '<meta>'}.${this.name}`; } toJSON() { return this.toString(); } } export class GraphQLArgument { constructor(parent, name, config) { this.__kind = argumentSymbol; this.parent = parent; this.name = assertName(name); this.description = config.description; this.type = config.type; this.defaultValue = config.defaultValue; this.default = config.default; this._memoizedCoercedDefaultValue = undefined; this.deprecationReason = config.deprecationReason; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; } get [Symbol.toStringTag]() { return 'GraphQLArgument'; } toConfig() { return { description: this.description, type: this.type, defaultValue: this.defaultValue, default: this.default, deprecationReason: this.deprecationReason, extensions: this.extensions, astNode: this.astNode, }; } toString() { return `${this.parent}(${this.name}:)`; } toJSON() { return this.toString(); } } export function isRequiredArgument(arg) { return (isNonNullType(arg.type) && arg.default === undefined && arg.defaultValue === undefined); } export class GraphQLInterfaceType { constructor(config) { this.__kind = interfaceSymbol; this.name = assertName(config.name); this.description = config.description; this.resolveType = config.resolveType; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes ?? []; this._fields = (defineFieldMap).bind(undefined, this, config.fields); this._interfaces = defineInterfaces.bind(undefined, config.interfaces); } 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: mapValue(this.getFields(), (field) => field.toConfig()), resolveType: this.resolveType, extensions: this.extensions, astNode: this.astNode, extensionASTNodes: this.extensionASTNodes, }; } toString() { return this.name; } toJSON() { return this.toString(); } } export class GraphQLUnionType { constructor(config) { this.__kind = unionSymbol; this.name = assertName(config.name); this.description = config.description; this.resolveType = config.resolveType; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes ?? []; this._types = defineTypes.bind(undefined, config.types); } 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(types) { return resolveReadonlyArrayThunk(types); } export class GraphQLEnumType { constructor(config) { this.__kind = enumSymbol; this.name = assertName(config.name); this.description = config.description; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes ?? []; this._values = defineEnumValues.bind(undefined, this, config.values); this._valueLookup = null; this._nameLookup = null; } get [Symbol.toStringTag]() { return 'GraphQLEnumType'; } getValues() { if (typeof this._values === 'function') { this._values = this._values(); } return this._values; } getValue(name) { this._nameLookup ??= keyMap(this.getValues(), (value) => value.name); return this._nameLookup[name]; } serialize(outputValue) { return this.coerceOutputValue(outputValue); } coerceOutputValue(outputValue) { 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, hideSuggestions) { return this.coerceInputValue(inputValue, hideSuggestions); } coerceInputValue(inputValue, hideSuggestions) { if (typeof inputValue !== 'string') { const valueStr = inspect(inputValue); throw new GraphQLError(`Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + (hideSuggestions ? '' : didYouMeanEnumValue(this, valueStr))); } const enumValue = this.getValue(inputValue); if (enumValue == null) { throw new GraphQLError(`Value "${inputValue}" does not exist in "${this.name}" enum.` + (hideSuggestions ? '' : didYouMeanEnumValue(this, inputValue))); } return enumValue.value; } parseLiteral(valueNode, _variables, hideSuggestions) { return this.coerceInputLiteral(valueNode, hideSuggestions); } coerceInputLiteral(valueNode, hideSuggestions) { if (valueNode.kind !== Kind.ENUM) { const valueStr = print(valueNode); throw new GraphQLError(`Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + (hideSuggestions ? '' : 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.` + (hideSuggestions ? '' : didYouMeanEnumValue(this, valueStr)), { nodes: valueNode }); } return enumValue.value; } valueToLiteral(value) { if (typeof value === 'string' && this.getValue(value)) { return { kind: Kind.ENUM, value }; } } toConfig() { return { name: this.name, description: this.description, values: keyValMap(this.getValues(), (value) => value.name, (value) => value.toConfig()), extensions: this.extensions, astNode: this.astNode, extensionASTNodes: this.extensionASTNodes, }; } toString() { return this.name; } toJSON() { return this.toString(); } } function defineEnumValues(parentEnum, values) { const valueMap = resolveObjMapThunk(values); return Object.entries(valueMap).map(([valueName, valueConfig]) => new GraphQLEnumValue(parentEnum, valueName, valueConfig)); } function didYouMeanEnumValue(enumType, unknownValueStr) { const allNames = enumType.getValues().map((value) => value.name); const suggestedValues = suggestionList(unknownValueStr, allNames); return didYouMean('the enum value', suggestedValues); } export class GraphQLEnumValue { constructor(parentEnum, name, config) { this.__kind = enumValueSymbol; this.parentEnum = parentEnum; this.name = assertEnumValueName(name); this.description = config.description; this.value = config.value !== undefined ? config.value : name; this.deprecationReason = config.deprecationReason; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; } get [Symbol.toStringTag]() { return 'GraphQLEnumValue'; } toConfig() { return { description: this.description, value: this.value, deprecationReason: this.deprecationReason, extensions: this.extensions, astNode: this.astNode, }; } toString() { return `${this.parentEnum.name}.${this.name}`; } toJSON() { return this.toString(); } } export class GraphQLInputObjectType { constructor(config) { this.__kind = inputObjectSymbol; this.name = assertName(config.name); this.description = config.description; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = config.extensionASTNodes ?? []; this.isOneOf = config.isOneOf ?? false; this._fields = defineInputFieldMap.bind(undefined, this, config.fields); } get [Symbol.toStringTag]() { return 'GraphQLInputObjectType'; } getFields() { if (typeof this._fields === 'function') { this._fields = this._fields(); } return this._fields; } toConfig() { return { name: this.name, description: this.description, fields: mapValue(this.getFields(), (field) => field.toConfig()), extensions: this.extensions, astNode: this.astNode, extensionASTNodes: this.extensionASTNodes, isOneOf: this.isOneOf, }; } toString() { return this.name; } toJSON() { return this.toString(); } } function defineInputFieldMap(parentType, fields) { const fieldMap = resolveObjMapThunk(fields); return mapValue(fieldMap, (fieldConfig, fieldName) => new GraphQLInputField(parentType, fieldName, fieldConfig)); } export class GraphQLInputField { constructor(parentType, name, config) { if (!(!('resolve' in config))) devAssert(false, `${parentType}.${name} field has a resolve property, but Input Types cannot define resolvers.`); this.__kind = inputFieldSymbol; this.parentType = parentType; this.name = assertName(name); this.description = config.description; this.type = config.type; this.defaultValue = config.defaultValue; this.default = config.default; this._memoizedCoercedDefaultValue = undefined; this.deprecationReason = config.deprecationReason; this.extensions = toObjMapWithSymbols(config.extensions); this.astNode = config.astNode; } get [Symbol.toStringTag]() { return 'GraphQLInputField'; } toConfig() { return { description: this.description, type: this.type, defaultValue: this.defaultValue, default: this.default, deprecationReason: this.deprecationReason, extensions: this.extensions, astNode: this.astNode, }; } toString() { return `${this.parentType}.${this.name}`; } toJSON() { return this.toString(); } } export function isRequiredInputField(field) { return (isNonNullType(field.type) && field.defaultValue === undefined && field.default === undefined); } //# sourceMappingURL=definition.js.map