11import type { ObjMap } from '../jsutils/ObjMap' ;
22
3- import type { DocumentNode , OperationDefinitionNode } from '../language/ast' ;
3+ import type {
4+ DocumentNode ,
5+ OperationDefinitionNode ,
6+ SelectionSetNode ,
7+ } from '../language/ast' ;
48import { Kind } from '../language/kinds' ;
59import { visit } from '../language/visitor' ;
610
@@ -13,36 +17,35 @@ import { visit } from '../language/visitor';
1317export function separateOperations (
1418 documentAST : DocumentNode ,
1519) : ObjMap < DocumentNode > {
16- const operations = [ ] ;
20+ const operations : Array < OperationDefinitionNode > = [ ] ;
1721 const depGraph : DepGraph = Object . create ( null ) ;
18- let fromName ;
1922
2023 // Populate metadata and build a dependency graph.
21- visit ( documentAST , {
22- OperationDefinition ( node ) {
23- fromName = opName ( node ) ;
24- operations . push ( node ) ;
25- } ,
26- FragmentDefinition ( node ) {
27- fromName = node . name . value ;
28- } ,
29- FragmentSpread ( node ) {
30- const toName = node . name . value ;
31- let dependents = depGraph [ fromName ] ;
32- if ( dependents === undefined ) {
33- dependents = depGraph [ fromName ] = Object . create ( null ) ;
34- }
35- dependents [ toName ] = true ;
36- } ,
37- } ) ;
24+ for ( const definitionNode of documentAST . definitions ) {
25+ switch ( definitionNode . kind ) {
26+ case Kind . OPERATION_DEFINITION :
27+ operations . push ( definitionNode ) ;
28+ break ;
29+ case Kind . FRAGMENT_DEFINITION :
30+ depGraph [ definitionNode . name . value ] = collectDependencies (
31+ definitionNode . selectionSet ,
32+ ) ;
33+ break ;
34+ }
35+ }
3836
3937 // For each operation, produce a new synthesized AST which includes only what
4038 // is necessary for completing that operation.
4139 const separatedDocumentASTs = Object . create ( null ) ;
4240 for ( const operation of operations ) {
43- const operationName = opName ( operation ) ;
44- const dependencies = Object . create ( null ) ;
45- collectTransitiveDependencies ( dependencies , depGraph , operationName ) ;
41+ const dependencies = new Set ( ) ;
42+
43+ for ( const fragmentName of collectDependencies ( operation . selectionSet ) ) {
44+ collectTransitiveDependencies ( dependencies , depGraph , fragmentName ) ;
45+ }
46+
47+ // Provides the empty string for anonymous operations.
48+ const operationName = operation . name ? operation . name . value : '' ;
4649
4750 // The list of definition nodes to be included for this operation, sorted
4851 // to retain the same order as the original document.
@@ -52,35 +55,42 @@ export function separateOperations(
5255 ( node ) =>
5356 node === operation ||
5457 ( node . kind === Kind . FRAGMENT_DEFINITION &&
55- dependencies [ node . name . value ] ) ,
58+ dependencies . has ( node . name . value ) ) ,
5659 ) ,
5760 } ;
5861 }
5962
6063 return separatedDocumentASTs ;
6164}
6265
63- type DepGraph = ObjMap < ObjMap < boolean >> ;
64-
65- // Provides the empty string for anonymous operations.
66- function opName ( operation : OperationDefinitionNode ) : string {
67- return operation . name ? operation . name . value : '' ;
68- }
66+ type DepGraph = ObjMap < Array < string >> ;
6967
7068// From a dependency graph, collects a list of transitive dependencies by
7169// recursing through a dependency graph.
7270function collectTransitiveDependencies (
73- collected : ObjMap < boolean > ,
71+ collected : Set < string > ,
7472 depGraph : DepGraph ,
7573 fromName : string ,
7674) : void {
77- const immediateDeps = depGraph [ fromName ] ;
78- if ( immediateDeps ) {
79- for ( const toName of Object . keys ( immediateDeps ) ) {
80- if ( ! collected [ toName ] ) {
81- collected [ toName ] = true ;
75+ if ( ! collected . has ( fromName ) ) {
76+ collected . add ( fromName ) ;
77+
78+ const immediateDeps = depGraph [ fromName ] ;
79+ if ( immediateDeps !== undefined ) {
80+ for ( const toName of immediateDeps ) {
8281 collectTransitiveDependencies ( collected , depGraph , toName ) ;
8382 }
8483 }
8584 }
8685}
86+
87+ function collectDependencies ( selectionSet : SelectionSetNode ) : Array < string > {
88+ const dependencies = [ ] ;
89+
90+ visit ( selectionSet , {
91+ FragmentSpread ( node ) {
92+ dependencies . push ( node . name . value ) ;
93+ } ,
94+ } ) ;
95+ return dependencies ;
96+ }
0 commit comments