From 996117f763f842ce76239985b998b428e9aab810 Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Fri, 16 Apr 2021 14:01:38 +0200 Subject: [PATCH 1/8] fix: generated client type --- internal/generator/runer_generate_service.go | 12 ++++++++++-- tests/__tests__/v2/generated/Test.ts | 12 ++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/internal/generator/runer_generate_service.go b/internal/generator/runer_generate_service.go index 7bfa6db..5def935 100644 --- a/internal/generator/runer_generate_service.go +++ b/internal/generator/runer_generate_service.go @@ -92,7 +92,7 @@ func (r *Runner) generateTypescriptClientInterface(generatedFileStream *protogen r.P( generatedFileStream, "export interface I"+strcase.ToCamel(serviceSpec.GetName())+"Client", - "extends joinGRPC.IClient> ", + "extends joinGRPC.IClient ", ", joinGRPC.IExtendedClient {", ) r.indentLevel += 2 @@ -147,11 +147,19 @@ func (r *Runner) generateTypescriptClient(generatedFileStream *protogen.Generate r.P( generatedFileStream, "export class "+strcase.ToCamel(serviceSpec.GetName())+"Client", - "extends joinGRPC.Client> ", + "extends joinGRPC.Client ", "implements I"+strcase.ToCamel(serviceSpec.GetName())+"Client {", ) r.indentLevel += 2 + r.P(generatedFileStream, "constructor(public readonly config: joinGRPC.IClientConfig) {") + r.indentLevel += 2 + + r.P(generatedFileStream, "super(config, '"+r.currentPackage+"."+serviceSpec.GetName()+"')") + + r.indentLevel -= 2 + r.P(generatedFileStream, "}\n") + for _, methodSpec := range serviceSpec.GetMethod() { r.generateTypescriptClientMethod(generatedFileStream, serviceSpec, methodSpec) } diff --git a/tests/__tests__/v2/generated/Test.ts b/tests/__tests__/v2/generated/Test.ts index 57e52f3..1180e27 100644 --- a/tests/__tests__/v2/generated/Test.ts +++ b/tests/__tests__/v2/generated/Test.ts @@ -486,9 +486,7 @@ export namespace Foo { } export interface IUsersClient - extends joinGRPC.IClient< - grpc.ServiceDefinition - >, + extends joinGRPC.IClient, joinGRPC.IExtendedClient { Find( request: IRequest, @@ -511,8 +509,14 @@ export namespace Foo { } export class UsersClient - extends joinGRPC.Client> + extends joinGRPC.Client implements IUsersClient { + constructor( + public readonly config: joinGRPC.IClientConfig + ) { + super(config, 'foo.Users') + } + public Find( request: IRequest, metadata?: Record, From 894e25515bcc2f87a92bf4c5a18c67a33da9208f Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Fri, 16 Apr 2021 14:07:38 +0200 Subject: [PATCH 2/8] build: bump @join-com/grpc version --- tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/package.json b/tests/package.json index 65f0992..eea9e61 100644 --- a/tests/package.json +++ b/tests/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@join-com/gcloud-logger-trace": "^0.1.17", - "@join-com/grpc": "^0.1.1", + "@join-com/grpc": "^0.1.2", "@join-com/grpc-ts": "^2.0.2", "grpc": "^1.24.6", "protobufjs": "^6.10.2" From acee53011e69d84a6e5983dc032bfaa844f6efdb Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Sat, 17 Apr 2021 12:52:44 +0200 Subject: [PATCH 3/8] fix!: generated method paths - remove legacy code generator --- .circleci/config.yml | 5 +- build.sh | 6 +- go.mod | 1 - internal/generator/runer_generate_service.go | 14 +- legacy/base/generator.go | 261 ------- legacy/generator/generator.go | 739 ------------------ main.go | 22 +- tests/__tests__/{v2 => }/classes.test.ts | 0 .../__tests__/{v2 => }/customOptions.test.ts | 0 tests/__tests__/{v2 => }/generated/Test.ts | 26 +- .../{v2 => }/generated/common/Common.ts | 0 .../{v2 => }/generated/common/Extra.ts | 0 .../generated/google/protobuf/Timestamp.ts | 0 .../generated => generatedLegacy}/Test.ts | 0 .../common/Common.ts | 0 .../google/protobuf/Timestamp.ts | 0 tests/__tests__/{v2 => }/interfaces.test.ts | 0 tests/__tests__/legacy/decode.test.ts | 128 --- tests/__tests__/legacy/encode.test.ts | 141 ---- .../legacy/proto/common/common.proto | 11 - .../__tests__/legacy/proto/common/extra.proto | 11 - tests/__tests__/legacy/proto/test.proto | 100 --- .../{v2 => }/legacyCompatibility.test.ts | 0 .../{v2 => }/proto/common/common.proto | 0 .../{v2 => }/proto/common/extra.proto | 0 .../proto/google/protobuf/descriptor.proto | 0 .../proto/google/protobuf/duration.proto | 0 .../proto/google/protobuf/empty.proto | 0 .../proto/google/protobuf/timestamp.proto | 0 tests/__tests__/{v2 => }/proto/options.proto | 0 tests/__tests__/{v2 => }/proto/test.proto | 0 .../v2/proto/google/protobuf/empty.proto | 52 -- .../v2/proto/google/protobuf/timestamp.proto | 147 ---- tests/package.json | 14 +- 34 files changed, 38 insertions(+), 1640 deletions(-) delete mode 100644 legacy/base/generator.go delete mode 100644 legacy/generator/generator.go rename tests/__tests__/{v2 => }/classes.test.ts (100%) rename tests/__tests__/{v2 => }/customOptions.test.ts (100%) rename tests/__tests__/{v2 => }/generated/Test.ts (96%) rename tests/__tests__/{v2 => }/generated/common/Common.ts (100%) rename tests/__tests__/{v2 => }/generated/common/Extra.ts (100%) rename tests/__tests__/{v2 => }/generated/google/protobuf/Timestamp.ts (100%) rename tests/__tests__/{legacy/generated => generatedLegacy}/Test.ts (100%) rename tests/__tests__/{legacy/generated => generatedLegacy}/common/Common.ts (100%) rename tests/__tests__/{legacy/generated => generatedLegacy}/google/protobuf/Timestamp.ts (100%) rename tests/__tests__/{v2 => }/interfaces.test.ts (100%) delete mode 100644 tests/__tests__/legacy/decode.test.ts delete mode 100644 tests/__tests__/legacy/encode.test.ts delete mode 100644 tests/__tests__/legacy/proto/common/common.proto delete mode 100644 tests/__tests__/legacy/proto/common/extra.proto delete mode 100644 tests/__tests__/legacy/proto/test.proto rename tests/__tests__/{v2 => }/legacyCompatibility.test.ts (100%) rename tests/__tests__/{v2 => }/proto/common/common.proto (100%) rename tests/__tests__/{v2 => }/proto/common/extra.proto (100%) rename tests/__tests__/{v2 => }/proto/google/protobuf/descriptor.proto (100%) rename tests/__tests__/{v2 => }/proto/google/protobuf/duration.proto (100%) rename tests/__tests__/{legacy => }/proto/google/protobuf/empty.proto (100%) rename tests/__tests__/{legacy => }/proto/google/protobuf/timestamp.proto (100%) rename tests/__tests__/{v2 => }/proto/options.proto (100%) rename tests/__tests__/{v2 => }/proto/test.proto (100%) delete mode 100644 tests/__tests__/v2/proto/google/protobuf/empty.proto delete mode 100644 tests/__tests__/v2/proto/google/protobuf/timestamp.proto diff --git a/.circleci/config.yml b/.circleci/config.yml index f813896..34a1ba2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,11 +22,8 @@ commands: name: Compile command: cd ./tests && yarn compile - run: - name: Generate TS code (legacy) + name: Generate TS code command: cd ./tests && yarn proto:build - - run: - name: Generate TS code (v2) - command: cd ./tests && yarn v2:build - run: name: Lint generated code command: cd ./tests && yarn lint diff --git a/build.sh b/build.sh index 9a2f117..fd4d682 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,7 @@ #!/bin/sh -go build -o ./dist/protoc-gen-ts +# Building binary +go build -o ./dist/protoc-gen-tsx + +# Stripping symbols to make the binary more lightweight +strip -u -r -S ./dist/protoc-gen-tsx diff --git a/go.mod b/go.mod index e9d5156..b6af6ce 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/join-com/protoc-gen-ts go 1.16 require ( - github.com/golang/protobuf v1.5.2 // Legacy import github.com/iancoleman/strcase v0.1.3 google.golang.org/protobuf v1.26.0 ) diff --git a/internal/generator/runer_generate_service.go b/internal/generator/runer_generate_service.go index 5def935..991c387 100644 --- a/internal/generator/runer_generate_service.go +++ b/internal/generator/runer_generate_service.go @@ -92,8 +92,7 @@ func (r *Runner) generateTypescriptClientInterface(generatedFileStream *protogen r.P( generatedFileStream, "export interface I"+strcase.ToCamel(serviceSpec.GetName())+"Client", - "extends joinGRPC.IClient ", - ", joinGRPC.IExtendedClient {", + "extends joinGRPC.IExtendedClient {", ) r.indentLevel += 2 @@ -147,7 +146,7 @@ func (r *Runner) generateTypescriptClient(generatedFileStream *protogen.Generate r.P( generatedFileStream, "export class "+strcase.ToCamel(serviceSpec.GetName())+"Client", - "extends joinGRPC.Client ", + "extends joinGRPC.Client ", "implements I"+strcase.ToCamel(serviceSpec.GetName())+"Client {", ) r.indentLevel += 2 @@ -206,14 +205,15 @@ func (r *Runner) generateTypescriptClientMethod(generatedFileStream *protogen.Ge r.P(generatedFileStream, "): "+returnType+" {") r.indentLevel += 2 + methodPath := "/" + r.currentPackage + "." + serviceSpec.GetName() + "/" + methodName if clientStream && serverStrean { - r.P(generatedFileStream, "return this.makeBidiStreamRequest('"+methodName+"', metadata, options)") + r.P(generatedFileStream, "return this.makeBidiStreamRequest('"+methodPath+"', metadata, options)") } else if !clientStream && !serverStrean { - r.P(generatedFileStream, "return this.makeUnaryRequest('"+methodName+"', request, metadata, options)") + r.P(generatedFileStream, "return this.makeUnaryRequest('"+methodPath+"', request, metadata, options)") } else if clientStream { - r.P(generatedFileStream, "return this.makeClientStreamRequest('"+methodName+"', metadata, options)") + r.P(generatedFileStream, "return this.makeClientStreamRequest('"+methodPath+"', metadata, options)") } else { // if serverStream - r.P(generatedFileStream, "return this.makeServerStreamRequest('"+methodName+"', request, metadata, options)") + r.P(generatedFileStream, "return this.makeServerStreamRequest('"+methodPath+"', request, metadata, options)") } r.indentLevel -= 2 diff --git a/legacy/base/generator.go b/legacy/base/generator.go deleted file mode 100644 index 580f18d..0000000 --- a/legacy/base/generator.go +++ /dev/null @@ -1,261 +0,0 @@ -package base - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path" - "regexp" - "strings" - - "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" -) - -var camel = regexp.MustCompile("(^[^A-Z0-9]*|[A-Z0-9]*)([A-Z0-9][^A-Z]+|$)") - -type Dependency struct { - protoFileName string - depFileName string -} - -type fileMaker interface { - Make(*google_protobuf.FileDescriptorProto, []*google_protobuf.FileDescriptorProto) (*plugin.CodeGeneratorResponse_File, error) -} - -type Generator struct { - *gen.Generator - indent string - enumNameToObject map[string]*google_protobuf.EnumDescriptorProto - reader io.Reader - writer io.Writer - dependencyNameImportMap map[Dependency]string - messageToFileMap map[string]string -} - -// New creates a new base generator -func New() *Generator { - return &Generator{ - Generator: gen.New(), - reader: os.Stdin, - writer: os.Stdout, - } -} - -// P prints the arguments to the generated output. It handles strings and int32s, plus -// handling indirections because they may be *string, etc. -func (g *Generator) P(str ...interface{}) { - g.WriteString(g.indent) - for _, v := range str { - switch s := v.(type) { - case string: - g.WriteString(s) - case *string: - g.WriteString(*s) - case bool: - fmt.Fprintf(g, "%t", s) - case *bool: - fmt.Fprintf(g, "%t", *s) - case int: - fmt.Fprintf(g, "%d", s) - case *int32: - fmt.Fprintf(g, "%d", *s) - case *int64: - fmt.Fprintf(g, "%d", *s) - case float64: - fmt.Fprintf(g, "%g", s) - case *float64: - fmt.Fprintf(g, "%g", *s) - default: - g.Fail(fmt.Sprintf("unknown type in printer: %T", v)) - } - } - g.WriteByte('\n') -} - -// In Indents the output one tab stop. -func (g *Generator) In() { g.indent += " " } - -// Out unindents the output one tab stop. -func (g *Generator) Out() { - if len(g.indent) > 0 { - g.indent = g.indent[2:] - } -} - -// Error reports a problem, including an error, and exits the program. -func (g *Generator) Error(err error, msgs ...string) { - s := strings.Join(msgs, " ") + ":" + err.Error() - log.Print("protoc-gen-ts: error:", s) - os.Exit(1) -} - -// Fail reports a problem and exits the program. -func (g *Generator) Fail(msgs ...string) { - s := strings.Join(msgs, " ") - log.Print("protoc-gen-ts: error:", s) - os.Exit(1) -} - -// sideEffect calls some methods of the embedded generator from protoc-gen-go -// to make it possible to get object name by type name (via TypeName). -func (g *Generator) sideEffect() { - g.CommandLineParameters(g.Request.GetParameter()) - g.BuildEnumNameMap(g.Request) - g.BuildImportsMap(g.Request) - g.BuildMessageOrEnumToFileMap(g.Request) - g.Reset() -} - -func (g *Generator) ProtoFileBaseName(name string) string { - if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" { - name = name[:len(name)-len(ext)] - } - return name -} - -func (g *Generator) generate(maker fileMaker, request *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, error) { - response := new(plugin.CodeGeneratorResponse) - for _, protoFile := range request.ProtoFile { - file, err := maker.Make(protoFile, request.ProtoFile) - if err != nil { - return response, err - } - response.File = append(response.File, file) - } - return response, nil -} - -func (g *Generator) Generate(maker fileMaker) { - input, err := ioutil.ReadAll(g.reader) - if err != nil { - g.Error(err, "reading input") - } - - request := g.Request - if err := proto.Unmarshal(input, request); err != nil { - g.Error(err, "parsing input proto") - } - - if len(request.FileToGenerate) == 0 { - g.Fail("no files to generate") - } - - g.sideEffect() - - response, err := g.generate(maker, request) - if err != nil { - g.Error(err, "failed to generate files from proto") - } - - output, err := proto.Marshal(response) - if err != nil { - g.Error(err, "failed to marshal output proto") - } - _, err = g.writer.Write(output) - if err != nil { - g.Error(err, "failed to write output proto") - } -} - -func (g *Generator) BuildEnumNameMap(request *plugin.CodeGeneratorRequest) { - g.enumNameToObject = make(map[string]*google_protobuf.EnumDescriptorProto) - for _, f := range request.ProtoFile { - // The names in this loop are defined by the proto world, not us, so the - // package name may be empty. If so, the dotted package name of X will - // be ".X"; otherwise it will be ".pkg.X". - dottedPkg := "." + f.GetPackage() - if dottedPkg != "." { - dottedPkg += "." - } - - for _, desc := range f.EnumType { - name := dottedPkg + *desc.Name - g.enumNameToObject[name] = desc - } - } -} - -func (g *Generator) BuildImportsMap(request *plugin.CodeGeneratorRequest) { - var exists = struct{}{} - g.dependencyNameImportMap = make(map[Dependency]string) - for _, protoFile := range request.ProtoFile { - usedImportNames := make(map[string]struct{}) - for _, dependency := range protoFile.Dependency { - var depProtoFile *google_protobuf.FileDescriptorProto - for _, extProtoFile := range request.ProtoFile { - depProtoFileName := *extProtoFile.Name - - if depProtoFileName == dependency { - depProtoFile = extProtoFile - } - } - - packageName := depProtoFile.GetPackage() - namespaceName := g.namespaceName(packageName) - importName := namespaceName - if _, ok := usedImportNames[namespaceName]; ok { - splits := strings.Split(*depProtoFile.Name, "/") - fileNameWithExt := splits[len(splits)-1] - fileNameSplit := strings.Split(fileNameWithExt, ".") - importName = importName + gen.CamelCase(fileNameSplit[0]) - } - usedImportNames[namespaceName] = exists - dep := Dependency{protoFileName: *protoFile.Name, depFileName: *depProtoFile.Name} - g.dependencyNameImportMap[dep] = importName - } - } -} - -func (g *Generator) BuildMessageOrEnumToFileMap(request *plugin.CodeGeneratorRequest) { - g.messageToFileMap = make(map[string]string) - for _, f := range request.ProtoFile { - // The names in this loop are defined by the proto world, not us, so the - // package name may be empty. If so, the dotted package name of X will - // be ".X"; otherwise it will be ".pkg.X". - dottedPkg := "." + f.GetPackage() - if dottedPkg != "." { - dottedPkg += "." - } - - for _, desc := range f.MessageType { - name := dottedPkg + *desc.Name - g.messageToFileMap[name] = f.GetName() - } - - for _, desc := range f.EnumType { - name := dottedPkg + *desc.Name - g.messageToFileMap[name] = f.GetName() - } - } -} - -func (g *Generator) namespaceName(packageName string) string { - splits := strings.Split(packageName, ".") - camelCaseName := "" - for _, name := range splits { - a := []string{camelCaseName, gen.CamelCase(name)} - camelCaseName = strings.Join(a, "") - } - - return camelCaseName -} - -func (g *Generator) GetEnumTypeByName(name string) *google_protobuf.EnumDescriptorProto { - return g.enumNameToObject[name] -} - -func (g *Generator) GetImportName(protoFileName string, depFileName string) string { - dep := Dependency{protoFileName: protoFileName, depFileName: depFileName} - return g.dependencyNameImportMap[dep] -} - -func (g *Generator) GetImportNameForMessage(protoFileName string, message string) string { - depFileName := g.messageToFileMap[message] - dep := Dependency{protoFileName: protoFileName, depFileName: depFileName} - return g.dependencyNameImportMap[dep] -} diff --git a/legacy/generator/generator.go b/legacy/generator/generator.go deleted file mode 100644 index e638548..0000000 --- a/legacy/generator/generator.go +++ /dev/null @@ -1,739 +0,0 @@ -package generator - -import ( - "fmt" - "strconv" - "strings" - "unicode" - - "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" - "github.com/join-com/protoc-gen-ts/legacy/base" -) - -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 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) namespaceName(packageName string) string { - splits := strings.Split(packageName, ".") - camelCaseName := "" - for _, name := range splits { - a := []string{camelCaseName, gen.CamelCase(name)} - camelCaseName = strings.Join(a, "") - } - - return camelCaseName -} - -func (g *generator) generateNamespace(packageName string) { - g.P(fmt.Sprintf("export namespace %s {", g.namespaceName(packageName))) -} - -func (g *generator) messageName(message *google_protobuf.DescriptorProto) string { - return gen.CamelCase(*message.Name) -} - -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) isFieldDeprecated(field *google_protobuf.FieldDescriptorProto) bool { - if field.Options == nil || field.Options.Deprecated == nil { - return false - } - return *field.Options.Deprecated -} - -func (g *generator) isMessageDeprecated(field *google_protobuf.DescriptorProto) 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, 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 interfaceName - } - return importName + "." + interfaceName -} - -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, *field.Type == google_protobuf.FieldDescriptorProto_TYPE_MESSAGE) - } - - 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) { - g.P() - if g.isMessageDeprecated(message) { - g.P("/**") - g.P("* @deprecated") - g.P("*/") - } - g.P(fmt.Sprintf("export interface I%s {", g.messageName(message))) - for _, field := range message.Field { - g.generateField(field, false) - } - g.P("}") -} - -func (g *generator) generateConstructor(message *google_protobuf.DescriptorProto) { - name := g.messageName(message) - g.P(fmt.Sprintf("constructor(attrs?: I%s){", name)) - 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("switch (val) {") - for _, value := range enum.Value { - g.P(fmt.Sprintf("case '%s':", *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) { - g.P("public encode(writer: protobufjs.Writer = protobufjs.Writer.create()){") - - if g.isMessageDeprecated(message) { - 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 %s({seconds: Math.floor(value.getTime() / 1000) , nanos: value.getMilliseconds() * 1000000});", g.getTsTypeFromMessage(field.TypeName, false))) - } else { - 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 %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 %s(this.%s);", g.getTsTypeFromMessage(field.TypeName, false), 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("switch (val) {") - for _, value := range enum.Value { - g.P(fmt.Sprintf("case %d:", *value.Number)) - g.P(fmt.Sprintf("return '%s';", *value.Name)) - } - g.P("default:") - g.P("return") - g.P("};") -} - -func (g *generator) generateDecode(message *google_protobuf.DescriptorProto) { - g.P("public static decode(inReader: Uint8Array | protobufjs.Reader, length?: number){") - if g.isMessageDeprecated(message) { - 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 %s();", g.getTsTypeFromMessage(message.Name, false))) - 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 = %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(%s.decode(reader, reader.uint32()));", name, g.getTsTypeFromMessage(field.TypeName, false))) - } - } else { - if field.GetTypeName() == ".google.protobuf.Timestamp" { - 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 = %s.decode(reader, reader.uint32());", name, g.getTsTypeFromMessage(field.TypeName, false))) - } - } - } 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) { - g.P() - if g.isMessageDeprecated(message) { - g.P("/**") - g.P("* @deprecated") - g.P("*/") - } - name := g.messageName(message) - g.P(fmt.Sprintf("export class %s implements I%s{", name, name)) - 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() - - var s []string - for _, value := range enum.Value { - s = append(s, "'"+*value.Name+"'") - } - g.P(fmt.Sprintf("export type %s = %s", g.enumName(enum), strings.Join(s, " | "))) -} - -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, 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("}") -} - -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 I%sImplementation extends grpcts.Implementations {", gen.CamelCase(*service.Name))) - - for _, method := range service.Method { - g.methodDeprecated(method) - 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: grpcts.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: grpcts.grpc.ServerWriteableStream<%s>): void;", g.toLowerFirst(*method.Name), inputTypeName)) - } else if method.ClientStreaming != nil && *method.ClientStreaming { - g.P(fmt.Sprintf("%s(call: grpcts.grpc.ServerReadableStream<%s>): Promise<%s>;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) - g.P(fmt.Sprintf("%s(call: grpcts.grpc.ServerReadableStream<%s>, callback: grpcts.grpc.sendUnaryData<%s>): void;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) - } else { - g.P(fmt.Sprintf("%s(call: grpcts.grpc.ServerUnaryCall<%s>): Promise<%s>;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) - g.P(fmt.Sprintf("%s(call: grpcts.grpc.ServerUnaryCall<%s>, callback: grpcts.grpc.sendUnaryData<%s>): void;", g.toLowerFirst(*method.Name), inputTypeName, outputTypeName)) - } - } - - g.P("}") - -} - -func (g *generator) generateClientConfigType() { - g.P() - g.P("export type ClientConfig = Omit;") -} - -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(config: ClientConfig){") - g.P(fmt.Sprintf("super({ definition: %sServiceDefinition, trace: nodeTrace, ...config });", g.toLowerFirst(*service.Name))) - g.P("}") - for _, method := range service.Method { - 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, 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("}") - } else if method.ServerStreaming != nil && *method.ServerStreaming { - 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("}") - } else if method.ClientStreaming != nil && *method.ClientStreaming { - 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("};") - } else { - 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))) - g.P("};") - } - } - - g.P("}") - -} - -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 _, message := range protoFile.MessageType { - g.generateMessageInterface(message) - g.generateMessageClass(message) - } - - for _, service := range protoFile.Service { - g.generateDefinition(service) - g.generateImplementation(service) - g.generateClientConfigType() - 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) -} diff --git a/main.go b/main.go index 330da9d..5fbf991 100644 --- a/main.go +++ b/main.go @@ -1,33 +1,13 @@ package main import ( - "fmt" "log" "os" "github.com/join-com/protoc-gen-ts/internal/generator" - "github.com/join-com/protoc-gen-ts/internal/utils" - legacyGenerator "github.com/join-com/protoc-gen-ts/legacy/generator" ) func main() { log.SetOutput(os.Stderr) - generatorVersion, isGeneratorConfigured := os.LookupEnv("PROTOC_TS_GENERATOR") - if !isGeneratorConfigured { - generatorVersion = "LEGACY" - } - - if generatorVersion == "LEGACY" { - g := legacyGenerator.New() - g.Generate() - } else if generatorVersion == "V2" { - generator.Generate() - } else { - utils.LogError( - fmt.Sprintf("invalid generator version (%s)", generatorVersion), - "acceptable values for the 'PROTOC_TS_GENERATOR' environment variable are:", - " - LEGACY", - " - V2", - ) - } + generator.Generate() } diff --git a/tests/__tests__/v2/classes.test.ts b/tests/__tests__/classes.test.ts similarity index 100% rename from tests/__tests__/v2/classes.test.ts rename to tests/__tests__/classes.test.ts diff --git a/tests/__tests__/v2/customOptions.test.ts b/tests/__tests__/customOptions.test.ts similarity index 100% rename from tests/__tests__/v2/customOptions.test.ts rename to tests/__tests__/customOptions.test.ts diff --git a/tests/__tests__/v2/generated/Test.ts b/tests/__tests__/generated/Test.ts similarity index 96% rename from tests/__tests__/v2/generated/Test.ts rename to tests/__tests__/generated/Test.ts index 1180e27..49a7129 100644 --- a/tests/__tests__/v2/generated/Test.ts +++ b/tests/__tests__/generated/Test.ts @@ -486,8 +486,7 @@ export namespace Foo { } export interface IUsersClient - extends joinGRPC.IClient, - joinGRPC.IExtendedClient { + extends joinGRPC.IExtendedClient { Find( request: IRequest, metadata?: Record, @@ -509,7 +508,7 @@ export namespace Foo { } export class UsersClient - extends joinGRPC.Client + extends joinGRPC.Client implements IUsersClient { constructor( public readonly config: joinGRPC.IClientConfig @@ -522,14 +521,23 @@ export namespace Foo { metadata?: Record, options?: grpc.CallOptions ): joinGRPC.IUnaryRequest { - return this.makeUnaryRequest('Find', request, metadata, options) + return this.makeUnaryRequest( + '/foo.Users/Find', + request, + metadata, + options + ) } public FindClientStream( metadata?: Record, options?: grpc.CallOptions ): joinGRPC.IClientStreamRequest { - return this.makeClientStreamRequest('FindClientStream', metadata, options) + return this.makeClientStreamRequest( + '/foo.Users/FindClientStream', + metadata, + options + ) } public FindServerStream( @@ -538,7 +546,7 @@ export namespace Foo { options?: grpc.CallOptions ): grpc.ClientReadableStream { return this.makeServerStreamRequest( - 'FindServerStream', + '/foo.Users/FindServerStream', request, metadata, options @@ -549,7 +557,11 @@ export namespace Foo { metadata?: Record, options?: grpc.CallOptions ): grpc.ClientDuplexStream { - return this.makeBidiStreamRequest('FindBidiStream', metadata, options) + return this.makeBidiStreamRequest( + '/foo.Users/FindBidiStream', + metadata, + options + ) } } } diff --git a/tests/__tests__/v2/generated/common/Common.ts b/tests/__tests__/generated/common/Common.ts similarity index 100% rename from tests/__tests__/v2/generated/common/Common.ts rename to tests/__tests__/generated/common/Common.ts diff --git a/tests/__tests__/v2/generated/common/Extra.ts b/tests/__tests__/generated/common/Extra.ts similarity index 100% rename from tests/__tests__/v2/generated/common/Extra.ts rename to tests/__tests__/generated/common/Extra.ts diff --git a/tests/__tests__/v2/generated/google/protobuf/Timestamp.ts b/tests/__tests__/generated/google/protobuf/Timestamp.ts similarity index 100% rename from tests/__tests__/v2/generated/google/protobuf/Timestamp.ts rename to tests/__tests__/generated/google/protobuf/Timestamp.ts diff --git a/tests/__tests__/legacy/generated/Test.ts b/tests/__tests__/generatedLegacy/Test.ts similarity index 100% rename from tests/__tests__/legacy/generated/Test.ts rename to tests/__tests__/generatedLegacy/Test.ts diff --git a/tests/__tests__/legacy/generated/common/Common.ts b/tests/__tests__/generatedLegacy/common/Common.ts similarity index 100% rename from tests/__tests__/legacy/generated/common/Common.ts rename to tests/__tests__/generatedLegacy/common/Common.ts diff --git a/tests/__tests__/legacy/generated/google/protobuf/Timestamp.ts b/tests/__tests__/generatedLegacy/google/protobuf/Timestamp.ts similarity index 100% rename from tests/__tests__/legacy/generated/google/protobuf/Timestamp.ts rename to tests/__tests__/generatedLegacy/google/protobuf/Timestamp.ts diff --git a/tests/__tests__/v2/interfaces.test.ts b/tests/__tests__/interfaces.test.ts similarity index 100% rename from tests/__tests__/v2/interfaces.test.ts rename to tests/__tests__/interfaces.test.ts diff --git a/tests/__tests__/legacy/decode.test.ts b/tests/__tests__/legacy/decode.test.ts deleted file mode 100644 index 607a3eb..0000000 --- a/tests/__tests__/legacy/decode.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import * as path from 'path' -import { Foo } from './generated/Test' -import { loadSync } from 'protobufjs' - -const baseValues = { - fieldInt32: 123, - fieldInt32Repeated: [123, 12312], - fieldInt64: 12321313, - fieldInt64Repeated: [1333023, 12000312], - fieldDouble: 1234.1221231323, - fieldDoubleRepeated: [1234.1221231323], - fieldFloat: 9999.1, - fieldFloatRepeated: [9999.1], - fieldUint32: 11119, - fieldUint32Repeated: [11119], - fieldUint64: 114119, - fieldUint64Repeated: [161119], - fieldSint32: 13123, - fieldSint32Repeated: [13123, 1312312], - fieldFixed32: 123123, - fieldFixed32Repeated: [3223, 12312], - fieldFixed64: 123123, - fieldFixed64Repeated: [3223, 12312], - fieldSfixed32: 123123, - fieldSfixed32Repeated: [3223, 12312], - fieldSfixed64: 123123, - fieldSfixed64Repeated: [3223, 12312], - fieldBool: true, - fieldBoolRepeated: [true, false, true], - fieldString: 'foo', - fieldStringRepeated: ['foo', 'bar'], - fieldBytes: new Uint8Array([21, 31]), - fieldBytesRepeated: [new Uint8Array([21, 31]), new Uint8Array([2, 31])], - fieldEnum: 'UNKNOWN', - fieldEnumRepeated: ['EDIT', 'VIEW'], - message: { - title: 'msg', - }, - messageRepeated: [ - { - title: 'msg1', - }, - { - title: 'msg2', - }, - ], - timestamp: { seconds: 1414841073, nanos: 123000000 }, - timestampRepeated: [ - { seconds: 1393412400, nanos: 234000000 }, - { seconds: 1369562410, nanos: 221000000 }, - ], -} - -describe('decode', () => { - const values = baseValues - - const root = loadSync(path.join(__dirname, 'proto', 'test.proto')) - const PbTest = root.lookupType('foo.Test') - let buffer: Uint8Array - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let decoded: Foo.Test & Record - - beforeEach(() => { - const message = PbTest.fromObject(values) - buffer = PbTest.encode(message).finish() - decoded = Foo.Test.decode(buffer) - }) - - describe.each([ - 'fieldInt32', - 'fieldInt64', - 'fieldDouble', - 'fieldUint32', - 'fieldUint64', - 'fieldSint32', - 'fieldFixed32', - 'fieldFixed64', - 'fieldSfixed32', - 'fieldSfixed64', - 'fieldBool', - 'fieldString', - 'fieldEnum', - 'fieldBytes', - 'message', - ])('%s', (fieldName: keyof typeof decoded) => { - it(`decodes ${fieldName}`, () => { - expect(decoded[fieldName]).toBeDefined() - expect(decoded[fieldName]).toEqual( - values[fieldName as keyof typeof values] - ) - }) - - it(`decodes ${fieldName}Repeated`, () => { - const name = `${fieldName}Repeated` - expect(decoded[name]).toBeDefined() - expect(decoded[name]).toEqual(values[name as keyof typeof values]) - }) - }) - - describe('timestamp', () => { - it('encodes timestamp', () => { - expect(decoded.timestamp).toBeDefined() - expect(decoded.timestamp).toEqual(new Date('2014-11-01T11:24:33.123Z')) - }) - - it('encodes timestampRepeated', () => { - expect(decoded.timestampRepeated).toBeDefined() - expect(decoded.timestampRepeated).toEqual([ - new Date('2014-02-26T11:00:00.234Z'), - new Date('2013-05-26T10:00:10.221Z'), - ]) - }) - }) - - describe('fieldFloat', () => { - it('encodes fieldFloat', () => { - expect(decoded.fieldFloat).toBeDefined() - expect(decoded.fieldFloat).toEqual(Math.fround(values.fieldFloat)) - }) - - it('encodes fieldFloatRepeated', () => { - expect(decoded.fieldFloatRepeated).toBeDefined() - expect(decoded.fieldFloatRepeated).toEqual( - values.fieldFloatRepeated.map(Math.fround) - ) - }) - }) -}) diff --git a/tests/__tests__/legacy/encode.test.ts b/tests/__tests__/legacy/encode.test.ts deleted file mode 100644 index 65701b7..0000000 --- a/tests/__tests__/legacy/encode.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as path from 'path' -import { Type, loadSync } from 'protobufjs' -import { Foo } from './generated/Test' - -let PbTest: Type -beforeAll(() => { - const root = loadSync(path.join(__dirname, 'proto', 'test.proto')) - PbTest = root.lookupType('foo.Test') -}) - -describe('encode', () => { - let buffer: Uint8Array - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let decoded: Record - const values: Foo.ITest = { - fieldInt32: 123, - fieldInt32Repeated: [123, 12312], - fieldInt64: 12321313, - fieldInt64Repeated: [1333023, 12000312], - fieldDouble: 1234.1221231323, - fieldDoubleRepeated: [1234.1221231323], - fieldFloat: 9999.1, - fieldFloatRepeated: [9999.1], - fieldUint32: 11119, - fieldUint32Repeated: [11119], - fieldSint32: 13123, - fieldSint32Repeated: [13123, 1312312], - fieldFixed32: 123123, - fieldFixed32Repeated: [3223, 12312], - fieldFixed64: 123123, - fieldFixed64Repeated: [3223, 12312], - fieldSfixed32: 123123, - fieldSfixed32Repeated: [3223, 12312], - fieldSfixed64: 123123, - fieldSfixed64Repeated: [3223, 12312], - fieldBool: true, - fieldBoolRepeated: [true, false, true], - fieldString: 'foo', - fieldStringRepeated: ['foo', 'bar'], - fieldBytes: new Uint8Array([21, 31]), - fieldBytesRepeated: [new Uint8Array([21, 31]), new Uint8Array([2, 31])], - fieldEnum: 'UNKNOWN', - fieldEnumRepeated: ['EDIT', 'VIEW'], - message: { - title: 'msg', - }, - messageRepeated: [ - { - title: 'msg1', - }, - { - title: 'msg2', - }, - ], - timestamp: new Date('2014-11-01T12:24:33.123'), - timestampRepeated: [ - new Date('2014-02-26T12:00:00.234'), - new Date('2013-05-26T12:00:10.221'), - ], - } - - beforeEach(() => { - const user = new Foo.Test(values) - buffer = user.encode().finish() - decoded = PbTest.toObject(PbTest.decode(buffer), { - enums: String, - longs: Number, - defaults: false, - }) - }) - - describe.each([ - 'fieldInt32', - 'fieldInt64', - 'fieldDouble', - 'fieldUint32', - 'fieldSint32', - 'fieldFixed32', - 'fieldFixed64', - 'fieldSfixed32', - 'fieldSfixed64', - 'fieldBool', - 'fieldString', - 'fieldEnum', - // 'fieldBytes' // -- failed - 'message', - ])('%s', (fieldName: keyof typeof decoded) => { - it(`encodes ${fieldName}`, () => { - expect(decoded[fieldName]).toBeDefined() - expect(decoded[fieldName]).toEqual( - values[fieldName as keyof typeof values] - ) - }) - - it(`encodes ${fieldName}Repeated`, () => { - const name = `${fieldName}Repeated` - expect(decoded[name]).toBeDefined() - expect(decoded[name]).toEqual(values[name as keyof typeof values]) - }) - }) - - describe('timestamp', () => { - const toDate = (timestamp: { nanos: number; seconds: number }) => - new Date( - (timestamp.seconds || 0) * 1000 + (timestamp.nanos || 0) / 1000000 - ) - - it('encodes timestamp', () => { - expect(decoded['timestamp']).toBeDefined() - expect(toDate(decoded['timestamp'])).toEqual(values.timestamp) - }) - - it('encodes timestampRepeated', () => { - expect(decoded['timestampRepeated']).toBeDefined() - expect( - (decoded['timestampRepeated'] as { - nanos: number - seconds: number - }[]).map(toDate) - ).toEqual(values.timestampRepeated) - }) - }) - - describe('fieldFloat', () => { - it('encodes fieldFloat', () => { - expect(decoded['fieldFloat']).toBeDefined() - expect(decoded['fieldFloat']).toEqual( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - Math.fround(values.fieldFloat!) - ) - }) - - it('encodes fieldFloatRepeated', () => { - expect(decoded['fieldFloatRepeated']).toBeDefined() - expect(decoded['fieldFloatRepeated']).toEqual( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - values.fieldFloatRepeated!.map(Math.fround) - ) - }) - }) -}) diff --git a/tests/__tests__/legacy/proto/common/common.proto b/tests/__tests__/legacy/proto/common/common.proto deleted file mode 100644 index af5827b..0000000 --- a/tests/__tests__/legacy/proto/common/common.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -// "Dummy" option to make protoc happy (useful for Golang code generation, not for TS) -option go_package = "github.com/join-com/protoc-gen-ts/foo/common"; - -package common; - -message OtherPkgMessage { - string first_name = 1[deprecated=true]; - string lats_name = 2; -} diff --git a/tests/__tests__/legacy/proto/common/extra.proto b/tests/__tests__/legacy/proto/common/extra.proto deleted file mode 100644 index 7933be1..0000000 --- a/tests/__tests__/legacy/proto/common/extra.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -// "Dummy" option to make protoc happy (useful for Golang code generation, not for TS) -option go_package = "github.com/join-com/protoc-gen-ts/foo/common"; - -package common; - -message ExtraPkgMessage { - string first_name = 1[deprecated=true]; - string lats_name = 2; -} diff --git a/tests/__tests__/legacy/proto/test.proto b/tests/__tests__/legacy/proto/test.proto deleted file mode 100644 index b6af24b..0000000 --- a/tests/__tests__/legacy/proto/test.proto +++ /dev/null @@ -1,100 +0,0 @@ -syntax = "proto3"; - -package foo; - -// Makes protoc happy (useful for Golang code generation, not for TS) -option go_package = "github.com/join-com/protoc-gen-ts/foo"; - -import "google/protobuf/timestamp.proto"; -import "common/common.proto"; - -service Users { - rpc Find(Request) returns (common.OtherPkgMessage) { - option deprecated = true; - } - rpc FindClientStream(stream Request) returns (common.OtherPkgMessage) {} - rpc FindServerStream(Request) returns (stream common.OtherPkgMessage) {} - rpc FindBidiStream(stream Request) returns (stream common.OtherPkgMessage) {} -} - -enum EnumType { - UNKNOWN = 0; - ADMIN = 1; - USER = 2; -} - -enum Role { - VIEW = 0; - EDIT = 1; -} - -message Request { - int32 id = 1; -} - - -message Nested { - option deprecated = true; - string title = 1; -} - -message Test { - reserved 31, 32; - int32 field_int32 = 1; - repeated int32 field_int32_repeated = 2; - - double field_double = 3; - repeated double field_double_repeated = 4; - - float field_float = 5; - repeated float field_float_repeated = 6; - - uint32 field_uint32 = 7; - repeated uint32 field_uint32_repeated = 8; - - uint64 field_uint64 = 9; - repeated uint64 field_uint64_repeated = 10; - - sint32 field_sint32 = 11; - repeated sint32 field_sint32_repeated = 12; - - sint64 field_sint64 = 13[deprecated = true]; - repeated sint64 field_sint64_repeated = 14; - - fixed32 field_fixed32 = 15; - repeated fixed32 field_fixed32_repeated = 16; - - fixed64 field_fixed64 = 17; - repeated fixed64 field_fixed64_repeated = 18; - - sfixed32 field_sfixed32 = 19; - repeated sfixed32 field_sfixed32_repeated = 20; - - sfixed64 field_sfixed64 = 21; - repeated sfixed64 field_sfixed64_repeated = 22; - - bool field_bool = 23; - repeated bool field_bool_repeated = 24; - - string field_string = 25; - repeated string field_string_repeated = 26; - - bytes field_bytes = 27; - repeated bytes field_bytes_repeated = 28; - - EnumType field_enum = 29; - repeated Role field_enum_repeated = 30; - - Nested message = 33; - repeated Nested message_repeated = 34; - - google.protobuf.Timestamp timestamp = 35; - repeated google.protobuf.Timestamp timestamp_repeated = 36; - - common.OtherPkgMessage other_pkg_message = 37; - repeated common.OtherPkgMessage other_pkg_message_repeated = 38; - - int64 field_int64 = 39; - repeated int64 field_int64_repeated = 40; - -} diff --git a/tests/__tests__/v2/legacyCompatibility.test.ts b/tests/__tests__/legacyCompatibility.test.ts similarity index 100% rename from tests/__tests__/v2/legacyCompatibility.test.ts rename to tests/__tests__/legacyCompatibility.test.ts diff --git a/tests/__tests__/v2/proto/common/common.proto b/tests/__tests__/proto/common/common.proto similarity index 100% rename from tests/__tests__/v2/proto/common/common.proto rename to tests/__tests__/proto/common/common.proto diff --git a/tests/__tests__/v2/proto/common/extra.proto b/tests/__tests__/proto/common/extra.proto similarity index 100% rename from tests/__tests__/v2/proto/common/extra.proto rename to tests/__tests__/proto/common/extra.proto diff --git a/tests/__tests__/v2/proto/google/protobuf/descriptor.proto b/tests/__tests__/proto/google/protobuf/descriptor.proto similarity index 100% rename from tests/__tests__/v2/proto/google/protobuf/descriptor.proto rename to tests/__tests__/proto/google/protobuf/descriptor.proto diff --git a/tests/__tests__/v2/proto/google/protobuf/duration.proto b/tests/__tests__/proto/google/protobuf/duration.proto similarity index 100% rename from tests/__tests__/v2/proto/google/protobuf/duration.proto rename to tests/__tests__/proto/google/protobuf/duration.proto diff --git a/tests/__tests__/legacy/proto/google/protobuf/empty.proto b/tests/__tests__/proto/google/protobuf/empty.proto similarity index 100% rename from tests/__tests__/legacy/proto/google/protobuf/empty.proto rename to tests/__tests__/proto/google/protobuf/empty.proto diff --git a/tests/__tests__/legacy/proto/google/protobuf/timestamp.proto b/tests/__tests__/proto/google/protobuf/timestamp.proto similarity index 100% rename from tests/__tests__/legacy/proto/google/protobuf/timestamp.proto rename to tests/__tests__/proto/google/protobuf/timestamp.proto diff --git a/tests/__tests__/v2/proto/options.proto b/tests/__tests__/proto/options.proto similarity index 100% rename from tests/__tests__/v2/proto/options.proto rename to tests/__tests__/proto/options.proto diff --git a/tests/__tests__/v2/proto/test.proto b/tests/__tests__/proto/test.proto similarity index 100% rename from tests/__tests__/v2/proto/test.proto rename to tests/__tests__/proto/test.proto diff --git a/tests/__tests__/v2/proto/google/protobuf/empty.proto b/tests/__tests__/v2/proto/google/protobuf/empty.proto deleted file mode 100644 index 5f992de..0000000 --- a/tests/__tests__/v2/proto/google/protobuf/empty.proto +++ /dev/null @@ -1,52 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/emptypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "EmptyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// A generic empty message that you can re-use to avoid defining duplicated -// empty messages in your APIs. A typical example is to use it as the request -// or the response type of an API method. For instance: -// -// service Foo { -// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); -// } -// -// The JSON representation for `Empty` is empty JSON object `{}`. -message Empty {} diff --git a/tests/__tests__/v2/proto/google/protobuf/timestamp.proto b/tests/__tests__/v2/proto/google/protobuf/timestamp.proto deleted file mode 100644 index 3b2df6d..0000000 --- a/tests/__tests__/v2/proto/google/protobuf/timestamp.proto +++ /dev/null @@ -1,147 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/timestamppb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TimestampProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// A Timestamp represents a point in time independent of any time zone or local -// calendar, encoded as a count of seconds and fractions of seconds at -// nanosecond resolution. The count is relative to an epoch at UTC midnight on -// January 1, 1970, in the proleptic Gregorian calendar which extends the -// Gregorian calendar backwards to year one. -// -// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap -// second table is needed for interpretation, using a [24-hour linear -// smear](https://developers.google.com/time/smear). -// -// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By -// restricting to that range, we ensure that we can convert to and from [RFC -// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// -// Example 5: Compute Timestamp from Java `Instant.now()`. -// -// Instant now = Instant.now(); -// -// Timestamp timestamp = -// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) -// .setNanos(now.getNano()).build(); -// -// -// Example 6: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A proto3 JSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a proto3 JSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard -// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using -// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with -// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use -// the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D -// ) to obtain a formatter capable of generating timestamps in this format. -// -// -message Timestamp { - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - int32 nanos = 2; -} diff --git a/tests/package.json b/tests/package.json index eea9e61..3a327ce 100644 --- a/tests/package.json +++ b/tests/package.json @@ -8,19 +8,15 @@ "lint": "yarn lint:tsc && yarn lint:eslint", "lint:eslint": "eslint . --ext .ts --max-warnings 0", "lint:tsc": "tsc --noEmit && eslint", - "proto:build": "yarn proto:clean && yarn proto:generate && yarn proto:prettier", - "proto:clean": "find __tests__/legacy/generated ! -name 'tslint.json' ! -name '.prettierrc' -type f -exec rm -f {} +", - "proto:generate": "export PATH=\"${PWD}/../dist:${PATH}\" && protoc __tests__/legacy/proto/*.proto -I __tests__/legacy/proto --ts_out=\"${PWD}/__tests__/legacy/generated\"", - "proto:prettier": "prettier --write '__tests__/legacy/generated/**/*.ts'", "test": "export PATH=\"${PWD}/../dist:${PATH}\" && jest --runInBand --forceExit", - "v2:build": "yarn v2:clean && yarn v2:generate && yarn v2:prettier", - "v2:clean": "find __tests__/v2/generated ! -name 'tslint.json' ! -name '.prettierrc' -type f -exec rm -f {} +", - "v2:generate": "export PROTOC_TS_GENERATOR=V2 && export PATH=\"${PWD}/../dist:${PATH}\" && protoc __tests__/v2/proto/*.proto -I __tests__/v2/proto --ts_out=\"${PWD}/__tests__/v2/generated\"", - "v2:prettier": "prettier --write '__tests__/v2/generated/**/*.ts'" + "proto:build": "yarn proto:clean && yarn proto:generate && yarn proto:prettier", + "proto:clean": "find __tests__/generated ! -name 'tslint.json' ! -name '.prettierrc' -type f -exec rm -f {} +", + "proto:generate": "export PATH=\"${PWD}/../dist:${PATH}\" && protoc __tests__/proto/*.proto -I __tests__/proto --tsx_out=\"${PWD}/__tests__/generated\"", + "proto:prettier": "prettier --write '__tests__/generated/**/*.ts'" }, "dependencies": { "@join-com/gcloud-logger-trace": "^0.1.17", - "@join-com/grpc": "^0.1.2", + "@join-com/grpc": "^0.2.0", "@join-com/grpc-ts": "^2.0.2", "grpc": "^1.24.6", "protobufjs": "^6.10.2" From 6984061a53921c3a4ea59f9d67a300c3f1731c22 Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Sat, 17 Apr 2021 15:51:42 +0200 Subject: [PATCH 4/8] refactor: simplify previous changes --- internal/generator/runer_generate_service.go | 9 ++++----- tests/__tests__/generated/Test.ts | 21 ++++---------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/internal/generator/runer_generate_service.go b/internal/generator/runer_generate_service.go index 991c387..814691f 100644 --- a/internal/generator/runer_generate_service.go +++ b/internal/generator/runer_generate_service.go @@ -205,15 +205,14 @@ func (r *Runner) generateTypescriptClientMethod(generatedFileStream *protogen.Ge r.P(generatedFileStream, "): "+returnType+" {") r.indentLevel += 2 - methodPath := "/" + r.currentPackage + "." + serviceSpec.GetName() + "/" + methodName if clientStream && serverStrean { - r.P(generatedFileStream, "return this.makeBidiStreamRequest('"+methodPath+"', metadata, options)") + r.P(generatedFileStream, "return this.makeBidiStreamRequest('"+methodName+"', metadata, options)") } else if !clientStream && !serverStrean { - r.P(generatedFileStream, "return this.makeUnaryRequest('"+methodPath+"', request, metadata, options)") + r.P(generatedFileStream, "return this.makeUnaryRequest('"+methodName+"', request, metadata, options)") } else if clientStream { - r.P(generatedFileStream, "return this.makeClientStreamRequest('"+methodPath+"', metadata, options)") + r.P(generatedFileStream, "return this.makeClientStreamRequest('"+methodName+"', metadata, options)") } else { // if serverStream - r.P(generatedFileStream, "return this.makeServerStreamRequest('"+methodPath+"', request, metadata, options)") + r.P(generatedFileStream, "return this.makeServerStreamRequest('"+methodName+"', request, metadata, options)") } r.indentLevel -= 2 diff --git a/tests/__tests__/generated/Test.ts b/tests/__tests__/generated/Test.ts index 49a7129..e4eee2e 100644 --- a/tests/__tests__/generated/Test.ts +++ b/tests/__tests__/generated/Test.ts @@ -521,23 +521,14 @@ export namespace Foo { metadata?: Record, options?: grpc.CallOptions ): joinGRPC.IUnaryRequest { - return this.makeUnaryRequest( - '/foo.Users/Find', - request, - metadata, - options - ) + return this.makeUnaryRequest('Find', request, metadata, options) } public FindClientStream( metadata?: Record, options?: grpc.CallOptions ): joinGRPC.IClientStreamRequest { - return this.makeClientStreamRequest( - '/foo.Users/FindClientStream', - metadata, - options - ) + return this.makeClientStreamRequest('FindClientStream', metadata, options) } public FindServerStream( @@ -546,7 +537,7 @@ export namespace Foo { options?: grpc.CallOptions ): grpc.ClientReadableStream { return this.makeServerStreamRequest( - '/foo.Users/FindServerStream', + 'FindServerStream', request, metadata, options @@ -557,11 +548,7 @@ export namespace Foo { metadata?: Record, options?: grpc.CallOptions ): grpc.ClientDuplexStream { - return this.makeBidiStreamRequest( - '/foo.Users/FindBidiStream', - metadata, - options - ) + return this.makeBidiStreamRequest('FindBidiStream', metadata, options) } } } From 550e339ba071a765716cab6d5ee8f81be7781358 Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Sat, 17 Apr 2021 15:56:13 +0200 Subject: [PATCH 5/8] build: run strip only locally in build.sh --- build.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index fd4d682..1fb50e8 100755 --- a/build.sh +++ b/build.sh @@ -3,5 +3,7 @@ # Building binary go build -o ./dist/protoc-gen-tsx -# Stripping symbols to make the binary more lightweight -strip -u -r -S ./dist/protoc-gen-tsx +if [ "${CI}" != "true" ]; then + # Stripping symbols to make the binary more lightweight + strip -u -r -S ./dist/protoc-gen-tsx +fi From 2a9e70501714ae01f82568c14e2a8c60800ed503 Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Sat, 17 Apr 2021 15:58:44 +0200 Subject: [PATCH 6/8] test: fix import path --- tests/__tests__/legacyCompatibility.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/__tests__/legacyCompatibility.test.ts b/tests/__tests__/legacyCompatibility.test.ts index 3312a06..b08e1a5 100644 --- a/tests/__tests__/legacyCompatibility.test.ts +++ b/tests/__tests__/legacyCompatibility.test.ts @@ -1,5 +1,5 @@ import { Foo } from './generated/Test' -import { Foo as LegacyFoo } from '../legacy/generated/Test' +import { Foo as LegacyFoo } from './generatedLegacy/Test' describe('(v2) legacy compatibility', () => { const request: Foo.IRequest = { id: 42 } From 03b07e7b59c13e5c7ead13790e4c530b4fccbf65 Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Sat, 17 Apr 2021 16:12:03 +0200 Subject: [PATCH 7/8] feat: mark generated static methods as having this:void --- internal/generator/runner_generate_class.go | 7 +++-- tests/.eslintignore | 3 ++- tests/.eslintrc.js | 2 +- tests/__tests__/generated/Test.ts | 26 +++++++++++++++---- tests/__tests__/generated/common/Common.ts | 7 ++++- tests/__tests__/generated/common/Extra.ts | 7 ++++- .../generated/google/protobuf/Timestamp.ts | 4 ++- 7 files changed, 42 insertions(+), 14 deletions(-) diff --git a/internal/generator/runner_generate_class.go b/internal/generator/runner_generate_class.go index de29911..c14c4ef 100644 --- a/internal/generator/runner_generate_class.go +++ b/internal/generator/runner_generate_class.go @@ -116,7 +116,7 @@ func (r *Runner) generateAsInterfaceMethod(generatedFileStream *protogen.Generat func (r *Runner) generateFromInterfaceMethod(generatedFileStream *protogen.GeneratedFile, messageSpec *descriptorpb.DescriptorProto, requiredFields bool, hasEnums bool) { className := strcase.ToCamel(messageSpec.GetName()) - r.P(generatedFileStream, "public static fromInterface(value: I"+className+"): "+className+" {") + r.P(generatedFileStream, "public static fromInterface(this: void, value: I"+className+"): "+className+" {") r.indentLevel += 2 if hasEnums { @@ -142,7 +142,7 @@ func (r *Runner) generateFromInterfaceMethod(generatedFileStream *protogen.Gener func (r *Runner) generateDecodePatchedMethod(generatedFileStream *protogen.GeneratedFile, messageSpec *descriptorpb.DescriptorProto, requiredFields bool, hasEnums bool) { className := strcase.ToCamel(messageSpec.GetName()) - r.P(generatedFileStream, "public static decodePatched(reader: protobufjs.Reader | Uint8Array): I"+className+" {") + r.P(generatedFileStream, "public static decodePatched(this: void, reader: protobufjs.Reader | Uint8Array): I"+className+" {") r.indentLevel += 2 if hasEnums { @@ -158,8 +158,7 @@ func (r *Runner) generateDecodePatchedMethod(generatedFileStream *protogen.Gener func (r *Runner) generateEncodePatchedMethod(generatedFileStream *protogen.GeneratedFile, messageSpec *descriptorpb.DescriptorProto, requiredFields bool, hasEnums bool) { className := strcase.ToCamel(messageSpec.GetName()) - // public static encode>(this: Constructor, message: (T|{ [k: string]: any }), writer?: Writer): Writer; - r.P(generatedFileStream, "public static encodePatched(message: I"+className+", writer?: protobufjs.Writer): protobufjs.Writer {") + r.P(generatedFileStream, "public static encodePatched(this: void, message: I"+className+", writer?: protobufjs.Writer): protobufjs.Writer {") r.indentLevel += 2 if hasEnums { diff --git a/tests/.eslintignore b/tests/.eslintignore index 3a2b6db..7f9d5fe 100644 --- a/tests/.eslintignore +++ b/tests/.eslintignore @@ -1,2 +1,3 @@ -node_modules/ generated/ +generatedLegacy/ +node_modules/ diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js index d1b47d8..0dc9dcf 100644 --- a/tests/.eslintrc.js +++ b/tests/.eslintrc.js @@ -56,5 +56,5 @@ module.exports = { }, }, ], - ignorePatterns: ['*.js', 'generated/**/*.ts'], + ignorePatterns: ['*.js'], } diff --git a/tests/__tests__/generated/Test.ts b/tests/__tests__/generated/Test.ts index e4eee2e..182b7eb 100644 --- a/tests/__tests__/generated/Test.ts +++ b/tests/__tests__/generated/Test.ts @@ -103,17 +103,19 @@ export namespace Foo { return this } - public static fromInterface(value: IRequest): Request { + public static fromInterface(this: void, value: IRequest): Request { return Request.fromObject(value) } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): IRequest { return Request.decode(reader) } public static encodePatched( + this: void, message: IRequest, writer?: protobufjs.Writer ): protobufjs.Writer { @@ -135,17 +137,19 @@ export namespace Foo { return this } - public static fromInterface(value: INested): Nested { + public static fromInterface(this: void, value: INested): Nested { return Nested.fromObject(value) } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): INested { return Nested.decode(reader) } public static encodePatched( + this: void, message: INested, writer?: protobufjs.Writer ): protobufjs.Writer { @@ -293,7 +297,7 @@ export namespace Foo { } } - public static fromInterface(value: ITest): Test { + public static fromInterface(this: void, value: ITest): Test { const patchedValue = { ...value, fieldEnum: (value.fieldEnum != null @@ -318,11 +322,15 @@ export namespace Foo { return Test.fromObject(patchedValue) } - public static decodePatched(reader: protobufjs.Reader | Uint8Array): ITest { + public static decodePatched( + this: void, + reader: protobufjs.Reader | Uint8Array + ): ITest { return Test.decode(reader).asInterface() } public static encodePatched( + this: void, message: ITest, writer?: protobufjs.Writer ): protobufjs.Writer { @@ -351,7 +359,10 @@ export namespace Foo { } } - public static fromInterface(value: ICustomOptionsTest): CustomOptionsTest { + public static fromInterface( + this: void, + value: ICustomOptionsTest + ): CustomOptionsTest { const patchedValue = { ...value, requiredField: Common_Extra.ExtraPkgMessage.fromInterface( @@ -363,12 +374,14 @@ export namespace Foo { } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): ICustomOptionsTest { return CustomOptionsTest.decode(reader).asInterface() } public static encodePatched( + this: void, message: ICustomOptionsTest, writer?: protobufjs.Writer ): protobufjs.Writer { @@ -395,18 +408,21 @@ export namespace Foo { } public static fromInterface( + this: void, value: IRequiredPropertiesTest ): RequiredPropertiesTest { return RequiredPropertiesTest.fromObject(value) } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): IRequiredPropertiesTest { return RequiredPropertiesTest.decode(reader) } public static encodePatched( + this: void, message: IRequiredPropertiesTest, writer?: protobufjs.Writer ): protobufjs.Writer { diff --git a/tests/__tests__/generated/common/Common.ts b/tests/__tests__/generated/common/Common.ts index 5861f8c..aab60e2 100644 --- a/tests/__tests__/generated/common/Common.ts +++ b/tests/__tests__/generated/common/Common.ts @@ -27,17 +27,22 @@ export namespace Common { return this } - public static fromInterface(value: IOtherPkgMessage): OtherPkgMessage { + public static fromInterface( + this: void, + value: IOtherPkgMessage + ): OtherPkgMessage { return OtherPkgMessage.fromObject(value) } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): IOtherPkgMessage { return OtherPkgMessage.decode(reader) } public static encodePatched( + this: void, message: IOtherPkgMessage, writer?: protobufjs.Writer ): protobufjs.Writer { diff --git a/tests/__tests__/generated/common/Extra.ts b/tests/__tests__/generated/common/Extra.ts index e1a9065..c5dfefd 100644 --- a/tests/__tests__/generated/common/Extra.ts +++ b/tests/__tests__/generated/common/Extra.ts @@ -42,7 +42,10 @@ export namespace Common { } } - public static fromInterface(value: IExtraPkgMessage): ExtraPkgMessage { + public static fromInterface( + this: void, + value: IExtraPkgMessage + ): ExtraPkgMessage { const patchedValue = { ...value, birthDate: @@ -58,12 +61,14 @@ export namespace Common { } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): IExtraPkgMessage { return ExtraPkgMessage.decode(reader).asInterface() } public static encodePatched( + this: void, message: IExtraPkgMessage, writer?: protobufjs.Writer ): protobufjs.Writer { diff --git a/tests/__tests__/generated/google/protobuf/Timestamp.ts b/tests/__tests__/generated/google/protobuf/Timestamp.ts index 8a90cf7..4e27448 100644 --- a/tests/__tests__/generated/google/protobuf/Timestamp.ts +++ b/tests/__tests__/generated/google/protobuf/Timestamp.ts @@ -27,17 +27,19 @@ export namespace GoogleProtobuf { return this } - public static fromInterface(value: ITimestamp): Timestamp { + public static fromInterface(this: void, value: ITimestamp): Timestamp { return Timestamp.fromObject(value) } public static decodePatched( + this: void, reader: protobufjs.Reader | Uint8Array ): ITimestamp { return Timestamp.decode(reader) } public static encodePatched( + this: void, message: ITimestamp, writer?: protobufjs.Writer ): protobufjs.Writer { From 7ef64c4aa44d582831fff26078491d2da55eab78 Mon Sep 17 00:00:00 2001 From: Andres Correa Casablanca Date: Sat, 17 Apr 2021 16:18:38 +0200 Subject: [PATCH 8/8] docs: document new generator --- readme.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 54ae7ef..712e1d9 100644 --- a/readme.md +++ b/readme.md @@ -4,19 +4,33 @@ Generates `ts` files from `proto` file definitions. ## Setup +To install the "new" generator (bear in mind that it could be installed in `${HOME}/.local/bin` too): ``` curl -Lo protoc-gen-ts \ - https://github.com/join-com/protoc-gen-ts/releases/download/[VERSION]/protoc-gen-ts.darwin.x86_64 \ + https://github.com/join-com/protoc-gen-ts/releases/download/[VERSION]/protoc-gen-tsx.darwin.x86_64 \ +&& chmod +x protoc-gen-tsx \ +&& sudo mv protoc-gen-tsx /usr/local/bin +``` + +In case you need to use the old generator as well, you can install it too in parallel: +``` +curl -Lo protoc-gen-ts \ + https://github.com/join-com/protoc-gen-ts/releases/download/0.7.1/protoc-gen-ts.darwin.x86_64 \ && chmod +x protoc-gen-ts \ && sudo mv protoc-gen-ts /usr/local/bin ``` ## Usage +will generate TS implementations into `proto-ts` folder for all your proto files inside `proto`: +``` +protoc proto/*.proto -I proto --tsx_out=proto-ts +``` + +If you want to use the old generator (notice the `tsx_out` -> `ts_out` change): ``` protoc proto/*.proto -I proto --ts_out=proto-ts ``` -will generate TS implementations into `proto-ts` folder for all your proto files inside `proto` ## Develop