1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.ReactApolloVisitor = void 0;
|
4 | const tslib_1 = require("tslib");
|
5 | const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
|
6 | const auto_bind_1 = tslib_1.__importDefault(require("auto-bind"));
|
7 | const graphql_1 = require("graphql");
|
8 | const change_case_all_1 = require("change-case-all");
|
9 | const APOLLO_CLIENT_3_UNIFIED_PACKAGE = `@apollo/client`;
|
10 | const GROUPED_APOLLO_CLIENT_3_IDENTIFIER = 'Apollo';
|
11 | function 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 | }
|
15 | class 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 | }
|
333 | exports.ReactApolloVisitor = ReactApolloVisitor;
|