From 0dc743a0ce7b2d55eadfe72df29bf53e81c37403 Mon Sep 17 00:00:00 2001 From: Anton Versal Date: Mon, 12 Nov 2018 15:51:51 +0100 Subject: [PATCH] Squashed commit of the following: commit 8b7da3e4275e0e8def53b680d746e77649f840bb Author: Anton Versal Date: Mon Nov 12 15:51:15 2018 +0100 remames generated messages commit 57fad651cf61a72c20a6564b38fac5ada32fbce7 Author: Anton Versal Date: Mon Nov 12 14:19:52 2018 +0100 adds interface I commit cd713b5a4b9d7f9038d544b43bb2d613e42a597f Author: Anton Versal Date: Mon Nov 12 10:39:27 2018 +0100 wip commit 53dcf5dcd7a90c8282a1df2fbb1d05d752826344 Author: Anton Versal Date: Mon Nov 12 10:39:17 2018 +0100 wip --- generator/generator.go | 68 +- integrationTests/__tests__/decode.ts | 4 +- integrationTests/__tests__/encode.ts | 2 +- integrationTests/__tests__/generated/Test.ts | 170 +++-- .../__tests__/generated/common/Common.ts | 9 +- .../generated/google/protobuf/Timestamp.ts | 9 +- integrationTests/package.json | 14 +- integrationTests/yarn.lock | 207 +++-- pkg/generator/generator.go | 716 ++++++++++++++++++ 9 files changed, 965 insertions(+), 234 deletions(-) create mode 100644 pkg/generator/generator.go diff --git a/generator/generator.go b/generator/generator.go index d87dd97..030eae6 100644 --- a/generator/generator.go +++ b/generator/generator.go @@ -152,13 +152,17 @@ func (g *generator) isServiceDeprecated(field *google_protobuf.ServiceDescriptor return *field.Options.Deprecated } -func (g *generator) getTsTypeFromMessage(typeName *string) string { +func (g *generator) getTsTypeFromMessage(typeName *string, isInterface bool) string { names := strings.Split(*typeName, ".") importName := g.GetImportNameForMessage(*g.protoFile.Name, *typeName) + interfaceName := names[len(names)-1] + if isInterface { + interfaceName = "I" + interfaceName + } if importName == "" { - return names[len(names)-1] + return interfaceName } - return importName + "." + names[len(names)-1] + return importName + "." + interfaceName } func (g *generator) getTsFieldType(field *google_protobuf.FieldDescriptorProto) string { @@ -172,7 +176,7 @@ func (g *generator) getTsFieldType(field *google_protobuf.FieldDescriptorProto) if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_MESSAGE || *field.Type == google_protobuf.FieldDescriptorProto_TYPE_ENUM { - return g.getTsTypeFromMessage(field.TypeName) + return g.getTsTypeFromMessage(field.TypeName, *field.Type == google_protobuf.FieldDescriptorProto_TYPE_MESSAGE) } return g.getTsFieldTypeForScalar(*field.Type) @@ -212,7 +216,7 @@ func (g *generator) generateMessageInterface(message *google_protobuf.Descriptor g.P("* @deprecated") g.P("*/") } - g.P(fmt.Sprintf("export interface %s {", g.messageName(message))) + g.P(fmt.Sprintf("export interface I%s {", g.messageName(message))) for _, field := range message.Field { g.generateField(field, false) } @@ -221,7 +225,7 @@ func (g *generator) generateMessageInterface(message *google_protobuf.Descriptor func (g *generator) generateConstructor(message *google_protobuf.DescriptorProto) { name := g.messageName(message) - g.P(fmt.Sprintf("constructor(attrs?: %s){", name)) + g.P(fmt.Sprintf("constructor(attrs?: I%s){", name)) g.P("Object.assign(this, attrs)") g.P("}") } @@ -375,17 +379,17 @@ func (g *generator) generateEncode(message *google_protobuf.DescriptorProto) { g.P(fmt.Sprintf("for (const value of this.%s) {", name)) g.P("if (!value) { continue; }") if field.GetTypeName() == ".google.protobuf.Timestamp" { - g.P(fmt.Sprintf("const msg = new %sMsg({seconds: Math.floor(value.getTime() / 1000) , nanos: value.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("const msg = new %s({seconds: Math.floor(value.getTime() / 1000) , nanos: value.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName, false))) } else { - g.P(fmt.Sprintf("const msg = new %sMsg(value);", g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("const msg = new %s(value);", g.getTsTypeFromMessage(field.TypeName, false))) } g.P(fmt.Sprintf("msg.encode(writer.uint32(%d).fork()).ldelim();", g.getFieldIndex(field))) g.P("}") } else { if field.GetTypeName() == ".google.protobuf.Timestamp" { - g.P(fmt.Sprintf("const msg = new %sMsg({seconds: Math.floor(this.%s.getTime() / 1000) , nanos: this.%s.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName), name, name)) + g.P(fmt.Sprintf("const msg = new %s({seconds: Math.floor(this.%s.getTime() / 1000) , nanos: this.%s.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName, false), name, name)) } else { - g.P(fmt.Sprintf("const msg = new %sMsg(this.%s);", g.getTsTypeFromMessage(field.TypeName), name)) + g.P(fmt.Sprintf("const msg = new %s(this.%s);", g.getTsTypeFromMessage(field.TypeName, false), name)) } g.P(fmt.Sprintf("msg.encode(writer.uint32(%d).fork()).ldelim();", g.getFieldIndex(field))) } @@ -427,7 +431,7 @@ func (g *generator) generateDecode(message *google_protobuf.DescriptorProto) { g.P("? protobufjs.Reader.create(inReader)") g.P(": inReader") g.P("const end = length === undefined ? reader.len : reader.pos + length;") - g.P(fmt.Sprintf("const message = new %sMsg();", g.getTsTypeFromMessage(message.Name))) + g.P(fmt.Sprintf("const message = new %s();", g.getTsTypeFromMessage(message.Name, false))) g.P("while (reader.pos < end) {") g.P("const tag = reader.uint32()") g.P("switch (tag >>> 3) {") @@ -467,17 +471,17 @@ func (g *generator) generateDecode(message *google_protobuf.DescriptorProto) { g.P(fmt.Sprintf("message.%s = [];", name)) g.P("}") if field.GetTypeName() == ".google.protobuf.Timestamp" { - g.P(fmt.Sprintf("const %s = %sMsg.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("const %s = %s.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName, false))) g.P(fmt.Sprintf("message.%s.push(new Date(((%s.seconds || 0) * 1000) + ((%s.nanos || 0) / 1000000)));", name, name, name)) } else { - g.P(fmt.Sprintf("message.%s.push(%sMsg.decode(reader, reader.uint32()));", name, g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("message.%s.push(%s.decode(reader, reader.uint32()));", name, g.getTsTypeFromMessage(field.TypeName, false))) } } else { if field.GetTypeName() == ".google.protobuf.Timestamp" { - g.P(fmt.Sprintf("const %s = %sMsg.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("const %s = %s.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName, false))) g.P(fmt.Sprintf("message.%s = new Date(((%s.seconds || 0) * 1000) + ((%s.nanos || 0) / 1000000));", name, name, name)) } else { - g.P(fmt.Sprintf("message.%s = %sMsg.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("message.%s = %s.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName, false))) } } } else { @@ -538,7 +542,7 @@ func (g *generator) generateMessageClass(message *google_protobuf.DescriptorProt g.P("*/") } name := g.messageName(message) - g.P(fmt.Sprintf("export class %sMsg implements %s{", name, name)) + g.P(fmt.Sprintf("export class %s implements I%s{", name, name)) g.generateDecode(message) for _, field := range message.Field { g.generateField(field, true) @@ -596,14 +600,16 @@ func (g *generator) generateDefinition(service *google_protobuf.ServiceDescripto serverStreaming = *method.ServerStreaming } g.P(fmt.Sprintf("responseStream: %s,", strconv.FormatBool(serverStreaming))) - requestType := g.getTsTypeFromMessage(method.InputType) - g.P(fmt.Sprintf("requestType: %sMsg,", requestType)) - responseType := g.getTsTypeFromMessage(method.OutputType) - g.P(fmt.Sprintf("responseType: %sMsg,", responseType)) - g.P(fmt.Sprintf("requestSerialize: (args: %s) => new %sMsg(args).encode().finish() as Buffer,", requestType, requestType)) - g.P(fmt.Sprintf("requestDeserialize: (argBuf: Buffer) => %sMsg.decode(argBuf),", requestType)) - g.P(fmt.Sprintf("responseSerialize: (args: %s) => new %sMsg(args).encode().finish() as Buffer,", responseType, responseType)) - g.P(fmt.Sprintf("responseDeserialize: (argBuf: Buffer) => %sMsg.decode(argBuf),", responseType)) + requestType := g.getTsTypeFromMessage(method.InputType, false) + iRequestType := g.getTsTypeFromMessage(method.InputType, true) + g.P(fmt.Sprintf("requestType: %s,", requestType)) + responseType := g.getTsTypeFromMessage(method.OutputType, false) + iResponseType := g.getTsTypeFromMessage(method.OutputType, true) + g.P(fmt.Sprintf("responseType: %s,", responseType)) + g.P(fmt.Sprintf("requestSerialize: (args: %s) => new %s(args).encode().finish() as Buffer,", iRequestType, requestType)) + g.P(fmt.Sprintf("requestDeserialize: (argBuf: Buffer) => %s.decode(argBuf),", requestType)) + g.P(fmt.Sprintf("responseSerialize: (args: %s) => new %s(args).encode().finish() as Buffer,", iResponseType, responseType)) + g.P(fmt.Sprintf("responseDeserialize: (argBuf: Buffer) => %s.decode(argBuf),", responseType)) g.P("},") } g.P("}") @@ -621,8 +627,8 @@ func (g *generator) generateImplementation(service *google_protobuf.ServiceDescr for _, method := range service.Method { g.methodDeprecated(method) - inputTypeName := g.getTsTypeFromMessage(method.InputType) - outputTypeName := g.getTsTypeFromMessage(method.OutputType) + inputTypeName := g.getTsTypeFromMessage(method.InputType, true) + outputTypeName := g.getTsTypeFromMessage(method.OutputType, true) if method.ServerStreaming != nil && *method.ServerStreaming && method.ClientStreaming != nil && *method.ClientStreaming { g.P(fmt.Sprintf("%s(call: grpc.ServerDuplexStream<%s, %s>): void;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) } else if method.ServerStreaming != nil && *method.ServerStreaming { @@ -653,28 +659,28 @@ func (g *generator) generateClient(service *google_protobuf.ServiceDescriptorPro g.P(fmt.Sprintf("super(%sServiceDefinition, address, credentials, trace, options);", g.toLowerFirst(*service.Name))) g.P("}") for _, method := range service.Method { - inputTypeName := g.getTsTypeFromMessage(method.InputType) + inputTypeName := g.getTsTypeFromMessage(method.InputType, true) g.methodDeprecated(method) if method.ServerStreaming != nil && *method.ServerStreaming && method.ClientStreaming != nil && *method.ClientStreaming { - outputTypeName := g.getTsTypeFromMessage(method.OutputType) + outputTypeName := g.getTsTypeFromMessage(method.OutputType, true) g.P(fmt.Sprintf("public %s(metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name))) g.methodDeprecatedLog(method) g.P(fmt.Sprintf("return super.makeBidiStreamRequest<%s, %s>('%s', metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) g.P(fmt.Sprint("}")) } else if method.ServerStreaming != nil && *method.ServerStreaming { - outputTypeName := g.getTsTypeFromMessage(method.OutputType) + outputTypeName := g.getTsTypeFromMessage(method.OutputType, true) g.P(fmt.Sprintf("public %s(req: %s, metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name), inputTypeName)) g.methodDeprecatedLog(method) g.P(fmt.Sprintf("return super.makeServerStreamRequest<%s, %s>('%s', req, metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) g.P(fmt.Sprint("}")) } else if method.ClientStreaming != nil && *method.ClientStreaming { - outputTypeName := g.getTsTypeFromMessage(method.OutputType) + outputTypeName := g.getTsTypeFromMessage(method.OutputType, true) g.P(fmt.Sprintf("public %s(metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name))) g.methodDeprecatedLog(method) g.P(fmt.Sprintf("return super.makeClientStreamRequest<%s, %s>('%s', metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) g.P(fmt.Sprint("};")) } else { - outputTypeName := g.getTsTypeFromMessage(method.OutputType) + outputTypeName := g.getTsTypeFromMessage(method.OutputType, true) g.P(fmt.Sprintf("public %s(req: %s, metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name), inputTypeName)) g.methodDeprecatedLog(method) g.P(fmt.Sprintf("return super.makeUnaryRequest<%s, %s>('%s', req, metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) diff --git a/integrationTests/__tests__/decode.ts b/integrationTests/__tests__/decode.ts index 6031041..7cba177 100644 --- a/integrationTests/__tests__/decode.ts +++ b/integrationTests/__tests__/decode.ts @@ -62,7 +62,7 @@ describe('decode', () => { beforeEach(() => { const message = PbTest.fromObject(values) buffer = PbTest.encode(message).finish() - decoded = Foo.TestMsg.decode(buffer) + decoded = Foo.Test.decode(buffer) }) describe.each([ @@ -141,7 +141,7 @@ describe('decode changed protos', () => { beforeEach(() => { const message = PbTest.fromObject(values) buffer = PbTest.encode(message).finish() - decoded = Foo.TestMsg.decode(buffer) + decoded = Foo.Test.decode(buffer) }) it('ignores missing field', () => { diff --git a/integrationTests/__tests__/encode.ts b/integrationTests/__tests__/encode.ts index dca9a90..775a70a 100644 --- a/integrationTests/__tests__/encode.ts +++ b/integrationTests/__tests__/encode.ts @@ -65,7 +65,7 @@ describe('encode', () => { } beforeEach(() => { - const user = new Foo.TestMsg(values) + const user = new Foo.Test(values) buffer = user.encode().finish() decoded = PbTest.toObject(PbTest.decode(buffer), { enums: String, diff --git a/integrationTests/__tests__/generated/Test.ts b/integrationTests/__tests__/generated/Test.ts index f884695..2784408 100644 --- a/integrationTests/__tests__/generated/Test.ts +++ b/integrationTests/__tests__/generated/Test.ts @@ -2,10 +2,12 @@ import { GoogleProtobuf } from './google/protobuf/Timestamp'; import { Common } from './common/Common'; import * as protobufjs from 'protobufjs/minimal'; +// @ts-ignore ignored as it's generated and it's difficult to predict if logger is needed import { logger } from '@join-com/gcloud-logger-trace'; import * as grpc from 'grpc'; import * as grpcts from '@join-com/grpc-ts'; +import * as nodeTrace from '@join-com/node-trace'; export namespace Foo { export enum EnumType { @@ -19,11 +21,11 @@ export namespace Foo { EDIT = 'EDIT' } - export interface Request { + export interface IRequest { id?: number; } - export class RequestMsg implements Request { + export class Request implements IRequest { public static decode( inReader: Uint8Array | protobufjs.Reader, length?: number @@ -32,7 +34,7 @@ export namespace Foo { ? protobufjs.Reader.create(inReader) : inReader; const end = length === undefined ? reader.len : reader.pos + length; - const message = new RequestMsg(); + const message = new Request(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -47,7 +49,7 @@ export namespace Foo { return message; } public id?: number; - constructor(attrs?: Request) { + constructor(attrs?: IRequest) { Object.assign(this, attrs); } public encode(writer: protobufjs.Writer = protobufjs.Writer.create()) { @@ -61,14 +63,14 @@ export namespace Foo { /** * @deprecated */ - export interface Nested { + export interface INested { title?: string; } /** * @deprecated */ - export class NestedMsg implements Nested { + export class Nested implements INested { public static decode( inReader: Uint8Array | protobufjs.Reader, length?: number @@ -78,7 +80,7 @@ export namespace Foo { ? protobufjs.Reader.create(inReader) : inReader; const end = length === undefined ? reader.len : reader.pos + length; - const message = new NestedMsg(); + const message = new Nested(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -93,7 +95,7 @@ export namespace Foo { return message; } public title?: string; - constructor(attrs?: Nested) { + constructor(attrs?: INested) { Object.assign(this, attrs); } public encode(writer: protobufjs.Writer = protobufjs.Writer.create()) { @@ -105,7 +107,7 @@ export namespace Foo { } } - export interface Test { + export interface ITest { fieldInt32?: number; fieldInt32Repeated?: number[]; fieldDouble?: number; @@ -137,17 +139,17 @@ export namespace Foo { fieldBytesRepeated?: Uint8Array[]; fieldEnum?: EnumType; fieldEnumRepeated?: Role[]; - message?: Nested; - messageRepeated?: Nested[]; + message?: INested; + messageRepeated?: INested[]; timestamp?: Date; timestampRepeated?: Date[]; - otherPkgMessage?: Common.OtherPkgMessage; - otherPkgMessageRepeated?: Common.OtherPkgMessage[]; + otherPkgMessage?: Common.IOtherPkgMessage; + otherPkgMessageRepeated?: Common.IOtherPkgMessage[]; fieldInt64?: number; fieldInt64Repeated?: number[]; } - export class TestMsg implements Test { + export class Test implements ITest { public static decode( inReader: Uint8Array | protobufjs.Reader, length?: number @@ -156,7 +158,7 @@ export namespace Foo { ? protobufjs.Reader.create(inReader) : inReader; const end = length === undefined ? reader.len : reader.pos + length; - const message = new TestMsg(); + const message = new Test(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -547,18 +549,18 @@ export namespace Foo { } break; case 33: - message.message = NestedMsg.decode(reader, reader.uint32()); + message.message = Nested.decode(reader, reader.uint32()); break; case 34: if (!(message.messageRepeated && message.messageRepeated.length)) { message.messageRepeated = []; } message.messageRepeated.push( - NestedMsg.decode(reader, reader.uint32()) + Nested.decode(reader, reader.uint32()) ); break; case 35: - const timestamp = GoogleProtobuf.TimestampMsg.decode( + const timestamp = GoogleProtobuf.Timestamp.decode( reader, reader.uint32() ); @@ -572,7 +574,7 @@ export namespace Foo { ) { message.timestampRepeated = []; } - const timestampRepeated = GoogleProtobuf.TimestampMsg.decode( + const timestampRepeated = GoogleProtobuf.Timestamp.decode( reader, reader.uint32() ); @@ -584,7 +586,7 @@ export namespace Foo { ); break; case 37: - message.otherPkgMessage = Common.OtherPkgMessageMsg.decode( + message.otherPkgMessage = Common.OtherPkgMessage.decode( reader, reader.uint32() ); @@ -599,7 +601,7 @@ export namespace Foo { message.otherPkgMessageRepeated = []; } message.otherPkgMessageRepeated.push( - Common.OtherPkgMessageMsg.decode(reader, reader.uint32()) + Common.OtherPkgMessage.decode(reader, reader.uint32()) ); break; case 39: @@ -674,15 +676,15 @@ export namespace Foo { public fieldBytesRepeated?: Uint8Array[]; public fieldEnum?: EnumType; public fieldEnumRepeated?: Role[]; - public message?: Nested; - public messageRepeated?: Nested[]; + public message?: INested; + public messageRepeated?: INested[]; public timestamp?: Date; public timestampRepeated?: Date[]; - public otherPkgMessage?: Common.OtherPkgMessage; - public otherPkgMessageRepeated?: Common.OtherPkgMessage[]; + public otherPkgMessage?: Common.IOtherPkgMessage; + public otherPkgMessageRepeated?: Common.IOtherPkgMessage[]; public fieldInt64?: number; public fieldInt64Repeated?: number[]; - constructor(attrs?: Test) { + constructor(attrs?: ITest) { Object.assign(this, attrs); } public encode(writer: protobufjs.Writer = protobufjs.Writer.create()) { @@ -833,7 +835,7 @@ export namespace Foo { } } if (this.message != null) { - const msg = new NestedMsg(this.message); + const msg = new Nested(this.message); msg.encode(writer.uint32(266).fork()).ldelim(); } if (this.messageRepeated != null) { @@ -841,12 +843,12 @@ export namespace Foo { if (!value) { continue; } - const msg = new NestedMsg(value); + const msg = new Nested(value); msg.encode(writer.uint32(274).fork()).ldelim(); } } if (this.timestamp != null) { - const msg = new GoogleProtobuf.TimestampMsg({ + const msg = new GoogleProtobuf.Timestamp({ seconds: Math.floor(this.timestamp.getTime() / 1000), nanos: this.timestamp.getMilliseconds() * 1000000 }); @@ -857,7 +859,7 @@ export namespace Foo { if (!value) { continue; } - const msg = new GoogleProtobuf.TimestampMsg({ + const msg = new GoogleProtobuf.Timestamp({ seconds: Math.floor(value.getTime() / 1000), nanos: value.getMilliseconds() * 1000000 }); @@ -865,7 +867,7 @@ export namespace Foo { } } if (this.otherPkgMessage != null) { - const msg = new Common.OtherPkgMessageMsg(this.otherPkgMessage); + const msg = new Common.OtherPkgMessage(this.otherPkgMessage); msg.encode(writer.uint32(298).fork()).ldelim(); } if (this.otherPkgMessageRepeated != null) { @@ -873,7 +875,7 @@ export namespace Foo { if (!value) { continue; } - const msg = new Common.OtherPkgMessageMsg(value); + const msg = new Common.OtherPkgMessage(value); msg.encode(writer.uint32(306).fork()).ldelim(); } } @@ -894,57 +896,57 @@ export namespace Foo { path: '/Users/Find', requestStream: false, responseStream: false, - requestType: RequestMsg, - responseType: Common.OtherPkgMessageMsg, - requestSerialize: (args: Request) => - new RequestMsg(args).encode().finish() as Buffer, - requestDeserialize: (argBuf: Buffer) => RequestMsg.decode(argBuf), - responseSerialize: (args: Common.OtherPkgMessage) => - new Common.OtherPkgMessageMsg(args).encode().finish() as Buffer, + requestType: Request, + responseType: Common.OtherPkgMessage, + requestSerialize: (args: IRequest) => + new Request(args).encode().finish() as Buffer, + requestDeserialize: (argBuf: Buffer) => Request.decode(argBuf), + responseSerialize: (args: Common.IOtherPkgMessage) => + new Common.OtherPkgMessage(args).encode().finish() as Buffer, responseDeserialize: (argBuf: Buffer) => - Common.OtherPkgMessageMsg.decode(argBuf) + Common.OtherPkgMessage.decode(argBuf) }, findClientStream: { path: '/Users/FindClientStream', requestStream: true, responseStream: false, - requestType: RequestMsg, - responseType: Common.OtherPkgMessageMsg, - requestSerialize: (args: Request) => - new RequestMsg(args).encode().finish() as Buffer, - requestDeserialize: (argBuf: Buffer) => RequestMsg.decode(argBuf), - responseSerialize: (args: Common.OtherPkgMessage) => - new Common.OtherPkgMessageMsg(args).encode().finish() as Buffer, + requestType: Request, + responseType: Common.OtherPkgMessage, + requestSerialize: (args: IRequest) => + new Request(args).encode().finish() as Buffer, + requestDeserialize: (argBuf: Buffer) => Request.decode(argBuf), + responseSerialize: (args: Common.IOtherPkgMessage) => + new Common.OtherPkgMessage(args).encode().finish() as Buffer, responseDeserialize: (argBuf: Buffer) => - Common.OtherPkgMessageMsg.decode(argBuf) + Common.OtherPkgMessage.decode(argBuf) }, findServerStream: { path: '/Users/FindServerStream', requestStream: false, responseStream: true, - requestType: RequestMsg, - responseType: Common.OtherPkgMessageMsg, - requestSerialize: (args: Request) => - new RequestMsg(args).encode().finish() as Buffer, - requestDeserialize: (argBuf: Buffer) => RequestMsg.decode(argBuf), - responseSerialize: (args: Common.OtherPkgMessage) => - new Common.OtherPkgMessageMsg(args).encode().finish() as Buffer, + requestType: Request, + responseType: Common.OtherPkgMessage, + requestSerialize: (args: IRequest) => + new Request(args).encode().finish() as Buffer, + requestDeserialize: (argBuf: Buffer) => Request.decode(argBuf), + responseSerialize: (args: Common.IOtherPkgMessage) => + new Common.OtherPkgMessage(args).encode().finish() as Buffer, responseDeserialize: (argBuf: Buffer) => - Common.OtherPkgMessageMsg.decode(argBuf) + Common.OtherPkgMessage.decode(argBuf) }, findBidiStream: { path: '/Users/FindBidiStream', requestStream: true, responseStream: true, - requestType: RequestMsg, - responseType: Common.OtherPkgMessageMsg, - requestSerialize: (args: Request) => - new RequestMsg(args).encode().finish() as Buffer, - requestDeserialize: (argBuf: Buffer) => RequestMsg.decode(argBuf), - responseSerialize: (args: Common.OtherPkgMessage) => - new Common.OtherPkgMessageMsg(args).encode().finish() as Buffer, + requestType: Request, + responseType: Common.OtherPkgMessage, + requestSerialize: (args: IRequest) => + new Request(args).encode().finish() as Buffer, + requestDeserialize: (argBuf: Buffer) => Request.decode(argBuf), + responseSerialize: (args: Common.IOtherPkgMessage) => + new Common.OtherPkgMessage(args).encode().finish() as Buffer, responseDeserialize: (argBuf: Buffer) => - Common.OtherPkgMessageMsg.decode(argBuf) + Common.OtherPkgMessage.decode(argBuf) } }; @@ -952,51 +954,61 @@ export namespace Foo { /** * @deprecated */ - find(call: grpc.ServerUnaryCall): Promise; find( - call: grpc.ServerUnaryCall, - callback: grpc.sendUnaryData + call: grpc.ServerUnaryCall + ): Promise; + find( + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData ): void; findClientStream( - call: grpc.ServerReadableStream - ): Promise; + call: grpc.ServerReadableStream + ): Promise; findClientStream( - call: grpc.ServerReadableStream, - callback: grpc.sendUnaryData + call: grpc.ServerReadableStream, + callback: grpc.sendUnaryData ): void; - findServerStream(call: grpc.ServerWriteableStream): void; + findServerStream(call: grpc.ServerWriteableStream): void; findBidiStream( - call: grpc.ServerDuplexStream + call: grpc.ServerDuplexStream ): void; } export class UsersClient extends grpcts.Client { + constructor( + address: string, + credentials: grpc.ChannelCredentials, + trace: grpcts.ClientTrace = nodeTrace, + options?: object + ) { + super(usersServiceDefinition, address, credentials, trace, options); + } /** * @deprecated */ - public find(req: Request, metadata?: grpcts.Metadata) { + public find(req: IRequest, metadata?: grpcts.Metadata) { logger.warn('method Find is deprecated'); - return super.makeUnaryRequest( + return super.makeUnaryRequest( 'find', req, metadata ); } public findClientStream(metadata?: grpcts.Metadata) { - return super.makeClientStreamRequest( + return super.makeClientStreamRequest( 'findClientStream', metadata ); } - public findServerStream(req: Request, metadata?: grpcts.Metadata) { - return super.makeServerStreamRequest( + public findServerStream(req: IRequest, metadata?: grpcts.Metadata) { + return super.makeServerStreamRequest( 'findServerStream', req, metadata ); } public findBidiStream(metadata?: grpcts.Metadata) { - return super.makeBidiStreamRequest( + return super.makeBidiStreamRequest( 'findBidiStream', metadata ); diff --git a/integrationTests/__tests__/generated/common/Common.ts b/integrationTests/__tests__/generated/common/Common.ts index dabe0de..2108300 100644 --- a/integrationTests/__tests__/generated/common/Common.ts +++ b/integrationTests/__tests__/generated/common/Common.ts @@ -1,14 +1,15 @@ // GENERATED CODE -- DO NOT EDIT! import * as protobufjs from 'protobufjs/minimal'; +// @ts-ignore ignored as it's generated and it's difficult to predict if logger is needed import { logger } from '@join-com/gcloud-logger-trace'; export namespace Common { - export interface OtherPkgMessage { + export interface IOtherPkgMessage { /** @deprecated */ firstName?: string; latsName?: string; } - export class OtherPkgMessageMsg implements OtherPkgMessage { + export class OtherPkgMessage implements IOtherPkgMessage { public static decode( inReader: Uint8Array | protobufjs.Reader, length?: number @@ -17,7 +18,7 @@ export namespace Common { ? protobufjs.Reader.create(inReader) : inReader; const end = length === undefined ? reader.len : reader.pos + length; - const message = new OtherPkgMessageMsg(); + const message = new OtherPkgMessage(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -38,7 +39,7 @@ export namespace Common { /** @deprecated */ public firstName?: string; public latsName?: string; - constructor(attrs?: OtherPkgMessage) { + constructor(attrs?: IOtherPkgMessage) { Object.assign(this, attrs); } public encode(writer: protobufjs.Writer = protobufjs.Writer.create()) { diff --git a/integrationTests/__tests__/generated/google/protobuf/Timestamp.ts b/integrationTests/__tests__/generated/google/protobuf/Timestamp.ts index 6a2ad2b..6c2cb79 100644 --- a/integrationTests/__tests__/generated/google/protobuf/Timestamp.ts +++ b/integrationTests/__tests__/generated/google/protobuf/Timestamp.ts @@ -1,13 +1,14 @@ // GENERATED CODE -- DO NOT EDIT! import * as protobufjs from 'protobufjs/minimal'; +// @ts-ignore ignored as it's generated and it's difficult to predict if logger is needed import { logger } from '@join-com/gcloud-logger-trace'; export namespace GoogleProtobuf { - export interface Timestamp { + export interface ITimestamp { seconds?: number; nanos?: number; } - export class TimestampMsg implements Timestamp { + export class Timestamp implements ITimestamp { public static decode( inReader: Uint8Array | protobufjs.Reader, length?: number @@ -16,7 +17,7 @@ export namespace GoogleProtobuf { ? protobufjs.Reader.create(inReader) : inReader; const end = length === undefined ? reader.len : reader.pos + length; - const message = new TimestampMsg(); + const message = new Timestamp(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -39,7 +40,7 @@ export namespace GoogleProtobuf { } public seconds?: number; public nanos?: number; - constructor(attrs?: Timestamp) { + constructor(attrs?: ITimestamp) { Object.assign(this, attrs); } public encode(writer: protobufjs.Writer = protobufjs.Writer.create()) { diff --git a/integrationTests/package.json b/integrationTests/package.json index b50ea80..4015866 100644 --- a/integrationTests/package.json +++ b/integrationTests/package.json @@ -11,20 +11,20 @@ }, "dependencies": { "@join-com/gcloud-logger-trace": "^0.1.5", - "@join-com/grpc-ts": "1.0.0-2", - "grpc": "^1.15.1", + "@join-com/grpc-ts": "1.0.0-3", + "grpc": "^1.16.0", "protobufjs": "^6.8.8" }, "devDependencies": { - "@types/jest": "^23.3.3", - "@types/node": "^10.11.4", + "@types/jest": "^23.3.9", + "@types/node": "^10.12.5", "jest": "^23.6.0", "jest-extended": "^0.11.0", "jest-watch-typeahead": "^0.2.0", - "prettier": "^1.14.3", - "ts-jest": "^23.10.3", + "prettier": "^1.15.2", + "ts-jest": "^23.10.4", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", - "typescript": "^3.1.1" + "typescript": "^3.1.6" } } diff --git a/integrationTests/yarn.lock b/integrationTests/yarn.lock index fca423a..652b87c 100644 --- a/integrationTests/yarn.lock +++ b/integrationTests/yarn.lock @@ -45,11 +45,11 @@ dependencies: "@join-com/gcloud-logger" "^0.1.4" -"@join-com/grpc-ts@1.0.0-2": - version "1.0.0-2" - resolved "https://registry.npmjs.org/@join-com/grpc-ts/-/grpc-ts-1.0.0-2.tgz#0df97e8a3e55867c71919e57985bfacae79bc126" +"@join-com/grpc-ts@1.0.0-3": + version "1.0.0-3" + resolved "https://registry.npmjs.org/@join-com/grpc-ts/-/grpc-ts-1.0.0-3.tgz#ad6c39d2313640820750e7ec9300a1ab9e3fe197" dependencies: - grpc "^1.15.1" + grpc "^1.16.0" "@join-com/node-trace@^0.1.5": version "0.1.5" @@ -100,21 +100,17 @@ version "1.1.0" resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" -"@types/jest@^23.3.3": - version "23.3.5" - resolved "https://registry.npmjs.org/@types/jest/-/jest-23.3.5.tgz#870a1434208b60603745bfd214fc3fc675142364" +"@types/jest@^23.3.9": + version "23.3.9" + resolved "https://registry.npmjs.org/@types/jest/-/jest-23.3.9.tgz#c16b55186ee73ae65e001fbee69d392c51337ad1" "@types/long@^4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" -"@types/node@^10.1.0", "@types/node@^10.11.4": - version "10.11.6" - resolved "https://registry.npmjs.org/@types/node/-/node-10.11.6.tgz#ce5690df6cd917a9178439a1013e39a7e565c46e" - -"@types/node@^10.3.4": - version "10.11.7" - resolved "https://registry.npmjs.org/@types/node/-/node-10.11.7.tgz#0e75ca9357d646ca754016ca1d68a127ad7e7300" +"@types/node@^10.1.0", "@types/node@^10.12.5", "@types/node@^10.3.4": + version "10.12.5" + resolved "https://registry.npmjs.org/@types/node/-/node-10.12.5.tgz#7e7ea1a9b34d2c8d704cb0b755dffbcda34741ad" abab@^2.0.0: version "2.0.0" @@ -140,21 +136,21 @@ acorn@^5.5.3: resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" acorn@^6.0.1: - version "6.0.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz#6a459041c320ab17592c6317abbfdf4bbaa98ca4" + version "6.0.4" + resolved "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" -ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" +ajv@^6.5.5: + version "6.5.5" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz#cf97cdade71c6399a92c6d6c4177381291b781a1" dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" + fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" ansi-escapes@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + resolved "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" ansi-regex@^2.0.0: version "2.1.1" @@ -224,7 +220,7 @@ arr-union@^3.1.0: array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-unique@^0.2.1: version "0.2.1" @@ -497,10 +493,10 @@ browser-resolve@^1.11.3: resolve "1.1.7" bs-logger@0.x: - version "0.2.5" - resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.5.tgz#1d82f0cf88864e1341cd9262237f8d0748a49b22" + version "0.2.6" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" dependencies: - fast-json-stable-stringify "^2.0.0" + fast-json-stable-stringify "2.x" bser@^2.0.0: version "2.0.0" @@ -576,7 +572,7 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chownr@^1.0.1: +chownr@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -638,13 +634,7 @@ colour@~0.7.1: version "0.7.1" resolved "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" -combined-stream@1.0.6: - version "1.0.6" - resolved "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" - -combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" dependencies: @@ -713,11 +703,11 @@ dashdash@^1.12.0: assert-plus "^1.0.0" data-urls@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz#d416ac3896918f29ca84d81085bc3705834da579" + version "1.1.0" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" dependencies: abab "^2.0.0" - whatwg-mimetype "^2.1.0" + whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: @@ -978,9 +968,9 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.0.0" @@ -1054,11 +1044,11 @@ forever-agent@~0.6.1: resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" form-data@~2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + version "2.3.3" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" dependencies: asynckit "^0.4.0" - combined-stream "1.0.6" + combined-stream "^1.0.6" mime-types "^2.1.12" fragment-cache@^0.2.1: @@ -1148,16 +1138,16 @@ globals@^9.18.0: resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" graceful-fs@^4.1.11, graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + version "4.1.15" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" growly@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" -grpc@^1.15.1: - version "1.15.1" - resolved "https://registry.npmjs.org/grpc/-/grpc-1.15.1.tgz#046263d9b0c440c8e36fece03e227cb3afe28514" +grpc@^1.16.0: + version "1.16.0" + resolved "https://registry.npmjs.org/grpc/-/grpc-1.16.0.tgz#cdf56d6ede2f1b6ab5224ad467cb22e1b3ec36fc" dependencies: lodash "^4.17.5" nan "^2.0.0" @@ -1179,10 +1169,10 @@ har-schema@^2.0.0: resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" har-validator@~5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + version "5.1.3" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" dependencies: - ajv "^5.3.0" + ajv "^6.5.5" har-schema "^2.0.0" has-ansi@^2.0.0: @@ -1687,7 +1677,7 @@ jest-extended@^0.11.0: jest-get-type@^22.1.0, jest-get-type@^22.4.3: version "22.4.3" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + resolved "http://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" jest-haste-map@^23.6.0: version "23.6.0" @@ -1942,11 +1932,11 @@ jsdom@^11.5.1: jsesc@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + resolved "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" json-schema@0.2.3: version "0.2.3" @@ -2103,8 +2093,8 @@ merge-stream@^1.0.1: readable-stream "^2.0.1" merge@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + version "1.2.1" + resolved "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" micromatch@^2.3.11: version "2.3.11" @@ -2142,15 +2132,15 @@ micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -mime-db@~1.36.0: - version "1.36.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" +mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.20" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" + version "2.1.21" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" dependencies: - mime-db "~1.36.0" + mime-db "~1.37.0" mimic-fn@^1.0.0: version "1.2.0" @@ -2174,16 +2164,16 @@ minimist@~0.0.1: version "0.0.10" resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" -minipass@^2.2.1, minipass@^2.3.3: - version "2.3.4" - resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" -minizlib@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" +minizlib@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz#6734acc045a46e61d596a43bb9d9cd326e19cc42" dependencies: minipass "^2.2.1" @@ -2245,11 +2235,11 @@ node-int64@^0.4.0: resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-notifier@^5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + version "5.3.0" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz#c77a4a7b84038733d5fb351aafd8a268bfe19a01" dependencies: growly "^1.3.0" - semver "^5.4.1" + semver "^5.5.0" shellwords "^0.1.1" which "^1.3.0" @@ -2406,7 +2396,7 @@ optjs@~3.2.2: os-homedir@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-locale@^1.4.0: version "1.4.0" @@ -2424,7 +2414,7 @@ os-locale@^2.0.0: os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@^0.1.4: version "0.1.5" @@ -2488,7 +2478,7 @@ path-exists@^3.0.0: path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-key@^2.0.0: version "2.0.1" @@ -2512,7 +2502,7 @@ performance-now@^2.1.0: pify@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pinkie-promise@^2.0.0: version "2.0.1" @@ -2546,9 +2536,9 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier@^1.14.3: - version "1.14.3" - resolved "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" +prettier@^1.15.2: + version "1.15.2" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.15.2.tgz#d31abe22afa4351efa14c7f8b94b58bb7452205e" pretty-format@^22.4.3: version "22.4.3" @@ -2627,8 +2617,8 @@ qs@~6.5.2: resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" randomatic@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz#36f2ca708e9e567f5ed2ec01949026d50aa10116" + version "3.1.1" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" dependencies: is-number "^4.0.0" kind-of "^6.0.0" @@ -2802,7 +2792,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: safe-regex@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" dependencies: ret "~0.1.10" @@ -2829,9 +2819,9 @@ sax@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0: - version "5.5.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5, semver@^5.5.0: + version "5.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -2962,8 +2952,8 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz#e2a303236cac54b04031fa7a5a79c7e701df852f" + version "3.0.2" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz#a59efc09784c2a5bada13cfeaf5c75dd214044d2" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -2976,18 +2966,17 @@ sprintf-js@~1.0.2: resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.14.2" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" + version "1.15.2" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz#c946d6bd9b1a39d0e8635763f5242d6ed6dcb629" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - safer-buffer "^2.0.2" - optionalDependencies: bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" ecc-jsbn "~0.1.1" + getpass "^0.1.1" jsbn "~0.1.0" + safer-buffer "^2.0.2" tweetnacl "~0.14.0" stack-utils@^1.0.1: @@ -3057,7 +3046,7 @@ strip-bom@^2.0.0: strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-json-comments@~2.0.1: version "2.0.1" @@ -3084,13 +3073,13 @@ symbol-tree@^3.2.2: resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" tar@^4: - version "4.4.6" - resolved "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" + version "4.4.8" + resolved "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" dependencies: - chownr "^1.0.1" + chownr "^1.1.1" fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" + minipass "^2.3.4" + minizlib "^1.1.1" mkdirp "^0.5.0" safe-buffer "^5.1.2" yallist "^3.0.2" @@ -3156,7 +3145,7 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -ts-jest@^23.10.3: +ts-jest@^23.10.4: version "23.10.4" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-23.10.4.tgz#a7a953f55c9165bcaa90ff91014a178e87fe0df8" dependencies: @@ -3216,9 +3205,9 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -typescript@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/typescript/-/typescript-3.1.2.tgz#c03a5d16f30bb60ad8bb6fe8e7cb212eedeec950" +typescript@^3.1.6: + version "3.1.6" + resolved "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" uglify-js@^3.1.4: version "3.4.9" @@ -3243,6 +3232,12 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + urix@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -3310,7 +3305,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: dependencies: iconv-lite "0.4.24" -whatwg-mimetype@^2.1.0: +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz#a3d58ef10b76009b042d03e25591ece89b88d171" diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go new file mode 100644 index 0000000..949f7c4 --- /dev/null +++ b/pkg/generator/generator.go @@ -0,0 +1,716 @@ +package generator + +import ( + "fmt" + "strconv" + "strings" + "unicode" + + "github.com/antonversal/protoc-gen-ts/pkg/base" + "github.com/golang/protobuf/proto" + google_protobuf "github.com/golang/protobuf/protoc-gen-go/descriptor" + gen "github.com/golang/protobuf/protoc-gen-go/generator" + plugin "github.com/golang/protobuf/protoc-gen-go/plugin" +) + +type generator struct { + *base.Generator + protoFile *google_protobuf.FileDescriptorProto +} + +func New() *generator { + return &generator{Generator: base.New()} +} + +func (g *generator) tsFileName(protoName *string) string { + fileNames := strings.Split(*protoName, "/") + fileBaseName := fileNames[len(fileNames)-1] + baseName := gen.CamelCase(g.ProtoFileBaseName(fileBaseName)) + if len(fileNames) > 1 { + return strings.Join(fileNames[:len(fileNames)-1], "/") + "/" + baseName + } + return baseName +} + +func (g *generator) tsFileNameWithExt(protoName *string) string { + return g.tsFileName(protoName) + ".ts" +} + +func (g *generator) generateGenericImports() { + g.P(` +import * as grpc from 'grpc'; +import * as grpcts from '@join-com/grpc-ts'; +import * as nodeTrace from '@join-com/node-trace'; +`) +} + +func (g *generator) generateImports(protoFile *google_protobuf.FileDescriptorProto, protoFiles []*google_protobuf.FileDescriptorProto) { + for _, dependency := range protoFile.Dependency { + var depProtoFile *google_protobuf.FileDescriptorProto + for _, extProtoFile := range protoFiles { + depProtoFileName := *extProtoFile.Name + if depProtoFileName == dependency { + depProtoFile = extProtoFile + } + } + + packageName := depProtoFile.GetPackage() + namespaceName := g.NamespaceName(packageName) + fileNames := strings.Split(*protoFile.Name, "/") + var path string + if len(fileNames) <= 1 { + path = "./" + } else { + path = strings.Repeat("../", len(fileNames)-1) + } + + path += g.tsFileName(depProtoFile.Name) + importName := g.GetImportName(*protoFile.Name, *depProtoFile.Name) + if importName == namespaceName { + g.P(fmt.Sprintf("import { %s } from '%s';", namespaceName, path)) + } else { + g.P(fmt.Sprintf("import { %s as %s} from '%s';", namespaceName, importName, path)) + } + } +} + +func (g *generator) generateNamespace(packageName string) { + g.P(fmt.Sprintf("export namespace %s {", g.NamespaceName(packageName))) +} + +func (g *generator) enumName(enum *google_protobuf.EnumDescriptorProto) string { + return gen.CamelCase(*enum.Name) +} + +func (g *generator) getTsFieldTypeForScalar(typeID google_protobuf.FieldDescriptorProto_Type) string { + m := make(map[google_protobuf.FieldDescriptorProto_Type]string) + m[google_protobuf.FieldDescriptorProto_TYPE_DOUBLE] = "number" // TYPE_DOUBLE + m[google_protobuf.FieldDescriptorProto_TYPE_FLOAT] = "number" // TYPE_FLOAT + m[google_protobuf.FieldDescriptorProto_TYPE_INT64] = "number" // TYPE_INT64 + m[google_protobuf.FieldDescriptorProto_TYPE_UINT64] = "number" // TYPE_UINT64 + m[google_protobuf.FieldDescriptorProto_TYPE_INT32] = "number" // TYPE_INT32 + m[google_protobuf.FieldDescriptorProto_TYPE_FIXED64] = "number" // TYPE_FIXED64 + m[google_protobuf.FieldDescriptorProto_TYPE_FIXED32] = "number" // TYPE_FIXED32 + m[google_protobuf.FieldDescriptorProto_TYPE_BOOL] = "boolean" // TYPE_BOOL + m[google_protobuf.FieldDescriptorProto_TYPE_STRING] = "string" // TYPE_STRING + m[google_protobuf.FieldDescriptorProto_TYPE_GROUP] = "Object" // TYPE_GROUP + m[google_protobuf.FieldDescriptorProto_TYPE_MESSAGE] = "Object" // TYPE_MESSAGE - Length-delimited aggregate. + m[google_protobuf.FieldDescriptorProto_TYPE_BYTES] = "Uint8Array" // TYPE_BYTES + m[google_protobuf.FieldDescriptorProto_TYPE_UINT32] = "number" // TYPE_UINT32 + m[google_protobuf.FieldDescriptorProto_TYPE_ENUM] = "number" // TYPE_ENUM + m[google_protobuf.FieldDescriptorProto_TYPE_SFIXED32] = "number" // TYPE_SFIXED32 + m[google_protobuf.FieldDescriptorProto_TYPE_SFIXED64] = "number" // TYPE_SFIXED64 + m[google_protobuf.FieldDescriptorProto_TYPE_SINT32] = "number" // TYPE_SINT32 - Uses ZigZag encoding. + m[google_protobuf.FieldDescriptorProto_TYPE_SINT64] = "number" // TYPE_SINT64 - Uses ZigZag encoding. + return m[typeID] +} + +func (g *generator) isFieldOneOf(field *google_protobuf.FieldDescriptorProto) bool { + return field.OneofIndex != nil +} + +func (g *generator) isFieldDeprecated(field *google_protobuf.FieldDescriptorProto) bool { + if field.Options == nil || field.Options.Deprecated == nil { + return false + } + return *field.Options.Deprecated +} + +func (g *generator) isMethodDeprecated(field *google_protobuf.MethodDescriptorProto) bool { + if field.Options == nil || field.Options.Deprecated == nil { + return false + } + return *field.Options.Deprecated +} + +func (g *generator) isServiceDeprecated(field *google_protobuf.ServiceDescriptorProto) bool { + if field.Options == nil || field.Options.Deprecated == nil { + return false + } + return *field.Options.Deprecated +} + +func (g *generator) getTsTypeFromMessage(typeName *string) string { + names := strings.Split(*typeName, ".") + importName := g.GetImportNameForMessage(*g.protoFile.Name, *typeName) + if importName == "" { + return names[len(names)-1] + } + return importName + "." + names[len(names)-1] +} + +func (g *generator) getTsFieldType(field *google_protobuf.FieldDescriptorProto) string { + if field.Type == nil { + return "" + } + + if field.TypeName != nil && strings.Contains(strings.ToLower(*field.TypeName), strings.ToLower(*field.Name+"Entry")) { + g.Fail("proto map type is not supported") + } + + if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_MESSAGE || + *field.Type == google_protobuf.FieldDescriptorProto_TYPE_ENUM { + return g.getTsTypeFromMessage(field.TypeName) + } + + return g.getTsFieldTypeForScalar(*field.Type) +} + +func (g *generator) isFieldRepeated(field *google_protobuf.FieldDescriptorProto) bool { + return field.Label != nil && *field.Label == google_protobuf.FieldDescriptorProto_LABEL_REPEATED +} + +func (g *generator) generateField(field *google_protobuf.FieldDescriptorProto, setPublic bool) { + if g.isFieldDeprecated(field) { + g.P("/** @deprecated */") + } + s := "" + if setPublic { + s += "public " + } + s += *field.JsonName + s += "?" + if field.GetTypeName() == ".google.protobuf.Timestamp" { + s += ": Date" + } else { + s += fmt.Sprintf(": %s", g.getTsFieldType(field)) + } + + if g.isFieldRepeated(field) { + s += "[]" + } + s += ";" + g.P(s) +} + +func (g *generator) generateMessageInterface(message *google_protobuf.DescriptorProto, messageMeta base.MessageMeta) { + g.P() + if messageMeta.IsDeprecated { + g.P("/**") + g.P("* @deprecated") + g.P("*/") + } + + g.P(fmt.Sprintf("export interface %s {", messageMeta.TsInterfaceName)) + for _, field := range message.Field { + g.generateField(field, false) + } + g.P("}") +} + +func (g *generator) generateConstructor(message *google_protobuf.DescriptorProto) { + g.P(fmt.Sprintf("constructor(attrs?: %s){", g.MessageMap[message].MessageName)) + g.P("Object.assign(this, attrs)") + g.P("}") +} + +func (g *generator) getFieldIndex(field *google_protobuf.FieldDescriptorProto) uint32 { + wireType := g.getWireType(field) + index := uint32(field.GetNumber()) + return ((index << 3) | wireType) >> 0 +} + +func (g *generator) getWireType(field *google_protobuf.FieldDescriptorProto) uint32 { + switch *field.Type { + case google_protobuf.FieldDescriptorProto_TYPE_DOUBLE: + return proto.WireFixed64 + case google_protobuf.FieldDescriptorProto_TYPE_FLOAT: + return proto.WireFixed32 + case google_protobuf.FieldDescriptorProto_TYPE_INT64, + google_protobuf.FieldDescriptorProto_TYPE_UINT64: + return proto.WireVarint + case google_protobuf.FieldDescriptorProto_TYPE_INT32, + google_protobuf.FieldDescriptorProto_TYPE_UINT32, + google_protobuf.FieldDescriptorProto_TYPE_ENUM: + return proto.WireVarint + case google_protobuf.FieldDescriptorProto_TYPE_FIXED64, + google_protobuf.FieldDescriptorProto_TYPE_SFIXED64: + return proto.WireFixed64 + case google_protobuf.FieldDescriptorProto_TYPE_FIXED32, + google_protobuf.FieldDescriptorProto_TYPE_SFIXED32: + return proto.WireFixed32 + case google_protobuf.FieldDescriptorProto_TYPE_BOOL: + return proto.WireVarint + case google_protobuf.FieldDescriptorProto_TYPE_STRING: + return proto.WireBytes + case google_protobuf.FieldDescriptorProto_TYPE_GROUP: + return proto.WireStartGroup + case google_protobuf.FieldDescriptorProto_TYPE_MESSAGE: + return proto.WireBytes + case google_protobuf.FieldDescriptorProto_TYPE_BYTES: + return proto.WireBytes + case google_protobuf.FieldDescriptorProto_TYPE_SINT32: + return proto.WireVarint + case google_protobuf.FieldDescriptorProto_TYPE_SINT64: + return proto.WireVarint + default: + g.Fail("undefined field type", field.Type.String()) + } + return 2 +} + +func (g *generator) isType64Bit(field *google_protobuf.FieldDescriptorProto) bool { + switch *field.Type { + case google_protobuf.FieldDescriptorProto_TYPE_INT64: + return true + case google_protobuf.FieldDescriptorProto_TYPE_UINT64: + return true + case google_protobuf.FieldDescriptorProto_TYPE_FIXED64: + return true + case google_protobuf.FieldDescriptorProto_TYPE_SFIXED64: + return true + case google_protobuf.FieldDescriptorProto_TYPE_SINT64: + return true + default: + return false + } +} + +func (g *generator) getWriteFunction(field *google_protobuf.FieldDescriptorProto) string { + switch *field.Type { + case google_protobuf.FieldDescriptorProto_TYPE_DOUBLE: + return "double" + case google_protobuf.FieldDescriptorProto_TYPE_FLOAT: + return "float" + case google_protobuf.FieldDescriptorProto_TYPE_INT64: + return "int64" + case google_protobuf.FieldDescriptorProto_TYPE_UINT64: + return "uint64" + case google_protobuf.FieldDescriptorProto_TYPE_INT32: + return "int32" + case google_protobuf.FieldDescriptorProto_TYPE_UINT32: + return "uint32" + case google_protobuf.FieldDescriptorProto_TYPE_ENUM: + return "int32" + case google_protobuf.FieldDescriptorProto_TYPE_FIXED64: + return "fixed64" + case google_protobuf.FieldDescriptorProto_TYPE_SFIXED64: + return "sfixed64" + case google_protobuf.FieldDescriptorProto_TYPE_FIXED32: + return "fixed32" + case google_protobuf.FieldDescriptorProto_TYPE_SFIXED32: + return "sfixed32" + case google_protobuf.FieldDescriptorProto_TYPE_BOOL: + return "bool" + case google_protobuf.FieldDescriptorProto_TYPE_STRING: + return "string" + case google_protobuf.FieldDescriptorProto_TYPE_MESSAGE: + return "MESSAGE" + case google_protobuf.FieldDescriptorProto_TYPE_BYTES: + return "bytes" + case google_protobuf.FieldDescriptorProto_TYPE_SINT32: + return "sint32" + case google_protobuf.FieldDescriptorProto_TYPE_SINT64: + return "sint64" + default: + g.Fail("undefined field type", field.Type.String()) + } + return "int32" +} + +func (g *generator) encodeEnumSwitch(field *google_protobuf.FieldDescriptorProto, name string, message *google_protobuf.DescriptorProto) { + enum := g.GetEnumTypeByName(*field.TypeName) + g.P(fmt.Sprintf("switch (val) {")) + typeName := g.getTsFieldType(field) + for _, value := range enum.Value { + g.P(fmt.Sprintf("case %s.%s:", typeName, *value.Name)) + g.P(fmt.Sprintf("return %d;", *value.Number)) + } + g.P("default:") + g.P("return") + g.P("};") +} + +func (g *generator) generateEncode(message *google_protobuf.DescriptorProto) { + messageMeta := g.MessageMap[message] + g.P("public encode(writer: protobufjs.Writer = protobufjs.Writer.create()){") + + if messageMeta.IsDeprecated { + g.P(fmt.Sprintf("logger.warn('message %s is deprecated');", *message.Name)) + } + for _, field := range message.Field { + name := *field.JsonName + g.P(fmt.Sprintf("if (this.%s != null) {", name)) + if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_ENUM { + if g.isFieldRepeated(field) { + g.P(fmt.Sprintf("for (const value of this.%s) {", name)) + g.P(fmt.Sprintf("const %s = (val => {", name)) + g.encodeEnumSwitch(field, name, message) + g.P("})(value);") + g.P(fmt.Sprintf("if (%s != null) {", name)) + g.P(fmt.Sprintf("writer.uint32(%d).int32(%s);", g.getFieldIndex(field), name)) + g.P("}") + g.P("}") + } else { + g.P(fmt.Sprintf("const %s = (val => {", name)) + g.encodeEnumSwitch(field, name, message) + g.P(fmt.Sprintf("})(this.%s);", name)) + g.P(fmt.Sprintf("if (%s != null) {", name)) + g.P(fmt.Sprintf("writer.uint32(%d).int32(%s);", g.getFieldIndex(field), name)) + g.P("}") + } + } else if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_MESSAGE { + if g.isFieldRepeated(field) { + g.P(fmt.Sprintf("for (const value of this.%s) {", name)) + g.P("if (!value) { continue; }") + if field.GetTypeName() == ".google.protobuf.Timestamp" { + g.P(fmt.Sprintf("const msg = new %sMsg({seconds: Math.floor(value.getTime() / 1000) , nanos: value.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName))) + } else { + g.P(fmt.Sprintf("const msg = new %sMsg(value);", g.getTsTypeFromMessage(field.TypeName))) + } + g.P(fmt.Sprintf("msg.encode(writer.uint32(%d).fork()).ldelim();", g.getFieldIndex(field))) + g.P("}") + } else { + if field.GetTypeName() == ".google.protobuf.Timestamp" { + g.P(fmt.Sprintf("const msg = new %sMsg({seconds: Math.floor(this.%s.getTime() / 1000) , nanos: this.%s.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName), name, name)) + } else { + g.P(fmt.Sprintf("const msg = new %sMsg(this.%s);", g.getTsTypeFromMessage(field.TypeName), name)) + } + g.P(fmt.Sprintf("msg.encode(writer.uint32(%d).fork()).ldelim();", g.getFieldIndex(field))) + } + } else { + if g.isFieldRepeated(field) { + g.P(fmt.Sprintf("for (const value of this.%s) {", name)) + g.P(fmt.Sprintf("writer.uint32(%d).%s(value);", g.getFieldIndex(field), g.getWriteFunction(field))) + g.P("}") + } else { + g.P(fmt.Sprintf("writer.uint32(%d).%s(this.%s);", g.getFieldIndex(field), g.getWriteFunction(field), name)) + } + } + g.P("}") + } + g.P("return writer") + g.P("}") +} + +func (g *generator) decodeEnumSwitch(field *google_protobuf.FieldDescriptorProto, name string, message *google_protobuf.DescriptorProto) { + enum := g.GetEnumTypeByName(*field.TypeName) + + g.P(fmt.Sprintf("switch (val) {")) + typeName := g.getTsFieldType(field) + for _, value := range enum.Value { + g.P(fmt.Sprintf("case %d:", *value.Number)) + g.P(fmt.Sprintf("return %s.%s;", typeName, *value.Name)) + } + g.P("default:") + g.P("return") + g.P("};") +} + +func (g *generator) generateDecode(message *google_protobuf.DescriptorProto) { + messageMeta := g.MessageMap[message] + g.P("public static decode(inReader: Uint8Array | protobufjs.Reader, length?: number){") + if messageMeta.IsDeprecated { + g.P(fmt.Sprintf("logger.warn('message %s is deprecated');", *message.Name)) + } + g.P("const reader = !(inReader instanceof protobufjs.Reader)") + g.P("? protobufjs.Reader.create(inReader)") + g.P(": inReader") + g.P("const end = length === undefined ? reader.len : reader.pos + length;") + g.P(fmt.Sprintf("const message = new %sMsg();", g.getTsTypeFromMessage(message.Name))) + g.P("while (reader.pos < end) {") + g.P("const tag = reader.uint32()") + g.P("switch (tag >>> 3) {") + for _, field := range message.Field { + name := *field.JsonName + g.P(fmt.Sprintf("case %d:", field.GetNumber())) + if g.isFieldDeprecated(field) { + g.P(fmt.Sprintf("logger.warn('field %s is deprecated in %s');", name, *message.Name)) + } + if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_ENUM { + if g.isFieldRepeated(field) { + assign := func() { + g.P(fmt.Sprintf("const %s = (((val) => {", name)) + g.decodeEnumSwitch(field, name, message) + g.P("})(reader.int32()));") + g.P(fmt.Sprintf("if (%s) {", name)) + g.P(fmt.Sprintf("message.%s.push(%s);", name, name)) + g.P("}") + } + g.P(fmt.Sprintf("if (!(message.%s && message.%s.length)) { message.%s = []; }", name, name, name)) + g.P("if ((tag & 7) === 2) {") + g.P("const end2 = reader.uint32() + reader.pos;") + g.P("while (reader.pos < end2) {") + assign() + g.P("}") + g.P("} else {") + assign() + g.P("}") + } else { + g.P(fmt.Sprintf("message.%s = ((val) => {", name)) + g.decodeEnumSwitch(field, name, message) + g.P("})(reader.int32());") + } + } else if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_MESSAGE { + if g.isFieldRepeated(field) { + g.P(fmt.Sprintf("if (!(message.%s && message.%s.length)) {", name, name)) + g.P(fmt.Sprintf("message.%s = [];", name)) + g.P("}") + if field.GetTypeName() == ".google.protobuf.Timestamp" { + g.P(fmt.Sprintf("const %s = %sMsg.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("message.%s.push(new Date(((%s.seconds || 0) * 1000) + ((%s.nanos || 0) / 1000000)));", name, name, name)) + } else { + g.P(fmt.Sprintf("message.%s.push(%sMsg.decode(reader, reader.uint32()));", name, g.getTsTypeFromMessage(field.TypeName))) + } + } else { + if field.GetTypeName() == ".google.protobuf.Timestamp" { + g.P(fmt.Sprintf("const %s = %sMsg.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName))) + g.P(fmt.Sprintf("message.%s = new Date(((%s.seconds || 0) * 1000) + ((%s.nanos || 0) / 1000000));", name, name, name)) + } else { + g.P(fmt.Sprintf("message.%s = %sMsg.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName))) + } + } + } else { + if g.isFieldRepeated(field) { + assign := func() { + if g.isType64Bit(field) { + g.P(fmt.Sprintf("const %s = reader.%s();", name, g.getWriteFunction(field))) + g.P(fmt.Sprintf("message.%s.push(new protobufjs.util.LongBits(%s.low >>> 0, %s.high >>> 0).toNumber());", name, name, name)) + } else if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_BYTES { + g.P(fmt.Sprintf("message.%s.push(new Uint8Array(reader.%s()));", name, g.getWriteFunction(field))) + } else { + g.P(fmt.Sprintf("message.%s.push(reader.%s());", name, g.getWriteFunction(field))) + } + } + g.P(fmt.Sprintf("if (!(message.%s && message.%s.length)) {", name, name)) + g.P(fmt.Sprintf("message.%s = [];", name)) + g.P("}") + + if (*field.Type != google_protobuf.FieldDescriptorProto_TYPE_STRING) && (*field.Type != google_protobuf.FieldDescriptorProto_TYPE_BYTES) { + g.P("if ((tag & 7) === 2) {") + g.P("const end2 = reader.uint32() + reader.pos;") + g.P("while (reader.pos < end2) {") + assign() + g.P("}") + g.P("} else {") + } + assign() + if (*field.Type != google_protobuf.FieldDescriptorProto_TYPE_STRING) && (*field.Type != google_protobuf.FieldDescriptorProto_TYPE_BYTES) { + g.P("}") + } + } else { + if g.isType64Bit(field) { + g.P(fmt.Sprintf("const %s = reader.%s();", name, g.getWriteFunction(field))) + g.P(fmt.Sprintf("message.%s = new protobufjs.util.LongBits(%s.low >>> 0, %s.high >>> 0).toNumber();", name, name, name)) + } else if *field.Type == google_protobuf.FieldDescriptorProto_TYPE_BYTES { + g.P(fmt.Sprintf("message.%s = new Uint8Array(reader.%s());", name, g.getWriteFunction(field))) + } else { + g.P(fmt.Sprintf("message.%s = reader.%s();", name, g.getWriteFunction(field))) + } + } + } + g.P("break;") + } + g.P("default:") + g.P("reader.skipType(tag & 7);") + g.P("break;") + g.P("}") + g.P("}") + g.P("return message;") + g.P("}") +} + +func (g *generator) generateMessageClass(message *google_protobuf.DescriptorProto, messageMeta base.MessageMeta) { + g.P() + if messageMeta.IsDeprecated { + g.P("/**") + g.P("* @deprecated") + g.P("*/") + } + g.P(fmt.Sprintf("export class %s implements I%s{", messageMeta.MessageName, messageMeta.TsInterfaceName)) + g.generateDecode(message) + for _, field := range message.Field { + g.generateField(field, true) + } + g.generateConstructor(message) + g.generateEncode(message) + g.P("}") +} + +func (g *generator) generateEnum(enum *google_protobuf.EnumDescriptorProto) { + g.P() + + g.P(fmt.Sprintf("export enum %s {", g.enumName(enum))) + + for _, value := range enum.Value { + g.P(fmt.Sprintf("%s = '%s',", *value.Name, *value.Name)) + } + + g.P(fmt.Sprint("}")) + +} + +func (g *generator) methodDeprecated(method *google_protobuf.MethodDescriptorProto) { + if g.isMethodDeprecated(method) { + g.P("/**") + g.P("* @deprecated") + g.P("*/") + } +} + +func (g *generator) methodDeprecatedLog(method *google_protobuf.MethodDescriptorProto) { + if g.isMethodDeprecated(method) { + g.P(fmt.Sprintf("logger.warn('method %s is deprecated');", *method.Name)) + } +} + +func (g *generator) generateDefinition(service *google_protobuf.ServiceDescriptorProto) { + g.P() + g.P(fmt.Sprintf("export const %sServiceDefinition = {", g.toLowerFirst(*service.Name))) + for _, method := range service.Method { + g.P(fmt.Sprintf("%s: {", g.toLowerFirst(*method.Name))) + + g.P(fmt.Sprintf("path: '/%s/%s',", *service.Name, *method.Name)) + var clientStreaming bool + if method.ClientStreaming == nil { + clientStreaming = false + } else { + clientStreaming = *method.ClientStreaming + } + g.P(fmt.Sprintf("requestStream: %s,", strconv.FormatBool(clientStreaming))) + var serverStreaming bool + if method.ServerStreaming == nil { + serverStreaming = false + } else { + serverStreaming = *method.ServerStreaming + } + g.P(fmt.Sprintf("responseStream: %s,", strconv.FormatBool(serverStreaming))) + requestType := g.getTsTypeFromMessage(method.InputType) + g.P(fmt.Sprintf("requestType: %sMsg,", requestType)) + responseType := g.getTsTypeFromMessage(method.OutputType) + g.P(fmt.Sprintf("responseType: %sMsg,", responseType)) + g.P(fmt.Sprintf("requestSerialize: (args: %s) => new %sMsg(args).encode().finish() as Buffer,", requestType, requestType)) + g.P(fmt.Sprintf("requestDeserialize: (argBuf: Buffer) => %sMsg.decode(argBuf),", requestType)) + g.P(fmt.Sprintf("responseSerialize: (args: %s) => new %sMsg(args).encode().finish() as Buffer,", responseType, responseType)) + g.P(fmt.Sprintf("responseDeserialize: (argBuf: Buffer) => %sMsg.decode(argBuf),", responseType)) + g.P("},") + } + g.P("}") +} + +func (g *generator) generateImplementation(service *google_protobuf.ServiceDescriptorProto) { + g.P() + + if g.isServiceDeprecated(service) { + g.P("/**") + g.P("* @deprecated") + g.P("*/") + } + g.P(fmt.Sprintf("export interface %sImplementation extends grpcts.Implementations {", gen.CamelCase(*service.Name))) + + for _, method := range service.Method { + g.methodDeprecated(method) + inputTypeName := g.getTsTypeFromMessage(method.InputType) + outputTypeName := g.getTsTypeFromMessage(method.OutputType) + if method.ServerStreaming != nil && *method.ServerStreaming && method.ClientStreaming != nil && *method.ClientStreaming { + g.P(fmt.Sprintf("%s(call: grpc.ServerDuplexStream<%s, %s>): void;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) + } else if method.ServerStreaming != nil && *method.ServerStreaming { + // TODO why there is no type for write stream? + g.P(fmt.Sprintf("%s(call: grpc.ServerWriteableStream<%s>): void;", g.toLowerFirst(*method.Name), inputTypeName)) + } else if method.ClientStreaming != nil && *method.ClientStreaming { + g.P(fmt.Sprintf("%s(call: grpc.ServerReadableStream<%s>): Promise<%s>;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) + g.P(fmt.Sprintf("%s(call: grpc.ServerReadableStream<%s>, callback: grpc.sendUnaryData<%s>): void;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) + } else { + g.P(fmt.Sprintf("%s(call: grpc.ServerUnaryCall<%s>): Promise<%s>;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) + g.P(fmt.Sprintf("%s(call: grpc.ServerUnaryCall<%s>, callback: grpc.sendUnaryData<%s>): void;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) + } + } + + g.P(fmt.Sprint("}")) + +} + +func (g *generator) generateClient(service *google_protobuf.ServiceDescriptorProto, packageName string, protoFileName string) { + g.P() + if g.isServiceDeprecated(service) { + g.P("/**") + g.P("* @deprecated") + g.P("*/") + } + g.P(fmt.Sprintf("export class %sClient extends grpcts.Client {", gen.CamelCase(*service.Name))) + g.P("constructor(address: string, credentials: grpc.ChannelCredentials, trace: grpcts.ClientTrace = nodeTrace, options?: object){") + g.P(fmt.Sprintf("super(%sServiceDefinition, address, credentials, trace, options);", g.toLowerFirst(*service.Name))) + g.P("}") + for _, method := range service.Method { + inputTypeName := g.getTsTypeFromMessage(method.InputType) + g.methodDeprecated(method) + if method.ServerStreaming != nil && *method.ServerStreaming && method.ClientStreaming != nil && *method.ClientStreaming { + outputTypeName := g.getTsTypeFromMessage(method.OutputType) + g.P(fmt.Sprintf("public %s(metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name))) + g.methodDeprecatedLog(method) + g.P(fmt.Sprintf("return super.makeBidiStreamRequest<%s, %s>('%s', metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) + g.P(fmt.Sprint("}")) + } else if method.ServerStreaming != nil && *method.ServerStreaming { + outputTypeName := g.getTsTypeFromMessage(method.OutputType) + g.P(fmt.Sprintf("public %s(req: %s, metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name), inputTypeName)) + g.methodDeprecatedLog(method) + g.P(fmt.Sprintf("return super.makeServerStreamRequest<%s, %s>('%s', req, metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) + g.P(fmt.Sprint("}")) + } else if method.ClientStreaming != nil && *method.ClientStreaming { + outputTypeName := g.getTsTypeFromMessage(method.OutputType) + g.P(fmt.Sprintf("public %s(metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name))) + g.methodDeprecatedLog(method) + g.P(fmt.Sprintf("return super.makeClientStreamRequest<%s, %s>('%s', metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) + g.P(fmt.Sprint("};")) + } else { + outputTypeName := g.getTsTypeFromMessage(method.OutputType) + g.P(fmt.Sprintf("public %s(req: %s, metadata?: grpcts.Metadata) {", g.toLowerFirst(*method.Name), inputTypeName)) + g.methodDeprecatedLog(method) + g.P(fmt.Sprintf("return super.makeUnaryRequest<%s, %s>('%s', req, metadata);", inputTypeName, outputTypeName, g.toLowerFirst(*method.Name))) + g.P(fmt.Sprint("};")) + } + } + + g.P(fmt.Sprint("}")) + +} + +func (g *generator) Make(protoFile *google_protobuf.FileDescriptorProto, protoFiles []*google_protobuf.FileDescriptorProto) (*plugin.CodeGeneratorResponse_File, error) { + g.protoFile = protoFile + + g.P("// GENERATED CODE -- DO NOT EDIT!") + + g.generateImports(protoFile, protoFiles) + g.P("import * as protobufjs from 'protobufjs/minimal';") + g.P("// @ts-ignore ignored as it's generated and it's difficult to predict if logger is needed") + g.P("import { logger } from '@join-com/gcloud-logger-trace';") + if len(protoFile.Service) > 0 { + g.generateGenericImports() + } + packageName := protoFile.GetPackage() + g.generateNamespace(packageName) + + for _, enum := range protoFile.EnumType { + g.generateEnum(enum) + } + + for _, messageMeta := range g.FilterMessageMeta(protoFile) { + g.generateMessageInterface(messageMeta.DescriptorProto, messageMeta) + g.generateMessageClass(messageMeta.DescriptorProto, messageMeta) + } + + for _, service := range protoFile.Service { + g.generateDefinition(service) + g.generateImplementation(service) + g.generateClient(service, *protoFile.Package, *protoFile.Name) + } + + g.P("}") + + file := &plugin.CodeGeneratorResponse_File{ + Name: proto.String(g.tsFileNameWithExt(protoFile.Name)), + Content: proto.String(g.String()), + } + g.Reset() + return file, nil +} + +func (g *generator) toLowerFirst(str string) string { + a := []rune(str) + a[0] = unicode.ToLower(a[0]) + return string(a) +} + +func (g *generator) Generate() { + g.Generator.Generate(g) +}