Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make more golint free generated code #241

Merged
merged 2 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions codegen/models_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,7 @@ func (cfg *Config) obj2Model(obj *Object) Model {
if field.GoFieldName != "" {
mf.GoFieldName = field.GoFieldName
} else {
mf.GoFieldName = ucFirst(field.GQLName)
if mf.IsScalar {
if mf.GoFieldName == "Id" {
mf.GoFieldName = "ID"
}
}
mf.GoFieldName = field.GoNameExported()
}

model.Fields = append(model.Fields, mf)
Expand Down
148 changes: 141 additions & 7 deletions codegen/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,37 +86,57 @@ func (f *Field) IsConcurrent() bool {
return f.IsResolver() && !f.Object.DisableConcurrency
}

func (f *Field) GoNameExported() string {
return lintName(ucFirst(f.GQLName))
}

func (f *Field) GoNameUnexported() string {
return lintName(f.GQLName)
}

func (f *Field) ShortInvocation() string {
if !f.IsResolver() {
return ""
}
shortName := strings.ToUpper(f.GQLName[:1]) + f.GQLName[1:]

return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, shortName, f.CallArgs())
return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, f.GoNameExported(), f.CallArgs())
}

func (f *Field) ResolverType() string {
if !f.IsResolver() {
return ""
}
shortName := strings.ToUpper(f.GQLName[:1]) + f.GQLName[1:]

return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, shortName, f.CallArgs())
return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, f.GoNameExported(), f.CallArgs())
}

func (f *Field) ShortResolverDeclaration() string {
if !f.IsResolver() {
return ""
}
decl := strings.TrimPrefix(f.ResolverDeclaration(), f.Object.GQLType+"_")
return strings.ToUpper(decl[:1]) + decl[1:]
res := fmt.Sprintf("%s(ctx context.Context", f.GoNameExported())

if !f.Object.Root {
res += fmt.Sprintf(", obj *%s", f.Object.FullName())
}
for _, arg := range f.Args {
res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature())
}

result := f.Signature()
if f.Object.Stream {
result = "<-chan " + result
}

res += fmt.Sprintf(") (%s, error)", result)
return res
}

func (f *Field) ResolverDeclaration() string {
if !f.IsResolver() {
return ""
}
res := fmt.Sprintf("%s_%s(ctx context.Context", f.Object.GQLType, f.GQLName)
res := fmt.Sprintf("%s_%s(ctx context.Context", f.Object.GQLType, f.GoNameUnexported())

if !f.Object.Root {
res += fmt.Sprintf(", obj *%s", f.Object.FullName())
Expand Down Expand Up @@ -226,3 +246,117 @@ func ucFirst(s string) string {
r[0] = unicode.ToUpper(r[0])
return string(r)
}

// copy from https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679

// lintName returns a different name if it should be different.
func lintName(name 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])
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.
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,
}
2 changes: 2 additions & 0 deletions example/config/.gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ resolver:
models:
Todo: # Object
fields:
id:
resolver: true
text:
fieldName: Description # Field
NewTodo: # Input
Expand Down
39 changes: 36 additions & 3 deletions example/config/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions example/config/models_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 19 additions & 4 deletions example/config/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ func New() Config {
c := Config{
Resolvers: &Resolver{
todos: []Todo{
{ID: "TODO:1", Description: "A todo not to forget", Done: false},
{ID: "TODO:2", Description: "This is the most important", Done: false},
{ID: "TODO:3", Description: "Please do this or else", Done: false},
{DatabaseID: 1, Description: "A todo not to forget", Done: false},
{DatabaseID: 2, Description: "This is the most important", Done: false},
{DatabaseID: 3, Description: "Please do this or else", Done: false},
},
nextID: 3,
},
Expand All @@ -32,6 +32,9 @@ func (r *Resolver) Mutation() MutationResolver {
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
}
func (r *Resolver) Todo() TodoResolver {
return &todoResolver{r}
}

type mutationResolver struct{ *Resolver }

Expand All @@ -40,7 +43,7 @@ func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (Todo,
r.nextID++

newTodo := Todo{
ID: fmt.Sprintf("TODO:%d", newID),
DatabaseID: newID,
Description: input.Text,
}

Expand All @@ -54,3 +57,15 @@ type queryResolver struct{ *Resolver }
func (r *queryResolver) Todos(ctx context.Context) ([]Todo, error) {
return r.todos, nil
}

type todoResolver struct{ *Resolver }

func (r *todoResolver) ID(ctx context.Context, obj *Todo) (string, error) {
if obj.ID != "" {
return obj.ID, nil
}

obj.ID = fmt.Sprintf("TODO:%d", obj.DatabaseID)

return obj.ID, nil
}
1 change: 1 addition & 0 deletions example/config/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

type Todo {
id: ID!
databaseId: Int!
text: String!
done: Boolean!
user: User!
Expand Down
4 changes: 2 additions & 2 deletions test/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/resolvers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (r *queryResolver) Viewer(ctx context.Context) (*models.Viewer, error) {
}, nil
}

func (r *queryResolver) JsonEncoding(ctx context.Context) (string, error) {
func (r *queryResolver) JSONEncoding(ctx context.Context) (string, error) {
return "\U000fe4ed", nil
}

Expand Down