separateOperations.mjs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { visit } from '../language/visitor';
  2. /**
  3. * separateOperations accepts a single AST document which may contain many
  4. * operations and fragments and returns a collection of AST documents each of
  5. * which contains a single operation as well the fragment definitions it
  6. * refers to.
  7. */
  8. export function separateOperations(documentAST) {
  9. var operations = [];
  10. var fragments = Object.create(null);
  11. var positions = new Map();
  12. var depGraph = Object.create(null);
  13. var fromName;
  14. var idx = 0; // Populate metadata and build a dependency graph.
  15. visit(documentAST, {
  16. OperationDefinition: function OperationDefinition(node) {
  17. fromName = opName(node);
  18. operations.push(node);
  19. positions.set(node, idx++);
  20. },
  21. FragmentDefinition: function FragmentDefinition(node) {
  22. fromName = node.name.value;
  23. fragments[fromName] = node;
  24. positions.set(node, idx++);
  25. },
  26. FragmentSpread: function FragmentSpread(node) {
  27. var toName = node.name.value;
  28. (depGraph[fromName] || (depGraph[fromName] = Object.create(null)))[toName] = true;
  29. }
  30. }); // For each operation, produce a new synthesized AST which includes only what
  31. // is necessary for completing that operation.
  32. var separatedDocumentASTs = Object.create(null);
  33. for (var _i2 = 0; _i2 < operations.length; _i2++) {
  34. var operation = operations[_i2];
  35. var operationName = opName(operation);
  36. var dependencies = Object.create(null);
  37. collectTransitiveDependencies(dependencies, depGraph, operationName); // The list of definition nodes to be included for this operation, sorted
  38. // to retain the same order as the original document.
  39. var definitions = [operation];
  40. for (var _i4 = 0, _Object$keys2 = Object.keys(dependencies); _i4 < _Object$keys2.length; _i4++) {
  41. var name = _Object$keys2[_i4];
  42. definitions.push(fragments[name]);
  43. }
  44. definitions.sort(function (n1, n2) {
  45. return (positions.get(n1) || 0) - (positions.get(n2) || 0);
  46. });
  47. separatedDocumentASTs[operationName] = {
  48. kind: 'Document',
  49. definitions: definitions
  50. };
  51. }
  52. return separatedDocumentASTs;
  53. }
  54. // Provides the empty string for anonymous operations.
  55. function opName(operation) {
  56. return operation.name ? operation.name.value : '';
  57. } // From a dependency graph, collects a list of transitive dependencies by
  58. // recursing through a dependency graph.
  59. function collectTransitiveDependencies(collected, depGraph, fromName) {
  60. var immediateDeps = depGraph[fromName];
  61. if (immediateDeps) {
  62. for (var _i6 = 0, _Object$keys4 = Object.keys(immediateDeps); _i6 < _Object$keys4.length; _i6++) {
  63. var toName = _Object$keys4[_i6];
  64. if (!collected[toName]) {
  65. collected[toName] = true;
  66. collectTransitiveDependencies(collected, depGraph, toName);
  67. }
  68. }
  69. }
  70. }