UNPKG

20.6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.ReactApolloVisitor = void 0;
4const tslib_1 = require("tslib");
5const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
6const auto_bind_1 = tslib_1.__importDefault(require("auto-bind"));
7const graphql_1 = require("graphql");
8const change_case_all_1 = require("change-case-all");
9const APOLLO_CLIENT_3_UNIFIED_PACKAGE = `@apollo/client`;
10const GROUPED_APOLLO_CLIENT_3_IDENTIFIER = 'Apollo';
11function hasRequiredVariables(node) {
12 var _a, _b;
13 return ((_b = (_a = node.variableDefinitions) === null || _a === void 0 ? void 0 : _a.some(variableDef => variableDef.type.kind === graphql_1.Kind.NON_NULL_TYPE && !variableDef.defaultValue)) !== null && _b !== void 0 ? _b : false);
14}
15class ReactApolloVisitor extends visitor_plugin_common_1.ClientSideBaseVisitor {
16 constructor(schema, fragments, rawConfig, documents) {
17 super(schema, fragments, rawConfig, {
18 componentSuffix: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.componentSuffix, 'Component'),
19 withHOC: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withHOC, false),
20 withComponent: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withComponent, false),
21 withHooks: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withHooks, true),
22 withMutationFn: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withMutationFn, true),
23 withRefetchFn: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withRefetchFn, false),
24 apolloReactCommonImportFrom: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.apolloReactCommonImportFrom, rawConfig.reactApolloVersion === 2 ? '@apollo/react-common' : APOLLO_CLIENT_3_UNIFIED_PACKAGE),
25 apolloReactComponentsImportFrom: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.apolloReactComponentsImportFrom, rawConfig.reactApolloVersion === 2
26 ? '@apollo/react-components'
27 : `${APOLLO_CLIENT_3_UNIFIED_PACKAGE}/react/components`),
28 apolloReactHocImportFrom: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.apolloReactHocImportFrom, rawConfig.reactApolloVersion === 2 ? '@apollo/react-hoc' : `${APOLLO_CLIENT_3_UNIFIED_PACKAGE}/react/hoc`),
29 apolloReactHooksImportFrom: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.apolloReactHooksImportFrom, rawConfig.reactApolloVersion === 2 ? '@apollo/react-hooks' : APOLLO_CLIENT_3_UNIFIED_PACKAGE),
30 reactApolloVersion: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.reactApolloVersion, 3),
31 withResultType: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withResultType, true),
32 withMutationOptionsType: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.withMutationOptionsType, true),
33 addDocBlocks: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.addDocBlocks, true),
34 defaultBaseOptions: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.defaultBaseOptions, {}),
35 gqlImport: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.gqlImport, rawConfig.reactApolloVersion === 2 ? null : `${APOLLO_CLIENT_3_UNIFIED_PACKAGE}#gql`),
36 hooksSuffix: (0, visitor_plugin_common_1.getConfigValue)(rawConfig.hooksSuffix, ''),
37 });
38 this.rawConfig = rawConfig;
39 this.imports = new Set();
40 this._externalImportPrefix = this.config.importOperationTypesFrom ? `${this.config.importOperationTypesFrom}.` : '';
41 this._documents = documents;
42 (0, auto_bind_1.default)(this);
43 }
44 getImportStatement(isTypeImport) {
45 return isTypeImport && this.config.useTypeImports ? 'import type' : 'import';
46 }
47 getReactImport() {
48 return `import * as React from 'react';`;
49 }
50 getApolloReactCommonIdentifier() {
51 if (this.rawConfig.apolloReactCommonImportFrom || this.config.reactApolloVersion === 2) {
52 return `ApolloReactCommon`;
53 }
54 return GROUPED_APOLLO_CLIENT_3_IDENTIFIER;
55 }
56 getApolloReactHooksIdentifier() {
57 if (this.rawConfig.apolloReactHooksImportFrom || this.config.reactApolloVersion === 2) {
58 return `ApolloReactHooks`;
59 }
60 return GROUPED_APOLLO_CLIENT_3_IDENTIFIER;
61 }
62 usesExternalHooksOnly() {
63 const apolloReactCommonIdentifier = this.getApolloReactCommonIdentifier();
64 return (apolloReactCommonIdentifier === GROUPED_APOLLO_CLIENT_3_IDENTIFIER &&
65 this.config.apolloReactHooksImportFrom !== APOLLO_CLIENT_3_UNIFIED_PACKAGE &&
66 this.config.withHooks &&
67 !this.config.withComponent &&
68 !this.config.withHOC);
69 }
70 getApolloReactCommonImport(isTypeImport) {
71 const apolloReactCommonIdentifier = this.getApolloReactCommonIdentifier();
72 return `${this.getImportStatement(isTypeImport &&
73 (apolloReactCommonIdentifier !== GROUPED_APOLLO_CLIENT_3_IDENTIFIER || this.usesExternalHooksOnly()))} * as ${apolloReactCommonIdentifier} from '${this.config.apolloReactCommonImportFrom}';`;
74 }
75 getApolloReactComponentsImport(isTypeImport) {
76 return `${this.getImportStatement(isTypeImport)} * as ApolloReactComponents from '${this.config.apolloReactComponentsImportFrom}';`;
77 }
78 getApolloReactHocImport(isTypeImport) {
79 return `${this.getImportStatement(isTypeImport)} * as ApolloReactHoc from '${this.config.apolloReactHocImportFrom}';`;
80 }
81 getApolloReactHooksImport(isTypeImport) {
82 return `${this.getImportStatement(isTypeImport)} * as ${this.getApolloReactHooksIdentifier()} from '${this.config.apolloReactHooksImportFrom}';`;
83 }
84 getOmitDeclaration() {
85 return visitor_plugin_common_1.OMIT_TYPE;
86 }
87 getDefaultOptions() {
88 return `const defaultOptions = ${JSON.stringify(this.config.defaultBaseOptions)} as const;`;
89 }
90 getDocumentNodeVariable(node, documentVariableName) {
91 var _a, _b;
92 return this.config.documentMode === visitor_plugin_common_1.DocumentMode.external
93 ? `Operations.${(_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ''}`
94 : documentVariableName;
95 }
96 getImports() {
97 const baseImports = super.getImports();
98 const hasOperations = this._collectedOperations.length > 0;
99 if (!hasOperations) {
100 return baseImports;
101 }
102 return [...baseImports, ...Array.from(this.imports)];
103 }
104 _buildHocProps(operationName, operationType) {
105 const typeVariableName = this._externalImportPrefix +
106 this.convertName(operationName + (0, change_case_all_1.pascalCase)(operationType) + this._parsedConfig.operationResultSuffix);
107 const variablesVarName = this._externalImportPrefix + this.convertName(operationName + (0, change_case_all_1.pascalCase)(operationType) + 'Variables');
108 const typeArgs = `<${typeVariableName}, ${variablesVarName}>`;
109 if (operationType === 'mutation') {
110 this.imports.add(this.getApolloReactCommonImport(true));
111 return `${this.getApolloReactCommonIdentifier()}.MutationFunction${typeArgs}`;
112 }
113 this.imports.add(this.getApolloReactHocImport(true));
114 return `ApolloReactHoc.DataValue${typeArgs}`;
115 }
116 _buildMutationFn(node, operationResultType, operationVariablesTypes) {
117 var _a, _b;
118 if (node.operation === 'mutation') {
119 this.imports.add(this.getApolloReactCommonImport(true));
120 return `export type ${this.convertName(((_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '') + 'MutationFn')} = ${this.getApolloReactCommonIdentifier()}.MutationFunction<${operationResultType}, ${operationVariablesTypes}>;`;
121 }
122 return null;
123 }
124 _buildOperationHoc(node, documentVariableName, operationResultType, operationVariablesTypes) {
125 var _a, _b;
126 this.imports.add(this.getApolloReactCommonImport(false));
127 this.imports.add(this.getApolloReactHocImport(false));
128 const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
129 const operationName = this.convertName(nodeName, { useTypesPrefix: false });
130 const propsTypeName = this.convertName(nodeName, { suffix: 'Props' });
131 const defaultDataName = node.operation === 'mutation' ? 'mutate' : 'data';
132 const propsVar = `export type ${propsTypeName}<TChildProps = {}, TDataName extends string = '${defaultDataName}'> = {
133 [key in TDataName]: ${this._buildHocProps(nodeName, node.operation)}
134 } & TChildProps;`;
135 const hocString = `export function with${operationName}<TProps, TChildProps = {}, TDataName extends string = '${defaultDataName}'>(operationOptions?: ApolloReactHoc.OperationOption<
136 TProps,
137 ${operationResultType},
138 ${operationVariablesTypes},
139 ${propsTypeName}<TChildProps, TDataName>>) {
140 return ApolloReactHoc.with${(0, change_case_all_1.pascalCase)(node.operation)}<TProps, ${operationResultType}, ${operationVariablesTypes}, ${propsTypeName}<TChildProps, TDataName>>(${this.getDocumentNodeVariable(node, documentVariableName)}, {
141 alias: '${(0, change_case_all_1.camelCase)(operationName)}',
142 ...operationOptions
143 });
144};`;
145 return [propsVar, hocString].filter(a => a).join('\n');
146 }
147 _buildComponent(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) {
148 var _a, _b;
149 const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
150 const componentPropsName = this.convertName(nodeName, {
151 suffix: this.config.componentSuffix + 'Props',
152 useTypesPrefix: false,
153 });
154 const componentName = this.convertName(nodeName, {
155 suffix: this.config.componentSuffix,
156 useTypesPrefix: false,
157 });
158 const isVariablesRequired = operationType === 'Query' && hasRequiredVariables(node);
159 this.imports.add(this.getReactImport());
160 this.imports.add(this.getApolloReactCommonImport(true));
161 this.imports.add(this.getApolloReactComponentsImport(false));
162 this.imports.add(this.getOmitDeclaration());
163 const propsType = `Omit<ApolloReactComponents.${operationType}ComponentOptions<${operationResultType}, ${operationVariablesTypes}>, '${operationType.toLowerCase()}'>`;
164 let componentProps = '';
165 if (isVariablesRequired) {
166 componentProps = `export type ${componentPropsName} = ${propsType} & ({ variables: ${operationVariablesTypes}; skip?: boolean; } | { skip: boolean; });`;
167 }
168 else {
169 componentProps = `export type ${componentPropsName} = ${propsType};`;
170 }
171 const component = `
172 export const ${componentName} = (props: ${componentPropsName}) => (
173 <ApolloReactComponents.${operationType}<${operationResultType}, ${operationVariablesTypes}> ${node.operation}={${this.getDocumentNodeVariable(node, documentVariableName)}} {...props} />
174 );
175 `;
176 return [componentProps, component].join('\n');
177 }
178 _buildHooksJSDoc(node, operationName, operationType) {
179 const variableString = node.variableDefinitions.reduce((acc, item) => {
180 const name = item.variable.name.value;
181 return `${acc}\n * ${name}: // value for '${name}'`;
182 }, '');
183 const queryDescription = `
184 * To run a query within a React component, call \`use${operationName}\` and pass it any options that fit your needs.
185 * When your component renders, \`use${operationName}\` returns an object from Apollo Client that contains loading, error, and data properties
186 * you can use to render your UI.`;
187 const queryExample = `
188 * const { data, loading, error } = use${operationName}({
189 * variables: {${variableString}
190 * },
191 * });`;
192 const mutationDescription = `
193 * To run a mutation, you first call \`use${operationName}\` within a React component and pass it any options that fit your needs.
194 * When your component renders, \`use${operationName}\` returns a tuple that includes:
195 * - A mutate function that you can call at any time to execute the mutation
196 * - An object with fields that represent the current status of the mutation's execution`;
197 const mutationExample = `
198 * const [${(0, change_case_all_1.camelCase)(operationName)}, { data, loading, error }] = use${operationName}({
199 * variables: {${variableString}
200 * },
201 * });`;
202 return `
203/**
204 * __use${operationName}__
205 *${operationType === 'Mutation' ? mutationDescription : queryDescription}
206 *
207 * @param baseOptions options that will be passed into the ${operationType.toLowerCase()}, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#${operationType === 'Mutation' ? 'options-2' : 'options'};
208 *
209 * @example${operationType === 'Mutation' ? mutationExample : queryExample}
210 */`;
211 }
212 _buildHooks(node, operationType, documentVariableName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
213 var _a, _b;
214 const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
215 const suffix = this._getHookSuffix(nodeName, operationType);
216 const operationName = this.convertName(nodeName, {
217 suffix,
218 useTypesPrefix: false,
219 useTypesSuffix: false,
220 }) + this.config.hooksSuffix;
221 this.imports.add(this.getApolloReactCommonImport(true));
222 this.imports.add(this.getApolloReactHooksImport(false));
223 this.imports.add(this.getDefaultOptions());
224 const hookFns = [
225 `export function use${operationName}(baseOptions${hasRequiredVariables && operationType !== 'Mutation' ? '' : '?'}: ${this.getApolloReactHooksIdentifier()}.${operationType}HookOptions<${operationResultType}, ${operationVariablesTypes}>) {
226 const options = {...defaultOptions, ...baseOptions}
227 return ${this.getApolloReactHooksIdentifier()}.use${operationType}<${operationResultType}, ${operationVariablesTypes}>(${this.getDocumentNodeVariable(node, documentVariableName)}, options);
228 }`,
229 ];
230 if (this.config.addDocBlocks) {
231 hookFns.unshift(this._buildHooksJSDoc(node, operationName, operationType));
232 }
233 const hookResults = [`export type ${operationName}HookResult = ReturnType<typeof use${operationName}>;`];
234 if (operationType === 'Query') {
235 const lazyOperationName = this.convertName(nodeName, {
236 suffix: (0, change_case_all_1.pascalCase)('LazyQuery'),
237 useTypesPrefix: false,
238 }) + this.config.hooksSuffix;
239 hookFns.push(`export function use${lazyOperationName}(baseOptions?: ${this.getApolloReactHooksIdentifier()}.LazyQueryHookOptions<${operationResultType}, ${operationVariablesTypes}>) {
240 const options = {...defaultOptions, ...baseOptions}
241 return ${this.getApolloReactHooksIdentifier()}.useLazyQuery<${operationResultType}, ${operationVariablesTypes}>(${this.getDocumentNodeVariable(node, documentVariableName)}, options);
242 }`);
243 hookResults.push(`export type ${lazyOperationName}HookResult = ReturnType<typeof use${lazyOperationName}>;`);
244 }
245 return [...hookFns, ...hookResults].join('\n');
246 }
247 _getHookSuffix(name, operationType) {
248 if (this.config.omitOperationSuffix) {
249 return '';
250 }
251 if (!this.config.dedupeOperationSuffix) {
252 return (0, change_case_all_1.pascalCase)(operationType);
253 }
254 if (name.includes('Query') || name.includes('Mutation') || name.includes('Subscription')) {
255 return '';
256 }
257 return (0, change_case_all_1.pascalCase)(operationType);
258 }
259 _buildResultType(node, operationType, operationResultType, operationVariablesTypes) {
260 var _a, _b;
261 const componentResultType = this.convertName((_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '', {
262 suffix: `${operationType}Result`,
263 useTypesPrefix: false,
264 });
265 switch (node.operation) {
266 case 'query':
267 this.imports.add(this.getApolloReactCommonImport(true));
268 return `export type ${componentResultType} = ${this.getApolloReactCommonIdentifier()}.QueryResult<${operationResultType}, ${operationVariablesTypes}>;`;
269 case 'mutation':
270 this.imports.add(this.getApolloReactCommonImport(true));
271 return `export type ${componentResultType} = ${this.getApolloReactCommonIdentifier()}.MutationResult<${operationResultType}>;`;
272 case 'subscription':
273 this.imports.add(this.getApolloReactCommonImport(true));
274 return `export type ${componentResultType} = ${this.getApolloReactCommonIdentifier()}.SubscriptionResult<${operationResultType}>;`;
275 default:
276 return '';
277 }
278 }
279 _buildWithMutationOptionsType(node, operationResultType, operationVariablesTypes) {
280 var _a, _b;
281 if (node.operation !== 'mutation') {
282 return '';
283 }
284 this.imports.add(this.getApolloReactCommonImport(true));
285 const mutationOptionsType = this.convertName((_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '', {
286 suffix: 'MutationOptions',
287 useTypesPrefix: false,
288 });
289 return `export type ${mutationOptionsType} = ${this.getApolloReactCommonIdentifier()}.BaseMutationOptions<${operationResultType}, ${operationVariablesTypes}>;`;
290 }
291 _buildRefetchFn(node, documentVariableName, operationType, operationVariablesTypes) {
292 var _a, _b;
293 if (node.operation !== 'query') {
294 return '';
295 }
296 const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
297 const operationName = this.convertName(nodeName, {
298 suffix: this._getHookSuffix(nodeName, operationType),
299 useTypesPrefix: false,
300 }) + this.config.hooksSuffix;
301 const optional = hasRequiredVariables(node) ? '' : '?';
302 return `export function refetch${operationName}(variables${optional}: ${operationVariablesTypes}) {
303 return { query: ${this.getDocumentNodeVariable(node, documentVariableName)}, variables: variables }
304 }`;
305 }
306 buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes, hasRequiredVariables) {
307 operationResultType = this._externalImportPrefix + operationResultType;
308 operationVariablesTypes = this._externalImportPrefix + operationVariablesTypes;
309 const mutationFn = this.config.withMutationFn || this.config.withComponent
310 ? this._buildMutationFn(node, operationResultType, operationVariablesTypes)
311 : null;
312 const component = this.config.withComponent
313 ? this._buildComponent(node, documentVariableName, operationType, operationResultType, operationVariablesTypes)
314 : null;
315 const hoc = this.config.withHOC
316 ? this._buildOperationHoc(node, documentVariableName, operationResultType, operationVariablesTypes)
317 : null;
318 const hooks = this.config.withHooks
319 ? this._buildHooks(node, operationType, documentVariableName, operationResultType, operationVariablesTypes, hasRequiredVariables)
320 : null;
321 const resultType = this.config.withResultType
322 ? this._buildResultType(node, operationType, operationResultType, operationVariablesTypes)
323 : null;
324 const mutationOptionsType = this.config.withMutationOptionsType
325 ? this._buildWithMutationOptionsType(node, operationResultType, operationVariablesTypes)
326 : null;
327 const refetchFn = this.config.withRefetchFn
328 ? this._buildRefetchFn(node, documentVariableName, operationType, operationVariablesTypes)
329 : null;
330 return [mutationFn, component, hoc, hooks, resultType, mutationOptionsType, refetchFn].filter(a => a).join('\n');
331 }
332}
333exports.ReactApolloVisitor = ReactApolloVisitor;