Skip to content

Commit

Permalink
Add option to choose descriptions source - "FixEnumOptions.Descriptio…
Browse files Browse the repository at this point in the history
…nSource";

Fix small bugs.
  • Loading branch information
unchase committed Mar 25, 2020
1 parent 7558604 commit c48232c
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 27 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

These are the changes to each version that has been released on the [nuget](https://www.nuget.org/packages/Unchase.Swashbuckle.AspNetCore.Extensions/).

## v2.3.3 `(2020-03-25)`

- [x] Add option to choose descriptions source - `FixEnumOptions.DescriptionSource`
- [x] Fix small bugs

## v2.3.2 `(2020-03-25)`

- [x] Fix bug with `System.MissingMethodException`
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ public void ConfigureServices(IServiceCollection services)
// add descriptions from DescriptionAttribute or xml-comments to fix enums (add 'x-enumDescriptions' for schema extensions) for applied filters
o.IncludeDescriptions = true;

// get descriptions from DescriptionAttribute then from xml-comments
o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;

// get descriptions from xml-file comments on the specified path
// should use "options.IncludeXmlComments(xmlFilePath);" before
o.IncludeXmlCommentsFrom(xmlFilePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@

namespace Unchase.Swashbuckle.AspNetCore.Extensions.Extensions
{
/// <summary>
/// Description sources.
/// </summary>
public enum DescriptionSources
{
/// <summary>
/// <see cref="DescriptionAttribute"/>.
/// </summary>
DescriptionAttributes = 0,

/// <summary>
/// Xml comments.
/// </summary>
XmlComments = 1,

/// <summary>
/// <see cref="DescriptionAttribute"/> then xml comments.
/// </summary>
DescriptionAttributesThenXmlComments = 2
}

internal static class EnumTypeExtensions
{
private static string GetDescriptionFromEnumOption(Type enumOptionType, object enumOption)
Expand All @@ -29,18 +50,43 @@ private static string GetFieldAttributeDescription(this Type enumType, object en
return string.Empty;
}

internal static List<OpenApiString> GetEnumValuesDescription(Type enumType, IEnumerable<XPathNavigator> xmlNavigators = null)
internal static List<OpenApiString> GetEnumValuesDescription(Type enumType, DescriptionSources descriptionSource, IEnumerable<XPathNavigator> xmlNavigators = null)
{
var enumsDescriptions = new List<OpenApiString>();
foreach (var enumValue in Enum.GetValues(enumType))
{
var enumDescription = GetDescriptionFromEnumOption(enumType, enumValue);
if (string.IsNullOrWhiteSpace(enumDescription))
var enumDescription = string.Empty;
try
{
var memberInfo = enumType.GetMembers().FirstOrDefault(m => m.Name.Equals(enumValue.ToString(), StringComparison.InvariantCultureIgnoreCase));
enumDescription = TryGetMemberComments(memberInfo, xmlNavigators);
switch (descriptionSource)
{
case DescriptionSources.DescriptionAttributes:
enumDescription = GetDescriptionFromEnumOption(enumType, enumValue);
break;
case DescriptionSources.XmlComments:
var memberInfo = enumType.GetMembers().FirstOrDefault(m =>
m.Name.Equals(enumValue.ToString(), StringComparison.InvariantCultureIgnoreCase));
enumDescription = TryGetMemberComments(memberInfo, xmlNavigators);
break;
case DescriptionSources.DescriptionAttributesThenXmlComments:
enumDescription = GetDescriptionFromEnumOption(enumType, enumValue);
if (string.IsNullOrWhiteSpace(enumDescription))
{
var memberInfo2 = enumType.GetMembers().FirstOrDefault(m =>
m.Name.Equals(enumValue.ToString(), StringComparison.InvariantCultureIgnoreCase));
enumDescription = TryGetMemberComments(memberInfo2, xmlNavigators);
}
break;
}
}
catch
{

}
finally
{
enumsDescriptions.Add(new OpenApiString(enumDescription));
}
enumsDescriptions.Add(new OpenApiString(enumDescription));
}
return enumsDescriptions;
}
Expand All @@ -50,20 +96,13 @@ private static string TryGetMemberComments(MemberInfo memberInfo, IEnumerable<XP
if (xmlNavigators == null)
return string.Empty;

try
{
foreach (var xmlNavigator in xmlNavigators)
{
var nodeNameForMember = XmlCommentsNodeNameHelper.GetNodeNameForMember(memberInfo);
var xpathNavigator1 = xmlNavigator.SelectSingleNode(
$"/doc/members/member[@name='{nodeNameForMember}']");
var xpathNavigator2 = xpathNavigator1?.SelectSingleNode("summary");
return xpathNavigator2 != null ? XmlCommentsTextHelper.Humanize(xpathNavigator2.InnerXml) : string.Empty;
}
}
catch
foreach (var xmlNavigator in xmlNavigators)
{
return string.Empty;
var nodeNameForMember = XmlCommentsNodeNameHelper.GetNodeNameForMember(memberInfo);
var xpathNavigator1 = xmlNavigator.SelectSingleNode(
$"/doc/members/member[@name='{nodeNameForMember}']");
var xpathNavigator2 = xpathNavigator1?.SelectSingleNode("summary");
return xpathNavigator2 != null ? XmlCommentsTextHelper.Humanize(xpathNavigator2.InnerXml) : string.Empty;
}

return string.Empty;
Expand Down Expand Up @@ -102,7 +141,8 @@ internal static string AddEnumValuesDescription(this OpenApiSchema schema, bool
if (xEnumDescriptions?.Count == schema.Enum.Count)
{
var description = ((OpenApiString)((OpenApiArray)schema.Extensions["x-enumDescriptions"])[i]).Value;
sb.Append($" ({description})");
if (!string.IsNullOrWhiteSpace(description))
sb.Append($" ({description})");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal class XEnumNamesParameterFilter : IParameterFilter
#region Fields

private readonly bool _includeXEnumDescriptions;
private readonly DescriptionSources _descriptionSources;
private readonly bool _applyFiler;
private readonly HashSet<XPathNavigator> _xmlNavigators = new HashSet<XPathNavigator>();

Expand All @@ -35,6 +36,7 @@ public XEnumNamesParameterFilter(IOptions<FixEnumsOptions> options, Action<FixEn
{
configureOptions?.Invoke(options.Value);
this._includeXEnumDescriptions = options.Value?.IncludeDescriptions ?? false;
this._descriptionSources = options.Value?.DescriptionSource ?? DescriptionSources.DescriptionAttributes;
this._applyFiler = options.Value?.ApplyParameterFilter ?? false;
foreach (var filePath in options.Value?.IncludedXmlCommentsPaths)
{
Expand Down Expand Up @@ -74,7 +76,7 @@ public void Apply(OpenApiParameter parameter, ParameterFilterContext context)

if (this._includeXEnumDescriptions)
{
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(typeInfo, this._xmlNavigators));
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(typeInfo, this._descriptionSources, this._xmlNavigators));
if (!parameter.Extensions.ContainsKey("x-enumDescriptions") && enumsDescriptionsArray.Any())
{
parameter.Extensions.Add("x-enumDescriptions", enumsDescriptionsArray);
Expand All @@ -96,7 +98,7 @@ public void Apply(OpenApiParameter parameter, ParameterFilterContext context)

if (this._includeXEnumDescriptions)
{
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(genericArgumentType, this._xmlNavigators));
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(genericArgumentType, this._descriptionSources, this._xmlNavigators));
if (!parameter.Extensions.ContainsKey("x-enumDescriptions") && enumsDescriptionsArray.Any())
{
parameter.Extensions.Add("x-enumDescriptions", enumsDescriptionsArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal class XEnumNamesSchemaFilter : ISchemaFilter
#region Fields

private readonly bool _includeXEnumDescriptions;
private readonly DescriptionSources _descriptionSources;
private readonly bool _applyFiler;
private readonly HashSet<XPathNavigator> _xmlNavigators = new HashSet<XPathNavigator>();

Expand All @@ -36,6 +37,7 @@ public XEnumNamesSchemaFilter(IOptions<FixEnumsOptions> options, Action<FixEnums
{
configureOptions?.Invoke(options.Value);
this._includeXEnumDescriptions = options.Value.IncludeDescriptions;
this._descriptionSources = options.Value?.DescriptionSource ?? DescriptionSources.DescriptionAttributes;
this._applyFiler = options.Value.ApplySchemaFilter;
foreach (var filePath in options.Value.IncludedXmlCommentsPaths)
{
Expand Down Expand Up @@ -75,7 +77,7 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context)

if (this._includeXEnumDescriptions)
{
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(context.Type, this._xmlNavigators));
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(context.Type, this._descriptionSources, this._xmlNavigators));
if (!schema.Extensions.ContainsKey("x-enumDescriptions") && enumsDescriptionsArray.Any())
{
schema.Extensions.Add("x-enumDescriptions", enumsDescriptionsArray);
Expand Down Expand Up @@ -108,7 +110,7 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context)

if (this._includeXEnumDescriptions)
{
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(genericArgumentType, this._xmlNavigators));
enumsDescriptionsArray.AddRange(EnumTypeExtensions.GetEnumValuesDescription(genericArgumentType, this._descriptionSources, this._xmlNavigators));
if (!schemaPropertyValue.Extensions.ContainsKey("x-enumDescriptions") && enumsDescriptionsArray.Any())
{
schemaPropertyValue.Extensions.Add("x-enumDescriptions", enumsDescriptionsArray);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.ComponentModel;
using Unchase.Swashbuckle.AspNetCore.Extensions.Extensions;

namespace Unchase.Swashbuckle.AspNetCore.Extensions.Options
{
Expand All @@ -20,6 +21,11 @@ public class FixEnumsOptions
/// </summary>
public bool IncludeDescriptions { get; set; } = false;

/// <summary>
/// Source to get descriptions. Default value is <see cref="DescriptionSources.DescriptionAttributes"/>.
/// </summary>
public DescriptionSources DescriptionSource { get; set; } = DescriptionSources.DescriptionAttributes;

/// <summary>
/// Apply fix enum filter to OpenApi schema. Default value is true.
/// <para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
<NeutralLanguage></NeutralLanguage>
<LangVersion>7.3</LangVersion>
<PackageIconUrl>https://github.com/unchase/Unchase.Swashbuckle.AspNetCore.Extensions/blob/master/assets/icon.png?raw=true</PackageIconUrl>
<Version>2.3.2</Version>
<AssemblyVersion>2.3.2.0</AssemblyVersion>
<FileVersion>2.3.2.0</FileVersion>
<Version>2.3.3</Version>
<AssemblyVersion>2.3.3.0</AssemblyVersion>
<FileVersion>2.3.3.0</FileVersion>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<DocumentationFile>Unchase.Swashbuckle.AspNetCore.Extensions.xml</DocumentationFile>
</PropertyGroup>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions test/WebApi3.1-Swashbuckle/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public void ConfigureServices(IServiceCollection services)
// add descriptions from DescriptionAttribute or xml-comments to fix enums (add 'x-enumDescriptions' for schema extensions) for applied filters
o.IncludeDescriptions = true;

// get descriptions from DescriptionAttribute then from xml-comments
o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;

// get descriptions from xml-file comments on the specified path
// should use "options.IncludeXmlComments(xmlFilePath);" before
o.IncludeXmlCommentsFrom(xmlFilePath);
Expand Down

0 comments on commit c48232c

Please sign in to comment.