Repository: jensneuse/graphql-go-tools
Pull request #108 (2019-11-17 13:54:12)

normalization of type extensions
This PR will implement the normalization of the remaining type extensions.
It also contains a [commit](https://github.com/jensneuse/graphql-go-tools/commit/78fb9edba4ddf28f45661788f351e9f897fd99e0) which fixed some naming inconsistencies.


Patch:
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go
index 4d4b735b..33d7fc6b 100644
--- a/pkg/ast/ast.go
+++ b/pkg/ast/ast.go
@@ -456,6 +456,20 @@ func (d *Document) FieldDefinitionTypeNode(ref int) Node {
 	return d.Index.Nodes[xxhash.Sum64(typeName)]
 }
 
+func (d *Document) ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(interfaceTypeDefinitionRef, interfaceTypeExtensionRef int) {
+	if d.InterfaceTypeExtensionHasFieldDefinitions(interfaceTypeExtensionRef) {
+		d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].FieldsDefinition.Refs = append(d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].FieldsDefinition.Refs, d.InterfaceTypeExtensions[interfaceTypeExtensionRef].FieldsDefinition.Refs...)
+		d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].HasFieldDefinitions = true
+	}
+
+	if d.InterfaceTypeExtensionHasDirectives(interfaceTypeExtensionRef) {
+		d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].Directives.Refs = append(d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].Directives.Refs, d.InterfaceTypeExtensions[interfaceTypeExtensionRef].Directives.Refs...)
+		d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].HasDirectives = true
+	}
+
+	d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: interfaceTypeExtensionRef, Kind: NodeKindInterfaceTypeExtension})
+}
+
 func (d *Document) ExtendObjectTypeDefinitionByObjectTypeExtension(objectTypeDefinitionRef, objectTypeExtensionRef int) {
 	if d.ObjectTypeExtensionHasFieldDefinitions(objectTypeExtensionRef) {
 		d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs = append(d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, d.ObjectTypeExtensions[objectTypeExtensionRef].FieldsDefinition.Refs...)
@@ -470,6 +484,57 @@ func (d *Document) ExtendObjectTypeDefinitionByObjectTypeExtension(objectTypeDef
 	d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: objectTypeExtensionRef, Kind: NodeKindObjectTypeExtension})
 }
 
