@@ -82,8 +82,13 @@ export interface ParsedResolversConfig extends ParsedConfig {
82
82
avoidCheckingAbstractTypesRecursively : boolean ;
83
83
}
84
84
85
+ export interface FieldDefinitionResult {
86
+ node : FieldDefinitionNode ;
87
+ printContent : FieldDefinitionPrintFn ;
88
+ }
89
+
85
90
type FieldDefinitionPrintFn = (
86
- parentName : string ,
91
+ parentNode : ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode ,
87
92
avoidResolverOptionals : boolean
88
93
) => { value : string | null ; meta : { federation ?: { isResolveReference : boolean } } } ;
89
94
export interface RootResolver {
@@ -1463,6 +1468,9 @@ export class BaseResolversVisitor<
1463
1468
return '' ;
1464
1469
}
1465
1470
1471
+ // FIXME: this Name method causes a lot of type inconsistencies
1472
+ // because the type of nodes no longer matches the `graphql-js` types
1473
+ // So, we should update this and remove any relevant `as any as string` or `as unknown as string`
1466
1474
Name ( node : NameNode ) : string {
1467
1475
return node . value ;
1468
1476
}
@@ -1519,122 +1527,133 @@ export class BaseResolversVisitor<
1519
1527
return `ParentType extends ${ parentType } = ${ parentType } ` ;
1520
1528
}
1521
1529
1522
- FieldDefinition ( node : FieldDefinitionNode , key : string | number , parent : any ) : FieldDefinitionPrintFn {
1530
+ FieldDefinition ( node : FieldDefinitionNode , key : string | number , parent : any ) : FieldDefinitionResult {
1523
1531
const hasArguments = node . arguments && node . arguments . length > 0 ;
1524
1532
const declarationKind = 'type' ;
1525
1533
1526
- return ( parentName , avoidResolverOptionals ) => {
1527
- const original : FieldDefinitionNode = parent [ key ] ;
1528
- const parentType = this . schema . getType ( parentName ) ;
1529
- const meta : ReturnType < FieldDefinitionPrintFn > [ 'meta' ] = { } ;
1534
+ const original : FieldDefinitionNode = parent [ key ] ;
1530
1535
1531
- if ( this . _federation . skipField ( { fieldNode : original , parentType } ) ) {
1532
- return { value : null , meta } ;
1533
- }
1536
+ return {
1537
+ node : original ,
1538
+ printContent : ( parentNode , avoidResolverOptionals ) => {
1539
+ const parentName = parentNode . name as unknown as string ;
1540
+ const parentType = this . schema . getType ( parentName ) ;
1541
+ const meta : ReturnType < FieldDefinitionPrintFn > [ 'meta' ] = { } ;
1542
+ const typeName = node . name as unknown as string ;
1543
+
1544
+ const fieldsToGenerate = this . _federation . findFieldNodesToGenerate ( { node : parentNode } ) ;
1545
+ const shouldGenerateField =
1546
+ fieldsToGenerate . some ( field => field . name . value === typeName ) ||
1547
+ this . _federation . isResolveReferenceField ( node ) ;
1548
+
1549
+ if ( ! shouldGenerateField ) {
1550
+ return { value : null , meta } ;
1551
+ }
1534
1552
1535
- const contextType = this . getContextType ( parentName , node ) ;
1536
-
1537
- let argsType = hasArguments
1538
- ? this . convertName (
1539
- parentName +
1540
- ( this . config . addUnderscoreToArgsType ? '_' : '' ) +
1541
- this . convertName ( node . name , {
1542
- useTypesPrefix : false ,
1543
- useTypesSuffix : false ,
1544
- } ) +
1545
- 'Args' ,
1546
- {
1547
- useTypesPrefix : true ,
1548
- } ,
1549
- true
1550
- )
1551
- : null ;
1553
+ const contextType = this . getContextType ( parentName , node ) ;
1554
+
1555
+ let argsType = hasArguments
1556
+ ? this . convertName (
1557
+ parentName +
1558
+ ( this . config . addUnderscoreToArgsType ? '_' : '' ) +
1559
+ this . convertName ( typeName , {
1560
+ useTypesPrefix : false ,
1561
+ useTypesSuffix : false ,
1562
+ } ) +
1563
+ 'Args' ,
1564
+ {
1565
+ useTypesPrefix : true ,
1566
+ } ,
1567
+ true
1568
+ )
1569
+ : null ;
1570
+
1571
+ const avoidInputsOptionals = this . config . avoidOptionals . inputValue ;
1572
+
1573
+ if ( argsType !== null ) {
1574
+ const argsToForceRequire = original . arguments . filter (
1575
+ arg => ! ! arg . defaultValue || arg . type . kind === 'NonNullType'
1576
+ ) ;
1577
+
1578
+ if ( argsToForceRequire . length > 0 ) {
1579
+ argsType = this . applyRequireFields ( argsType , argsToForceRequire ) ;
1580
+ } else if ( original . arguments . length > 0 && avoidInputsOptionals !== true ) {
1581
+ argsType = this . applyOptionalFields ( argsType , original . arguments ) ;
1582
+ }
1583
+ }
1552
1584
1553
- const avoidInputsOptionals = this . config . avoidOptionals . inputValue ;
1585
+ const parentTypeSignature = this . _federation . transformFieldParentType ( {
1586
+ fieldNode : original ,
1587
+ parentType,
1588
+ parentTypeSignature : this . getParentTypeForSignature ( node ) ,
1589
+ federationTypeSignature : 'FederationType' ,
1590
+ } ) ;
1554
1591
1555
- if ( argsType !== null ) {
1556
- const argsToForceRequire = original . arguments . filter (
1557
- arg => ! ! arg . defaultValue || arg . type . kind === 'NonNullType'
1558
- ) ;
1592
+ const { mappedTypeKey, resolverType } = ( ( ) : { mappedTypeKey : string ; resolverType : string } => {
1593
+ const baseType = getBaseTypeNode ( original . type ) ;
1594
+ const realType = baseType . name . value ;
1595
+ const typeToUse = this . getTypeToUse ( realType ) ;
1596
+ /**
1597
+ * Turns GraphQL type to TypeScript types (`mappedType`) e.g.
1598
+ * - String! -> ResolversTypes['String']>
1599
+ * - String -> Maybe<ResolversTypes['String']>
1600
+ * - [String] -> Maybe<Array<Maybe<ResolversTypes['String']>>>
1601
+ * - [String!]! -> Array<ResolversTypes['String']>
1602
+ */
1603
+ const mappedType = this . _variablesTransformer . wrapAstTypeWithModifiers ( typeToUse , original . type ) ;
1604
+
1605
+ const subscriptionType = this . _schema . getSubscriptionType ( ) ;
1606
+ const isSubscriptionType = subscriptionType && subscriptionType . name === parentName ;
1607
+
1608
+ if ( isSubscriptionType ) {
1609
+ return {
1610
+ mappedTypeKey : `${ mappedType } , "${ typeName } "` ,
1611
+ resolverType : 'SubscriptionResolver' ,
1612
+ } ;
1613
+ }
1559
1614
1560
- if ( argsToForceRequire . length > 0 ) {
1561
- argsType = this . applyRequireFields ( argsType , argsToForceRequire ) ;
1562
- } else if ( original . arguments . length > 0 && avoidInputsOptionals !== true ) {
1563
- argsType = this . applyOptionalFields ( argsType , original . arguments ) ;
1564
- }
1565
- }
1615
+ const directiveMappings =
1616
+ node . directives
1617
+ ?. map ( directive => this . _directiveResolverMappings [ directive . name as any ] )
1618
+ . filter ( Boolean )
1619
+ . reverse ( ) ?? [ ] ;
1566
1620
1567
- const parentTypeSignature = this . _federation . transformFieldParentType ( {
1568
- fieldNode : original ,
1569
- parentType,
1570
- parentTypeSignature : this . getParentTypeForSignature ( node ) ,
1571
- federationTypeSignature : 'FederationType' ,
1572
- } ) ;
1573
-
1574
- const { mappedTypeKey, resolverType } = ( ( ) : { mappedTypeKey : string ; resolverType : string } => {
1575
- const baseType = getBaseTypeNode ( original . type ) ;
1576
- const realType = baseType . name . value ;
1577
- const typeToUse = this . getTypeToUse ( realType ) ;
1578
- /**
1579
- * Turns GraphQL type to TypeScript types (`mappedType`) e.g.
1580
- * - String! -> ResolversTypes['String']>
1581
- * - String -> Maybe<ResolversTypes['String']>
1582
- * - [String] -> Maybe<Array<Maybe<ResolversTypes['String']>>>
1583
- * - [String!]! -> Array<ResolversTypes['String']>
1584
- */
1585
- const mappedType = this . _variablesTransformer . wrapAstTypeWithModifiers ( typeToUse , original . type ) ;
1586
-
1587
- const subscriptionType = this . _schema . getSubscriptionType ( ) ;
1588
- const isSubscriptionType = subscriptionType && subscriptionType . name === parentName ;
1589
-
1590
- if ( isSubscriptionType ) {
1591
1621
return {
1592
- mappedTypeKey : ` ${ mappedType } , " ${ node . name } "` ,
1593
- resolverType : 'SubscriptionResolver ',
1622
+ mappedTypeKey : mappedType ,
1623
+ resolverType : directiveMappings [ 0 ] ?? 'Resolver ',
1594
1624
} ;
1595
- }
1625
+ } ) ( ) ;
1626
+
1627
+ const signature : {
1628
+ name : string ;
1629
+ modifier : string ;
1630
+ type : string ;
1631
+ genericTypes : string [ ] ;
1632
+ } = {
1633
+ name : typeName ,
1634
+ modifier : avoidResolverOptionals ? '' : '?' ,
1635
+ type : resolverType ,
1636
+ genericTypes : [ mappedTypeKey , parentTypeSignature , contextType , argsType ] . filter ( f => f ) ,
1637
+ } ;
1596
1638
1597
- const directiveMappings =
1598
- node . directives
1599
- ?. map ( directive => this . _directiveResolverMappings [ directive . name as any ] )
1600
- . filter ( Boolean )
1601
- . reverse ( ) ?? [ ] ;
1639
+ if ( this . _federation . isResolveReferenceField ( node ) ) {
1640
+ if ( ! this . _federation . getMeta ( ) [ parentType . name ] . hasResolveReference ) {
1641
+ return { value : '' , meta } ;
1642
+ }
1643
+ signature . type = 'ReferenceResolver' ;
1644
+ signature . genericTypes = [ mappedTypeKey , parentTypeSignature , contextType ] ;
1645
+ meta . federation = { isResolveReference : true } ;
1646
+ }
1602
1647
1603
1648
return {
1604
- mappedTypeKey : mappedType ,
1605
- resolverType : directiveMappings [ 0 ] ?? 'Resolver' ,
1649
+ value : indent (
1650
+ `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1651
+ ', '
1652
+ ) } >${ this . getPunctuation ( declarationKind ) } `
1653
+ ) ,
1654
+ meta,
1606
1655
} ;
1607
- } ) ( ) ;
1608
-
1609
- const signature : {
1610
- name : string ;
1611
- modifier : string ;
1612
- type : string ;
1613
- genericTypes : string [ ] ;
1614
- } = {
1615
- name : node . name as any ,
1616
- modifier : avoidResolverOptionals ? '' : '?' ,
1617
- type : resolverType ,
1618
- genericTypes : [ mappedTypeKey , parentTypeSignature , contextType , argsType ] . filter ( f => f ) ,
1619
- } ;
1620
-
1621
- if ( this . _federation . isResolveReferenceField ( node ) ) {
1622
- if ( ! this . _federation . getMeta ( ) [ parentType . name ] . hasResolveReference ) {
1623
- return { value : '' , meta } ;
1624
- }
1625
- signature . type = 'ReferenceResolver' ;
1626
- signature . genericTypes = [ mappedTypeKey , parentTypeSignature , contextType ] ;
1627
- meta . federation = { isResolveReference : true } ;
1628
- }
1629
-
1630
- return {
1631
- value : indent (
1632
- `${ signature . name } ${ signature . modifier } : ${ signature . type } <${ signature . genericTypes . join (
1633
- ', '
1634
- ) } >${ this . getPunctuation ( declarationKind ) } `
1635
- ) ,
1636
- meta,
1637
- } ;
1656
+ } ,
1638
1657
} ;
1639
1658
}
1640
1659
@@ -1707,12 +1726,17 @@ export class BaseResolversVisitor<
1707
1726
return `Partial<${ argsType } >` ;
1708
1727
}
1709
1728
1710
- ObjectTypeDefinition ( node : ObjectTypeDefinitionNode ) : string {
1729
+ ObjectTypeDefinition ( node : ObjectTypeDefinitionNode ) : string | null {
1730
+ const typeName = node . name as unknown as string ;
1731
+ const fieldsToGenerate = this . _federation . findFieldNodesToGenerate ( { node } ) ;
1732
+ if ( fieldsToGenerate . length === 0 ) {
1733
+ return null ;
1734
+ }
1735
+
1711
1736
const declarationKind = 'type' ;
1712
1737
const name = this . convertName ( node , {
1713
1738
suffix : this . config . resolverTypeSuffix ,
1714
1739
} ) ;
1715
- const typeName = node . name as any as string ;
1716
1740
const parentType = this . getParentTypeToUse ( typeName ) ;
1717
1741
1718
1742
const rootType = ( ( ) : false | 'query' | 'mutation' | 'subscription' => {
@@ -1728,15 +1752,17 @@ export class BaseResolversVisitor<
1728
1752
return false ;
1729
1753
} ) ( ) ;
1730
1754
1731
- const fieldsContent = ( node . fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f => {
1732
- return f (
1733
- typeName ,
1734
- ( rootType === 'query' && this . config . avoidOptionals . query ) ||
1735
- ( rootType === 'mutation' && this . config . avoidOptionals . mutation ) ||
1736
- ( rootType === 'subscription' && this . config . avoidOptionals . subscription ) ||
1737
- ( rootType === false && this . config . avoidOptionals . resolvers )
1738
- ) . value ;
1739
- } ) ;
1755
+ const fieldsContent = ( node . fields as unknown as FieldDefinitionResult [ ] )
1756
+ . map ( ( { printContent } ) => {
1757
+ return printContent (
1758
+ node ,
1759
+ ( rootType === 'query' && this . config . avoidOptionals . query ) ||
1760
+ ( rootType === 'mutation' && this . config . avoidOptionals . mutation ) ||
1761
+ ( rootType === 'subscription' && this . config . avoidOptionals . subscription ) ||
1762
+ ( rootType === false && this . config . avoidOptionals . resolvers )
1763
+ ) . value ;
1764
+ } )
1765
+ . filter ( v => v ) ;
1740
1766
1741
1767
if ( ! rootType && this . _parsedSchemaMeta . typesWithIsTypeOf [ typeName ] ) {
1742
1768
fieldsContent . push (
@@ -1748,6 +1774,10 @@ export class BaseResolversVisitor<
1748
1774
) ;
1749
1775
}
1750
1776
1777
+ if ( fieldsContent . length === 0 ) {
1778
+ return null ;
1779
+ }
1780
+
1751
1781
const genericTypes : string [ ] = [
1752
1782
`ContextType = ${ this . config . contextType . type } ` ,
1753
1783
this . transformParentGenericType ( parentType ) ,
@@ -1958,8 +1988,8 @@ export class BaseResolversVisitor<
1958
1988
1959
1989
// An Interface in Federation may have the additional __resolveReference resolver, if resolvable.
1960
1990
// So, we filter out the normal fields declared on the Interface and add the __resolveReference resolver.
1961
- const fields = ( node . fields as unknown as FieldDefinitionPrintFn [ ] ) . map ( f =>
1962
- f ( typeName , this . config . avoidOptionals . resolvers )
1991
+ const fields = ( node . fields as unknown as FieldDefinitionResult [ ] ) . map ( ( { printContent } ) =>
1992
+ printContent ( node , this . config . avoidOptionals . resolvers )
1963
1993
) ;
1964
1994
for ( const field of fields ) {
1965
1995
if ( field . meta . federation ?. isResolveReference ) {
0 commit comments