UniqueFieldDefinitionNamesRule.mjs 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { GraphQLError } from '../../error/GraphQLError.mjs';
  2. import {
  3. isInputObjectType,
  4. isInterfaceType,
  5. isObjectType,
  6. } from '../../type/definition.mjs';
  7. /**
  8. * Unique field definition names
  9. *
  10. * A GraphQL complex type is only valid if all its fields are uniquely named.
  11. */
  12. export function UniqueFieldDefinitionNamesRule(context) {
  13. const schema = context.getSchema();
  14. const existingTypeMap = schema ? schema.getTypeMap() : Object.create(null);
  15. const knownFieldNames = Object.create(null);
  16. return {
  17. InputObjectTypeDefinition: checkFieldUniqueness,
  18. InputObjectTypeExtension: checkFieldUniqueness,
  19. InterfaceTypeDefinition: checkFieldUniqueness,
  20. InterfaceTypeExtension: checkFieldUniqueness,
  21. ObjectTypeDefinition: checkFieldUniqueness,
  22. ObjectTypeExtension: checkFieldUniqueness,
  23. };
  24. function checkFieldUniqueness(node) {
  25. var _node$fields;
  26. const typeName = node.name.value;
  27. if (!knownFieldNames[typeName]) {
  28. knownFieldNames[typeName] = Object.create(null);
  29. } // FIXME: https://github.com/graphql/graphql-js/issues/2203
  30. /* c8 ignore next */
  31. const fieldNodes =
  32. (_node$fields = node.fields) !== null && _node$fields !== void 0
  33. ? _node$fields
  34. : [];
  35. const fieldNames = knownFieldNames[typeName];
  36. for (const fieldDef of fieldNodes) {
  37. const fieldName = fieldDef.name.value;
  38. if (hasField(existingTypeMap[typeName], fieldName)) {
  39. context.reportError(
  40. new GraphQLError(
  41. `Field "${typeName}.${fieldName}" already exists in the schema. It cannot also be defined in this type extension.`,
  42. {
  43. nodes: fieldDef.name,
  44. },
  45. ),
  46. );
  47. } else if (fieldNames[fieldName]) {
  48. context.reportError(
  49. new GraphQLError(
  50. `Field "${typeName}.${fieldName}" can only be defined once.`,
  51. {
  52. nodes: [fieldNames[fieldName], fieldDef.name],
  53. },
  54. ),
  55. );
  56. } else {
  57. fieldNames[fieldName] = fieldDef.name;
  58. }
  59. }
  60. return false;
  61. }
  62. }
  63. function hasField(type, fieldName) {
  64. if (isObjectType(type) || isInterfaceType(type) || isInputObjectType(type)) {
  65. return type.getFields()[fieldName] != null;
  66. }
  67. return false;
  68. }