@@ -149,7 +149,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
149149
150150 // Register builtin types
151151 for ( const name of [
152- 'string' , 'boolean' , 'number' , 'null'
152+ 'string' , 'boolean' , 'number' , 'null' , 'void' , 'binary'
153153 ] ) {
154154 const typeName = {
155155 namespace : '_builtins' ,
@@ -546,33 +546,29 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
546546 }
547547
548548 function validateTypeAlias ( typeDef : model . TypeAlias ) : void {
549- const openGenerics = new Set ( typeDef . generics ?. map ( t => t . name ) )
549+ const openGenerics = openGenericSet ( typeDef )
550550
551551 if ( typeDef . variants != null ) {
552- if ( typeDef . generics != null && typeDef . generics . length !== 0 ) {
553- modelError ( 'A tagged union should not have generic parameters' )
554- }
555-
556552 if ( typeDef . type . kind !== 'union_of' ) {
557553 modelError ( 'The "variants" tag only applies to unions' )
558554 } else {
559- validateTaggedUnion ( typeDef . name , typeDef . type , typeDef . variants )
555+ validateTaggedUnion ( typeDef . name , typeDef . type , typeDef . variants , openGenerics )
560556 }
561557 } else {
562558 validateValueOf ( typeDef . type , openGenerics )
563559 }
564560 }
565561
566- function validateTaggedUnion ( parentName : TypeName , valueOf : model . UnionOf , variants : model . InternalTag | model . ExternalTag | model . Untagged ) : void {
562+ function validateTaggedUnion ( parentName : TypeName , valueOf : model . UnionOf , variants : model . InternalTag | model . ExternalTag | model . Untagged , openGenerics : Set < string > ) : void {
567563 if ( variants . kind === 'external_tag' ) {
568564 // All items must have a 'variant' attribute
569- const items = flattenUnionMembers ( valueOf )
565+ const items = flattenUnionMembers ( valueOf , openGenerics )
570566
571567 for ( const item of items ) {
572568 if ( item . kind !== 'instance_of' ) {
573569 modelError ( 'Items of externally tagged unions must be types with a "variant_tag" annotation' )
574570 } else {
575- validateTypeRef ( item . type , undefined , new Set < string > ( ) )
571+ validateTypeRef ( item . type , item . generics , openGenerics )
576572 const type = getTypeDef ( item . type )
577573 if ( type == null ) {
578574 modelError ( `Type ${ fqn ( item . type ) } not found` )
@@ -587,13 +583,13 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
587583 }
588584 } else if ( variants . kind === 'internal_tag' ) {
589585 const tagName = variants . tag
590- const items = flattenUnionMembers ( valueOf )
586+ const items = flattenUnionMembers ( valueOf , openGenerics )
591587
592588 for ( const item of items ) {
593589 if ( item . kind !== 'instance_of' ) {
594590 modelError ( 'Items of internally tagged unions must be type references' )
595591 } else {
596- validateTypeRef ( item . type , undefined , new Set < string > ( ) )
592+ validateTypeRef ( item . type , item . generics , openGenerics )
597593 const type = getTypeDef ( item . type )
598594 if ( type == null ) {
599595 modelError ( `Type ${ fqn ( item . type ) } not found` )
@@ -606,7 +602,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
606602 }
607603 }
608604
609- validateValueOf ( valueOf , new Set ( ) )
605+ validateValueOf ( valueOf , openGenerics )
610606 } else if ( variants . kind === 'untagged' ) {
611607 if ( fqn ( parentName ) !== '_types.query_dsl:DecayFunction' &&
612608 fqn ( parentName ) !== '_types.query_dsl:DistanceFeatureQuery' &&
@@ -619,15 +615,15 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
619615 modelError ( `Type ${ fqn ( variants . untypedVariant ) } not found` )
620616 }
621617
622- const items = flattenUnionMembers ( valueOf )
618+ const items = flattenUnionMembers ( valueOf , openGenerics )
623619 const baseTypes = new Set < string > ( )
624620 let foundUntyped = false
625621
626622 for ( const item of items ) {
627623 if ( item . kind !== 'instance_of' ) {
628624 modelError ( 'Items of type untagged unions must be type references' )
629625 } else {
630- validateTypeRef ( item . type , undefined , new Set < string > ( ) )
626+ validateTypeRef ( item . type , item . generics , openGenerics )
631627 const type = getTypeDef ( item . type )
632628 if ( type == null ) {
633629 modelError ( `Type ${ fqn ( item . type ) } not found` )
@@ -679,7 +675,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
679675 // -----------------------------------------------------------------------------------------------
680676 // Constituents of type definitions
681677
682- function openGenericSet ( typeDef : model . Request | model . Response | model . Interface ) : Set < string > {
678+ function openGenericSet ( typeDef : model . Request | model . Response | model . Interface | model . TypeAlias ) : Set < string > {
683679 return new Set ( ( typeDef . generics ?? [ ] ) . map ( name => fqn ( name ) ) )
684680 }
685681
@@ -884,7 +880,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
884880 } else {
885881 // tagged union: the discriminant tells us what to look for, check each member in isolation
886882 assert ( typeDef . type . kind === 'union_of' , 'Variants are only allowed on union_of type aliases' )
887- for ( const item of flattenUnionMembers ( typeDef . type ) ) {
883+ for ( const item of flattenUnionMembers ( typeDef . type , new Set ( ) ) ) {
888884 validateValueOfJsonEvents ( item )
889885 }
890886
@@ -899,13 +895,13 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
899895 }
900896
901897 /** Build the flattened item list of potentially nested unions (this is used for large unions) */
902- function flattenUnionMembers ( union : model . UnionOf ) : model . ValueOf [ ] {
898+ function flattenUnionMembers ( union : model . UnionOf , openGenerics : Set < string > ) : model . ValueOf [ ] {
903899 const allItems = new Array < model . ValueOf > ( )
904900
905901 function collectItems ( items : model . ValueOf [ ] ) : void {
906902 for ( const item of items ) {
907903 if ( item . kind !== 'instance_of' ) {
908- validateValueOf ( item , new Set < string > ( ) )
904+ validateValueOf ( item , openGenerics )
909905 allItems . push ( item )
910906 } else {
911907 const itemType = getTypeDef ( item . type )
@@ -915,7 +911,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
915911 // Recurse in nested union
916912 collectItems ( itemType . type . items )
917913 } else {
918- validateValueOf ( item , new Set < string > ( ) )
914+ validateValueOf ( item , openGenerics )
919915 allItems . push ( item )
920916 }
921917 }
0 commit comments