64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
|
package casing
|
||
|
|
||
|
// Camel returns the CamelCased name.
|
||
|
//
|
||
|
// This was moved from the now deprecated github.com/golang/protobuf/protoc-gen-go/generator package
|
||
|
//
|
||
|
// If there is an interior underscore followed by a lower case letter,
|
||
|
// drop the underscore and convert the letter to upper case.
|
||
|
// There is a remote possibility of this rewrite causing a name collision,
|
||
|
// but it's so remote we're prepared to pretend it's nonexistent - since the
|
||
|
// C++ generator lowercases names, it's extremely unlikely to have two fields
|
||
|
// with different capitalizations.
|
||
|
// In short, _my_field_name_2 becomes XMyFieldName_2.
|
||
|
func Camel(s string) string {
|
||
|
if s == "" {
|
||
|
return ""
|
||
|
}
|
||
|
t := make([]byte, 0, 32)
|
||
|
i := 0
|
||
|
if s[0] == '_' {
|
||
|
// Need a capital letter; drop the '_'.
|
||
|
t = append(t, 'X')
|
||
|
i++
|
||
|
}
|
||
|
// Invariant: if the next letter is lower case, it must be converted
|
||
|
// to upper case.
|
||
|
// That is, we process a word at a time, where words are marked by _ or
|
||
|
// upper case letter. Digits are treated as words.
|
||
|
for ; i < len(s); i++ {
|
||
|
c := s[i]
|
||
|
if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
|
||
|
continue // Skip the underscore in s.
|
||
|
}
|
||
|
if isASCIIDigit(c) {
|
||
|
t = append(t, c)
|
||
|
continue
|
||
|
}
|
||
|
// Assume we have a letter now - if not, it's a bogus identifier.
|
||
|
// The next word is a sequence of characters that must start upper case.
|
||
|
if isASCIILower(c) {
|
||
|
c ^= ' ' // Make it a capital letter.
|
||
|
}
|
||
|
t = append(t, c) // Guaranteed not lower case.
|
||
|
// Accept lower case sequence that follows.
|
||
|
for i+1 < len(s) && isASCIILower(s[i+1]) {
|
||
|
i++
|
||
|
t = append(t, s[i])
|
||
|
}
|
||
|
}
|
||
|
return string(t)
|
||
|
}
|
||
|
|
||
|
// And now lots of helper functions.
|
||
|
|
||
|
// Is c an ASCII lower-case letter?
|
||
|
func isASCIILower(c byte) bool {
|
||
|
return 'a' <= c && c <= 'z'
|
||
|
}
|
||
|
|
||
|
// Is c an ASCII digit?
|
||
|
func isASCIIDigit(c byte) bool {
|
||
|
return '0' <= c && c <= '9'
|
||
|
}
|