SingleFieldSubscriptionsRule.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true,
  4. });
  5. exports.SingleFieldSubscriptionsRule = SingleFieldSubscriptionsRule;
  6. var _GraphQLError = require('../../error/GraphQLError.js');
  7. var _kinds = require('../../language/kinds.js');
  8. var _collectFields = require('../../execution/collectFields.js');
  9. /**
  10. * Subscriptions must only include a non-introspection field.
  11. *
  12. * A GraphQL subscription is valid only if it contains a single root field and
  13. * that root field is not an introspection field.
  14. *
  15. * See https://spec.graphql.org/draft/#sec-Single-root-field
  16. */
  17. function SingleFieldSubscriptionsRule(context) {
  18. return {
  19. OperationDefinition(node) {
  20. if (node.operation === 'subscription') {
  21. const schema = context.getSchema();
  22. const subscriptionType = schema.getSubscriptionType();
  23. if (subscriptionType) {
  24. const operationName = node.name ? node.name.value : null;
  25. const variableValues = Object.create(null);
  26. const document = context.getDocument();
  27. const fragments = Object.create(null);
  28. for (const definition of document.definitions) {
  29. if (definition.kind === _kinds.Kind.FRAGMENT_DEFINITION) {
  30. fragments[definition.name.value] = definition;
  31. }
  32. }
  33. const fields = (0, _collectFields.collectFields)(
  34. schema,
  35. fragments,
  36. variableValues,
  37. subscriptionType,
  38. node.selectionSet,
  39. );
  40. if (fields.size > 1) {
  41. const fieldSelectionLists = [...fields.values()];
  42. const extraFieldSelectionLists = fieldSelectionLists.slice(1);
  43. const extraFieldSelections = extraFieldSelectionLists.flat();
  44. context.reportError(
  45. new _GraphQLError.GraphQLError(
  46. operationName != null
  47. ? `Subscription "${operationName}" must select only one top level field.`
  48. : 'Anonymous Subscription must select only one top level field.',
  49. {
  50. nodes: extraFieldSelections,
  51. },
  52. ),
  53. );
  54. }
  55. for (const fieldNodes of fields.values()) {
  56. const field = fieldNodes[0];
  57. const fieldName = field.name.value;
  58. if (fieldName.startsWith('__')) {
  59. context.reportError(
  60. new _GraphQLError.GraphQLError(
  61. operationName != null
  62. ? `Subscription "${operationName}" must not select an introspection top level field.`
  63. : 'Anonymous Subscription must not select an introspection top level field.',
  64. {
  65. nodes: fieldNodes,
  66. },
  67. ),
  68. );
  69. }
  70. }
  71. }
  72. }
  73. },
  74. };
  75. }