diff --git a/codegen/config/config.go b/codegen/config/config.go index 923442862c1..b1b3a5cca3e 100644 --- a/codegen/config/config.go +++ b/codegen/config/config.go @@ -26,6 +26,7 @@ type Config struct { Models TypeMap `yaml:"models,omitempty"` StructTag string `yaml:"struct_tag,omitempty"` Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` + GoInitialisms GoInitialismsConfig `yaml:"go_initialisms,omitempty"` OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"` OmitGetters bool `yaml:"omit_getters,omitempty"` OmitComplexity bool `yaml:"omit_complexity,omitempty"` @@ -201,6 +202,9 @@ func CompleteConfig(config *Config) error { config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)}) } + + config.GoInitialisms.setInitialisms() + return nil } diff --git a/codegen/config/initialisms.go b/codegen/config/initialisms.go new file mode 100644 index 00000000000..5c169c89004 --- /dev/null +++ b/codegen/config/initialisms.go @@ -0,0 +1,94 @@ +package config + +import "strings" + +// 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, + "CSV": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTP": true, + "HTTPS": true, + "ICMP": true, + "ID": true, + "IP": true, + "JSON": true, + "KVK": true, + "LHS": true, + "PDF": true, + "PGP": true, + "QPS": true, + "QR": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SQL": true, + "SSH": true, + "SVG": true, + "TCP": true, + "TLS": true, + "TTL": true, + "UDP": true, + "UI": true, + "UID": true, + "URI": true, + "URL": true, + "UTF8": true, + "UUID": true, + "VM": true, + "XML": true, + "XMPP": true, + "XSRF": true, + "XSS": true, +} + +// GetInitialisms returns the initialisms to capitalize in Go names. If unchanged, default initialisms will be returned +var GetInitialisms = func() map[string]bool { + return commonInitialisms +} + +// GoInitialismsConfig allows to modify the default behavior of naming Go methods, types and properties +type GoInitialismsConfig struct { + // If true, the Initialisms won't get appended to the default ones but replace them + ReplaceDefaults bool `yaml:"replace_defaults"` + // Custom initialisms to be added or to replace the default ones + Initialisms []string `yaml:"initialisms"` +} + +// setInitialisms adjustes GetInitialisms based on its settings. +func (i GoInitialismsConfig) setInitialisms() { + toUse := i.determineGoInitialisms() + GetInitialisms = func() map[string]bool { + return toUse + } +} + +// determineGoInitialisms returns the Go initialims to be used, based on its settings. +func (i GoInitialismsConfig) determineGoInitialisms() (initialismsToUse map[string]bool) { + if i.ReplaceDefaults { + initialismsToUse = make(map[string]bool, len(i.Initialisms)) + for _, initialism := range i.Initialisms { + initialismsToUse[strings.ToUpper(initialism)] = true + } + } else { + initialismsToUse = make(map[string]bool, len(commonInitialisms)+len(i.Initialisms)) + for initialism, value := range commonInitialisms { + initialismsToUse[strings.ToUpper(initialism)] = value + } + for _, initialism := range i.Initialisms { + initialismsToUse[strings.ToUpper(initialism)] = true + } + } + return initialismsToUse +} diff --git a/codegen/config/initialisms_test.go b/codegen/config/initialisms_test.go new file mode 100644 index 00000000000..5bea561a3a3 --- /dev/null +++ b/codegen/config/initialisms_test.go @@ -0,0 +1,39 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGoInitialismsConfig(t *testing.T) { + t.Run("load go initialisms config", func(t *testing.T) { + config, err := LoadConfig("testdata/cfg/goInitialisms.yml") + require.NoError(t, err) + require.True(t, config.GoInitialisms.ReplaceDefaults) + require.Len(t, config.GoInitialisms.Initialisms, 2) + }) + t.Run("empty initialism config doesn't change anything", func(t *testing.T) { + tt := GoInitialismsConfig{} + result := tt.determineGoInitialisms() + assert.Equal(t, len(commonInitialisms), len(result)) + }) + t.Run("initialism config appends if desired", func(t *testing.T) { + tt := GoInitialismsConfig{ReplaceDefaults: false, Initialisms: []string{"ASDF"}} + result := tt.determineGoInitialisms() + assert.Equal(t, len(commonInitialisms)+1, len(result)) + assert.True(t, result["ASDF"]) + }) + t.Run("initialism config replaces if desired", func(t *testing.T) { + tt := GoInitialismsConfig{ReplaceDefaults: true, Initialisms: []string{"ASDF"}} + result := tt.determineGoInitialisms() + assert.Equal(t, 1, len(result)) + assert.True(t, result["ASDF"]) + }) + t.Run("initialism config uppercases the initialsms", func(t *testing.T) { + tt := GoInitialismsConfig{Initialisms: []string{"asdf"}} + result := tt.determineGoInitialisms() + assert.True(t, result["ASDF"]) + }) +} diff --git a/codegen/config/testdata/cfg/goInitialisms.yml b/codegen/config/testdata/cfg/goInitialisms.yml new file mode 100644 index 00000000000..662bbd7974c --- /dev/null +++ b/codegen/config/testdata/cfg/goInitialisms.yml @@ -0,0 +1,5 @@ +go_initialisms: + replace_defaults: true + initialisms: + - 'CC' + - 'BCC' diff --git a/codegen/templates/templates.go b/codegen/templates/templates.go index 6d536d3c17e..332498f878f 100644 --- a/codegen/templates/templates.go +++ b/codegen/templates/templates.go @@ -465,14 +465,15 @@ func wordWalker(str string, f func(*wordInfo)) { } i++ + initialisms := config.GetInitialisms() // [w,i) is a word. word := string(runes[w:i]) - if !eow && commonInitialisms[word] && !unicode.IsLower(runes[i]) { + if !eow && initialisms[word] && !unicode.IsLower(runes[i]) { // through // split IDFoo → ID, Foo // but URLs → URLs } else if !eow { - if commonInitialisms[word] { + if initialisms[word] { hasCommonInitial = true } continue @@ -480,7 +481,7 @@ func wordWalker(str string, f func(*wordInfo)) { matchCommonInitial := false upperWord := strings.ToUpper(word) - if commonInitialisms[upperWord] { + if initialisms[upperWord] { // If the uppercase word (string(runes[w:i]) is "ID" or "IP" // AND // the word is the first two characters of the str @@ -553,57 +554,6 @@ func sanitizeKeywords(name string) string { return name } -// 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, - "CSV": true, - "DNS": true, - "EOF": true, - "GUID": true, - "HTML": true, - "HTTP": true, - "HTTPS": true, - "ICMP": true, - "ID": true, - "IP": true, - "JSON": true, - "KVK": true, - "LHS": true, - "PDF": true, - "PGP": true, - "QPS": true, - "QR": true, - "RAM": true, - "RHS": true, - "RPC": true, - "SLA": true, - "SMTP": true, - "SQL": true, - "SSH": true, - "SVG": true, - "TCP": true, - "TLS": true, - "TTL": true, - "UDP": true, - "UI": true, - "UID": true, - "URI": true, - "URL": true, - "UTF8": true, - "UUID": true, - "VM": true, - "XML": true, - "XMPP": true, - "XSRF": true, - "XSS": true, -} - func rawQuote(s string) string { return "`" + strings.ReplaceAll(s, "`", "`+\"`\"+`") + "`" } diff --git a/docs/config.yml b/docs/config.yml index 3b63f08286b..e6a1e73e296 100644 --- a/docs/config.yml +++ b/docs/config.yml @@ -28,6 +28,12 @@ menu: security: funcs: getenv: - - '^HUGO_' - - 'VERSIONS' - - 'CURRENT_VERSION' + - '^HUGO_' + - 'VERSIONS' + - 'CURRENT_VERSION' + +go_initialisms: + replace_defaults: false + initialisms: + - 'CC' + - 'BCC' diff --git a/docs/content/config.md b/docs/content/config.md index aa8c8a3ba3d..493da22cd0c 100644 --- a/docs/content/config.md +++ b/docs/content/config.md @@ -77,6 +77,13 @@ resolver: # Optional: set to skip running `go mod tidy` when generating server code # skip_mod_tidy: true +# Optional: set to modify the initialisms regarded for Go names +# go_initialisms: +# replace_defaults: false # if true, the default initialisms will get dropped in favor of the new ones instead of being added +# initialisms: # List of initialisms to for Go names +# - 'CC' +# - 'BCC' + # gqlgen will search for any type names in the schema in these go packages # if they match it will use them, otherwise it will generate them. # autobind: