UNPKG

ts-proto

Version:

[![npm](https://img.shields.io/npm/v/ts-proto)](https://www.npmjs.com/package/ts-proto) [![build](https://github.com/stephenh/ts-proto/workflows/Build/badge.svg)](https://github.com/stephenh/ts-proto/actions)

204 lines (203 loc) 9.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateGrpcJsService = generateGrpcJsService; const ts_poet_1 = require("ts-poet"); const sourceInfo_1 = require("./sourceInfo"); const types_1 = require("./types"); const utils_1 = require("./utils"); const encode_1 = require("./encode"); const CallOptions = (0, ts_poet_1.imp)("t:CallOptions@@grpc/grpc-js"); const ChannelCredentials = (0, ts_poet_1.imp)("t:ChannelCredentials@@grpc/grpc-js"); const ClientOptions = (0, ts_poet_1.imp)("t:ClientOptions@@grpc/grpc-js"); const Client = (0, ts_poet_1.imp)("Client@@grpc/grpc-js"); const ClientDuplexStream = (0, ts_poet_1.imp)("t:ClientDuplexStream@@grpc/grpc-js"); const ClientReadableStream = (0, ts_poet_1.imp)("t:ClientReadableStream@@grpc/grpc-js"); const ClientUnaryCall = (0, ts_poet_1.imp)("t:ClientUnaryCall@@grpc/grpc-js"); const ClientWritableStream = (0, ts_poet_1.imp)("t:ClientWritableStream@@grpc/grpc-js"); const handleBidiStreamingCall = (0, ts_poet_1.imp)("t:handleBidiStreamingCall@@grpc/grpc-js"); const handleClientStreamingCall = (0, ts_poet_1.imp)("t:handleClientStreamingCall@@grpc/grpc-js"); const handleServerStreamingCall = (0, ts_poet_1.imp)("t:handleServerStreamingCall@@grpc/grpc-js"); const handleUnaryCall = (0, ts_poet_1.imp)("t:handleUnaryCall@@grpc/grpc-js"); const UntypedServiceImplementation = (0, ts_poet_1.imp)("t:UntypedServiceImplementation@@grpc/grpc-js"); const makeGenericClientConstructor = (0, ts_poet_1.imp)("makeGenericClientConstructor@@grpc/grpc-js"); const Metadata = (0, ts_poet_1.imp)("t:Metadata@@grpc/grpc-js"); const ServiceError = (0, ts_poet_1.imp)("t:ServiceError@@grpc/grpc-js"); /** * Generates a service definition and server / client stubs for the * `@grpc/grpc-js` library. */ function generateGrpcJsService(ctx, fileDesc, sourceInfo, serviceDesc) { const { options } = ctx; const chunks = []; chunks.push(generateServiceDefinition(ctx, fileDesc, sourceInfo, serviceDesc)); chunks.push(generateServerStub(ctx, sourceInfo, serviceDesc)); if (options.outputClientImpl) { chunks.push(generateClientStub(ctx, sourceInfo, serviceDesc)); chunks.push(generateClientConstructor(fileDesc, serviceDesc)); } return (0, ts_poet_1.joinCode)(chunks, { on: "\n\n" }); } function generateServiceDefinition(ctx, fileDesc, sourceInfo, serviceDesc) { const chunks = []; (0, utils_1.maybeAddComment)(ctx.options, sourceInfo, chunks, serviceDesc.options?.deprecated); // Service definition type const name = (0, ts_poet_1.def)(`${serviceDesc.name}Service`); chunks.push((0, ts_poet_1.code) ` export type ${name} = typeof ${name}; `); // Service definition chunks.push((0, ts_poet_1.code) ` export const ${name} = { `); for (const [index, methodDesc] of serviceDesc.method.entries()) { (0, utils_1.assertInstanceOf)(methodDesc, utils_1.FormattedMethodDescriptor); const inputType = (0, types_1.messageToTypeName)(ctx, methodDesc.inputType); const outputType = (0, types_1.messageToTypeName)(ctx, methodDesc.outputType); const info = sourceInfo.lookup(sourceInfo_1.Fields.service.method, index); (0, utils_1.maybeAddComment)(ctx.options, info, chunks, methodDesc.options?.deprecated); const inputEncoder = (0, encode_1.generateEncoder)(ctx, methodDesc.inputType); const outputEncoder = (0, encode_1.generateEncoder)(ctx, methodDesc.outputType); const inputDecoder = (0, encode_1.generateDecoder)(ctx, methodDesc.inputType); const outputDecoder = (0, encode_1.generateDecoder)(ctx, methodDesc.outputType); chunks.push((0, ts_poet_1.code) ` ${methodDesc.formattedName}: { path: '/${(0, utils_1.maybePrefixPackage)(fileDesc, serviceDesc.name)}/${methodDesc.name}' as const, requestStream: ${methodDesc.clientStreaming} as const, responseStream: ${methodDesc.serverStreaming} as const, requestSerialize: (value: ${inputType}): Buffer => Buffer.from(${inputEncoder}), requestDeserialize: (value: Buffer): ${inputType} => ${inputDecoder}, responseSerialize: (value: ${outputType}): Buffer => Buffer.from(${outputEncoder}), responseDeserialize: (value: Buffer): ${outputType} => ${outputDecoder}, }, `); } chunks.push((0, ts_poet_1.code) `} as const;`); return (0, ts_poet_1.joinCode)(chunks, { on: "\n" }); } function generateServerStub(ctx, sourceInfo, serviceDesc) { const chunks = []; chunks.push((0, ts_poet_1.code) `export interface ${(0, ts_poet_1.def)(`${serviceDesc.name}Server`)} extends ${UntypedServiceImplementation} {`); for (const [index, methodDesc] of serviceDesc.method.entries()) { (0, utils_1.assertInstanceOf)(methodDesc, utils_1.FormattedMethodDescriptor); const inputType = (0, types_1.messageToTypeName)(ctx, methodDesc.inputType); const outputType = (0, types_1.messageToTypeName)(ctx, methodDesc.outputType); const info = sourceInfo.lookup(sourceInfo_1.Fields.service.method, index); (0, utils_1.maybeAddComment)(ctx.options, info, chunks, methodDesc.options?.deprecated); const callType = methodDesc.clientStreaming ? methodDesc.serverStreaming ? handleBidiStreamingCall : handleClientStreamingCall : methodDesc.serverStreaming ? handleServerStreamingCall : handleUnaryCall; chunks.push((0, ts_poet_1.code) ` ${methodDesc.formattedName}: ${callType}<${inputType}, ${outputType}>; `); } chunks.push((0, ts_poet_1.code) `}`); return (0, ts_poet_1.joinCode)(chunks, { on: "\n" }); } function generateClientStub(ctx, sourceInfo, serviceDesc) { const chunks = []; chunks.push((0, ts_poet_1.code) `export interface ${(0, ts_poet_1.def)(`${serviceDesc.name}Client`)} extends ${Client} {`); for (const [index, methodDesc] of serviceDesc.method.entries()) { (0, utils_1.assertInstanceOf)(methodDesc, utils_1.FormattedMethodDescriptor); const inputType = (0, types_1.messageToTypeName)(ctx, methodDesc.inputType); const outputType = (0, types_1.messageToTypeName)(ctx, methodDesc.outputType); const info = sourceInfo.lookup(sourceInfo_1.Fields.service.method, index); (0, utils_1.maybeAddComment)(ctx.options, info, chunks, methodDesc.options?.deprecated); const responseCallback = (0, ts_poet_1.code) `(error: ${ServiceError} | null, response: ${outputType}) => void`; if (methodDesc.clientStreaming) { if (methodDesc.serverStreaming) { // bidi streaming chunks.push((0, ts_poet_1.code) ` ${methodDesc.formattedName}(): ${ClientDuplexStream}<${inputType}, ${outputType}>; ${methodDesc.formattedName}( options: Partial<${CallOptions}>, ): ${ClientDuplexStream}<${inputType}, ${outputType}>; ${methodDesc.formattedName}( metadata: ${Metadata}, options?: Partial<${CallOptions}>, ): ${ClientDuplexStream}<${inputType}, ${outputType}>; `); } else { // client streaming chunks.push((0, ts_poet_1.code) ` ${methodDesc.formattedName}( callback: ${responseCallback}, ): ${ClientWritableStream}<${inputType}>; ${methodDesc.formattedName}( metadata: ${Metadata}, callback: ${responseCallback}, ): ${ClientWritableStream}<${inputType}>; ${methodDesc.formattedName}( options: Partial<${CallOptions}>, callback: ${responseCallback}, ): ${ClientWritableStream}<${inputType}>; ${methodDesc.formattedName}( metadata: ${Metadata}, options: Partial<${CallOptions}>, callback: ${responseCallback}, ): ${ClientWritableStream}<${inputType}>; `); } } else { if (methodDesc.serverStreaming) { // server streaming chunks.push((0, ts_poet_1.code) ` ${methodDesc.formattedName}( request: ${inputType}, options?: Partial<${CallOptions}>, ): ${ClientReadableStream}<${outputType}>; ${methodDesc.formattedName}( request: ${inputType}, metadata?: ${Metadata}, options?: Partial<${CallOptions}>, ): ${ClientReadableStream}<${outputType}>; `); } else { // unary chunks.push((0, ts_poet_1.code) ` ${methodDesc.formattedName}( request: ${inputType}, callback: ${responseCallback}, ): ${ClientUnaryCall}; ${methodDesc.formattedName}( request: ${inputType}, metadata: ${Metadata}, callback: ${responseCallback}, ): ${ClientUnaryCall}; ${methodDesc.formattedName}( request: ${inputType}, metadata: ${Metadata}, options: Partial<${CallOptions}>, callback: ${responseCallback}, ): ${ClientUnaryCall}; `); } } } chunks.push((0, ts_poet_1.code) `}`); return (0, ts_poet_1.joinCode)(chunks, { on: "\n" }); } function generateClientConstructor(fileDesc, serviceDesc) { return (0, ts_poet_1.code) ` export const ${(0, ts_poet_1.def)(`${serviceDesc.name}Client`)} = ${makeGenericClientConstructor}( ${serviceDesc.name}Service, '${(0, utils_1.maybePrefixPackage)(fileDesc, serviceDesc.name)}' ) as unknown as { new ( address: string, credentials: ${ChannelCredentials}, options?: Partial<${ClientOptions}>, ): ${serviceDesc.name}Client; service: typeof ${serviceDesc.name}Service; serviceName: string; } `; }