UNPKG

@graphql-codegen/c-sharp-operations

Version:

GraphQL Code Generator plugin for generating ready-to-use Angular Components based on GraphQL operations

265 lines (251 loc) • 10.5 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } const graphql = require('graphql'); const visitorPluginCommon = require('@graphql-codegen/visitor-plugin-common'); const autoBind = _interopDefault(require('auto-bind')); const camelCase = require('camel-case'); const path = require('path'); const gql = _interopDefault(require('graphql-tag')); const R_NAME = /name:\s*"([^"]+)"/; function R_DEF(directive) { return new RegExp(`\\s+\\@${directive}\\([^)]+\\)`, 'gm'); } class CSharpOperationsVisitor extends visitorPluginCommon.ClientSideBaseVisitor { constructor(schema, fragments, rawConfig, documents) { super(schema, fragments, rawConfig, { namedClient: rawConfig.namedClient, serviceName: rawConfig.serviceName, querySuffix: rawConfig.querySuffix, mutationSuffix: rawConfig.mutationSuffix, subscriptionSuffix: rawConfig.subscriptionSuffix, }, documents); this._operationsToInclude = []; autoBind(this); } _operationHasDirective(operation, directive) { if (typeof operation === 'string') { return operation.includes(`${directive}`); } let found = false; graphql.visit(operation, { Directive(node) { if (node.name.value === directive) { found = true; } }, }); return found; } _extractDirective(operation, directive) { const directives = graphql.print(operation).match(R_DEF(directive)); if (directives.length > 1) { throw new Error(`The ${directive} directive used multiple times in '${operation.name}' operation`); } return directives[0]; } _namedClient(operation) { let name; if (this._operationHasDirective(operation, 'namedClient')) { name = this._extractNamedClient(operation); } else if (this.config.namedClient) { name = this.config.namedClient; } return name ? `client = '${name}';` : ''; } _extractNamedClient(operation) { const [, name] = this._extractDirective(operation, 'namedClient').match(R_NAME); return name; } _gql(node) { const fragments = this._transformFragments(node); let doc = this._prepareDocument(` ${graphql.print(node).split('\\').join('\\\\')} ${this._includeFragments(fragments)}`); doc = doc.replace(/"/g, '""'); if (this.config.documentMode === visitorPluginCommon.DocumentMode.string) { return '@"' + doc + '"'; } return '@"' + doc + '"'; } _getDocumentNodeVariable(node, documentVariableName) { return this.config.documentMode === visitorPluginCommon.DocumentMode.external ? `Operations.${node.name.value}` : documentVariableName; } _operationSuffix(operationType) { const defaultSuffix = 'GQL'; switch (operationType) { case 'Query': return this.config.querySuffix || defaultSuffix; case 'Mutation': return this.config.mutationSuffix || defaultSuffix; case 'Subscription': return this.config.subscriptionSuffix || defaultSuffix; default: return defaultSuffix; } } buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) { const serviceName = `${this.convertName(node)}${this._operationSuffix(operationType)}`; this._operationsToInclude.push({ node, documentVariableName, operationType, operationResultType, operationVariablesTypes, serviceName, }); const content = ` public class ${serviceName}{ public static GraphQLRequest get${serviceName}() { return new GraphQLRequest { Query = ${this._getDocumentNodeVariable(node, documentVariableName)}, OperationName = "${this.convertName(node)}" }; } ${this._namedClient(node)} } `; return content; } get sdkClass() { const actionType = operation => { switch (operation) { case 'Mutation': return 'mutate'; case 'Subscription': return 'subscribe'; default: return 'fetch'; } }; const allPossibleActions = this._operationsToInclude .map(o => { const optionalVariables = !o.node.variableDefinitions || o.node.variableDefinitions.length === 0 || o.node.variableDefinitions.every(v => v.type.kind !== graphql.Kind.NON_NULL_TYPE || !!v.defaultValue); const options = o.operationType === 'Mutation' ? `${o.operationType}OptionsAlone<${o.operationResultType}, ${o.operationVariablesTypes}>` : `${o.operationType}OptionsAlone<${o.operationVariablesTypes}>`; const method = ` ${camelCase.camelCase(o.node.name.value)}(variables${optionalVariables ? '?' : ''}: ${o.operationVariablesTypes}, options?: ${options}) { return this.${camelCase.camelCase(o.serviceName)}.${actionType(o.operationType)}(variables, options) }`; let watchMethod; if (o.operationType === 'Query') { watchMethod = ` ${camelCase.camelCase(o.node.name.value)}Watch(variables${optionalVariables ? '?' : ''}: ${o.operationVariablesTypes}, options?: WatchQueryOptionsAlone<${o.operationVariablesTypes}>) { return this.${camelCase.camelCase(o.serviceName)}.watch(variables, options) }`; } return [method, watchMethod].join(''); }) .map(s => visitorPluginCommon.indentMultiline(s, 2)); const injectString = (service) => `private ${camelCase.camelCase(service)}: ${service}`; const injections = this._operationsToInclude .map(op => injectString(op.serviceName)) .map(s => visitorPluginCommon.indentMultiline(s, 3)) .join(',\n'); const serviceName = this.config.serviceName || 'GraphQLSDK'; return ` type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; interface WatchQueryOptionsAlone<V> extends Omit<ApolloCore.WatchQueryOptions<V>, 'query' | 'variables'> {} interface QueryOptionsAlone<V> extends Omit<ApolloCore.QueryOptions<V>, 'query' | 'variables'> {} interface MutationOptionsAlone<T, V> extends Omit<ApolloCore.MutationOptions<T, V>, 'mutation' | 'variables'> {} interface SubscriptionOptionsAlone<V> extends Omit<ApolloCore.SubscriptionOptions<V>, 'query' | 'variables'> {} public class ${serviceName} { constructor( ${injections} ) {} ${allPossibleActions.join('\n')} }`; } OperationDefinition(node) { if (!node.name || !node.name.value) { return null; } this._collectedOperations.push(node); const documentVariableName = this.convertName(node, { suffix: this.config.documentVariableSuffix, prefix: this.config.documentVariablePrefix, useTypesPrefix: false, }); let documentString = ''; if (this.config.documentMode !== visitorPluginCommon.DocumentMode.external) { const isDocumentNode = this.config.documentMode === visitorPluginCommon.DocumentMode.documentNode; documentString = `${this.config.noExport ? '' : 'public'} static string ${documentVariableName}${isDocumentNode ? ': DocumentNode' : ''} = ${this._gql(node)};`; } const operationType = node.operation; const operationTypeSuffix = this.config.dedupeOperationSuffix && node.name.value.toLowerCase().endsWith(node.operation) ? '' : !operationType ? '' : operationType; const operationResultType = this.convertName(node, { suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix, }); const operationVariablesTypes = this.convertName(node, { suffix: operationTypeSuffix + 'Variables', }); const serviceName = `${this.convertName(node)}${this._operationSuffix(operationType)}`; this._operationsToInclude.push({ node, documentVariableName, operationType, operationResultType, operationVariablesTypes, serviceName, }); const content = ` public class ${serviceName}{ public static GraphQLRequest get${serviceName}() { return new GraphQLRequest { Query = ${this._getDocumentNodeVariable(node, documentVariableName)}, OperationName = "${this.convertName(node)}" }; } ${this._namedClient(node)} ${documentString} } `; return [content].filter(a => a).join('\n'); } } const plugin = (schema, documents, config) => { const openNameSpace = 'namespace GraphQLCodeGen {'; const allAst = graphql.concatAST(documents.map(v => v.document)); const allFragments = [ ...allAst.definitions.filter(d => d.kind === graphql.Kind.FRAGMENT_DEFINITION).map(fragmentDef => ({ node: fragmentDef, name: fragmentDef.name.value, onType: fragmentDef.typeCondition.name.value, isExternal: false, })), ...(config.externalFragments || []), ]; const visitor = new CSharpOperationsVisitor(schema, allFragments, config, documents); const visitorResult = graphql.visit(allAst, { leave: visitor }); return { prepend: [], content: [openNameSpace, visitor.fragments, ...visitorResult.definitions.filter(t => typeof t === 'string'), '}'] .filter(a => a) .join('\n'), }; }; const addToSchema = gql ` directive @namedClient(name: String!) on OBJECT | FIELD `; const validate = async (schema, documents, config, outputFile) => { if (path.extname(outputFile) !== '.cs') { throw new Error(`Plugin "c-sharp-operations" requires extension to be ".cs"!`); } }; exports.CSharpOperationsVisitor = CSharpOperationsVisitor; exports.addToSchema = addToSchema; exports.plugin = plugin; exports.validate = validate; //# sourceMappingURL=index.cjs.js.map