UNPKG

ts-proto

Version:

> `ts-proto` transforms your `.proto` files into strongly-typed, idiomatic TypeScript files!

137 lines (136 loc) 8.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateNestjsGrpcServiceMethodsDecorator = exports.generateNestjsServiceClient = exports.generateNestjsServiceController = void 0; const types_1 = require("./types"); const sourceInfo_1 = require("./sourceInfo"); const ts_poet_1 = require("ts-poet"); const utils_1 = require("./utils"); const case_1 = require("./case"); const main_1 = require("./main"); function generateNestjsServiceController(typeMap, fileDesc, sourceInfo, serviceDesc, options) { let service = ts_poet_1.InterfaceSpec.create(`${serviceDesc.name}Controller`).addModifiers(ts_poet_1.Modifier.EXPORT); if (options.useContext) { service = service.addTypeVariable(main_1.contextTypeVar); } utils_1.maybeAddComment(sourceInfo, (text) => (service = service.addJavadoc(text))); serviceDesc.method.forEach((methodDesc, index) => { if (options.lowerCaseServiceMethods) { methodDesc.name = case_1.camelCase(methodDesc.name); } let requestFn = ts_poet_1.FunctionSpec.create(methodDesc.name); if (options.useContext) { requestFn = requestFn.addParameter('ctx', ts_poet_1.TypeNames.typeVariable('Context')); } const info = sourceInfo.lookup(sourceInfo_1.Fields.service.method, index); utils_1.maybeAddComment(info, (text) => (requestFn = requestFn.addJavadoc(text))); requestFn = requestFn.addParameter('request', types_1.requestType(typeMap, methodDesc, options)); // Use metadata as last argument for interface only configuration if (options.addGrpcMetadata) { requestFn = requestFn.addParameter(options.addNestjsRestParameter ? 'metadata' : 'metadata?', 'Metadata@grpc'); } if (options.addNestjsRestParameter) { requestFn = requestFn.addParameter('...rest', 'any'); } // Return observable for interface only configuration, passing returnObservable=true and methodDesc.serverStreaming=true if (types_1.isEmptyType(methodDesc.outputType)) { requestFn = requestFn.returns(ts_poet_1.TypeNames.anyType('void')); } else if (options.returnObservable || methodDesc.serverStreaming) { requestFn = requestFn.returns(types_1.responseObservable(typeMap, methodDesc, options)); } else { // generate nestjs union type requestFn = requestFn.returns(ts_poet_1.TypeNames.unionType(types_1.responsePromise(typeMap, methodDesc, options), types_1.responseObservable(typeMap, methodDesc, options), types_1.responseType(typeMap, methodDesc, options))); } service = service.addFunction(requestFn); if (options.useContext) { const batchMethod = types_1.detectBatchMethod(typeMap, fileDesc, serviceDesc, methodDesc, options); if (batchMethod) { const name = batchMethod.methodDesc.name.replace('Batch', 'Get'); let batchFn = ts_poet_1.FunctionSpec.create(name); if (options.useContext) { batchFn = batchFn.addParameter('ctx', ts_poet_1.TypeNames.typeVariable('Context')); } batchFn = batchFn.addParameter(utils_1.singular(batchMethod.inputFieldName), batchMethod.inputType); batchFn = batchFn.returns(ts_poet_1.TypeNames.PROMISE.param(batchMethod.outputType)); service = service.addFunction(batchFn); } } }); return service; } exports.generateNestjsServiceController = generateNestjsServiceController; function generateNestjsServiceClient(typeMap, fileDesc, sourceInfo, serviceDesc, options) { let service = ts_poet_1.InterfaceSpec.create(`${serviceDesc.name}Client`).addModifiers(ts_poet_1.Modifier.EXPORT); if (options.useContext) { service = service.addTypeVariable(main_1.contextTypeVar); } utils_1.maybeAddComment(sourceInfo, (text) => (service = service.addJavadoc(text))); serviceDesc.method.forEach((methodDesc, index) => { if (options.lowerCaseServiceMethods) { methodDesc.name = case_1.camelCase(methodDesc.name); } let requestFn = ts_poet_1.FunctionSpec.create(methodDesc.name); if (options.useContext) { requestFn = requestFn.addParameter('ctx', ts_poet_1.TypeNames.typeVariable('Context')); } const info = sourceInfo.lookup(sourceInfo_1.Fields.service.method, index); utils_1.maybeAddComment(info, (text) => (requestFn = requestFn.addJavadoc(text))); requestFn = requestFn.addParameter('request', types_1.requestType(typeMap, methodDesc, options)); // Use metadata as last argument for interface only configuration if (options.addGrpcMetadata) { requestFn = requestFn.addParameter(options.addNestjsRestParameter ? 'metadata' : 'metadata?', 'Metadata@grpc'); } if (options.addNestjsRestParameter) { requestFn = requestFn.addParameter('...rest', 'any'); } // Return observable since nestjs client always returns an Observable requestFn = requestFn.returns(types_1.responseObservable(typeMap, methodDesc, options)); service = service.addFunction(requestFn); if (options.useContext) { const batchMethod = types_1.detectBatchMethod(typeMap, fileDesc, serviceDesc, methodDesc, options); if (batchMethod) { const name = batchMethod.methodDesc.name.replace('Batch', 'Get'); let batchFn = ts_poet_1.FunctionSpec.create(name); if (options.useContext) { batchFn = batchFn.addParameter('ctx', ts_poet_1.TypeNames.typeVariable('Context')); } batchFn = batchFn.addParameter(utils_1.singular(batchMethod.inputFieldName), batchMethod.inputType); batchFn = batchFn.returns(ts_poet_1.TypeNames.PROMISE.param(batchMethod.outputType)); service = service.addFunction(batchFn); } } }); return service; } exports.generateNestjsServiceClient = generateNestjsServiceClient; function generateNestjsGrpcServiceMethodsDecorator(serviceDesc, options) { let grpcServiceDecorator = ts_poet_1.FunctionSpec.create(`${serviceDesc.name}ControllerMethods`).addModifiers(ts_poet_1.Modifier.EXPORT); const grpcMethods = serviceDesc.method .filter((m) => !m.clientStreaming) .map((m) => `'${options.lowerCaseServiceMethods ? case_1.camelCase(m.name) : m.name}'`) .join(', '); const grpcStreamMethods = serviceDesc.method .filter((m) => m.clientStreaming) .map((m) => `'${options.lowerCaseServiceMethods ? case_1.camelCase(m.name) : m.name}'`) .join(', '); const grpcMethodType = ts_poet_1.TypeNames.importedType('GrpcMethod@@nestjs/microservices'); const grpcStreamMethodType = ts_poet_1.TypeNames.importedType('GrpcStreamMethod@@nestjs/microservices'); let decoratorFunction = ts_poet_1.FunctionSpec.createCallable().addParameter('constructor', ts_poet_1.TypeNames.typeVariable('Function')); // add loop for applying @GrpcMethod decorators to functions decoratorFunction = generateGrpcMethodDecoratorLoop(decoratorFunction, serviceDesc, 'grpcMethods', grpcMethods, grpcMethodType); // add loop for applying @GrpcStreamMethod decorators to functions decoratorFunction = generateGrpcMethodDecoratorLoop(decoratorFunction, serviceDesc, 'grpcStreamMethods', grpcStreamMethods, grpcStreamMethodType); const body = ts_poet_1.CodeBlock.empty().add('return function %F', decoratorFunction); grpcServiceDecorator = grpcServiceDecorator.addCodeBlock(body); return grpcServiceDecorator; } exports.generateNestjsGrpcServiceMethodsDecorator = generateNestjsGrpcServiceMethodsDecorator; function generateGrpcMethodDecoratorLoop(decoratorFunction, serviceDesc, grpcMethodsName, grpcMethods, grpcType) { return decoratorFunction .addStatement('const %L: string[] = [%L]', grpcMethodsName, grpcMethods) .beginControlFlow('for (const method of %L)', grpcMethodsName) .addStatement(`const %L: any = %L`, 'descriptor', `Reflect.getOwnPropertyDescriptor(constructor.prototype, method)`) .addStatement(`%T('${serviceDesc.name}', method)(constructor.prototype[method], method, descriptor)`, grpcType) .endControlFlow(); }