UNPKG

graphql-codegen-typescript-operations-tester

Version:
108 lines (92 loc) 3.1 kB
import { PluginFunction } from '@graphql-codegen/plugin-helpers' import { pascalCase } from 'change-case-all' import { concatAST, DocumentNode, ExecutionResult, FragmentDefinitionNode, graphql, GraphQLArgs, GraphQLSchema, OperationDefinitionNode, print, visit, } from 'graphql' function getOperationFragments( node: OperationDefinitionNode | FragmentDefinitionNode, allFragments: Map<string, FragmentDefinitionNode>, operationFragments?: Map<string, FragmentDefinitionNode> ): Map<string, FragmentDefinitionNode> { const fragments = operationFragments || new Map<string, FragmentDefinitionNode>() visit(node, { FragmentSpread: { enter(node) { const fragment = allFragments.get(node.name.value) if (fragment) { fragments.set(node.name.value, fragment) getOperationFragments(fragment, allFragments, fragments) } else { throw new Error('Unknown fragment: ' + node.name.value) } }, }, }) return fragments } type Config = { prefix?: string } export const plugin: PluginFunction<Config> = (schema, documents, config) => { const imports = [`import { request, Args } from 'graphql-codegen-typescript-operations-tester'`] const prefix = config.prefix || 'test' const allAst = concatAST( documents.reduce<DocumentNode[]>((acc, source) => { if (source.document) { acc.push(source.document) } return acc }, []) ) const allFragments = new Map<string, FragmentDefinitionNode>() visit(allAst, { FragmentDefinition(node) { allFragments.set(node.name.value, node) }, }) const lines: string[] = [] visit(allAst, { OperationDefinition(node) { if (!node.name) return const type = node.operation === 'mutation' ? 'Mutation' : 'Query' // Mimic the default naming convention. // See https://www.graphql-code-generator.com/docs/getting-started/naming-convention#namingconvention const name = pascalCase(`${node.name.value}${type}`) const fragments = getOperationFragments(node, allFragments) const fragmentsStr = fragments.size > 0 ? `${Array.from(fragments.values()).map(print)}\n` : '' lines.push(``) lines.push(`export const ${name}Source: string = \``) lines.push(`${fragmentsStr}${print(node)}\`;`) lines.push(``) lines.push(`export function ${prefix}${name}(`) lines.push(` graphqlArgs: Args,`) lines.push(` variables?: ${name}Variables`) lines.push(`) {`) lines.push( ` return request<${name}>({ ...graphqlArgs, source: ${name}Source, variableValues: variables })` ) lines.push(`};`) }, }) const content = lines.join('\n') return { prepend: imports, content: content, } } export type Args = { schema: GraphQLSchema } & Partial<GraphQLArgs> export async function request<TData extends Record<string, unknown> = Record<string, unknown>>( graphqlArgs: GraphQLArgs ): Promise<ExecutionResult<TData>> { return graphql(graphqlArgs) as Promise<ExecutionResult<TData>> }