UNPKG

@pqstudio/protobuf_ts_plugin

Version:

The protocol buffer compiler plugin "protobuf-ts" generates TypeScript, gRPC-web, Twirp, and more.

234 lines (233 loc) 16.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProtobuftsPlugin = void 0; const protobuf_ts_framework_1 = require("@pqstudio/protobuf_ts_framework"); const out_file_1 = require("./out-file"); const local_type_name_1 = require("./code-gen/local-type-name"); const rt = require("@protobuf-ts/runtime"); const interpreter_1 = require("./interpreter"); const our_options_1 = require("./our-options"); const service_server_generator_grpc_1 = require("./code-gen/service-server-generator-grpc"); const comment_generator_1 = require("./code-gen/comment-generator"); const message_interface_generator_1 = require("./code-gen/message-interface-generator"); const message_type_generator_1 = require("./code-gen/message-type-generator"); const enum_generator_1 = require("./code-gen/enum-generator"); const service_type_generator_1 = require("./code-gen/service-type-generator"); const service_client_generator_call_1 = require("./code-gen/service-client-generator-call"); const service_client_generator_promise_1 = require("./code-gen/service-client-generator-promise"); const service_client_generator_rxjs_1 = require("./code-gen/service-client-generator-rxjs"); const file_table_1 = require("./file-table"); const service_server_generator_generic_1 = require("./code-gen/service-server-generator-generic"); class ProtobuftsPlugin extends protobuf_ts_framework_1.PluginBase { constructor(version, type) { super(); this.version = version; this.type = type; this.parameters = { // @formatter:off // long type long_type_string: { description: "Sets jstype = JS_STRING for message fields with 64 bit integral values. \n" + "The default behaviour is to use native `bigint`. \n" + "Only applies to fields that do *not* use the option `jstype`.", excludes: ["long_type_number", "long_type_bigint"], }, long_type_number: { description: "Sets jstype = JS_NUMBER for message fields with 64 bit integral values. \n" + "The default behaviour is to use native `bigint`. \n" + "Only applies to fields that do *not* use the option `jstype`.", excludes: ["long_type_string", "long_type_bigint"], }, long_type_bigint: { description: "Sets jstype = JS_NORMAL for message fields with 64 bit integral values. \n" + "This is the default behavior. \n" + "Only applies to fields that do *not* use the option `jstype`.", excludes: ["long_type_string", "long_type_number"], }, // misc generate_dependencies: { description: "By default, only the PROTO_FILES passed as input to protoc are generated, \n" + "not the files they import. Set this option to generate code for dependencies \n" + "too.", }, // client client_none: { description: "Do not generate rpc clients. \n" + "Only applies to services that do *not* use the option `ts.client`. \n" + "If you do not want rpc clients at all, use `force_client_none`.", excludes: ['client_call', 'client_promise', 'client_rx'], }, client_call: { description: "Use *Call return types for rpc clients. \n" + "Only applies to services that do *not* use the option `ts.client`. \n" + "Since CALL is the default, this option has no effect.", excludes: ['client_none', 'client_promise', 'client_rx', 'force_client_none'], }, client_promise: { description: "Use Promise return types for rpc clients. \n" + "Only applies to services that do *not* use the option `ts.client`.", excludes: ['client_none', 'client_call', 'client_rx', 'force_client_none'], }, client_rx: { description: "Use Observable return types from the `rxjs` package for rpc clients. \n" + "Only applies to services that do *not* use the option `ts.client`.", excludes: ['client_none', 'client_call', 'client_promise', 'force_client_none'], }, force_client_none: { description: "Do not generate rpc clients, ignore options in proto files.", }, enable_angular_annotations: { description: "If set, the generated rpc client will have an angular @Injectable() \n" + "annotation and the `RpcTransport` constructor argument is annotated with a \n" + "@Inject annotation. For this feature, you will need the npm package \n" + "'@protobuf-ts/runtime-angular'.", excludes: ['force_client_none'], }, // server server_none: { description: "Do not generate rpc servers. \n" + "This is the default behaviour, but only applies to services that do \n" + "*not* use the option `ts.server`. \n" + "If you do not want servers at all, use `force_server_none`.", excludes: ['server_grpc'], }, server_generic: { description: "Generate a generic server interface. Adapters be used to serve the service, \n" + "for example @protobuf-ts/grpc-backend for gRPC. \n" + "Only applies to services that do *not* use the option `ts.server`.", excludes: ['server_none', 'force_server_none'], }, server_grpc: { description: "Generate a server interface and definition for use with @grpc/grpc-js. \n" + "Only applies to services that do *not* use the option `ts.server`.", excludes: ['server_none', 'force_server_none'], }, force_server_none: { description: "Do not generate rpc servers, ignore options in proto files.", }, // optimization optimize_speed: { description: "Sets optimize_for = SPEED for proto files that have no file option \n" + "'option optimize_for'. Since SPEED is the default, this option has no effect.", excludes: ['force_optimize_speed'], }, optimize_code_size: { description: "Sets optimize_for = CODE_SIZE for proto files that have no file option \n" + "'option optimize_for'.", excludes: ['force_optimize_speed'], }, force_optimize_code_size: { description: "Forces optimize_for = CODE_SIZE for all proto files, ignore file options.", excludes: ['optimize_code_size', 'force_optimize_speed'] }, force_optimize_speed: { description: "Forces optimize_for = SPEED for all proto files, ignore file options.", excludes: ['optimize_code_size', 'force_optimize_code_size'] }, }; // we support proto3-optionals, so we let protoc know this.getSupportedFeatures = () => [protobuf_ts_framework_1.CodeGeneratorResponse_Feature.PROTO3_OPTIONAL]; this.version = version; } generate(request) { const params = this.parseParameters(this.parameters, request.parameter), options = our_options_1.makeInternalOptions({ pluginCredit: `by protobuf-ts ${this.version}` + (request.parameter ? ` with parameters ${request.parameter}` : ''), emitAngularAnnotations: params.enable_angular_annotations, normalLongType: params.long_type_string ? rt.LongType.STRING : params.long_type_number ? rt.LongType.NUMBER : rt.LongType.BIGINT, }); if (this.type == "client") { options.runtimeImportPath = "../protobuf/index"; } const registry = protobuf_ts_framework_1.DescriptorRegistry.createFrom(request), symbols = new protobuf_ts_framework_1.SymbolTable(), fileTable = new file_table_1.FileTable(), imports = new protobuf_ts_framework_1.TypeScriptImports(symbols, this.type), comments = new comment_generator_1.CommentGenerator(registry), interpreter = new interpreter_1.Interpreter(registry, options), optionResolver = new our_options_1.OptionResolver(interpreter, registry, params), genMessageInterface = new message_interface_generator_1.MessageInterfaceGenerator(symbols, registry, imports, comments, interpreter, options), genEnum = new enum_generator_1.EnumGenerator(symbols, registry, imports, comments, interpreter, options), genMessageType = new message_type_generator_1.MessageTypeGenerator(symbols, registry, imports, comments, interpreter, options), genServiceType = new service_type_generator_1.ServiceTypeGenerator(symbols, registry, imports, comments, interpreter, options), genServerGeneric = new service_server_generator_generic_1.ServiceServerGeneratorGeneric(symbols, registry, imports, comments, interpreter, options), genServerGrpc = new service_server_generator_grpc_1.ServiceServerGeneratorGrpc(symbols, registry, imports, comments, interpreter, options), genClientCall = new service_client_generator_call_1.ServiceClientGeneratorCall(symbols, registry, imports, comments, interpreter, options), genClientPromise = new service_client_generator_promise_1.ServiceClientGeneratorPromise(symbols, registry, imports, comments, interpreter, options), genClientRx = new service_client_generator_rxjs_1.ServiceClientGeneratorRxjs(symbols, registry, imports, comments, interpreter, options); let outFiles = []; // ensure unique file names for (let fileDescriptor of registry.allFiles()) { const base = fileDescriptor.name.replace('.proto', ''); fileTable.register(base + '.ts', fileDescriptor); } for (let fileDescriptor of registry.allFiles()) { const base = fileDescriptor.name.replace('.proto', ''); fileTable.register(base + '.server.ts', fileDescriptor, 'generic-server'); fileTable.register(base + '.grpc-server.ts', fileDescriptor, 'grpc-server'); fileTable.register(base + '.client.ts', fileDescriptor, 'client'); fileTable.register(base + '.rx-client.ts', fileDescriptor, 'rx-client'); fileTable.register(base + '.promise-client.ts', fileDescriptor, 'promise-client'); } for (let fileDescriptor of registry.allFiles()) { const outMain = new out_file_1.OutFile(fileTable.get(fileDescriptor).name, fileDescriptor, registry, options, this.type), outServerGeneric = new out_file_1.OutFile(fileTable.get(fileDescriptor, 'generic-server').name, fileDescriptor, registry, options, this.type), outServerGrpc = new out_file_1.OutFile(fileTable.get(fileDescriptor, 'grpc-server').name, fileDescriptor, registry, options, this.type), outClientCall = new out_file_1.OutFile(fileTable.get(fileDescriptor, 'client').name, fileDescriptor, registry, options, this.type), outClientRx = new out_file_1.OutFile(fileTable.get(fileDescriptor, 'rx-client').name, fileDescriptor, registry, options, this.type), outClientPromise = new out_file_1.OutFile(fileTable.get(fileDescriptor, 'promise-client').name, fileDescriptor, registry, options, this.type); outFiles.push(outMain, outServerGeneric, outServerGrpc, outClientCall, outClientRx, outClientPromise); registry.visitTypes(fileDescriptor, descriptor => { // we are not interested in synthetic types like map entry messages if (registry.isSyntheticElement(descriptor)) return; // register all symbols, regardless whether they are going to be used - we want stable behaviour symbols.register(local_type_name_1.createLocalTypeName(descriptor, registry), descriptor, outMain); if (protobuf_ts_framework_1.ServiceDescriptorProto.is(descriptor)) { genClientCall.registerSymbols(outClientCall, descriptor); genClientRx.registerSymbols(outClientRx, descriptor); genClientPromise.registerSymbols(outClientPromise, descriptor); genServerGeneric.registerSymbols(outServerGeneric, descriptor); genServerGrpc.registerSymbols(outServerGrpc, descriptor); } }); registry.visitTypes(fileDescriptor, descriptor => { // we are not interested in synthetic types like map entry messages if (registry.isSyntheticElement(descriptor)) return; if (protobuf_ts_framework_1.DescriptorProto.is(descriptor)) { genMessageInterface.generateMessageInterface(outMain, descriptor); } if (protobuf_ts_framework_1.EnumDescriptorProto.is(descriptor)) { genEnum.generateEnum(outMain, descriptor); } }); registry.visitTypes(fileDescriptor, descriptor => { // still not interested in synthetic types like map entry messages if (registry.isSyntheticElement(descriptor)) return; if (protobuf_ts_framework_1.DescriptorProto.is(descriptor)) { genMessageType.generateMessageType(outMain, descriptor, optionResolver.getOptimizeMode(fileDescriptor)); } if (protobuf_ts_framework_1.ServiceDescriptorProto.is(descriptor)) { // service type genServiceType.generateServiceType(outMain, descriptor); // clients const clientStyles = optionResolver.getClientStyles(descriptor); if (clientStyles.includes(our_options_1.ClientStyle.CALL_CLIENT)) { genClientCall.generateInterface(outClientCall, descriptor); genClientCall.generateImplementationClass(outClientCall, descriptor); } if (clientStyles.includes(our_options_1.ClientStyle.RX_CLIENT)) { genClientRx.generateInterface(outClientRx, descriptor); genClientRx.generateImplementationClass(outClientRx, descriptor); } if (clientStyles.includes(our_options_1.ClientStyle.PROMISE_CLIENT)) { genClientPromise.generateInterface(outClientPromise, descriptor); genClientPromise.generateImplementationClass(outClientPromise, descriptor); } // grpc server const serverStyles = optionResolver.getServerStyles(descriptor); if (serverStyles.includes(our_options_1.ServerStyle.GENERIC_SERVER)) { genServerGeneric.generateInterface(outServerGeneric, descriptor); } if (serverStyles.includes(our_options_1.ServerStyle.GRPC_SERVER)) { genServerGrpc.generateInterface(outServerGrpc, descriptor); genServerGrpc.generateDefinition(outServerGrpc, descriptor); } } }); } // plugins should only return files requested to generate // unless our option "generate_dependencies" is set if (!params.generate_dependencies) { outFiles = outFiles.filter(file => request.fileToGenerate.includes(file.fileDescriptor.name)); } // if a proto file is imported to use custom options, or if a proto file declares custom options, // we do not to emit it. unless it was explicitly requested. const outFileDescriptors = outFiles.map(of => of.fileDescriptor); outFiles = outFiles.filter(of => request.fileToGenerate.includes(of.fileDescriptor.name) || registry.isFileUsed(of.fileDescriptor, outFileDescriptors)); return outFiles; } } exports.ProtobuftsPlugin = ProtobuftsPlugin;