UNPKG

@apollo/subgraph

Version:
170 lines (145 loc) 4.67 kB
import { GraphQLSchema, GraphQLNamedType, isIntrospectionType, isObjectType, GraphQLObjectType, GraphQLType, isListType, GraphQLList, isNonNullType, GraphQLNonNull, GraphQLFieldConfigMap, GraphQLFieldConfigArgumentMap, isInterfaceType, GraphQLInterfaceType, isUnionType, GraphQLUnionType, isInputObjectType, GraphQLInputObjectType, GraphQLInputFieldConfigMap, GraphQLDirective } from "graphql"; type TypeTransformer = ( type: GraphQLNamedType ) => GraphQLNamedType | null | undefined; function mapValues<T, U = T>( object: Record<string, T>, callback: (value: T) => U ): Record<string, U> { const result: Record<string, U> = Object.create(null); for (const [key, value] of Object.entries(object)) { result[key] = callback(value); } return result; } export function transformSchema( schema: GraphQLSchema, transformType: TypeTransformer ): GraphQLSchema { const typeMap: { [typeName: string]: GraphQLNamedType } = Object.create(null); for (const oldType of Object.values(schema.getTypeMap())) { if (isIntrospectionType(oldType)) continue; const result = transformType(oldType); // Returning `null` removes the type. if (result === null) continue; // Returning `undefined` keeps the old type. const newType = result || oldType; typeMap[newType.name] = recreateNamedType(newType); } const schemaConfig = schema.toConfig(); return new GraphQLSchema({ ...schemaConfig, types: Object.values(typeMap), query: replaceMaybeType(schemaConfig.query), mutation: replaceMaybeType(schemaConfig.mutation), subscription: replaceMaybeType(schemaConfig.subscription), directives: replaceDirectives(schemaConfig.directives) }); function recreateNamedType(type: GraphQLNamedType): GraphQLNamedType { if (isObjectType(type)) { const config = type.toConfig(); return new GraphQLObjectType({ ...config, interfaces: () => config.interfaces.map(replaceNamedType), fields: () => replaceFields(config.fields) }); } else if (isInterfaceType(type)) { const config = type.toConfig(); return new GraphQLInterfaceType({ ...config, interfaces: () => config.interfaces.map(replaceNamedType), fields: () => replaceFields(config.fields) }); } else if (isUnionType(type)) { const config = type.toConfig(); return new GraphQLUnionType({ ...config, types: () => config.types.map(replaceNamedType) }); } else if (isInputObjectType(type)) { const config = type.toConfig(); return new GraphQLInputObjectType({ ...config, fields: () => replaceInputFields(config.fields) }); } return type; } function replaceType<T extends GraphQLType>( type: GraphQLList<T> ): GraphQLList<T>; function replaceType<T extends GraphQLType>( type: GraphQLNonNull<T> ): GraphQLNonNull<T>; function replaceType<T extends GraphQLType>(type: T): T; function replaceType(type: GraphQLType): GraphQLType { if (isListType(type)) { return new GraphQLList(replaceType(type.ofType)); } else if (isNonNullType(type)) { return new GraphQLNonNull(replaceType(type.ofType)); } return replaceNamedType(type); } function replaceNamedType<T extends GraphQLNamedType>(type: T): T { const newType = typeMap[type.name] as T; return newType ? newType : type; } function replaceMaybeType<T extends GraphQLNamedType>( type: T | null | undefined ): T | undefined { return type ? replaceNamedType(type) : undefined; } function replaceFields<TSource, TContext>( fieldsMap: GraphQLFieldConfigMap<TSource, TContext> ): GraphQLFieldConfigMap<TSource, TContext> { return mapValues(fieldsMap, field => ({ ...field, type: replaceType(field.type), args: field.args ? replaceArgs(field.args) : undefined })); } function replaceInputFields( fieldsMap: GraphQLInputFieldConfigMap ): GraphQLInputFieldConfigMap { return mapValues(fieldsMap, field => ({ ...field, type: replaceType(field.type) })); } function replaceArgs(args: GraphQLFieldConfigArgumentMap): GraphQLFieldConfigArgumentMap { return mapValues(args, (arg) => ({ ...arg, type: replaceType(arg.type), })); } function replaceDirectives(directives: readonly GraphQLDirective[]): readonly GraphQLDirective[] { return directives.map((directive) => { const config = directive.toConfig(); return new GraphQLDirective({ ...config, args: replaceArgs(config.args), }); }); } }