1- import { ApolloFederation , getBaseType } from '@graphql-codegen/plugin-helpers' ;
1+ import { ApolloFederation , checkObjectTypeFederationDetails , getBaseType } from '@graphql-codegen/plugin-helpers' ;
22import { getRootTypeNames } from '@graphql-tools/utils' ;
33import autoBind from 'auto-bind' ;
44import {
@@ -33,6 +33,8 @@ import {
3333 ConvertOptions ,
3434 DeclarationKind ,
3535 EnumValuesMap ,
36+ type NormalizedGenerateInternalResolversIfNeededConfig ,
37+ type GenerateInternalResolversIfNeededConfig ,
3638 NormalizedAvoidOptionalsConfig ,
3739 NormalizedScalarsMap ,
3840 ParsedEnumValuesMap ,
@@ -75,12 +77,20 @@ export interface ParsedResolversConfig extends ParsedConfig {
7577 resolverTypeSuffix : string ;
7678 allResolversTypeName : string ;
7779 internalResolversPrefix : string ;
80+ generateInternalResolversIfNeeded : NormalizedGenerateInternalResolversIfNeededConfig ;
7881 onlyResolveTypeForInterfaces : boolean ;
7982 directiveResolverMappings : Record < string , string > ;
8083 resolversNonOptionalTypename : ResolversNonOptionalTypenameConfig ;
8184}
8285
8386type FieldDefinitionPrintFn = ( parentName : string , avoidResolverOptionals : boolean ) => string | null ;
87+ export interface RootResolver {
88+ content : string ;
89+ generatedResolverTypes : {
90+ resolversMap : { name : string } ;
91+ userDefined : Record < string , { name : string ; federation ?: { hasResolveReference : boolean } } > ;
92+ } ;
93+ }
8494
8595export interface RawResolversConfig extends RawConfig {
8696 /**
@@ -570,6 +580,16 @@ export interface RawResolversConfig extends RawConfig {
570580 * If you are using `mercurius-js`, please set this field to empty string for better compatibility.
571581 */
572582 internalResolversPrefix ?: string ;
583+ /**
584+ * @type object
585+ * @default { __resolveReference: false }
586+ * @description If relevant internal resolvers are set to `true`, the resolver type will only be generated if the right conditions are met.
587+ * Enabling this allows a more correct type generation for the resolvers.
588+ * For example:
589+ * - `__isTypeOf` is generated for implementing types and union members
590+ * - `__resolveReference` is generated for federation types that have at least one resolvable `@key` directive
591+ */
592+ generateInternalResolversIfNeeded ?: GenerateInternalResolversIfNeededConfig ;
573593 /**
574594 * @type boolean
575595 * @default false
@@ -641,7 +661,12 @@ export class BaseResolversVisitor<
641661> extends BaseVisitor < TRawConfig , TPluginConfig > {
642662 protected _parsedConfig : TPluginConfig ;
643663 protected _declarationBlockConfig : DeclarationBlockConfig = { } ;
644- protected _collectedResolvers : { [ key : string ] : { typename : string ; baseGeneratedTypename ?: string } } = { } ;
664+ protected _collectedResolvers : {
665+ [ key : string ] : {
666+ typename : string ;
667+ baseGeneratedTypename ?: string ;
668+ } ;
669+ } = { } ;
645670 protected _collectedDirectiveResolvers : { [ key : string ] : string } = { } ;
646671 protected _variablesTransformer : OperationVariablesToObject ;
647672 protected _usedMappers : { [ key : string ] : boolean } = { } ;
@@ -656,7 +681,6 @@ export class BaseResolversVisitor<
656681 protected _globalDeclarations = new Set < string > ( ) ;
657682 protected _federation : ApolloFederation ;
658683 protected _hasScalars = false ;
659- protected _hasFederation = false ;
660684 protected _fieldContextTypeMap : FieldContextTypeMap ;
661685 protected _directiveContextTypesMap : FieldContextTypeMap ;
662686 protected _checkedTypesWithNestedAbstractTypes : Record < string , { checkStatus : 'yes' | 'no' | 'checking' } > = { } ;
@@ -696,6 +720,9 @@ export class BaseResolversVisitor<
696720 mappers : transformMappers ( rawConfig . mappers || { } , rawConfig . mapperTypeSuffix ) ,
697721 scalars : buildScalarsFromConfig ( _schema , rawConfig , defaultScalars ) ,
698722 internalResolversPrefix : getConfigValue ( rawConfig . internalResolversPrefix , '__' ) ,
723+ generateInternalResolversIfNeeded : {
724+ __resolveReference : rawConfig . generateInternalResolversIfNeeded ?. __resolveReference ?? false ,
725+ } ,
699726 resolversNonOptionalTypename : normalizeResolversNonOptionalTypename (
700727 getConfigValue ( rawConfig . resolversNonOptionalTypename , false )
701728 ) ,
@@ -1269,21 +1296,15 @@ export class BaseResolversVisitor<
12691296 }
12701297
12711298 public hasFederation ( ) : boolean {
1272- return this . _hasFederation ;
1299+ return Object . keys ( this . _federation . getMeta ( ) ) . length > 0 ;
12731300 }
12741301
1275- public getRootResolver ( ) : {
1276- content : string ;
1277- generatedResolverTypes : {
1278- resolversMap : { name : string } ;
1279- userDefined : Record < string , { name : string } > ;
1280- } ;
1281- } {
1302+ public getRootResolver ( ) : RootResolver {
12821303 const name = this . convertName ( this . config . allResolversTypeName ) ;
12831304 const declarationKind = 'type' ;
12841305 const contextType = `<ContextType = ${ this . config . contextType . type } >` ;
12851306
1286- const userDefinedTypes : Record < string , { name : string } > = { } ;
1307+ const userDefinedTypes : RootResolver [ 'generatedResolverTypes' ] [ 'userDefined' ] = { } ;
12871308 const content = [
12881309 new DeclarationBlock ( this . _declarationBlockConfig )
12891310 . export ( )
@@ -1295,7 +1316,14 @@ export class BaseResolversVisitor<
12951316 const resolverType = this . _collectedResolvers [ schemaTypeName ] ;
12961317
12971318 if ( resolverType . baseGeneratedTypename ) {
1298- userDefinedTypes [ schemaTypeName ] = { name : resolverType . baseGeneratedTypename } ;
1319+ userDefinedTypes [ schemaTypeName ] = {
1320+ name : resolverType . baseGeneratedTypename ,
1321+ } ;
1322+
1323+ const federationMeta = this . _federation . getMeta ( ) [ schemaTypeName ] ;
1324+ if ( federationMeta ) {
1325+ userDefinedTypes [ schemaTypeName ] . federation = federationMeta ;
1326+ }
12991327 }
13001328
13011329 return indent ( this . formatRootResolver ( schemaTypeName , resolverType . typename , declarationKind ) ) ;
@@ -1480,9 +1508,20 @@ export class BaseResolversVisitor<
14801508 } ;
14811509
14821510 if ( this . _federation . isResolveReferenceField ( node ) ) {
1483- this . _hasFederation = true ;
1484- signature . type = 'ReferenceResolver' ;
1511+ if ( this . config . generateInternalResolversIfNeeded . __resolveReference ) {
1512+ const federationDetails = checkObjectTypeFederationDetails (
1513+ parentType . astNode as ObjectTypeDefinitionNode ,
1514+ this . _schema
1515+ ) ;
1516+
1517+ if ( ! federationDetails || federationDetails . resolvableKeyDirectives . length === 0 ) {
1518+ return '' ;
1519+ }
1520+ signature . modifier = '' ; // if a federation type has resolvable @key , then it should be required
1521+ }
14851522
1523+ this . _federation . setMeta ( parentType . name , { hasResolveReference : true } ) ;
1524+ signature . type = 'ReferenceResolver' ;
14861525 if ( signature . genericTypes . length >= 3 ) {
14871526 signature . genericTypes = signature . genericTypes . slice ( 0 , 3 ) ;
14881527 }
0 commit comments