UNPKG

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