Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.9 KiB
128 lines
2.9 KiB
package lint |
|
|
|
import ( |
|
"strings" |
|
"unicode" |
|
) |
|
|
|
// Name returns a different name if it should be different. |
|
func Name(name string, whitelist, blacklist []string) (should string) { |
|
// Fast path for simple cases: "_" and all lowercase. |
|
if name == "_" { |
|
return name |
|
} |
|
allLower := true |
|
for _, r := range name { |
|
if !unicode.IsLower(r) { |
|
allLower = false |
|
break |
|
} |
|
} |
|
if allLower { |
|
return name |
|
} |
|
|
|
// Split camelCase at any lower->upper transition, and split on underscores. |
|
// Check each word for common initialisms. |
|
runes := []rune(name) |
|
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]) |
|
ignoreInitWarnings := map[string]bool{} |
|
for _, i := range whitelist { |
|
ignoreInitWarnings[i] = true |
|
} |
|
|
|
extraInits := map[string]bool{} |
|
for _, i := range blacklist { |
|
extraInits[i] = true |
|
} |
|
|
|
if u := strings.ToUpper(word); (commonInitialisms[u] || extraInits[u]) && !ignoreInitWarnings[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. |
|
var commonInitialisms = map[string]bool{ |
|
"ACL": true, |
|
"API": true, |
|
"ASCII": true, |
|
"CPU": true, |
|
"CSS": true, |
|
"DNS": true, |
|
"EOF": true, |
|
"GUID": true, |
|
"HTML": true, |
|
"HTTP": true, |
|
"HTTPS": true, |
|
"ID": true, |
|
"IP": true, |
|
"JSON": true, |
|
"LHS": true, |
|
"QPS": true, |
|
"RAM": 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, |
|
}
|
|
|