UniqueEnumValueNamesRule.js.flow 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // @flow strict
  2. import { GraphQLError } from '../../error/GraphQLError';
  3. import type { ASTVisitor } from '../../language/visitor';
  4. import type {
  5. EnumTypeDefinitionNode,
  6. EnumTypeExtensionNode,
  7. } from '../../language/ast';
  8. import { isEnumType } from '../../type/definition';
  9. import type { SDLValidationContext } from '../ValidationContext';
  10. /**
  11. * Unique enum value names
  12. *
  13. * A GraphQL enum type is only valid if all its values are uniquely named.
  14. */
  15. export function UniqueEnumValueNamesRule(
  16. context: SDLValidationContext,
  17. ): ASTVisitor {
  18. const schema = context.getSchema();
  19. const existingTypeMap = schema ? schema.getTypeMap() : Object.create(null);
  20. const knownValueNames = Object.create(null);
  21. return {
  22. EnumTypeDefinition: checkValueUniqueness,
  23. EnumTypeExtension: checkValueUniqueness,
  24. };
  25. function checkValueUniqueness(
  26. node: EnumTypeDefinitionNode | EnumTypeExtensionNode,
  27. ) {
  28. const typeName = node.name.value;
  29. if (!knownValueNames[typeName]) {
  30. knownValueNames[typeName] = Object.create(null);
  31. }
  32. // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
  33. const valueNodes = node.values ?? [];
  34. const valueNames = knownValueNames[typeName];
  35. for (const valueDef of valueNodes) {
  36. const valueName = valueDef.name.value;
  37. const existingType = existingTypeMap[typeName];
  38. if (isEnumType(existingType) && existingType.getValue(valueName)) {
  39. context.reportError(
  40. new GraphQLError(
  41. `Enum value "${typeName}.${valueName}" already exists in the schema. It cannot also be defined in this type extension.`,
  42. valueDef.name,
  43. ),
  44. );
  45. } else if (valueNames[valueName]) {
  46. context.reportError(
  47. new GraphQLError(
  48. `Enum value "${typeName}.${valueName}" can only be defined once.`,
  49. [valueNames[valueName], valueDef.name],
  50. ),
  51. );
  52. } else {
  53. valueNames[valueName] = valueDef.name;
  54. }
  55. }
  56. return false;
  57. }
  58. }