@@ -14,18 +14,48 @@ namespace Asp.Versioning.OpenApi.Transformers;
1414using System . Threading ;
1515using System . Threading . Tasks ;
1616
17- internal sealed class ApiExplorerTransformer (
18- ApiVersionDescription apiVersionDescription ,
19- IOptions < OpenApiDocumentDescriptionOptions > descriptionOptions ) :
17+ /// <summary>
18+ /// Represents a <see cref="IOpenApiDocumentTransformer">transformer</see> used to apply API Explorer metadata to an
19+ /// OpenAPI document.
20+ /// </summary>
21+ [ CLSCompliant ( false ) ]
22+ public class ApiExplorerTransformer :
2023 IOpenApiSchemaTransformer ,
2124 IOpenApiDocumentTransformer ,
2225 IOpenApiOperationTransformer
2326{
27+ private readonly ApiVersionDescription apiVersionDescription ;
28+ private readonly IOptions < OpenApiDocumentDescriptionOptions > descriptionOptions ;
29+
30+ /// <summary>
31+ /// Initializes a new instance of the <see cref="ApiExplorerTransformer"/> class.
32+ /// </summary>
33+ /// <param name="apiVersionDescription">The <see cref="ApiVersionDescription">metadata</see> to apply.</param>
34+ /// <param name="descriptionOptions">The <see cref="OpenApiDocumentDescriptionOptions">options</see> applied
35+ /// to OpenAPI document descriptions.</param>
36+ public ApiExplorerTransformer (
37+ ApiVersionDescription apiVersionDescription ,
38+ IOptions < OpenApiDocumentDescriptionOptions > descriptionOptions )
39+ {
40+ this . apiVersionDescription = apiVersionDescription ;
41+ this . descriptionOptions = descriptionOptions ;
42+ }
43+
44+ /// <summary>
45+ /// Gets or sets the OpenApi extension name.
46+ /// </summary>
47+ /// <value>The OpenAPI extension name. The default value is <c>x-api-versioning</c>.</value>
48+ protected string ExtensionName { get ; set ; } = "x-api-versioning" ;
49+
50+ /// <inheritdoc />
2451 public Task TransformAsync (
2552 OpenApiSchema schema ,
2653 OpenApiSchemaTransformerContext context ,
2754 CancellationToken cancellationToken )
2855 {
56+ ArgumentNullException . ThrowIfNull ( schema ) ;
57+ ArgumentNullException . ThrowIfNull ( context ) ;
58+
2959 if ( schema . Default is null
3060 && context . ParameterDescription ? . DefaultValue is string value )
3161 {
@@ -35,11 +65,15 @@ public Task TransformAsync(
3565 return Task . CompletedTask ;
3666 }
3767
68+ /// <inheritdoc />
3869 public Task TransformAsync (
3970 OpenApiDocument document ,
4071 OpenApiDocumentTransformerContext context ,
4172 CancellationToken cancellationToken )
4273 {
74+ ArgumentNullException . ThrowIfNull ( document ) ;
75+ ArgumentNullException . ThrowIfNull ( context ) ;
76+
4377 var options = descriptionOptions . Value ;
4478
4579 UpdateFromAssemblyInfo ( document , apiVersionDescription ) ;
@@ -52,6 +86,7 @@ public Task TransformAsync(
5286 return Task . CompletedTask ;
5387 }
5488
89+ /// <inheritdoc />
5590 public Task TransformAsync (
5691 OpenApiOperation operation ,
5792 OpenApiOperationTransformerContext context ,
@@ -115,7 +150,7 @@ private static void UpdateFromAssemblyInfo( OpenApiDocument document, ApiVersion
115150 }
116151 }
117152
118- private static void UpdateDescriptionToMarkdown (
153+ private void UpdateDescriptionToMarkdown (
119154 OpenApiDocument document ,
120155 ApiVersionDescription api ,
121156 OpenApiDocumentDescriptionOptions options )
@@ -170,48 +205,68 @@ private static void UpdateDescriptionToMarkdown(
170205 document . Info . Description = description . ToString ( ) ;
171206 }
172207
173- private static bool IsHtml ( LinkHeaderValue link ) =>
174- StringSegmentComparer . OrdinalIgnoreCase . Equals ( link . Type , "text/html" ) ;
175-
176- private static void AddMarkdownLinks ( StringBuilder markdown , IList < LinkHeaderValue > links )
208+ /// <summary>
209+ /// Determines if the specified link should be rendered.
210+ /// </summary>
211+ /// <param name="link">The <see cref="LinkHeaderValue">link</see> to evaluate.</param>
212+ /// <returns>True if the link should be rendered; otherwise, false.</returns>
213+ /// <remarks>The default implementation only renders <c>text/html</c> links.</remarks>
214+ protected virtual bool ShouldRenderLink ( LinkHeaderValue link )
177215 {
178- for ( var i = 0 ; i < links . Count ; i ++ )
179- {
180- var link = links [ i ] ;
216+ ArgumentNullException . ThrowIfNull ( link ) ;
217+ return StringSegmentComparer . OrdinalIgnoreCase . Equals ( link . Type , "text/html" ) ;
218+ }
181219
182- if ( ! IsHtml ( link ) )
183- {
184- continue ;
185- }
220+ /// <summary>
221+ /// Renders the specified link as markdown.
222+ /// </summary>
223+ /// <param name="markdown">The <see cref="StringBuilder">builder</see> to render the Markdown into.</param>
224+ /// <param name="link">The <see cref="LinkHeaderValue">link</see> to render.</param>
225+ protected virtual void RenderLink ( StringBuilder markdown , LinkHeaderValue link )
226+ {
227+ ArgumentNullException . ThrowIfNull ( markdown ) ;
228+ ArgumentNullException . ThrowIfNull ( link ) ;
186229
187- if ( StringSegment . IsNullOrEmpty ( link . Title ) )
230+ if ( StringSegment . IsNullOrEmpty ( link . Title ) )
231+ {
232+ if ( link . LinkTarget . IsAbsoluteUri )
188233 {
189- if ( link . LinkTarget . IsAbsoluteUri )
190- {
191- markdown . Append ( "- " ) . AppendLine ( link . LinkTarget . OriginalString ) ;
192- }
193- else
194- {
195- markdown . Append ( "- <a href=\" " )
196- . Append ( link . LinkTarget . OriginalString )
197- . Append ( "\" >" )
198- . Append ( link . LinkTarget . OriginalString )
199- . AppendLine ( "</a>" ) ;
200- }
234+ markdown . Append ( "- " ) . AppendLine ( link . LinkTarget . OriginalString ) ;
201235 }
202236 else
203237 {
204- markdown . Append ( "- [ " )
205- . Append ( link . Title . ToString ( ) )
206- . Append ( "]( " )
238+ markdown . Append ( "- <a href= \" " )
239+ . Append ( link . LinkTarget . OriginalString )
240+ . Append ( "\" > " )
207241 . Append ( link . LinkTarget . OriginalString )
208- . Append ( ')' )
209- . AppendLine ( ) ;
242+ . AppendLine ( "</a>" ) ;
243+ }
244+ }
245+ else
246+ {
247+ markdown . Append ( "- [" )
248+ . Append ( link . Title . ToString ( ) )
249+ . Append ( "](" )
250+ . Append ( link . LinkTarget . OriginalString )
251+ . Append ( ')' )
252+ . AppendLine ( ) ;
253+ }
254+ }
255+
256+ private void AddMarkdownLinks ( StringBuilder markdown , IList < LinkHeaderValue > links )
257+ {
258+ for ( var i = 0 ; i < links . Count ; i ++ )
259+ {
260+ var link = links [ i ] ;
261+
262+ if ( ShouldRenderLink ( link ) )
263+ {
264+ RenderLink ( markdown , link ) ;
210265 }
211266 }
212267 }
213268
214- private static void AddLinkExtensions ( OpenApiDocument document , ApiVersionDescription api )
269+ private void AddLinkExtensions ( OpenApiDocument document , ApiVersionDescription api )
215270 {
216271 var array = new JsonArray ( ) ;
217272
@@ -223,22 +278,29 @@ private static void AddLinkExtensions( OpenApiDocument document, ApiVersionDescr
223278 if ( array . Count > 0 )
224279 {
225280 var extensions = document . Extensions ??= new Dictionary < string , IOpenApiExtension > ( ) ;
226- extensions [ "x-api-versioning" ] = new JsonNodeExtension ( array ) ;
281+ extensions [ ExtensionName ] = new JsonNodeExtension ( array ) ;
227282 }
228283 }
229284
230285 [ UnconditionalSuppressMessage ( "ILLink" , "IL2026" ) ]
231286 [ UnconditionalSuppressMessage ( "ILLink" , "IL3050" ) ]
232- private static void AddLinks ( JsonArray array , IList < LinkHeaderValue > links )
287+ private void AddLinks ( JsonArray array , IList < LinkHeaderValue > links )
233288 {
234289 for ( var i = 0 ; i < links . Count ; i ++ )
235290 {
236- array . Add ( LinkToJson ( links [ i ] ) ) ;
291+ array . Add ( ToJson ( links [ i ] ) ) ;
237292 }
238293 }
239294
240- private static JsonObject LinkToJson ( LinkHeaderValue link )
295+ /// <summary>
296+ /// Converts the specified link into JSON as an OpenAPI extension.
297+ /// </summary>
298+ /// <param name="link">The <see cref="LinkHeaderValue">link</see> to convert.</param>
299+ /// <returns>The OpenAPI extension <see cref="JsonObject">JSON</see> node.</returns>
300+ protected virtual JsonObject ToJson ( LinkHeaderValue link )
241301 {
302+ ArgumentNullException . ThrowIfNull ( link ) ;
303+
242304 var obj = new JsonObject ( ) ;
243305
244306 if ( link . Title . HasValue )
0 commit comments