# -*- coding: utf-8 -*-
"""
Visitors provide abstractions for traversing and transforming a GraphQL AST.
"""
import functools
from typing import Optional, TypeVar, Union
from .._utils import classdispatch, map_and_filter
from ..exc import GraphQLError
from . import ast as _ast
T = TypeVar("T")
N = TypeVar("N", bound=_ast.Node)
S = TypeVar("S", bound=_ast.Selection)
__all__ = (
"SkipNode",
"ASTVisitor",
"DispatchingVisitor",
"ChainedVisitor",
)
[docs]class SkipNode(GraphQLError):
"""
Raise this to short-circuit traversal and ignore the node and all its children.
"""
def _visit_method(method):
@functools.wraps(method)
def wrapper(inst, node):
try:
node = inst.enter(node)
except SkipNode:
return node
if node is not None:
node = method(inst, node)
if node is not None:
inst.leave(node)
return node
return wrapper
[docs]class ASTVisitor:
"""
Base visitor class encoding AST traversal and transforms behaviors.
"""
[docs] def enter(self, node: N) -> Optional[N]:
"""
Process an AST node.
Implement this for the main visiting behavior (i.e. before a node's
children have been visited).
Return ``None`` to delete the node from it's parent context or raise
:class:`SkipNode` to prevent any further processing (children do not get
visited and `leave` doesn't get called for that node).
"""
return node
[docs] def leave(self, node: N) -> None:
"""
Cleanup after processing an AST node and its children.
Implement this if you need behavior to run after a node's children
have been visited.
This is called with the corresponding value returned by :meth:`enter`.
In case you modify the node, this will be called on the modified node.
This doesn't run if :meth:`enter` returned ``None`` or raised
:class:`SkipNode`.
"""
pass
[docs] def visit(self, node: N) -> Optional[N]:
"""
Apply visitor's behavior to a given node.
Warning:
Transformations are applied inline. If you rely on node identity
in your tooling, you should use `copy.deepcopy` or analogous before
calling this.
Warning:
In general you should not override this method as this is where
traversal of a node's children and orchestration around :meth:`enter`
and :meth:`leave` is encoded.
"""
return classdispatch(
node,
{
_ast.Document: self._visit_document,
_ast.OperationDefinition: self._visit_operation_definition,
_ast.VariableDefinition: self._visit_variable_definition,
_ast.Variable: self._visit_variable,
_ast.SelectionSet: self._visit_selection_set,
_ast.Field: self._visit_field,
_ast.Argument: self._visit_argument,
_ast.FragmentSpread: self._visit_fragment_spread,
_ast.InlineFragment: self._visit_inline_fragment,
_ast.FragmentDefinition: self._visit_fragment_definition,
_ast.IntValue: self._visit_value,
_ast.FloatValue: self._visit_value,
_ast.BooleanValue: self._visit_value,
_ast.NullValue: self._visit_value,
_ast.EnumValue: self._visit_value,
_ast.StringValue: self._visit_value,
_ast.ListValue: self._visit_value,
_ast.ObjectValue: self._visit_value,
_ast.ObjectField: self._visit_object_field,
_ast.Directive: self._visit_directive,
_ast.NonNullType: self._visit_type,
_ast.ListType: self._visit_type,
_ast.NamedType: self._visit_type,
_ast.SchemaDefinition: self._visit_schema_definition,
_ast.OperationTypeDefinition: self._visit_operation_type_definition,
_ast.ScalarTypeDefinition: self._visit_scalar_type_definition,
_ast.ObjectTypeDefinition: self._visit_object_type_definition,
_ast.FieldDefinition: self._visit_field_definition,
_ast.InputValueDefinition: self._visit_input_value_definition,
_ast.InterfaceTypeDefinition: self._visit_interface_type_definition,
_ast.UnionTypeDefinition: self._visit_union_type_definition,
_ast.EnumTypeDefinition: self._visit_enum_type_definition,
_ast.EnumValueDefinition: self._visit_enum_value_definition,
_ast.InputObjectTypeDefinition: (
self._visit_input_object_type_definition
),
_ast.SchemaExtension: self._visit_schema_definition,
_ast.ScalarTypeExtension: self._visit_scalar_type_definition,
_ast.ObjectTypeExtension: self._visit_object_type_definition,
_ast.InterfaceTypeExtension: self._visit_interface_type_definition,
_ast.UnionTypeExtension: self._visit_union_type_definition,
_ast.EnumTypeExtension: self._visit_enum_type_definition,
_ast.InputObjectTypeExtension: self._visit_input_object_type_definition,
_ast.DirectiveDefinition: self._visit_directive_definition,
},
)
@_visit_method
def _visit_document(self, document: _ast.Document) -> _ast.Document:
document.definitions = map_and_filter(
self._visit_definition, document.definitions
)
return document
def _visit_definition(self, node: _ast.Definition) -> _ast.Definition:
return classdispatch(
node,
{
_ast.OperationDefinition: self._visit_operation_definition,
_ast.FragmentDefinition: self._visit_fragment_definition,
_ast.SchemaDefinition: self._visit_schema_definition,
_ast.ScalarTypeDefinition: self._visit_scalar_type_definition,
_ast.ObjectTypeDefinition: self._visit_object_type_definition,
_ast.InterfaceTypeDefinition: self._visit_interface_type_definition,
_ast.UnionTypeDefinition: self._visit_union_type_definition,
_ast.EnumTypeDefinition: self._visit_enum_type_definition,
_ast.InputObjectTypeDefinition: (
self._visit_input_object_type_definition
),
_ast.SchemaExtension: self._visit_schema_definition,
_ast.ScalarTypeExtension: self._visit_scalar_type_definition,
_ast.ObjectTypeExtension: self._visit_object_type_definition,
_ast.InterfaceTypeExtension: self._visit_interface_type_definition,
_ast.UnionTypeExtension: self._visit_union_type_definition,
_ast.EnumTypeExtension: self._visit_enum_type_definition,
_ast.InputObjectTypeExtension: self._visit_input_object_type_definition,
_ast.DirectiveDefinition: self._visit_directive_definition,
},
)
@_visit_method
def _visit_operation_definition(
self, definition: _ast.OperationDefinition
) -> _ast.OperationDefinition:
definition.variable_definitions = map_and_filter(
self._visit_variable_definition, definition.variable_definitions
)
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.selection_set = self._visit_selection_set(
definition.selection_set
)
return definition
@_visit_method
def _visit_fragment_definition(
self, definition: _ast.FragmentDefinition
) -> _ast.FragmentDefinition:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.selection_set = self._visit_selection_set(
definition.selection_set
)
return definition
@_visit_method
def _visit_variable_definition(
self, definition: _ast.VariableDefinition
) -> _ast.VariableDefinition:
if definition.default_value:
definition.default_value = self._visit_value(
definition.default_value
)
definition.type = self._visit_type(definition.type)
return definition
@_visit_method
def _visit_type(self, type_: _ast.Type) -> _ast.Type:
return type_
@_visit_method
def _visit_directive(self, directive: _ast.Directive) -> _ast.Directive:
directive.arguments = map_and_filter(
self._visit_argument, directive.arguments
)
return directive
@_visit_method
def _visit_argument(self, argument: _ast.Argument) -> _ast.Argument:
argument.value = self._visit_input_value(argument.value)
return argument
@_visit_method
def _visit_selection_set(
self, selection_set: _ast.SelectionSet
) -> _ast.SelectionSet:
selection_set.selections = map_and_filter(
self._visit_selection, selection_set.selections
)
return selection_set
def _visit_selection(self, selection: S) -> S:
return classdispatch(
selection,
{
_ast.Field: self._visit_field,
_ast.FragmentSpread: self._visit_fragment_spread,
_ast.InlineFragment: self._visit_inline_fragment,
},
)
@_visit_method
def _visit_field(self, field: _ast.Field) -> _ast.Field:
field.arguments = map_and_filter(self._visit_argument, field.arguments)
field.directives = map_and_filter(
self._visit_directive, field.directives
)
if field.selection_set is not None:
field.selection_set = self._visit_selection_set(field.selection_set)
return field
@_visit_method
def _visit_fragment_spread(
self, spread: _ast.FragmentSpread
) -> _ast.FragmentSpread:
spread.directives = list(
map_and_filter(self._visit_directive, spread.directives)
)
return spread
@_visit_method
def _visit_inline_fragment(
self, fragment: _ast.InlineFragment
) -> _ast.InlineFragment:
fragment.directives = map_and_filter(
self._visit_directive, fragment.directives
)
fragment.selection_set = self._visit_selection_set(
fragment.selection_set
)
return fragment
def _visit_input_value(
self, value: Union[_ast.Value, _ast.Variable]
) -> Union[_ast.Value, _ast.Variable]:
if isinstance(value, _ast.Variable):
return self._visit_variable(value) # type: ignore
return self._visit_value(value) # type: ignore
@_visit_method
def _visit_variable(self, var: _ast.Variable) -> _ast.Variable:
return var
@_visit_method
def _visit_value(self, value: _ast.Value) -> _ast.Value:
if isinstance(value, _ast.ObjectValue):
value.fields = map_and_filter(
self._visit_object_field, value.fields
)
elif isinstance(value, _ast.ListValue):
value.values = map_and_filter(self._visit_input_value, value.values)
return value
@_visit_method
def _visit_object_field(self, field: _ast.ObjectField) -> _ast.ObjectField:
field.value = self._visit_value(field.value)
return field
@_visit_method
def _visit_schema_definition(
self, definition: Union[_ast.SchemaDefinition, _ast.SchemaExtension]
) -> Union[_ast.SchemaDefinition, _ast.SchemaExtension]:
definition.operation_types = map_and_filter(
self._visit_operation_type_definition, definition.operation_types
)
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
return definition
@_visit_method
def _visit_operation_type_definition(
self, definition: _ast.OperationTypeDefinition
) -> _ast.OperationTypeDefinition:
definition.type = self._visit_type(definition.type)
return definition
@_visit_method
def _visit_scalar_type_definition(
self,
definition: Union[_ast.ScalarTypeDefinition, _ast.ScalarTypeExtension],
) -> Union[_ast.ScalarTypeDefinition, _ast.ScalarTypeExtension]:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
return definition
@_visit_method
def _visit_object_type_definition(
self,
definition: Union[_ast.ObjectTypeDefinition, _ast.ObjectTypeExtension],
) -> Union[_ast.ObjectTypeDefinition, _ast.ObjectTypeExtension]:
definition.interfaces = map_and_filter(
self._visit_type, definition.interfaces
)
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.fields = map_and_filter(
self._visit_field_definition, definition.fields
)
return definition
@_visit_method
def _visit_interface_type_definition(
self,
definition: Union[
_ast.InterfaceTypeDefinition, _ast.InterfaceTypeExtension
],
) -> Union[_ast.InterfaceTypeDefinition, _ast.InterfaceTypeExtension]:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.fields = map_and_filter(
self._visit_field_definition, definition.fields
)
return definition
@_visit_method
def _visit_union_type_definition(
self,
definition: Union[_ast.UnionTypeDefinition, _ast.UnionTypeExtension],
) -> Union[_ast.UnionTypeDefinition, _ast.UnionTypeExtension]:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.types = map_and_filter(self._visit_type, definition.types)
return definition
@_visit_method
def _visit_enum_type_definition(
self, definition: Union[_ast.EnumTypeDefinition, _ast.EnumTypeExtension]
) -> Union[_ast.EnumTypeDefinition, _ast.EnumTypeExtension]:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.values = map_and_filter(
self._visit_enum_value_definition, definition.values
)
return definition
@_visit_method
def _visit_input_object_type_definition(
self,
definition: Union[
_ast.InputObjectTypeDefinition, _ast.InputObjectTypeExtension
],
) -> Union[_ast.InputObjectTypeDefinition, _ast.InputObjectTypeExtension]:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
definition.fields = map_and_filter(
self._visit_input_value_definition, definition.fields
)
return definition
@_visit_method
def _visit_field_definition(
self, definition: _ast.FieldDefinition
) -> _ast.FieldDefinition:
definition.type = self._visit_type(definition.type)
definition.arguments = map_and_filter(
self._visit_input_value_definition, definition.arguments
)
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
return definition
@_visit_method
def _visit_input_value_definition(
self, definition: _ast.InputValueDefinition
) -> _ast.InputValueDefinition:
definition.type = self._visit_type(definition.type)
if definition.default_value is not None:
self._visit_input_value(definition.default_value)
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
return definition
@_visit_method
def _visit_enum_value_definition(
self, definition: _ast.EnumValueDefinition
) -> _ast.EnumValueDefinition:
definition.directives = map_and_filter(
self._visit_directive, definition.directives
)
return definition
@_visit_method
def _visit_directive_definition(
self, definition: _ast.DirectiveDefinition
) -> _ast.DirectiveDefinition:
definition.arguments = map_and_filter(
self._visit_input_value_definition, definition.arguments
)
return definition
[docs]class DispatchingVisitor(ASTVisitor):
"""
Base class for specialized visitors.
You should subclass this and implement methods named ``enter_*`` and
``leave_*`` where ``*`` represents the node class to be handled.
For instance to process :class:`py_gql.lang.ast.FloatValue` nodes,
implement ``enter_float_value``.
Default behavior is noop for all node types.
"""
[docs] def enter(self, node: N) -> Optional[N]:
# Not sure why typechecking doesn't work here, maybe something to do
# with the decorator?
return classdispatch( # type: ignore
node,
{
_ast.Document: self.enter_document,
_ast.OperationDefinition: self.enter_operation_definition,
_ast.FragmentDefinition: self.enter_fragment_definition,
_ast.VariableDefinition: self.enter_variable_definition,
_ast.Directive: self.enter_directive,
_ast.Argument: self.enter_argument,
_ast.SelectionSet: self.enter_selection_set,
_ast.Field: self.enter_field,
_ast.FragmentSpread: self.enter_fragment_spread,
_ast.InlineFragment: self.enter_inline_fragment,
_ast.NullValue: self.enter_null_value,
_ast.IntValue: self.enter_int_value,
_ast.FloatValue: self.enter_float_value,
_ast.StringValue: self.enter_string_value,
_ast.BooleanValue: self.enter_boolean_value,
_ast.EnumValue: self.enter_enum_value,
_ast.Variable: self.enter_variable,
_ast.ListValue: self.enter_list_value,
_ast.ObjectValue: self.enter_object_value,
_ast.ObjectField: self.enter_object_field,
_ast.NamedType: self.enter_named_type,
_ast.ListType: self.enter_list_type,
_ast.NonNullType: self.enter_non_null_type,
_ast.SchemaDefinition: self.enter_schema_definition,
_ast.OperationTypeDefinition: self.enter_operation_type_definition,
_ast.ScalarTypeDefinition: self.enter_scalar_type_definition,
_ast.ObjectTypeDefinition: self.enter_object_type_definition,
_ast.FieldDefinition: self.enter_field_definition,
_ast.InputValueDefinition: self.enter_input_value_definition,
_ast.InterfaceTypeDefinition: self.enter_interface_type_definition,
_ast.UnionTypeDefinition: self.enter_union_type_definition,
_ast.EnumTypeDefinition: self.enter_enum_type_definition,
_ast.EnumValueDefinition: self.enter_enum_value_definition,
_ast.InputObjectTypeDefinition: self.enter_input_object_type_definition,
_ast.SchemaExtension: self.enter_schema_extension,
_ast.ScalarTypeExtension: self.enter_scalar_type_extension,
_ast.ObjectTypeExtension: self.enter_object_type_extension,
_ast.InterfaceTypeExtension: self.enter_interface_type_extension,
_ast.UnionTypeExtension: self.enter_union_type_extension,
_ast.EnumTypeExtension: self.enter_enum_type_extension,
_ast.InputObjectTypeExtension: self.enter_input_object_type_extension,
_ast.DirectiveDefinition: self.enter_directive_definition,
},
)
# Not sure why typechecking doesn't work here, maybe something to do
# with the decorator?
[docs] def leave(self, node: _ast.Node) -> None:
return classdispatch( # type: ignore
node,
{
_ast.Document: self.leave_document,
_ast.OperationDefinition: self.leave_operation_definition,
_ast.FragmentDefinition: self.leave_fragment_definition,
_ast.VariableDefinition: self.leave_variable_definition,
_ast.Directive: self.leave_directive,
_ast.Argument: self.leave_argument,
_ast.SelectionSet: self.leave_selection_set,
_ast.Field: self.leave_field,
_ast.FragmentSpread: self.leave_fragment_spread,
_ast.InlineFragment: self.leave_inline_fragment,
_ast.NullValue: self.leave_null_value,
_ast.IntValue: self.leave_int_value,
_ast.FloatValue: self.leave_float_value,
_ast.StringValue: self.leave_string_value,
_ast.BooleanValue: self.leave_boolean_value,
_ast.EnumValue: self.leave_enum_value,
_ast.Variable: self.leave_variable,
_ast.ListValue: self.leave_list_value,
_ast.ObjectValue: self.leave_object_value,
_ast.ObjectField: self.leave_object_field,
_ast.NamedType: self.leave_named_type,
_ast.ListType: self.leave_list_type,
_ast.NonNullType: self.leave_non_null_type,
_ast.SchemaDefinition: self.leave_schema_definition,
_ast.OperationTypeDefinition: self.leave_operation_type_definition,
_ast.ScalarTypeDefinition: self.leave_scalar_type_definition,
_ast.ObjectTypeDefinition: self.leave_object_type_definition,
_ast.FieldDefinition: self.leave_field_definition,
_ast.InputValueDefinition: self.leave_input_value_definition,
_ast.InterfaceTypeDefinition: self.leave_interface_type_definition,
_ast.UnionTypeDefinition: self.leave_union_type_definition,
_ast.EnumTypeDefinition: self.leave_enum_type_definition,
_ast.EnumValueDefinition: self.leave_enum_value_definition,
_ast.InputObjectTypeDefinition: self.leave_input_object_type_definition,
_ast.SchemaExtension: self.leave_schema_extension,
_ast.ScalarTypeExtension: self.leave_scalar_type_extension,
_ast.ObjectTypeExtension: self.leave_object_type_extension,
_ast.InterfaceTypeExtension: self.leave_interface_type_extension,
_ast.UnionTypeExtension: self.leave_union_type_extension,
_ast.EnumTypeExtension: self.leave_enum_type_extension,
_ast.InputObjectTypeExtension: self.leave_input_object_type_extension,
_ast.DirectiveDefinition: self.leave_directive_definition,
},
)
def enter_document(self, node: _ast.Document) -> Optional[_ast.Document]:
return node
def leave_document(self, _: _ast.Document) -> None:
pass
def enter_operation_definition(
self, node: _ast.OperationDefinition
) -> Optional[_ast.OperationDefinition]:
return node
def leave_operation_definition(self, _: _ast.OperationDefinition) -> None:
pass
def enter_fragment_definition(
self, node: _ast.FragmentDefinition
) -> Optional[_ast.FragmentDefinition]:
return node
def leave_fragment_definition(self, _: _ast.FragmentDefinition) -> None:
pass
def enter_variable_definition(
self, node: _ast.VariableDefinition
) -> Optional[_ast.VariableDefinition]:
return node
def leave_variable_definition(self, _: _ast.VariableDefinition) -> None:
pass
def enter_directive(self, node: _ast.Directive) -> Optional[_ast.Directive]:
return node
def leave_directive(self, _: _ast.Directive) -> None:
pass
def enter_argument(self, node: _ast.Argument) -> Optional[_ast.Argument]:
return node
def leave_argument(self, _: _ast.Argument) -> None:
pass
def enter_selection_set(
self, node: _ast.SelectionSet
) -> Optional[_ast.SelectionSet]:
return node
def leave_selection_set(self, _: _ast.SelectionSet) -> None:
pass
def enter_field(self, node: _ast.Field) -> Optional[_ast.Field]:
return node
def leave_field(self, _: _ast.Field) -> None:
pass
def enter_fragment_spread(
self, node: _ast.FragmentSpread
) -> Optional[_ast.FragmentSpread]:
return node
def leave_fragment_spread(self, _: _ast.FragmentSpread) -> None:
pass
def enter_inline_fragment(
self, node: _ast.InlineFragment
) -> Optional[_ast.InlineFragment]:
return node
def leave_inline_fragment(self, _: _ast.InlineFragment) -> None:
pass
def enter_null_value(
self, node: _ast.NullValue
) -> Optional[_ast.NullValue]:
return node
def leave_null_value(self, _: _ast.NullValue) -> None:
pass
def enter_int_value(self, node: _ast.IntValue) -> Optional[_ast.IntValue]:
return node
def leave_int_value(self, _: _ast.IntValue) -> None:
pass
def enter_float_value(
self, node: _ast.FloatValue
) -> Optional[_ast.FloatValue]:
return node
def leave_float_value(self, _: _ast.FloatValue) -> None:
pass
def enter_string_value(
self, node: _ast.StringValue
) -> Optional[_ast.StringValue]:
return node
def leave_string_value(self, _: _ast.StringValue) -> None:
pass
def enter_boolean_value(
self, node: _ast.BooleanValue
) -> Optional[_ast.BooleanValue]:
return node
def leave_boolean_value(self, _: _ast.BooleanValue) -> None:
pass
def enter_enum_value(
self, node: _ast.EnumValue
) -> Optional[_ast.EnumValue]:
return node
def leave_enum_value(self, _: _ast.EnumValue) -> None:
pass
def enter_variable(self, node: _ast.Variable) -> Optional[_ast.Variable]:
return node
def leave_variable(self, _: _ast.Variable) -> None:
pass
def enter_list_value(
self, node: _ast.ListValue
) -> Optional[_ast.ListValue]:
return node
def leave_list_value(self, _: _ast.ListValue) -> None:
pass
def enter_object_value(
self, node: _ast.ObjectValue
) -> Optional[_ast.ObjectValue]:
return node
def leave_object_value(self, _: _ast.ObjectValue) -> None:
pass
def enter_object_field(
self, node: _ast.ObjectField
) -> Optional[_ast.ObjectField]:
return node
def leave_object_field(self, _: _ast.ObjectField) -> None:
pass
def enter_named_type(
self, node: _ast.NamedType
) -> Optional[_ast.NamedType]:
return node
def leave_named_type(self, _: _ast.NamedType) -> None:
pass
def enter_list_type(self, node: _ast.ListType) -> Optional[_ast.ListType]:
return node
def leave_list_type(self, _: _ast.ListType) -> None:
pass
def enter_non_null_type(
self, node: _ast.NonNullType
) -> Optional[_ast.NonNullType]:
return node
def leave_non_null_type(self, _: _ast.NonNullType) -> None:
pass
def enter_schema_definition(
self, node: _ast.SchemaDefinition
) -> Optional[_ast.SchemaDefinition]:
return node
def leave_schema_definition(self, _: _ast.SchemaDefinition) -> None:
pass
def enter_operation_type_definition(
self, node: _ast.OperationTypeDefinition
) -> Optional[_ast.OperationTypeDefinition]:
return node
def leave_operation_type_definition(
self, _: _ast.OperationTypeDefinition
) -> None:
pass
def enter_scalar_type_definition(
self, node: _ast.ScalarTypeDefinition
) -> Optional[_ast.ScalarTypeDefinition]:
return node
def leave_scalar_type_definition(
self, _: _ast.ScalarTypeDefinition
) -> None:
pass
def enter_object_type_definition(
self, node: _ast.ObjectTypeDefinition
) -> Optional[_ast.ObjectTypeDefinition]:
return node
def leave_object_type_definition(
self, _: _ast.ObjectTypeDefinition
) -> None:
pass
def enter_field_definition(
self, node: _ast.FieldDefinition
) -> Optional[_ast.FieldDefinition]:
return node
def leave_field_definition(self, _: _ast.FieldDefinition) -> None:
pass
def enter_input_value_definition(
self, node: _ast.InputValueDefinition
) -> Optional[_ast.InputValueDefinition]:
return node
def leave_input_value_definition(
self, _: _ast.InputValueDefinition
) -> None:
pass
def enter_interface_type_definition(
self, node: _ast.InterfaceTypeDefinition
) -> Optional[_ast.InterfaceTypeDefinition]:
return node
def leave_interface_type_definition(
self, _: _ast.InterfaceTypeDefinition
) -> None:
pass
def enter_union_type_definition(
self, node: _ast.UnionTypeDefinition
) -> Optional[_ast.UnionTypeDefinition]:
return node
def leave_union_type_definition(self, _: _ast.UnionTypeDefinition) -> None:
pass
def enter_enum_type_definition(
self, node: _ast.EnumTypeDefinition
) -> Optional[_ast.EnumTypeDefinition]:
return node
def leave_enum_type_definition(self, _: _ast.EnumTypeDefinition) -> None:
pass
def enter_enum_value_definition(
self, node: _ast.EnumValueDefinition
) -> Optional[_ast.EnumValueDefinition]:
return node
def leave_enum_value_definition(self, _: _ast.EnumValueDefinition) -> None:
pass
def enter_input_object_type_definition(
self, node: _ast.InputObjectTypeDefinition
) -> Optional[_ast.InputObjectTypeDefinition]:
return node
def leave_input_object_type_definition(
self, _: _ast.InputObjectTypeDefinition
) -> None:
pass
def enter_schema_extension(
self, node: _ast.SchemaExtension
) -> Optional[_ast.SchemaExtension]:
return node
def leave_schema_extension(self, _: _ast.SchemaExtension) -> None:
pass
def enter_scalar_type_extension(
self, node: _ast.ScalarTypeExtension
) -> Optional[_ast.ScalarTypeExtension]:
return node
def leave_scalar_type_extension(self, _: _ast.ScalarTypeExtension) -> None:
pass
def enter_object_type_extension(
self, node: _ast.ObjectTypeExtension
) -> Optional[_ast.ObjectTypeExtension]:
return node
def leave_object_type_extension(self, _: _ast.ObjectTypeExtension) -> None:
pass
def enter_interface_type_extension(
self, node: _ast.InterfaceTypeExtension
) -> Optional[_ast.InterfaceTypeExtension]:
return node
def leave_interface_type_extension(
self, _: _ast.InterfaceTypeExtension
) -> None:
pass
def enter_union_type_extension(
self, node: _ast.UnionTypeExtension
) -> Optional[_ast.UnionTypeExtension]:
return node
def leave_union_type_extension(self, _: _ast.UnionTypeExtension) -> None:
pass
def enter_enum_type_extension(
self, node: _ast.EnumTypeExtension
) -> Optional[_ast.EnumTypeExtension]:
return node
def leave_enum_type_extension(self, _: _ast.EnumTypeExtension) -> None:
pass
def enter_input_object_type_extension(
self, node: _ast.InputObjectTypeExtension
) -> Optional[_ast.InputObjectTypeExtension]:
return node
def leave_input_object_type_extension(
self, _: _ast.InputObjectTypeExtension
) -> None:
pass
def enter_directive_definition(
self, node: _ast.DirectiveDefinition
) -> Optional[_ast.DirectiveDefinition]:
return node
def leave_directive_definition(self, _: _ast.DirectiveDefinition) -> None:
pass
[docs]class ChainedVisitor(ASTVisitor):
"""
Run multiple visitor instances in sequence.
- All visitors are run in the order they are defined, with enter being
called in order and leave in reverse order.
- raising :class:`SkipNode` in one of them will prevent any later visitor
to run.
Args:
*visitors: List of visitors to run.
Attributes:
visitors (List[ASTVisitor]): Children visitors.
"""
def __init__(self, *visitors: ASTVisitor):
self.visitors = tuple(visitors)
[docs] def enter(self, node: N) -> N:
cur = node # type: Optional[N]
for v in self.visitors:
if cur is None:
break
cur = v.enter(cur)
return node
[docs] def leave(self, node: N) -> None:
for v in self.visitors[::-1]:
v.leave(node)