import { Config , Plugin , Refs } from 'pretty-format' ; import { PlanNode , QueryPlan } from '../' ; import { parse , Kind , visit , DocumentNode } from 'graphql' ; export default { test ( value ) { return value && value . kind === 'QueryPlan' ; } , serialize ( queryPlan , config , indentation , depth , refs , printer ) { return ( 'QueryPlan {' + printNodes ( queryPlan . node ? [ queryPlan . node ] : undefined , config , indentation , depth , refs , printer ) + '}' ) ; } , } as Plugin ; function printNode ( node , config , indentation , depth , refs , printer ) { let result = '' ; const indentationNext = indentation + config . indent ; switch ( node . kind ) { case 'Fetch' : result += `Fetch(service: "${ node . serviceName }")` + ' {' + config . spacingOuter + ( node . requires ? printer ( { kind : Kind . SELECTION_SET , selections : node . requires } , config , indentationNext , depth , refs , printer ) + ' =>' + config . spacingOuter : '' ) + printer ( flattenEntitiesField ( parse ( node . operation ) ) , config , indentationNext , depth , refs , printer ) + config . spacingOuter + indentation + '}' ; break ; case 'Flatten' : result += `Flatten(path: "${ node . path . join ( '.' ) }")` ; break ; default : result += node . kind ; } const nodes = 'nodes' in node ? node . nodes : 'node' in node ? [ node . node ] : [ ] ; if ( nodes . length > 0 ) { result += ' {' + printNodes ( nodes , config , indentation , depth , refs , printer ) + '}' ; } return result ; } function printNodes ( nodes , config , indentation , depth , refs , printer ) { let result = '' ; if ( nodes && nodes . length > 0 ) { result += config . spacingOuter ; const indentationNext = indentation + config . indent ; for ( let i = 0 ; i < nodes . length ; i ++ ) { const node = nodes [ i ] ; if ( ! node ) continue ; result += indentationNext + printNode ( node , config , indentationNext , depth , refs , printer ) ; if ( i < nodes . length - 1 ) { result += ',' + config . spacingInner ; } else if ( ! config . min ) { result += ',' ; } } result += config . spacingOuter + indentation ; } return result ; } /**
 * when we serialize a query plan, we want to serialize the operation, but not
 * show the root level `query` definition or the `_entities` call. This function
 * flattens those nodes to only show their selectionSets
 */ function flattenEntitiesField ( node ) { return visit ( node , { OperationDefinition : ( { operation , selectionSet } ) => { const firstSelection = selectionSet . selections [ 0 ] ; if ( operation === 'query' && firstSelection . kind === Kind . FIELD && firstSelection . name . value === '_entities' ) { return firstSelection . selectionSet ; } return selectionSet ; } , } ) ; }