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 ,
@@ -1392,7 +1389,9 @@ export class BaseResolversVisitor<
1392
1389
1393
1390
const federationMeta = this . _federation . getMeta ( ) [ schemaTypeName ] ;
1394
1391
if ( federationMeta ) {
1395
- userDefinedTypes [ schemaTypeName ] . federation = federationMeta ;
1392
+ userDefinedTypes [ schemaTypeName ] . federation = {
1393
+ hasResolveReference : federationMeta . hasResolveReference ,
1394
+ } ;
1396
1395
}
1397
1396
}
1398
1397
@@ -1506,9 +1505,10 @@ export class BaseResolversVisitor<
1506
1505
return ( parentName , avoidResolverOptionals ) => {
1507
1506
const original : FieldDefinitionNode = parent [ key ] ;
1508
1507
const parentType = this . schema . getType ( parentName ) ;
1508
+ const meta : ReturnType < FieldDefinitionPrintFn > [ 'meta' ] = { } ;
1509
1509
1510
1510
if ( this . _federation . skipField ( { fieldNode : original , parentType } ) ) {
1511
- return null ;
1511
+ return { value : null , meta } ;
1512
1512
}
1513
1513
1514
1514
const contextType = this . getContextType ( parentName , node ) ;
@@ -1543,7 +1543,7 @@ export class BaseResolversVisitor<
1543
1543
}
1544
1544
}
1545
1545
1546
- const parentTypeSignature = this . _federation . transformParentType ( {
1546
+ const parentTypeSignature = this . _federation . transformFieldParentType ( {
1547
1547
fieldNode : original ,
1548
1548
parentType,
1549
1549
parentTypeSignature : this . getParentTypeForSignature ( node ) ,
@@ -1598,29 +1598,22 @@ export class BaseResolversVisitor<
1598
1598
} ;
1599
1599
1600
1600
if ( this . _federation . isResolveReferenceField ( node ) ) {
1601
- if ( this . config . generateInternalResolversIfNeeded . __resolveReference ) {
1602
- const federationDetails = checkObjectTypeFederationDetails (
1603
- parentType . astNode as ObjectTypeDefinitionNode ,
1604
- this . _schema
1605
- ) ;
1606
-
1607
- if ( ! federationDetails || federationDetails . resolvableKeyDirectives . length === 0 ) {
1608
- return '' ;
1609
- }
1601
+ if ( ! this . _federation . getMeta ( ) [ parentType . name ] . hasResolveReference ) {
1602
+ return { value : '' , meta } ;
1610
1603
}
1611
-
1612
- this . _federation . setMeta ( parentType . name , { hasResolveReference : true } ) ;
1613
1604
signature . type = 'ReferenceResolver' ;
1614
- if ( signature . genericTypes . length >= 3 ) {
1615
- signature . genericTypes = signature . genericTypes . slice ( 0 , 3 ) ;
1616
- }
1605
+ signature . genericTypes = [ mappedTypeKey , parentTypeSignature , contextType ] ;
1606
+ meta . federation = { isResolveReference : true } ;
1617
1607
}
1618
1608
1619
- return indent (
1620
- `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1621
- ', '
1622
- ) } >${ this . getPunctuation ( declarationKind ) } `
1623
- ) ;
1609
+ return {
1610
+ value : indent (
1611
+ `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1612
+ ', '
1613
+ ) } >${ this . getPunctuation ( declarationKind ) } `
1614
+ ) ,
1615
+ meta,
1616
+ } ;
1624
1617
} ;
1625
1618
}
1626
1619
@@ -1681,7 +1674,7 @@ export class BaseResolversVisitor<
1681
1674
( rootType === 'mutation' && this . config . avoidOptionals . mutation ) ||
1682
1675
( rootType === 'subscription' && this . config . avoidOptionals . subscription ) ||
1683
1676
( rootType === false && this . config . avoidOptionals . resolvers )
1684
- ) ;
1677
+ ) . value ;
1685
1678
} ) ;
1686
1679
1687
1680
if ( ! rootType ) {
@@ -1698,10 +1691,11 @@ export class BaseResolversVisitor<
1698
1691
`ContextType = ${ this . config . contextType . type } ` ,
1699
1692
this . transformParentGenericType ( parentType ) ,
1700
1693
] ;
1701
- if ( this . _federation . getMeta ( ) [ typeName ] ) {
1702
- const typeRef = `${ this . convertName ( 'FederationTypes' ) } ['${ typeName } ']` ;
1703
- genericTypes . push ( `FederationType extends ${ typeRef } = ${ typeRef } ` ) ;
1704
- }
1694
+ this . _federation . addFederationTypeGenericIfApplicable ( {
1695
+ genericTypes,
1696
+ federationTypesType : this . convertName ( 'FederationTypes' ) ,
1697
+ typeName,
1698
+ } ) ;
1705
1699
1706
1700
const block = new DeclarationBlock ( this . _declarationBlockConfig )
1707
1701
. export ( )
@@ -1890,25 +1884,44 @@ export class BaseResolversVisitor<
1890
1884
}
1891
1885
1892
1886
const parentType = this . getParentTypeToUse ( typeName ) ;
1887
+
1888
+ const genericTypes : string [ ] = [
1889
+ `ContextType = ${ this . config . contextType . type } ` ,
1890
+ this . transformParentGenericType ( parentType ) ,
1891
+ ] ;
1892
+ this . _federation . addFederationTypeGenericIfApplicable ( {
1893
+ genericTypes,
1894
+ federationTypesType : this . convertName ( 'FederationTypes' ) ,
1895
+ typeName,
1896
+ } ) ;
1897
+
1893
1898
const possibleTypes = implementingTypes . map ( name => `'${ name } '` ) . join ( ' | ' ) || 'null' ;
1894
- const fields = this . config . onlyResolveTypeForInterfaces ? [ ] : node . fields || [ ] ;
1899
+
1900
+ // An Interface has __resolveType resolver, and no other fields.
1901
+ const blockFields : string [ ] = [
1902
+ indent (
1903
+ `${ this . config . internalResolversPrefix } resolveType${
1904
+ this . config . optionalResolveType ? '?' : ''
1905
+ } : TypeResolveFn<${ possibleTypes } , ParentType, ContextType>${ this . getPunctuation ( declarationKind ) } `
1906
+ ) ,
1907
+ ] ;
1908
+
1909
+ // An Interface in Federation may have the additional __resolveReference resolver, if resolvable.
1910
+ // So, we filter out the normal fields declared on the Interface and add the __resolveReference resolver.
1911
+ const fields = ( node . fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1912
+ f ( typeName , this . config . avoidOptionals . resolvers )
1913
+ ) ;
1914
+ for ( const field of fields ) {
1915
+ if ( field . meta . federation ?. isResolveReference ) {
1916
+ blockFields . push ( field . value ) ;
1917
+ }
1918
+ }
1895
1919
1896
1920
return new DeclarationBlock ( this . _declarationBlockConfig )
1897
1921
. export ( )
1898
1922
. asKind ( declarationKind )
1899
- . withName ( name , `<ContextType = ${ this . config . contextType . type } , ${ this . transformParentGenericType ( parentType ) } >` )
1900
- . withBlock (
1901
- [
1902
- indent (
1903
- `${ this . config . internalResolversPrefix } resolveType${
1904
- this . config . optionalResolveType ? '?' : ''
1905
- } : TypeResolveFn<${ possibleTypes } , ParentType, ContextType>${ this . getPunctuation ( declarationKind ) } `
1906
- ) ,
1907
- ...( fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1908
- f ( typeName , this . config . avoidOptionals . resolvers )
1909
- ) ,
1910
- ] . join ( '\n' )
1911
- ) . string ;
1923
+ . withName ( name , `<${ genericTypes . join ( ', ' ) } >` )
1924
+ . withBlock ( blockFields . join ( '\n' ) ) . string ;
1912
1925
}
1913
1926
1914
1927
SchemaDefinition ( ) {
0 commit comments