Skip to content

Commit

Permalink
feat: Implemented Class Style for ModelGenerator.
Browse files Browse the repository at this point in the history
  • Loading branch information
HavenDV committed Dec 6, 2023
1 parent 29d40a6 commit 055576d
Show file tree
Hide file tree
Showing 17 changed files with 707 additions and 17 deletions.
106 changes: 106 additions & 0 deletions src/libs/OpenApiGenerator/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Globalization;
using H.Generators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using OpenApiGenerator.Models;
Expand Down Expand Up @@ -50,4 +52,108 @@ public static OpenApiDocument GetOpenApiDocument(

return openApiDocument;
}

public static string GetCSharpType(this OpenApiSchema schema)
{
return (schema.Type, schema.Format) switch
{
("boolean", _) => "bool",
("integer", "int32") => "int",
("integer", "int64") => "long",
("number", "float") => "float",
("number", "double") => "double",
("string", "byte") => "byte",
("string", "binary") => "byte[]?",
("string", "date") => "global::System.DateTime",
("string", "date-time") => "global::System.DateTime",
("string", "password") => "string?",

("integer", _) => "int",
("number", _) => "double",
("string", _) => "string?",
("object", _) => "object?",
("array", _) => "object[]?",
_ => throw new NotSupportedException($"Type {schema.Type} is not supported."),
};
}

public static string? GetDefaultValue(this OpenApiSchema schema)
{
return schema.Default?.GetString();
}

private readonly static string[] NewLine = { "\n" };

public static string GetSummary(this OpenApiSchema schema)
{
var summary = schema.Description ?? string.Empty;
if (schema.Default != null)
{
summary += $"\nDefault Value: {schema.Default.GetString()}";
}
if (schema.Example != null)
{
summary += $"\nExample: {schema.Example.GetString()}";
}

return summary;
}

public static string GetString(this IOpenApiAny any)
{
return any switch
{
OpenApiString @string => @string.Value,
OpenApiInteger integer => integer.Value.ToString(CultureInfo.InvariantCulture),
OpenApiLong @long => @long.Value.ToString(CultureInfo.InvariantCulture),
OpenApiFloat @float => @float.Value.ToString(CultureInfo.InvariantCulture),
OpenApiDouble @double => @double.Value.ToString(CultureInfo.InvariantCulture),
OpenApiBoolean boolean => boolean.Value.ToString(),
OpenApiArray array => $"[{string.Join(", ", array.Select(GetString))}]",
OpenApiObject @object => $"{{{string.Join(", ", @object.Select(x => $"{x.Key}: {GetString(x.Value)}"))}}}",
_ => string.Empty,
};
}

public static string ToXmlDocumentationSummary(
this string text,
int level = 4)
{
var lines = text.Split(NewLine, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length == 0)
{
lines = new[] { string.Empty };
}

var spaces = string.Join(string.Empty, Enumerable.Repeat(" ", level));

return $@"/// <summary>
{string.Join("\n", lines
.Select(line => $"{spaces}/// {line}"))}
{spaces}/// </summary>";
}

public static string FixClassName(
this string propertyName,
string className)
{
return propertyName == className
? $"{propertyName}1"
: propertyName;
}

public static string FixUnderscore(
this string propertyName)
{
if (!propertyName.Contains('_'))
{
return propertyName;
}

return string.Join(
string.Empty,
propertyName
.Split('_')
.Select(word => word.ToPropertyName()));
}
}
14 changes: 13 additions & 1 deletion src/libs/OpenApiGenerator/Generators/ModelGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using H.Generators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.OpenApi.Models;
using OpenApiGenerator.Models;

namespace OpenApiGenerator;
Expand Down Expand Up @@ -46,7 +47,18 @@ private static EquatableArray<Model> PrepareData(
Name: schema.Key.ToPropertyName(),
Namespace: settings.Namespace,
Style: settings.ModelStyle,
Properties: Array.Empty<Property>().ToImmutableArray()))
Properties: schema.Value.Properties
.Select(x => new Property(
Id: x.Key,
Name: x.Key.ToPropertyName()
.FixClassName(schema.Key.ToPropertyName())
.FixUnderscore(),
Type: x.Value.GetCSharpType(),
IsRequired: x.Value.Required.Contains(x.Key),
DefaultValue: x.Value.GetDefaultValue(),
Summary: x.Value.GetSummary()))
.ToImmutableArray(),
Summary: schema.Value.GetSummary()))
.ToImmutableArray();
}

Expand Down
3 changes: 2 additions & 1 deletion src/libs/OpenApiGenerator/Models/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ internal readonly record struct Model(
string Name,
string Namespace,
ModelStyle Style,
EquatableArray<Property> Properties);
EquatableArray<Property> Properties,
string Summary);
6 changes: 5 additions & 1 deletion src/libs/OpenApiGenerator/Models/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ namespace OpenApiGenerator.Models;

