KnownDirectivesRule.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true,
  4. });
  5. exports.KnownDirectivesRule = KnownDirectivesRule;
  6. var _inspect = require('../../jsutils/inspect.js');
  7. var _invariant = require('../../jsutils/invariant.js');
  8. var _GraphQLError = require('../../error/GraphQLError.js');
  9. var _ast = require('../../language/ast.js');
  10. var _directiveLocation = require('../../language/directiveLocation.js');
  11. var _kinds = require('../../language/kinds.js');
  12. var _directives = require('../../type/directives.js');
  13. /**
  14. * Known directives
  15. *
  16. * A GraphQL document is only valid if all `@directives` are known by the
  17. * schema and legally positioned.
  18. *
  19. * See https://spec.graphql.org/draft/#sec-Directives-Are-Defined
  20. */
  21. function KnownDirectivesRule(context) {
  22. const locationsMap = Object.create(null);
  23. const schema = context.getSchema();
  24. const definedDirectives = schema
  25. ? schema.getDirectives()
  26. : _directives.specifiedDirectives;
  27. for (const directive of definedDirectives) {
  28. locationsMap[directive.name] = directive.locations;
  29. }
  30. const astDefinitions = context.getDocument().definitions;
  31. for (const def of astDefinitions) {
  32. if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
  33. locationsMap[def.name.value] = def.locations.map((name) => name.value);
  34. }
  35. }
  36. return {
  37. Directive(node, _key, _parent, _path, ancestors) {
  38. const name = node.name.value;
  39. const locations = locationsMap[name];
  40. if (!locations) {
  41. context.reportError(
  42. new _GraphQLError.GraphQLError(`Unknown directive "@${name}".`, {
  43. nodes: node,
  44. }),
  45. );
  46. return;
  47. }
  48. const candidateLocation = getDirectiveLocationForASTPath(ancestors);
  49. if (candidateLocation && !locations.includes(candidateLocation)) {
  50. context.reportError(
  51. new _GraphQLError.GraphQLError(
  52. `Directive "@${name}" may not be used on ${candidateLocation}.`,
  53. {
  54. nodes: node,
  55. },
  56. ),
  57. );
  58. }
  59. },
  60. };
  61. }
  62. function getDirectiveLocationForASTPath(ancestors) {
  63. const appliedTo = ancestors[ancestors.length - 1];
  64. 'kind' in appliedTo || (0, _invariant.invariant)(false);
  65. switch (appliedTo.kind) {
  66. case _kinds.Kind.OPERATION_DEFINITION:
  67. return getDirectiveLocationForOperation(appliedTo.operation);
  68. case _kinds.Kind.FIELD:
  69. return _directiveLocation.DirectiveLocation.FIELD;
  70. case _kinds.Kind.FRAGMENT_SPREAD:
  71. return _directiveLocation.DirectiveLocation.FRAGMENT_SPREAD;
  72. case _kinds.Kind.INLINE_FRAGMENT:
  73. return _directiveLocation.DirectiveLocation.INLINE_FRAGMENT;
  74. case _kinds.Kind.FRAGMENT_DEFINITION:
  75. return _directiveLocation.DirectiveLocation.FRAGMENT_DEFINITION;
  76. case _kinds.Kind.VARIABLE_DEFINITION:
  77. return _directiveLocation.DirectiveLocation.VARIABLE_DEFINITION;
  78. case _kinds.Kind.SCHEMA_DEFINITION:
  79. case _kinds.Kind.SCHEMA_EXTENSION:
  80. return _directiveLocation.DirectiveLocation.SCHEMA;
  81. case _kinds.Kind.SCALAR_TYPE_DEFINITION:
  82. case _kinds.Kind.SCALAR_TYPE_EXTENSION:
  83. return _directiveLocation.DirectiveLocation.SCALAR;
  84. case _kinds.Kind.OBJECT_TYPE_DEFINITION:
  85. case _kinds.Kind.OBJECT_TYPE_EXTENSION:
  86. return _directiveLocation.DirectiveLocation.OBJECT;
  87. case _kinds.Kind.FIELD_DEFINITION:
  88. return _directiveLocation.DirectiveLocation.FIELD_DEFINITION;
  89. case _kinds.Kind.INTERFACE_TYPE_DEFINITION:
  90. case _kinds.Kind.INTERFACE_TYPE_EXTENSION:
  91. return _directiveLocation.DirectiveLocation.INTERFACE;
  92. case _kinds.Kind.UNION_TYPE_DEFINITION:
  93. case _kinds.Kind.UNION_TYPE_EXTENSION:
  94. return _directiveLocation.DirectiveLocation.UNION;
  95. case _kinds.Kind.ENUM_TYPE_DEFINITION:
  96. case _kinds.Kind.ENUM_TYPE_EXTENSION:
  97. return _directiveLocation.DirectiveLocation.ENUM;
  98. case _kinds.Kind.ENUM_VALUE_DEFINITION:
  99. return _directiveLocation.DirectiveLocation.ENUM_VALUE;
  100. case _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION:
  101. case _kinds.Kind.INPUT_OBJECT_TYPE_EXTENSION:
  102. return _directiveLocation.DirectiveLocation.INPUT_OBJECT;
  103. case _kinds.Kind.INPUT_VALUE_DEFINITION: {
  104. const parentNode = ancestors[ancestors.length - 3];
  105. 'kind' in parentNode || (0, _invariant.invariant)(false);
  106. return parentNode.kind === _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION
  107. ? _directiveLocation.DirectiveLocation.INPUT_FIELD_DEFINITION
  108. : _directiveLocation.DirectiveLocation.ARGUMENT_DEFINITION;
  109. }
  110. // Not reachable, all possible types have been considered.
  111. /* c8 ignore next */
  112. default:
  113. false ||
  114. (0, _invariant.invariant)(
  115. false,
  116. 'Unexpected kind: ' + (0, _inspect.inspect)(appliedTo.kind),
  117. );
  118. }
  119. }
  120. function getDirectiveLocationForOperation(operation) {
  121. switch (operation) {
  122. case _ast.OperationTypeNode.QUERY:
  123. return _directiveLocation.DirectiveLocation.QUERY;
  124. case _ast.OperationTypeNode.MUTATION:
  125. return _directiveLocation.DirectiveLocation.MUTATION;
  126. case _ast.OperationTypeNode.SUBSCRIPTION:
  127. return _directiveLocation.DirectiveLocation.SUBSCRIPTION;
  128. }
  129. }