protoc-gen-go-micro/helpers/helpers.go

1328 lines
33 KiB
Go
Raw Normal View History

package pgghelpers
import (
"encoding/json"
"fmt"
"reflect"
2017-04-13 14:15:40 +03:00
"regexp"
"strings"
2018-08-23 19:48:43 +03:00
"sync"
"text/template"
"github.com/Masterminds/sprig"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
ggdescriptor "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
"github.com/huandu/xstrings"
options "google.golang.org/genproto/googleapis/api/annotations"
)
2017-12-25 11:17:09 +03:00
var jsReservedRe = regexp.MustCompile(`(^|[^A-Za-z])(do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)($|[^A-Za-z])`)
2017-04-13 14:15:40 +03:00
var (
registry *ggdescriptor.Registry // some helpers need access to registry
)
var ProtoHelpersFuncMap = template.FuncMap{
"string": func(i interface {
String() string
}) string {
return i.String()
},
"json": func(v interface{}) string {
2017-12-25 11:17:09 +03:00
a, err := json.Marshal(v)
if err != nil {
return err.Error()
}
return string(a)
},
"prettyjson": func(v interface{}) string {
2017-12-25 11:17:09 +03:00
a, err := json.MarshalIndent(v, "", " ")
if err != nil {
return err.Error()
}
return string(a)
},
"splitArray": func(sep string, s string) []interface{} {
var r []interface{}
t := strings.Split(s, sep)
for i := range t {
if t[i] != "" {
r = append(r, t[i])
}
}
return r
},
"first": func(a []string) string {
return a[0]
},
"last": func(a []string) string {
return a[len(a)-1]
},
2018-04-06 17:42:23 +03:00
"concat": func(a string, b ...string) string {
return strings.Join(append([]string{a}, b...), "")
},
"join": func(sep string, a ...string) string {
return strings.Join(a, sep)
},
2016-12-19 17:43:38 +03:00
"upperFirst": func(s string) string {
return strings.ToUpper(s[:1]) + s[1:]
},
"lowerFirst": func(s string) string {
return strings.ToLower(s[:1]) + s[1:]
},
2016-12-20 13:31:46 +03:00
"camelCase": func(s string) string {
2017-01-04 01:41:58 +03:00
if len(s) > 1 {
return xstrings.ToCamelCase(s)
}
return strings.ToUpper(s[:1])
2016-12-20 13:31:46 +03:00
},
2017-01-11 18:33:03 +03:00
"lowerCamelCase": func(s string) string {
if len(s) > 1 {
s = xstrings.ToCamelCase(s)
}
2017-01-04 01:41:58 +03:00
2017-01-11 18:33:03 +03:00
return strings.ToLower(s[:1]) + s[1:]
},
2016-12-20 13:31:46 +03:00
"kebabCase": func(s string) string {
return strings.Replace(xstrings.ToSnakeCase(s), "_", "-", -1)
},
2017-06-26 12:34:02 +03:00
"contains": func(sub, s string) bool {
return strings.Contains(s, sub)
},
"trimstr": func(cutset, s string) string {
return strings.Trim(s, cutset)
},
2018-02-12 18:36:21 +03:00
"index": func(array interface{}, i int32) interface{} {
slice := reflect.ValueOf(array)
if slice.Kind() != reflect.Slice {
panic("Error in index(): given a non-slice type")
}
2018-02-12 18:36:21 +03:00
if i < 0 || int(i) >= slice.Len() {
panic("Error in index(): index out of bounds")
}
2018-02-12 18:36:21 +03:00
return slice.Index(int(i)).Interface()
},
2018-04-06 17:42:23 +03:00
"add": func(a int, b int) int {
return a + b
},
"subtract": func(a int, b int) int {
return a - b
},
"multiply": func(a int, b int) int {
return a * b
},
"divide": func(a int, b int) int {
if b == 0 {
panic("psssst ... little help here ... you cannot divide by 0")
}
return a / b
},
"snakeCase": xstrings.ToSnakeCase,
"getProtoFile": getProtoFile,
"getMessageType": getMessageType,
"getEnumValue": getEnumValue,
"isFieldMessage": isFieldMessage,
"isFieldMessageTimeStamp": isFieldMessageTimeStamp,
"isFieldRepeated": isFieldRepeated,
"haskellType": haskellType,
"goType": goType,
"goZeroValue": goZeroValue,
"goTypeWithPackage": goTypeWithPackage,
"goTypeWithGoPackage": goTypeWithGoPackage,
"jsType": jsType,
"jsSuffixReserved": jsSuffixReservedKeyword,
"namespacedFlowType": namespacedFlowType,
"httpVerb": httpVerb,
"httpPath": httpPath,
"httpPathsAdditionalBindings": httpPathsAdditionalBindings,
"httpBody": httpBody,
"shortType": shortType,
"urlHasVarsFromMessage": urlHasVarsFromMessage,
"lowerGoNormalize": lowerGoNormalize,
"goNormalize": goNormalize,
"leadingComment": leadingComment,
"trailingComment": trailingComment,
"leadingDetachedComments": leadingDetachedComments,
2019-04-26 21:34:25 +03:00
"stringFileOptionsExtension": stringFileOptionsExtension,
2019-02-08 21:03:10 +03:00
"stringMessageExtension": stringMessageExtension,
"stringFieldExtension": stringFieldExtension,
2019-01-18 21:39:16 +03:00
"int64FieldExtension": int64FieldExtension,
2019-02-08 21:03:10 +03:00
"int64MessageExtension": int64MessageExtension,
"stringMethodOptionsExtension": stringMethodOptionsExtension,
2018-08-20 18:41:36 +03:00
"boolMethodOptionsExtension": boolMethodOptionsExtension,
2019-02-08 21:03:10 +03:00
"boolMessageExtension": boolMessageExtension,
"boolFieldExtension": boolFieldExtension,
"isFieldMap": isFieldMap,
"fieldMapKeyType": fieldMapKeyType,
"fieldMapValueType": fieldMapValueType,
"replaceDict": replaceDict,
2018-04-06 17:42:23 +03:00
"setStore": setStore,
"getStore": getStore,
"goPkg": goPkg,
"goPkgLastElement": goPkgLastElement,
2018-01-12 20:38:10 +03:00
}
var pathMap map[interface{}]*descriptor.SourceCodeInfo_Location
2018-08-23 19:48:43 +03:00
var store = newStore()
// Utility to store some vars across multiple scope
type globalStore struct {
store map[string]interface{}
mu sync.Mutex
}
func newStore() *globalStore {
return &globalStore{
store: make(map[string]interface{}),
}
2018-04-06 17:42:23 +03:00
}
2018-08-23 19:48:43 +03:00
func (s *globalStore) getData(key string) interface{} {
s.mu.Lock()
defer s.mu.Unlock()
if v, ok := s.store[key]; ok {
2018-04-06 17:42:23 +03:00
return v
}
2018-08-20 18:41:58 +03:00
return false
2018-04-06 17:42:23 +03:00
}
2018-08-23 19:48:43 +03:00
func (s *globalStore) setData(key string, o interface{}) {
s.mu.Lock()
s.store[key] = o
s.mu.Unlock()
}
func setStore(key string, o interface{}) string {
store.setData(key, o)
return ""
}
func getStore(key string) interface{} {
return store.getData(key)
}
func SetRegistry(reg *ggdescriptor.Registry) {
registry = reg
}
2018-01-12 20:38:10 +03:00
func InitPathMap(file *descriptor.FileDescriptorProto) {
pathMap = make(map[interface{}]*descriptor.SourceCodeInfo_Location)
addToPathMap(file.GetSourceCodeInfo(), file, []int32{})
}
func InitPathMaps(files []*descriptor.FileDescriptorProto) {
pathMap = make(map[interface{}]*descriptor.SourceCodeInfo_Location)
for _, file := range files {
addToPathMap(file.GetSourceCodeInfo(), file, []int32{})
}
}
2018-01-12 21:36:29 +03:00
// addToPathMap traverses through the AST adding SourceCodeInfo_Location entries to the pathMap.
// Since the AST is a tree, the recursion finishes once it has gone through all the nodes.
2018-01-12 20:38:10 +03:00
func addToPathMap(info *descriptor.SourceCodeInfo, i interface{}, path []int32) {
loc := findLoc(info, path)
if loc != nil {
pathMap[i] = loc
}
switch d := i.(type) {
case *descriptor.FileDescriptorProto:
for index, descriptor := range d.MessageType {
addToPathMap(info, descriptor, newPath(path, 4, index))
}
for index, descriptor := range d.EnumType {
addToPathMap(info, descriptor, newPath(path, 5, index))
}
for index, descriptor := range d.Service {
addToPathMap(info, descriptor, newPath(path, 6, index))
}
case *descriptor.DescriptorProto:
for index, descriptor := range d.Field {
addToPathMap(info, descriptor, newPath(path, 2, index))
}
for index, descriptor := range d.NestedType {
addToPathMap(info, descriptor, newPath(path, 3, index))
}
for index, descriptor := range d.EnumType {
addToPathMap(info, descriptor, newPath(path, 4, index))
}
case *descriptor.EnumDescriptorProto:
for index, descriptor := range d.Value {
addToPathMap(info, descriptor, newPath(path, 2, index))
}
case *descriptor.ServiceDescriptorProto:
for index, descriptor := range d.Method {
addToPathMap(info, descriptor, newPath(path, 2, index))
}
}
}
func newPath(base []int32, field int32, index int) []int32 {
p := append([]int32{}, base...)
p = append(p, field, int32(index))
return p
}
func findLoc(info *descriptor.SourceCodeInfo, path []int32) *descriptor.SourceCodeInfo_Location {
for _, loc := range info.GetLocation() {
if samePath(loc.Path, path) {
return loc
}
}
return nil
}
func samePath(a, b []int32) bool {
if len(a) != len(b) {
return false
}
for i, p := range a {
if p != b[i] {
return false
}
}
return true
}
2019-01-19 22:01:03 +03:00
/*func findSourceInfoLocation(i interface{}) *descriptor.SourceCodeInfo_Location {
2018-01-12 20:38:10 +03:00
if pathMap == nil {
return nil
}
return pathMap[i]
2019-01-19 22:01:03 +03:00
}*/
2018-01-12 20:38:10 +03:00
func leadingComment(i interface{}) string {
loc := pathMap[i]
return loc.GetLeadingComments()
}
func trailingComment(i interface{}) string {
loc := pathMap[i]
return loc.GetTrailingComments()
}
func leadingDetachedComments(i interface{}) []string {
loc := pathMap[i]
return loc.GetLeadingDetachedComments()
}
// stringMethodOptionsExtension extracts method options of a string type.
// To define your own extensions see:
// https://developers.google.com/protocol-buffers/docs/proto#customoptions
// Typically the fieldID of private extensions should be in the range:
// 50000-99999
func stringMethodOptionsExtension(fieldID int32, f *descriptor.MethodDescriptorProto) string {
if f == nil {
return ""
}
if f.Options == nil {
return ""
}
var extendedType *descriptor.MethodOptions
var extensionType *string
2019-04-26 21:34:25 +03:00
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
Tag: fmt.Sprintf("bytes,%d", fieldID),
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return ""
}
str, ok := ext.(*string)
if !ok {
return ""
}
return *str
}
// stringFileOptionsExtension extracts file options of a string type.
// To define your own extensions see:
// https://developers.google.com/protocol-buffers/docs/proto#customoptions
// Typically the fieldID of private extensions should be in the range:
// 50000-99999
func stringFileOptionsExtension(fieldID int32, f *descriptor.FileDescriptorProto) string {
if f == nil {
return ""
}
if f.Options == nil {
return ""
}
var extendedType *descriptor.FileOptions
var extensionType *string
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
Tag: fmt.Sprintf("bytes,%d", fieldID),
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return ""
}
str, ok := ext.(*string)
if !ok {
return ""
}
return *str
}
2018-01-12 20:56:25 +03:00
func stringFieldExtension(fieldID int32, f *descriptor.FieldDescriptorProto) string {
2018-01-12 20:38:10 +03:00
if f == nil {
return ""
}
if f.Options == nil {
return ""
}
var extendedType *descriptor.FieldOptions
var extensionType *string
eds := proto.RegisteredExtensions(f.Options)
2018-01-12 20:56:25 +03:00
if eds[fieldID] == nil {
2018-01-12 20:38:10 +03:00
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
2018-01-12 20:56:25 +03:00
Field: fieldID,
Tag: fmt.Sprintf("bytes,%d", fieldID),
2018-01-12 20:38:10 +03:00
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
2018-01-12 20:56:25 +03:00
ext, err := proto.GetExtension(f.Options, eds[fieldID])
2018-01-12 20:38:10 +03:00
if err != nil {
return ""
}
str, ok := ext.(*string)
if !ok {
return ""
}
return *str
}
2019-01-18 21:39:16 +03:00
func int64FieldExtension(fieldID int32, f *descriptor.FieldDescriptorProto) int64 {
if f == nil {
return 0
}
if f.Options == nil {
return 0
}
var extendedType *descriptor.FieldOptions
2019-02-10 21:50:23 +03:00
var extensionType *int64
2019-01-18 21:39:16 +03:00
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
2019-02-10 21:50:23 +03:00
Tag: fmt.Sprintf("varint,%d", fieldID),
2019-01-18 21:39:16 +03:00
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return 0
}
i, ok := ext.(*int64)
if !ok {
return 0
}
return *i
}
2019-02-08 21:03:10 +03:00
func int64MessageExtension(fieldID int32, f *descriptor.DescriptorProto) int64 {
if f == nil {
return 0
}
if f.Options == nil {
return 0
}
var extendedType *descriptor.MessageOptions
2019-02-10 21:50:23 +03:00
var extensionType *int64
2019-02-08 21:03:10 +03:00
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
2019-02-10 21:50:23 +03:00
Tag: fmt.Sprintf("varint,%d", fieldID),
2019-02-08 21:03:10 +03:00
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return 0
}
i, ok := ext.(*int64)
if !ok {
return 0
}
return *i
}
func stringMessageExtension(fieldID int32, f *descriptor.DescriptorProto) string {
if f == nil {
return ""
}
if f.Options == nil {
return ""
}
var extendedType *descriptor.MessageOptions
var extensionType *string
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
Tag: fmt.Sprintf("bytes,%d", fieldID),
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return ""
}
str, ok := ext.(*string)
if !ok {
return ""
}
return *str
}
2018-08-20 18:41:36 +03:00
func boolMethodOptionsExtension(fieldID int32, f *descriptor.MethodDescriptorProto) bool {
if f == nil {
return false
}
if f.Options == nil {
return false
}
var extendedType *descriptor.MethodOptions
var extensionType *bool
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
2019-01-18 21:39:16 +03:00
Tag: fmt.Sprintf("varint,%d", fieldID),
2018-08-20 18:41:36 +03:00
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return false
}
b, ok := ext.(*bool)
if !ok {
return false
}
return *b
}
2018-01-12 20:56:25 +03:00
func boolFieldExtension(fieldID int32, f *descriptor.FieldDescriptorProto) bool {
2018-01-12 20:38:10 +03:00
if f == nil {
return false
}
if f.Options == nil {
return false
}
var extendedType *descriptor.FieldOptions
var extensionType *bool
2019-02-08 21:03:10 +03:00
eds := proto.RegisteredExtensions(f.Options)
if eds[fieldID] == nil {
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
Field: fieldID,
Tag: fmt.Sprintf("varint,%d", fieldID),
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
ext, err := proto.GetExtension(f.Options, eds[fieldID])
if err != nil {
return false
}
b, ok := ext.(*bool)
if !ok {
return false
}
return *b
}
func boolMessageExtension(fieldID int32, f *descriptor.DescriptorProto) bool {
if f == nil {
return false
}
if f.Options == nil {
return false
}
var extendedType *descriptor.MessageOptions
var extensionType *bool
2018-01-12 20:38:10 +03:00
eds := proto.RegisteredExtensions(f.Options)
2018-01-12 20:56:25 +03:00
if eds[fieldID] == nil {
2018-01-12 20:38:10 +03:00
ed := &proto.ExtensionDesc{
ExtendedType: extendedType,
ExtensionType: extensionType,
2018-01-12 20:56:25 +03:00
Field: fieldID,
Tag: fmt.Sprintf("varint,%d", fieldID),
2018-01-12 20:38:10 +03:00
}
proto.RegisterExtension(ed)
eds = proto.RegisteredExtensions(f.Options)
}
2018-01-12 20:56:25 +03:00
ext, err := proto.GetExtension(f.Options, eds[fieldID])
2018-01-12 20:38:10 +03:00
if err != nil {
return false
}
2018-08-20 18:41:36 +03:00
b, ok := ext.(*bool)
2018-01-12 20:38:10 +03:00
if !ok {
return false
}
2018-08-20 18:41:36 +03:00
return *b
}
func init() {
for k, v := range sprig.TxtFuncMap() {
ProtoHelpersFuncMap[k] = v
}
}
func getProtoFile(name string) *ggdescriptor.File {
if registry == nil {
return nil
}
file, err := registry.LookupFile(name)
if err != nil {
panic(err)
}
return file
}
func getMessageType(f *descriptor.FileDescriptorProto, name string) *ggdescriptor.Message {
if registry != nil {
msg, err := registry.LookupMsg(".", name)
if err != nil {
panic(err)
}
return msg
}
// name is in the form .packageName.MessageTypeName.InnerMessageTypeName...
// e.g. .article.ProductTag
splits := strings.Split(name, ".")
target := splits[len(splits)-1]
for _, m := range f.MessageType {
if target == *m.Name {
return &ggdescriptor.Message{
DescriptorProto: m,
}
}
}
return nil
}
2017-05-12 21:46:18 +03:00
func getEnumValue(f []*descriptor.EnumDescriptorProto, name string) []*descriptor.EnumValueDescriptorProto {
for _, item := range f {
if strings.EqualFold(*item.Name, name) {
return item.GetValue()
}
}
return nil
}
2017-09-18 16:04:39 +03:00
func isFieldMessageTimeStamp(f *descriptor.FieldDescriptorProto) bool {
if f.Type != nil && *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE {
2017-09-18 19:56:37 +03:00
if strings.Compare(*f.TypeName, ".google.protobuf.Timestamp") == 0 {
2017-09-18 16:04:39 +03:00
return true
}
}
return false
}
func isFieldMessage(f *descriptor.FieldDescriptorProto) bool {
2016-12-29 19:21:53 +03:00
if f.Type != nil && *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE {
return true
}
return false
}
func isFieldRepeated(f *descriptor.FieldDescriptorProto) bool {
2018-01-12 20:38:10 +03:00
if f == nil {
return false
}
if f.Type != nil && f.Label != nil && *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return true
}
return false
}
2018-01-12 20:38:10 +03:00
func isFieldMap(f *descriptor.FieldDescriptorProto, m *descriptor.DescriptorProto) bool {
if f.TypeName == nil {
return false
}
shortName := shortType(*f.TypeName)
var nt *descriptor.DescriptorProto
for _, t := range m.NestedType {
if *t.Name == shortName {
nt = t
break
}
}
if nt == nil {
return false
}
for _, f := range nt.Field {
switch *f.Name {
case "key":
if *f.Number != 1 {
return false
}
case "value":
if *f.Number != 2 {
return false
}
default:
return false
}
}
return true
}
func fieldMapKeyType(f *descriptor.FieldDescriptorProto, m *descriptor.DescriptorProto) *descriptor.FieldDescriptorProto {
if f.TypeName == nil {
return nil
}
shortName := shortType(*f.TypeName)
var nt *descriptor.DescriptorProto
for _, t := range m.NestedType {
if *t.Name == shortName {
nt = t
break
}
}
if nt == nil {
return nil
}
for _, f := range nt.Field {
if *f.Name == "key" {
return f
}
}
return nil
}
func fieldMapValueType(f *descriptor.FieldDescriptorProto, m *descriptor.DescriptorProto) *descriptor.FieldDescriptorProto {
if f.TypeName == nil {
return nil
}
shortName := shortType(*f.TypeName)
var nt *descriptor.DescriptorProto
for _, t := range m.NestedType {
if *t.Name == shortName {
nt = t
break
}
}
if nt == nil {
return nil
}
for _, f := range nt.Field {
if *f.Name == "value" {
return f
}
}
return nil
}
// goTypeWithGoPackage types the field MESSAGE and ENUM with the go_package name.
// This method is an evolution of goTypeWithPackage. It handles message embedded.
//
// example:
// ```proto
// message GetArticleResponse {
// Article article = 1;
// message Storage {
// string code = 1;
// }
// repeated Storage storages = 2;
// }
// ```
// Then the type of `storages` is `GetArticleResponse_Storage` for the go language.
//
func goTypeWithGoPackage(p *descriptor.FileDescriptorProto, f *descriptor.FieldDescriptorProto) string {
pkg := ""
if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE || *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
if isTimestampPackage(*f.TypeName) {
pkg = "timestamp"
} else {
pkg = *p.GetOptions().GoPackage
if strings.Contains(*p.GetOptions().GoPackage, ";") {
pkg = strings.Split(*p.GetOptions().GoPackage, ";")[1]
}
}
}
return goTypeWithEmbedded(pkg, f, p)
}
// Warning does not handle message embedded like goTypeWithGoPackage does.
2017-05-02 00:55:55 +03:00
func goTypeWithPackage(f *descriptor.FieldDescriptorProto) string {
pkg := ""
if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE || *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
if isTimestampPackage(*f.TypeName) {
pkg = "timestamp"
} else {
pkg = getPackageTypeName(*f.TypeName)
}
}
2017-05-02 00:55:55 +03:00
return goType(pkg, f)
}
2017-06-22 14:40:09 +03:00
func haskellType(pkg string, f *descriptor.FieldDescriptorProto) string {
switch *f.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Float]"
}
return "Float"
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Float]"
}
return "Float"
case descriptor.FieldDescriptorProto_TYPE_INT64:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Int64]"
}
return "Int64"
case descriptor.FieldDescriptorProto_TYPE_UINT64:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Word]"
}
return "Word"
case descriptor.FieldDescriptorProto_TYPE_INT32:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Int]"
}
return "Int"
case descriptor.FieldDescriptorProto_TYPE_UINT32:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Word]"
}
return "Word"
case descriptor.FieldDescriptorProto_TYPE_BOOL:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Bool]"
}
return "Bool"
case descriptor.FieldDescriptorProto_TYPE_STRING:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Text]"
}
return "Text"
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
if pkg != "" {
pkg = pkg + "."
}
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return fmt.Sprintf("[%s%s]", pkg, shortType(*f.TypeName))
}
return fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName))
case descriptor.FieldDescriptorProto_TYPE_BYTES:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[Word8]"
}
return "Word8"
case descriptor.FieldDescriptorProto_TYPE_ENUM:
return fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName))
default:
return "Generic"
}
}
func goTypeWithEmbedded(pkg string, f *descriptor.FieldDescriptorProto, p *descriptor.FileDescriptorProto) string {
if pkg != "" {
pkg = pkg + "."
}
switch *f.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]float64"
}
return "float64"
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]float32"
}
return "float32"
case descriptor.FieldDescriptorProto_TYPE_INT64:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]int64"
}
return "int64"
case descriptor.FieldDescriptorProto_TYPE_UINT64:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]uint64"
}
return "uint64"
case descriptor.FieldDescriptorProto_TYPE_INT32:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]int32"
}
return "int32"
case descriptor.FieldDescriptorProto_TYPE_UINT32:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]uint32"
}
return "uint32"
case descriptor.FieldDescriptorProto_TYPE_BOOL:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]bool"
}
return "bool"
case descriptor.FieldDescriptorProto_TYPE_STRING:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]string"
}
return "string"
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
name := *f.TypeName
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
fieldPackage := strings.Split(*f.TypeName, ".")
filePackage := strings.Split(*p.Package, ".")
// check if we are working with a message embedded.
if len(fieldPackage) > 1 && len(fieldPackage)+1 > len(filePackage)+1 {
name = strings.Join(fieldPackage[len(filePackage)+1:], "_")
}
return fmt.Sprintf("[]*%s%s", pkg, shortType(name))
}
return fmt.Sprintf("*%s%s", pkg, shortType(name))
case descriptor.FieldDescriptorProto_TYPE_BYTES:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]byte"
}
return "byte"
case descriptor.FieldDescriptorProto_TYPE_ENUM:
name := *f.TypeName
fieldPackage := strings.Split(*f.TypeName, ".")
filePackage := strings.Split(*p.Package, ".")
// check if we are working with a message embedded.
if len(fieldPackage) > 1 && len(fieldPackage)+1 > len(filePackage)+1 {
name = strings.Join(fieldPackage[len(filePackage)+1:], "_")
}
return fmt.Sprintf("*%s%s", pkg, shortType(name))
default:
return "interface{}"
}
}
//Deprecated. Instead use goTypeWithEmbedded
func goType(pkg string, f *descriptor.FieldDescriptorProto) string {
2017-06-22 14:40:29 +03:00
if pkg != "" {
pkg = pkg + "."
}
switch *f.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]float64"
}
return "float64"
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]float32"
}
return "float32"
case descriptor.FieldDescriptorProto_TYPE_INT64:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]int64"
}
return "int64"
case descriptor.FieldDescriptorProto_TYPE_UINT64:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]uint64"
}
return "uint64"
case descriptor.FieldDescriptorProto_TYPE_INT32:
2017-06-09 12:53:33 +03:00
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]int32"
}
return "int32"
case descriptor.FieldDescriptorProto_TYPE_UINT32:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]uint32"
}
return "uint32"
case descriptor.FieldDescriptorProto_TYPE_BOOL:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]bool"
}
return "bool"
case descriptor.FieldDescriptorProto_TYPE_STRING:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]string"
}
return "string"
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return fmt.Sprintf("[]*%s%s", pkg, shortType(*f.TypeName))
}
return fmt.Sprintf("*%s%s", pkg, shortType(*f.TypeName))
case descriptor.FieldDescriptorProto_TYPE_BYTES:
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
return "[]byte"
}
return "byte"
case descriptor.FieldDescriptorProto_TYPE_ENUM:
2017-06-22 14:40:29 +03:00
return fmt.Sprintf("*%s%s", pkg, shortType(*f.TypeName))
default:
return "interface{}"
}
}
2018-01-12 20:38:10 +03:00
func goZeroValue(f *descriptor.FieldDescriptorProto) string {
2018-01-12 21:12:15 +03:00
const nilString = "nil"
2018-01-12 20:38:10 +03:00
if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
2018-01-12 21:12:15 +03:00
return nilString
2018-01-12 20:38:10 +03:00
}
switch *f.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
return "0.0"
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
return "0.0"
case descriptor.FieldDescriptorProto_TYPE_INT64:
return "0"
case descriptor.FieldDescriptorProto_TYPE_UINT64:
return "0"
case descriptor.FieldDescriptorProto_TYPE_INT32:
return "0"
case descriptor.FieldDescriptorProto_TYPE_UINT32:
return "0"
case descriptor.FieldDescriptorProto_TYPE_BOOL:
return "false"
case descriptor.FieldDescriptorProto_TYPE_STRING:
return "\"\""
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2018-01-12 21:12:15 +03:00
return nilString
2018-01-12 20:38:10 +03:00
case descriptor.FieldDescriptorProto_TYPE_BYTES:
return "0"
case descriptor.FieldDescriptorProto_TYPE_ENUM:
2018-01-12 21:12:15 +03:00
return nilString
2018-01-12 20:38:10 +03:00
default:
2018-01-12 21:12:15 +03:00
return nilString
2018-01-12 20:38:10 +03:00
}
}
2017-01-04 02:35:21 +03:00
func jsType(f *descriptor.FieldDescriptorProto) string {
2017-01-05 20:04:20 +03:00
template := "%s"
2017-12-25 11:17:09 +03:00
if isFieldRepeated(f) {
2017-01-05 20:04:20 +03:00
template = "Array<%s>"
}
2017-01-04 02:35:21 +03:00
switch *f.Type {
2017-01-10 13:40:48 +03:00
case descriptor.FieldDescriptorProto_TYPE_MESSAGE,
descriptor.FieldDescriptorProto_TYPE_ENUM:
2017-01-10 14:24:06 +03:00
return fmt.Sprintf(template, namespacedFlowType(*f.TypeName))
2017-01-05 20:04:20 +03:00
case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
descriptor.FieldDescriptorProto_TYPE_FLOAT,
descriptor.FieldDescriptorProto_TYPE_INT64,
descriptor.FieldDescriptorProto_TYPE_UINT64,
descriptor.FieldDescriptorProto_TYPE_INT32,
descriptor.FieldDescriptorProto_TYPE_FIXED64,
descriptor.FieldDescriptorProto_TYPE_FIXED32,
descriptor.FieldDescriptorProto_TYPE_UINT32,
descriptor.FieldDescriptorProto_TYPE_SFIXED32,
descriptor.FieldDescriptorProto_TYPE_SFIXED64,
descriptor.FieldDescriptorProto_TYPE_SINT32,
descriptor.FieldDescriptorProto_TYPE_SINT64:
return fmt.Sprintf(template, "number")
2017-01-04 02:35:21 +03:00
case descriptor.FieldDescriptorProto_TYPE_BOOL:
2017-01-05 20:04:20 +03:00
return fmt.Sprintf(template, "boolean")
2017-01-05 20:32:54 +03:00
case descriptor.FieldDescriptorProto_TYPE_BYTES:
2017-01-11 16:52:00 +03:00
return fmt.Sprintf(template, "Uint8Array")
2017-01-04 02:35:21 +03:00
case descriptor.FieldDescriptorProto_TYPE_STRING:
2017-01-05 20:04:20 +03:00
return fmt.Sprintf(template, "string")
2017-01-04 02:35:21 +03:00
default:
2017-01-05 20:04:20 +03:00
return fmt.Sprintf(template, "any")
2017-01-04 02:35:21 +03:00
}
}
2017-04-13 14:15:40 +03:00
func jsSuffixReservedKeyword(s string) string {
return jsReservedRe.ReplaceAllString(s, "${1}${2}_${3}")
}
func isTimestampPackage(s string) bool {
var isTimestampPackage bool
2017-06-08 17:40:52 +03:00
if strings.Compare(s, ".google.protobuf.Timestamp") == 0 {
isTimestampPackage = true
2017-06-08 17:40:52 +03:00
}
return isTimestampPackage
}
func getPackageTypeName(s string) string {
2017-05-02 00:55:55 +03:00
if strings.Contains(s, ".") {
return strings.Split(s, ".")[1]
}
return ""
}
func shortType(s string) string {
t := strings.Split(s, ".")
return t[len(t)-1]
}
2017-01-10 14:24:06 +03:00
func namespacedFlowType(s string) string {
trimmed := strings.TrimLeft(s, ".")
splitted := strings.Split(trimmed, ".")
2017-02-11 19:18:26 +03:00
return strings.Join(splitted, "$")
2017-01-10 14:24:06 +03:00
}
func httpPath(m *descriptor.MethodDescriptorProto) string {
ext, err := proto.GetExtension(m.Options, options.E_Http)
if err != nil {
return err.Error()
}
opts, ok := ext.(*options.HttpRule)
if !ok {
return fmt.Sprintf("extension is %T; want an HttpRule", ext)
}
switch t := opts.Pattern.(type) {
default:
return ""
case *options.HttpRule_Get:
return t.Get
case *options.HttpRule_Post:
return t.Post
case *options.HttpRule_Put:
return t.Put
case *options.HttpRule_Delete:
return t.Delete
case *options.HttpRule_Patch:
return t.Patch
case *options.HttpRule_Custom:
return t.Custom.Path
}
}
func httpPathsAdditionalBindings(m *descriptor.MethodDescriptorProto) []string {
ext, err := proto.GetExtension(m.Options, options.E_Http)
if err != nil {
panic(err.Error())
}
opts, ok := ext.(*options.HttpRule)
if !ok {
panic(fmt.Sprintf("extension is %T; want an HttpRule", ext))
}
var httpPaths []string
var optsAdditionalBindings = opts.GetAdditionalBindings()
for _, optAdditionalBindings := range optsAdditionalBindings {
switch t := optAdditionalBindings.Pattern.(type) {
case *options.HttpRule_Get:
httpPaths = append(httpPaths, t.Get)
case *options.HttpRule_Post:
httpPaths = append(httpPaths, t.Post)
case *options.HttpRule_Put:
httpPaths = append(httpPaths, t.Put)
case *options.HttpRule_Delete:
httpPaths = append(httpPaths, t.Delete)
case *options.HttpRule_Patch:
httpPaths = append(httpPaths, t.Patch)
case *options.HttpRule_Custom:
httpPaths = append(httpPaths, t.Custom.Path)
default:
// nothing
}
}
return httpPaths
}
func httpVerb(m *descriptor.MethodDescriptorProto) string {
ext, err := proto.GetExtension(m.Options, options.E_Http)
if err != nil {
return err.Error()
}
opts, ok := ext.(*options.HttpRule)
if !ok {
return fmt.Sprintf("extension is %T; want an HttpRule", ext)
}
switch t := opts.Pattern.(type) {
default:
return ""
case *options.HttpRule_Get:
return "GET"
case *options.HttpRule_Post:
return "POST"
case *options.HttpRule_Put:
return "PUT"
case *options.HttpRule_Delete:
return "DELETE"
case *options.HttpRule_Patch:
return "PATCH"
case *options.HttpRule_Custom:
return t.Custom.Kind
}
}
2017-09-19 23:53:57 +03:00
func httpBody(m *descriptor.MethodDescriptorProto) string {
ext, err := proto.GetExtension(m.Options, options.E_Http)
if err != nil {
return err.Error()
}
opts, ok := ext.(*options.HttpRule)
if !ok {
return fmt.Sprintf("extension is %T; want an HttpRule", ext)
}
return opts.Body
}
func urlHasVarsFromMessage(path string, d *ggdescriptor.Message) bool {
for _, field := range d.Field {
if !isFieldMessage(field) {
if strings.Contains(path, fmt.Sprintf("{%s}", *field.Name)) {
return true
}
}
}
return false
}
// lowerGoNormalize takes a string and applies formatting
// rules to conform to Golang convention. It applies a camel
// case filter, lowers the first character and formats fields
// with `id` to `ID`.
func lowerGoNormalize(s string) string {
fmtd := xstrings.ToCamelCase(s)
fmtd = xstrings.FirstRuneToLower(fmtd)
return formatID(s, fmtd)
}
// goNormalize takes a string and applies formatting rules
// to conform to Golang convention. It applies a camel case
// filter and formats fields with `id` to `ID`.
func goNormalize(s string) string {
fmtd := xstrings.ToCamelCase(s)
return formatID(s, fmtd)
}
// formatID takes a base string alonsgide a formatted string.
// It acts as a transformation filter for fields containing
// `id` in order to conform to Golang convention.
func formatID(base string, formatted string) string {
if formatted == "" {
return formatted
}
switch {
case base == "id":
// id -> ID
return "ID"
case strings.HasPrefix(base, "id_"):
// id_some -> IDSome
return "ID" + formatted[2:]
case strings.HasSuffix(base, "_id"):
// some_id -> SomeID
return formatted[:len(formatted)-2] + "ID"
case strings.HasSuffix(base, "_ids"):
// some_ids -> SomeIDs
return formatted[:len(formatted)-3] + "IDs"
}
return formatted
}
2018-01-12 20:38:10 +03:00
func replaceDict(src string, dict map[string]interface{}) string {
for old, v := range dict {
new, ok := v.(string)
if !ok {
continue
}
src = strings.Replace(src, old, new, -1)
}
return src
}
func goPkg(f *descriptor.FileDescriptorProto) string {
return f.Options.GetGoPackage()
}
func goPkgLastElement(f *descriptor.FileDescriptorProto) string {
pkg := goPkg(f)
pkgSplitted := strings.Split(pkg, "/")
return pkgSplitted[len(pkgSplitted)-1]
}