collectFields.js 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.collectSubFields = exports.collectFields = void 0;
  4. const memoize_js_1 = require("./memoize.js");
  5. const graphql_1 = require("graphql");
  6. // Taken from GraphQL-JS v16 for backwards compat
  7. function collectFields(schema, fragments, variableValues, runtimeType, selectionSet, fields, visitedFragmentNames) {
  8. for (const selection of selectionSet.selections) {
  9. switch (selection.kind) {
  10. case graphql_1.Kind.FIELD: {
  11. if (!shouldIncludeNode(variableValues, selection)) {
  12. continue;
  13. }
  14. const name = getFieldEntryKey(selection);
  15. const fieldList = fields.get(name);
  16. if (fieldList !== undefined) {
  17. fieldList.push(selection);
  18. }
  19. else {
  20. fields.set(name, [selection]);
  21. }
  22. break;
  23. }
  24. case graphql_1.Kind.INLINE_FRAGMENT: {
  25. if (!shouldIncludeNode(variableValues, selection) ||
  26. !doesFragmentConditionMatch(schema, selection, runtimeType)) {
  27. continue;
  28. }
  29. collectFields(schema, fragments, variableValues, runtimeType, selection.selectionSet, fields, visitedFragmentNames);
  30. break;
  31. }
  32. case graphql_1.Kind.FRAGMENT_SPREAD: {
  33. const fragName = selection.name.value;
  34. if (visitedFragmentNames.has(fragName) || !shouldIncludeNode(variableValues, selection)) {
  35. continue;
  36. }
  37. visitedFragmentNames.add(fragName);
  38. const fragment = fragments[fragName];
  39. if (!fragment || !doesFragmentConditionMatch(schema, fragment, runtimeType)) {
  40. continue;
  41. }
  42. collectFields(schema, fragments, variableValues, runtimeType, fragment.selectionSet, fields, visitedFragmentNames);
  43. break;
  44. }
  45. }
  46. }
  47. return fields;
  48. }
  49. exports.collectFields = collectFields;
  50. /**
  51. * Determines if a field should be included based on the `@include` and `@skip`
  52. * directives, where `@skip` has higher precedence than `@include`.
  53. */
  54. function shouldIncludeNode(variableValues, node) {
  55. const skip = (0, graphql_1.getDirectiveValues)(graphql_1.GraphQLSkipDirective, node, variableValues);
  56. if ((skip === null || skip === void 0 ? void 0 : skip['if']) === true) {
  57. return false;
  58. }
  59. const include = (0, graphql_1.getDirectiveValues)(graphql_1.GraphQLIncludeDirective, node, variableValues);
  60. if ((include === null || include === void 0 ? void 0 : include['if']) === false) {
  61. return false;
  62. }
  63. return true;
  64. }
  65. /**
  66. * Determines if a fragment is applicable to the given type.
  67. */
  68. function doesFragmentConditionMatch(schema, fragment, type) {
  69. const typeConditionNode = fragment.typeCondition;
  70. if (!typeConditionNode) {
  71. return true;
  72. }
  73. const conditionalType = (0, graphql_1.typeFromAST)(schema, typeConditionNode);
  74. if (conditionalType === type) {
  75. return true;
  76. }
  77. if ((0, graphql_1.isAbstractType)(conditionalType)) {
  78. const possibleTypes = schema.getPossibleTypes(conditionalType);
  79. return possibleTypes.includes(type);
  80. }
  81. return false;
  82. }
  83. /**
  84. * Implements the logic to compute the key of a given field's entry
  85. */
  86. function getFieldEntryKey(node) {
  87. return node.alias ? node.alias.value : node.name.value;
  88. }
  89. exports.collectSubFields = (0, memoize_js_1.memoize5)(function collectSubFields(schema, fragments, variableValues, type, fieldNodes) {
  90. const subFieldNodes = new Map();
  91. const visitedFragmentNames = new Set();
  92. for (const fieldNode of fieldNodes) {
  93. if (fieldNode.selectionSet) {
  94. collectFields(schema, fragments, variableValues, type, fieldNode.selectionSet, subFieldNodes, visitedFragmentNames);
  95. }
  96. }
  97. return subFieldNodes;
  98. });