UNPKG

4.66 kBJavaScriptView Raw
1import { concatAST, Kind, visit } from 'graphql';
2import { ClientSideBaseVisitor, DocumentMode } from '@graphql-codegen/visitor-plugin-common';
3import autoBind from 'auto-bind';
4import { pascalCase } from 'change-case-all';
5import { extname } from 'path';
6
7class ReactApolloVisitor extends ClientSideBaseVisitor {
8 constructor(schema, fragments, rawConfig, documents) {
9 super(schema, fragments, rawConfig, {});
10 this.imports = new Set();
11 this._externalImportPrefix = this.config.importOperationTypesFrom ? `${this.config.importOperationTypesFrom}.` : '';
12 this._documents = documents;
13 autoBind(this);
14 }
15 getOffixReactHooksImport() {
16 return `import * as OffixReactHooks from "react-offix-hooks";`;
17 }
18 getDocumentNodeVariable(node, documentVariableName) {
19 return this.config.documentMode === DocumentMode.external ? `Operations.${node.name.value}` : documentVariableName;
20 }
21 getImports() {
22 const baseImports = super.getImports({ excludeFragments: true });
23 const hasOperations = this._collectedOperations.length > 0;
24 if (!hasOperations) {
25 return baseImports;
26 }
27 return [...baseImports, ...Array.from(this.imports)];
28 }
29 _buildHooks(node, operationType, documentVariableName, operationResultType, operationVariablesTypes) {
30 var _a, _b;
31 const operationName = this.convertName((_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '', {
32 useTypesPrefix: false,
33 });
34 this.imports.add(this.getOffixReactHooksImport());
35 const hookFns = [];
36 if (operationType === 'Mutation') {
37 hookFns.push(`export function useOffline${operationName}(baseOptions?: OffixReactHooks.${operationType}HookOptions<${operationResultType}, ${operationVariablesTypes}>) {
38 return OffixReactHooks.useOfflineMutation<${operationResultType}, ${operationVariablesTypes}>(${this.getDocumentNodeVariable(node, documentVariableName)}, baseOptions);
39}`);
40 }
41 return [...hookFns].join('\n');
42 }
43 buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) {
44 operationResultType = this._externalImportPrefix + operationResultType;
45 operationVariablesTypes = this._externalImportPrefix + operationVariablesTypes;
46 const hooks = this._buildHooks(node, operationType, documentVariableName, operationResultType, operationVariablesTypes);
47 return [hooks].filter(a => a).join('\n');
48 }
49 OperationDefinition(node) {
50 if (!node.name || !node.name.value) {
51 return null;
52 }
53 this._collectedOperations.push(node);
54 const documentVariableName = this.convertName(node, {
55 suffix: this.config.documentVariableSuffix,
56 prefix: this.config.documentVariablePrefix,
57 useTypesPrefix: false,
58 });
59 const operationType = pascalCase(node.operation);
60 const operationTypeSuffix = this.getOperationSuffix(node, operationType);
61 const operationResultType = this.convertName(node, {
62 suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix,
63 });
64 const operationVariablesTypes = this.convertName(node, {
65 suffix: operationTypeSuffix + 'Variables',
66 });
67 const additional = this.buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes);
68 return [additional].filter(a => a).join('\n');
69 }
70}
71
72const plugin = (schema, documents, config) => {
73 const allAst = concatAST(documents.map(v => v.document));
74 const allFragments = [
75 ...allAst.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION).map(fragmentDef => ({
76 node: fragmentDef,
77 name: fragmentDef.name.value,
78 onType: fragmentDef.typeCondition.name.value,
79 isExternal: false,
80 })),
81 ...(config.externalFragments || []),
82 ];
83 const visitor = new ReactApolloVisitor(schema, allFragments, config, documents);
84 const visitorResult = visit(allAst, { leave: visitor });
85 return {
86 prepend: visitor.getImports(),
87 content: [...visitorResult.definitions.filter(t => typeof t === 'string')].join('\n'),
88 };
89};
90const validate = async (_schema, _documents, _config, outputFile) => {
91 if (extname(outputFile) !== '.tsx' && extname(outputFile) !== '.ts') {
92 throw new Error(`Plugin "react-apollo" requires extension to be ".tsx" or ".ts!`);
93 }
94};
95
96export { ReactApolloVisitor, plugin, validate };