PossibleFragmentSpreadsRule.js.flow 2.2 KB

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