UNPKG

@graphql-codegen/typescript-react-query

Version:

GraphQL Code Generator plugin for generating a ready-to-use React-Query Hooks based on GraphQL operations

155 lines (154 loc) 7.52 kB
import autoBind from 'auto-bind'; import { pascalCase } from 'change-case-all'; import { ClientSideBaseVisitor, DocumentMode, getConfigValue, } from '@graphql-codegen/visitor-plugin-common'; import { CustomMapperFetcher } from './fetcher-custom-mapper.js'; import { HardcodedFetchFetcher } from './fetcher-fetch-hardcoded.js'; import { FetchFetcher } from './fetcher-fetch.js'; import { GraphQLRequestClientFetcher } from './fetcher-graphql-request.js'; export class ReactQueryVisitor extends ClientSideBaseVisitor { constructor(schema, fragments, rawConfig, documents) { const defaultReactQueryVersion = !rawConfig.reactQueryVersion && rawConfig.legacyMode ? 3 : 4; super(schema, fragments, rawConfig, { documentMode: DocumentMode.string, errorType: getConfigValue(rawConfig.errorType, 'unknown'), exposeDocument: getConfigValue(rawConfig.exposeDocument, false), exposeQueryKeys: getConfigValue(rawConfig.exposeQueryKeys, false), exposeQueryRootKeys: getConfigValue(rawConfig.exposeQueryRootKeys, false), exposeMutationKeys: getConfigValue(rawConfig.exposeMutationKeys, false), exposeFetcher: getConfigValue(rawConfig.exposeFetcher, false), addInfiniteQuery: getConfigValue(rawConfig.addInfiniteQuery, false), addSuspenseQuery: getConfigValue(rawConfig.addSuspenseQuery, false), reactQueryVersion: getConfigValue(rawConfig.reactQueryVersion, defaultReactQueryVersion), reactQueryImportFrom: getConfigValue(rawConfig.reactQueryImportFrom, ''), }); this.rawConfig = rawConfig; this.reactQueryHookIdentifiersInUse = new Set(); this.reactQueryOptionsIdentifiersInUse = new Set(); this._externalImportPrefix = this.config.importOperationTypesFrom ? `${this.config.importOperationTypesFrom}.` : ''; this._documents = documents; this.fetcher = this.createFetcher(rawConfig.fetcher || 'fetch'); autoBind(this); } get imports() { return this._imports; } createFetcher(raw) { if (raw === 'fetch') { return new FetchFetcher(this); } if (typeof raw === 'object' && 'endpoint' in raw) { return new HardcodedFetchFetcher(this, raw); } if (raw === 'graphql-request' || (typeof raw === 'object' && 'clientImportPath' in raw)) { return new GraphQLRequestClientFetcher(this, raw); } return new CustomMapperFetcher(this, raw); } get hasOperations() { return this._collectedOperations.length > 0; } getImports() { const baseImports = super.getImports(); if (!this.hasOperations) { return baseImports; } const hookAndTypeImports = [ ...Array.from(this.reactQueryHookIdentifiersInUse), ...Array.from(this.reactQueryOptionsIdentifiersInUse).map(identifier => `${this.config.useTypeImports ? 'type ' : ''}${identifier}`), ]; const moduleName = this.config.reactQueryImportFrom ? this.config.reactQueryImportFrom : this.config.reactQueryVersion <= 3 ? 'react-query' : '@tanstack/react-query'; return [...baseImports, `import { ${hookAndTypeImports.join(', ')} } from '${moduleName}';`]; } getFetcherImplementation() { return this.fetcher.generateFetcherImplementation(); } _getHookSuffix(name, operationType) { if (this.config.omitOperationSuffix) { return ''; } if (!this.config.dedupeOperationSuffix) { return pascalCase(operationType); } if (name.includes('Query') || name.includes('Mutation') || name.includes('Subscription')) { return ''; } return pascalCase(operationType); } buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes, hasRequiredVariables) { var _a, _b; const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ''; const suffix = this._getHookSuffix(nodeName, operationType); const operationName = this.convertName(nodeName, { suffix, useTypesPrefix: false, useTypesSuffix: false, }); const generateConfig = { node, documentVariableName, operationResultType: this._externalImportPrefix + operationResultType, operationVariablesTypes: this._externalImportPrefix + operationVariablesTypes, hasRequiredVariables, operationName, }; const queries = []; const getOutputFromQueries = () => `\n${queries.join('\n\n')}\n`; if (operationType === 'Query') { const addQuery = (generateConfig, isSuspense = false) => { const { hook, getKey, rootKey, document } = this.fetcher.generateQueryOutput(generateConfig, isSuspense); queries.push(hook); if (this.config.exposeDocument) queries.push(document); if (this.config.exposeQueryKeys) queries.push(getKey); if (this.config.exposeQueryRootKeys) queries.push(rootKey); }; addQuery(generateConfig); if (this.config.addSuspenseQuery) addQuery(generateConfig, true); if (this.config.addInfiniteQuery) { const addInfiniteQuery = (generateConfig, isSuspense = false) => { const { hook, getKey, rootKey } = this.fetcher.generateInfiniteQueryOutput(generateConfig, isSuspense); queries.push(hook); if (this.config.exposeQueryKeys) queries.push(getKey); if (this.config.exposeQueryRootKeys) queries.push(rootKey); }; addInfiniteQuery(generateConfig); if (this.config.addSuspenseQuery) { addInfiniteQuery(generateConfig, true); } } // The reason we're looking at the private field of the CustomMapperFetcher to see if it's a react hook // is to prevent calling generateFetcherFetch for each query since all the queries won't be able to generate // a fetcher field anyways. if (this.config.exposeFetcher && !this.fetcher._isReactHook) { queries.push(this.fetcher.generateFetcherFetch(generateConfig)); } return getOutputFromQueries(); } if (operationType === 'Mutation') { const { hook, getKey } = this.fetcher.generateMutationOutput(generateConfig); queries.push(hook); if (this.config.exposeMutationKeys) queries.push(getKey); if (this.config.exposeFetcher && !this.fetcher._isReactHook) { queries.push(this.fetcher.generateFetcherFetch(generateConfig)); } return getOutputFromQueries(); } if (operationType === 'Subscription') { // eslint-disable-next-line no-console console.warn(`Plugin "typescript-react-query" does not support GraphQL Subscriptions at the moment! Ignoring "${node.name.value}"...`); } return null; } }