Skip to content

Commit

Permalink
feat: Added smart names for Named AnyOf with all referenced properties.
Browse files Browse the repository at this point in the history
  • Loading branch information
HavenDV committed Jun 16, 2024
1 parent fa434b5 commit 0aebf33
Show file tree
Hide file tree
Showing 23 changed files with 1,969 additions and 1,309 deletions.
26 changes: 26 additions & 0 deletions src/libs/OpenApiGenerator.Core/Extensions/OpenApiExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections.Immutable;
using System.Globalization;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using OpenApiGenerator.Core.Helpers;
using OpenApiGenerator.Core.Json;
using OpenApiGenerator.Core.Models;
using OpenApiGenerator.Core.Naming.Methods;
Expand Down Expand Up @@ -198,6 +200,30 @@ public static bool IsObjectWithoutReference(
schema.Enum.Any());
}

public static ImmutableArray<PropertyData> ToAnyOfProperties(
this IList<OpenApiSchema> schemas,
Settings settings,
string key)
{
var useSmartNames = schemas.All(x => x.Reference != null);
var className = key.ToClassName();

return schemas.Select((x, i) =>
{
var type = TypeData.FromSchema(x.UseReferenceIdOrKey(key + $"Variant{i + 1}"), settings);

return PropertyData.Default with
{
Name = useSmartNames
? SmartNamedAnyOfNames.ComputeSmartName(
type.ShortCSharpTypeWithoutNullability,
className)
: $"Value{i + 1}",
Type = type,
};
}).ToImmutableArray();
}

public static bool IsEnum(
this OpenApiSchema schema)
{
Expand Down
18 changes: 9 additions & 9 deletions src/libs/OpenApiGenerator.Core/Generation/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,26 +198,26 @@ .. includedTags.Select(x => PropertyData.Default with
.ToArray() : [];
var anyOfs = allSchemas
.Where(x => x.AnyOf is { Count: > 0 })
.Select(x => new AnyOfData("AnyOf", x.AnyOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<TypeData>.Empty))
.Select(x => new AnyOfData("AnyOf", x.AnyOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<PropertyData>.Empty))
.Concat(allSchemas
.Where(x => x.Items?.AnyOf is { Count: > 0 })
.Select(x => new AnyOfData("AnyOf", x.Items.AnyOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<TypeData>.Empty)))
.Select(x => new AnyOfData("AnyOf", x.Items.AnyOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<PropertyData>.Empty)))
.Distinct()
.ToImmutableArray();
var oneOfs = allSchemas
.Where(x => x.OneOf is { Count: > 0 })
.Select(x => new AnyOfData("OneOf", x.OneOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<TypeData>.Empty))
.Select(x => new AnyOfData("OneOf", x.OneOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<PropertyData>.Empty))
.Concat(allSchemas
.Where(x => x.Items?.OneOf is { Count: > 0 })
.Select(x => new AnyOfData("OneOf", x.Items.OneOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<TypeData>.Empty)))
.Select(x => new AnyOfData("OneOf", x.Items.OneOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<PropertyData>.Empty)))
.Distinct()
.ToImmutableArray();
var allOfs = allSchemas
.Where(x => x.AllOf is { Count: > 0 })
.Select(x => new AnyOfData("AllOf", x.AllOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<TypeData>.Empty))
.Select(x => new AnyOfData("AllOf", x.AllOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<PropertyData>.Empty))
.Concat(allSchemas
.Where(x => x.Items?.AllOf is { Count: > 0 })
.Select(x => new AnyOfData("AllOf", x.Items.AllOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<TypeData>.Empty)))
.Select(x => new AnyOfData("AllOf", x.Items.AllOf.Count, settings.JsonSerializerType, isTrimming, "System", string.Empty, string.Empty, ImmutableArray<PropertyData>.Empty)))
.Distinct()
.ToImmutableArray();
anyOfs = settings.GenerateSdk || settings.GenerateModels ? anyOfs
Expand All @@ -231,7 +231,7 @@ .. includedTags.Select(x => PropertyData.Default with
settings.Namespace,
schema.Key.ToClassName(),
schema.Value.GetSummary(),
schema.Value.AnyOf.Select((x, i) => TypeData.FromSchema(x.UseReferenceIdOrKey(schema.Key + $"Variant{i + 1}"), settings)).ToImmutableArray())))
schema.Value.AnyOf.ToAnyOfProperties(settings, schema.Key))))
.ToImmutableArray() : [];
oneOfs = settings.GenerateSdk || settings.GenerateModels ? oneOfs
.Concat(includedSchemas
Expand All @@ -244,7 +244,7 @@ .. includedTags.Select(x => PropertyData.Default with
settings.Namespace,
schema.Key.ToClassName(),
schema.Value.GetSummary(),
schema.Value.OneOf.Select((x, i) => TypeData.FromSchema(x.UseReferenceIdOrKey(schema.Key + $"Variant{i + 1}"), settings)).ToImmutableArray())))
schema.Value.OneOf.ToAnyOfProperties(settings, schema.Key))))
.ToImmutableArray() : [];
allOfs = settings.GenerateSdk || settings.GenerateModels ? allOfs
.Concat(includedSchemas
Expand All @@ -257,7 +257,7 @@ .. includedTags.Select(x => PropertyData.Default with
settings.Namespace,
schema.Key.ToClassName(),
schema.Value.GetSummary(),
schema.Value.AllOf.Select((x, i) => TypeData.FromSchema(x.UseReferenceIdOrKey(schema.Key + $"Variant{i + 1}"), settings)).ToImmutableArray())))
schema.Value.AllOf.ToAnyOfProperties(settings, schema.Key))))
.ToImmutableArray() : [];

