UNPKG

@graphql-mesh/incontext-sdk-codegen

Version:
133 lines (128 loc) 5.36 kB
import { getNamedType, isAbstractType, Kind } from 'graphql'; import { pascalCase } from 'pascal-case'; import { codegen } from '@graphql-codegen/core'; import { getCachedDocumentNodeFromSchema } from '@graphql-codegen/plugin-helpers'; import { defaultImportFn } from '@graphql-mesh/utils'; async function loadTypeScriptCodegenPlugin() { return defaultImportFn('@graphql-codegen/typescript'); } function createCodegenHelpers(tsBasePlugin) { return class CodegenHelpers extends tsBasePlugin.TsVisitor { getTypeToUse(namedType, isVisitingInputType) { if (this.scalars[namedType.name.value]) { return this._getScalar(namedType.name.value, isVisitingInputType ? 'input' : 'output'); } return this._getTypeForNode(namedType, isVisitingInputType); } }; } function buildSignatureBasedOnRootFields(codegenHelpers, type, schema, unifiedContextIdentifier) { if (!type) { return {}; } const fields = type.getFields(); const operationMap = {}; for (const fieldName in fields) { const field = fields[fieldName]; const argsExists = field.args && field.args.length > 0; const argsName = argsExists ? `${type.name}${field.name}Args` : '{}'; const parentTypeNode = { kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: type.name, }, }; const namedFieldType = getNamedType(field.type); const fieldDescriptionBlock = field.description ? `/** ${field.description} **/\n` : ''; if (isAbstractType(namedFieldType)) { const possibleTypes = schema.getPossibleTypes(namedFieldType); const typeNamesDef = possibleTypes .map(possibleType => codegenHelpers.getTypeToUse({ kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: possibleType.name, }, }, false)) .join(' | '); const originalDef = field.type.toString(); const def = originalDef.replace(namedFieldType.name, typeNamesDef); operationMap[fieldName] = ` ${fieldDescriptionBlock} ${field.name}: InContextSdkMethod<${def}, ${argsName}, ${unifiedContextIdentifier}>`; } else { operationMap[fieldName] = ` ${fieldDescriptionBlock}\n ${field.name}: InContextSdkMethod<${codegenHelpers.getTypeToUse(parentTypeNode, false)}['${fieldName}'], ${argsName}, ${unifiedContextIdentifier}>`; } } return operationMap; } export async function generateIncontextSDKTypes(options) { const config = { skipTypename: true, flattenGeneratedTypes: options.flattenTypes, onlyOperationTypes: options.flattenTypes, preResolveTypes: options.flattenTypes, namingConvention: 'keep', enumsAsTypes: true, ignoreEnumValuesFromSchema: true, useIndexSignature: true, ...options.codegenConfig, }; const tsBasePlugin = await loadTypeScriptCodegenPlugin(); const baseTypes = await codegen({ filename: options.name + '_types.ts', documents: [], config, schemaAst: options.schema, schema: getCachedDocumentNodeFromSchema(options.schema), skipDocumentsValidation: true, plugins: [ { typescript: {}, }, ], pluginMap: { typescript: tsBasePlugin, }, }); const CodegenHelpers = createCodegenHelpers(tsBasePlugin); const codegenHelpers = new CodegenHelpers(options.schema, config, {}); const namespace = pascalCase(`${options.name}Types`); const queryOperationMap = buildSignatureBasedOnRootFields(codegenHelpers, options.schema.getQueryType(), options.schema, options.unifiedContextIdentifier); const mutationOperationMap = buildSignatureBasedOnRootFields(codegenHelpers, options.schema.getMutationType(), options.schema, options.unifiedContextIdentifier); const subscriptionsOperationMap = buildSignatureBasedOnRootFields(codegenHelpers, options.schema.getSubscriptionType(), options.schema, options.unifiedContextIdentifier); const codeAst = ` import type { InContextSdkMethod } from '@graphql-mesh/types'; export namespace ${namespace} { ${baseTypes} export type QuerySdk = { ${Object.values(queryOperationMap).join(',\n')} }; export type MutationSdk = { ${Object.values(mutationOperationMap).join(',\n')} }; export type SubscriptionSdk = { ${Object.values(subscriptionsOperationMap).join(',\n')} }; export type Context = { [${JSON.stringify(options.name)}]: { Query: QuerySdk, Mutation: MutationSdk, Subscription: SubscriptionSdk }, ${Object.keys(options.contextVariables) .map(key => `[${JSON.stringify(key)}]: ${options.contextVariables[key]}`) .join(',\n')} }; } `; return { identifier: namespace, codeAst, }; } export function generateUnifiedContextTypeFromIdentifiers(identifiers) { if (identifiers.length === 0) { return 'export type MeshInContextSDK = {};'; } return `export type MeshInContextSDK = ${identifiers .map(identifier => `${identifier}.Context`) .filter(Boolean) .join(' & ')};`; }