1
- import { ApolloFederation , getBaseType } from '@graphql-codegen/plugin-helpers' ;
1
+ import { ApolloFederation , checkObjectTypeFederationDetails , getBaseType } from '@graphql-codegen/plugin-helpers' ;
2
2
import { getRootTypeNames } from '@graphql-tools/utils' ;
3
3
import autoBind from 'auto-bind' ;
4
4
import {
@@ -33,6 +33,8 @@ import {
33
33
ConvertOptions ,
34
34
DeclarationKind ,
35
35
EnumValuesMap ,
36
+ type NormalizedGenerateInternalResolversIfNeededConfig ,
37
+ type GenerateInternalResolversIfNeededConfig ,
36
38
NormalizedAvoidOptionalsConfig ,
37
39
NormalizedScalarsMap ,
38
40
ParsedEnumValuesMap ,
@@ -75,12 +77,20 @@ export interface ParsedResolversConfig extends ParsedConfig {
75
77
resolverTypeSuffix : string ;
76
78
allResolversTypeName : string ;
77
79
internalResolversPrefix : string ;
80
+ generateInternalResolversIfNeeded : NormalizedGenerateInternalResolversIfNeededConfig ;
78
81
onlyResolveTypeForInterfaces : boolean ;
79
82
directiveResolverMappings : Record < string , string > ;
80
83
resolversNonOptionalTypename : ResolversNonOptionalTypenameConfig ;
81
84
}
82
85
83
86
type 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
+ }
84
94
85
95
export interface RawResolversConfig extends RawConfig {
86
96
/**
@@ -570,6 +580,16 @@ export interface RawResolversConfig extends RawConfig {
570
580
* If you are using `mercurius-js`, please set this field to empty string for better compatibility.
571
581
*/
572
582
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 ;
573
593
/**
574
594
* @type boolean
575
595
* @default false
@@ -641,7 +661,12 @@ export class BaseResolversVisitor<
641
661
> extends BaseVisitor < TRawConfig , TPluginConfig > {
642
662
protected _parsedConfig : TPluginConfig ;
643
663
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
+ } = { } ;
645
670
protected _collectedDirectiveResolvers : { [ key : string ] : string } = { } ;
646
671
protected _variablesTransformer : OperationVariablesToObject ;
647
672
protected _usedMappers : { [ key : string ] : boolean } = { } ;
@@ -656,7 +681,6 @@ export class BaseResolversVisitor<
656
681
protected _globalDeclarations = new Set < string > ( ) ;
657
682
protected _federation : ApolloFederation ;
658
683
protected _hasScalars = false ;
659
- protected _hasFederation = false ;
660
684
protected _fieldContextTypeMap : FieldContextTypeMap ;
661
685
protected _directiveContextTypesMap : FieldContextTypeMap ;
662
686
protected _checkedTypesWithNestedAbstractTypes : Record < string , { checkStatus : 'yes' | 'no' | 'checking' } > = { } ;
@@ -696,6 +720,9 @@ export class BaseResolversVisitor<
696
720
mappers : transformMappers ( rawConfig . mappers || { } , rawConfig . mapperTypeSuffix ) ,
697
721
scalars : buildScalarsFromConfig ( _schema , rawConfig , defaultScalars ) ,
698
722
internalResolversPrefix : getConfigValue ( rawConfig . internalResolversPrefix , '__' ) ,
723
+ generateInternalResolversIfNeeded : {
724
+ __resolveReference : rawConfig . generateInternalResolversIfNeeded ?. __resolveReference ?? false ,
725
+ } ,
699
726
resolversNonOptionalTypename : normalizeResolversNonOptionalTypename (
700
727
getConfigValue ( rawConfig . resolversNonOptionalTypename , false )
701
728
) ,
@@ -1269,21 +1296,15 @@ export class BaseResolversVisitor<
1269
1296
}
1270
1297
1271
1298
public hasFederation ( ) : boolean {
1272
- return this . _hasFederation ;
1299
+ return Object . keys ( this . _federation . getMeta ( ) ) . length > 0 ;
1273
1300
}
1274
1301
1275
- public getRootResolver ( ) : {
1276
- content : string ;
1277
- generatedResolverTypes : {
1278
- resolversMap : { name : string } ;
1279
- userDefined : Record < string , { name : string } > ;
1280
- } ;
1281
- } {
1302
+ public getRootResolver ( ) : RootResolver {
1282
1303
const name = this . convertName ( this . config . allResolversTypeName ) ;
1283
1304
const declarationKind = 'type' ;
1284
1305
const contextType = `<ContextType = ${ this . config . contextType . type } >` ;
1285
1306
1286
- const userDefinedTypes : Record < string , { name : string } > = { } ;
1307
+ const userDefinedTypes : RootResolver [ 'generatedResolverTypes' ] [ 'userDefined' ] = { } ;
1287
1308
const content = [
1288
1309
new DeclarationBlock ( this . _declarationBlockConfig )
1289
1310
. export ( )
@@ -1295,7 +1316,14 @@ export class BaseResolversVisitor<
1295
1316
const resolverType = this . _collectedResolvers [ schemaTypeName ] ;
1296
1317
1297
1318
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
+ }
1299
1327
}
1300
1328
1301
1329
return indent ( this . formatRootResolver ( schemaTypeName , resolverType . typename , declarationKind ) ) ;
@@ -1480,9 +1508,20 @@ export class BaseResolversVisitor<
1480
1508
} ;
1481
1509
1482
1510
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
+ }
1485
1522
1523
+ this . _federation . setMeta ( parentType . name , { hasResolveReference : true } ) ;
1524
+ signature . type = 'ReferenceResolver' ;
1486
1525
if ( signature . genericTypes . length >= 3 ) {
1487
1526
signature . genericTypes = signature . genericTypes . slice ( 0 , 3 ) ;
1488
1527
}
0 commit comments