Created
June 4, 2020 19:22
-
-
Save ydnar/327d33e4c9fa54f08b6d7f0e31880bf7 to your computer and use it in GitHub Desktop.
protoc-gen-good
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"flag" | |
"fmt" | |
"os" | |
"path/filepath" | |
"strings" | |
"unicode" | |
gengo "google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo" | |
"google.golang.org/protobuf/compiler/protogen" | |
"google.golang.org/protobuf/proto" | |
"google.golang.org/protobuf/reflect/protoreflect" | |
"google.golang.org/protobuf/types/descriptorpb" | |
) | |
func main() { | |
if len(os.Args) == 2 && os.Args[1] == "--version" { | |
fmt.Fprintf(os.Stderr, "%v %v\n", filepath.Base(os.Args[0]), "1.0") | |
os.Exit(1) | |
} | |
var ( | |
flags flag.FlagSet | |
plugins = flags.String("plugins", "", "deprecated option") | |
importPrefix = flags.String("import_prefix", "", "deprecated option") | |
) | |
protogen.Options{ | |
ParamFunc: flags.Set, | |
}.Run(func(gen *protogen.Plugin) error { | |
if *plugins != "" { | |
return errors.New("protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC") | |
} | |
if *importPrefix != "" { | |
return errors.New("protoc-gen-go: import_prefix is not supported") | |
} | |
for _, f := range gen.Files { | |
if f.Generate { | |
fixNames(f) | |
gengo.GenerateFile(gen, f) | |
} | |
} | |
return nil | |
}) | |
} | |
func fixNames(f *protogen.File) { | |
for _, e := range f.Enums { | |
fmt.Fprintf(os.Stderr, "Enum: %s\n", e.GoIdent.String()) | |
for _, v := range e.Values { | |
fmt.Fprintf(os.Stderr, "Value: %s\n", v.GoIdent.GoName) | |
} | |
} | |
for _, m := range f.Messages { | |
fmt.Fprintf(os.Stderr, "Message: %s\n", m.GoIdent.String()) | |
for _, field := range m.Fields { | |
options := field.Desc.Options().(*descriptorpb.FieldOptions) | |
fmt.Fprintf(os.Stderr, "Field: %s → %s → %s Ident: %v → %v\n", | |
field.Desc.Name(), field.GoName, fixCamelCase(field.GoName), | |
field.GoIdent.GoName, fixCamelCase(field.GoIdent.GoName)) | |
field.GoName = fixCamelCase(field.GoName) | |
field.GoIdent.GoName = fixCamelCase(field.GoIdent.GoName) | |
} | |
} | |
} | |
// fixCamelCase returns a different name if it should be different. | |
// Copied from: https://github.com/golang/lint/blob/master/lint.go | |
func fixCamelCase(name string) string { | |
// Fast path for simple case: "" and "_" | |
if name == "" || name == "_" { | |
return name | |
} | |
runes := []rune(name) | |
// Ensure first character is uppercase. | |
runes[0] = unicode.ToUpper(runes[0]) | |
// Split camelCase at any lower->upper transition, and split on underscores. | |
// Check each word for common initialisms. | |
w, i := 0, 0 // index of start of word, scan | |
for i+1 <= len(runes) { | |
eow := false // whether we hit the end of a word | |
if i+1 == len(runes) { | |
eow = true | |
} else if runes[i+1] == '_' { | |
// underscore; shift the remainder forward over any run of underscores | |
eow = true | |
n := 1 | |
for i+n+1 < len(runes) && runes[i+n+1] == '_' { | |
n++ | |
} | |
// Leave at most one underscore if the underscore is between two digits | |
if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) { | |
n-- | |
} | |
copy(runes[i+1:], runes[i+n+1:]) | |
runes = runes[:len(runes)-n] | |
} else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) { | |
// lower->non-lower | |
eow = true | |
} | |
i++ | |
if !eow { | |
continue | |
} | |
// [w,i) is a word. | |
word := string(runes[w:i]) | |
if u := strings.ToUpper(word); commonInitialisms[u] { | |
// Keep consistent case, which is lowercase only at the start. | |
if w == 0 && unicode.IsLower(runes[w]) { | |
u = strings.ToLower(u) | |
} | |
// All the common initialisms are ASCII, | |
// so we can replace the bytes exactly. | |
copy(runes[w:], []rune(u)) | |
} else if w > 0 && strings.ToLower(word) == word { | |
// already all lowercase, and not the first word, so uppercase the first character. | |
runes[w] = unicode.ToUpper(runes[w]) | |
} | |
w = i | |
} | |
return string(runes) | |
} | |
// commonInitialisms is a set of common initialisms. | |
// Only add entries that are highly unlikely to be non-initialisms. | |
// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. | |
// Copied from: https://github.com/golang/lint/blob/master/lint.go | |
var commonInitialisms = map[string]bool{ | |
"ACL": true, | |
"API": true, | |
"ASCII": true, | |
"CPU": true, | |
"CSS": true, | |
"CORS": true, | |
"DNS": true, | |
"EOF": true, | |
"GUID": true, | |
"HTML": true, | |
"HTTP": true, | |
"HTTPS": true, | |
"ID": true, | |
"IMAP": true, | |
"IP": true, | |
"JSON": true, | |
"LHS": true, | |
"QPS": true, | |
"RAM": true, | |
"RFC": true, | |
"RHS": true, | |
"RPC": true, | |
"SLA": true, | |
"SMTP": true, | |
"SQL": true, | |
"SSH": true, | |
"TCP": true, | |
"TLS": true, | |
"TTL": true, | |
"UDP": true, | |
"UI": true, | |
"UID": true, | |
"UUID": true, | |
"URI": true, | |
"URL": true, | |
"UTF8": true, | |
"VM": true, | |
"XML": true, | |
"XMPP": true, | |
"XSRF": true, | |
"XSS": true, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment