redo comment parsing to set up for field-level config
This commit is contained in:
@@ -101,7 +101,7 @@ Generated code customization:
|
|||||||
- add flag(s) to make a field use a pointer (for optionality or perf; see DESIGN)
|
- add flag(s) to make a field use a pointer (for optionality or perf; see DESIGN)
|
||||||
- omitempty-like thing for optional arguments
|
- omitempty-like thing for optional arguments
|
||||||
- collapsing -- should be able to have `mutation { myMutation { error { code } } }` just return `(code string, err error)`
|
- collapsing -- should be able to have `mutation { myMutation { error { code } } }` just return `(code string, err error)`
|
||||||
- map a GraphQL type to a particular Go type (if you want to use a named type for some string, say)
|
- map a field to a particular Go type (if you want to use a named type for some string, say)
|
||||||
- specify a particular name for a Go type, or for the helper function, or whatever else
|
- specify a particular name for a Go type, or for the helper function, or whatever else
|
||||||
- include full query in generated godoc
|
- include full query in generated godoc
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package generate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
"github.com/vektah/gqlparser/v2/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *generator) parsePrecedingComment(pos *ast.Position) (comment string, directives []*ast.Directive, err error) {
|
||||||
|
var commentLines []string
|
||||||
|
sourceLines := strings.Split(pos.Src.Input, "\n")
|
||||||
|
for i := pos.Line - 1; i > 0; i-- {
|
||||||
|
line := strings.TrimSpace(sourceLines[i-1])
|
||||||
|
trimmed := strings.TrimSpace(strings.TrimPrefix(line, "#"))
|
||||||
|
if strings.HasPrefix(line, "# @genqlient") {
|
||||||
|
directive, err := parseDirective(trimmed, pos)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
directives = append(directives, directive)
|
||||||
|
} else if strings.HasPrefix(line, "#") {
|
||||||
|
commentLines = append(commentLines, trimmed)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse(commentLines)
|
||||||
|
|
||||||
|
return strings.TrimSpace(strings.Join(commentLines, "\n")), directives, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDirective(line string, pos *ast.Position) (*ast.Directive, error) {
|
||||||
|
// HACK: parse the "directive" by making a fake query containing it.
|
||||||
|
fakeQuery := fmt.Sprintf("query %v { field }", line)
|
||||||
|
doc, err := parser.ParseQuery(&ast.Source{
|
||||||
|
Name: fmt.Sprintf("@genqlient directive at %v:%v:%v",
|
||||||
|
pos.Src.Name, pos.Line, pos.Column),
|
||||||
|
Input: fakeQuery,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return doc.Operations[0].Directives[0], nil
|
||||||
|
}
|
||||||
@@ -76,6 +76,9 @@ type Config struct {
|
|||||||
// to int, Float to float64, and Boolean to bool), but this setting will
|
// to int, Float to float64, and Boolean to bool), but this setting will
|
||||||
// extend or override those mappings. These types must define MarshalJSON
|
// extend or override those mappings. These types must define MarshalJSON
|
||||||
// and UnmarshalJSON methods, or otherwise be convertible to JSON.
|
// and UnmarshalJSON methods, or otherwise be convertible to JSON.
|
||||||
|
// TODO: figure out if it makes sense to say you can use these for
|
||||||
|
// non-scalar types; technically it should just work, but what if you
|
||||||
|
// didn't request the right fields?
|
||||||
Scalars map[string]string `yaml:"scalars"`
|
Scalars map[string]string `yaml:"scalars"`
|
||||||
|
|
||||||
// Set automatically to the filename of the config file itself.
|
// Set automatically to the filename of the config file itself.
|
||||||
|
|||||||
+11
-19
@@ -120,24 +120,6 @@ func (g *generator) getArgument(opName string, arg *ast.VariableDefinition) (arg
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *generator) getDocComment(op *ast.OperationDefinition) string {
|
|
||||||
var commentLines []string
|
|
||||||
sourceLines := strings.Split(op.Position.Src.Input, "\n")
|
|
||||||
for i := op.Position.Line - 1; i > 0; i-- {
|
|
||||||
line := strings.TrimSpace(sourceLines[i-1])
|
|
||||||
if strings.HasPrefix(line, "#") && !strings.HasPrefix(line, "# @genqlient") {
|
|
||||||
commentLines = append(commentLines,
|
|
||||||
"// "+strings.TrimSpace(strings.TrimPrefix(line, "#")))
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse(commentLines)
|
|
||||||
|
|
||||||
return strings.Join(commentLines, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *generator) addOperation(op *ast.OperationDefinition) error {
|
func (g *generator) addOperation(op *ast.OperationDefinition) error {
|
||||||
if op.Name == "" {
|
if op.Name == "" {
|
||||||
return fmt.Errorf("operations must have operation-names")
|
return fmt.Errorf("operations must have operation-names")
|
||||||
@@ -165,10 +147,20 @@ func (g *generator) addOperation(op *ast.OperationDefinition) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commentLines, _, err := g.parsePrecedingComment(op.Position)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var docComment string
|
||||||
|
if len(commentLines) > 0 {
|
||||||
|
docComment = "// " + strings.ReplaceAll(commentLines, "\n", "\n// ")
|
||||||
|
}
|
||||||
|
|
||||||
g.Operations = append(g.Operations, operation{
|
g.Operations = append(g.Operations, operation{
|
||||||
Type: op.Operation,
|
Type: op.Operation,
|
||||||
Name: op.Name,
|
Name: op.Name,
|
||||||
Doc: g.getDocComment(op),
|
Doc: docComment,
|
||||||
// The newline just makes it format a little nicer.
|
// The newline just makes it format a little nicer.
|
||||||
Body: "\n" + builder.String(),
|
Body: "\n" + builder.String(),
|
||||||
Args: args,
|
Args: args,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# @genqlient
|
||||||
|
#
|
||||||
# SimpleMutation creates a user.
|
# SimpleMutation creates a user.
|
||||||
#
|
#
|
||||||
# It has a long doc-comment, to test that we handle that correctly.
|
# It has a long doc-comment, to test that we handle that correctly.
|
||||||
|
|||||||
Reference in New Issue
Block a user