-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TT-5279] Subgraphs with empty type bodies are invalidated before ext…
…ension could occur [changelog] internal: Added visitor to return an error if a type has an empty body.
- Loading branch information
David Stutt
committed
May 19, 2022
1 parent
9295cc4
commit 6820fd5
Showing
6 changed files
with
153 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package astnormalization | ||
|
||
import ( | ||
"github.com/jensneuse/graphql-go-tools/pkg/ast" | ||
"github.com/jensneuse/graphql-go-tools/pkg/astvisitor" | ||
"github.com/jensneuse/graphql-go-tools/pkg/operationreport" | ||
) | ||
|
||
type validateTypeBody struct { | ||
*astvisitor.Walker | ||
operation *ast.Document | ||
lastEnumRef int | ||
lastInputRef int | ||
lastInterfaceRef int | ||
lastObjectRef int | ||
} | ||
|
||
func validateTypeBodyVisitor(walker *astvisitor.Walker) { | ||
visitor := validateTypeBody{ | ||
Walker: walker, | ||
operation: nil, | ||
lastEnumRef: ast.InvalidRef, | ||
lastInputRef: ast.InvalidRef, | ||
lastInterfaceRef: ast.InvalidRef, | ||
lastObjectRef: ast.InvalidRef, | ||
} | ||
walker.RegisterEnterDocumentVisitor(&visitor) | ||
walker.RegisterEnterEnumTypeDefinitionVisitor(&visitor) | ||
walker.RegisterEnterInputObjectTypeDefinitionVisitor(&visitor) | ||
walker.RegisterEnterInterfaceTypeDefinitionVisitor(&visitor) | ||
walker.RegisterEnterObjectTypeDefinitionVisitor(&visitor) | ||
} | ||
|
||
func (v *validateTypeBody) EnterDocument(operation, _ *ast.Document) { | ||
v.operation = operation | ||
} | ||
|
||
func (v validateTypeBody) EnterEnumTypeDefinition(ref int) { | ||
if v.lastEnumRef >= ref { | ||
return | ||
} | ||
operation := v.operation | ||
if !operation.EnumTypeDefinitions[ref].HasEnumValuesDefinition { | ||
v.Walker.StopWithExternalErr(operationreport.ErrTypeBodyMustNotBeEmpty("enum", operation.EnumTypeDefinitionNameString(ref))) | ||
} | ||
v.lastEnumRef = ref | ||
} | ||
|
||
func (v validateTypeBody) EnterInputObjectTypeDefinition(ref int) { | ||
if v.lastInputRef >= ref { | ||
return | ||
} | ||
operation := v.operation | ||
if !operation.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition { | ||
v.Walker.StopWithExternalErr(operationreport.ErrTypeBodyMustNotBeEmpty("input", operation.InputObjectTypeDefinitionNameString(ref))) | ||
} | ||
v.lastInputRef = ref | ||
} | ||
|
||
func (v validateTypeBody) EnterInterfaceTypeDefinition(ref int) { | ||
if v.lastInterfaceRef >= ref { | ||
return | ||
} | ||
operation := v.operation | ||
if !operation.InterfaceTypeDefinitions[ref].HasFieldDefinitions { | ||
v.Walker.StopWithExternalErr(operationreport.ErrTypeBodyMustNotBeEmpty("interface", operation.InterfaceTypeDefinitionNameString(ref))) | ||
} | ||
v.lastInterfaceRef = ref | ||
} | ||
|
||
func (v validateTypeBody) EnterObjectTypeDefinition(ref int) { | ||
if v.lastObjectRef >= ref { | ||
return | ||
} | ||
operation := v.operation | ||
if !operation.ObjectTypeDefinitions[ref].HasFieldDefinitions { | ||
v.Walker.StopWithExternalErr(operationreport.ErrTypeBodyMustNotBeEmpty("object", operation.ObjectTypeDefinitionNameString(ref))) | ||
} | ||
v.lastObjectRef = ref | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package astnormalization | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
func TestCheckUnresolvedExtensionOrphans(t *testing.T) { | ||
t.Run("Empty enum body returns an error", func(t *testing.T) { | ||
runAndExpectError(t, validateTypeBodyVisitor, testDefinition, ` | ||
enum Badges { | ||
} | ||
`, EmptyTypeBodyErrorMessage("enum", "Badges")) | ||
}) | ||
|
||
t.Run("Empty input body returns an error", func(t *testing.T) { | ||
runAndExpectError(t, validateTypeBodyVisitor, testDefinition, ` | ||
input Badges { | ||
} | ||
`, EmptyTypeBodyErrorMessage("input", "Badges")) | ||
}) | ||
|
||
t.Run("Empty interface body returns an error", func(t *testing.T) { | ||
runAndExpectError(t, validateTypeBodyVisitor, testDefinition, ` | ||
interface Badges { | ||
} | ||
`, EmptyTypeBodyErrorMessage("interface", "Badges")) | ||
}) | ||
|
||
t.Run("Empty object body returns an error", func(t *testing.T) { | ||
runAndExpectError(t, validateTypeBodyVisitor, testDefinition, ` | ||
type Badges { | ||
} | ||
`, EmptyTypeBodyErrorMessage("object", "Badges")) | ||
}) | ||
} | ||
|
||
func EmptyTypeBodyErrorMessage(definitionType, typeName string) string { | ||
return fmt.Sprintf("the %s named '%s' is invalid due to an empty body", definitionType, typeName) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters