1
- import { ApolloFederation , checkObjectTypeFederationDetails , getBaseType } from '@graphql-codegen/plugin-helpers' ;
1
+ import { ApolloFederation , type FederationMeta , getBaseType } from '@graphql-codegen/plugin-helpers' ;
2
2
import { getRootTypeNames } from '@graphql-tools/utils' ;
3
3
import autoBind from 'auto-bind' ;
4
4
import {
@@ -78,13 +78,15 @@ export interface ParsedResolversConfig extends ParsedConfig {
78
78
allResolversTypeName : string ;
79
79
internalResolversPrefix : string ;
80
80
generateInternalResolversIfNeeded : NormalizedGenerateInternalResolversIfNeededConfig ;
81
- onlyResolveTypeForInterfaces : boolean ;
82
81
directiveResolverMappings : Record < string , string > ;
83
82
resolversNonOptionalTypename : ResolversNonOptionalTypenameConfig ;
84
83
avoidCheckingAbstractTypesRecursively : boolean ;
85
84
}
86
85
87
- type FieldDefinitionPrintFn = ( parentName : string , avoidResolverOptionals : boolean ) => string | null ;
86
+ type FieldDefinitionPrintFn = (
87
+ parentName : string ,
88
+ avoidResolverOptionals : boolean
89
+ ) => { value : string | null ; meta : { federation ?: { isResolveReference : boolean } } } ;
88
90
export interface RootResolver {
89
91
content : string ;
90
92
generatedResolverTypes : {
@@ -584,20 +586,13 @@ export interface RawResolversConfig extends RawConfig {
584
586
internalResolversPrefix ?: string ;
585
587
/**
586
588
* @type object
587
- * @default { __resolveReference: false }
589
+ * @default {}
588
590
* @description If relevant internal resolvers are set to `true`, the resolver type will only be generated if the right conditions are met.
589
591
* Enabling this allows a more correct type generation for the resolvers.
590
592
* For example:
591
593
* - `__isTypeOf` is generated for implementing types and union members
592
- * - `__resolveReference` is generated for federation types that have at least one resolvable `@key` directive
593
594
*/
594
595
generateInternalResolversIfNeeded ?: GenerateInternalResolversIfNeededConfig ;
595
- /**
596
- * @type boolean
597
- * @default false
598
- * @description Turning this flag to `true` will generate resolver signature that has only `resolveType` for interfaces, forcing developers to write inherited type resolvers in the type itself.
599
- */
600
- onlyResolveTypeForInterfaces ?: boolean ;
601
596
/**
602
597
* @description Makes `__typename` of resolver mappings non-optional without affecting the base types.
603
598
* @default false
@@ -700,7 +695,8 @@ export class BaseResolversVisitor<
700
695
rawConfig : TRawConfig ,
701
696
additionalConfig : TPluginConfig ,
702
697
private _schema : GraphQLSchema ,
703
- defaultScalars : NormalizedScalarsMap = DEFAULT_SCALARS
698
+ defaultScalars : NormalizedScalarsMap = DEFAULT_SCALARS ,
699
+ federationMeta : FederationMeta = { }
704
700
) {
705
701
super ( rawConfig , {
706
702
immutableTypes : getConfigValue ( rawConfig . immutableTypes , false ) ,
@@ -714,7 +710,6 @@ export class BaseResolversVisitor<
714
710
mapOrStr : rawConfig . enumValues ,
715
711
} ) ,
716
712
addUnderscoreToArgsType : getConfigValue ( rawConfig . addUnderscoreToArgsType , false ) ,
717
- onlyResolveTypeForInterfaces : getConfigValue ( rawConfig . onlyResolveTypeForInterfaces , false ) ,
718
713
contextType : parseMapper ( rawConfig . contextType || 'any' , 'ContextType' ) ,
719
714
fieldContextTypes : getConfigValue ( rawConfig . fieldContextTypes , [ ] ) ,
720
715
directiveContextTypes : getConfigValue ( rawConfig . directiveContextTypes , [ ] ) ,
@@ -729,9 +724,7 @@ export class BaseResolversVisitor<
729
724
mappers : transformMappers ( rawConfig . mappers || { } , rawConfig . mapperTypeSuffix ) ,
730
725
scalars : buildScalarsFromConfig ( _schema , rawConfig , defaultScalars ) ,
731
726
internalResolversPrefix : getConfigValue ( rawConfig . internalResolversPrefix , '__' ) ,
732
- generateInternalResolversIfNeeded : {
733
- __resolveReference : rawConfig . generateInternalResolversIfNeeded ?. __resolveReference ?? false ,
734
- } ,
727
+ generateInternalResolversIfNeeded : { } ,
735
728
resolversNonOptionalTypename : normalizeResolversNonOptionalTypename (
736
729
getConfigValue ( rawConfig . resolversNonOptionalTypename , false )
737
730
) ,
@@ -740,7 +733,11 @@ export class BaseResolversVisitor<
740
733
} as TPluginConfig ) ;
741
734
742
735
autoBind ( this ) ;
743
- this . _federation = new ApolloFederation ( { enabled : this . config . federation , schema : this . schema } ) ;
736
+ this . _federation = new ApolloFederation ( {
737
+ enabled : this . config . federation ,
738
+ schema : this . schema ,
739
+ meta : federationMeta ,
740
+ } ) ;
744
741
this . _rootTypeNames = getRootTypeNames ( _schema ) ;
745
742
this . _variablesTransformer = new OperationVariablesToObject (
746
743
this . scalars ,
@@ -1358,7 +1355,9 @@ export class BaseResolversVisitor<
1358
1355
1359
1356
const federationMeta = this . _federation . getMeta ( ) [ schemaTypeName ] ;
1360
1357
if ( federationMeta ) {
1361
- userDefinedTypes [ schemaTypeName ] . federation = federationMeta ;
1358
+ userDefinedTypes [ schemaTypeName ] . federation = {
1359
+ hasResolveReference : federationMeta . hasResolveReference ,
1360
+ } ;
1362
1361
}
1363
1362
}
1364
1363
@@ -1474,9 +1473,10 @@ export class BaseResolversVisitor<
1474
1473
const baseType = getBaseTypeNode ( original . type ) ;
1475
1474
const realType = baseType . name . value ;
1476
1475
const parentType = this . schema . getType ( parentName ) ;
1476
+ const meta : ReturnType < FieldDefinitionPrintFn > [ 'meta' ] = { } ;
1477
1477
1478
1478
if ( this . _federation . skipField ( { fieldNode : original , parentType } ) ) {
1479
- return null ;
1479
+ return { value : null , meta } ;
1480
1480
}
1481
1481
1482
1482
const contextType = this . getContextType ( parentName , node ) ;
@@ -1516,7 +1516,7 @@ export class BaseResolversVisitor<
1516
1516
}
1517
1517
}
1518
1518
1519
- const parentTypeSignature = this . _federation . transformParentType ( {
1519
+ const parentTypeSignature = this . _federation . transformFieldParentType ( {
1520
1520
fieldNode : original ,
1521
1521
parentType,
1522
1522
parentTypeSignature : this . getParentTypeForSignature ( node ) ,
@@ -1545,29 +1545,22 @@ export class BaseResolversVisitor<
1545
1545
} ;
1546
1546
1547
1547
if ( this . _federation . isResolveReferenceField ( node ) ) {
1548
- if ( this . config . generateInternalResolversIfNeeded . __resolveReference ) {
1549
- const federationDetails = checkObjectTypeFederationDetails (
1550
- parentType . astNode as ObjectTypeDefinitionNode ,
1551
- this . _schema
1552
- ) ;
1553
-
1554
- if ( ! federationDetails || federationDetails . resolvableKeyDirectives . length === 0 ) {
1555
- return '' ;
1556
- }
1548
+ if ( ! this . _federation . getMeta ( ) [ parentType . name ] . hasResolveReference ) {
1549
+ return { value : '' , meta } ;
1557
1550
}
1558
-
1559
- this . _federation . setMeta ( parentType . name , { hasResolveReference : true } ) ;
1560
1551
signature . type = 'ReferenceResolver' ;
1561
- if ( signature . genericTypes . length >= 3 ) {
1562
- signature . genericTypes = signature . genericTypes . slice ( 0 , 3 ) ;
1563
- }
1552
+ signature . genericTypes = [ mappedTypeKey , parentTypeSignature , contextType ] ;
1553
+ meta . federation = { isResolveReference : true } ;
1564
1554
}
1565
1555
1566
- return indent (
1567
- `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1568
- ', '
1569
- ) } >${ this . getPunctuation ( declarationKind ) } `
1570
- ) ;
1556
+ return {
1557
+ value : indent (
1558
+ `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1559
+ ', '
1560
+ ) } >${ this . getPunctuation ( declarationKind ) } `
1561
+ ) ,
1562
+ meta,
1563
+ } ;
1571
1564
} ;
1572
1565
}
1573
1566
@@ -1628,7 +1621,7 @@ export class BaseResolversVisitor<
1628
1621
( rootType === 'mutation' && this . config . avoidOptionals . mutation ) ||
1629
1622
( rootType === 'subscription' && this . config . avoidOptionals . subscription ) ||
1630
1623
( rootType === false && this . config . avoidOptionals . resolvers )
1631
- ) ;
1624
+ ) . value ;
1632
1625
} ) ;
1633
1626
1634
1627
if ( ! rootType ) {
@@ -1645,10 +1638,11 @@ export class BaseResolversVisitor<
1645
1638
`ContextType = ${ this . config . contextType . type } ` ,
1646
1639
this . transformParentGenericType ( parentType ) ,
1647
1640
] ;
1648
- if ( this . _federation . getMeta ( ) [ typeName ] ) {
1649
- const typeRef = `${ this . convertName ( 'FederationTypes' ) } ['${ typeName } ']` ;
1650
- genericTypes . push ( `FederationType extends ${ typeRef } = ${ typeRef } ` ) ;
1651
- }
1641
+ this . _federation . addFederationTypeGenericIfApplicable ( {
1642
+ genericTypes,
1643
+ federationTypesType : this . convertName ( 'FederationTypes' ) ,
1644
+ typeName,
1645
+ } ) ;
1652
1646
1653
1647
const block = new DeclarationBlock ( this . _declarationBlockConfig )
1654
1648
. export ( )
@@ -1837,25 +1831,44 @@ export class BaseResolversVisitor<
1837
1831
}
1838
1832
1839
1833
const parentType = this . getParentTypeToUse ( typeName ) ;
1834
+
1835
+ const genericTypes : string [ ] = [
1836
+ `ContextType = ${ this . config . contextType . type } ` ,
1837
+ this . transformParentGenericType ( parentType ) ,
1838
+ ] ;
1839
+ this . _federation . addFederationTypeGenericIfApplicable ( {
1840
+ genericTypes,
1841
+ federationTypesType : this . convertName ( 'FederationTypes' ) ,
1842
+ typeName,
1843
+ } ) ;
1844
+
1840
1845
const possibleTypes = implementingTypes . map ( name => `'${ name } '` ) . join ( ' | ' ) || 'null' ;
1841
- const fields = this . config . onlyResolveTypeForInterfaces ? [ ] : node . fields || [ ] ;
1846
+
1847
+ // An Interface has __resolveType resolver, and no other fields.
1848
+ const blockFields : string [ ] = [
1849
+ indent (
1850
+ `${ this . config . internalResolversPrefix } resolveType${
1851
+ this . config . optionalResolveType ? '?' : ''
1852
+ } : TypeResolveFn<${ possibleTypes } , ParentType, ContextType>${ this . getPunctuation ( declarationKind ) } `
1853
+ ) ,
1854
+ ] ;
1855
+
1856
+ // An Interface in Federation may have the additional __resolveReference resolver, if resolvable.
1857
+ // So, we filter out the normal fields declared on the Interface and add the __resolveReference resolver.
1858
+ const fields = ( node . fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1859
+ f ( typeName , this . config . avoidOptionals . resolvers )
1860
+ ) ;
1861
+ for ( const field of fields ) {
1862
+ if ( field . meta . federation ?. isResolveReference ) {
1863
+ blockFields . push ( field . value ) ;
1864
+ }
1865
+ }
1842
1866
1843
1867
return new DeclarationBlock ( this . _declarationBlockConfig )
1844
1868
. export ( )
1845
1869
. asKind ( declarationKind )
1846
- . withName ( name , `<ContextType = ${ this . config . contextType . type } , ${ this . transformParentGenericType ( parentType ) } >` )
1847
- . withBlock (
1848
- [
1849
- indent (
1850
- `${ this . config . internalResolversPrefix } resolveType${
1851
- this . config . optionalResolveType ? '?' : ''
1852
- } : TypeResolveFn<${ possibleTypes } , ParentType, ContextType>${ this . getPunctuation ( declarationKind ) } `
1853
- ) ,
1854
- ...( fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1855
- f ( typeName , this . config . avoidOptionals . resolvers )
1856
- ) ,
1857
- ] . join ( '\n' )
1858
- ) . string ;
1870
+ . withName ( name , `<${ genericTypes . join ( ', ' ) } >` )
1871
+ . withBlock ( blockFields . join ( '\n' ) ) . string ;
1859
1872
}
1860
1873
1861
1874
SchemaDefinition ( ) {
0 commit comments