@graphql-codegen/typescript-generic-sdk
Version:
GraphQL Code Generator plugin for generating a ready-to-use client-agnostic SDK based on GraphQL operations
100 lines (99 loc) • 4.75 kB
JavaScript
import autoBind from 'auto-bind';
import { Kind, print } from 'graphql';
import { ClientSideBaseVisitor, DocumentMode, getConfigValue, indentMultiline, } from '@graphql-codegen/visitor-plugin-common';
function isStreamOperation(operationAST) {
var _a;
if (operationAST.operation === 'subscription') {
return true;
}
if (operationAST.operation === 'query' &&
((_a = operationAST.directives) === null || _a === void 0 ? void 0 : _a.some(directiveNode => directiveNode.name.value === 'live'))) {
return true;
}
return false;
}
export class GenericSdkVisitor extends ClientSideBaseVisitor {
constructor(schema, fragments, rawConfig) {
super(schema, fragments, rawConfig, {
usingObservableFrom: rawConfig.usingObservableFrom,
rawRequest: getConfigValue(rawConfig.rawRequest, false),
});
this._operationsToInclude = [];
autoBind(this);
if (this.config.usingObservableFrom) {
this._additionalImports.push(this.config.usingObservableFrom);
}
const importType = this.config.useTypeImports ? 'import type' : 'import';
if (this.config.documentMode !== DocumentMode.string) {
this._additionalImports.push(`${importType} { DocumentNode${this.config.rawRequest ? ', ExecutionResult' : ''} } from 'graphql';`);
}
else if (this.config.rawRequest) {
this._additionalImports.push(`${importType} { ExecutionResult } from 'graphql';`);
}
this._externalImportPrefix = this.config.importOperationTypesFrom
? `${this.config.importOperationTypesFrom}.`
: '';
}
buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) {
operationResultType = this._externalImportPrefix + operationResultType;
operationVariablesTypes = this._externalImportPrefix + operationVariablesTypes;
if (node.name == null) {
throw new Error("Plugin 'generic-sdk' cannot generate SDK for unnamed operation.\n\n" + print(node));
}
else {
this._operationsToInclude.push({
node,
documentVariableName,
operationType,
operationResultType,
operationVariablesTypes,
});
}
return null;
}
getDocumentNodeVariable(documentVariableName) {
return this.config.documentMode === DocumentMode.external
? `Operations.${documentVariableName}`
: documentVariableName;
}
get sdkContent() {
const usingObservable = !!this.config.usingObservableFrom;
const allPossibleActions = this._operationsToInclude
.map(o => {
const operationName = o.node.name.value;
const optionalVariables = !o.node.variableDefinitions ||
o.node.variableDefinitions.length === 0 ||
o.node.variableDefinitions.every(v => v.type.kind !== Kind.NON_NULL_TYPE || v.defaultValue);
const docVarName = this.getDocumentNodeVariable(o.documentVariableName);
const returnType = isStreamOperation(o.node)
? usingObservable
? 'Observable'
: 'AsyncIterable'
: 'Promise';
const resultData = this.config.rawRequest
? `ExecutionResult<${o.operationResultType}, E>`
: o.operationResultType;
return `${operationName}(variables${optionalVariables ? '?' : ''}: ${o.operationVariablesTypes}, options?: C): ${returnType}<${resultData}> {
return requester<${o.operationResultType}, ${o.operationVariablesTypes}>(${docVarName}, variables, options) as ${returnType}<${resultData}>;
}`;
})
.map(s => indentMultiline(s, 2));
const documentNodeType = this.config.documentMode === DocumentMode.string ? 'string' : 'DocumentNode';
if (this.config.rawRequest) {
return `export type Requester<C = {}, E = unknown> = <R, V>(doc: ${documentNodeType}, vars?: V, options?: C) => Promise<ExecutionResult<R, E>> | ${usingObservable ? 'Observable' : 'AsyncIterable'}<ExecutionResult<R, E>>
export function getSdk<C, E>(requester: Requester<C, E>) {
return {
${allPossibleActions.join(',\n')}
};
}
export type Sdk = ReturnType<typeof getSdk>;`;
}
return `export type Requester<C = {}> = <R, V>(doc: ${documentNodeType}, vars?: V, options?: C) => Promise<R> | ${usingObservable ? 'Observable' : 'AsyncIterable'}<R>
export function getSdk<C>(requester: Requester<C>) {
return {
${allPossibleActions.join(',\n')}
};
}
export type Sdk = ReturnType<typeof getSdk>;`;
}
}