diff --git a/README.md b/README.md index b7c8a043..18b9b7d4 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,8 @@ ts_proto_library( [JSON mapping]: https://developers.google.com/protocol-buffers/docs/proto3#json +* With `--ts_opt=explicit_override`, inherited methods are generated with `override` modifier, this fixes transpilation error when `noImplicitOverride` is enabled. + ## Support We need your constant support to keep protoc-gen-ts well maintained and add new features. diff --git a/src/descriptor.ts b/src/descriptor.ts index 8bef4406..9b76fbc2 100644 --- a/src/descriptor.ts +++ b/src/descriptor.ts @@ -1965,9 +1965,17 @@ function createDeserializeBinary( messageDescriptor: descriptor.DescriptorProto, parentName: string = '', ): ts.ClassElement { + const modifiers: ts.Modifier[] = [ + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword) + ]; + if (config.explicit_override) { + modifiers.push( + ts.factory.createModifier(ts.SyntaxKind.OverrideKeyword) + ); + } return ts.factory.createMethodDeclaration( undefined, - [ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)], + modifiers, undefined, ts.factory.createIdentifier("deserializeBinary"), undefined, diff --git a/src/option.ts b/src/option.ts index 2f8a8205..62978ed4 100644 --- a/src/option.ts +++ b/src/option.ts @@ -3,6 +3,7 @@ export interface Options { grpc_package: string; no_namespace: boolean; json_names: boolean; + explicit_override: boolean; } export function parse(raw?: string): Options { @@ -14,6 +15,7 @@ export function parse(raw?: string): Options { grpc_package: "@grpc/grpc-js", no_namespace: false, json_names: false, + explicit_override: false, }; for (const raw_option of raw.split(",")) { let [k, v] = raw_option.split("=", 2); @@ -22,6 +24,7 @@ export function parse(raw?: string): Options { case 'grpc_package': options[k] = v; break; case 'no_namespace': options[k] = v != "false"; break; case 'json_names': options[k] = v != "false"; break; + case 'explicit_override': options[k] = v != "false"; break; } } return options; diff --git a/test/_/explicit_override/BUILD.bazel b/test/_/explicit_override/BUILD.bazel new file mode 100644 index 00000000..5c45ba7d --- /dev/null +++ b/test/_/explicit_override/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("//:index.bzl", "ts_proto_library") + + +SRCS = glob(["**/*.proto"]) + +proto_library( + name = "protos", + srcs = SRCS, +) + +ts_proto_library( + name = "explicit_override", + outs = [ + src.replace(".proto", ".ts") + for src in SRCS + ], + features = ["explicit_override"], + deps = [":protos"], + visibility = ["//test/explicit_override:__pkg__"] +) diff --git a/test/_/explicit_override/explicit_override.proto b/test/_/explicit_override/explicit_override.proto new file mode 100644 index 00000000..c5dac82d --- /dev/null +++ b/test/_/explicit_override/explicit_override.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message ExplicitOverrideMessage { + uint32 example = 1; +} diff --git a/test/explicit_override/BUILD.bazel b/test/explicit_override/BUILD.bazel new file mode 100644 index 00000000..b7a926b5 --- /dev/null +++ b/test/explicit_override/BUILD.bazel @@ -0,0 +1,38 @@ +load("//tools:diff_and_update.bzl", "diff_and_update") +load("@npm//@bazel/jasmine:index.bzl", "jasmine_node_test") +load("@npm//@bazel/typescript:index.bzl", "ts_project") + +diff_and_update( + name = "diff_explicit_override", + srcs = [ + "//test/_/explicit_override:explicit_override.ts", + ], + checked = [ "explicit_override.ts" ] +) + +ts_project( + name = "explicit_override", + srcs = glob(["*.ts"]), + tsconfig = { + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "noImplicitAny": True, + "noImplicitOverride": True + }, + }, + deps = [ + "@npm//@types/jasmine", + "@npm//@types/node", + "@npm//@types/google-protobuf", + "@npm//google-protobuf", + "@npm//@grpc/grpc-js", + ], +) + +jasmine_node_test( + name = "test", + deps = [ + ":explicit_override", + ], +) diff --git a/test/explicit_override/explicit_override.spec.ts b/test/explicit_override/explicit_override.spec.ts new file mode 100644 index 00000000..13d20c40 --- /dev/null +++ b/test/explicit_override/explicit_override.spec.ts @@ -0,0 +1,11 @@ +import { ExplicitOverrideMessage } from './explicit_override'; + +describe('Explicit Override', () => { + it('should compile with noImplicitOverride', () => { + const message = new ExplicitOverrideMessage({ + example: 1, + }); + + expect(message.example).toEqual(1); + }); +}); diff --git a/test/explicit_override/explicit_override.ts b/test/explicit_override/explicit_override.ts new file mode 100644 index 00000000..d7b17320 --- /dev/null +++ b/test/explicit_override/explicit_override.ts @@ -0,0 +1,73 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 3.19.1 + * source: test/_/explicit_override/explicit_override.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export class ExplicitOverrideMessage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + example?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("example" in data && data.example != undefined) { + this.example = data.example; + } + } + } + get example() { + return pb_1.Message.getField(this, 1) as number; + } + set example(value: number) { + pb_1.Message.setField(this, 1, value); + } + static fromObject(data: { + example?: number; + }): ExplicitOverrideMessage { + const message = new ExplicitOverrideMessage({}); + if (data.example != null) { + message.example = data.example; + } + return message; + } + toObject() { + const data: { + example?: number; + } = {}; + if (this.example != null) { + data.example = this.example; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.example !== undefined) + writer.writeUint32(1, this.example); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): ExplicitOverrideMessage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new ExplicitOverrideMessage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.example = reader.readUint32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static override deserializeBinary(bytes: Uint8Array): ExplicitOverrideMessage { + return ExplicitOverrideMessage.deserialize(bytes); + } +}