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
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public IEnumerable<EnumerationItemModel> Enums
var value = _schema.Enumeration.ElementAt(i);
if (value != null)
{
var description = _schema.EnumerationDescriptions.Count > i ?
_schema.EnumerationDescriptions.ElementAt(i) : null;
if (_schema.Type.IsInteger())
{
var name = _schema.EnumerationNames.Count > i ?
Expand All @@ -78,6 +80,7 @@ public IEnumerable<EnumerationItemModel> Enums
Name = _settings.EnumNameGenerator.Generate(i, name, value, _schema),
OriginalName = name,
Value = value.ToString()!,
Description = description,
InternalValue = valueInt64.ToString(CultureInfo.InvariantCulture),
InternalFlagValue = valueInt64.ToString(CultureInfo.InvariantCulture)
});
Expand All @@ -89,6 +92,7 @@ public IEnumerable<EnumerationItemModel> Enums
Name = _settings.EnumNameGenerator.Generate(i, name, value, _schema),
OriginalName = name,
Value = value.ToString()!,
Description = description,
InternalValue = value.ToString(),
InternalFlagValue = (1 << i).ToString(CultureInfo.InvariantCulture)
});
Expand All @@ -104,6 +108,7 @@ public IEnumerable<EnumerationItemModel> Enums
Name = _settings.EnumNameGenerator.Generate(i, name, value, _schema),
OriginalName = name!,
Value = value.ToString()!,
Description = description,
InternalValue = i.ToString(CultureInfo.InvariantCulture),
InternalFlagValue = (1 << i).ToString(CultureInfo.InvariantCulture)
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,15 @@ public List<EnumerationItemModel> Enums
var name = _schema.EnumerationNames.Count > i
? _schema.EnumerationNames.ElementAt(i)
: _schema.Type.IsInteger() ? "_" + value : value.ToString()!;
var description = _schema.EnumerationDescriptions.Count > i ?
_schema.EnumerationDescriptions.ElementAt(i) : null;

