import { visit, Kind, isEqualType, isAbstractType, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, GraphQLCompositeType, GraphQLEnumValue, GraphQLError, GraphQLSchema, GraphQLType, ASTNode, Location, ValueNode, OperationDefinitionNode, SelectionSetNode, FieldNode, GraphQLField, DocumentNode, DirectiveNode, isListType, isNonNullType, isObjectType, isInterfaceType, isUnionType, } from "graphql"; declare module "graphql/utilities/buildASTSchema" { function buildASTSchema( ast: DocumentNode, options?: { assumeValid?: boolean; commentDescriptions?: boolean } ): GraphQLSchema; } export function sortEnumValues(values: GraphQLEnumValue[]): GraphQLEnumValue[] { return values.sort((a, b) => a.value < b.value ? -1 : a.value > b.value ? 1 : 0 ); } export function isList(type: GraphQLType): boolean { return isListType(type) || (isNonNullType(type) && isListType(type.ofType)); } export function isMetaFieldName(name: string) { return name.startsWith("__"); } export function removeConnectionDirectives(ast: ASTNode) { return visit(ast, { Directive(node: DirectiveNode): DirectiveNode | null { if (node.name.value === "connection") return null; return node; }, }); } export function removeClientDirectives(ast: ASTNode) { return visit(ast, { Field(node: FieldNode): FieldNode | null { if ( node.directives && node.directives.find((directive) => directive.name.value === "client") ) return null; return node; }, OperationDefinition: { leave(node: OperationDefinitionNode): OperationDefinitionNode | null { if (!node.selectionSet.selections.length) return null; return node; }, }, }); } const typenameField = { kind: Kind.FIELD, name: { kind: Kind.NAME, value: "__typename" }, }; export function sourceAt(location: Location) { return location.source.body.slice(location.start, location.end); } export function filePathForNode(node: ASTNode): string { const name = node.loc && node.loc.source && node.loc.source.name; if (!name || name === "GraphQL") { throw new Error("Node does not seem to have a file path"); } return name; } export function valueFromValueNode( valueNode: ValueNode ): any | { kind: "Variable"; variableName: string } { switch (valueNode.kind) { case "IntValue": case "FloatValue": return Number(valueNode.value); case "NullValue": return null; case "ListValue": return valueNode.values.map(valueFromValueNode); case "ObjectValue": return valueNode.fields.reduce((object, field) => { object[field.name.value] = valueFromValueNode(field.value); return object; }, {} as any); case "Variable": return { kind: "Variable", variableName: valueNode.name.value }; default: return valueNode.value; } } export function isTypeProperSuperTypeOf( schema: GraphQLSchema, maybeSuperType: GraphQLCompositeType, subType: GraphQLCompositeType ) { return ( isEqualType(maybeSuperType, subType) || (isObjectType(subType) && isAbstractType(maybeSuperType) && schema.isPossibleType(maybeSuperType, subType)) ); } // Utility functions extracted from graphql-js /** * Extracts the root type of the operation from the schema. */ export function getOperationRootType( schema: GraphQLSchema, operation: OperationDefinitionNode ) { switch (operation.operation) { case "query": return schema.getQueryType(); case "mutation": const mutationType = schema.getMutationType(); if (!mutationType) { throw new GraphQLError("Schema is not configured for mutations", [ operation, ]); } return mutationType; case "subscription": const subscriptionType = schema.getSubscriptionType(); if (!subscriptionType) { throw new GraphQLError("Schema is not configured for subscriptions", [ operation, ]); } return subscriptionType; default: throw new GraphQLError( "Can only compile queries, mutations and subscriptions", [operation] ); } } /** * Not exactly the same as the executor's definition of getFieldDef, in this * statically evaluated environment we do not always have an Object type, * and need to handle Interface and Union types. */ export function getFieldDef( schema: GraphQLSchema, parentType: GraphQLCompositeType, fieldAST: FieldNode ): GraphQLField | undefined { const name = fieldAST.name.value; if ( name === SchemaMetaFieldDef.name && schema.getQueryType() === parentType ) { return SchemaMetaFieldDef; } if (name === TypeMetaFieldDef.name && schema.getQueryType() === parentType) { return TypeMetaFieldDef; } if ( name === TypeNameMetaFieldDef.name && (isObjectType(parentType) || isInterfaceType(parentType) || isUnionType(parentType)) ) { return TypeNameMetaFieldDef; } if (isObjectType(parentType) || isInterfaceType(parentType)) { return parentType.getFields()[name]; } return undefined; }