AnyOfData[] anyOfDatas =
Expand Down
26 changes: 11 additions & 15 deletions src/libs/OpenApiGenerator.Core/Generation/Sources.AnyOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ public static string GenerateAnyOf(
{
var (subType, count, _, _, @namespace, className, summary, fixedTypes) = anyOfData;
var types = $"<{string.Join(", ", Enumerable.Range(1, count).Select(x => $"T{x}"))}>";
var validation = subType switch
{
"AnyOf" => string.Join(" || ", Enumerable.Range(1, count).Select(x => $"IsValue{x}")),
"OneOf" => string.Join(" || ", Enumerable.Range(1, count).Select(x =>
string.Join(" && ", Enumerable.Range(1, count).Select(y => $"{(y == x ? "!" : "")}IsValue{y}")))),
"AllOf" => string.Join(" && ", Enumerable.Range(1, count).Select(x => $"IsValue{x}")),
_ => throw new NotImplementedException(),
};
var classNameWithoutTypes = string.IsNullOrWhiteSpace(className)
? $"{subType}"
: className;
Expand All @@ -38,21 +30,25 @@ public static string GenerateAnyOf(
},
})
.ToImmutableArray()
: fixedTypes.Select((type, i) => PropertyData.Default with
{
Name = $"Value{i + 1}",
Type = type,
}).ToImmutableArray();
: fixedTypes;
var validation = subType switch
{
"AnyOf" => string.Join(" || ", allTypes.Select(x => $"Is{x.Name}")),
"OneOf" => string.Join(" || ", allTypes.Select((x, xi) =>
string.Join(" && ", allTypes.Select((y, yi) => $"{(yi == xi ? "!" : "")}Is{y.Name}")))),
"AllOf" => string.Join(" && ", allTypes.Select(x => $"Is{x.Name}")),
_ => throw new NotImplementedException(),
};
var constructorWithAllValues = count > 1 ? $@"
{string.Empty.ToXmlDocumentationSummary(level: 8)}
public {classNameWithoutTypes}(
{allTypes.Select(x => $@"
{x.Type.CSharpTypeWithNullability} {x.Name.ToParameterName()},
{x.Type.CSharpTypeWithNullability} {x.ParameterName},
").Inject().TrimEnd(',', '\n')}
)
{{
{allTypes.Select(x => $@"
{x.Name} = {x.Name.ToParameterName()};
{x.Name} = {x.ParameterName};
").Inject()}
}}" : " ";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static string GenerateAnyOfJsonConverter(
CancellationToken cancellationToken = default)
{
var (subType, count, jsonSerializerType, isTrimming, @namespace, name, _, fixedTypes) = anyOfData;
if (jsonSerializerType == JsonSerializerType.NewtonsoftJson)
if (jsonSerializerType != JsonSerializerType.SystemTextJson)
{
return string.Empty;
}
Expand All @@ -36,11 +36,7 @@ public static string GenerateAnyOfJsonConverter(
},
})
.ToImmutableArray()
: fixedTypes.Select((type, i) => PropertyData.Default with
{
Name = $"Value{i + 1}",
Type = type,
}).ToImmutableArray();
: fixedTypes;

return $@"#nullable enable
{(fixedTypes.IsEmpty ? "" : @"#pragma warning disable CS0618 // Type or member is obsolete
Expand Down
2 changes: 1 addition & 1 deletion src/libs/OpenApiGenerator.Core/Generation/Sources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static FileWithName AnyOfJsonConverterFactory(
CancellationToken cancellationToken = default)
{
if (anyOf.JsonSerializerType == JsonSerializerType.NewtonsoftJson ||
!anyOf.Types.IsEmpty)
!anyOf.Properties.IsEmpty)
{
return FileWithName.Empty;
}
Expand Down
33 changes: 33 additions & 0 deletions src/libs/OpenApiGenerator.Core/Helpers/SmartNamedAnyOfNames.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace OpenApiGenerator.Core.Helpers;

public static class SmartNamedAnyOfNames
{
public static string ComputeSmartName(string typeName, string className)
{
var nameWords = SplitToWordsByUpperCharacters(typeName);
var classNameWords = SplitToWordsByUpperCharacters(className);

// Combine the unique strings from both collections
return string.Concat(
nameWords.Except(classNameWords));
}

public static IReadOnlyList<string> SplitToWordsByUpperCharacters(string text)
{
text = text ?? throw new ArgumentNullException(nameof(text));

var words = new List<string>();
var startIndex = 0;
for (var i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]))
{
words.Add(text.Substring(startIndex, i - startIndex));
startIndex = i;
}
}
words.Add(text.Substring(startIndex));

return words;
}
}
2 changes: 1 addition & 1 deletion src/libs/OpenApiGenerator.Core/Models/AnyOfData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ public readonly record struct AnyOfData(
string Namespace,
string Name,
string Summary,
ImmutableArray<TypeData> Types
ImmutableArray<PropertyData> Properties
);
Loading

0 comments on commit 0aebf33

Please sign in to comment.