@graphql-codegen/typescript-msw
Version:
GraphQL Code Generator plugin for generating MSW mock handlers based on GraphQL operations
72 lines (71 loc) • 3.33 kB
JavaScript
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, ResponseResolver, GraphQLRequest, GraphQLContext } from 'msw'`];
}
getContent() {
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 operations = this._operationsToInclude.map(({ node, operationType, operationResultType, operationVariablesTypes }) => {
if (operationType === 'Query' || operationType === 'Mutation') {
const handlerName = `mock${pascalCase(node.name.value)}${operationType}${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 a captured request and may return a mocked response.
* @see https://mswjs.io/docs/basics/response-resolver
* @example
* ${handlerName}((req, res, ctx) => {${variables && `\n * const { ${variables} } = req.variables;`}
* return res(
* ctx.data({ ${selections} })
* )
* })
*/
export const ${handlerName} = (resolver: ResponseResolver<GraphQLRequest<${operationVariablesTypes}>, GraphQLContext<${operationResultType}>, any>) =>
${(link === null || link === void 0 ? void 0 : link.name) || 'graphql'}.${operationType.toLowerCase()}<${operationResultType}, ${operationVariablesTypes}>(
'${node.name.value}',
resolver
)\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;
}
}