UniqueEnumValueNames.js.flow 2.1 KB

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