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 : {
@@ -618,20 +620,13 @@ export interface RawResolversConfig extends RawConfig {
618
620
internalResolversPrefix ?: string ;
619
621
/**
620
622
* @type object
621
- * @default { __resolveReference: false }
623
+ * @default {}
622
624
* @description If relevant internal resolvers are set to `true`, the resolver type will only be generated if the right conditions are met.
623
625
* Enabling this allows a more correct type generation for the resolvers.
624
626
* For example:
625
627
* - `__isTypeOf` is generated for implementing types and union members
626
- * - `__resolveReference` is generated for federation types that have at least one resolvable `@key` directive
627
628
*/
628
629
generateInternalResolversIfNeeded ?: GenerateInternalResolversIfNeededConfig ;
629
- /**
630
- * @type boolean
631
- * @default false
632
- * @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.
633
- */
634
- onlyResolveTypeForInterfaces ?: boolean ;
635
630
/**
636
631
* @description Makes `__typename` of resolver mappings non-optional without affecting the base types.
637
632
* @default false
@@ -734,7 +729,8 @@ export class BaseResolversVisitor<
734
729
rawConfig : TRawConfig ,
735
730
additionalConfig : TPluginConfig ,
736
731
private _schema : GraphQLSchema ,
737
- defaultScalars : NormalizedScalarsMap = DEFAULT_SCALARS
732
+ defaultScalars : NormalizedScalarsMap = DEFAULT_SCALARS ,
733
+ federationMeta : FederationMeta = { }
738
734
) {
739
735
super ( rawConfig , {
740
736
immutableTypes : getConfigValue ( rawConfig . immutableTypes , false ) ,
@@ -748,7 +744,6 @@ export class BaseResolversVisitor<
748
744
mapOrStr : rawConfig . enumValues ,
749
745
} ) ,
750
746
addUnderscoreToArgsType : getConfigValue ( rawConfig . addUnderscoreToArgsType , false ) ,
751
- onlyResolveTypeForInterfaces : getConfigValue ( rawConfig . onlyResolveTypeForInterfaces , false ) ,
752
747
contextType : parseMapper ( rawConfig . contextType || 'any' , 'ContextType' ) ,
753
748
fieldContextTypes : getConfigValue ( rawConfig . fieldContextTypes , [ ] ) ,
754
749
directiveContextTypes : getConfigValue ( rawConfig . directiveContextTypes , [ ] ) ,
@@ -763,9 +758,7 @@ export class BaseResolversVisitor<
763
758
mappers : transformMappers ( rawConfig . mappers || { } , rawConfig . mapperTypeSuffix ) ,
764
759
scalars : buildScalarsFromConfig ( _schema , rawConfig , defaultScalars ) ,
765
760
internalResolversPrefix : getConfigValue ( rawConfig . internalResolversPrefix , '__' ) ,
766
- generateInternalResolversIfNeeded : {
767
- __resolveReference : rawConfig . generateInternalResolversIfNeeded ?. __resolveReference ?? false ,
768
- } ,
761
+ generateInternalResolversIfNeeded : { } ,
769
762
resolversNonOptionalTypename : normalizeResolversNonOptionalTypename (
770
763
getConfigValue ( rawConfig . resolversNonOptionalTypename , false )
771
764
) ,
@@ -774,7 +767,11 @@ export class BaseResolversVisitor<
774
767
} as TPluginConfig ) ;
775
768
776
769
autoBind ( this ) ;
777
- this . _federation = new ApolloFederation ( { enabled : this . config . federation , schema : this . schema } ) ;
770
+ this . _federation = new ApolloFederation ( {
771
+ enabled : this . config . federation ,
772
+ schema : this . schema ,
773
+ meta : federationMeta ,
774
+ } ) ;
778
775
this . _rootTypeNames = getRootTypeNames ( _schema ) ;
779
776
this . _variablesTransformer = new OperationVariablesToObject (
780
777
this . scalars ,
@@ -1396,7 +1393,9 @@ export class BaseResolversVisitor<
1396
1393
1397
1394
const federationMeta = this . _federation . getMeta ( ) [ schemaTypeName ] ;
1398
1395
if ( federationMeta ) {
1399
- userDefinedTypes [ schemaTypeName ] . federation = federationMeta ;
1396
+ userDefinedTypes [ schemaTypeName ] . federation = {
1397
+ hasResolveReference : federationMeta . hasResolveReference ,
1398
+ } ;
1400
1399
}
1401
1400
}
1402
1401
@@ -1510,9 +1509,10 @@ export class BaseResolversVisitor<
1510
1509
return ( parentName , avoidResolverOptionals ) => {
1511
1510
const original : FieldDefinitionNode = parent [ key ] ;
1512
1511
const parentType = this . schema . getType ( parentName ) ;
1512
+ const meta : ReturnType < FieldDefinitionPrintFn > [ 'meta' ] = { } ;
1513
1513
1514
1514
if ( this . _federation . skipField ( { fieldNode : original , parentType } ) ) {
1515
- return null ;
1515
+ return { value : null , meta } ;
1516
1516
}
1517
1517
1518
1518
const contextType = this . getContextType ( parentName , node ) ;
@@ -1547,7 +1547,7 @@ export class BaseResolversVisitor<
1547
1547
}
1548
1548
}
1549
1549
1550
- const parentTypeSignature = this . _federation . transformParentType ( {
1550
+ const parentTypeSignature = this . _federation . transformFieldParentType ( {
1551
1551
fieldNode : original ,
1552
1552
parentType,
1553
1553
parentTypeSignature : this . getParentTypeForSignature ( node ) ,
@@ -1602,29 +1602,22 @@ export class BaseResolversVisitor<
1602
1602
} ;
1603
1603
1604
1604
if ( this . _federation . isResolveReferenceField ( node ) ) {
1605
- if ( this . config . generateInternalResolversIfNeeded . __resolveReference ) {
1606
- const federationDetails = checkObjectTypeFederationDetails (
1607
- parentType . astNode as ObjectTypeDefinitionNode ,
1608
- this . _schema
1609
- ) ;
1610
-
1611
- if ( ! federationDetails || federationDetails . resolvableKeyDirectives . length === 0 ) {
1612
- return '' ;
1613
- }
1605
+ if ( ! this . _federation . getMeta ( ) [ parentType . name ] . hasResolveReference ) {
1606
+ return { value : '' , meta } ;
1614
1607
}
1615
-
1616
- this . _federation . setMeta ( parentType . name , { hasResolveReference : true } ) ;
1617
1608
signature . type = 'ReferenceResolver' ;
1618
- if ( signature . genericTypes . length >= 3 ) {
1619
- signature . genericTypes = signature . genericTypes . slice ( 0 , 3 ) ;
1620
- }
1609
+ signature . genericTypes = [ mappedTypeKey , parentTypeSignature , contextType ] ;
1610
+ meta . federation = { isResolveReference : true } ;
1621
1611
}
1622
1612
1623
- return indent (
1624
- `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1625
- ', '
1626
- ) } >${ this . getPunctuation ( declarationKind ) } `
1627
- ) ;
1613
+ return {
1614
+ value : indent (
1615
+ `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1616
+ ', '
1617
+ ) } >${ this . getPunctuation ( declarationKind ) } `
1618
+ ) ,
1619
+ meta,
1620
+ } ;
1628
1621
} ;
1629
1622
}
1630
1623
@@ -1685,7 +1678,7 @@ export class BaseResolversVisitor<
1685
1678
( rootType === 'mutation' && this . config . avoidOptionals . mutation ) ||
1686
1679
( rootType === 'subscription' && this . config . avoidOptionals . subscription ) ||
1687
1680
( rootType === false && this . config . avoidOptionals . resolvers )
1688
- ) ;
1681
+ ) . value ;
1689
1682
} ) ;
1690
1683
1691
1684
if ( ! rootType ) {
@@ -1702,10 +1695,11 @@ export class BaseResolversVisitor<
1702
1695
`ContextType = ${ this . config . contextType . type } ` ,
1703
1696
this . transformParentGenericType ( parentType ) ,
1704
1697
] ;
1705
- if ( this . _federation . getMeta ( ) [ typeName ] ) {
1706
- const typeRef = `${ this . convertName ( 'FederationTypes' ) } ['${ typeName } ']` ;
1707
- genericTypes . push ( `FederationType extends ${ typeRef } = ${ typeRef } ` ) ;
1708
- }
1698
+ this . _federation . addFederationTypeGenericIfApplicable ( {
1699
+ genericTypes,
1700
+ federationTypesType : this . convertName ( 'FederationTypes' ) ,
1701
+ typeName,
1702
+ } ) ;
1709
1703
1710
1704
const block = new DeclarationBlock ( this . _declarationBlockConfig )
1711
1705
. export ( )
@@ -1894,25 +1888,44 @@ export class BaseResolversVisitor<
1894
1888
}
1895
1889
1896
1890
const parentType = this . getParentTypeToUse ( typeName ) ;
1891
+
1892
+ const genericTypes : string [ ] = [
1893
+ `ContextType = ${ this . config . contextType . type } ` ,
1894
+ this . transformParentGenericType ( parentType ) ,
1895
+ ] ;
1896
+ this . _federation . addFederationTypeGenericIfApplicable ( {
1897
+ genericTypes,
1898
+ federationTypesType : this . convertName ( 'FederationTypes' ) ,
1899
+ typeName,
1900
+ } ) ;
1901
+
1897
1902
const possibleTypes = implementingTypes . map ( name => `'${ name } '` ) . join ( ' | ' ) || 'null' ;
1898
- const fields = this . config . onlyResolveTypeForInterfaces ? [ ] : node . fields || [ ] ;
1903
+
1904
+ // An Interface has __resolveType resolver, and no other fields.
1905
+ const blockFields : string [ ] = [
1906
+ indent (
1907
+ `${ this . config . internalResolversPrefix } resolveType${
1908
+ this . config . optionalResolveType ? '?' : ''
1909
+ } : TypeResolveFn<${ possibleTypes } , ParentType, ContextType>${ this . getPunctuation ( declarationKind ) } `
1910
+ ) ,
1911
+ ] ;
1912
+
1913
+ // An Interface in Federation may have the additional __resolveReference resolver, if resolvable.
1914
+ // So, we filter out the normal fields declared on the Interface and add the __resolveReference resolver.
1915
+ const fields = ( node . fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1916
+ f ( typeName , this . config . avoidOptionals . resolvers )
1917
+ ) ;
1918
+ for ( const field of fields ) {
1919
+ if ( field . meta . federation ?. isResolveReference ) {
1920
+ blockFields . push ( field . value ) ;
1921
+ }
1922
+ }
1899
1923
1900
1924
return new DeclarationBlock ( this . _declarationBlockConfig )
1901
1925
. export ( )
1902
1926
. asKind ( declarationKind )
1903
- . withName ( name , `<ContextType = ${ this . config . contextType . type } , ${ this . transformParentGenericType ( parentType ) } >` )
1904
- . withBlock (
1905
- [
1906
- indent (
1907
- `${ this . config . internalResolversPrefix } resolveType${
1908
- this . config . optionalResolveType ? '?' : ''
1909
- } : TypeResolveFn<${ possibleTypes } , ParentType, ContextType>${ this . getPunctuation ( declarationKind ) } `
1910
- ) ,
1911
- ...( fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1912
- f ( typeName , this . config . avoidOptionals . resolvers )
1913
- ) ,
1914
- ] . join ( '\n' )
1915
- ) . string ;
1927
+ . withName ( name , `<${ genericTypes . join ( ', ' ) } >` )
1928
+ . withBlock ( blockFields . join ( '\n' ) ) . string ;
1916
1929
}
1917
1930
1918
1931
SchemaDefinition ( ) {
0 commit comments