PossibleFragmentSpreadsRule.mjs 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { inspect } from '../../jsutils/inspect.mjs';
  2. import { GraphQLError } from '../../error/GraphQLError.mjs';
  3. import { isCompositeType } from '../../type/definition.mjs';
  4. import { doTypesOverlap } from '../../utilities/typeComparators.mjs';
  5. import { typeFromAST } from '../../utilities/typeFromAST.mjs';
  6. /**
  7. * Possible fragment spread
  8. *
  9. * A fragment spread is only valid if the type condition could ever possibly
  10. * be true: if there is a non-empty intersection of the possible parent types,
  11. * and possible types which pass the type condition.
  12. */
  13. export function PossibleFragmentSpreadsRule(context) {
  14. return {
  15. InlineFragment(node) {
  16. const fragType = context.getType();
  17. const parentType = context.getParentType();
  18. if (
  19. isCompositeType(fragType) &&
  20. isCompositeType(parentType) &&
  21. !doTypesOverlap(context.getSchema(), fragType, parentType)
  22. ) {
  23. const parentTypeStr = inspect(parentType);
  24. const fragTypeStr = inspect(fragType);
  25. context.reportError(
  26. new GraphQLError(
  27. `Fragment cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`,
  28. {
  29. nodes: node,
  30. },
  31. ),
  32. );
  33. }
  34. },
  35. FragmentSpread(node) {
  36. const fragName = node.name.value;
  37. const fragType = getFragmentType(context, fragName);
  38. const parentType = context.getParentType();
  39. if (
  40. fragType &&
  41. parentType &&
  42. !doTypesOverlap(context.getSchema(), fragType, parentType)
  43. ) {
  44. const parentTypeStr = inspect(parentType);
  45. const fragTypeStr = inspect(fragType);
  46. context.reportError(
  47. new GraphQLError(
  48. `Fragment "${fragName}" cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`,
  49. {
  50. nodes: node,
  51. },
  52. ),
  53. );
  54. }
  55. },
  56. };
  57. }
  58. function getFragmentType(context, name) {
  59. const frag = context.getFragment(name);
  60. if (frag) {
  61. const type = typeFromAST(context.getSchema(), frag.typeCondition);
  62. if (isCompositeType(type)) {
  63. return type;
  64. }
  65. }
  66. }