PossibleFragmentSpreadsRule.js.flow 2.4 KB

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