@@ -15,45 +15,22 @@ public sealed class MinimalApiGenerator : IIncrementalGenerator
1515 private const string BaseNamespace = "Microsoft.AspNetCore.Generated" ;
1616 private const string AttributesNamespace = $ "{ BaseNamespace } .Attributes";
1717
18- private const string MapGetAttributeName = "MapGetAttribute" ;
19- private const string MapGetAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapGetAttributeName } ";
20- private const string MapGetAttributeHint = $ "{ MapGetAttributeFullyQualifiedName } .gs.cs";
21-
22- private const string MapPostAttributeName = "MapPostAttribute" ;
23- private const string MapPostAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapPostAttributeName } ";
24- private const string MapPostAttributeHint = $ "{ MapPostAttributeFullyQualifiedName } .gs.cs";
25-
26- private const string MapPutAttributeName = "MapPutAttribute" ;
27- private const string MapPutAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapPutAttributeName } ";
28- private const string MapPutAttributeHint = $ "{ MapPutAttributeFullyQualifiedName } .gs.cs";
29-
30- private const string MapDeleteAttributeName = "MapDeleteAttribute" ;
31- private const string MapDeleteAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapDeleteAttributeName } ";
32- private const string MapDeleteAttributeHint = $ "{ MapDeleteAttributeFullyQualifiedName } .gs.cs";
33-
34- private const string MapOptionsAttributeName = "MapOptionsAttribute" ;
35- private const string MapOptionsAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapOptionsAttributeName } ";
36- private const string MapOptionsAttributeHint = $ "{ MapOptionsAttributeFullyQualifiedName } .gs.cs";
37-
38- private const string MapHeadAttributeName = "MapHeadAttribute" ;
39- private const string MapHeadAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapHeadAttributeName } ";
40- private const string MapHeadAttributeHint = $ "{ MapHeadAttributeFullyQualifiedName } .gs.cs";
41-
42- private const string MapPatchAttributeName = "MapPatchAttribute" ;
43- private const string MapPatchAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapPatchAttributeName } ";
44- private const string MapPatchAttributeHint = $ "{ MapPatchAttributeFullyQualifiedName } .gs.cs";
45-
46- private const string MapQueryAttributeName = "MapQueryAttribute" ;
47- private const string MapQueryAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapQueryAttributeName } ";
48- private const string MapQueryAttributeHint = $ "{ MapQueryAttributeFullyQualifiedName } .gs.cs";
49-
50- private const string MapTraceAttributeName = "MapTraceAttribute" ;
51- private const string MapTraceAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapTraceAttributeName } ";
52- private const string MapTraceAttributeHint = $ "{ MapTraceAttributeFullyQualifiedName } .gs.cs";
53-
54- private const string MapConnectAttributeName = "MapConnectAttribute" ;
55- private const string MapConnectAttributeFullyQualifiedName = $ "{ AttributesNamespace } .{ MapConnectAttributeName } ";
56- private const string MapConnectAttributeHint = $ "{ MapConnectAttributeFullyQualifiedName } .gs.cs";
18+ private static readonly ImmutableArray < HttpAttributeDefinition > HttpAttributeDefinitions =
19+ [
20+ CreateHttpAttributeDefinition ( "MapGetAttribute" , "GET" ) ,
21+ CreateHttpAttributeDefinition ( "MapPostAttribute" , "POST" ) ,
22+ CreateHttpAttributeDefinition ( "MapPutAttribute" , "PUT" ) ,
23+ CreateHttpAttributeDefinition ( "MapPatchAttribute" , "PATCH" ) ,
24+ CreateHttpAttributeDefinition ( "MapDeleteAttribute" , "DELETE" ) ,
25+ CreateHttpAttributeDefinition ( "MapOptionsAttribute" , "OPTIONS" ) ,
26+ CreateHttpAttributeDefinition ( "MapHeadAttribute" , "HEAD" ) ,
27+ CreateHttpAttributeDefinition ( "MapQueryAttribute" , "QUERY" ) ,
28+ CreateHttpAttributeDefinition ( "MapTraceAttribute" , "TRACE" ) ,
29+ CreateHttpAttributeDefinition ( "MapConnectAttribute" , "CONNECT" ) ,
30+ ] ;
31+
32+ private static readonly ImmutableDictionary < string , HttpAttributeDefinition > HttpAttributeDefinitionsByName =
33+ HttpAttributeDefinitions . ToImmutableDictionary ( static definition => definition . Name ) ;
5734
5835 private const string NameAttributeNamedParameter = "Name" ;
5936 private const string SummaryAttributeNamedParameter = "Summary" ;
@@ -116,103 +93,55 @@ public sealed class MinimalApiGenerator : IIncrementalGenerator
11693 #nullable enable
11794 """ ;
11895
96+ private static HttpAttributeDefinition CreateHttpAttributeDefinition ( string attributeName , string verb )
97+ {
98+ var fullyQualifiedName = $ "{ AttributesNamespace } .{ attributeName } ";
99+ return new HttpAttributeDefinition ( attributeName , fullyQualifiedName , $ "{ fullyQualifiedName } .gs.cs", verb ) ;
100+ }
101+
119102 public void Initialize ( IncrementalGeneratorInitializationContext context )
120103 {
121104 context . RegisterPostInitializationOutput ( RegisterAttributes ) ;
122105
123- var getRequestHandlers = context . SyntaxProvider
124- . ForAttributeWithMetadataName ( MapGetAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
125- . WhereNotNull ( )
126- . Collect ( ) ;
127-
128- var postRequestHandlers = context . SyntaxProvider
129- . ForAttributeWithMetadataName ( MapPostAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
130- . WhereNotNull ( )
131- . Collect ( ) ;
132-
133- var putRequestHandlers = context . SyntaxProvider
134- . ForAttributeWithMetadataName ( MapPutAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
135- . WhereNotNull ( )
136- . Collect ( ) ;
137-
138- var deleteRequestHandlers = context . SyntaxProvider
139- . ForAttributeWithMetadataName ( MapDeleteAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
140- . WhereNotNull ( )
141- . Collect ( ) ;
142-
143- var optionsRequestHandlers = context . SyntaxProvider
144- . ForAttributeWithMetadataName ( MapOptionsAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
145- . WhereNotNull ( )
146- . Collect ( ) ;
147-
148- var headRequestHandlers = context . SyntaxProvider
149- . ForAttributeWithMetadataName ( MapHeadAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
150- . WhereNotNull ( )
151- . Collect ( ) ;
152-
153- var patchRequestHandlers = context . SyntaxProvider
154- . ForAttributeWithMetadataName ( MapPatchAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
155- . WhereNotNull ( )
156- . Collect ( ) ;
157-
158- var queryRequestHandlers = context . SyntaxProvider
159- . ForAttributeWithMetadataName ( MapQueryAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
160- . WhereNotNull ( )
161- . Collect ( ) ;
162-
163- var traceRequestHandlers = context . SyntaxProvider
164- . ForAttributeWithMetadataName ( MapTraceAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
165- . WhereNotNull ( )
166- . Collect ( ) ;
167-
168- var connectRequestHandlers = context . SyntaxProvider
169- . ForAttributeWithMetadataName ( MapConnectAttributeFullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
170- . WhereNotNull ( )
171- . Collect ( ) ;
172-
173- var requestHandlers = getRequestHandlers . Combine ( postRequestHandlers )
174- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
175- . Combine ( putRequestHandlers )
176- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
177- . Combine ( patchRequestHandlers )
178- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
179- . Combine ( deleteRequestHandlers )
180- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
181- . Combine ( optionsRequestHandlers )
182- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
183- . Combine ( headRequestHandlers )
184- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
185- . Combine ( queryRequestHandlers )
186- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
187- . Combine ( traceRequestHandlers )
188- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) )
189- . Combine ( connectRequestHandlers )
190- . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) ) ;
106+ var requestHandlerProviders = ImmutableArray . CreateBuilder < IncrementalValueProvider < ImmutableArray < RequestHandler > > > (
107+ HttpAttributeDefinitions . Length ) ;
108+
109+ foreach ( var definition in HttpAttributeDefinitions )
110+ {
111+ var handlers = context . SyntaxProvider
112+ . ForAttributeWithMetadataName ( definition . FullyQualifiedName , RequestHandlerFilter , RequestHandlerTransform )
113+ . WhereNotNull ( )
114+ . Collect ( ) ;
115+
116+ requestHandlerProviders . Add ( handlers ) ;
117+ }
118+
119+ var requestHandlers = CombineRequestHandlers ( requestHandlerProviders . MoveToImmutable ( ) ) ;
191120
192121 context . RegisterSourceOutput ( requestHandlers , GenerateSource ) ;
193122 }
194123
195- private static void RegisterAttributes ( IncrementalGeneratorPostInitializationContext context )
124+ private static IncrementalValueProvider < ImmutableArray < RequestHandler > > CombineRequestHandlers (
125+ ImmutableArray < IncrementalValueProvider < ImmutableArray < RequestHandler > > > handlerProviders )
196126 {
197- // Definitions for HTTP method attributes
198- var httpAttributes = new [ ]
127+ if ( handlerProviders . IsDefaultOrEmpty )
128+ throw new InvalidOperationException ( "No HTTP attribute definitions were provided." ) ;
129+
130+ var combined = handlerProviders [ 0 ] ;
131+ for ( var i = 1 ; i < handlerProviders . Length ; i ++ )
199132 {
200- ( Name : MapGetAttributeName , FullyQualified : MapGetAttributeFullyQualifiedName , Hint : MapGetAttributeHint , Verb : "GET" ) ,
201- ( Name : MapPostAttributeName , FullyQualified : MapPostAttributeFullyQualifiedName , Hint : MapPostAttributeHint , Verb : "POST" ) ,
202- ( Name : MapPutAttributeName , FullyQualified : MapPutAttributeFullyQualifiedName , Hint : MapPutAttributeHint , Verb : "PUT" ) ,
203- ( Name : MapDeleteAttributeName , FullyQualified : MapDeleteAttributeFullyQualifiedName , Hint : MapDeleteAttributeHint , Verb : "DELETE" ) ,
204- ( Name : MapOptionsAttributeName , FullyQualified : MapOptionsAttributeFullyQualifiedName , Hint : MapOptionsAttributeHint , Verb : "OPTIONS" ) ,
205- ( Name : MapHeadAttributeName , FullyQualified : MapHeadAttributeFullyQualifiedName , Hint : MapHeadAttributeHint , Verb : "HEAD" ) ,
206- ( Name : MapPatchAttributeName , FullyQualified : MapPatchAttributeFullyQualifiedName , Hint : MapPatchAttributeHint , Verb : "PATCH" ) ,
207- ( Name : MapQueryAttributeName , FullyQualified : MapQueryAttributeFullyQualifiedName , Hint : MapQueryAttributeHint , Verb : "QUERY" ) ,
208- ( Name : MapTraceAttributeName , FullyQualified : MapTraceAttributeFullyQualifiedName , Hint : MapTraceAttributeHint , Verb : "TRACE" ) ,
209- ( Name : MapConnectAttributeName , FullyQualified : MapConnectAttributeFullyQualifiedName , Hint : MapConnectAttributeHint , Verb : "CONNECT" ) ,
210- } ;
133+ combined = combined . Combine ( handlerProviders [ i ] ) . Select ( static ( x , _ ) => x . Left . AddRange ( x . Right ) ) ;
134+ }
211135
212- foreach ( var ( name , _, hint , verb ) in httpAttributes )
136+ return combined ;
137+ }
138+
139+ private static void RegisterAttributes ( IncrementalGeneratorPostInitializationContext context )
140+ {
141+ foreach ( var definition in HttpAttributeDefinitions )
213142 {
214- var source = GenerateHttpAttributeSource ( FileHeader , AttributesNamespace , name , verb ) ;
215- context . AddSource ( hint , SourceText . From ( source , Encoding . UTF8 ) ) ;
143+ var source = GenerateHttpAttributeSource ( FileHeader , AttributesNamespace , definition . Name , definition . Verb ) ;
144+ context . AddSource ( definition . Hint , SourceText . From ( source , Encoding . UTF8 ) ) ;
216145 }
217146
218147 // RequireAuthorization
@@ -646,20 +575,9 @@ CancellationToken cancellationToken
646575
647576 var attributeName = attribute . AttributeClass ? . Name ?? "" ;
648577
649- var httpMethod = attributeName switch
650- {
651- MapGetAttributeName => "Get" ,
652- MapPostAttributeName => "Post" ,
653- MapPutAttributeName => "Put" ,
654- MapDeleteAttributeName => "Delete" ,
655- MapOptionsAttributeName => "OPTIONS" ,
656- MapHeadAttributeName => "HEAD" ,
657- MapPatchAttributeName => "Patch" ,
658- MapQueryAttributeName => "QUERY" ,
659- MapTraceAttributeName => "TRACE" ,
660- MapConnectAttributeName => "CONNECT" ,
661- _ => "" ,
662- } ;
578+ var httpMethod = HttpAttributeDefinitionsByName . TryGetValue ( attributeName , out var definition )
579+ ? definition . Verb
580+ : "" ;
663581
664582 var pattern = ( attribute . ConstructorArguments . Length > 0 ? attribute . ConstructorArguments [ 0 ] . Value as string : "" ) ?? "" ;
665583
@@ -1432,13 +1350,15 @@ private static void GenerateMapRequestHandler(StringBuilder source, RequestHandl
14321350 source . AppendLine ( "(" ) ;
14331351 }
14341352
1353+ var mapMethodSuffix = GetMapMethodSuffix ( requestHandler . HttpMethod ) ;
1354+
14351355 source . Append ( indent ) ;
14361356 source . Append ( "builder.Map" ) ;
1437- source . Append ( requestHandler . HttpMethod is "Get" or "Post" or "Put" or "Delete" or "Patch" ? requestHandler . HttpMethod : "Methods" ) ;
1357+ source . Append ( mapMethodSuffix ?? "Methods" ) ;
14381358 source . Append ( '(' ) ;
14391359 source . Append ( StringLiteral ( requestHandler . Pattern ) ) ;
14401360 source . Append ( ", " ) ;
1441- if ( requestHandler . HttpMethod is "OPTIONS" or "HEAD" or "TRACE" or "CONNECT" or "QUERY" )
1361+ if ( mapMethodSuffix is null )
14421362 {
14431363 source . Append ( "new[] { \" " ) ;
14441364 source . Append ( requestHandler . HttpMethod ) ;
@@ -1638,6 +1558,19 @@ private static void GenerateMapRequestHandler(StringBuilder source, RequestHandl
16381558 }
16391559 }
16401560
1561+ private static string ? GetMapMethodSuffix ( string httpMethod )
1562+ {
1563+ return httpMethod switch
1564+ {
1565+ "GET" => "Get" ,
1566+ "POST" => "Post" ,
1567+ "PUT" => "Put" ,
1568+ "DELETE" => "Delete" ,
1569+ "PATCH" => "Patch" ,
1570+ _ => null ,
1571+ } ;
1572+ }
1573+
16411574 private static string GetBindingSourceAttribute ( BindingSource source , string ? key )
16421575 {
16431576 return source switch
@@ -1900,6 +1833,8 @@ _ when char.IsControl(c) => "\\u" + ((int)c).ToString("x4", CultureInfo.Invarian
19001833 } ;
19011834 }
19021835
1836+ private readonly record struct HttpAttributeDefinition ( string Name , string FullyQualifiedName , string Hint , string Verb ) ;
1837+
19031838 private readonly record struct RequestHandler (
19041839 RequestHandlerClass Class ,
19051840 RequestHandlerMethod Method ,
0 commit comments