separateOperations.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true,
  4. });
  5. exports.separateOperations = separateOperations;
  6. var _kinds = require('../language/kinds.js');
  7. var _visitor = require('../language/visitor.js');
  8. /**
  9. * separateOperations accepts a single AST document which may contain many
  10. * operations and fragments and returns a collection of AST documents each of
  11. * which contains a single operation as well the fragment definitions it
  12. * refers to.
  13. */
  14. function separateOperations(documentAST) {
  15. const operations = [];
  16. const depGraph = Object.create(null); // Populate metadata and build a dependency graph.
  17. for (const definitionNode of documentAST.definitions) {
  18. switch (definitionNode.kind) {
  19. case _kinds.Kind.OPERATION_DEFINITION:
  20. operations.push(definitionNode);
  21. break;
  22. case _kinds.Kind.FRAGMENT_DEFINITION:
  23. depGraph[definitionNode.name.value] = collectDependencies(
  24. definitionNode.selectionSet,
  25. );
  26. break;
  27. default: // ignore non-executable definitions
  28. }
  29. } // For each operation, produce a new synthesized AST which includes only what
  30. // is necessary for completing that operation.
  31. const separatedDocumentASTs = Object.create(null);
  32. for (const operation of operations) {
  33. const dependencies = new Set();
  34. for (const fragmentName of collectDependencies(operation.selectionSet)) {
  35. collectTransitiveDependencies(dependencies, depGraph, fragmentName);
  36. } // Provides the empty string for anonymous operations.
  37. const operationName = operation.name ? operation.name.value : ''; // The list of definition nodes to be included for this operation, sorted
  38. // to retain the same order as the original document.
  39. separatedDocumentASTs[operationName] = {
  40. kind: _kinds.Kind.DOCUMENT,
  41. definitions: documentAST.definitions.filter(
  42. (node) =>
  43. node === operation ||
  44. (node.kind === _kinds.Kind.FRAGMENT_DEFINITION &&
  45. dependencies.has(node.name.value)),
  46. ),
  47. };
  48. }
  49. return separatedDocumentASTs;
  50. }
  51. // From a dependency graph, collects a list of transitive dependencies by
  52. // recursing through a dependency graph.
  53. function collectTransitiveDependencies(collected, depGraph, fromName) {
  54. if (!collected.has(fromName)) {
  55. collected.add(fromName);
  56. const immediateDeps = depGraph[fromName];
  57. if (immediateDeps !== undefined) {
  58. for (const toName of immediateDeps) {
  59. collectTransitiveDependencies(collected, depGraph, toName);
  60. }
  61. }
  62. }
  63. }
  64. function collectDependencies(selectionSet) {
  65. const dependencies = [];
  66. (0, _visitor.visit)(selectionSet, {
  67. FragmentSpread(node) {
  68. dependencies.push(node.name.value);
  69. },
  70. });
  71. return dependencies;
  72. }