NoUndefinedVariables.js.flow 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  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 undefinedVarMessage(varName: string, opName: ?string): string {
  6. return opName
  7. ? `Variable "$${varName}" is not defined by operation "${opName}".`
  8. : `Variable "$${varName}" is not defined.`;
  9. }
  10. /**
  11. * No undefined variables
  12. *
  13. * A GraphQL operation is only valid if all variables encountered, both directly
  14. * and via fragment spreads, are defined by that operation.
  15. */
  16. export function NoUndefinedVariables(context: ValidationContext): ASTVisitor {
  17. let variableNameDefined = Object.create(null);
  18. return {
  19. OperationDefinition: {
  20. enter() {
  21. variableNameDefined = Object.create(null);
  22. },
  23. leave(operation) {
  24. const usages = context.getRecursiveVariableUsages(operation);
  25. for (const { node } of usages) {
  26. const varName = node.name.value;
  27. if (variableNameDefined[varName] !== true) {
  28. context.reportError(
  29. new GraphQLError(
  30. undefinedVarMessage(
  31. varName,
  32. operation.name && operation.name.value,
  33. ),
  34. [node, operation],
  35. ),
  36. );
  37. }
  38. }
  39. },
  40. },
  41. VariableDefinition(node) {
  42. variableNameDefined[node.variable.name.value] = true;
  43. },
  44. };
  45. }