/
visitor.ts
127 lines (108 loc) · 4.25 KB
/
visitor.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import {
ClientSideBaseVisitor,
ClientSideBasePluginConfig,
LoadedFragment,
getConfigValue,
OMIT_TYPE,
} from '@graphql-codegen/visitor-plugin-common';
import { UrqlRawPluginConfig } from './config';
import autoBind from 'auto-bind';
import { OperationDefinitionNode, Kind, GraphQLSchema } from 'graphql';
import { pascalCase } from 'pascal-case';
export interface UrqlPluginConfig extends ClientSideBasePluginConfig {
withComponent: boolean;
withHooks: boolean;
urqlImportFrom: string;
}
export class UrqlVisitor extends ClientSideBaseVisitor<UrqlRawPluginConfig, UrqlPluginConfig> {
constructor(schema: GraphQLSchema, fragments: LoadedFragment[], rawConfig: UrqlRawPluginConfig) {
super(schema, fragments, rawConfig, {
withComponent: getConfigValue(rawConfig.withComponent, true),
withHooks: getConfigValue(rawConfig.withHooks, false),
urqlImportFrom: getConfigValue(rawConfig.urqlImportFrom, null),
});
autoBind(this);
}
public getImports(): string[] {
const baseImports = super.getImports();
const imports = [];
const hasOperations = this._collectedOperations.length > 0;
if (!hasOperations) {
return baseImports;
}
if (this.config.withComponent) {
imports.push(`import * as React from 'react';`);
}
if (this.config.withComponent || this.config.withHooks) {
imports.push(`import * as Urql from '${this.config.urqlImportFrom || 'urql'}';`);
}
imports.push(OMIT_TYPE);
return [...baseImports, ...imports];
}
private _buildComponent(
node: OperationDefinitionNode,
documentVariableName: string,
operationType: string,
operationResultType: string,
operationVariablesTypes: string
): string {
const componentName: string = this.convertName(node.name.value, { suffix: 'Component', useTypesPrefix: false });
const isVariablesRequired =
operationType === 'Query' &&
node.variableDefinitions.some(variableDef => variableDef.type.kind === Kind.NON_NULL_TYPE);
const generics = [operationResultType, operationVariablesTypes];
if (operationType === 'Subscription') {
generics.unshift(operationResultType);
}
return `
export const ${componentName} = (props: Omit<Urql.${operationType}Props<${generics.join(
', '
)}>, 'query'> & { variables${isVariablesRequired ? '' : '?'}: ${operationVariablesTypes} }) => (
<Urql.${operationType} {...props} query={${documentVariableName}} />
);
`;
}
private _buildHooks(
node: OperationDefinitionNode,
operationType: string,
documentVariableName: string,
operationResultType: string,
operationVariablesTypes: string
): string {
const operationName: string = this.convertName(node.name.value, {
suffix: pascalCase(operationType),
useTypesPrefix: false,
});
if (operationType === 'Mutation') {
return `
export function use${operationName}() {
return Urql.use${operationType}<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName});
};`;
}
if (operationType === 'Subscription') {
return `
export function use${operationName}<TData = any>(options: Omit<Urql.Use${operationType}Args<${operationVariablesTypes}>, 'query'> = {}, handler?: Urql.SubscriptionHandler<${operationName}, TData>) {
return Urql.use${operationType}<${operationResultType}, TData, ${operationVariablesTypes}>({ query: ${documentVariableName}, ...options }, handler);
};`;
}
return `
export function use${operationName}(options: Omit<Urql.Use${operationType}Args<${operationVariablesTypes}>, 'query'> = {}) {
return Urql.use${operationType}<${operationResultType}>({ query: ${documentVariableName}, ...options });
};`;
}
protected buildOperation(
node: OperationDefinitionNode,
documentVariableName: string,
operationType: string,
operationResultType: string,
operationVariablesTypes: string
): string {
const component = this.config.withComponent
? this._buildComponent(node, documentVariableName, operationType, operationResultType, operationVariablesTypes)
: null;
const hooks = this.config.withHooks
? this._buildHooks(node, operationType, documentVariableName, operationResultType, operationVariablesTypes)
: null;
return [component, hooks].filter(a => a).join('\n');
}
}