+func (d *Document) ExtendScalarTypeDefinitionByScalarTypeExtension(scalarTypeDefinitionRef, scalarTypeExtensionRef int) {
+	if d.ScalarTypeExtensionHasDirectives(scalarTypeExtensionRef) {
+		d.ScalarTypeDefinitions[scalarTypeDefinitionRef].Directives.Refs = append(d.ScalarTypeDefinitions[scalarTypeDefinitionRef].Directives.Refs, d.ScalarTypeExtensions[scalarTypeExtensionRef].Directives.Refs...)
+		d.ScalarTypeDefinitions[scalarTypeDefinitionRef].HasDirectives = true
+	}
+
+	d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: scalarTypeExtensionRef, Kind: NodeKindScalarTypeExtension})
+}
+
+func (d *Document) ExtendUnionTypeDefinitionByUnionTypeExtension(unionTypeDefinitionRef, unionTypeExtensionRef int) {
+	if d.UnionTypeExtensionHasDirectives(unionTypeExtensionRef) {
+		d.UnionTypeDefinitions[unionTypeDefinitionRef].Directives.Refs = append(d.UnionTypeDefinitions[unionTypeDefinitionRef].Directives.Refs, d.UnionTypeExtensions[unionTypeExtensionRef].Directives.Refs...)
+		d.UnionTypeDefinitions[unionTypeDefinitionRef].HasDirectives = true
+	}
+
+	if d.UnionTypeExtensionHasUnionMemberTypes(unionTypeExtensionRef) {
+		d.UnionTypeDefinitions[unionTypeDefinitionRef].UnionMemberTypes.Refs = append(d.UnionTypeDefinitions[unionTypeDefinitionRef].UnionMemberTypes.Refs, d.UnionTypeExtensions[unionTypeExtensionRef].UnionMemberTypes.Refs...)
+		d.UnionTypeDefinitions[unionTypeDefinitionRef].HasUnionMemberTypes = true
+	}
+
+	d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: unionTypeExtensionRef, Kind: NodeKindUnionTypeExtension})
+}
+
+func (d *Document) ExtendEnumTypeDefinitionByEnumTypeExtension(enumTypeDefinitionRef, enumTypeExtensionRef int) {
+	if d.EnumTypeExtensionHasDirectives(enumTypeExtensionRef) {
+		d.EnumTypeDefinitions[enumTypeDefinitionRef].Directives.Refs = append(d.EnumTypeDefinitions[enumTypeDefinitionRef].Directives.Refs, d.EnumTypeExtensions[enumTypeExtensionRef].Directives.Refs...)
+		d.EnumTypeDefinitions[enumTypeDefinitionRef].HasDirectives = true
+	}
+
+	if d.EnumTypeDefinitionHasEnumValueDefinition(enumTypeExtensionRef) {
+		d.EnumTypeDefinitions[enumTypeDefinitionRef].EnumValuesDefinition.Refs = append(d.EnumTypeDefinitions[enumTypeDefinitionRef].EnumValuesDefinition.Refs, d.EnumTypeExtensions[enumTypeExtensionRef].EnumValuesDefinition.Refs...)
+		d.EnumTypeDefinitions[enumTypeDefinitionRef].HasEnumValuesDefinition = true
+	}
+
+	d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: enumTypeExtensionRef, Kind: NodeKindEnumTypeExtension})
+}
+
+func (d *Document) ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(inputObjectTypeDefinitionRef, inputObjectTypeExtensionRef int) {
+	if d.InputObjectTypeExtensionHasDirectives(inputObjectTypeExtensionRef) {
+		d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].Directives.Refs = append(d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].Directives.Refs, d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].Directives.Refs...)
+		d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].HasDirectives = true
+	}
+
+	if d.InputObjectTypeExtensionHasInputFieldsDefinition(inputObjectTypeExtensionRef) {
+		d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].InputFieldsDefinition.Refs = append(d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].InputFieldsDefinition.Refs, d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].InputFieldsDefinition.Refs...)
+		d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].HasInputFieldsDefinition = true
+	}
+
+	d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: inputObjectTypeExtensionRef, Kind: NodeKindInputObjectTypeExtension})
+}
+
 func (d *Document) RemoveMergedTypeExtensions() {
 	for _, node := range d.Index.MergedTypeExtensions {
 		d.RemoveRootNode(node)
@@ -1846,13 +1911,21 @@ type DefaultValue struct {
 }
 
 type InputObjectTypeDefinition struct {
-	Description               Description        // optional, describes the input type
-	InputLiteral              position.Position  // input
-	Name                      ByteSliceReference // name of the input type
-	HasDirectives             bool
-	Directives                DirectiveList // optional, e.g. @foo
-	HasInputFieldsDefinitions bool
-	InputFieldsDefinition     InputValueDefinitionList // e.g. x:Float
+	Description              Description        // optional, describes the input type
+	InputLiteral             position.Position  // input
+	Name                     ByteSliceReference // name of the input type
+	HasDirectives            bool
+	Directives               DirectiveList // optional, e.g. @foo
+	HasInputFieldsDefinition bool
+	InputFieldsDefinition    InputValueDefinitionList // e.g. x:Float
+}
+
+func (d *Document) InputObjectTypeExtensionHasDirectives(ref int) bool {
+	return d.InputObjectTypeExtensions[ref].HasDirectives
+}
+
+func (d *Document) InputObjectTypeExtensionHasInputFieldsDefinition(ref int) bool {
+	return d.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition
 }
 
 func (d *Document) InputObjectTypeDefinitionNameBytes(ref int) ByteSlice {
@@ -1942,6 +2015,14 @@ type InterfaceTypeDefinition struct {
 	FieldsDefinition    FieldDefinitionList // optional, e.g. { name: String }
 }
 
+func (d *Document) InterfaceTypeExtensionHasDirectives(ref int) bool {
+	return d.InterfaceTypeExtensions[ref].HasDirectives
+}
+
+func (d *Document) InterfaceTypeExtensionHasFieldDefinitions(ref int) bool {
+	return d.InterfaceTypeExtensions[ref].HasFieldDefinitions
+}
+
 func (d *Document) InterfaceTypeDefinitionNameBytes(ref int) ByteSlice {
 	return d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Name)
 }
@@ -2046,6 +2127,10 @@ func (d *Document) UnionTypeExtensionHasDirectives(ref int) bool {
 	return d.UnionTypeExtensions[ref].HasDirectives
 }
 
+func (d *Document) UnionTypeExtensionHasUnionMemberTypes(ref int) bool {
+	return d.UnionTypeExtensions[ref].HasUnionMemberTypes
+}
+
 func (d *Document) UnionTypeExtensionNameBytes(ref int) ByteSlice {
 	return d.Input.ByteSlice(d.UnionTypeExtensions[ref].Name)
 }
@@ -2063,19 +2148,23 @@ func (d *Document) UnionTypeExtensionNameString(ref int) string {
 //  WEST
 //}
 type EnumTypeDefinition struct {
-	Description              Description        // optional, describes enum
-	EnumLiteral              position.Position  // enum
-	Name                     ByteSliceReference // e.g. Direction
-	HasDirectives            bool
-	Directives               DirectiveList // optional, e.g. @foo
-	HasEnumValuesDefinitions bool
-	EnumValuesDefinition     EnumValueDefinitionList // optional, e.g. { NORTH EAST }
+	Description             Description        // optional, describes enum
+	EnumLiteral             position.Position  // enum
+	Name                    ByteSliceReference // e.g. Direction
+	HasDirectives           bool
+	Directives              DirectiveList // optional, e.g. @foo
+	HasEnumValuesDefinition bool
+	EnumValuesDefinition    EnumValueDefinitionList // optional, e.g. { NORTH EAST }
 }
 
 func (d *Document) EnumTypeDefinitionHasDirectives(ref int) bool {
 	return d.EnumTypeDefinitions[ref].HasDirectives
 }
 
+func (d *Document) EnumTypeDefinitionHasEnumValueDefinition(ref int) bool {
+	return d.EnumTypeDefinitions[ref].HasEnumValuesDefinition
+}
+
 func (d *Document) EnumTypeDefinitionNameBytes(ref int) ByteSlice {
 	return d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Name)
 }
diff --git a/pkg/astnormalization/enum_type_extending.go b/pkg/astnormalization/enum_type_extending.go
new file mode 100644
index 00000000..784b5e62
--- /dev/null
+++ b/pkg/astnormalization/enum_type_extending.go
@@ -0,0 +1,38 @@
+package astnormalization
+
+import (
+	"github.com/cespare/xxhash"
+	"github.com/jensneuse/graphql-go-tools/pkg/ast"
+	"github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
+)
+
+func extendEnumTypeDefinition(walker *astvisitor.Walker) {
+	visitor := extendEnumTypeDefinitionVisitor{
+		Walker: walker,
+	}
+	walker.RegisterEnterDocumentVisitor(&visitor)
+	walker.RegisterEnterEnumTypeExtensionVisitor(&visitor)
+}
+
+type extendEnumTypeDefinitionVisitor struct {
+	*astvisitor.Walker
+	operation *ast.Document
+}
+
+func (e *extendEnumTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
+	e.operation = operation
+}
+
+func (e *extendEnumTypeDefinitionVisitor) EnterEnumTypeExtension(ref int) {
+
+	baseNode, exists := e.operation.Index.Nodes[xxhash.Sum64(e.operation.EnumTypeExtensionNameBytes(ref))]
+	if !exists {
+		return
+	}
+
+	if baseNode.Kind != ast.NodeKindEnumTypeDefinition {
+		return
+	}
+
+	e.operation.ExtendEnumTypeDefinitionByEnumTypeExtension(baseNode.Ref, ref)
+}
diff --git a/pkg/astnormalization/input_object_type_extending.go b/pkg/astnormalization/input_object_type_extending.go
new file mode 100644
index 00000000..654b2203
--- /dev/null
+++ b/pkg/astnormalization/input_object_type_extending.go
@@ -0,0 +1,38 @@
+package astnormalization
+
+import (
+	"github.com/cespare/xxhash"
+	"github.com/jensneuse/graphql-go-tools/pkg/ast"
+	"github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
+)
+
+func extendInputObjectTypeDefinition(walker *astvisitor.Walker) {
+	visitor := extendInputObjectTypeDefinitionVisitor{
+		Walker: walker,
+	}
+	walker.RegisterEnterDocumentVisitor(&visitor)
+	walker.RegisterEnterInputObjectTypeExtensionVisitor(&visitor)
+}
+
+type extendInputObjectTypeDefinitionVisitor struct {
+	*astvisitor.Walker
+	operation *ast.Document
+}
+
+func (e *extendInputObjectTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
+	e.operation = operation
+}
+
+func (e *extendInputObjectTypeDefinitionVisitor) EnterInputObjectTypeExtension(ref int) {
+
+	baseNode, exists := e.operation.Index.Nodes[xxhash.Sum64(e.operation.InputObjectTypeExtensionNameBytes(ref))]
+	if !exists {
+		return
+	}
+
+	if baseNode.Kind != ast.NodeKindInputObjectTypeDefinition {
+		return
+	}
+
+	e.operation.ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(baseNode.Ref, ref)
+}
diff --git a/pkg/astnormalization/interface_type_extending.go b/pkg/astnormalization/interface_type_extending.go
new file mode 100644
index 00000000..afa16688
--- /dev/null
+++ b/pkg/astnormalization/interface_type_extending.go
@@ -0,0 +1,38 @@
+package astnormalization
+
+import (
+	"github.com/cespare/xxhash"
+	"github.com/jensneuse/graphql-go-tools/pkg/ast"
+	"github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
+)
+
+func extendInterfaceTypeDefinition(walker *astvisitor.Walker) {
+	visitor := extendInterfaceTypeDefinitionVisitor{
+		Walker: walker,
+	}
+	walker.RegisterEnterDocumentVisitor(&visitor)
+	walker.RegisterEnterInterfaceTypeExtensionVisitor(&visitor)
+}
+
+type extendInterfaceTypeDefinitionVisitor struct {
+	*astvisitor.Walker
+	operation *ast.Document
+}
+
+func (e *extendInterfaceTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
+	e.operation = operation
+}
+
+func (e *extendInterfaceTypeDefinitionVisitor) EnterInterfaceTypeExtension(ref int) {
+
+	baseNode, exists := e.operation.Index.Nodes[xxhash.Sum64(e.operation.InterfaceTypeExtensionNameBytes(ref))]
+	if !exists {
+		return
+	}
+
+	if baseNode.Kind != ast.NodeKindInterfaceTypeDefinition {
+		return
+	}
+
+	e.operation.ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(baseNode.Ref, ref)
+}
diff --git a/pkg/astnormalization/scalar_type_extending.go b/pkg/astnormalization/scalar_type_extending.go
new file mode 100644
index 00000000..df136f94
--- /dev/null
+++ b/pkg/astnormalization/scalar_type_extending.go
@@ -0,0 +1,38 @@
+package astnormalization
+
+import (
+	"github.com/cespare/xxhash"
+	"github.com/jensneuse/graphql-go-tools/pkg/ast"
+	"github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
+)
+
+func extendScalarTypeDefinition(walker *astvisitor.Walker) {
+	visitor := extendScalarTypeDefinitionVisitor{
+		Walker: walker,
+	}
+	walker.RegisterEnterDocumentVisitor(&visitor)
+	walker.RegisterEnterScalarTypeExtensionVisitor(&visitor)
+}
+
+type extendScalarTypeDefinitionVisitor struct {
+	*astvisitor.Walker
+	operation *ast.Document
+}
+
+func (e *extendScalarTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
+	e.operation = operation
+}
+
+func (e *extendScalarTypeDefinitionVisitor) EnterScalarTypeExtension(ref int) {
+
+	baseNode, exists := e.operation.Index.Nodes[xxhash.Sum64(e.operation.ScalarTypeExtensionNameBytes(ref))]
+	if !exists {
+		return
+	}
+
+	if baseNode.Kind != ast.NodeKindScalarTypeDefinition {
+		return
+	}
+
+	e.operation.ExtendScalarTypeDefinitionByScalarTypeExtension(baseNode.Ref, ref)
+}
diff --git a/pkg/astnormalization/union_type_extending.go b/pkg/astnormalization/union_type_extending.go
new file mode 100644
index 00000000..15bbfb9f
--- /dev/null
+++ b/pkg/astnormalization/union_type_extending.go
@@ -0,0 +1,38 @@
+package astnormalization
+
+import (
+	"github.com/cespare/xxhash"
+	"github.com/jensneuse/graphql-go-tools/pkg/ast"
+	"github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
+)
+
+func extendUnionTypeDefinition(walker *astvisitor.Walker) {
+	visitor := extendUnionTypeDefinitionVisitor{
+		Walker: walker,
+	}
+	walker.RegisterEnterDocumentVisitor(&visitor)
+	walker.RegisterEnterUnionTypeExtensionVisitor(&visitor)
+}
+
+type extendUnionTypeDefinitionVisitor struct {
+	*astvisitor.Walker
+	operation *ast.Document
+}
+
+func (e *extendUnionTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
+	e.operation = operation
+}
+
+func (e *extendUnionTypeDefinitionVisitor) EnterUnionTypeExtension(ref int) {
+
+	baseNode, exists := e.operation.Index.Nodes[xxhash.Sum64(e.operation.UnionTypeExtensionNameBytes(ref))]
+	if !exists {
+		return
+	}
+
+	if baseNode.Kind != ast.NodeKindUnionTypeDefinition {
+		return
+	}
+
+	e.operation.ExtendUnionTypeDefinitionByUnionTypeExtension(baseNode.Ref, ref)
+}
diff --git a/pkg/astparser/parser.go b/pkg/astparser/parser.go
index c437b694..8ca95ee2 100644
--- a/pkg/astparser/parser.go
+++ b/pkg/astparser/parser.go
@@ -1133,7 +1133,7 @@ func (p *Parser) parseInputObjectTypeDefinition(description *ast.Description) {
 	}
 	if p.peekEquals(keyword.LBRACE) {
 		inputObjectTypeDefinition.InputFieldsDefinition = p.parseInputValueDefinitionList(keyword.RBRACE)
-		inputObjectTypeDefinition.HasInputFieldsDefinitions = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0
+		inputObjectTypeDefinition.HasInputFieldsDefinition = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0
 	}
 	p.document.InputObjectTypeDefinitions = append(p.document.InputObjectTypeDefinitions, inputObjectTypeDefinition)
 	ref := len(p.document.InputObjectTypeDefinitions) - 1
@@ -1292,7 +1292,7 @@ func (p *Parser) parseEnumTypeDefinition(description *ast.Description) {
 	}
 	if p.peekEquals(keyword.LBRACE) {
 		enumTypeDefinition.EnumValuesDefinition = p.parseEnumValueDefinitionList()
-		enumTypeDefinition.HasEnumValuesDefinitions = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0
+		enumTypeDefinition.HasEnumValuesDefinition = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0
 	}
 	p.document.EnumTypeDefinitions = append(p.document.EnumTypeDefinitions, enumTypeDefinition)
 	ref := len(p.document.EnumTypeDefinitions) - 1
@@ -1876,7 +1876,7 @@ func (p *Parser) parseEnumTypeExtension(extend position.Position) {
 	}
 	if p.peekEquals(keyword.LBRACE) {
 		enumTypeDefinition.EnumValuesDefinition = p.parseEnumValueDefinitionList()
-		enumTypeDefinition.HasEnumValuesDefinitions = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0
+		enumTypeDefinition.HasEnumValuesDefinition = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0
 	}
 	enumTypeExtension := ast.EnumTypeExtension{
 		ExtendLiteral:      extend,
@@ -1897,7 +1897,7 @@ func (p *Parser) parseInputObjectTypeExtension(extend position.Position) {
 	}
 	if p.peekEquals(keyword.LBRACE) {
 		inputObjectTypeDefinition.InputFieldsDefinition = p.parseInputValueDefinitionList(keyword.RBRACE)
-		inputObjectTypeDefinition.HasInputFieldsDefinitions = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0
+		inputObjectTypeDefinition.HasInputFieldsDefinition = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0
 	}
 	inputObjectTypeExtension := ast.InputObjectTypeExtension{
 		ExtendLiteral:             extend,
diff --git a/pkg/astvisitor/simplevisitor.go b/pkg/astvisitor/simplevisitor.go
index f0a11218..8fef8411 100644
--- a/pkg/astvisitor/simplevisitor.go
+++ b/pkg/astvisitor/simplevisitor.go
@@ -575,7 +575,7 @@ func (w *SimpleWalker) walkEnumTypeDefinition(ref int) {
 		}
 	}
 
-	if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinitions {
+	if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinition {
 		for _, i := range w.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs {
 			w.walkEnumValueDefinition(i)
 		}
@@ -601,7 +601,7 @@ func (w *SimpleWalker) walkEnumTypeExtension(ref int) {
 		}
 	}
 
-	if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinitions {
+	if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinition {
 		for _, i := range w.document.EnumTypeExtensions[ref].EnumValuesDefinition.Refs {
 			w.walkEnumValueDefinition(i)
 		}
@@ -647,7 +647,7 @@ func (w *SimpleWalker) walkInputObjectTypeDefinition(ref int) {
 		}
 	}
 
-	if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinitions {
+	if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition {
 		for _, i := range w.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs {
 			w.walkInputValueDefinition(i)
 		}
@@ -673,7 +673,7 @@ func (w *SimpleWalker) walkInputObjectTypeExtension(ref int) {
 		}
 	}
 
-	if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinitions {
+	if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinition {
 		for _, i := range w.document.InputObjectTypeExtensions[ref].InputFieldsDefinition.Refs {
 			w.walkInputValueDefinition(i)
 		}
diff --git a/pkg/astvisitor/visitor.go b/pkg/astvisitor/visitor.go
index 762a089a..b1912f36 100644
--- a/pkg/astvisitor/visitor.go
+++ b/pkg/astvisitor/visitor.go
@@ -2448,7 +2448,7 @@ func (w *Walker) walkEnumTypeDefinition(ref int) {
 		}
 	}
 
-	if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinitions {
+	if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinition {
 		for _, i := range w.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs {
 			w.walkEnumValueDefinition(i)
 			if w.stop {
@@ -2513,7 +2513,7 @@ func (w *Walker) walkEnumTypeExtension(ref int) {
 		}
 	}
 
-	if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinitions {
+	if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinition {
 		for _, i := range w.document.EnumTypeExtensions[ref].EnumValuesDefinition.Refs {
 			w.walkEnumValueDefinition(i)
 			if w.stop {
@@ -2634,7 +2634,7 @@ func (w *Walker) walkInputObjectTypeDefinition(ref int) {
 		}
 	}
 
-	if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinitions {
+	if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition {
 		for _, i := range w.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs {
 			w.walkInputValueDefinition(i)
 			if w.stop {
@@ -2699,7 +2699,7 @@ func (w *Walker) walkInputObjectTypeExtension(ref int) {
 		}
 	}
 
-	if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinitions {
+	if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinition {
 		for _, i := range w.document.InputObjectTypeExtensions[ref].InputFieldsDefinition.Refs {
 			w.walkInputValueDefinition(i)
 			if w.stop {


Test patch:
diff --git a/pkg/astnormalization/enum_type_extending_test.go b/pkg/astnormalization/enum_type_extending_test.go
new file mode 100644
index 00000000..173520e9
--- /dev/null
+++ b/pkg/astnormalization/enum_type_extending_test.go
@@ -0,0 +1,33 @@
+package astnormalization
+
+import "testing"
+
+func TestExtendEnumType(t *testing.T) {
+	t.Run("extend enum type by directive", func(t *testing.T) {
+		run(extendEnumTypeDefinition, testDefinition, `
+					enum Countries {DE ES NL}
+					extend enum Countries @deprecated(reason: "some reason")
+					 `, `
+					enum Countries @deprecated(reason: "some reason") {DE ES NL} 
+					extend enum Countries @deprecated(reason: "some reason")
+					`)
+	})
+	t.Run("extend enum type by enum values", func(t *testing.T) {
+		run(extendEnumTypeDefinition, testDefinition, `
+					enum Countries {DE ES NL}
+					extend enum Countries {EN}
+					 `, `
+					enum Countries {DE ES NL EN}
+					extend enum Countries {EN}
+					`)
+	})
+	t.Run("extend enum type by multiple enum values and directives", func(t *testing.T) {
+		run(extendEnumTypeDefinition, testDefinition, `
+					enum Countries {DE ES NL}
+					extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT}
+					 `, `
+					enum Countries @deprecated(reason: "some reason") @skip(if: false) {DE ES NL EN IT}
+					extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT}
+					`)
+	})
+}
diff --git a/pkg/astnormalization/input_object_type_extending_test.go b/pkg/astnormalization/input_object_type_extending_test.go
new file mode 100644
index 00000000..01ab96f9
--- /dev/null
+++ b/pkg/astnormalization/input_object_type_extending_test.go
@@ -0,0 +1,33 @@
+package astnormalization
+
+import "testing"
+
+func TestExtendInputObjectType(t *testing.T) {
+	t.Run("extend input object type by directive", func(t *testing.T) {
+		run(extendInputObjectTypeDefinition, testDefinition, `
+					input DogSize {width: Float height: Float}
+					extend input DogSize @deprecated(reason: "some reason")
+					 `, `
+					input DogSize @deprecated(reason: "some reason") {width: Float height: Float}
+					extend input DogSize @deprecated(reason: "some reason")
+					`)
+	})
+	t.Run("extend input object type by input fields definition", func(t *testing.T) {
+		run(extendInputObjectTypeDefinition, testDefinition, `
+					input DogSize {width: Float height: Float}
+					extend input DogSize {breadth: Float}
+					 `, `
+					input DogSize {width: Float height: Float, breadth: Float}
+					extend input DogSize {breadth: Float}
+					`)
+	})
+	t.Run("extend input object type by multiple input fields definition and directives", func(t *testing.T) {
+		run(extendInputObjectTypeDefinition, testDefinition, `
+					input DogSize {width: Float height: Float}
+					extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float}
+					 `, `
+					input DogSize @deprecated(reason: "some reason") @skip(if: false) {width: Float height: Float breadth: Float weight: Float}
+					extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float}
+					`)
+	})
+}
diff --git a/pkg/astnormalization/interface_type_extending_test.go b/pkg/astnormalization/interface_type_extending_test.go
new file mode 100644
index 00000000..2e847565
--- /dev/null
+++ b/pkg/astnormalization/interface_type_extending_test.go
@@ -0,0 +1,58 @@
+package astnormalization
+
+import "testing"
+
+func TestExtendInterfaceType(t *testing.T) {
+	t.Run("extend simple interface type by field", func(t *testing.T) {
+		run(extendInterfaceTypeDefinition, testDefinition, `
+					interface Mammal {
+						name: String
+					}
+					extend interface Mammal {
+						furType: String
+					}
+					 `, `
+					interface Mammal {
+						name: String
+						furType: String
+					}
+					extend interface Mammal {
+						furType: String
+					}
+					`)
+	})
+	t.Run("extend simple interface type by directive", func(t *testing.T) {
+		run(extendInterfaceTypeDefinition, testDefinition, `
+					interface Mammal {
+						name: String
+					}
+					extend interface Mammal @deprecated(reason: "some reason")
+					 `, `
+					interface Mammal @deprecated(reason: "some reason") {
+						name: String
+					}
+					extend interface Mammal @deprecated(reason: "some reason")
+					`)
+	})
+	t.Run("extend interface type by complex extends", func(t *testing.T) {
+		run(extendInterfaceTypeDefinition, testDefinition, `
+					interface Mammal {
+						name: String
+					}
+					extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) {
+						furType: String
+						age: Int
+					}
+					 `, `
+					interface Mammal @deprecated(reason: "some reason") @skip(if: false) {
+						name: String
+						furType: String
+						age: Int
+					}
+					extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) {
+						furType: String
+						age: Int
+					}
+					`)
+	})
+}
diff --git a/pkg/astnormalization/object_type_extending_test.go b/pkg/astnormalization/object_type_extending_test.go
index 037c35fe..658881c5 100644
--- a/pkg/astnormalization/object_type_extending_test.go
+++ b/pkg/astnormalization/object_type_extending_test.go
@@ -3,7 +3,7 @@ package astnormalization
 import "testing"
 
 func TestExtendObjectType(t *testing.T) {
-	t.Run("extend simple object type by field", func(t *testing.T) {
+	t.Run("extend object type by field", func(t *testing.T) {
 		run(extendObjectTypeDefinition, testDefinition, `
 					type Dog {
 						name: String
@@ -21,7 +21,7 @@ func TestExtendObjectType(t *testing.T) {
 					}
 					`)
 	})
-	t.Run("extend simple object type by directive", func(t *testing.T) {
+	t.Run("extend object type by directive", func(t *testing.T) {
 		run(extendObjectTypeDefinition, testDefinition, `
 					type Cat {
 						name: String
diff --git a/pkg/astnormalization/remove_type_extensions_test.go b/pkg/astnormalization/remove_type_extensions_test.go
index 5fca0ac4..2919d31b 100644
--- a/pkg/astnormalization/remove_type_extensions_test.go
+++ b/pkg/astnormalization/remove_type_extensions_test.go
@@ -52,4 +52,63 @@ func TestRemoveTypeExtensions(t *testing.T) {
 			extendObjectTypeDefinition,
 			removeMergedTypeExtensions)
 	})
+	t.Run("remove scalar type extensions", func(t *testing.T) {
+		runMany(testDefinition, `
+					scalar Coordinates
+					extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false)
+					 `, `
+					scalar Coordinates @deprecated(reason: "some reason") @skip(if: false)
+					`,
+			extendScalarTypeDefinition,
+			removeMergedTypeExtensions)
+	})
+	t.Run("remove enum type extensions", func(t *testing.T) {
+		runMany(testDefinition, `
+					enum Countries {DE ES NL}
+					extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT}
+					 `, `
+					enum Countries @deprecated(reason: "some reason") @skip(if: false) {DE ES NL EN IT}
+					`,
+			extendEnumTypeDefinition,
+			removeMergedTypeExtensions)
+	})
+	t.Run("remove union type extensions", func(t *testing.T) {
+		runMany(testDefinition, `
+					union Mammal
+					extend union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog
+					 `, `
+					union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog
+					`,
+			extendUnionTypeDefinition,
+			removeMergedTypeExtensions)
+	})
+	t.Run("remove input object type extensions", func(t *testing.T) {
+		runMany(testDefinition, `
+					input DogSize {width: Float height: Float}
+					extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float}
+					 `, `
+					input DogSize @deprecated(reason: "some reason") @skip(if: false) {width: Float height: Float breadth: Float weight: Float}
+					`,
+			extendInputObjectTypeDefinition,
+			removeMergedTypeExtensions)
+	})
+	t.Run("remove interface type extensions", func(t *testing.T) {
+		runMany(testDefinition, `
+					interface Mammal {
+						name: String
+					}
+					extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) {
+						furType: String
+						age: Int
+					}
+					 `, `
+					interface Mammal @deprecated(reason: "some reason") @skip(if: false) {
+						name: String
+						furType: String
+						age: Int
+					}
+					`,
+			extendInterfaceTypeDefinition,
+			removeMergedTypeExtensions)
+	})
 }
diff --git a/pkg/astnormalization/scalar_type_extending_test.go b/pkg/astnormalization/scalar_type_extending_test.go
new file mode 100644
index 00000000..11e72624
--- /dev/null
+++ b/pkg/astnormalization/scalar_type_extending_test.go
@@ -0,0 +1,24 @@
+package astnormalization
+
+import "testing"
+
+func TestExtendScalarType(t *testing.T) {
+	t.Run("extend simple scalar type", func(t *testing.T) {
+		run(extendScalarTypeDefinition, testDefinition, `
+					scalar Coordinates
+					extend scalar Coordinates @deprecated(reason: "some reason")
+					 `, `
+					scalar Coordinates @deprecated(reason: "some reason")
+					extend scalar Coordinates @deprecated(reason: "some reason")
+					`)
+	})
+	t.Run("extend scalar type by multiple directives", func(t *testing.T) {
+		run(extendScalarTypeDefinition, testDefinition, `
+					scalar Coordinates
+					extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false)
+					 `, `
+					scalar Coordinates @deprecated(reason: "some reason") @skip(if: false)
+					extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false)
+					`)
+	})
+}
diff --git a/pkg/astnormalization/union_type_extending_test.go b/pkg/astnormalization/union_type_extending_test.go
new file mode 100644
index 00000000..52b48378
--- /dev/null
+++ b/pkg/astnormalization/union_type_extending_test.go
@@ -0,0 +1,51 @@
+package astnormalization
+
+import "testing"
+
+func TestExtendUnionType(t *testing.T) {
+	t.Run("extend union type by directive", func(t *testing.T) {
+		run(extendUnionTypeDefinition, testDefinition, `
+					union Mammal
+					extend union Mammal @deprecated(reason: "some reason")
+					 `, `
+					union Mammal @deprecated(reason: "some reason")
+					extend union Mammal @deprecated(reason: "some reason")
+					`)
+	})
+	t.Run("extend union type by UnionMemberType", func(t *testing.T) {
+		run(extendUnionTypeDefinition, testDefinition, `
+					union Mammal
+					extend union Mammal = Cat
+					 `, `
+					union Mammal = Cat
+					extend union Mammal = Cat
+					`)
+	})
+	t.Run("extend union type by multiple UnionMemberTypes", func(t *testing.T) {
+		run(extendUnionTypeDefinition, testDefinition, `
+					union Mammal
+					extend union Mammal = Cat | Dog
+					 `, `
+					union Mammal = Cat | Dog
+					extend union Mammal = Cat | Dog
+					`)
+	})
+	t.Run("extend union by multiple directives and union members", func(t *testing.T) {
+		run(extendUnionTypeDefinition, testDefinition, `
+					union Mammal
+					extend union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog
+					 `, `
+					union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog
+					extend union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog
+					`)
+	})
+	t.Run("extend union type which already has union member", func(t *testing.T) {
+		run(extendUnionTypeDefinition, testDefinition, `
+					union Mammal = Cat
+					extend union Mammal @deprecated(reason: "some reason") = Dog
+					 `, `
+					union Mammal @deprecated(reason: "some reason") = Cat | Dog
+					extend union Mammal @deprecated(reason: "some reason") = Dog
+					`)
+	})
+}