internal readonly record struct Property(
string Id,
string Type);
string Name,
string Type,
bool IsRequired,
string? DefaultValue,
string Summary);
31 changes: 30 additions & 1 deletion src/libs/OpenApiGenerator/Sources/Sources.Models.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using H.Generators.Extensions;
using OpenApiGenerator.Models;

namespace OpenApiGenerator;
Expand All @@ -8,6 +9,34 @@ public static string GenerateModel(
Model model,
CancellationToken cancellationToken = default)
{
return "//";
return model.Style switch
{
ModelStyle.Class => GenerateClassModel(model, cancellationToken),
_ => throw new NotSupportedException($"Model style {model.Style} is not supported."),
};
}

public static string GenerateClassModel(
Model model,
CancellationToken cancellationToken = default)
{
return $@"
#nullable enable
namespace {model.Namespace}
{{
{model.Summary.ToXmlDocumentationSummary(level: 4)}
public sealed class {model.Name}
{{
{model.Properties.Select(property => @$"
{property.Summary.ToXmlDocumentationSummary(level: 8)}
[global::System.Text.Json.Serialization.JsonPropertyName(""{property.Id}"")]
public{(property.IsRequired ? " required" : "")} {property.Type} {property.Name} {{ get; set; }}{(property.IsRequired || property.DefaultValue == null ? string.Empty : $" = {property.DefaultValue};")}
").Inject()}
[global::System.Text.Json.Serialization.JsonExtensionData]
public global::System.Collections.Generic.IDictionary<string, object> AdditionalProperties {{ get; set; }} = new global::System.Collections.Generic.Dictionary<string, object>();
}}
}}";
}
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,51 @@
//HintName: G.Models.AbuseResponse.g.cs
//

#nullable enable

namespace G
{
/// <summary>
///
/// </summary>
public sealed class AbuseResponse
{
/// <summary>
/// Example: US, CA, Mountain View, 1600 Amphitheatre Parkway, 94043
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("address")]
public string? Address { get; set; }

/// <summary>
/// Example: US
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("country")]
public string? Country { get; set; }

/// <summary>
/// Example: [email protected]
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("email")]
public string? Email { get; set; }

/// <summary>
/// Example: Abuse
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("name")]
public string? Name { get; set; }

/// <summary>
/// Example: 8.8.8.0/24
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("network")]
public string? Network { get; set; }

/// <summary>
/// Example: +1-650-253-0000
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("phone")]
public string? Phone { get; set; }

[global::System.Text.Json.Serialization.JsonExtensionData]
public global::System.Collections.Generic.IDictionary<string, object> AdditionalProperties { get; set; } = new global::System.Collections.Generic.Dictionary<string, object>();
}
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,99 @@
//HintName: G.Models.AsnResponse.g.cs
//

#nullable enable

namespace G
{
/// <summary>
///
/// </summary>
public sealed class AsnResponse
{
/// <summary>
/// Example: AS10507
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("asn")]
public string? Asn { get; set; }

/// <summary>
/// Example: Sprint Personal Communications Systems
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("name")]
public string? Name { get; set; }

/// <summary>
/// Example: US
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("country")]
public string? Country { get; set; }

/// <summary>
/// Example: 1997-02-14
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("allocated")]
public string? Allocated { get; set; }

/// <summary>
/// Example: arin
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("registry")]
public string? Registry { get; set; }

/// <summary>
/// Example: sprint.net
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("domain")]
public string? Domain { get; set; }

/// <summary>
/// Example: 71224576
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("num_ips")]
public int NumIps { get; set; }

/// <summary>
/// Example: 66.87.125.0/24
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("route")]
public string? Route { get; set; }

/// <summary>
/// Example: isp
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("type")]
public string? Type { get; set; }

/// <summary>
///
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("prefixes")]
public object[]? Prefixes { get; set; }

/// <summary>
///
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("prefixes6")]
public object[]? Prefixes6 { get; set; }

/// <summary>
///
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("peers")]
public object[]? Peers { get; set; }

/// <summary>
///
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("upstreams")]
public object[]? Upstreams { get; set; }

/// <summary>
///
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("downstreams")]
public object[]? Downstreams { get; set; }

[global::System.Text.Json.Serialization.JsonExtensionData]
public global::System.Collections.Generic.IDictionary<string, object> AdditionalProperties { get; set; } = new global::System.Collections.Generic.Dictionary<string, object>();
}
}
Loading

0 comments on commit 055576d

Please sign in to comment.