import { DefinitionNode , DocumentNode , FieldDefinitionNode , InputValueDefinitionNode , Kind , NamedTypeNode , TypeNode , } from 'graphql' ; import { Source } from '@graphql-tools/utils' ; import parse from 'parse-filepath' ; const sep = '/' ; /**
 * Searches every node to collect used types
 */ export function collectUsedTypes ( doc ) { const used = [ ] ; doc . definitions . forEach ( findRelated ) ; function markAsUsed ( type ) { pushUnique ( used , type ) ; } function findRelated ( node ) { if ( node . kind === Kind . OBJECT_TYPE_DEFINITION || node . kind === Kind . OBJECT_TYPE_EXTENSION ) { markAsUsed ( node . name . value ) ; if ( node . fields ) { node . fields . forEach ( findRelated ) ; } if ( node . interfaces ) { node . interfaces . forEach ( findRelated ) ; } } else if ( node . kind === Kind . INPUT_OBJECT_TYPE_DEFINITION || node . kind === Kind . INPUT_OBJECT_TYPE_EXTENSION ) { markAsUsed ( node . name . value ) ; if ( node . fields ) { node . fields . forEach ( findRelated ) ; } } else if ( node . kind === Kind . INTERFACE_TYPE_DEFINITION || node . kind === Kind . INTERFACE_TYPE_EXTENSION ) { markAsUsed ( node . name . value ) ; if ( node . fields ) { node . fields . forEach ( findRelated ) ; } if ( node . interfaces ) { node . interfaces . forEach ( findRelated ) ; } } else if ( node . kind === Kind . UNION_TYPE_DEFINITION || node . kind === Kind . UNION_TYPE_EXTENSION ) { markAsUsed ( node . name . value ) ; if ( node . types ) { node . types . forEach ( findRelated ) ; } } else if ( node . kind === Kind . ENUM_TYPE_DEFINITION || node . kind === Kind . ENUM_TYPE_EXTENSION ) { markAsUsed ( node . name . value ) ; } else if ( node . kind === Kind . SCALAR_TYPE_DEFINITION || node . kind === Kind . SCALAR_TYPE_EXTENSION ) { if ( ! isGraphQLPrimitive ( node . name . value ) ) { markAsUsed ( node . name . value ) ; } } else if ( node . kind === Kind . INPUT_VALUE_DEFINITION ) { findRelated ( resolveTypeNode ( node . type ) ) ; } else if ( node . kind === Kind . FIELD_DEFINITION ) { findRelated ( resolveTypeNode ( node . type ) ) ; if ( node . arguments ) { node . arguments . forEach ( findRelated ) ; } } else if ( node . kind === Kind . NAMED_TYPE ) { if ( ! isGraphQLPrimitive ( node . name . value ) ) { markAsUsed ( node . name . value ) ; } } } return used ; } export function resolveTypeNode ( node ) { if ( node . kind === Kind . LIST_TYPE ) { return resolveTypeNode ( node . type ) ; } if ( node . kind === Kind . NON_NULL_TYPE ) { return resolveTypeNode ( node . type ) ; } return node ; } export function isGraphQLPrimitive ( name ) { return [ 'String' , 'Boolean' , 'ID' , 'Float' , 'Int' ] . includes ( name ) ; } export function unique < T > ( val , i , all ) { return i === all . indexOf ( val ) ; } export function withQuotes ( val ) { return `'${ val }'` ; } export function indent ( size ) { const space = new Array ( size ) . fill ( ' ' ) . join ( '' ) ; function indentInner ( val ) { return val . split ( '\n' ) . map ( line => `${ space }${ line }` ) . join ( '\n' ) ; } return indentInner ; } export function buildBlock ( { name , lines } ) { if ( ! lines . length ) { return '' ; } return [ `${ name } {` , ... lines . map ( indent ( 2 ) ) , '};' ] . join ( '\n' ) ; } const getRelativePath = function ( filepath , basePath ) { const normalizedFilepath = normalize ( filepath ) ; const normalizedBasePath = ensureStartsWithSeparator ( normalize ( ensureEndsWithSeparator ( basePath ) ) ) ; const [ , relativePath ] = normalizedFilepath . split ( normalizedBasePath ) ; return relativePath ; } ; export function groupSourcesByModule ( sources , basePath ) { const grouped = { } ; sources . forEach ( source => { const relativePath = getRelativePath ( source . location , basePath ) ; if ( relativePath ) { const mod = extractModuleDirectory ( source . location , basePath ) ; if ( ! grouped [ mod ] ) { grouped [ mod ] = [ ] ; } grouped [ mod ] . push ( source ) ; } } ) ; return grouped ; } function extractModuleDirectory ( filepath , basePath ) { const relativePath = getRelativePath ( filepath , basePath ) ; const [ moduleDirectory ] = relativePath . split ( sep ) ; return moduleDirectory ; } export function stripFilename ( path ) { const parsedPath = parse ( path ) ; return normalize ( parsedPath . dir ) ; } export function normalize ( path ) { return path . replace ( /\\/g , '/' ) ; } function ensureEndsWithSeparator ( path ) { return path . endsWith ( sep ) ? path : path + sep ; } function ensureStartsWithSeparator ( path ) { return path . startsWith ( '.' ) ? path . replace ( /^(..\/)|(.\/)/ , '/' ) : path . startsWith ( '/' ) ? path : '/' + path ; } /**
 * Pushes an item to a list only if the list doesn't include the item
 */ export function pushUnique < T > ( list , item ) { if ( ! list . includes ( item ) ) { list . push ( item ) ; } } export function concatByKey < T extends Record < string , any [ ] > , K extends keyof T > ( left , right , key ) { return [ ... new Set ( [ ... left [ key ] , ... right [ key ] ] ) ] ; } export function uniqueByKey < T extends Record < string , any [ ] > , K extends keyof T > ( left , right , key ) { return left [ key ] . filter ( item => ! right [ key ] . includes ( item ) ) ; } export function createObject < K extends string , T > ( keys , valueFn ) { const obj = { } as any ; keys . forEach ( key => { obj [ key ] = valueFn ( key ) ; } ) ; return obj ; }