ScalarLeafs.js.flow 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. // @flow strict
  2. import inspect from '../../jsutils/inspect';
  3. import { GraphQLError } from '../../error/GraphQLError';
  4. import { type FieldNode } from '../../language/ast';
  5. import { type ASTVisitor } from '../../language/visitor';
  6. import { getNamedType, isLeafType } from '../../type/definition';
  7. import { type ValidationContext } from '../ValidationContext';
  8. export function noSubselectionAllowedMessage(
  9. fieldName: string,
  10. type: string,
  11. ): string {
  12. return `Field "${fieldName}" must not have a selection since type "${type}" has no subfields.`;
  13. }
  14. export function requiredSubselectionMessage(
  15. fieldName: string,
  16. type: string,
  17. ): string {
  18. return `Field "${fieldName}" of type "${type}" must have a selection of subfields. Did you mean "${fieldName} { ... }"?`;
  19. }
  20. /**
  21. * Scalar leafs
  22. *
  23. * A GraphQL document is valid only if all leaf fields (fields without
  24. * sub selections) are of scalar or enum types.
  25. */
  26. export function ScalarLeafs(context: ValidationContext): ASTVisitor {
  27. return {
  28. Field(node: FieldNode) {
  29. const type = context.getType();
  30. const selectionSet = node.selectionSet;
  31. if (type) {
  32. if (isLeafType(getNamedType(type))) {
  33. if (selectionSet) {
  34. context.reportError(
  35. new GraphQLError(
  36. noSubselectionAllowedMessage(node.name.value, inspect(type)),
  37. selectionSet,
  38. ),
  39. );
  40. }
  41. } else if (!selectionSet) {
  42. context.reportError(
  43. new GraphQLError(
  44. requiredSubselectionMessage(node.name.value, inspect(type)),
  45. node,
  46. ),
  47. );
  48. }
  49. }
  50. },
  51. };
  52. }