55 DefinitionNode ,
66 DocumentNode ,
77 EnumTypeDefinitionNode ,
8+ EnumValueDefinitionNode ,
89 FieldDefinitionNode ,
910 InterfaceTypeDefinitionNode ,
1011 Kind ,
@@ -423,7 +424,7 @@ export class FroidSchema {
423424 *
424425 * Enum values with @inaccessible tags are stripped in Federation 2.
425426 *
426- * Contract @tag directives are NOt applied when generating non-native scalar
427+ * Contract @tag directives are NOT applied when generating non-native scalar
427428 * return types in the Froid subgraph. Contract @tag directives are merged
428429 * during supergraph composition so Froid subgraph can rely on @tag directives
429430 * defined by the owning subgraph(s), UNLESS an enum value is marked @inaccessible,
@@ -450,8 +451,12 @@ export class FroidSchema {
450451 } ) ;
451452 } ) ;
452453
453- // De-dupe non-native scalar return types. Any definitions of scalars and enums
454- // will work since they can be guaranteed to be consistent across subgraphs
454+ // De-dupe non-native scalar return types.
455+ //
456+ // Any definitions of scalars and enums will work since they are
457+ // consistent across subgraphs.
458+ //
459+ // Enums must be combined across all subgraphs since they can deviate.
455460 const nonNativeScalarFieldTypes = new Map <
456461 string ,
457462 SupportedFroidReturnTypes
@@ -462,30 +467,60 @@ export class FroidSchema {
462467 ) as SupportedFroidReturnTypes [ ]
463468 ) . forEach ( ( nonNativeScalarType ) => {
464469 const returnTypeName = nonNativeScalarType . name . value ;
465- if (
466- ! nonNativeScalarDefinitionNames . has ( returnTypeName ) ||
467- nonNativeScalarFieldTypes . has ( returnTypeName )
468- ) {
470+ if ( ! nonNativeScalarDefinitionNames . has ( returnTypeName ) ) {
469471 // Don't get types that are not returned in froid schema
470472 return ;
471473 }
472474
473475 if ( nonNativeScalarType . kind === Kind . ENUM_TYPE_DEFINITION ) {
476+ let finalEnumValues : readonly EnumValueDefinitionNode [ ] = [ ] ;
477+
478+ // Collect the enum values from the enum that is currently being inspected,
479+ // omitting all applied directives.
474480 const enumValues = nonNativeScalarType . values ?. map ( ( enumValue ) => ( {
475481 ...enumValue ,
476- directives : enumValue . directives ?. filter (
477- ( directive ) => directive . name . value === 'inaccessible'
478- ) ,
482+ directives : [ ] ,
479483 } ) ) ;
484+
485+ // Get the enum definition we've created so far if one exists
486+ const existingEnum = nonNativeScalarFieldTypes . get (
487+ returnTypeName
488+ ) as EnumTypeDefinitionNode ;
489+
490+ // If there are existing enum values, use them for the final enum
491+ if ( existingEnum ?. values ) {
492+ finalEnumValues = existingEnum . values ;
493+ }
494+
495+ // If there are enum values associated with the enum definition
496+ // we're currently inspecting, include them in the final list of
497+ // enum values
498+ if ( enumValues ) {
499+ // Deduplicate enum values
500+ const dedupedEnumValues = enumValues . filter (
501+ ( value ) =>
502+ ! finalEnumValues . some (
503+ ( existingValue ) => existingValue . name . value === value . name . value
504+ )
505+ ) ;
506+ // Update the final enum value list
507+ finalEnumValues = [ ...finalEnumValues , ...dedupedEnumValues ] ;
508+ }
509+
480510 nonNativeScalarFieldTypes . set ( returnTypeName , {
481511 ...nonNativeScalarType ,
482- values : enumValues ,
512+ values : finalEnumValues . length ? finalEnumValues : undefined ,
483513 directives : [ ] ,
484514 description : undefined ,
485515 } as EnumTypeDefinitionNode ) ;
486516 return ;
487517 }
488518
519+ if ( nonNativeScalarFieldTypes . has ( returnTypeName ) ) {
520+ // Don't duplicate scalars
521+ return ;
522+ }
523+
489524 nonNativeScalarFieldTypes . set ( returnTypeName , {
490525 ...nonNativeScalarType ,
491526 description : undefined ,
0 commit comments