diff --git a/.golangci.yaml b/.golangci.yaml index 290bdcc0..b667a302 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,33 +1,125 @@ +# All settings can be found here https://github.com/golangci/golangci-lint/blob/HEAD/.golangci.reference.yml version: "2" run: tests: true +formatters: + enable: + - golines + - gofumpt + - gci + settings: + gci: + sections: + - standard + - default + - prefix(github.com/vektah) + golines: + # Target maximum line length. + # Default: 100 + max-len: 100 + shorten-comments: true + exclusions: + paths: + - generated + - node_modules + - bin + - third_party$ + - builtin$ + - examples$ linters: default: none enable: +# - asasalint +# - asciicheck +# - bidichk - bodyclose +# - copyloopvar - dupl +# - dupword +# - durationcheck - errcheck - gocritic - govet - ineffassign - misspell - nakedret - - prealloc +# - nolintlint +# - perfsprint +# - reassign - revive - staticcheck +# - testableexamples - testifylint - unconvert +# - unparam - unused +# - usestdlibvars +# - usetesting +# - wastedassign +# - prealloc # disabled because it is a huge pain settings: errcheck: exclude-functions: - (io.Writer).Write + - (http.ResponseWriter).Write + - (*bytes.Buffer).WriteByte + - (*strings.Builder).WriteByte + - (*strings.Builder).WriteString - io.Copy - io.WriteString + - fmt.Fprintln + gocritic: + enabled-checks: + - emptyStringTest + - equalFold + - httpNoBody + - nilValReturn + - paramTypeCombine + - preferFprint + - yodaStyleExpr + govet: + disable: + - fieldalignment + - shadow + - unusedwrite + enable-all: true + perfsprint: + int-conversion: false + err-error: false + errorf: true + sprintf1: false + strconcat: false revive: enable-all-rules: false rules: - name: empty-lines + - name: use-any + # https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#struct-tag +# - name: struct-tag +# exclude: ["**/*_go124_test.go"] +# - name: blank-imports +# - name: context-as-argument +# - name: context-keys-type +# - name: error-return +# - name: error-naming +# - name: exported +# disabled: true +# - name: if-return +# - name: increment-decrement +# - name: var-declaration +# - name: package-comments +# disabled: true +# - name: range +# - name: receiver-naming +# - name: time-naming +# - name: unexported-return +# - name: indent-error-flow +# - name: errorf +# - name: superfluous-else +# - name: unused-parameter +# disabled: true +# - name: unreachable-code +# - name: redefines-builtin-id testifylint: disable-all: true enable: @@ -54,14 +146,3 @@ linters: - third_party$ - builtin$ - examples$ -formatters: - enable: - - gofmt - - goimports - exclusions: - generated: lax - paths: - - bin - - third_party$ - - builtin$ - - examples$ diff --git a/ast/argmap.go b/ast/argmap.go index 43f6a3d6..1b65c276 100644 --- a/ast/argmap.go +++ b/ast/argmap.go @@ -1,11 +1,15 @@ package ast -func arg2map(defs ArgumentDefinitionList, args ArgumentList, vars map[string]interface{}) map[string]interface{} { - result := map[string]interface{}{} +func arg2map( + defs ArgumentDefinitionList, + args ArgumentList, + vars map[string]any, +) map[string]any { + result := map[string]any{} var err error for _, argDef := range defs { - var val interface{} + var val any var hasValue bool if argValue := args.ForName(argDef.Name); argValue != nil { diff --git a/ast/argmap_test.go b/ast/argmap_test.go index 9ac50a6b..1f7971a9 100644 --- a/ast/argmap_test.go +++ b/ast/argmap_test.go @@ -8,7 +8,11 @@ import ( func TestArg2Map(t *testing.T) { defs := ArgumentDefinitionList{ - {Name: "A", Type: NamedType("String", nil), DefaultValue: &Value{Kind: StringValue, Raw: "defaultA"}}, + { + Name: "A", + Type: NamedType("String", nil), + DefaultValue: &Value{Kind: StringValue, Raw: "defaultA"}, + }, {Name: "B", Type: NamedType("String", nil)}, } @@ -42,7 +46,7 @@ func TestArg2Map(t *testing.T) { args := arg2map(defs, ArgumentList{ {Name: "A", Value: &Value{Kind: Variable, Raw: "VarA"}}, {Name: "B", Value: &Value{Kind: Variable, Raw: "VarB"}}, - }, map[string]interface{}{}) + }, map[string]any{}) require.Equal(t, "defaultA", args["A"]) require.NotContains(t, args, "B") }) @@ -51,7 +55,7 @@ func TestArg2Map(t *testing.T) { args := arg2map(defs, ArgumentList{ {Name: "A", Value: &Value{Kind: Variable, Raw: "VarA"}}, {Name: "B", Value: &Value{Kind: Variable, Raw: "VarB"}}, - }, map[string]interface{}{ + }, map[string]any{ "VarA": nil, "VarB": nil, }) @@ -65,7 +69,7 @@ func TestArg2Map(t *testing.T) { args := arg2map(defs, ArgumentList{ {Name: "A", Value: &Value{Kind: Variable, Raw: "VarA"}}, {Name: "B", Value: &Value{Kind: Variable, Raw: "VarB"}}, - }, map[string]interface{}{ + }, map[string]any{ "VarA": "varvalA", "VarB": "varvalB", }) diff --git a/ast/definition.go b/ast/definition.go index 9ceebf1b..426db758 100644 --- a/ast/definition.go +++ b/ast/definition.go @@ -1,5 +1,7 @@ package ast +import "slices" + type DefinitionKind string const ( @@ -54,12 +56,7 @@ func (d *Definition) IsInputType() bool { } func (d *Definition) OneOf(types ...string) bool { - for _, t := range types { - if d.Name == t { - return true - } - } - return false + return slices.Contains(types, d.Name) } type FieldDefinition struct { diff --git a/ast/directive.go b/ast/directive.go index 54dd45b1..de8d9840 100644 --- a/ast/directive.go +++ b/ast/directive.go @@ -3,7 +3,7 @@ package ast type DirectiveLocation string const ( - // Executable + // Executable. LocationQuery DirectiveLocation = `QUERY` LocationMutation DirectiveLocation = `MUTATION` LocationSubscription DirectiveLocation = `SUBSCRIPTION` @@ -12,7 +12,7 @@ const ( LocationFragmentSpread DirectiveLocation = `FRAGMENT_SPREAD` LocationInlineFragment DirectiveLocation = `INLINE_FRAGMENT` - // Type System + // Type System. LocationSchema DirectiveLocation = `SCHEMA` LocationScalar DirectiveLocation = `SCALAR` LocationObject DirectiveLocation = `OBJECT` @@ -38,7 +38,7 @@ type Directive struct { Location DirectiveLocation } -func (d *Directive) ArgumentMap(vars map[string]interface{}) map[string]interface{} { +func (d *Directive) ArgumentMap(vars map[string]any) map[string]any { if d.Definition == nil { return nil } diff --git a/ast/document.go b/ast/document.go index e2520ffb..66d55b43 100644 --- a/ast/document.go +++ b/ast/document.go @@ -42,7 +42,7 @@ type Schema struct { Comment *CommentGroup } -// AddTypes is the helper to add types definition to the schema +// AddTypes is the helper to add types definition to the schema. func (s *Schema) AddTypes(defs ...*Definition) { if s.Types == nil { s.Types = make(map[string]*Definition) @@ -56,7 +56,7 @@ func (s *Schema) AddPossibleType(name string, def *Definition) { s.PossibleTypes[name] = append(s.PossibleTypes[name], def) } -// GetPossibleTypes will enumerate all the definitions for a given interface or union +// GetPossibleTypes will enumerate all the definitions for a given interface or union. func (s *Schema) GetPossibleTypes(def *Definition) []*Definition { return s.PossibleTypes[def.Name] } @@ -65,7 +65,8 @@ func (s *Schema) AddImplements(name string, iface *Definition) { s.Implements[name] = append(s.Implements[name], iface) } -// GetImplements returns all the interface and union definitions that the given definition satisfies +// GetImplements returns all the interface and union definitions that the given definition +// satisfies. func (s *Schema) GetImplements(def *Definition) []*Definition { return s.Implements[def.Name] } diff --git a/ast/document_test.go b/ast/document_test.go index 1f6ea721..2dab6746 100644 --- a/ast/document_test.go +++ b/ast/document_test.go @@ -20,12 +20,12 @@ func TestQueryDocMethods(t *testing.T) { require.NoError(t, err) t.Run("GetOperation", func(t *testing.T) { - require.EqualValues(t, "Bob", doc.Operations.ForName("Bob").Name) + require.Equal(t, "Bob", doc.Operations.ForName("Bob").Name) require.Nil(t, doc.Operations.ForName("Alice")) }) t.Run("GetFragment", func(t *testing.T) { - require.EqualValues(t, "Frag", doc.Fragments.ForName("Frag").Name) + require.Equal(t, "Frag", doc.Fragments.ForName("Frag").Name) require.Nil(t, doc.Fragments.ForName("Alice")) }) } @@ -34,21 +34,69 @@ func TestNamedTypeCompatability(t *testing.T) { assert.True(t, NamedType("A", nil).IsCompatible(NamedType("A", nil))) assert.False(t, NamedType("A", nil).IsCompatible(NamedType("B", nil))) - assert.True(t, ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("A", nil), nil))) - assert.False(t, ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil))) - assert.False(t, ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil))) + assert.True( + t, + ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("A", nil), nil)), + ) + assert.False( + t, + ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil)), + ) + assert.False( + t, + ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil)), + ) - assert.True(t, ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("A", nil), nil))) - assert.False(t, ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil))) - assert.False(t, ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil))) + assert.True( + t, + ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("A", nil), nil)), + ) + assert.False( + t, + ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil)), + ) + assert.False( + t, + ListType(NamedType("A", nil), nil).IsCompatible(ListType(NamedType("B", nil), nil)), + ) assert.True(t, NonNullNamedType("A", nil).IsCompatible(NamedType("A", nil))) assert.False(t, NamedType("A", nil).IsCompatible(NonNullNamedType("A", nil))) - assert.True(t, NonNullListType(NamedType("String", nil), nil).IsCompatible(NonNullListType(NamedType("String", nil), nil))) - assert.True(t, NonNullListType(NamedType("String", nil), nil).IsCompatible(ListType(NamedType("String", nil), nil))) - assert.False(t, ListType(NamedType("String", nil), nil).IsCompatible(NonNullListType(NamedType("String", nil), nil))) + assert.True( + t, + NonNullListType( + NamedType("String", nil), + nil, + ).IsCompatible(NonNullListType(NamedType("String", nil), nil)), + ) + assert.True( + t, + NonNullListType( + NamedType("String", nil), + nil, + ).IsCompatible(ListType(NamedType("String", nil), nil)), + ) + assert.False( + t, + ListType( + NamedType("String", nil), + nil, + ).IsCompatible(NonNullListType(NamedType("String", nil), nil)), + ) - assert.True(t, ListType(NonNullNamedType("String", nil), nil).IsCompatible(ListType(NamedType("String", nil), nil))) - assert.False(t, ListType(NamedType("String", nil), nil).IsCompatible(ListType(NonNullNamedType("String", nil), nil))) + assert.True( + t, + ListType( + NonNullNamedType("String", nil), + nil, + ).IsCompatible(ListType(NamedType("String", nil), nil)), + ) + assert.False( + t, + ListType( + NamedType("String", nil), + nil, + ).IsCompatible(ListType(NonNullNamedType("String", nil), nil)), + ) } diff --git a/ast/dumper.go b/ast/dumper.go index e9ea88a1..e9fa6afd 100644 --- a/ast/dumper.go +++ b/ast/dumper.go @@ -8,8 +8,8 @@ import ( "strings" ) -// Dump turns ast into a stable string format for assertions in tests -func Dump(i interface{}) string { +// Dump turns ast into a stable string format for assertions in tests. +func Dump(i any) string { v := reflect.ValueOf(i) d := dumper{Buffer: &bytes.Buffer{}} @@ -146,6 +146,9 @@ func isZero(v reflect.Value) bool { return v.String() == "" } + // TODO(steve): more correct, but breaks tests + // return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) + // Compare other types directly: return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type())) } diff --git a/ast/path.go b/ast/path.go index f40aa953..4a702d40 100644 --- a/ast/path.go +++ b/ast/path.go @@ -41,7 +41,7 @@ func (path Path) String() string { } func (path *Path) UnmarshalJSON(b []byte) error { - var vs []interface{} + var vs []any err := json.Unmarshal(b, &vs) if err != nil { return err diff --git a/ast/selection.go b/ast/selection.go index efc78efe..b6e6890d 100644 --- a/ast/selection.go +++ b/ast/selection.go @@ -36,7 +36,7 @@ type Argument struct { Comment *CommentGroup } -func (f *Field) ArgumentMap(vars map[string]interface{}) map[string]interface{} { +func (f *Field) ArgumentMap(vars map[string]any) map[string]any { if f.Definition == nil { return nil } diff --git a/ast/source.go b/ast/source.go index 2949f83f..213a63a3 100644 --- a/ast/source.go +++ b/ast/source.go @@ -1,6 +1,6 @@ package ast -// Source covers a single *.graphql file +// Source covers a single *.graphql file. type Source struct { // Name is the filename of the source Name string diff --git a/ast/value.go b/ast/value.go index c731b77b..83b47163 100644 --- a/ast/value.go +++ b/ast/value.go @@ -42,7 +42,7 @@ type ChildValue struct { Comment *CommentGroup } -func (v *Value) Value(vars map[string]interface{}) (interface{}, error) { +func (v *Value) Value(vars map[string]any) (any, error) { if v == nil { return nil, nil } @@ -66,7 +66,7 @@ func (v *Value) Value(vars map[string]interface{}) (interface{}, error) { case NullValue: return nil, nil case ListValue: - var val []interface{} + var val []any for _, elem := range v.Children { elemVal, err := elem.Value.Value(vars) if err != nil { @@ -76,7 +76,7 @@ func (v *Value) Value(vars map[string]interface{}) (interface{}, error) { } return val, nil case ObjectValue: - val := map[string]interface{}{} + val := map[string]any{} for _, elem := range v.Children { elemVal, err := elem.Value.Value(vars) if err != nil { diff --git a/formatter/formatter.go b/formatter/formatter.go index bf7e1051..f0280ac7 100644 --- a/formatter/formatter.go +++ b/formatter/formatter.go @@ -15,7 +15,6 @@ type Formatter interface { FormatQueryDocument(doc *ast.QueryDocument) } -//nolint:revive // Ignore "stuttering" name format.FormatterOption type FormatterOption func(*formatter) // WithIndent uses the given string for indenting block bodies in the output, @@ -281,18 +280,26 @@ func (f *formatter) FormatSchemaDefinitionList(lists ast.SchemaDefinitionList, e description string ) + var descriptionSb284 strings.Builder for _, def := range lists { if def.BeforeDescriptionComment != nil { - beforeDescComment.List = append(beforeDescComment.List, def.BeforeDescriptionComment.List...) + beforeDescComment.List = append( + beforeDescComment.List, + def.BeforeDescriptionComment.List...) } if def.AfterDescriptionComment != nil { - afterDescComment.List = append(afterDescComment.List, def.AfterDescriptionComment.List...) + afterDescComment.List = append( + afterDescComment.List, + def.AfterDescriptionComment.List...) } if def.EndOfDefinitionComment != nil { - endOfDefinitionComment.List = append(endOfDefinitionComment.List, def.EndOfDefinitionComment.List...) + endOfDefinitionComment.List = append( + endOfDefinitionComment.List, + def.EndOfDefinitionComment.List...) } - description += def.Description + descriptionSb284.WriteString(def.Description) } + description += descriptionSb284.String() f.FormatCommentGroup(beforeDescComment) f.WriteDescription(description) @@ -327,7 +334,7 @@ func (f *formatter) FormatSchemaDefinitionList(lists ast.SchemaDefinitionList, e f.WriteNewline() } -// Return true if schema definitions is empty (besides directives), false otherwise +// Return true if schema definitions is empty (besides directives), false otherwise. func (f *formatter) IsSchemaDefinitionsEmpty(lists ast.SchemaDefinitionList) bool { for _, def := range lists { if len(def.OperationTypes) > 0 { @@ -557,7 +564,10 @@ func (f *formatter) FormatDefinition(def *ast.Definition, extend bool) { f.WriteNewline() } -func (f *formatter) FormatEnumValueList(lists ast.EnumValueList, endOfDefComment *ast.CommentGroup) { +func (f *formatter) FormatEnumValueList( + lists ast.EnumValueList, + endOfDefComment *ast.CommentGroup, +) { if len(lists) == 0 { return } diff --git a/formatter/formatter_test.go b/formatter/formatter_test.go index 151f253b..a6ac54c7 100644 --- a/formatter/formatter_test.go +++ b/formatter/formatter_test.go @@ -10,6 +10,7 @@ import ( "unicode/utf8" "github.com/stretchr/testify/assert" + "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/formatter" @@ -192,7 +193,6 @@ func executeGoldenTesting(t *testing.T, cfg *goldenConfig) { if f.IsDir() { continue } - f := f t.Run(f.Name(), func(t *testing.T) { result := cfg.Run(t, cfg, f) @@ -226,7 +226,12 @@ func executeGoldenTesting(t *testing.T, cfg *goldenConfig) { } if utf8.Valid(expected) { - assert.Equalf(t, string(expected), string(result), "if you want to accept new result. use -u option") + assert.Equalf( + t, + string(expected), + string(result), + "if you want to accept new result. use -u option", + ) } }) } diff --git a/gqlerror/error.go b/gqlerror/error.go index d9f20288..b2ba01bb 100644 --- a/gqlerror/error.go +++ b/gqlerror/error.go @@ -11,12 +11,12 @@ import ( // Error is the standard graphql error type described in https://spec.graphql.org/draft/#sec-Errors type Error struct { - Err error `json:"-"` - Message string `json:"message"` - Path ast.Path `json:"path,omitempty"` - Locations []Location `json:"locations,omitempty"` - Extensions map[string]interface{} `json:"extensions,omitempty"` - Rule string `json:"-"` + Err error `json:"-"` + Message string `json:"message"` + Path ast.Path `json:"path,omitempty"` + Locations []Location `json:"locations,omitempty"` + Extensions map[string]any `json:"extensions,omitempty"` + Rule string `json:"-"` } func (err *Error) SetFile(file string) { @@ -24,7 +24,7 @@ func (err *Error) SetFile(file string) { return } if err.Extensions == nil { - err.Extensions = map[string]interface{}{} + err.Extensions = map[string]any{} } err.Extensions["file"] = file @@ -99,7 +99,7 @@ func (errs List) Is(target error) bool { return false } -func (errs List) As(target interface{}) bool { +func (errs List) As(target any) bool { for _, err := range errs { if errors.As(err, target) { return true @@ -141,7 +141,8 @@ func WrapIfUnwrapped(err error) *Error { if err == nil { return nil } - if gqlErr, ok := err.(*Error); ok { + gqlErr := &Error{} + if errors.As(err, &gqlErr) { return gqlErr } return &Error{ @@ -150,20 +151,20 @@ func WrapIfUnwrapped(err error) *Error { } } -func Errorf(message string, args ...interface{}) *Error { +func Errorf(message string, args ...any) *Error { return &Error{ Message: fmt.Sprintf(message, args...), } } -func ErrorPathf(path ast.Path, message string, args ...interface{}) *Error { +func ErrorPathf(path ast.Path, message string, args ...any) *Error { return &Error{ Message: fmt.Sprintf(message, args...), Path: path, } } -func ErrorPosf(pos *ast.Position, message string, args ...interface{}) *Error { +func ErrorPosf(pos *ast.Position, message string, args ...any) *Error { if pos == nil { return ErrorLocf( "", @@ -182,10 +183,10 @@ func ErrorPosf(pos *ast.Position, message string, args ...interface{}) *Error { ) } -func ErrorLocf(file string, line int, col int, message string, args ...interface{}) *Error { - var extensions map[string]interface{} +func ErrorLocf(file string, line, col int, message string, args ...any) *Error { + var extensions map[string]any if file != "" { - extensions = map[string]interface{}{"file": file} + extensions = map[string]any{"file": file} } return &Error{ Message: fmt.Sprintf(message, args...), diff --git a/gqlerror/error_test.go b/gqlerror/error_test.go index d4c0812c..a2e0e3b1 100644 --- a/gqlerror/error_test.go +++ b/gqlerror/error_test.go @@ -47,7 +47,10 @@ func TestErrorFormatting(t *testing.T) { }) t.Run("with path", func(t *testing.T) { - err := ErrorPathf(ast.Path{ast.PathName("a"), ast.PathIndex(1), ast.PathName("b")}, "kabloom") + err := ErrorPathf( + ast.Path{ast.PathName("a"), ast.PathIndex(1), ast.PathName("b")}, + "kabloom", + ) require.Equal(t, `input: a[1].b kabloom`, err.Error()) }) @@ -103,8 +106,6 @@ func TestList_As(t *testing.T) { } for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -165,7 +166,6 @@ func TestList_Is(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -182,7 +182,7 @@ func TestList_Is(t *testing.T) { func BenchmarkError(b *testing.B) { list := List([]*Error{error1, error2}) - for i := 0; i < b.N; i++ { + for range b.N { _ = underlyingError.Error() _ = error1.Error() _ = error2.Error() diff --git a/gqlparser.go b/gqlparser.go index 2b22894b..92793ea7 100644 --- a/gqlparser.go +++ b/gqlparser.go @@ -1,6 +1,8 @@ package gqlparser import ( + "errors" + "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/parser" @@ -10,7 +12,8 @@ import ( func LoadSchema(str ...*ast.Source) (*ast.Schema, error) { schema, err := validator.LoadSchema(append([]*ast.Source{validator.Prelude}, str...)...) - gqlErr, ok := err.(*gqlerror.Error) + gqlErr := &gqlerror.Error{} + ok := errors.As(err, &gqlErr) if ok { return schema, gqlErr } @@ -32,7 +35,8 @@ func MustLoadSchema(str ...*ast.Source) *ast.Schema { func LoadQuery(schema *ast.Schema, str string) (*ast.QueryDocument, gqlerror.List) { query, err := parser.ParseQuery(&ast.Source{Input: str}) if err != nil { - gqlErr, ok := err.(*gqlerror.Error) + gqlErr := &gqlerror.Error{} + ok := errors.As(err, &gqlErr) if ok { return nil, gqlerror.List{gqlErr} } @@ -46,10 +50,15 @@ func LoadQuery(schema *ast.Schema, str string) (*ast.QueryDocument, gqlerror.Lis return query, nil } -func LoadQueryWithRules(schema *ast.Schema, str string, rules *rules.Rules) (*ast.QueryDocument, gqlerror.List) { +func LoadQueryWithRules( + schema *ast.Schema, + str string, + rules *rules.Rules, +) (*ast.QueryDocument, gqlerror.List) { query, err := parser.ParseQuery(&ast.Source{Input: str}) if err != nil { - gqlErr, ok := err.(*gqlerror.Error) + gqlErr := &gqlerror.Error{} + ok := errors.As(err, &gqlErr) if ok { return nil, gqlerror.List{gqlErr} } diff --git a/lexer/blockstring_test.go b/lexer/blockstring_test.go index 3edfab43..7214b5c1 100644 --- a/lexer/blockstring_test.go +++ b/lexer/blockstring_test.go @@ -62,6 +62,10 @@ func TestBlockStringValue(t *testing.T) { `) - require.Equal(t, "Hello, \n World! \n \nYours, \n GraphQL. ", result) + require.Equal( + t, + "Hello, \n World! \n \nYours, \n GraphQL. ", + result, + ) }) } diff --git a/lexer/lexer.go b/lexer/lexer.go index 1cbb4a03..7a82a42b 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -2,13 +2,14 @@ package lexer import ( "bytes" + "slices" "unicode/utf8" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" ) -// Lexer turns graphql request and schema strings into tokens +// Lexer turns graphql request and schema strings into tokens. type Lexer struct { *ast.Source // An offset into the string in bytes @@ -32,7 +33,7 @@ func New(src *ast.Source) Lexer { } } -// take one rune from input and advance end +// take one rune from input and advance end. func (s *Lexer) peek() (rune, int) { return utf8.DecodeRuneInString(s.Input[s.end:]) } @@ -55,7 +56,7 @@ func (s *Lexer) makeValueToken(kind Type, value string) (Token, error) { }, nil } -func (s *Lexer) makeError(format string, args ...interface{}) (Token, *gqlerror.Error) { +func (s *Lexer) makeError(format string, args ...any) (Token, *gqlerror.Error) { column := s.endRunes - s.lineStartRunes + 1 return Token{ Kind: Invalid, @@ -122,7 +123,59 @@ func (s *Lexer) ReadToken() (Token, error) { case '#': return s.readComment() - case '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z': + case '_', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z': return s.readName() case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': @@ -144,14 +197,16 @@ func (s *Lexer) ReadToken() (Token, error) { } if r == '\'' { - return s.makeError(`Unexpected single quote character ('), did you mean to use a double quote (")?`) + return s.makeError( + `Unexpected single quote character ('), did you mean to use a double quote (")?`, + ) } return s.makeError(`Cannot parse the unexpected character "%s".`, string(r)) } // ws reads from body starting at startPosition until it finds a non-whitespace -// or commented character, and updates the token end to include all whitespace +// or commented character, and updates the token end to include all whitespace. func (s *Lexer) ws() { for s.end < len(s.Input) { switch s.Input[s.end] { @@ -189,7 +244,7 @@ func (s *Lexer) ws() { // readComment from the input // -// #[\u0009\u0020-\uFFFF]* +// #[\u0009\u0020-\uFFFF]*. func (s *Lexer) readComment() (Token, error) { for s.end < len(s.Input) { r, w := s.peek() @@ -256,23 +311,21 @@ func (s *Lexer) readNumber() (Token, error) { return s.makeToken(Int) } -// acceptByte if it matches any of given bytes, returning true if it found anything +// acceptByte if it matches any of given bytes, returning true if it found anything. func (s *Lexer) acceptByte(bytes ...uint8) bool { if s.end >= len(s.Input) { return false } - for _, accepted := range bytes { - if s.Input[s.end] == accepted { - s.end++ - s.endRunes++ - return true - } + if slices.Contains(bytes, s.Input[s.end]) { + s.end++ + s.endRunes++ + return true } return false } -// acceptDigits from the input, returning the number of digits it found +// acceptDigits from the input, returning the number of digits it found. func (s *Lexer) acceptDigits() int { consumed := 0 for s.end < len(s.Input) && s.Input[s.end] >= '0' && s.Input[s.end] <= '9' { @@ -285,7 +338,7 @@ func (s *Lexer) acceptDigits() int { } // describeNext peeks at the input and returns a human readable string. This should will alloc -// and should only be used in errors +// and should only be used in errors. func (s *Lexer) describeNext() string { if s.end < len(s.Input) { return `"` + string(s.Input[s.end]) + `"` @@ -295,7 +348,7 @@ func (s *Lexer) describeNext() string { // readString from the input // -// "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*" +// "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*". func (s *Lexer) readString() (Token, error) { inputLen := len(s.Input) @@ -332,7 +385,8 @@ func (s *Lexer) readString() (Token, error) { case '"': t, err := s.makeToken(String) - // the token should not include the quotes in its value, but should cover them in its position + // the token should not include the quotes in its value, but should cover them in its + // position t.Pos.Start-- t.Pos.End++ @@ -370,7 +424,10 @@ func (s *Lexer) readString() (Token, error) { if !ok { s.end++ s.endRunes++ - return s.makeError("Invalid character escape sequence: \\%s.", s.Input[s.end:s.end+5]) + return s.makeError( + "Invalid character escape sequence: \\%s.", + s.Input[s.end:s.end+5], + ) } buf.WriteRune(r) s.end += 6 @@ -405,7 +462,7 @@ func (s *Lexer) readString() (Token, error) { // readBlockString from the input // -// """("?"?(\\"""|\\(?!=""")|[^"\\]))*""" +// """("?"?(\\"""|\\(?!=""")|[^"\\]))*""". func (s *Lexer) readBlockString() (Token, error) { inputLen := len(s.Input) @@ -433,7 +490,7 @@ func (s *Lexer) readBlockString() (Token, error) { // If we have at least 3 quotes, use the last 3 as the closing quote if quoteCount >= 3 { // Add any extra quotes to the buffer (except the last 3) - for j := 0; j < quoteCount-3; j++ { + for range quoteCount - 3 { buf.WriteByte('"') } @@ -508,7 +565,7 @@ func unhex(b string) (v rune, ok bool) { // readName from the input // -// [_A-Za-z][_0-9A-Za-z]* +// [_A-Za-z][_0-9A-Za-z]*. func (s *Lexer) readName() (Token, error) { for s.end < len(s.Input) { r, w := s.peek() diff --git a/lexer/lexer_test.go b/lexer/lexer_test.go index 00c75915..c131a1dc 100644 --- a/lexer/lexer_test.go +++ b/lexer/lexer_test.go @@ -1,11 +1,11 @@ package lexer import ( + "errors" "testing" - "github.com/vektah/gqlparser/v2/gqlerror" - "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/parser/testrunner" ) @@ -17,7 +17,11 @@ func TestLexer(t *testing.T) { for { tok, err := l.ReadToken() if err != nil { - ret.Error = err.(*gqlerror.Error) + ret.Error = func() *gqlerror.Error { + target := &gqlerror.Error{} + _ = errors.As(err, &target) + return target + }() break } diff --git a/parser/parser.go b/parser/parser.go index 2aba9837..b6a30640 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -91,7 +91,7 @@ func (p *parser) peek() lexer.Token { return p.peekToken } -func (p *parser) error(tok lexer.Token, format string, args ...interface{}) { +func (p *parser) error(tok lexer.Token, format string, args ...any) { if p.err != nil { return } @@ -165,7 +165,7 @@ func (p *parser) unexpectedToken(tok lexer.Token) { p.error(tok, "Unexpected %s", tok.String()) } -func (p *parser) many(start lexer.Type, end lexer.Type, cb func()) { +func (p *parser) many(start, end lexer.Type, cb func()) { hasDef := p.skip(start) if !hasDef { return @@ -177,7 +177,7 @@ func (p *parser) many(start lexer.Type, end lexer.Type, cb func()) { p.next() } -func (p *parser) some(start lexer.Type, end lexer.Type, cb func()) *ast.CommentGroup { +func (p *parser) some(start, end lexer.Type, cb func()) *ast.CommentGroup { hasDef := p.skip(start) if !hasDef { return nil diff --git a/parser/parser_test.go b/parser/parser_test.go index b80a5388..2ded42e5 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/lexer" ) @@ -94,7 +95,11 @@ func TestParserUtils(t *testing.T) { p.some(lexer.BracketL, lexer.BracketR, func() { arr = append(arr, p.next().Value) }) - require.EqualError(t, p.err, "input.graphql:1:2: expected at least one definition, found ]") + require.EqualError( + t, + p.err, + "input.graphql:1:2: expected at least one definition, found ]", + ) require.Equal(t, []string(nil), arr) require.NotEqual(t, lexer.EOF, p.peek().Kind) }) diff --git a/parser/query.go b/parser/query.go index 47ac214a..271a2ffe 100644 --- a/parser/query.go +++ b/parser/query.go @@ -1,9 +1,8 @@ package parser import ( - "github.com/vektah/gqlparser/v2/lexer" - . "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // bad, yeah + "github.com/vektah/gqlparser/v2/lexer" ) func ParseQuery(source *Source) (*QueryDocument, error) { @@ -259,7 +258,12 @@ func (p *parser) parseValueLiteral(isConst bool) *Value { p.unexpectedError() return nil } - return &Value{Position: &token.Pos, Comment: p.comment, Raw: p.parseVariable(), Kind: Variable} + return &Value{ + Position: &token.Pos, + Comment: p.comment, + Raw: p.parseVariable(), + Kind: Variable, + } case lexer.Int: kind = IntValue case lexer.Float: diff --git a/parser/query_test.go b/parser/query_test.go index 9170f4ef..fe000106 100644 --- a/parser/query_test.go +++ b/parser/query_test.go @@ -1,6 +1,7 @@ package parser import ( + "errors" "testing" "github.com/stretchr/testify/assert" @@ -14,7 +15,11 @@ func TestQueryDocument(t *testing.T) { testrunner.Test(t, "query_test.yml", func(t *testing.T, input string) testrunner.Spec { doc, err := ParseQuery(&ast.Source{Input: input, Name: "spec"}) if err != nil { - gqlErr := err.(*gqlerror.Error) + gqlErr := func() *gqlerror.Error { + target := &gqlerror.Error{} + _ = errors.As(err, &target) + return target + }() return testrunner.Spec{ Error: gqlErr, AST: ast.Dump(doc), @@ -41,6 +46,10 @@ query SomeOperation { }) assert.NoError(t, err) assert.Equal(t, 3, query.Operations.ForName("SomeOperation").Position.Line) - assert.Equal(t, 5, query.Operations.ForName("SomeOperation").SelectionSet[0].GetPosition().Line) + assert.Equal( + t, + 5, + query.Operations.ForName("SomeOperation").SelectionSet[0].GetPosition().Line, + ) }) } diff --git a/parser/schema_test.go b/parser/schema_test.go index 16b35058..957c86cf 100644 --- a/parser/schema_test.go +++ b/parser/schema_test.go @@ -1,12 +1,13 @@ package parser import ( + "errors" "testing" "github.com/stretchr/testify/assert" - "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/parser/testrunner" ) @@ -15,8 +16,12 @@ func TestSchemaDocument(t *testing.T) { doc, err := ParseSchema(&ast.Source{Input: input, Name: "spec"}) if err != nil { return testrunner.Spec{ - Error: err.(*gqlerror.Error), - AST: ast.Dump(doc), + Error: func() *gqlerror.Error { + target := &gqlerror.Error{} + _ = errors.As(err, &target) + return target + }(), + AST: ast.Dump(doc), } } return testrunner.Spec{ @@ -34,7 +39,11 @@ func TestTypePosition(t *testing.T) { `, }) assert.NoError(t, parseErr) - assert.Equal(t, 2, schema.Definitions.ForName("query").Fields.ForName("me").Type.Position.Line) + assert.Equal( + t, + 2, + schema.Definitions.ForName("query").Fields.ForName("me").Type.Position.Line, + ) }) t.Run("type line number with bang", func(t *testing.T) { schema, parseErr := ParseSchema(&ast.Source{ @@ -44,7 +53,11 @@ func TestTypePosition(t *testing.T) { `, }) assert.NoError(t, parseErr) - assert.Equal(t, 2, schema.Definitions.ForName("query").Fields.ForName("me").Type.Position.Line) + assert.Equal( + t, + 2, + schema.Definitions.ForName("query").Fields.ForName("me").Type.Position.Line, + ) }) t.Run("type line number with comments", func(t *testing.T) { schema, parseErr := ParseSchema(&ast.Source{ @@ -55,6 +68,10 @@ func TestTypePosition(t *testing.T) { `, }) assert.NoError(t, parseErr) - assert.Equal(t, 3, schema.Definitions.ForName("query").Fields.ForName("me").Type.Position.Line) + assert.Equal( + t, + 3, + schema.Definitions.ForName("query").Fields.ForName("me").Type.Position.Line, + ) }) } diff --git a/parser/testrunner/runner.go b/parser/testrunner/runner.go index b9a2046f..ba385ab3 100644 --- a/parser/testrunner/runner.go +++ b/parser/testrunner/runner.go @@ -7,8 +7,9 @@ import ( "testing" "github.com/andreyvit/diff" - "github.com/vektah/gqlparser/v2/gqlerror" "gopkg.in/yaml.v3" + + "github.com/vektah/gqlparser/v2/gqlerror" ) type Features map[string][]Spec @@ -61,10 +62,15 @@ func Test(t *testing.T, filename string, f func(t *testing.T, input string) Spec t.Errorf("expected error but got none") default: if result.Error.Message != spec.Error.Message { - t.Errorf("wrong error returned\nexpected: %s\ngot: %s", spec.Error.Message, result.Error.Message) + t.Errorf( + "wrong error returned\nexpected: %s\ngot: %s", + spec.Error.Message, + result.Error.Message, + ) } - if result.Error.Locations[0].Column != spec.Error.Locations[0].Column || result.Error.Locations[0].Line != spec.Error.Locations[0].Line { + if result.Error.Locations[0].Column != spec.Error.Locations[0].Column || + result.Error.Locations[0].Line != spec.Error.Locations[0].Line { t.Errorf( "wrong error location:\nexpected: line %d column %d\ngot: line %d column %d", spec.Error.Locations[0].Line, @@ -85,26 +91,63 @@ func Test(t *testing.T, filename string, f func(t *testing.T, input string) Spec for i, tok := range result.Tokens { expected := spec.Tokens[i] - if !strings.EqualFold(strings.ReplaceAll(expected.Kind, "_", ""), tok.Kind) { - t.Errorf("token[%d].kind should be %s, was %s", i, expected.Kind, tok.Kind) + if !strings.EqualFold( + strings.ReplaceAll(expected.Kind, "_", ""), + tok.Kind, + ) { + t.Errorf( + "token[%d].kind should be %s, was %s", + i, + expected.Kind, + tok.Kind, + ) } if expected.Value != "undefined" && expected.Value != tok.Value { - t.Errorf("token[%d].value incorrect\nexpected: %s\ngot: %s", i, strconv.Quote(expected.Value), strconv.Quote(tok.Value)) + t.Errorf( + "token[%d].value incorrect\nexpected: %s\ngot: %s", + i, + strconv.Quote(expected.Value), + strconv.Quote(tok.Value), + ) } if expected.Start != 0 && expected.Start != tok.Start { - t.Errorf("token[%d].start should be %d, was %d", i, expected.Start, tok.Start) + t.Errorf( + "token[%d].start should be %d, was %d", + i, + expected.Start, + tok.Start, + ) } if expected.End != 0 && expected.End != tok.End { - t.Errorf("token[%d].end should be %d, was %d", i, expected.End, tok.End) + t.Errorf( + "token[%d].end should be %d, was %d", + i, + expected.End, + tok.End, + ) } if expected.Line != 0 && expected.Line != tok.Line { - t.Errorf("token[%d].line should be %d, was %d", i, expected.Line, tok.Line) + t.Errorf( + "token[%d].line should be %d, was %d", + i, + expected.Line, + tok.Line, + ) } if expected.Column != 0 && expected.Column != tok.Column { - t.Errorf("token[%d].column should be %d, was %d", i, expected.Column, tok.Column) + t.Errorf( + "token[%d].column should be %d, was %d", + i, + expected.Column, + tok.Column, + ) } if tok.Src != "spec" { - t.Errorf("token[%d].source.name should be spec, was %s", i, strconv.Quote(tok.Src)) + t.Errorf( + "token[%d].source.name should be spec, was %s", + i, + strconv.Quote(tok.Src), + ) } } } diff --git a/validator/core/helpers.go b/validator/core/helpers.go index b395a840..f977d00a 100644 --- a/validator/core/helpers.go +++ b/validator/core/helpers.go @@ -8,11 +8,12 @@ import ( "strings" "github.com/agnivade/levenshtein" + "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" ) -func Message(msg string, args ...interface{}) ErrorOption { +func Message(msg string, args ...any) ErrorOption { return func(err *gqlerror.Error) { err.Message += fmt.Sprintf(msg, args...) } @@ -33,7 +34,7 @@ func At(position *ast.Position) ErrorOption { } } -func SuggestListQuoted(prefix string, typed string, suggestions []string) ErrorOption { +func SuggestListQuoted(prefix, typed string, suggestions []string) ErrorOption { suggested := SuggestionList(typed, suggestions) return func(err *gqlerror.Error) { if len(suggested) > 0 { @@ -42,7 +43,7 @@ func SuggestListQuoted(prefix string, typed string, suggestions []string) ErrorO } } -func SuggestListUnquoted(prefix string, typed string, suggestions []string) ErrorOption { +func SuggestListUnquoted(prefix, typed string, suggestions []string) ErrorOption { suggested := SuggestionList(typed, suggestions) return func(err *gqlerror.Error) { if len(suggested) > 0 { @@ -51,7 +52,7 @@ func SuggestListUnquoted(prefix string, typed string, suggestions []string) Erro } } -func Suggestf(suggestion string, args ...interface{}) ErrorOption { +func Suggestf(suggestion string, args ...any) ErrorOption { return func(err *gqlerror.Error) { err.Message += " Did you mean " + fmt.Sprintf(suggestion, args...) + "?" } @@ -117,12 +118,8 @@ func SuggestionList(input string, options []string) []string { func calcThreshold(a string) (threshold int) { // the logic is copied from here // https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/jsutils/suggestionList.ts#L14 - threshold = int(math.Floor(float64(len(a))*0.4) + 1) - - if threshold < 1 { - threshold = 1 - } - return + threshold = max(int(math.Floor(float64(len(a))*0.4)+1), 1) + return threshold } // Computes the lexical distance between strings A and B. @@ -136,7 +133,7 @@ func calcThreshold(a string) (threshold int) { // as a single edit which helps identify mis-cased values with an edit distance // of 1. // -// This distance can be useful for detecting typos in input or sorting +// This distance can be useful for detecting typos in input or sorting. func lexicalDistance(a, b string) int { if a == b { return 0 diff --git a/validator/core/walk.go b/validator/core/walk.go index 53245086..4e4c9b30 100644 --- a/validator/core/walk.go +++ b/validator/core/walk.go @@ -142,7 +142,11 @@ func (w *Walker) walkFragment(it *ast.FragmentDefinition) { } } -func (w *Walker) walkDirectives(parentDef *ast.Definition, directives []*ast.Directive, location ast.DirectiveLocation) { +func (w *Walker) walkDirectives( + parentDef *ast.Definition, + directives []*ast.Directive, + location ast.DirectiveLocation, +) { for _, dir := range directives { def := w.Schema.Directives[dir.Name] dir.Definition = def @@ -182,7 +186,8 @@ func (w *Walker) walkValue(value *ast.Value) { fieldDef := value.Definition.Fields.ForName(child.Name) if fieldDef != nil { child.Value.ExpectedType = fieldDef.Type - child.Value.ExpectedTypeHasDefault = fieldDef.DefaultValue != nil && fieldDef.DefaultValue.Kind != ast.NullValue + child.Value.ExpectedTypeHasDefault = fieldDef.DefaultValue != nil && + fieldDef.DefaultValue.Kind != ast.NullValue child.Value.Definition = w.Schema.Types[fieldDef.Type.Name()] } } @@ -209,7 +214,8 @@ func (w *Walker) walkValue(value *ast.Value) { func (w *Walker) walkArgument(argDef *ast.ArgumentDefinition, arg *ast.Argument) { if argDef != nil { arg.Value.ExpectedType = argDef.Type - arg.Value.ExpectedTypeHasDefault = argDef.DefaultValue != nil && argDef.DefaultValue.Kind != ast.NullValue + arg.Value.ExpectedTypeHasDefault = argDef.DefaultValue != nil && + argDef.DefaultValue.Kind != ast.NullValue arg.Value.Definition = w.Schema.Types[argDef.Type.Name()] } diff --git a/validator/imported_test.go b/validator/imported_test.go index 65cc65b7..6c3e5ff4 100644 --- a/validator/imported_test.go +++ b/validator/imported_test.go @@ -46,7 +46,9 @@ func TestValidation(t *testing.T) { schemas := make([]*ast.Schema, 0, len(rawSchemas)) for i, schema := range rawSchemas { - schema, err := gqlparser.LoadSchema(&ast.Source{Input: schema, Name: fmt.Sprintf("schemas.yml[%d]", i)}) + schema, err := gqlparser.LoadSchema( + &ast.Source{Input: schema, Name: fmt.Sprintf("schemas.yml[%d]", i)}, + ) if err != nil { panic(err) } @@ -91,7 +93,9 @@ func runSpec(t *testing.T, schemas []*ast.Schema, deviations []*Deviation, filen var schema *ast.Schema if idx, err := strconv.Atoi(spec.Schema); err != nil { var gqlErr error - schema, gqlErr = gqlparser.LoadSchema(&ast.Source{Input: spec.Schema, Name: spec.Name}) + schema, gqlErr = gqlparser.LoadSchema( + &ast.Source{Input: spec.Schema, Name: spec.Name}, + ) if gqlErr != nil { t.Fatal(err) } @@ -113,13 +117,21 @@ func runSpec(t *testing.T, schemas []*ast.Schema, deviations []*Deviation, filen spec.Errors[i].Rule = spec.Rule // remove inconsistent use of ; - spec.Errors[i].Message = strings.ReplaceAll(spec.Errors[i].Message, "; Did you mean", ". Did you mean") + spec.Errors[i].Message = strings.ReplaceAll( + spec.Errors[i].Message, + "; Did you mean", + ". Did you mean", + ) } sort.Slice(spec.Errors, compareErrors(spec.Errors)) sort.Slice(finalErrors, compareErrors(finalErrors)) if len(finalErrors) != len(spec.Errors) { - t.Errorf("wrong number of errors returned\ngot:\n%s\nwant:\n%s", finalErrors.Error(), spec.Errors) + t.Errorf( + "wrong number of errors returned\ngot:\n%s\nwant:\n%s", + finalErrors.Error(), + spec.Errors, + ) } else { for i := range spec.Errors { expected := spec.Errors[i] @@ -149,7 +161,12 @@ func runSpec(t *testing.T, schemas []*ast.Schema, deviations []*Deviation, filen } if len(errLocs) > 0 { - t.Errorf("%s\ngot: %s\nwant: %s", strings.Join(errLocs, ", "), finalErrors[i].Error(), spec.Errors[i].Error()) + t.Errorf( + "%s\ngot: %s\nwant: %s", + strings.Join(errLocs, ", "), + finalErrors[i].Error(), + spec.Errors[i].Error(), + ) } } } @@ -163,7 +180,12 @@ func runSpec(t *testing.T, schemas []*ast.Schema, deviations []*Deviation, filen }) } -func runSpecWithRules(t *testing.T, schemas []*ast.Schema, deviations []*Deviation, filename string) { +func runSpecWithRules( + t *testing.T, + schemas []*ast.Schema, + deviations []*Deviation, + filename string, +) { ruleName := strings.TrimSuffix(filepath.Base(filename), ".spec.yml") var specs []Spec @@ -189,7 +211,9 @@ func runSpecWithRules(t *testing.T, schemas []*ast.Schema, deviations []*Deviati var schema *ast.Schema if idx, err := strconv.Atoi(spec.Schema); err != nil { var gqlErr error - schema, gqlErr = gqlparser.LoadSchema(&ast.Source{Input: spec.Schema, Name: spec.Name}) + schema, gqlErr = gqlparser.LoadSchema( + &ast.Source{Input: spec.Schema, Name: spec.Name}, + ) if gqlErr != nil { t.Fatal(err) } @@ -210,13 +234,21 @@ func runSpecWithRules(t *testing.T, schemas []*ast.Schema, deviations []*Deviati spec.Errors[i].Rule = spec.Rule // remove inconsistent use of ; - spec.Errors[i].Message = strings.ReplaceAll(spec.Errors[i].Message, "; Did you mean", ". Did you mean") + spec.Errors[i].Message = strings.ReplaceAll( + spec.Errors[i].Message, + "; Did you mean", + ". Did you mean", + ) } sort.Slice(spec.Errors, compareErrors(spec.Errors)) sort.Slice(finalErrors, compareErrors(finalErrors)) if len(finalErrors) != len(spec.Errors) { - t.Errorf("wrong number of errors returned\ngot:\n%s\nwant:\n%s", finalErrors.Error(), spec.Errors) + t.Errorf( + "wrong number of errors returned\ngot:\n%s\nwant:\n%s", + finalErrors.Error(), + spec.Errors, + ) } else { for i := range spec.Errors { expected := spec.Errors[i] @@ -246,7 +278,12 @@ func runSpecWithRules(t *testing.T, schemas []*ast.Schema, deviations []*Deviati } if len(errLocs) > 0 { - t.Errorf("%s\ngot: %s\nwant: %s", strings.Join(errLocs, ", "), finalErrors[i].Error(), spec.Errors[i].Error()) + t.Errorf( + "%s\ngot: %s\nwant: %s", + strings.Join(errLocs, ", "), + finalErrors[i].Error(), + spec.Errors[i].Error(), + ) } } } @@ -270,7 +307,7 @@ func compareErrors(errors gqlerror.List) func(i, j int) bool { } } -func readYaml(filename string, result interface{}) { +func readYaml(filename string, result any) { b, err := os.ReadFile(filename) if err != nil { panic(err) diff --git a/validator/messaging_test.go b/validator/messaging_test.go index 834ccd88..7c552ec0 100644 --- a/validator/messaging_test.go +++ b/validator/messaging_test.go @@ -8,7 +8,7 @@ import ( func TestMessaging(t *testing.T) { t.Run("OrList", func(t *testing.T) { - assert.Equal(t, "", OrList()) + assert.Empty(t, OrList()) assert.Equal(t, "A", OrList("A")) assert.Equal(t, "A or B", OrList("A", "B")) assert.Equal(t, "A, B, or C", OrList("A", "B", "C")) @@ -17,7 +17,7 @@ func TestMessaging(t *testing.T) { }) t.Run("QuotedOrList", func(t *testing.T) { - assert.Equal(t, ``, QuotedOrList()) + assert.Empty(t, QuotedOrList()) assert.Equal(t, `"A"`, QuotedOrList("A")) assert.Equal(t, `"A" or "B"`, QuotedOrList("A", "B")) assert.Equal(t, `"A", "B", or "C"`, QuotedOrList("A", "B", "C")) diff --git a/validator/rules/fields_on_correct_type.go b/validator/rules/fields_on_correct_type.go index e4a67eb0..1c6f5587 100644 --- a/validator/rules/fields_on_correct_type.go +++ b/validator/rules/fields_on_correct_type.go @@ -3,10 +3,8 @@ package rules import ( "fmt" "sort" - "strings" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -17,12 +15,24 @@ func ruleFuncFieldsOnCorrectType(observers *Events, addError AddErrFunc, disable return } - message := fmt.Sprintf(`Cannot query field "%s" on type "%s".`, field.Name, field.ObjectDefinition.Name) + message := fmt.Sprintf( + `Cannot query field "%s" on type "%s".`, + field.Name, + field.ObjectDefinition.Name, + ) if !disableSuggestion { - if suggestedTypeNames := getSuggestedTypeNames(walker, field.ObjectDefinition, field.Name); suggestedTypeNames != nil { - message += " Did you mean to use an inline fragment on " + QuotedOrList(suggestedTypeNames...) + "?" - } else if suggestedFieldNames := getSuggestedFieldNames(field.ObjectDefinition, field.Name); suggestedFieldNames != nil { + if suggestedTypeNames := getSuggestedTypeNames( + walker, + field.ObjectDefinition, + field.Name, + ); suggestedTypeNames != nil { + message += " Did you mean to use an inline fragment on " + QuotedOrList( + suggestedTypeNames...) + "?" + } else if suggestedFieldNames := getSuggestedFieldNames( + field.ObjectDefinition, + field.Name, + ); suggestedFieldNames != nil { message += " Did you mean " + QuotedOrList(suggestedFieldNames...) + "?" } } @@ -89,7 +99,7 @@ func getSuggestedTypeNames(walker *Walker, parent *ast.Definition, name string) if diff != 0 { return diff < 0 } - return strings.Compare(typeA, typeB) < 0 + return typeA < typeB }) return suggestedTypes @@ -99,8 +109,8 @@ func getSuggestedTypeNames(walker *Walker, parent *ast.Definition, name string) // where max is set to the slice’s length, // we ensure that appending elements results // in a slice backed by a distinct array. -// This method prevents the shared array issue -func concatSlice(first []string, second []string) []string { +// This method prevents the shared array issue. +func concatSlice(first, second []string) []string { n := len(first) return append(first[:n:n], second...) } diff --git a/validator/rules/fragments_on_composite_types.go b/validator/rules/fragments_on_composite_types.go index 8fb26925..bd1f8494 100644 --- a/validator/rules/fragments_on_composite_types.go +++ b/validator/rules/fragments_on_composite_types.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -18,7 +17,10 @@ var FragmentsOnCompositeTypesRule = Rule{ return } - message := fmt.Sprintf(`Fragment cannot condition on non composite type "%s".`, inlineFragment.TypeCondition) + message := fmt.Sprintf( + `Fragment cannot condition on non composite type "%s".`, + inlineFragment.TypeCondition, + ) addError( Message("%s", message), @@ -27,11 +29,16 @@ var FragmentsOnCompositeTypesRule = Rule{ }) observers.OnFragment(func(walker *Walker, fragment *ast.FragmentDefinition) { - if fragment.Definition == nil || fragment.TypeCondition == "" || fragment.Definition.IsCompositeType() { + if fragment.Definition == nil || fragment.TypeCondition == "" || + fragment.Definition.IsCompositeType() { return } - message := fmt.Sprintf(`Fragment "%s" cannot condition on non composite type "%s".`, fragment.Name, fragment.TypeCondition) + message := fmt.Sprintf( + `Fragment "%s" cannot condition on non composite type "%s".`, + fragment.Name, + fragment.TypeCondition, + ) addError( Message("%s", message), diff --git a/validator/rules/known_argument_names.go b/validator/rules/known_argument_names.go index 4c065a71..af7ca6db 100644 --- a/validator/rules/known_argument_names.go +++ b/validator/rules/known_argument_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -21,7 +20,12 @@ func ruleFuncKnownArgumentNames(observers *Events, addError AddErrFunc, disableS if disableSuggestion { addError( - Message(`Unknown argument "%s" on field "%s.%s".`, arg.Name, field.ObjectDefinition.Name, field.Name), + Message( + `Unknown argument "%s" on field "%s.%s".`, + arg.Name, + field.ObjectDefinition.Name, + field.Name, + ), At(field.Position), ) } else { @@ -30,7 +34,12 @@ func ruleFuncKnownArgumentNames(observers *Events, addError AddErrFunc, disableS suggestions = append(suggestions, argDef.Name) } addError( - Message(`Unknown argument "%s" on field "%s.%s".`, arg.Name, field.ObjectDefinition.Name, field.Name), + Message( + `Unknown argument "%s" on field "%s.%s".`, + arg.Name, + field.ObjectDefinition.Name, + field.Name, + ), SuggestListQuoted("Did you mean", arg.Name, suggestions), At(field.Position), ) diff --git a/validator/rules/known_directives.go b/validator/rules/known_directives.go index 2430d29b..b81b93ed 100644 --- a/validator/rules/known_directives.go +++ b/validator/rules/known_directives.go @@ -1,8 +1,9 @@ package rules import ( - "github.com/vektah/gqlparser/v2/ast" + "slices" + "github.com/vektah/gqlparser/v2/ast" //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -25,10 +26,8 @@ var KnownDirectivesRule = Rule{ return } - for _, loc := range directive.Definition.Locations { - if loc == directive.Location { - return - } + if slices.Contains(directive.Definition.Locations, directive.Location) { + return } // position must be exists if directive.Definition != nil @@ -40,7 +39,11 @@ var KnownDirectivesRule = Rule{ if !seen[tmp] { addError( - Message(`Directive "@%s" may not be used on %s.`, directive.Name, directive.Location), + Message( + `Directive "@%s" may not be used on %s.`, + directive.Name, + directive.Location, + ), At(directive.Position), ) seen[tmp] = true diff --git a/validator/rules/known_fragment_names.go b/validator/rules/known_fragment_names.go index c9b9f90d..c55cd658 100644 --- a/validator/rules/known_fragment_names.go +++ b/validator/rules/known_fragment_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/known_root_type.go b/validator/rules/known_root_type.go index b67da68c..bc2d2d00 100644 --- a/validator/rules/known_root_type.go +++ b/validator/rules/known_root_type.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/known_type_names.go b/validator/rules/known_type_names.go index a0f10fba..5a85d3bf 100644 --- a/validator/rules/known_type_names.go +++ b/validator/rules/known_type_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/lone_anonymous_operation.go b/validator/rules/lone_anonymous_operation.go index dfa851c5..890f71f7 100644 --- a/validator/rules/lone_anonymous_operation.go +++ b/validator/rules/lone_anonymous_operation.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/max_introspection_depth.go b/validator/rules/max_introspection_depth.go index 651b23b4..012a4744 100644 --- a/validator/rules/max_introspection_depth.go +++ b/validator/rules/max_introspection_depth.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -29,7 +28,11 @@ var MaxIntrospectionDepth = Rule{ }, } -func checkDepthSelectionSet(selectionSet ast.SelectionSet, visitedFragments map[string]bool, depth int) bool { +func checkDepthSelectionSet( + selectionSet ast.SelectionSet, + visitedFragments map[string]bool, + depth int, +) bool { for _, child := range selectionSet { if field, ok := child.(*ast.Field); ok { if checkDepthField(field, visitedFragments, depth) { @@ -63,7 +66,11 @@ func checkDepthField(field *ast.Field, visitedFragments map[string]bool, depth i return checkDepthSelectionSet(field.SelectionSet, visitedFragments, depth) } -func checkDepthFragmentSpread(fragmentSpread *ast.FragmentSpread, visitedFragments map[string]bool, depth int) bool { +func checkDepthFragmentSpread( + fragmentSpread *ast.FragmentSpread, + visitedFragments map[string]bool, + depth int, +) bool { fragmentName := fragmentSpread.Name if visited, ok := visitedFragments[fragmentName]; ok && visited { // Fragment cycles are handled by `NoFragmentCyclesRule`. diff --git a/validator/rules/no_fragment_cycles.go b/validator/rules/no_fragment_cycles.go index fb3ac6ad..ead6ae91 100644 --- a/validator/rules/no_fragment_cycles.go +++ b/validator/rules/no_fragment_cycles.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -55,7 +54,11 @@ var NoFragmentCyclesRule = Rule{ via = fmt.Sprintf(" via %s", strings.Join(fragmentNames, ", ")) } addError( - Message(`Cannot spread fragment "%s" within itself%s.`, spreadName, via), + Message( + `Cannot spread fragment "%s" within itself%s.`, + spreadName, + via, + ), At(spreadNode.Position), ) } diff --git a/validator/rules/no_undefined_variables.go b/validator/rules/no_undefined_variables.go index 562d7f19..76cafb80 100644 --- a/validator/rules/no_undefined_variables.go +++ b/validator/rules/no_undefined_variables.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -11,13 +10,18 @@ var NoUndefinedVariablesRule = Rule{ Name: "NoUndefinedVariables", RuleFunc: func(observers *Events, addError AddErrFunc) { observers.OnValue(func(walker *Walker, value *ast.Value) { - if walker.CurrentOperation == nil || value.Kind != ast.Variable || value.VariableDefinition != nil { + if walker.CurrentOperation == nil || value.Kind != ast.Variable || + value.VariableDefinition != nil { return } if walker.CurrentOperation.Name != "" { addError( - Message(`Variable "%s" is not defined by operation "%s".`, value, walker.CurrentOperation.Name), + Message( + `Variable "%s" is not defined by operation "%s".`, + value, + walker.CurrentOperation.Name, + ), At(value.Position), ) } else { diff --git a/validator/rules/no_unused_fragments.go b/validator/rules/no_unused_fragments.go index 6d27e11e..d28389a4 100644 --- a/validator/rules/no_unused_fragments.go +++ b/validator/rules/no_unused_fragments.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/no_unused_variables.go b/validator/rules/no_unused_variables.go index a4ce0709..b393c5b2 100644 --- a/validator/rules/no_unused_variables.go +++ b/validator/rules/no_unused_variables.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -18,7 +17,11 @@ var NoUnusedVariablesRule = Rule{ if operation.Name != "" { addError( - Message(`Variable "$%s" is never used in operation "%s".`, varDef.Variable, operation.Name), + Message( + `Variable "$%s" is never used in operation "%s".`, + varDef.Variable, + operation.Name, + ), At(varDef.Position), ) } else { diff --git a/validator/rules/overlapping_fields_can_be_merged.go b/validator/rules/overlapping_fields_can_be_merged.go index 9e843e76..77014e3e 100644 --- a/validator/rules/overlapping_fields_can_be_merged.go +++ b/validator/rules/overlapping_fields_can_be_merged.go @@ -6,7 +6,6 @@ import ( "reflect" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -82,7 +81,8 @@ var OverlappingFieldsCanBeMergedRule = Rule{ }) observers.OnField(func(walker *Walker, field *ast.Field) { if walker.CurrentOperation == nil { - // When checking both Operation and Fragment, errors are duplicated when processing FragmentDefinition referenced from Operation + // When checking both Operation and Fragment, errors are duplicated when processing + // FragmentDefinition referenced from Operation return } m.walker = walker @@ -112,7 +112,11 @@ type pairSet struct { data map[string]map[string]bool } -func (pairSet *pairSet) Add(a *ast.FragmentSpread, b *ast.FragmentSpread, areMutuallyExclusive bool) { +func (pairSet *pairSet) Add( + a *ast.FragmentSpread, + b *ast.FragmentSpread, + areMutuallyExclusive bool, +) { add := func(a *ast.FragmentSpread, b *ast.FragmentSpread) { m := pairSet.data[a.Name] if m == nil { @@ -125,7 +129,11 @@ func (pairSet *pairSet) Add(a *ast.FragmentSpread, b *ast.FragmentSpread, areMut add(b, a) } -func (pairSet *pairSet) Has(a *ast.FragmentSpread, b *ast.FragmentSpread, areMutuallyExclusive bool) bool { +func (pairSet *pairSet) Has( + a *ast.FragmentSpread, + b *ast.FragmentSpread, + areMutuallyExclusive bool, +) bool { am, ok := pairSet.data[a.Name] if !ok { return false @@ -224,7 +232,11 @@ func (m *ConflictMessage) addFieldsConflictMessage(addError AddErrFunc) { var buf bytes.Buffer m.String(&buf) addError( - Message(`Fields "%s" conflict because %s. Use different aliases on the fields to fetch both if this was intentional.`, m.ResponseName, buf.String()), + Message( + `Fields "%s" conflict because %s. Use different aliases on the fields to fetch both if this was intentional.`, + m.ResponseName, + buf.String(), + ), At(m.Position), ) } @@ -240,7 +252,9 @@ type overlappingFieldsCanBeMergedManager struct { comparedFragments map[string]bool } -func (m *overlappingFieldsCanBeMergedManager) findConflictsWithinSelectionSet(selectionSet ast.SelectionSet) []*ConflictMessage { +func (m *overlappingFieldsCanBeMergedManager) findConflictsWithinSelectionSet( + selectionSet ast.SelectionSet, +) []*ConflictMessage { if len(selectionSet) == 0 { return nil } @@ -271,7 +285,12 @@ func (m *overlappingFieldsCanBeMergedManager) findConflictsWithinSelectionSet(se return conflicts.Conflicts } -func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFieldsAndFragment(conflicts *conflictMessageContainer, areMutuallyExclusive bool, fieldsMap *sequentialFieldsMap, fragmentSpread *ast.FragmentSpread) { +func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFieldsAndFragment( + conflicts *conflictMessageContainer, + areMutuallyExclusive bool, + fieldsMap *sequentialFieldsMap, + fragmentSpread *ast.FragmentSpread, +) { if m.comparedFragments[fragmentSpread.Name] { return } @@ -299,11 +318,21 @@ func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFieldsAndFr if fragmentSpread.Name == baseFragmentSpread.Name { continue } - m.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsMap, fragmentSpread) + m.collectConflictsBetweenFieldsAndFragment( + conflicts, + areMutuallyExclusive, + fieldsMap, + fragmentSpread, + ) } } -func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFragments(conflicts *conflictMessageContainer, areMutuallyExclusive bool, fragmentSpreadA *ast.FragmentSpread, fragmentSpreadB *ast.FragmentSpread) { +func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFragments( + conflicts *conflictMessageContainer, + areMutuallyExclusive bool, + fragmentSpreadA *ast.FragmentSpread, + fragmentSpreadB *ast.FragmentSpread, +) { var check func(fragmentSpreadA *ast.FragmentSpread, fragmentSpreadB *ast.FragmentSpread) check = func(fragmentSpreadA *ast.FragmentSpread, fragmentSpreadB *ast.FragmentSpread) { if fragmentSpreadA.Name == fragmentSpreadB.Name { @@ -322,8 +351,12 @@ func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFragments(c return } - fieldsMapA, fragmentSpreadsA := getFieldsAndFragmentNames(fragmentSpreadA.Definition.SelectionSet) - fieldsMapB, fragmentSpreadsB := getFieldsAndFragmentNames(fragmentSpreadB.Definition.SelectionSet) + fieldsMapA, fragmentSpreadsA := getFieldsAndFragmentNames( + fragmentSpreadA.Definition.SelectionSet, + ) + fieldsMapB, fragmentSpreadsB := getFieldsAndFragmentNames( + fragmentSpreadB.Definition.SelectionSet, + ) // (F) First, collect all conflicts between these two collections of fields // (not including any nested fragments). @@ -344,7 +377,11 @@ func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetweenFragments(c check(fragmentSpreadA, fragmentSpreadB) } -func (m *overlappingFieldsCanBeMergedManager) findConflictsBetweenSubSelectionSets(areMutuallyExclusive bool, selectionSetA ast.SelectionSet, selectionSetB ast.SelectionSet) *conflictMessageContainer { +func (m *overlappingFieldsCanBeMergedManager) findConflictsBetweenSubSelectionSets( + areMutuallyExclusive bool, + selectionSetA ast.SelectionSet, + selectionSetB ast.SelectionSet, +) *conflictMessageContainer { var conflicts conflictMessageContainer fieldsMapA, fragmentSpreadsA := getFieldsAndFragmentNames(selectionSetA) @@ -357,14 +394,24 @@ func (m *overlappingFieldsCanBeMergedManager) findConflictsBetweenSubSelectionSe // those referenced by each fragment name associated with the second. for _, fragmentSpread := range fragmentSpreadsB { m.comparedFragments = make(map[string]bool) - m.collectConflictsBetweenFieldsAndFragment(&conflicts, areMutuallyExclusive, fieldsMapA, fragmentSpread) + m.collectConflictsBetweenFieldsAndFragment( + &conflicts, + areMutuallyExclusive, + fieldsMapA, + fragmentSpread, + ) } // (I) Then collect conflicts between the second collection of fields and // those referenced by each fragment name associated with the first. for _, fragmentSpread := range fragmentSpreadsA { m.comparedFragments = make(map[string]bool) - m.collectConflictsBetweenFieldsAndFragment(&conflicts, areMutuallyExclusive, fieldsMapB, fragmentSpread) + m.collectConflictsBetweenFieldsAndFragment( + &conflicts, + areMutuallyExclusive, + fieldsMapB, + fragmentSpread, + ) } // (J) Also collect conflicts between any fragment names by the first and @@ -372,7 +419,12 @@ func (m *overlappingFieldsCanBeMergedManager) findConflictsBetweenSubSelectionSe // names to each item in the second set of names. for _, fragmentSpreadA := range fragmentSpreadsA { for _, fragmentSpreadB := range fragmentSpreadsB { - m.collectConflictsBetweenFragments(&conflicts, areMutuallyExclusive, fragmentSpreadA, fragmentSpreadB) + m.collectConflictsBetweenFragments( + &conflicts, + areMutuallyExclusive, + fragmentSpreadA, + fragmentSpreadB, + ) } } @@ -383,7 +435,10 @@ func (m *overlappingFieldsCanBeMergedManager) findConflictsBetweenSubSelectionSe return &conflicts } -func (m *overlappingFieldsCanBeMergedManager) collectConflictsWithin(conflicts *conflictMessageContainer, fieldsMap *sequentialFieldsMap) { +func (m *overlappingFieldsCanBeMergedManager) collectConflictsWithin( + conflicts *conflictMessageContainer, + fieldsMap *sequentialFieldsMap, +) { for _, fields := range fieldsMap.Iterator() { for idx, fieldA := range fields { for _, fieldB := range fields[idx+1:] { @@ -396,7 +451,12 @@ func (m *overlappingFieldsCanBeMergedManager) collectConflictsWithin(conflicts * } } -func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetween(conflicts *conflictMessageContainer, parentFieldsAreMutuallyExclusive bool, fieldsMapA *sequentialFieldsMap, fieldsMapB *sequentialFieldsMap) { +func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetween( + conflicts *conflictMessageContainer, + parentFieldsAreMutuallyExclusive bool, + fieldsMapA *sequentialFieldsMap, + fieldsMapB *sequentialFieldsMap, +) { for _, fieldsEntryA := range fieldsMapA.KeyValueIterator() { fieldsB, ok := fieldsMapB.Get(fieldsEntryA.ResponseName) if !ok { @@ -413,7 +473,11 @@ func (m *overlappingFieldsCanBeMergedManager) collectConflictsBetween(conflicts } } -func (m *overlappingFieldsCanBeMergedManager) findConflict(parentFieldsAreMutuallyExclusive bool, fieldA *ast.Field, fieldB *ast.Field) *ConflictMessage { +func (m *overlappingFieldsCanBeMergedManager) findConflict( + parentFieldsAreMutuallyExclusive bool, + fieldA *ast.Field, + fieldB *ast.Field, +) *ConflictMessage { if fieldA.ObjectDefinition == nil || fieldB.ObjectDefinition == nil { return nil } @@ -437,8 +501,12 @@ func (m *overlappingFieldsCanBeMergedManager) findConflict(parentFieldsAreMutual if fieldA.Name != fieldB.Name { return &ConflictMessage{ ResponseName: fieldNameA, - Message: fmt.Sprintf(`"%s" and "%s" are different fields`, fieldA.Name, fieldB.Name), - Position: fieldB.Position, + Message: fmt.Sprintf( + `"%s" and "%s" are different fields`, + fieldA.Name, + fieldB.Name, + ), + Position: fieldB.Position, } } @@ -452,18 +520,27 @@ func (m *overlappingFieldsCanBeMergedManager) findConflict(parentFieldsAreMutual } } - if fieldA.Definition != nil && fieldB.Definition != nil && doTypesConflict(m.walker, fieldA.Definition.Type, fieldB.Definition.Type) { + if fieldA.Definition != nil && fieldB.Definition != nil && + doTypesConflict(m.walker, fieldA.Definition.Type, fieldB.Definition.Type) { return &ConflictMessage{ ResponseName: fieldNameA, - Message: fmt.Sprintf(`they return conflicting types "%s" and "%s"`, fieldA.Definition.Type.String(), fieldB.Definition.Type.String()), - Position: fieldB.Position, + Message: fmt.Sprintf( + `they return conflicting types "%s" and "%s"`, + fieldA.Definition.Type.String(), + fieldB.Definition.Type.String(), + ), + Position: fieldB.Position, } } // Collect and compare sub-fields. Use the same "visited fragment names" list // for both collections so fields in a fragment reference are never // compared to themselves. - conflicts := m.findConflictsBetweenSubSelectionSets(areMutuallyExclusive, fieldA.SelectionSet, fieldB.SelectionSet) + conflicts := m.findConflictsBetweenSubSelectionSets( + areMutuallyExclusive, + fieldA.SelectionSet, + fieldB.SelectionSet, + ) if conflicts == nil { return nil } @@ -474,7 +551,7 @@ func (m *overlappingFieldsCanBeMergedManager) findConflict(parentFieldsAreMutual } } -func sameArguments(args1 []*ast.Argument, args2 []*ast.Argument) bool { +func sameArguments(args1, args2 []*ast.Argument) bool { if len(args1) != len(args2) { return false } @@ -493,7 +570,7 @@ func sameArguments(args1 []*ast.Argument, args2 []*ast.Argument) bool { return true } -func sameValue(value1 *ast.Value, value2 *ast.Value) bool { +func sameValue(value1, value2 *ast.Value) bool { if value1.Kind != value2.Kind { return false } @@ -503,7 +580,7 @@ func sameValue(value1 *ast.Value, value2 *ast.Value) bool { return true } -func doTypesConflict(walker *Walker, type1 *ast.Type, type2 *ast.Type) bool { +func doTypesConflict(walker *Walker, type1, type2 *ast.Type) bool { if type1.Elem != nil { if type2.Elem != nil { return doTypesConflict(walker, type1.Elem, type2.Elem) @@ -522,14 +599,17 @@ func doTypesConflict(walker *Walker, type1 *ast.Type, type2 *ast.Type) bool { t1 := walker.Schema.Types[type1.NamedType] t2 := walker.Schema.Types[type2.NamedType] - if (t1.Kind == ast.Scalar || t1.Kind == ast.Enum) && (t2.Kind == ast.Scalar || t2.Kind == ast.Enum) { + if (t1.Kind == ast.Scalar || t1.Kind == ast.Enum) && + (t2.Kind == ast.Scalar || t2.Kind == ast.Enum) { return t1.Name != t2.Name } return false } -func getFieldsAndFragmentNames(selectionSet ast.SelectionSet) (*sequentialFieldsMap, []*ast.FragmentSpread) { +func getFieldsAndFragmentNames( + selectionSet ast.SelectionSet, +) (*sequentialFieldsMap, []*ast.FragmentSpread) { fieldsMap := sequentialFieldsMap{ data: make(map[string][]*ast.Field), } diff --git a/validator/rules/possible_fragment_spreads.go b/validator/rules/possible_fragment_spreads.go index f932ac8c..94cc6356 100644 --- a/validator/rules/possible_fragment_spreads.go +++ b/validator/rules/possible_fragment_spreads.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -49,7 +48,11 @@ var PossibleFragmentSpreadsRule = Rule{ observers.OnInlineFragment(func(walker *Walker, inlineFragment *ast.InlineFragment) { validate(walker, inlineFragment.ObjectDefinition, inlineFragment.TypeCondition, func() { addError( - Message(`Fragment cannot be spread here as objects of type "%s" can never be of type "%s".`, inlineFragment.ObjectDefinition.Name, inlineFragment.TypeCondition), + Message( + `Fragment cannot be spread here as objects of type "%s" can never be of type "%s".`, + inlineFragment.ObjectDefinition.Name, + inlineFragment.TypeCondition, + ), At(inlineFragment.Position), ) }) @@ -59,12 +62,22 @@ var PossibleFragmentSpreadsRule = Rule{ if fragmentSpread.Definition == nil { return } - validate(walker, fragmentSpread.ObjectDefinition, fragmentSpread.Definition.TypeCondition, func() { - addError( - Message(`Fragment "%s" cannot be spread here as objects of type "%s" can never be of type "%s".`, fragmentSpread.Name, fragmentSpread.ObjectDefinition.Name, fragmentSpread.Definition.TypeCondition), - At(fragmentSpread.Position), - ) - }) + validate( + walker, + fragmentSpread.ObjectDefinition, + fragmentSpread.Definition.TypeCondition, + func() { + addError( + Message( + `Fragment "%s" cannot be spread here as objects of type "%s" can never be of type "%s".`, + fragmentSpread.Name, + fragmentSpread.ObjectDefinition.Name, + fragmentSpread.Definition.TypeCondition, + ), + At(fragmentSpread.Position), + ) + }, + ) }) }, } diff --git a/validator/rules/rules_test.go b/validator/rules/rules_test.go index 86d63fc5..f7c0f2f8 100644 --- a/validator/rules/rules_test.go +++ b/validator/rules/rules_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/vektah/gqlparser/v2/validator/core" "github.com/vektah/gqlparser/v2/validator/rules" ) @@ -101,7 +102,9 @@ func TestNewDefaultRules(t *testing.T) { // TestGetInnerReturnsCopy confirms that GetInner returns a copy of the internal map. func TestGetInnerReturnsCopy(t *testing.T) { - rs := rules.NewRules(core.Rule{Name: "DummyRule", RuleFunc: func(*core.Events, core.AddErrFunc) {}}) + rs := rules.NewRules( + core.Rule{Name: "DummyRule", RuleFunc: func(*core.Events, core.AddErrFunc) {}}, + ) first := rs.GetInner() delete(first, "DummyRule") diff --git a/validator/rules/scalar_leafs.go b/validator/rules/scalar_leafs.go index e4f210d7..95fd2298 100644 --- a/validator/rules/scalar_leafs.go +++ b/validator/rules/scalar_leafs.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -22,14 +21,22 @@ var ScalarLeafsRule = Rule{ if fieldType.IsLeafType() && len(field.SelectionSet) > 0 { addError( - Message(`Field "%s" must not have a selection since type "%s" has no subfields.`, field.Name, fieldType.Name), + Message( + `Field "%s" must not have a selection since type "%s" has no subfields.`, + field.Name, + fieldType.Name, + ), At(field.Position), ) } if !fieldType.IsLeafType() && len(field.SelectionSet) == 0 { addError( - Message(`Field "%s" of type "%s" must have a selection of subfields.`, field.Name, field.Definition.Type.String()), + Message( + `Field "%s" of type "%s" must have a selection of subfields.`, + field.Name, + field.Definition.Type.String(), + ), Suggestf(`"%s { ... }"`, field.Name), At(field.Position), ) diff --git a/validator/rules/single_field_subscriptions.go b/validator/rules/single_field_subscriptions.go index feed91d5..2d4322da 100644 --- a/validator/rules/single_field_subscriptions.go +++ b/validator/rules/single_field_subscriptions.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/unique_argument_names.go b/validator/rules/unique_argument_names.go index 2ed1da2b..882a8cb1 100644 --- a/validator/rules/unique_argument_names.go +++ b/validator/rules/unique_argument_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/unique_directives_per_location.go b/validator/rules/unique_directives_per_location.go index 0f577028..a1a01016 100644 --- a/validator/rules/unique_directives_per_location.go +++ b/validator/rules/unique_directives_per_location.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -16,7 +15,10 @@ var UniqueDirectivesPerLocationRule = Rule{ for _, dir := range directives { if dir.Name != "repeatable" && seen[dir.Name] { addError( - Message(`The directive "@%s" can only be used once at this location.`, dir.Name), + Message( + `The directive "@%s" can only be used once at this location.`, + dir.Name, + ), At(dir.Position), ) } diff --git a/validator/rules/unique_fragment_names.go b/validator/rules/unique_fragment_names.go index 136b0fdb..7b1a40ce 100644 --- a/validator/rules/unique_fragment_names.go +++ b/validator/rules/unique_fragment_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/unique_input_field_names.go b/validator/rules/unique_input_field_names.go index 41d8d667..67c92de1 100644 --- a/validator/rules/unique_input_field_names.go +++ b/validator/rules/unique_input_field_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/unique_operation_names.go b/validator/rules/unique_operation_names.go index ae4c54ee..199a4b0f 100644 --- a/validator/rules/unique_operation_names.go +++ b/validator/rules/unique_operation_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/unique_variable_names.go b/validator/rules/unique_variable_names.go index 4d4a6a87..6a33d0e9 100644 --- a/validator/rules/unique_variable_names.go +++ b/validator/rules/unique_variable_names.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/values_of_correct_type.go b/validator/rules/values_of_correct_type.go index 43c1a1bf..5126245e 100644 --- a/validator/rules/values_of_correct_type.go +++ b/validator/rules/values_of_correct_type.go @@ -6,7 +6,6 @@ import ( "strconv" "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -19,7 +18,11 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable if value.Kind == ast.NullValue && value.ExpectedType.NonNull { addError( - Message(`Expected value of type "%s", found %s.`, value.ExpectedType.String(), value.String()), + Message( + `Expected value of type "%s", found %s.`, + value.ExpectedType.String(), + value.String(), + ), At(value.Position), ) } @@ -66,13 +69,21 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable if value.Definition.Kind == ast.Enum { if disableSuggestion { addError( - Message(`Enum "%s" cannot represent non-enum value: %s.`, value.ExpectedType.String(), value.String()), + Message( + `Enum "%s" cannot represent non-enum value: %s.`, + value.ExpectedType.String(), + value.String(), + ), At(value.Position), ) } else { rawValStr := fmt.Sprint(rawVal) addError( - Message(`Enum "%s" cannot represent non-enum value: %s.`, value.ExpectedType.String(), value.String()), + Message( + `Enum "%s" cannot represent non-enum value: %s.`, + value.ExpectedType.String(), + value.String(), + ), SuggestListQuoted("Did you mean the enum value", rawValStr, possibleEnums), At(value.Position), ) @@ -92,20 +103,32 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable rawValStr := fmt.Sprint(rawVal) addError( unexpectedTypeMessageOnly(value), - SuggestListUnquoted("Did you mean the enum value", rawValStr, possibleEnums), + SuggestListUnquoted( + "Did you mean the enum value", + rawValStr, + possibleEnums, + ), At(value.Position), ) } } else if value.Definition.EnumValues.ForName(value.Raw) == nil { if disableSuggestion { addError( - Message(`Value "%s" does not exist in "%s" enum.`, value.String(), value.ExpectedType.String()), + Message( + `Value "%s" does not exist in "%s" enum.`, + value.String(), + value.ExpectedType.String(), + ), At(value.Position), ) } else { rawValStr := fmt.Sprint(rawVal) addError( - Message(`Value "%s" does not exist in "%s" enum.`, value.String(), value.ExpectedType.String()), + Message( + `Value "%s" does not exist in "%s" enum.`, + value.String(), + value.ExpectedType.String(), + ), SuggestListQuoted("Did you mean the enum value", rawValStr, possibleEnums), At(value.Position), ) @@ -124,7 +147,12 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable fieldValue := value.Children.ForName(field.Name) if fieldValue == nil && field.DefaultValue == nil { addError( - Message(`Field "%s.%s" of required type "%s" was not provided.`, value.Definition.Name, field.Name, field.Type.String()), + Message( + `Field "%s.%s" of required type "%s" was not provided.`, + value.Definition.Name, + field.Name, + field.Type.String(), + ), At(value.Position), ) continue @@ -137,7 +165,10 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable func() { if len(value.Children) != 1 { addError( - Message(`OneOf Input Object "%s" must specify exactly one key.`, value.Definition.Name), + Message( + `OneOf Input Object "%s" must specify exactly one key.`, + value.Definition.Name, + ), At(value.Position), ) return @@ -147,7 +178,11 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable isNullLiteral := fieldValue == nil || fieldValue.Kind == ast.NullValue if isNullLiteral { addError( - Message(`Field "%s.%s" must be non-null.`, value.Definition.Name, value.Definition.Fields[0].Name), + Message( + `Field "%s.%s" must be non-null.`, + value.Definition.Name, + value.Definition.Fields[0].Name, + ), At(fieldValue.Position), ) return @@ -159,7 +194,11 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable isNullableVariable := !fieldValue.VariableDefinition.Type.NonNull if isNullableVariable { addError( - Message(`Variable "%s" must be non-nullable to be used for OneOf Input Object "%s".`, variableName, value.Definition.Name), + Message( + `Variable "%s" must be non-nullable to be used for OneOf Input Object "%s".`, + variableName, + value.Definition.Name, + ), At(fieldValue.Position), ) } @@ -172,7 +211,11 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable if value.Definition.Fields.ForName(fieldValue.Name) == nil { if disableSuggestion { addError( - Message(`Field "%s" is not defined by type "%s".`, fieldValue.Name, value.Definition.Name), + Message( + `Field "%s" is not defined by type "%s".`, + fieldValue.Name, + value.Definition.Name, + ), At(fieldValue.Position), ) } else { @@ -182,7 +225,11 @@ func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disable } addError( - Message(`Field "%s" is not defined by type "%s".`, fieldValue.Name, value.Definition.Name), + Message( + `Field "%s" is not defined by type "%s".`, + fieldValue.Name, + value.Definition.Name, + ), SuggestListQuoted("Did you mean", fieldValue.Name, suggestions), At(fieldValue.Position), ) @@ -223,7 +270,12 @@ func unexpectedTypeMessage(addError AddErrFunc, v *ast.Value) { func unexpectedTypeMessageOnly(v *ast.Value) ErrorOption { switch v.ExpectedType.String() { case "Int", "Int!": - if _, err := strconv.ParseInt(v.Raw, 10, 32); err != nil && errors.Is(err, strconv.ErrRange) { + if _, err := strconv.ParseInt( + v.Raw, + 10, + 32, + ); err != nil && + errors.Is(err, strconv.ErrRange) { return Message(`Int cannot represent non 32-bit signed integer value: %s`, v.String()) } return Message(`Int cannot represent non-integer value: %s`, v.String()) @@ -236,11 +288,20 @@ func unexpectedTypeMessageOnly(v *ast.Value) ErrorOption { case "ID", "ID!": return Message(`ID cannot represent a non-string and non-integer value: %s`, v.String()) // case "Enum": - // return Message(`Enum "%s" cannot represent non-enum value: %s`, v.ExpectedType.String(), v.String()) + // return Message(`Enum "%s" cannot represent non-enum value: %s`, v.ExpectedType.String(), + // v.String()) default: if v.Definition.Kind == ast.Enum { - return Message(`Enum "%s" cannot represent non-enum value: %s.`, v.ExpectedType.String(), v.String()) + return Message( + `Enum "%s" cannot represent non-enum value: %s.`, + v.ExpectedType.String(), + v.String(), + ) } - return Message(`Expected value of type "%s", found %s.`, v.ExpectedType.String(), v.String()) + return Message( + `Expected value of type "%s", found %s.`, + v.ExpectedType.String(), + v.String(), + ) } } diff --git a/validator/rules/variables_are_input_types.go b/validator/rules/variables_are_input_types.go index 77f116bb..b0670404 100644 --- a/validator/rules/variables_are_input_types.go +++ b/validator/rules/variables_are_input_types.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) diff --git a/validator/rules/variables_in_allowed_position.go b/validator/rules/variables_in_allowed_position.go index e1832334..d3d36a29 100644 --- a/validator/rules/variables_in_allowed_position.go +++ b/validator/rules/variables_in_allowed_position.go @@ -2,7 +2,6 @@ package rules import ( "github.com/vektah/gqlparser/v2/ast" - //nolint:staticcheck // Validator rules each use dot imports for convenience. . "github.com/vektah/gqlparser/v2/validator/core" ) @@ -11,7 +10,9 @@ var VariablesInAllowedPositionRule = Rule{ Name: "VariablesInAllowedPosition", RuleFunc: func(observers *Events, addError AddErrFunc) { observers.OnValue(func(walker *Walker, value *ast.Value) { - if value.Kind != ast.Variable || value.ExpectedType == nil || value.VariableDefinition == nil || walker.CurrentOperation == nil { + if value.Kind != ast.Variable || value.ExpectedType == nil || + value.VariableDefinition == nil || + walker.CurrentOperation == nil { return } @@ -19,7 +20,8 @@ var VariablesInAllowedPositionRule = Rule{ // todo: move me into walk // If there is a default non nullable types can be null - if value.VariableDefinition.DefaultValue != nil && value.VariableDefinition.DefaultValue.Kind != ast.NullValue { + if value.VariableDefinition.DefaultValue != nil && + value.VariableDefinition.DefaultValue.Kind != ast.NullValue { if value.ExpectedType.NonNull { tmp.NonNull = false } diff --git a/validator/schema.go b/validator/schema.go index a8754afc..d40b9f19 100644 --- a/validator/schema.go +++ b/validator/schema.go @@ -1,6 +1,7 @@ package validator import ( + "slices" "sort" "strconv" "strings" @@ -48,7 +49,13 @@ func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) { } if def.Kind != ext.Kind { - return nil, gqlerror.ErrorPosf(ext.Position, "Cannot extend type %s because the base type is a %s, not %s.", ext.Name, def.Kind, ext.Kind) + return nil, gqlerror.ErrorPosf( + ext.Position, + "Cannot extend type %s because the base type is a %s, not %s.", + ext.Name, + def.Kind, + ext.Kind, + ) } def.Directives = append(def.Directives, ext.Directives...) @@ -95,14 +102,21 @@ func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) { // version of gqlparser, in which case they're in trouble // anyway. default: - return nil, gqlerror.ErrorPosf(dir.Position, "Cannot redeclare directive %s.", dir.Name) + return nil, gqlerror.ErrorPosf( + dir.Position, + "Cannot redeclare directive %s.", + dir.Name, + ) } } schema.Directives[dir.Name] = sd.Directives[i] } if len(sd.Schema) > 1 { - return nil, gqlerror.ErrorPosf(sd.Schema[1].Position, "Cannot have multiple schema entry points, consider schema extensions instead.") + return nil, gqlerror.ErrorPosf( + sd.Schema[1].Position, + "Cannot have multiple schema entry points, consider schema extensions instead.", + ) } if len(sd.Schema) == 1 { @@ -110,7 +124,12 @@ func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) { for _, entrypoint := range sd.Schema[0].OperationTypes { def := schema.Types[entrypoint.Type] if def == nil { - return nil, gqlerror.ErrorPosf(entrypoint.Position, "Schema root %s refers to a type %s that does not exist.", entrypoint.Operation, entrypoint.Type) + return nil, gqlerror.ErrorPosf( + entrypoint.Position, + "Schema root %s refers to a type %s that does not exist.", + entrypoint.Operation, + entrypoint.Type, + ) } switch entrypoint.Operation { case Query: @@ -121,7 +140,12 @@ func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) { schema.Subscription = def } } - if err := validateDirectives(&schema, sd.Schema[0].Directives, LocationSchema, nil); err != nil { + if err := validateDirectives( + &schema, + sd.Schema[0].Directives, + LocationSchema, + nil, + ); err != nil { return nil, err } schema.SchemaDirectives = append(schema.SchemaDirectives, sd.Schema[0].Directives...) @@ -131,7 +155,12 @@ func ValidateSchemaDocument(sd *SchemaDocument) (*Schema, error) { for _, entrypoint := range ext.OperationTypes { def := schema.Types[entrypoint.Type] if def == nil { - return nil, gqlerror.ErrorPosf(entrypoint.Position, "Schema root %s refers to a type %s that does not exist.", entrypoint.Operation, entrypoint.Type) + return nil, gqlerror.ErrorPosf( + entrypoint.Position, + "Schema root %s refers to a type %s that does not exist.", + entrypoint.Operation, + entrypoint.Type, + ) } switch entrypoint.Operation { case Query: @@ -259,7 +288,13 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error { return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(typ)) } if !isValidKind(typDef.Kind, Object) { - return gqlerror.ErrorPosf(def.Position, "%s type %s must be %s.", def.Kind, strconv.Quote(typ), kindList(Object)) + return gqlerror.ErrorPosf( + def.Position, + "%s type %s must be %s.", + def.Kind, + strconv.Quote(typ), + kindList(Object), + ) } } @@ -272,37 +307,75 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error { switch def.Kind { case Object, Interface: if len(def.Fields) == 0 { - return gqlerror.ErrorPosf(def.Position, "%s %s: must define one or more fields.", def.Kind, def.Name) + return gqlerror.ErrorPosf( + def.Position, + "%s %s: must define one or more fields.", + def.Kind, + def.Name, + ) } for _, field := range def.Fields { if typ, ok := schema.Types[field.Type.Name()]; ok { if !isValidKind(typ.Kind, Scalar, Object, Interface, Union, Enum) { - return gqlerror.ErrorPosf(field.Position, "%s %s: field must be one of %s.", def.Kind, def.Name, kindList(Scalar, Object, Interface, Union, Enum)) + return gqlerror.ErrorPosf( + field.Position, + "%s %s: field must be one of %s.", + def.Kind, + def.Name, + kindList(Scalar, Object, Interface, Union, Enum), + ) } } } case Enum: if len(def.EnumValues) == 0 { - return gqlerror.ErrorPosf(def.Position, "%s %s: must define one or more unique enum values.", def.Kind, def.Name) + return gqlerror.ErrorPosf( + def.Position, + "%s %s: must define one or more unique enum values.", + def.Kind, + def.Name, + ) } for _, value := range def.EnumValues { for _, nonEnum := range [3]string{"true", "false", "null"} { if value.Name == nonEnum { - return gqlerror.ErrorPosf(def.Position, "%s %s: non-enum value %s.", def.Kind, def.Name, value.Name) + return gqlerror.ErrorPosf( + def.Position, + "%s %s: non-enum value %s.", + def.Kind, + def.Name, + value.Name, + ) } } - if err := validateDirectives(schema, value.Directives, LocationEnumValue, nil); err != nil { + if err := validateDirectives( + schema, + value.Directives, + LocationEnumValue, + nil, + ); err != nil { return err } } case InputObject: if len(def.Fields) == 0 { - return gqlerror.ErrorPosf(def.Position, "%s %s: must define one or more input fields.", def.Kind, def.Name) + return gqlerror.ErrorPosf( + def.Position, + "%s %s: must define one or more input fields.", + def.Kind, + def.Name, + ) } for _, field := range def.Fields { if typ, ok := schema.Types[field.Type.Name()]; ok { if !isValidKind(typ.Kind, Scalar, Enum, InputObject) { - return gqlerror.ErrorPosf(field.Position, "%s %s: field must be one of %s.", typ.Kind, field.Name, kindList(Scalar, Enum, InputObject)) + return gqlerror.ErrorPosf( + field.Position, + "%s %s: field must be one of %s.", + typ.Kind, + field.Name, + kindList(Scalar, Enum, InputObject), + ) } } } @@ -311,7 +384,12 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error { for idx, field1 := range def.Fields { for _, field2 := range def.Fields[idx+1:] { if field1.Name == field2.Name { - return gqlerror.ErrorPosf(field2.Position, "Field %s.%s can only be defined once.", def.Name, field2.Name) + return gqlerror.ErrorPosf( + field2.Position, + "Field %s.%s can only be defined once.", + def.Name, + field2.Name, + ) } } } @@ -334,7 +412,11 @@ func validateTypeRef(schema *Schema, typ *Type) *gqlerror.Error { return nil } -func validateArgs(schema *Schema, args ArgumentDefinitionList, currentDirective *DirectiveDefinition) *gqlerror.Error { +func validateArgs( + schema *Schema, + args ArgumentDefinitionList, + currentDirective *DirectiveDefinition, +) *gqlerror.Error { for _, arg := range args { if err := validateName(arg.Position, arg.Name); err != nil { // now, GraphQL spec doesn't have reserved argument name @@ -353,45 +435,71 @@ func validateArgs(schema *Schema, args ArgumentDefinitionList, currentDirective def.Kind, ) } - if err := validateDirectives(schema, arg.Directives, LocationArgumentDefinition, currentDirective); err != nil { + if err := validateDirectives( + schema, + arg.Directives, + LocationArgumentDefinition, + currentDirective, + ); err != nil { return err } } return nil } -func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLocation, currentDirective *DirectiveDefinition) *gqlerror.Error { +func validateDirectives( + schema *Schema, + dirs DirectiveList, + location DirectiveLocation, + currentDirective *DirectiveDefinition, +) *gqlerror.Error { for _, dir := range dirs { if err := validateName(dir.Position, dir.Name); err != nil { // now, GraphQL spec doesn't have reserved directive name return err } if currentDirective != nil && dir.Name == currentDirective.Name { - return gqlerror.ErrorPosf(dir.Position, "Directive %s cannot refer to itself.", currentDirective.Name) + return gqlerror.ErrorPosf( + dir.Position, + "Directive %s cannot refer to itself.", + currentDirective.Name, + ) } dirDefinition := schema.Directives[dir.Name] if dirDefinition == nil { return gqlerror.ErrorPosf(dir.Position, "Undefined directive %s.", dir.Name) } - validKind := false - for _, dirLocation := range dirDefinition.Locations { - if dirLocation == location { - validKind = true - break - } - } + validKind := slices.Contains(dirDefinition.Locations, location) if !validKind { - return gqlerror.ErrorPosf(dir.Position, "Directive %s is not applicable on %s.", dir.Name, location) + return gqlerror.ErrorPosf( + dir.Position, + "Directive %s is not applicable on %s.", + dir.Name, + location, + ) } for _, arg := range dir.Arguments { if dirDefinition.Arguments.ForName(arg.Name) == nil { - return gqlerror.ErrorPosf(arg.Position, "Undefined argument %s for directive %s.", arg.Name, dir.Name) + return gqlerror.ErrorPosf( + arg.Position, + "Undefined argument %s for directive %s.", + arg.Name, + dir.Name, + ) } } for _, schemaArg := range dirDefinition.Arguments { if schemaArg.Type.NonNull && schemaArg.DefaultValue == nil { - if arg := dir.Arguments.ForName(schemaArg.Name); arg == nil || arg.Value.Kind == NullValue { - return gqlerror.ErrorPosf(dir.Position, "Argument %s for directive %s cannot be null.", schemaArg.Name, dir.Name) + if arg := dir.Arguments.ForName( + schemaArg.Name, + ); arg == nil || + arg.Value.Kind == NullValue { + return gqlerror.ErrorPosf( + dir.Position, + "Argument %s for directive %s cannot be null.", + schemaArg.Name, + dir.Name, + ) } } } @@ -408,7 +516,12 @@ func validateImplements(schema *Schema, def *Definition, intfName string) *gqler return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(intfName)) } if intf.Kind != Interface { - return gqlerror.ErrorPosf(def.Position, "%s is a non interface type %s.", strconv.Quote(intfName), intf.Kind) + return gqlerror.ErrorPosf( + def.Position, + "%s is a non interface type %s.", + strconv.Quote(intfName), + intf.Kind, + ) } for _, requiredField := range intf.Fields { foundField := def.Fields.ForName(requiredField.Name) @@ -429,24 +542,37 @@ func validateImplements(schema *Schema, def *Definition, intfName string) *gqler for _, requiredArg := range requiredField.Arguments { foundArg := foundField.Arguments.ForName(requiredArg.Name) if foundArg == nil { - return gqlerror.ErrorPosf(foundField.Position, + return gqlerror.ErrorPosf( + foundField.Position, `For %s to implement %s the field %s must have the same arguments but it is missing %s.`, - def.Name, intf.Name, requiredField.Name, requiredArg.Name, + def.Name, + intf.Name, + requiredField.Name, + requiredArg.Name, ) } if !requiredArg.Type.IsCompatible(foundArg.Type) { - return gqlerror.ErrorPosf(foundArg.Position, + return gqlerror.ErrorPosf( + foundArg.Position, `For %s to implement %s the field %s must have the same arguments but %s has the wrong type.`, - def.Name, intf.Name, requiredField.Name, requiredArg.Name, + def.Name, + intf.Name, + requiredField.Name, + requiredArg.Name, ) } } for _, foundArgs := range foundField.Arguments { - if requiredField.Arguments.ForName(foundArgs.Name) == nil && foundArgs.Type.NonNull && foundArgs.DefaultValue == nil { - return gqlerror.ErrorPosf(foundArgs.Position, + if requiredField.Arguments.ForName(foundArgs.Name) == nil && foundArgs.Type.NonNull && + foundArgs.DefaultValue == nil { + return gqlerror.ErrorPosf( + foundArgs.Position, `For %s to implement %s any additional arguments on %s must be optional or have a default value but %s is required.`, - def.Name, intf.Name, foundField.Name, foundArgs.Name, + def.Name, + intf.Name, + foundField.Name, + foundArgs.Name, ) } } @@ -456,7 +582,11 @@ func validateImplements(schema *Schema, def *Definition, intfName string) *gqler // validateTypeImplementsAncestors // https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/type/validate.ts#L428 -func validateTypeImplementsAncestors(schema *Schema, def *Definition, intfName string) *gqlerror.Error { +func validateTypeImplementsAncestors( + schema *Schema, + def *Definition, + intfName string, +) *gqlerror.Error { intf := schema.Types[intfName] if intf == nil { return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(intfName)) @@ -479,15 +609,10 @@ func validateTypeImplementsAncestors(schema *Schema, def *Definition, intfName s } func containsString(slice []string, want string) bool { - for _, str := range slice { - if want == str { - return true - } - } - return false + return slices.Contains(slice, want) } -func isCovariant(schema *Schema, required *Type, actual *Type) bool { +func isCovariant(schema *Schema, required, actual *Type) bool { if required.NonNull && !actual.NonNull { return false } @@ -513,18 +638,17 @@ func isCovariant(schema *Schema, required *Type, actual *Type) bool { func validateName(pos *Position, name string) *gqlerror.Error { if strings.HasPrefix(name, "__") { - return gqlerror.ErrorPosf(pos, `Name "%s" must not begin with "__", which is reserved by GraphQL introspection.`, name) + return gqlerror.ErrorPosf( + pos, + `Name "%s" must not begin with "__", which is reserved by GraphQL introspection.`, + name, + ) } return nil } func isValidKind(kind DefinitionKind, valid ...DefinitionKind) bool { - for _, k := range valid { - if kind == k { - return true - } - } - return false + return slices.Contains(valid, kind) } func kindList(kinds ...DefinitionKind) string { diff --git a/validator/schema_test.go b/validator/schema_test.go index 93cd3d72..d23de402 100644 --- a/validator/schema_test.go +++ b/validator/schema_test.go @@ -1,13 +1,14 @@ package validator import ( + "errors" "os" "testing" - "github.com/vektah/gqlparser/v2/gqlerror" - "github.com/stretchr/testify/require" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/parser/testrunner" ) @@ -19,7 +20,11 @@ func TestLoadSchema(t *testing.T) { boolDef := s.Types["Boolean"] require.Equal(t, "Boolean", boolDef.Name) require.Equal(t, ast.Scalar, boolDef.Kind) - require.Equal(t, "The `Boolean` scalar type represents `true` or `false`.", boolDef.Description) + require.Equal( + t, + "The `Boolean` scalar type represents `true` or `false`.", + boolDef.Description, + ) deferDef := s.Directives["defer"] require.Equal(t, "defer", deferDef.Name, "@defer exists.") @@ -73,9 +78,9 @@ func TestLoadSchema(t *testing.T) { require.Equal(t, "Subscription", s.Subscription.Name) require.Equal(t, "dogEvents", s.Subscription.Fields[0].Name) - require.Equal(t, 1, len(s.SchemaDirectives)) + require.Len(t, s.SchemaDirectives, 1) require.Equal(t, "exampleOnSchemaDirective", s.SchemaDirectives[0].Name) - require.Equal(t, 1, len(s.SchemaDirectives[0].Arguments)) + require.Len(t, s.SchemaDirectives[0].Arguments, 1) require.Equal(t, "name", s.SchemaDirectives[0].Arguments[0].Name) require.Equal(t, "foo", s.SchemaDirectives[0].Arguments[0].Value.Raw) @@ -112,7 +117,11 @@ func TestLoadSchema(t *testing.T) { _, err := LoadSchema(Prelude, &ast.Source{Input: input}) if err != nil { return testrunner.Spec{ - Error: err.(*gqlerror.Error), + Error: func() *gqlerror.Error { + target := &gqlerror.Error{} + _ = errors.As(err, &target) + return target + }(), } } return testrunner.Spec{} @@ -149,7 +158,11 @@ func TestSchemaDescriptionWithQuotesAtEnd(t *testing.T) { field: String } `, BuiltIn: false}) - require.NoError(t, err, "Schema with quotes followed by space at end of description should parse successfully") + require.NoError( + t, + err, + "Schema with quotes followed by space at end of description should parse successfully", + ) }) t.Run("bug - quotes at end of description", func(t *testing.T) { @@ -160,6 +173,10 @@ func TestSchemaDescriptionWithQuotesAtEnd(t *testing.T) { field: String } `, BuiltIn: false}) - require.NoError(t, err, "Schema with quotes at end of description should parse successfully") + require.NoError( + t, + err, + "Schema with quotes at end of description should parse successfully", + ) }) } diff --git a/validator/validator.go b/validator/validator.go index 1214ed16..9fb40d6a 100644 --- a/validator/validator.go +++ b/validator/validator.go @@ -2,6 +2,7 @@ package validator import ( "sort" + //nolint:staticcheck // bad, yeah . "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" @@ -24,7 +25,7 @@ var ( OrList = core.OrList ) -// Walk is an alias for core.Walk +// Walk is an alias for core.Walk. func Walk(schema *Schema, document *QueryDocument, observers *Events) { core.Walk(schema, document, observers) } @@ -49,9 +50,9 @@ func AddRule(name string, ruleFunc RuleFunc) { // RemoveRule removes an existing rule from the rule set // if one of the same name exists. -// The rule set is global, so it is not safe for concurrent changes +// The rule set is global, so it is not safe for concurrent changes. func RemoveRule(name string) { - var result []Rule // nolint:prealloc // using initialized with len(rules) produces a race condition + var result []Rule //nolint:prealloc // using initialized with len(rules) produces a race condition for _, r := range specifiedRules { if r.Name == name { continue @@ -64,10 +65,10 @@ func RemoveRule(name string) { // ReplaceRule replaces an existing rule from the rule set // if one of the same name exists. // If no match is found, it will add a new rule to the rule set. -// The rule set is global, so it is not safe for concurrent changes +// The rule set is global, so it is not safe for concurrent changes. func ReplaceRule(name string, ruleFunc RuleFunc) { var found bool - var result []Rule // nolint:prealloc // using initialized with len(rules) produces a race condition + var result []Rule //nolint:prealloc // using initialized with len(rules) produces a race condition for _, r := range specifiedRules { if r.Name == name { found = true @@ -117,7 +118,11 @@ func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List { return errs } -func ValidateWithRules(schema *Schema, doc *QueryDocument, rules *validatorrules.Rules) gqlerror.List { +func ValidateWithRules( + schema *Schema, + doc *QueryDocument, + rules *validatorrules.Rules, +) gqlerror.List { if rules == nil { rules = validatorrules.NewDefaultRules() } @@ -134,7 +139,7 @@ func ValidateWithRules(schema *Schema, doc *QueryDocument, rules *validatorrules } observers := &core.Events{} - var currentRules []Rule // nolint:prealloc // would require extra local refs for len + var currentRules []Rule //nolint:prealloc // would require extra local refs for len for name, ruleFunc := range rules.GetInner() { currentRules = append(currentRules, Rule{Name: name, RuleFunc: ruleFunc}) // ensure deterministic order evaluation diff --git a/validator/validator_test.go b/validator/validator_test.go index 6befa032..8e1cc82f 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -3,14 +3,13 @@ package validator_test import ( "testing" - "github.com/vektah/gqlparser/v2/validator/rules" - "github.com/stretchr/testify/require" "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/parser" "github.com/vektah/gqlparser/v2/validator" + "github.com/vektah/gqlparser/v2/validator/rules" ) func TestExtendingNonExistantTypes(t *testing.T) { @@ -40,7 +39,7 @@ extend type Query { } }`}) require.NoError(t, err) - //nolint:staticcheck + require.Nil(t, validator.Validate(s, q)) require.Nil(t, validator.ValidateWithRules(s, q, nil)) } @@ -76,7 +75,7 @@ query SomeOperation { `, }) require.NoError(t, err) - //nolint:staticcheck + r1 := validator.Validate(s, q1) require.Len(t, r1, 1) const errorString = `SomeOperation:4:2: Field "myAction" argument "myEnum" of type "Locale!" is required, but it was not provided.` @@ -94,7 +93,7 @@ query SomeOperation ($locale: Locale! = DE) { `, }) require.NoError(t, err) - //nolint:staticcheck + require.Nil(t, validator.Validate(s, q2)) // Repeating same query and expecting to still return same validation error @@ -197,7 +196,7 @@ func TestNoUnusedVariables(t *testing.T) { } `}) require.NoError(t, err) - //nolint:staticcheck + require.Nil(t, validator.Validate(s, q)) }) } @@ -248,7 +247,8 @@ func TestCustomRuleSet(t *testing.T) { type Query { bar: String! } - `, BuiltIn: false}, + `, BuiltIn: false, + }, ) q, err := parser.ParseQuery(&ast.Source{ @@ -257,9 +257,10 @@ func TestCustomRuleSet(t *testing.T) { query Foo($flag: Boolean!) { ...Bar } - `}) + `, + }) require.NoError(t, err) - //nolint:staticcheck + errList := validator.Validate(s, q, []validator.Rule{someRule, someOtherRule}...) require.Len(t, errList, 2) require.Equal(t, "some error message", errList[0].Message) @@ -288,7 +289,8 @@ func TestCustomRuleSetWithRules(t *testing.T) { type Query { bar: String! } - `, BuiltIn: false}, + `, BuiltIn: false, + }, ) q, err := parser.ParseQuery(&ast.Source{ @@ -297,13 +299,15 @@ func TestCustomRuleSetWithRules(t *testing.T) { query Foo($flag: Boolean!) { ...Bar } - `}) + `, + }) require.NoError(t, err) errList := validator.ValidateWithRules(s, q, rules.NewRules(someRule, someOtherRule)) require.Len(t, errList, 2) // because we hold rules in a map, the order is not guaranteed - // this is fine because we used to add the rule in the init function, so it didn't need to be specified as a requirement for the order. + // this is fine because we used to add the rule in the init function, so it didn't need to be + // specified as a requirement for the order. messages := []string{errList[0].Message, errList[1].Message} require.Contains(t, messages, "some error message") require.Contains(t, messages, "some other error message") @@ -313,7 +317,10 @@ func TestRemoveRule(t *testing.T) { // no error validator.RemoveRule("rule that does not exist") - validator.AddRule("Rule that should no longer exist", func(observers *validator.Events, addError validator.AddErrFunc) {}) + validator.AddRule( + "Rule that should no longer exist", + func(observers *validator.Events, addError validator.AddErrFunc) {}, + ) // no error validator.RemoveRule("Rule that should no longer exist") diff --git a/validator/vars.go b/validator/vars.go index 205a7fb5..50e2cdb2 100644 --- a/validator/vars.go +++ b/validator/vars.go @@ -2,6 +2,7 @@ package validator import ( "encoding/json" + "errors" "fmt" "reflect" "strconv" @@ -12,11 +13,15 @@ import ( ) //nolint:staticcheck // We do not care about capitalized error strings -var ErrUnexpectedType = fmt.Errorf("Unexpected Type") +var ErrUnexpectedType = errors.New("Unexpected Type") -// VariableValues coerces and validates variable values -func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables map[string]interface{}) (map[string]interface{}, error) { - coercedVars := map[string]interface{}{} +// VariableValues coerces and validates variable values. +func VariableValues( + schema *ast.Schema, + op *ast.OperationDefinition, + variables map[string]any, +) (map[string]any, error) { + coercedVars := map[string]any{} validator := varValidator{ path: ast.Path{ast.PathName("variable")}, @@ -60,13 +65,23 @@ func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables m case "Int": n, err := jsonNumber.Int64() if err != nil { - return nil, gqlerror.ErrorPathf(validator.path, "cannot use value %d as %s", n, v.Type.NamedType) + return nil, gqlerror.ErrorPathf( + validator.path, + "cannot use value %d as %s", + n, + v.Type.NamedType, + ) } rv = reflect.ValueOf(n) case "Float": f, err := jsonNumber.Float64() if err != nil { - return nil, gqlerror.ErrorPathf(validator.path, "cannot use value %f as %s", f, v.Type.NamedType) + return nil, gqlerror.ErrorPathf( + validator.path, + "cannot use value %f as %s", + f, + v.Type.NamedType, + ) } rv = reflect.ValueOf(f) } @@ -93,7 +108,10 @@ type varValidator struct { schema *ast.Schema } -func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflect.Value, *gqlerror.Error) { +func (v *varValidator) validateVarType( + typ *ast.Type, + val reflect.Value, +) (reflect.Value, *gqlerror.Error) { currentPath := v.path resetPath := func() { v.path = currentPath @@ -137,7 +155,8 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflec switch def.Kind { case ast.Enum: kind := val.Type().Kind() - if kind != reflect.Int && kind != reflect.Int32 && kind != reflect.Int64 && kind != reflect.String { + if kind != reflect.Int && kind != reflect.Int32 && kind != reflect.Int64 && + kind != reflect.String { return val, gqlerror.ErrorPathf(v.path, "enums must be ints or strings") } isValidEnum := false @@ -154,11 +173,17 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflec kind := val.Type().Kind() switch typ.NamedType { case "Int": - if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.Float32 || kind == reflect.Float64 || IsValidIntString(val, kind) { + if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || + kind == reflect.Float32 || + kind == reflect.Float64 || + IsValidIntString(val, kind) { return val, nil } case "Float": - if kind == reflect.Float32 || kind == reflect.Float64 || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || IsValidFloatString(val, kind) { + if kind == reflect.Float32 || kind == reflect.Float64 || kind == reflect.Int || + kind == reflect.Int32 || + kind == reflect.Int64 || + IsValidFloatString(val, kind) { return val, nil } case "String": @@ -172,7 +197,8 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflec } case "ID": - if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String { + if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || + kind == reflect.String { return val, nil } default: diff --git a/validator/vars_test.go b/validator/vars_test.go index 2aa07d4c..6f7989bd 100644 --- a/validator/vars_test.go +++ b/validator/vars_test.go @@ -28,9 +28,13 @@ func TestValidateVars(t *testing.T) { t.Run("nil in required value", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query($id: Int!) { intArg(i: $id) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "id": nil, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "id": nil, + }, + ) require.EqualError(t, gerr, "input: variable.id cannot be null") }) @@ -54,124 +58,205 @@ func TestValidateVars(t *testing.T) { t.Run("input object", func(t *testing.T) { t.Run("non object", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": "hello", - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": "hello", + }, + ) require.EqualError(t, gerr, "input: variable.var must be a InputType, not a string") }) t.Run("defaults", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType! = {name: "foo"}) { structArg(i: $var) }`) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType! = {name: "foo"}) { structArg(i: $var) }`, + ) vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"name": "foo"}, vars["var"]) + require.EqualValues(t, map[string]any{"name": "foo"}, vars["var"]) }) t.Run("valid value", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + }, }, - }) + ) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"name": "foobar"}, vars["var"]) + require.EqualValues(t, map[string]any{"name": "foobar"}, vars["var"]) }) t.Run("null object field", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "nullName": nil, + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "nullName": nil, + }, }, - }) + ) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"name": "foobar", "nullName": nil}, vars["var"]) + require.EqualValues( + t, + map[string]any{"name": "foobar", "nullName": nil}, + vars["var"], + ) }) t.Run("missing required values", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{}, - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{}, + }, + ) require.EqualError(t, gerr, "input: variable.var.name must be defined") }) t.Run("null required field", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": nil, + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": nil, + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var.name cannot be null") }) t.Run("null embedded input object", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foo", - "nullEmbedded": nil, + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foo", + "nullEmbedded": nil, + }, }, - }) + ) require.NoError(t, gerr) }) t.Run("unknown field", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "foobard": true, + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "foobard": true, + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var.foobard unknown field") }) t.Run("unknown __typefield", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "__typename": "InputType", + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "__typename": "InputType", + }, }, - }) + ) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"__typename": "InputType", "name": "foobar"}, vars["var"]) + require.EqualValues( + t, + map[string]any{"__typename": "InputType", "name": "foobar"}, + vars["var"], + ) }) t.Run("enum input object", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "enum": "A", + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "enum": "A", + }, }, - }) + ) require.NoError(t, gerr) }) t.Run("unknown enum value input object", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "enum": "B", + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "enum": "B", + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var.enum B is not a valid Enum") }) }) @@ -179,20 +264,31 @@ func TestValidateVars(t *testing.T) { t.Run("array", func(t *testing.T) { t.Run("non-null object value should be coerced to an array", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{"name": "hello"}, - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{"name": "hello"}, + }, + ) require.NoError(t, gerr) - require.EqualValues(t, []map[string]interface{}{{"name": "hello"}}, vars["var"]) + require.EqualValues(t, []map[string]any{{"name": "hello"}}, vars["var"]) }) t.Run("non-null int value should be coerced to an array", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: [Int!]) { intArrayArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 5, - }) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 5, + }, + ) require.NoError(t, gerr) expected := []int{5} require.EqualValues(t, expected, vars["var"]) @@ -200,67 +296,105 @@ func TestValidateVars(t *testing.T) { t.Run("non-null int deep value should be coerced to an array", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []map[string]interface{}{{"and": 5}}, - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []map[string]any{{"and": 5}}, + }, + ) require.NoError(t, gerr) - expected := []map[string]interface{}{{"and": []int{5}}} + expected := []map[string]any{{"and": []int{5}}} require.EqualValues(t, expected, vars["var"]) }) t.Run("defaults", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`, + ) vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) - require.EqualValues(t, []interface{}{map[string]interface{}{ + require.EqualValues(t, []any{map[string]any{ "name": "foo", }}, vars["var"]) }) t.Run("valid value", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []interface{}{map[string]interface{}{ - "name": "foo", - }}, - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []any{map[string]any{ + "name": "foo", + }}, + }, + ) require.NoError(t, gerr) - require.EqualValues(t, []interface{}{map[string]interface{}{ + require.EqualValues(t, []any{map[string]any{ "name": "foo", }}, vars["var"]) }) t.Run("null element value", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []interface{}{nil}, - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []any{nil}, + }, + ) require.EqualError(t, gerr, "input: variable.var[0] cannot be null") }) t.Run("missing required values", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []interface{}{map[string]interface{}{}}, - }) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []any{map[string]any{}}, + }, + ) require.EqualError(t, gerr, "input: variable.var[0].name must be defined") }) t.Run("invalid variable paths", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var1: InputType!, $var2: InputType!) { a:structArg(i: $var1) b:structArg(i: $var2) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var1": map[string]interface{}{ - "name": "foobar", + q := gqlparser.MustLoadQuery( + schema, + `query foo($var1: InputType!, $var2: InputType!) { a:structArg(i: $var1) b:structArg(i: $var2) }`, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var1": map[string]any{ + "name": "foobar", + }, + "var2": map[string]any{ + "nullName": "foobar", + }, }, - "var2": map[string]interface{}{ - "nullName": "foobar", - }, - }) + ) require.EqualError(t, gerr, "input: variable.var2.name must be defined") }) }) @@ -269,9 +403,13 @@ func TestValidateVars(t *testing.T) { t.Run("String -> String", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": "asdf", - }) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": "asdf", + }, + ) require.NoError(t, gerr) require.EqualValues(t, "asdf", vars["var"]) }) @@ -279,18 +417,26 @@ func TestValidateVars(t *testing.T) { t.Run("Int -> String", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 1, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 1, + }, + ) require.EqualError(t, gerr, "input: variable.var cannot use int as String") }) t.Run("Nil -> String", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": nil, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": nil, + }, + ) require.EqualError(t, gerr, "input: variable.var cannot be null") }) @@ -311,9 +457,13 @@ func TestValidateVars(t *testing.T) { t.Run("Json Number -> Int", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 10, - }) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 10, + }, + ) require.NoError(t, gerr) require.Equal(t, 10, vars["var"]) }) @@ -321,9 +471,13 @@ func TestValidateVars(t *testing.T) { t.Run("Json Number -> Float", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: Float!) { floatArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 10.2, - }) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 10.2, + }, + ) require.NoError(t, gerr) require.Equal(t, 10.2, vars["var"]) }) @@ -331,9 +485,13 @@ func TestValidateVars(t *testing.T) { t.Run("Nil -> Int", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": nil, - }) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": nil, + }, + ) require.NoError(t, gerr) require.Nil(t, vars["var"]) }) @@ -341,9 +499,13 @@ func TestValidateVars(t *testing.T) { t.Run("Bool -> Int", func(t *testing.T) { //nolint:staticcheck q := gqlparser.MustLoadQuery(schema, `query foo($var: Int!) { intArg(i: $var) }`) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": true, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": true, + }, + ) require.EqualError(t, gerr, "input: variable.var cannot use bool as Int") }) }) @@ -355,9 +517,13 @@ func TestValidateVars(t *testing.T) { a := 1 b := 2 - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []*int{&a, &b, nil}, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []*int{&a, &b, nil}, + }, + ) require.NoError(t, gerr) }) }) @@ -365,13 +531,20 @@ func TestValidateVars(t *testing.T) { t.Run("String Array", func(t *testing.T) { t.Run("Array with null", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [String]) { stringArrayArg(i: $var) }`) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [String]) { stringArrayArg(i: $var) }`, + ) a := "1" b := "2" - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []*string{&a, &b, nil}, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []*string{&a, &b, nil}, + }, + ) require.NoError(t, gerr) }) }) @@ -379,13 +552,20 @@ func TestValidateVars(t *testing.T) { t.Run("Boolean Array", func(t *testing.T) { t.Run("Array with null", func(t *testing.T) { //nolint:staticcheck - q := gqlparser.MustLoadQuery(schema, `query foo($var: [Boolean]) { boolArrayArg(i: $var) }`) + q := gqlparser.MustLoadQuery( + schema, + `query foo($var: [Boolean]) { boolArrayArg(i: $var) }`, + ) a := true b := false - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []*bool{&a, &b, nil}, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []*bool{&a, &b, nil}, + }, + ) require.NoError(t, gerr) }) }) @@ -399,28 +579,48 @@ func TestValidateVarsWithRules(t *testing.T) { t.Run("undefined variable", func(t *testing.T) { t.Run("without default", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query($id: Int!) { intArg(i: $id) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query($id: Int!) { intArg(i: $id) }`, + nil, + ) _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.EqualError(t, gerr, "input: variable.id must be defined") }) t.Run("nil in required value", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query($id: Int!) { intArg(i: $id) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "id": nil, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query($id: Int!) { intArg(i: $id) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "id": nil, + }, + ) require.EqualError(t, gerr, "input: variable.id cannot be null") }) t.Run("with default", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query($id: Int! = 1) { intArg(i: $id) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query($id: Int! = 1) { intArg(i: $id) }`, + nil, + ) vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) require.EqualValues(t, 1, vars["id"]) }) t.Run("with union", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query($id: Int! = 1) { intArg(i: $id) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query($id: Int! = 1) { intArg(i: $id) }`, + nil, + ) vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) require.EqualValues(t, 1, vars["id"]) @@ -429,308 +629,548 @@ func TestValidateVarsWithRules(t *testing.T) { t.Run("input object", func(t *testing.T) { t.Run("non object", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": "hello", - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": "hello", + }, + ) require.EqualError(t, gerr, "input: variable.var must be a InputType, not a string") }) t.Run("defaults", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType! = {name: "foo"}) { structArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType! = {name: "foo"}) { structArg(i: $var) }`, + nil, + ) vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"name": "foo"}, vars["var"]) + require.EqualValues(t, map[string]any{"name": "foo"}, vars["var"]) }) t.Run("valid value", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + }, }, - }) + ) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"name": "foobar"}, vars["var"]) + require.EqualValues(t, map[string]any{"name": "foobar"}, vars["var"]) }) t.Run("null object field", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "nullName": nil, + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "nullName": nil, + }, }, - }) + ) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"name": "foobar", "nullName": nil}, vars["var"]) + require.EqualValues( + t, + map[string]any{"name": "foobar", "nullName": nil}, + vars["var"], + ) }) t.Run("missing required values", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{}, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{}, + }, + ) require.EqualError(t, gerr, "input: variable.var.name must be defined") }) t.Run("null required field", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": nil, + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": nil, + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var.name cannot be null") }) t.Run("null embedded input object", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foo", - "nullEmbedded": nil, + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foo", + "nullEmbedded": nil, + }, }, - }) + ) require.NoError(t, gerr) }) t.Run("unknown field", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "foobard": true, + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "foobard": true, + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var.foobard unknown field") }) t.Run("unknown __typefield", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "__typename": "InputType", + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "__typename": "InputType", + }, }, - }) + ) require.NoError(t, gerr) - require.EqualValues(t, map[string]interface{}{"__typename": "InputType", "name": "foobar"}, vars["var"]) + require.EqualValues( + t, + map[string]any{"__typename": "InputType", "name": "foobar"}, + vars["var"], + ) }) t.Run("enum input object", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "enum": "A", + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "enum": "A", + }, }, - }) + ) require.NoError(t, gerr) }) t.Run("unknown enum value input object", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: InputType!) { structArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{ - "name": "foobar", - "enum": "B", + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: InputType!) { structArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{ + "name": "foobar", + "enum": "B", + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var.enum B is not a valid Enum") }) }) t.Run("array", func(t *testing.T) { t.Run("non-null object value should be coerced to an array", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": map[string]interface{}{"name": "hello"}, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": map[string]any{"name": "hello"}, + }, + ) require.NoError(t, gerr) - require.EqualValues(t, []map[string]interface{}{{"name": "hello"}}, vars["var"]) + require.EqualValues(t, []map[string]any{{"name": "hello"}}, vars["var"]) }) t.Run("non-null int value should be coerced to an array", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [Int!]) { intArrayArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 5, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [Int!]) { intArrayArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 5, + }, + ) require.NoError(t, gerr) expected := []int{5} require.EqualValues(t, expected, vars["var"]) }) t.Run("non-null int deep value should be coerced to an array", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []map[string]interface{}{{"and": 5}}, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []map[string]any{{"and": 5}}, + }, + ) require.NoError(t, gerr) - expected := []map[string]interface{}{{"and": []int{5}}} + expected := []map[string]any{{"and": []int{5}}} require.EqualValues(t, expected, vars["var"]) }) t.Run("defaults", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`, + nil, + ) vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) - require.EqualValues(t, []interface{}{map[string]interface{}{ + require.EqualValues(t, []any{map[string]any{ "name": "foo", }}, vars["var"]) }) t.Run("valid value", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []interface{}{map[string]interface{}{ - "name": "foo", - }}, - }) - require.NoError(t, gerr) - require.EqualValues(t, []interface{}{map[string]interface{}{ + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []any{map[string]any{ + "name": "foo", + }}, + }, + ) + require.NoError(t, gerr) + require.EqualValues(t, []any{map[string]any{ "name": "foo", }}, vars["var"]) }) t.Run("null element value", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []interface{}{nil}, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []any{nil}, + }, + ) require.EqualError(t, gerr, "input: variable.var[0] cannot be null") }) t.Run("missing required values", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []interface{}{map[string]interface{}{}}, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [InputType!]) { arrayArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []any{map[string]any{}}, + }, + ) require.EqualError(t, gerr, "input: variable.var[0].name must be defined") }) t.Run("invalid variable paths", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var1: InputType!, $var2: InputType!) { a:structArg(i: $var1) b:structArg(i: $var2) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var1": map[string]interface{}{ - "name": "foobar", - }, - "var2": map[string]interface{}{ - "nullName": "foobar", + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var1: InputType!, $var2: InputType!) { a:structArg(i: $var1) b:structArg(i: $var2) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var1": map[string]any{ + "name": "foobar", + }, + "var2": map[string]any{ + "nullName": "foobar", + }, }, - }) + ) require.EqualError(t, gerr, "input: variable.var2.name must be defined") }) }) t.Run("Scalars", func(t *testing.T) { t.Run("String -> String", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: String!) { stringArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": "asdf", - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: String!) { stringArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": "asdf", + }, + ) require.NoError(t, gerr) require.EqualValues(t, "asdf", vars["var"]) }) t.Run("Int -> String", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: String!) { stringArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 1, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: String!) { stringArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 1, + }, + ) require.EqualError(t, gerr, "input: variable.var cannot use int as String") }) t.Run("Nil -> String", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: String!) { stringArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": nil, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: String!) { stringArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": nil, + }, + ) require.EqualError(t, gerr, "input: variable.var cannot be null") }) t.Run("Undefined -> String!", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: String!) { stringArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: String!) { stringArg(i: $var) }`, + nil, + ) _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.EqualError(t, gerr, "input: variable.var must be defined") }) t.Run("Undefined -> Int", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: Int) { optionalIntArg(i: $var) }`, + nil, + ) _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil) require.NoError(t, gerr) }) t.Run("Json Number -> Int", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 10, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: Int) { optionalIntArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 10, + }, + ) require.NoError(t, gerr) require.Equal(t, 10, vars["var"]) }) t.Run("Json Number -> Float", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: Float!) { floatArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": 10.2, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: Float!) { floatArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": 10.2, + }, + ) require.NoError(t, gerr) require.Equal(t, 10.2, vars["var"]) }) t.Run("Nil -> Int", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`, nil) - vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": nil, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: Int) { optionalIntArg(i: $var) }`, + nil, + ) + vars, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": nil, + }, + ) require.NoError(t, gerr) require.Nil(t, vars["var"]) }) t.Run("Bool -> Int", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: Int!) { intArg(i: $var) }`, nil) - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": true, - }) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: Int!) { intArg(i: $var) }`, + nil, + ) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": true, + }, + ) require.EqualError(t, gerr, "input: variable.var cannot use bool as Int") }) }) t.Run("Int Array", func(t *testing.T) { t.Run("Array with null", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [Int]) { intArrayArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [Int]) { intArrayArg(i: $var) }`, + nil, + ) a := 1 b := 2 - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []*int{&a, &b, nil}, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []*int{&a, &b, nil}, + }, + ) require.NoError(t, gerr) }) }) t.Run("String Array", func(t *testing.T) { t.Run("Array with null", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [String]) { stringArrayArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [String]) { stringArrayArg(i: $var) }`, + nil, + ) a := "1" b := "2" - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []*string{&a, &b, nil}, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []*string{&a, &b, nil}, + }, + ) require.NoError(t, gerr) }) }) t.Run("Boolean Array", func(t *testing.T) { t.Run("Array with null", func(t *testing.T) { - q := gqlparser.MustLoadQueryWithRules(schema, `query foo($var: [Boolean]) { boolArrayArg(i: $var) }`, nil) + q := gqlparser.MustLoadQueryWithRules( + schema, + `query foo($var: [Boolean]) { boolArrayArg(i: $var) }`, + nil, + ) a := true b := false - _, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{ - "var": []*bool{&a, &b, nil}, - }) + _, gerr := validator.VariableValues( + schema, + q.Operations.ForName(""), + map[string]any{ + "var": []*bool{&a, &b, nil}, + }, + ) require.NoError(t, gerr) }) }) diff --git a/validator/walk_test.go b/validator/walk_test.go index d92b8858..4b952832 100644 --- a/validator/walk_test.go +++ b/validator/walk_test.go @@ -4,12 +4,16 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/parser" ) func TestWalker(t *testing.T) { - schema, err := LoadSchema(Prelude, &ast.Source{Input: "type Query { name: String }\n schema { query: Query }"}) + schema, err := LoadSchema( + Prelude, + &ast.Source{Input: "type Query { name: String }\n schema { query: Query }"}, + ) require.NoError(t, err) query, err := parser.ParseQuery(&ast.Source{Input: "{ as: name }"}) require.NoError(t, err) @@ -31,7 +35,10 @@ func TestWalker(t *testing.T) { } func TestWalkInlineFragment(t *testing.T) { - schema, err := LoadSchema(Prelude, &ast.Source{Input: "type Query { name: String }\n schema { query: Query }"}) + schema, err := LoadSchema( + Prelude, + &ast.Source{Input: "type Query { name: String }\n schema { query: Query }"}, + ) require.NoError(t, err) query, err := parser.ParseQuery(&ast.Source{Input: "{ ... { name } }"}) require.NoError(t, err)