@@ -7,11 +7,12 @@ internal static class ExtensionMethodGenerator
77 /// <param name="document">The OpenAPI document.</param>
88 /// <param name="namespace">The namespace for generated code.</param>
99 /// <param name="className">The class name for extension methods.</param>
10- /// <param name="baseUrl">The base URL for API requests.</param>
10+ /// <param name="baseUrl">The base URL for API requests (not used, kept for API compatibility) .</param>
1111 /// <param name="basePath">The base path for API requests.</param>
1212 /// <param name="jsonNamingPolicy">JSON naming policy (camelCase, PascalCase, snake_case).</param>
1313 /// <param name="caseInsensitive">Enable case-insensitive JSON deserialization.</param>
1414 /// <returns>Tuple containing the extension methods code and type aliases code.</returns>
15+ #pragma warning disable IDE0060 // Remove unused parameter
1516 public static ( string ExtensionMethods , string TypeAliases ) GenerateExtensionMethods (
1617 OpenApiDocument document ,
1718 string @namespace ,
@@ -21,6 +22,7 @@ public static (string ExtensionMethods, string TypeAliases) GenerateExtensionMet
2122 string jsonNamingPolicy = "camelCase" ,
2223 bool caseInsensitive = true
2324 )
25+ #pragma warning restore IDE0060 // Remove unused parameter
2426 {
2527 var groupedMethods =
2628 new Dictionary < string , List < ( string PublicMethod , string PrivateDelegate ) > > ( ) ;
@@ -77,6 +79,7 @@ when s.Equals("snake_case", StringComparison.OrdinalIgnoreCase)
7779 var caseInsensitiveCode = caseInsensitive ? "true" : "false" ;
7880
7981 var extensionMethodsCode = $$ """
82+ #nullable enable
8083 using System;
8184 using System.Collections.Generic;
8285 using System.Net.Http;
@@ -251,6 +254,8 @@ string summary
251254 : operationType == HttpMethod . Put ? "Put"
252255 : operationType == HttpMethod . Delete ? "Delete"
253256 : operationType == HttpMethod . Patch ? "Patch"
257+ : operationType == HttpMethod . Head ? "Head"
258+ : operationType == HttpMethod . Options ? "Options"
254259 : operationType . Method ;
255260 var createMethod = $ "Create{ verb } ";
256261 var delegateType = $ "{ verb } Async";
@@ -265,7 +270,7 @@ string summary
265270 var deserializeMethod = isDelete ? "_deserializeUnit" : deserializer ;
266271
267272 var privateDelegate = $$ """
268- private static {{ delegateType }} <{{ resultResponseType }} , string, Unit> {{ privateFunctionName }} { get; } =
273+ private static {{ delegateType }} <{{ resultResponseType }} , string, Unit> {{ privateFunctionName }} () =>
269274 RestClient.Net.HttpClientFactoryExtensions.{{ createMethod }} <{{ resultResponseType }} , string, Unit>(
270275 url: BaseUrl,
271276 buildRequest: static _ => new HttpRequestParts(new RelativeUrl("{{ path }} "), null, null),
@@ -289,7 +294,7 @@ string summary
289294 var deserializeMethod = isDelete ? "_deserializeUnit" : deserializer ;
290295
291296 var privateDelegate = $$ """
292- private static {{ delegateType }} <{{ resultResponseType }} , string, {{ bodyType }} > {{ privateFunctionName }} { get; } =
297+ private static {{ delegateType }} <{{ resultResponseType }} , string, {{ bodyType }} > {{ privateFunctionName }} () =>
293298 RestClient.Net.HttpClientFactoryExtensions.{{ createMethod }} <{{ resultResponseType }} , string, {{ bodyType }} >(
294299 url: BaseUrl,
295300 buildRequest: static body => new HttpRequestParts(new RelativeUrl("{{ path }} "), CreateJsonContent(body), null),
@@ -304,7 +309,7 @@ string summary
304309 this HttpClient httpClient,
305310 {{ bodyType }} body,
306311 CancellationToken ct = default
307- ) => {{ privateFunctionName }} (httpClient, body, ct);
312+ ) => {{ privateFunctionName }} ()( httpClient, body, ct);
308313 """ ;
309314
310315 return ( publicMethod , privateDelegate ) ;
@@ -330,7 +335,7 @@ string summary
330335 ) ;
331336
332337 var privateDelegate = $$ """
333- private static {{ delegateType }} <{{ resultResponseType }} , string, {{ queryParamsType }} > {{ privateFunctionName }} { get; } =
338+ private static {{ delegateType }} <{{ resultResponseType }} , string, {{ queryParamsType }} > {{ privateFunctionName }} () =>
334339 RestClient.Net.HttpClientFactoryExtensions.{{ createMethod }} <{{ resultResponseType }} , string, {{ queryParamsType }} >(
335340 url: BaseUrl,
336341 buildRequest: static param => new HttpRequestParts(new RelativeUrl($"{{ path }} {{ queryStringWithParam }} "), null, null),
@@ -345,7 +350,7 @@ string summary
345350 this HttpClient httpClient,
346351 {{ string . Join ( ", " , queryParams . Select ( q => $ "{ q . Type } { q . Name } ") ) }} ,
347352 CancellationToken ct = default
348- ) => {{ privateFunctionName }} (httpClient, {{ paramInvocation }} , ct);
353+ ) => {{ privateFunctionName }} ()( httpClient, {{ paramInvocation }} , ct);
349354 """ ;
350355
351356 return ( publicMethod , privateDelegate ) ;
@@ -358,7 +363,7 @@ string summary
358363 ? pathParams [ 0 ] . Type
359364 : $ "({ string . Join ( ", " , pathParams . Select ( p => $ "{ p . Type } { p . Name } ") ) } )";
360365 var pathParamsNames = string . Join ( ", " , pathParams . Select ( p => p . Name ) ) ;
361- var lambda = isSinglePathParam ? pathParams [ 0 ] . Name : $ "( { pathParamsNames } ) ";
366+ var lambda = isSinglePathParam ? pathParams [ 0 ] . Name : "param ";
362367 var publicMethodParams = string . Join ( ", " , pathParams . Select ( p => $ "{ p . Type } { p . Name } ") ) ;
363368 var publicMethodInvocation = isSinglePathParam ? pathParamsNames : $ "({ pathParamsNames } )";
364369
@@ -381,17 +386,21 @@ string summary
381386 "&" ,
382387 queryParams . Select ( q => $ "{ q . OriginalName } ={{param.{ q . Name } }}")
383388 ) ;
389+ var sanitizedPath = CodeGenerationHelpers . SanitizePathParameters (
390+ pathExpression ,
391+ parameters
392+ ) ;
384393 var pathWithParam =
385394 isSingleParam && hasPathParams
386- ? pathExpression . Replace (
395+ ? sanitizedPath . Replace (
387396 "{" + parameters . First ( p => p . IsPath ) . Name + "}" ,
388397 "{param}" ,
389398 StringComparison . Ordinal
390399 )
391- : pathExpression . Replace ( "{" , "{param." , StringComparison . Ordinal ) ;
400+ : sanitizedPath . Replace ( "{" , "{param." , StringComparison . Ordinal ) ;
392401
393402 var privateDelegate = $$ """
394- private static {{ delegateType }} <{{ resultResponseType }} , string, {{ allParamsType }} > {{ privateFunctionName }} { get; } =
403+ private static {{ delegateType }} <{{ resultResponseType }} , string, {{ allParamsType }} > {{ privateFunctionName }} =>
395404 RestClient.Net.HttpClientFactoryExtensions.{{ createMethod }} <{{ resultResponseType }} , string, {{ allParamsType }} >(
396405 url: BaseUrl,
397406 buildRequest: static param => new HttpRequestParts(new RelativeUrl($"{{ pathWithParam }} {{ queryStringWithParam }} "), null, null),
@@ -415,12 +424,19 @@ string summary
415424 if ( ! hasBody )
416425 {
417426 var deserializeMethod = isDelete ? "_deserializeUnit" : deserializer ;
427+ var sanitizedPath = CodeGenerationHelpers . SanitizePathParameters (
428+ pathExpression ,
429+ parameters
430+ ) ;
431+ var pathWithParam = isSinglePathParam
432+ ? sanitizedPath
433+ : sanitizedPath . Replace ( "{" , "{param." , StringComparison . Ordinal ) ;
418434
419435 var privateDelegate = $$ """
420- private static {{ delegateType }} <{{ resultResponseType }} , string, {{ pathParamsType }} > {{ privateFunctionName }} { get; } =
436+ private static {{ delegateType }} <{{ resultResponseType }} , string, {{ pathParamsType }} > {{ privateFunctionName }} () =>
421437 RestClient.Net.HttpClientFactoryExtensions.{{ createMethod }} <{{ resultResponseType }} , string, {{ pathParamsType }} >(
422438 url: BaseUrl,
423- buildRequest: static {{ lambda }} => new HttpRequestParts(new RelativeUrl($"{{ pathExpression }} "), null, null),
439+ buildRequest: static {{ lambda }} => new HttpRequestParts(new RelativeUrl($"{{ pathWithParam }} "), null, null),
424440 deserializeSuccess: {{ deserializeMethod }} ,
425441 deserializeError: DeserializeError
426442 );
@@ -432,20 +448,28 @@ string summary
432448 this HttpClient httpClient,
433449 {{ publicMethodParams }} ,
434450 CancellationToken ct = default
435- ) => {{ privateFunctionName }} (httpClient, {{ publicMethodInvocation }} , ct);
451+ ) => {{ privateFunctionName }} ()( httpClient, {{ publicMethodInvocation }} , ct);
436452 """ ;
437453
438454 return ( publicMethod , privateDelegate ) ;
439455 }
440456 else
441457 {
442458 var compositeType = $ "({ pathParamsType } Params, { bodyType } Body)";
443- var pathWithParamInterpolation = CodeGenerationHelpers
444- . PathParameterRegex ( )
445- . Replace ( pathExpression , "{param.Params}" ) ;
459+ var sanitizedPath = CodeGenerationHelpers . SanitizePathParameters (
460+ pathExpression ,
461+ parameters
462+ ) ;
463+ var pathWithParamInterpolation = isSinglePathParam
464+ ? sanitizedPath . Replace (
465+ "{" + pathParams [ 0 ] . Name + "}" ,
466+ "{param.Params}" ,
467+ StringComparison . Ordinal
468+ )
469+ : sanitizedPath . Replace ( "{" , "{param.Params." , StringComparison . Ordinal ) ;
446470
447471 var privateDelegate = $$ """
448- private static {{ delegateType }} <{{ resultResponseType }} , string, {{ compositeType }} > {{ privateFunctionName }} { get; } =
472+ private static {{ delegateType }} <{{ resultResponseType }} , string, {{ compositeType }} > {{ privateFunctionName }} () =>
449473 RestClient.Net.HttpClientFactoryExtensions.{{ createMethod }} <{{ resultResponseType }} , string, {{ compositeType }} >(
450474 url: BaseUrl,
451475 buildRequest: static param => new HttpRequestParts(new RelativeUrl($"{{ pathWithParamInterpolation }} "), CreateJsonContent(param.Body), null),
@@ -460,7 +484,7 @@ string summary
460484 this HttpClient httpClient,
461485 {{ compositeType }} param,
462486 CancellationToken ct = default
463- ) => {{ privateFunctionName }} (httpClient, param, ct);
487+ ) => {{ privateFunctionName }} ()( httpClient, param, ct);
464488 """ ;
465489
466490 return ( publicMethod , privateDelegate ) ;
@@ -488,6 +512,8 @@ string path
488512 : operationType == HttpMethod . Put ? "Update"
489513 : operationType == HttpMethod . Delete ? "Delete"
490514 : operationType == HttpMethod . Patch ? "Patch"
515+ : operationType == HttpMethod . Head ? "Head"
516+ : operationType == HttpMethod . Options ? "Options"
491517 : operationType . Method ;
492518
493519 return $ "{ methodName } { CodeGenerationHelpers . ToPascalCase ( pathPart ) } ";
@@ -591,14 +617,14 @@ _ when responseType.StartsWith("List<", StringComparison.Ordinal) =>
591617 // Generate Ok alias
592618 aliases . Add (
593619 $$ """
594- using Ok{{ aliasName }} = Outcome.Result<{{ qualifiedType }} , Outcome.HttpError<string>>.Ok<{{ qualifiedType }} , Outcome.HttpError<string>>;
620+ global using Ok{{ aliasName }} = Outcome.Result<{{ qualifiedType }} , Outcome.HttpError<string>>.Ok<{{ qualifiedType }} , Outcome.HttpError<string>>;
595621 """
596622 ) ;
597623
598624 // Generate Error alias
599625 aliases . Add (
600626 $$ """
601- using Error{{ aliasName }} = Outcome.Result<{{ qualifiedType }} , Outcome.HttpError<string>>.Error<{{ qualifiedType }} , Outcome.HttpError<string>>;
627+ global using Error{{ aliasName }} = Outcome.Result<{{ qualifiedType }} , Outcome.HttpError<string>>.Error<{{ qualifiedType }} , Outcome.HttpError<string>>;
602628 """
603629 ) ;
604630 }
0 commit comments