Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/Refitter.Core/XmlDocumentationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ public void AppendInterfaceDocumentationByTag(OpenApiDocument document, string t
return;
}

var controllerTag = document.Tags.FirstOrDefault(t => t.Name.SanitizeControllerTag() == tag);
var controllerTag = document.Tags?.FirstOrDefault(t => t.Name.SanitizeControllerTag() == tag);
var controllerDescription = controllerTag?.Description;
if (!string.IsNullOrEmpty(controllerDescription))
{
this.AppendXmlCommentBlock(SummaryTag, EscapeSymbols(controllerDescription), code, indent: Separator);
this.AppendXmlCommentBlock(SummaryTag, EscapeSymbols(controllerDescription!), code, indent: Separator);
}
}

Expand Down Expand Up @@ -88,7 +88,7 @@ public void AppendSingleInterfaceDocumentation(OpenApiDocument document, StringB
var title = document.Info?.Title;
if (!string.IsNullOrEmpty(title))
{
this.AppendXmlCommentBlock(SummaryTag, EscapeSymbols(title), code, indent: Separator);
this.AppendXmlCommentBlock(SummaryTag, EscapeSymbols(title!), code, indent: Separator);
}
}

Expand Down Expand Up @@ -334,6 +334,7 @@ private string BuildResponseDescription(string text, IEnumerable<CSharpResponseM
private string EscapeSymbols(string input)
{
return input
.Replace("&", "&amp;")
.Replace("<", "&lt;")
.Replace(">", "&gt;");
}
Comment on lines 334 to 340

Copilot AI Feb 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EscapeSymbols now escapes ampersands, but several XML doc blocks still write OpenAPI-provided text without escaping (e.g., <param> uses parameter.Description directly). This means parameter descriptions containing &, <, or > can still generate malformed XML documentation and trigger compiler warnings/errors. Consider applying escaping to OpenAPI-sourced parameter/response description text before passing it into AppendXmlCommentBlock (while preserving intentionally-generated XML markup like <see/> and <list>).

Copilot uses AI. Check for mistakes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ public partial interface IUpdatePetWithFormEndpoint
public partial interface IDeletePetEndpoint
{
/// <summary>Deletes a pet</summary>
/// <param name="api_key">api_key parameter</param>
/// <param name="petId">Pet id to delete</param>
/// <param name="cancellationToken">The cancellation token to cancel the request.</param>
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
Expand Down Expand Up @@ -218,6 +219,7 @@ public partial interface IUploadFileEndpoint
/// <summary>uploads an image</summary>
/// <param name="petId">ID of pet to update</param>
/// <param name="additionalMetadata">Additional Metadata</param>
/// <param name="body">body parameter</param>
/// <param name="cancellationToken">The cancellation token to cancel the request.</param>
/// <returns>
/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:
Expand Down Expand Up @@ -256,6 +258,7 @@ public partial interface IPlaceOrderEndpoint
{
/// <summary>Place an order for a pet</summary>
/// <remarks>Place a new order in the store</remarks>
/// <param name="body">body parameter</param>
/// <param name="cancellationToken">The cancellation token to cancel the request.</param>
/// <returns>successful operation</returns>
/// <exception cref="ApiException">
Expand Down Expand Up @@ -357,6 +360,7 @@ public partial interface ICreateUsersWithListInputEndpoint
{
/// <summary>Creates list of users with given input array</summary>
/// <remarks>Creates list of users with given input array</remarks>
/// <param name="body">body parameter</param>
/// <param name="cancellationToken">The cancellation token to cancel the request.</param>
/// <returns>Successful operation</returns>
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using FluentAssertions;
using FluentAssertions;
using Refitter.Core;
using Refitter.Tests.Build;
using Refitter.Tests.TestUtilities;
Expand Down
36 changes: 34 additions & 2 deletions src/Refitter.Tests/XmlDocumentationGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,46 @@ public void Can_Generate_Interface_Doc_With_Linebreaks()
public void Can_Generate_Interface_Doc_From_Controller_Tag()
{
var docs = new StringBuilder();
var controllerTag = new OpenApiTag { Name = "TestController", Description = "TestControllerDescription" };
var document = new OpenApiDocument { Tags = [controllerTag] };
var controllerTag = new OpenApiTag { Name = "TestController", Description = "TestControllerDescription" };
var document = new OpenApiDocument { Tags = [controllerTag] };

this._generator.AppendInterfaceDocumentationByTag(document, "TestController", docs);

docs.ToString().Trim().Should().Be("/// <summary>TestControllerDescription</summary>");
}

[Test]
public void Can_Handle_Null_Document_Tags()
{
var docs = new StringBuilder();
var document = new OpenApiDocument { Tags = null };

this._generator.AppendInterfaceDocumentationByTag(document, "TestController", docs);

docs.ToString().Trim().Should().BeEmpty();
}

[Test]
public void Can_Escape_Xml_Special_Characters_In_Interface_Doc()
{
var docs = new StringBuilder();
var controllerTag = new OpenApiTag { Name = "TestController", Description = "Test <tag> & content" };
var document = new OpenApiDocument { Tags = [controllerTag] };

this._generator.AppendInterfaceDocumentationByTag(document, "TestController", docs);

docs.ToString().Trim().Should().Be("/// <summary>Test &lt;tag&gt; &amp; content</summary>");
}

[Test]
public void Can_Escape_Xml_Special_Characters_In_Method_Summary()
{
var docs = new StringBuilder();
var method = CreateOperationModel(new OpenApiOperation { Summary = "Test <tag> & content", });
this._generator.AppendMethodDocumentation(method, false, false, false, false, docs);
docs.ToString().Trim().Should().StartWith("/// <summary>Test &lt;tag&gt; &amp; content</summary>");
}

[Test]
public void Can_Generate_Method_Summary()
{
Expand Down
Loading