from typing import Any, List, Set from ...error import GraphQLError from ...language import OperationDefinitionNode, VariableDefinitionNode from . import ValidationContext, ValidationRule __all__ = ["NoUnusedVariablesRule"] class NoUnusedVariablesRule(ValidationRule): """No unused variables A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment. See https://spec.graphql.org/draft/#sec-All-Variables-Used """ def __init__(self, context: ValidationContext): super().__init__(context) self.variable_defs: List[VariableDefinitionNode] = [] def enter_operation_definition(self, *_args: Any) -> None: self.variable_defs.clear() def leave_operation_definition( self, operation: OperationDefinitionNode, *_args: Any ) -> None: variable_name_used: Set[str] = set() usages = self.context.get_recursive_variable_usages(operation) for usage in usages: variable_name_used.add(usage.node.name.value) for variable_def in self.variable_defs: variable_name = variable_def.variable.name.value if variable_name not in variable_name_used: self.report_error( GraphQLError( f"Variable '${variable_name}' is never used" f" in operation '{operation.name.value}'." if operation.name else f"Variable '${variable_name}' is never used.", variable_def, ) ) def enter_variable_definition( self, definition: VariableDefinitionNode, *_args: Any ) -> None: self.variable_defs.append(definition)