UNPKG

7.02 kBJavaScriptView Raw
1import { ClientSideBaseVisitor, DocumentMode, getConfigValue, } from '@graphql-codegen/visitor-plugin-common';
2import { generateMutationKeyMaker, generateQueryKeyMaker, generateInfiniteQueryKeyMaker, } from './variables-generator.js';
3import { CustomMapperFetcher } from './fetcher-custom-mapper.js';
4import { FetchFetcher } from './fetcher-fetch.js';
5import { GraphQLRequestClientFetcher } from './fetcher-graphql-request.js';
6import { HardcodedFetchFetcher } from './fetcher-fetch-hardcoded.js';
7import autoBind from 'auto-bind';
8import { pascalCase } from 'change-case-all';
9export class ReactQueryVisitor extends ClientSideBaseVisitor {
10 constructor(schema, fragments, rawConfig, documents) {
11 super(schema, fragments, rawConfig, {
12 documentMode: DocumentMode.string,
13 errorType: getConfigValue(rawConfig.errorType, 'unknown'),
14 exposeDocument: getConfigValue(rawConfig.exposeDocument, false),
15 exposeQueryKeys: getConfigValue(rawConfig.exposeQueryKeys, false),
16 exposeMutationKeys: getConfigValue(rawConfig.exposeMutationKeys, false),
17 exposeFetcher: getConfigValue(rawConfig.exposeFetcher, false),
18 addInfiniteQuery: getConfigValue(rawConfig.addInfiniteQuery, false),
19 legacyMode: getConfigValue(rawConfig.legacyMode, false),
20 });
21 this.rawConfig = rawConfig;
22 this.reactQueryHookIdentifiersInUse = new Set();
23 this.reactQueryOptionsIdentifiersInUse = new Set();
24 this.queryMethodMap = {
25 infiniteQuery: {
26 hook: 'useInfiniteQuery',
27 options: 'UseInfiniteQueryOptions',
28 },
29 query: {
30 hook: 'useQuery',
31 options: 'UseQueryOptions',
32 },
33 mutation: {
34 hook: 'useMutation',
35 options: 'UseMutationOptions',
36 },
37 };
38 this._externalImportPrefix = this.config.importOperationTypesFrom ? `${this.config.importOperationTypesFrom}.` : '';
39 this._documents = documents;
40 this.fetcher = this.createFetcher(rawConfig.fetcher || 'fetch');
41 autoBind(this);
42 }
43 get imports() {
44 return this._imports;
45 }
46 createFetcher(raw) {
47 if (raw === 'fetch') {
48 return new FetchFetcher(this);
49 }
50 if (typeof raw === 'object' && 'endpoint' in raw) {
51 return new HardcodedFetchFetcher(this, raw);
52 }
53 if (raw === 'graphql-request') {
54 return new GraphQLRequestClientFetcher(this);
55 }
56 return new CustomMapperFetcher(this, raw);
57 }
58 get hasOperations() {
59 return this._collectedOperations.length > 0;
60 }
61 getImports() {
62 const baseImports = super.getImports();
63 if (!this.hasOperations) {
64 return baseImports;
65 }
66 const hookAndTypeImports = [
67 ...Array.from(this.reactQueryHookIdentifiersInUse),
68 ...Array.from(this.reactQueryOptionsIdentifiersInUse).map(identifier => `${this.config.useTypeImports ? 'type ' : ''}${identifier}`),
69 ];
70 const moduleName = this.config.legacyMode ? 'react-query' : '@tanstack/react-query';
71 return [...baseImports, `import { ${hookAndTypeImports.join(', ')} } from '${moduleName}';`];
72 }
73 getFetcherImplementation() {
74 return this.fetcher.generateFetcherImplementaion();
75 }
76 _getHookSuffix(name, operationType) {
77 if (this.config.omitOperationSuffix) {
78 return '';
79 }
80 if (!this.config.dedupeOperationSuffix) {
81 return pascalCase(operationType);
82 }
83 if (name.includes('Query') || name.includes('Mutation') || name.includes('Subscription')) {
84 return '';
85 }
86 return pascalCase(operationType);
87 }
88 buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes, hasRequiredVariables) {
89 var _a, _b;
90 const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
91 const suffix = this._getHookSuffix(nodeName, operationType);
92 const operationName = this.convertName(nodeName, {
93 suffix,
94 useTypesPrefix: false,
95 useTypesSuffix: false,
96 });
97 operationResultType = this._externalImportPrefix + operationResultType;
98 operationVariablesTypes = this._externalImportPrefix + operationVariablesTypes;
99 if (operationType === 'Query') {
100 let query = this.fetcher.generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables);
101 if (this.config.exposeDocument) {
102 query += `\nuse${operationName}.document = ${documentVariableName};\n`;
103 }
104 if (this.config.exposeQueryKeys) {
105 query += `\n${generateQueryKeyMaker(node, operationName, operationVariablesTypes, hasRequiredVariables)};\n`;
106 }
107 if (this.config.addInfiniteQuery) {
108 query += `\n${this.fetcher.generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables)}\n`;
109 if (this.config.exposeQueryKeys) {
110 query += `\n${generateInfiniteQueryKeyMaker(node, operationName, operationVariablesTypes, hasRequiredVariables)};\n`;
111 }
112 }
113 // The reason we're looking at the private field of the CustomMapperFetcher to see if it's a react hook
114 // is to prevent calling generateFetcherFetch for each query since all the queries won't be able to generate
115 // a fetcher field anyways.
116 if (this.config.exposeFetcher && !this.fetcher._isReactHook) {
117 query += this.fetcher.generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables);
118 }
119 return query;
120 }
121 if (operationType === 'Mutation') {
122 let query = this.fetcher.generateMutationHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables);
123 if (this.config.exposeMutationKeys) {
124 query += generateMutationKeyMaker(node, operationName);
125 }
126 if (this.config.exposeFetcher && !this.fetcher._isReactHook) {
127 query += this.fetcher.generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables);
128 }
129 return query;
130 }
131 if (operationType === 'Subscription') {
132 // eslint-disable-next-line no-console
133 console.warn(`Plugin "typescript-react-query" does not support GraphQL Subscriptions at the moment! Ignoring "${node.name.value}"...`);
134 }
135 return null;
136 }
137}