entries.Add(new EnumerationItemModel
{
Name = _settings.EnumNameGenerator.Generate(i, name, value, _schema),
OriginalName = name,
Value = _schema.Type.IsInteger() ? value.ToString()! : "\"" + value + "\"",
Description = description,
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/NJsonSchema.CodeGeneration/Models/EnumerationItemModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class EnumerationItemModel
/// <summary>Gets or sets the value.</summary>
public required string Value { get; set; }

/// <summary>Gets or sets the description.</summary>
public string? Description { get; set; }

/// <summary>Gets or sets the internal value (e.g. the underlying/system value).</summary>
public string? InternalValue { get; set; }

Expand Down
109 changes: 108 additions & 1 deletion src/NJsonSchema.Tests/Generation/EnumTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.ComponentModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using NJsonSchema.CodeGeneration.Tests;
using NJsonSchema.NewtonsoftJson.Generation;

namespace NJsonSchema.Tests.Generation
Expand Down Expand Up @@ -150,5 +152,110 @@ public async Task When_enum_does_not_have_FlagsAttribute_then_custom_property_is
Assert.False(schema.IsFlagEnumerable);
Assert.DoesNotContain("x-enumFlags", json);
}

public enum EnumWithDescriptions
{
[Description("First value description")]
FirstValue,

[Description("Second value description")]
SecondValue,

// No description for this one
ThirdValue
}

[Fact]
public async Task When_enum_has_description_attributes_then_descriptions_are_included_in_schema()
{
// Arrange

// Act
var schema = NewtonsoftJsonSchemaGenerator.FromType<EnumWithDescriptions>(new NewtonsoftJsonSchemaGeneratorSettings
{
SerializerSettings =
{
Converters = { new StringEnumConverter() }
}
});
var json = schema.ToJson();

// Assert
Assert.Equal(3, schema.EnumerationDescriptions.Count);
Assert.Equal("First value description", schema.EnumerationDescriptions[0]);
Assert.Equal("Second value description", schema.EnumerationDescriptions[1]);
Assert.Null(schema.EnumerationDescriptions[2]); // No description for ThirdValue

// Verify the JSON output contains the x-enumDescriptions property
await VerifyHelper.Verify(json);
}

[Fact]
public async Task When_schema_has_x_enum_names_then_backward_compatibility_works()
{
// Arrange
var schema = new JsonSchema();
schema.Type = JsonObjectType.String;

schema.Enumeration.Clear();
schema.Enumeration.Add("value1");
schema.Enumeration.Add("value2");

schema.EnumerationNames.Clear();
schema.EnumerationNames.Add("Name1");
schema.EnumerationNames.Add("Name2");

// Act
var json = schema.ToJson();

// Assert
await VerifyHelper.Verify(json);
}

[Fact]
public async Task When_schema_has_x_enum_varnames_then_backward_compatibility_works()
{
// Arrange
var schema = new JsonSchema();
schema.Type = JsonObjectType.String;

schema.Enumeration.Clear();
schema.Enumeration.Add("value1");
schema.Enumeration.Add("value2");

schema.EnumerationNames.Clear();
schema.EnumerationNames.Add("VarName1");
schema.EnumerationNames.Add("VarName2");

// Act
var json = schema.ToJson();

// Assert
await VerifyHelper.Verify(json);
}

[Fact]
public async Task When_schema_has_x_enum_descriptions_then_backward_compatibility_works()
{
// Arrange
var schema = new JsonSchema();
schema.Type = JsonObjectType.String;

schema.Enumeration.Clear();
schema.Enumeration.Add("value1");
schema.Enumeration.Add("value2");
schema.Enumeration.Add("value3");

schema.EnumerationDescriptions.Clear();
schema.EnumerationDescriptions.Add("Desc1");
schema.EnumerationDescriptions.Add("Desc2");
schema.EnumerationDescriptions.Add(null);

// Act
var json = schema.ToJson();

// Assert
await VerifyHelper.Verify(json);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "EnumWithDescriptions",
"type": "string",
"description": "",
"x-enum-names": [
"FirstValue",
"SecondValue",
"ThirdValue"
],
"x-enum-varnames": [
"FirstValue",
"SecondValue",
"ThirdValue"
],
"x-enumNames": [
"FirstValue",
"SecondValue",
"ThirdValue"
],
"x-enum-descriptions": [
"First value description",
"Second value description",
null
],
"x-enumDescriptions": [
"First value description",
"Second value description",
null
],
"enum": [
"FirstValue",
"SecondValue",
"ThirdValue"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "string",
"x-enum-descriptions": [
"Desc1",
"Desc2",
null
],
"x-enumDescriptions": [
"Desc1",
"Desc2",
null
],
"enum": [
"value1",
"value2",
"value3"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "string",
"x-enum-names": [
"Name1",
"Name2"
],
"x-enum-varnames": [
"Name1",
"Name2"
],
"x-enumNames": [
"Name1",
"Name2"
],
"enum": [
"value1",
"value2"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "string",
"x-enum-names": [
"VarName1",
"VarName2"
],
"x-enum-varnames": [
"VarName1",
"VarName2"
],
"x-enumNames": [
"VarName1",
"VarName2"
],
"enum": [
"value1",
"value2"
]
}
15 changes: 14 additions & 1 deletion src/NJsonSchema/Generation/JsonSchemaGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using NJsonSchema.Generation.TypeMappers;
using NJsonSchema.Infrastructure;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -698,12 +699,23 @@ protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeD
schema.Type = typeDescription.Type;
schema.Enumeration.Clear();
schema.EnumerationNames.Clear();
schema.EnumerationDescriptions.Clear();
schema.IsFlagEnumerable = contextualType.IsAttributeDefined<FlagsAttribute>(true);

Func<object, string?>? enumValueConverter = null;
var underlyingType = Enum.GetUnderlyingType(contextualType.Type);
foreach (var enumName in Enum.GetNames(contextualType.Type))
{
string? enumDescription = null;
var field = contextualType.Type.GetRuntimeField(enumName);
// Retrieve the Description attribute value, if present.
var descriptionAttribute = field?.GetCustomAttribute<DescriptionAttribute>();

if (descriptionAttribute != null)
{
enumDescription = descriptionAttribute.Description;
}

if (typeDescription.Type == JsonObjectType.Integer)
{
var value = Convert.ChangeType(Enum.Parse(contextualType.Type, enumName), underlyingType, CultureInfo.InvariantCulture);
Expand All @@ -712,7 +724,7 @@ protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeD
else
{
// EnumMember only checked if StringEnumConverter is used
var enumMemberAttribute = contextualType.Type.GetRuntimeField(enumName)?.GetCustomAttribute<EnumMemberAttribute>();
var enumMemberAttribute = field?.GetCustomAttribute<EnumMemberAttribute>();
if (enumMemberAttribute != null && !string.IsNullOrEmpty(enumMemberAttribute.Value))
{
schema.Enumeration.Add(enumMemberAttribute.Value);
Expand All @@ -726,6 +738,7 @@ protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeD
}

schema.EnumerationNames.Add(enumName);
schema.EnumerationDescriptions.Add(enumDescription);
}

if (typeDescription.Type == JsonObjectType.Integer && Settings.GenerateEnumMappingDescription)
Expand Down
Loading