NoUnusedVariables.js.flow 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. // @flow strict
  2. import { GraphQLError } from '../../error/GraphQLError';
  3. import { type ASTVisitor } from '../../language/visitor';
  4. import { type ValidationContext } from '../ValidationContext';
  5. export function unusedVariableMessage(
  6. varName: string,
  7. opName: ?string,
  8. ): string {
  9. return opName
  10. ? `Variable "$${varName}" is never used in operation "${opName}".`
  11. : `Variable "$${varName}" is never used.`;
  12. }
  13. /**
  14. * No unused variables
  15. *
  16. * A GraphQL operation is only valid if all variables defined by an operation
  17. * are used, either directly or within a spread fragment.
  18. */
  19. export function NoUnusedVariables(context: ValidationContext): ASTVisitor {
  20. let variableDefs = [];
  21. return {
  22. OperationDefinition: {
  23. enter() {
  24. variableDefs = [];
  25. },
  26. leave(operation) {
  27. const variableNameUsed = Object.create(null);
  28. const usages = context.getRecursiveVariableUsages(operation);
  29. const opName = operation.name ? operation.name.value : null;
  30. for (const { node } of usages) {
  31. variableNameUsed[node.name.value] = true;
  32. }
  33. for (const variableDef of variableDefs) {
  34. const variableName = variableDef.variable.name.value;
  35. if (variableNameUsed[variableName] !== true) {
  36. context.reportError(
  37. new GraphQLError(
  38. unusedVariableMessage(variableName, opName),
  39. variableDef,
  40. ),
  41. );
  42. }
  43. }
  44. },
  45. },
  46. VariableDefinition(def) {
  47. variableDefs.push(def);
  48. },
  49. };
  50. }