UNPKG

@graphql-codegen/typescript-msw

Version:

GraphQL Code Generator plugin for generating MSW mock handlers based on GraphQL operations

83 lines (82 loc) 3.95 kB
import autoBind from 'auto-bind'; import { pascalCase } from 'change-case-all'; import { print } from 'graphql'; import { ClientSideBaseVisitor, getConfigValue, } from '@graphql-codegen/visitor-plugin-common'; export class MSWVisitor extends ClientSideBaseVisitor { constructor(schema, fragments, rawConfig) { super(schema, fragments, rawConfig, { link: getConfigValue(rawConfig.link, undefined) }); this._operationsToInclude = []; autoBind(this); this._externalImportPrefix = this.config.importOperationTypesFrom ? `${this.config.importOperationTypesFrom}.` : ''; } getImports() { const hasOperations = this._collectedOperations.length > 0; if (!hasOperations) { return []; } return [ `import { graphql, type GraphQLResponseResolver, type RequestHandlerOptions } from 'msw'`, ]; } getContent() { var _a; const { link } = this.config; let endpoint; if (link) { endpoint = `const ${link.name} = graphql.link('${link.endpoint}')\n`; } const suffix = pascalCase((link === null || link === void 0 ? void 0 : link.name) || ''); const withSuffix = (_a = link === null || link === void 0 ? void 0 : link.withSuffix) !== null && _a !== void 0 ? _a : true; const operations = this._operationsToInclude.map(({ node, operationType, operationResultType, operationVariablesTypes }) => { if (operationType === 'Query' || operationType === 'Mutation') { const handlerName = `mock${pascalCase(node.name.value)}${operationType}${withSuffix ? suffix : ''}`; /** @ts-expect-error name DOES exist on @type{import('graphql').SelectionNode} */ const selections = node.selectionSet.selections.map(sel => sel.name.value).join(', '); const variables = node.variableDefinitions.map(def => def.variable.name.value).join(', '); return `/** * @param resolver A function that accepts [resolver arguments](https://mswjs.io/docs/api/graphql#resolver-argument) and must always return the instruction on what to do with the intercepted request. ([see more](https://mswjs.io/docs/concepts/response-resolver#resolver-instructions)) * @param options Options object to customize the behavior of the mock. ([see more](https://mswjs.io/docs/api/graphql#handler-options)) * @see https://mswjs.io/docs/basics/response-resolver * @example * ${handlerName}( * ({ query, variables }) => {${variables && ` * const { ${variables} } = variables;`} * return HttpResponse.json({ * data: { ${selections} } * }) * }, * requestOptions * ) */ export const ${handlerName} = (resolver: GraphQLResponseResolver<${operationResultType}, ${operationVariablesTypes}>, options?: RequestHandlerOptions) => ${(link === null || link === void 0 ? void 0 : link.name) || 'graphql'}.${operationType.toLowerCase()}<${operationResultType}, ${operationVariablesTypes}>( '${node.name.value}', resolver, options )\n`; } return ''; }); return [endpoint, ...operations].join('\n'); } buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) { operationResultType = this._externalImportPrefix + operationResultType; operationVariablesTypes = this._externalImportPrefix + operationVariablesTypes; if (node.name == null) { throw new Error("Plugin 'msw' cannot generate mocks for unnamed operation.\n\n" + print(node)); } else { this._operationsToInclude.push({ node, documentVariableName, operationType, operationResultType, operationVariablesTypes, }); } return null; } }