import { NormalizedScalarsMap } from './types' ; import autoBind from 'auto-bind' ; import { DEFAULT_SCALARS } from './scalars' ; import { DeclarationBlock , DeclarationBlockConfig , getConfigValue , buildScalarsFromConfig } from './utils' ; import { GraphQLSchema , FragmentDefinitionNode , OperationDefinitionNode , VariableDefinitionNode , OperationTypeNode , } from 'graphql' ; import { SelectionSetToObject } from './selection-set-to-object' ; import { OperationVariablesToObject } from './variables-to-object' ; import { BaseVisitor } from './base-visitor' ; import { ParsedTypesConfig , RawTypesConfig } from './base-types-visitor' ; import { pascalCase } from 'change-case-all' ; function getRootType ( operation , schema ) { switch ( operation ) { case 'query' : return schema . getQueryType ( ) ; case 'mutation' : return schema . getMutationType ( ) ; case 'subscription' : return schema . getSubscriptionType ( ) ; } throw new Error ( `Unknown operation type: ${ operation }` ) ; } export interface ParsedDocumentsConfig extends ParsedTypesConfig { addTypename : boolean ; preResolveTypes : boolean ; globalNamespace : boolean ; operationResultSuffix : string ; dedupeOperationSuffix : boolean ; omitOperationSuffix : boolean ; namespacedImportName : string | null ; exportFragmentSpreadSubTypes : boolean ; skipTypeNameForRoot : boolean ; experimentalFragmentVariables : boolean ; } export interface RawDocumentsConfig extends RawTypesConfig { default description exampleMarkdown preResolveTypes ? : boolean ; default description exampleMarkdown skipTypeNameForRoot ? : boolean ; default description exampleMarkdown globalNamespace ? : boolean ; default description operationResultSuffix ? : string ; default description dedupeOperationSuffix ? : boolean ; default description omitOperationSuffix ? : boolean ; default description exportFragmentSpreadSubTypes ? : boolean ; default description experimentalFragmentVariables ? : boolean ; ignore namespacedImportName ? : string ; } export class BaseDocumentsVisitor < TRawConfig extends RawDocumentsConfig = RawDocumentsConfig , TPluginConfig extends ParsedDocumentsConfig = ParsedDocumentsConfig > extends BaseVisitor < TRawConfig , TPluginConfig > { protected _unnamedCounter = 1 ; protected _variablesTransfomer : OperationVariablesToObject ; protected _selectionSetToObject : SelectionSetToObject ; protected _globalDeclarations : Set < string > = new Set < string > ( ) ; constructor ( rawConfig , additionalConfig , protected _schema , defaultScalars = DEFAULT_SCALARS ) { super ( rawConfig , { exportFragmentSpreadSubTypes : getConfigValue ( rawConfig . exportFragmentSpreadSubTypes , false ) , enumPrefix : getConfigValue ( rawConfig . enumPrefix , true ) , preResolveTypes : getConfigValue ( rawConfig . preResolveTypes , true ) , dedupeOperationSuffix : getConfigValue ( rawConfig . dedupeOperationSuffix , false ) , omitOperationSuffix : getConfigValue ( rawConfig . omitOperationSuffix , false ) , skipTypeNameForRoot : getConfigValue ( rawConfig . skipTypeNameForRoot , false ) , namespacedImportName : getConfigValue ( rawConfig . namespacedImportName , null ) , experimentalFragmentVariables : getConfigValue ( rawConfig . experimentalFragmentVariables , false ) , addTypename : ! rawConfig . skipTypename , globalNamespace : ! ! rawConfig . globalNamespace , operationResultSuffix : getConfigValue ( rawConfig . operationResultSuffix , '' ) , scalars : buildScalarsFromConfig ( _schema , rawConfig , defaultScalars ) , ... ( ( additionalConfig || { } ) as any ) , } ) ; autoBind ( this ) ; this . _variablesTransfomer = new OperationVariablesToObject ( this . scalars , this . convertName , this . config . namespacedImportName ) ; } public getGlobalDeclarations ( noExport = false ) { return Array . from ( this . _globalDeclarations ) . map ( t => ( noExport ? t : `export ${ t }` ) ) ; } setSelectionSetHandler ( handler ) { this . _selectionSetToObject = handler ; } setDeclarationBlockConfig ( config ) { this . _declarationBlockConfig = config ; } setVariablesTransformer ( variablesTransfomer ) { this . _variablesTransfomer = variablesTransfomer ; } public get schema ( ) : GraphQLSchema { return this . _schema ; } public get addTypename ( ) : boolean { return this . _parsedConfig . addTypename ; } private handleAnonymousOperation ( node ) { const name = node . name && node . name . value ; if ( name ) { return this . convertName ( name , { useTypesPrefix : false , useTypesSuffix : false , } ) ; } return this . convertName ( this . _unnamedCounter ++ + '' , { prefix : 'Unnamed_' , suffix : '_' , useTypesPrefix : false , useTypesSuffix : false , } ) ; } FragmentDefinition ( node ) { const fragmentRootType = this . _schema . getType ( node . typeCondition . name . value ) ; const selectionSet = this . _selectionSetToObject . createNext ( fragmentRootType , node . selectionSet ) ; const fragmentSuffix = this . getFragmentSuffix ( node ) ; return [ selectionSet . transformFragmentSelectionSetToTypes ( node . name . value , fragmentSuffix , this . _declarationBlockConfig ) , this . config . experimentalFragmentVariables ? new DeclarationBlock ( { ... this . _declarationBlockConfig , blockTransformer : t => this . applyVariablesWrapper ( t ) , } ) . export ( ) . asKind ( 'type' ) . withName ( this . convertName ( node . name . value , { suffix : fragmentSuffix + 'Variables' , } ) ) . withBlock ( this . _variablesTransfomer . transform ( node . variableDefinitions ) ) . string : undefined , ] . filter ( r => r ) . join ( '\n\n' ) ; } protected applyVariablesWrapper ( variablesBlock ) { return variablesBlock ; } OperationDefinition ( node ) { const name = this . handleAnonymousOperation ( node ) ; const operationRootType = getRootType ( node . operation , this . _schema ) ; if ( ! operationRootType ) { throw new Error ( `Unable to find root schema type for operation type "${ node . operation }"!` ) ; } const selectionSet = this . _selectionSetToObject . createNext ( operationRootType , node . selectionSet ) ; const visitedOperationVariables = this . _variablesTransfomer . transform < VariableDefinitionNode > ( node . variableDefinitions ) ; const operationType = pascalCase ( node . operation ) ; const operationTypeSuffix = this . getOperationSuffix ( name , operationType ) ; const operationResult = new DeclarationBlock ( this . _declarationBlockConfig ) . export ( ) . asKind ( 'type' ) . withName ( this . convertName ( name , { suffix : operationTypeSuffix + this . _parsedConfig . operationResultSuffix , } ) ) . withContent ( selectionSet . transformSelectionSet ( ) ) . string ; const operationVariables = new DeclarationBlock ( { ... this . _declarationBlockConfig , blockTransformer : t => this . applyVariablesWrapper ( t ) , } ) . export ( ) . asKind ( 'type' ) . withName ( this . convertName ( name , { suffix : operationTypeSuffix + 'Variables' , } ) ) . withBlock ( visitedOperationVariables ) . string ; return [ operationVariables , operationResult ] . filter ( r => r ) . join ( '\n\n' ) ; } }