Skip to content

Commit

Permalink
feat: Added ability to use Newtonsoft.Json.
Browse files Browse the repository at this point in the history
  • Loading branch information
HavenDV committed May 11, 2024
1 parent 6519e0f commit 3ef6e91
Show file tree
Hide file tree
Showing 41 changed files with 268 additions and 226 deletions.
1 change: 1 addition & 0 deletions src/apps/OpenApiGenerator.Cli/Commands/GenerateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ private static async Task HandleAsync(string inputPath, string outputPath, strin
Namespace: @namespace,
ClassName: clientClassName,
NamingConvention: default,
JsonSerializerType: default,
IncludeOperationIds: [],
GenerateModels: true,
ModelStyle: default,
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</ItemGroup>

<PropertyGroup Label="Versioning">
<Version>0.1.5</Version>
<Version>0.2.0</Version>
<MinVerMinimumMajorMinor>0.1</MinVerMinimumMajorMinor>
<MinVerTagPrefix>v</MinVerTagPrefix>
<MinVerDefaultPreReleaseIdentifiers>dev</MinVerDefaultPreReleaseIdentifiers>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using OpenApiGenerator.Core.Json;
using OpenApiGenerator.Core.Models;

namespace OpenApiGenerator.Core.Extensions;
Expand Down Expand Up @@ -37,8 +38,11 @@ public static string GetCSharpType(
(null, _) when schema.Value.OneOf.Any() => ("object", true),
(null, _) when schema.Value.AllOf.Any() => ("object", true),

("string", _) when schema.Value.Enum.Any() =>
// Only Newtonsoft.Json supports EnumMemberAttribute
("string", _) when schema.Value.Enum.Any() && settings.JsonSerializerType == JsonSerializerType.NewtonsoftJson =>
($"{(model with { Style = ModelStyle.Enumeration }).ExternalClassName}", true),
("string", _) when schema.Value.Enum.Any() && settings.JsonSerializerType != JsonSerializerType.NewtonsoftJson =>
("string", true),

("boolean", _) => ("bool", false),
("integer", "int32") => ("int", false),
Expand Down
23 changes: 20 additions & 3 deletions src/libs/OpenApiGenerator.Core/Generation/Sources.Models.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using OpenApiGenerator.Core.Extensions;
using OpenApiGenerator.Core.Json;
using OpenApiGenerator.Core.Models;

namespace OpenApiGenerator.Core.Generation;
Expand Down Expand Up @@ -45,7 +46,10 @@ public static string GenerateEnumerationModel(
ModelData modelData,
CancellationToken cancellationToken = default)
{
return $@"
// Only Newtonsoft.Json supports EnumMemberAttribute
if (modelData.JsonSerializerType == JsonSerializerType.NewtonsoftJson)
{
return $@"
{modelData.Summary.ToXmlDocumentationSummary(level: 4)}
[global::System.Runtime.Serialization.DataContract]
public enum {modelData.ClassName}
Expand All @@ -55,25 +59,38 @@ public enum {modelData.ClassName}
[global::System.Runtime.Serialization.EnumMember(Value=""{property.Id}"")]
{property.Name},
").Inject()}
}}".RemoveBlankLinesWhereOnlyWhitespaces();
}

return $@"
{modelData.Summary.ToXmlDocumentationSummary(level: 4)}
public abstract class {modelData.ClassName}
{{
{modelData.Properties.Select(property => @$"
{property.Summary.ToXmlDocumentationSummary(level: 8)}
public const string {property.Name} = ""{property.Id}"";
").Inject()}
}}".RemoveBlankLinesWhereOnlyWhitespaces();
}

public static string GenerateClassModel(
ModelData modelData,
CancellationToken cancellationToken = default)
{
var jsonSerializer = modelData.JsonSerializerType.GetSerializer();

return $@"
{modelData.Summary.ToXmlDocumentationSummary(level: 4)}
public sealed partial class {modelData.ClassName}
{{
{modelData.Properties.Select(property => @$"
{property.Summary.ToXmlDocumentationSummary(level: 8)}
[global::System.Text.Json.Serialization.JsonPropertyName(""{property.Id}"")]
{jsonSerializer.GeneratePropertyAttribute(property.Id)}
public{(property.IsRequired ? " required" : "")} {property.Type} {property.Name} {{ get; set; }}{(property.IsRequired || property.DefaultValue == null ? string.Empty : $" = {property.DefaultValue};")}
").Inject()}
{"Additional properties that are not explicitly defined in the schema".ToXmlDocumentationSummary(level: 8)}
[global::System.Text.Json.Serialization.JsonExtensionData]
{jsonSerializer.GenerateExtensionDataAttribute()}
public global::System.Collections.Generic.IDictionary<string, object> AdditionalProperties {{ get; set; }} = new global::System.Collections.Generic.Dictionary<string, object>();
}}".RemoveBlankLinesWhereOnlyWhitespaces();
}
Expand Down
7 changes: 7 additions & 0 deletions src/libs/OpenApiGenerator.Core/Json/IJsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OpenApiGenerator.Core.Json;

public interface IJsonSerializer
{
public string GeneratePropertyAttribute(string id);
string GenerateExtensionDataAttribute();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace OpenApiGenerator.Core.Json;

public static class JsonSerializationTypeExtensions
{
// Returns the serializer type based on the provided enum value.
public static IJsonSerializer GetSerializer(this JsonSerializerType type)
{
return type switch
{
JsonSerializerType.SystemTextJson => SystemTextJsonSerializer.Instance,
JsonSerializerType.NewtonsoftJson => NewtonsoftJsonSerializer.Instance,
_ => throw new NotSupportedException($"Serializer type {type} is not supported.")
};
}
}
7 changes: 7 additions & 0 deletions src/libs/OpenApiGenerator.Core/Json/JsonSerializerType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OpenApiGenerator.Core.Json;

public enum JsonSerializerType
{
SystemTextJson,
NewtonsoftJson,
}
16 changes: 16 additions & 0 deletions src/libs/OpenApiGenerator.Core/Json/NewtonsoftJsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace OpenApiGenerator.Core.Json;

public class NewtonsoftJsonSerializer : IJsonSerializer
{
public static IJsonSerializer Instance { get; } = new NewtonsoftJsonSerializer();

public string GeneratePropertyAttribute(string id)
{
return $"[global::Newtonsoft.Json.JsonProperty(\"{id}\")]";
}

public string GenerateExtensionDataAttribute()
{
return "[global::Newtonsoft.Json.JsonExtensionData]";
}
}
16 changes: 16 additions & 0 deletions src/libs/OpenApiGenerator.Core/Json/SystemTextJsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace OpenApiGenerator.Core.Json;

public class SystemTextJsonSerializer : IJsonSerializer
{
public static IJsonSerializer Instance { get; } = new SystemTextJsonSerializer();

public string GeneratePropertyAttribute(string id)
{
return $"[global::System.Text.Json.Serialization.JsonPropertyName(\"{id}\")]";
}

public string GenerateExtensionDataAttribute()
{
return "[global::System.Text.Json.Serialization.JsonExtensionData]";
}
}
4 changes: 4 additions & 0 deletions src/libs/OpenApiGenerator.Core/Models/ModelData.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using Microsoft.OpenApi.Models;
using OpenApiGenerator.Core.Extensions;
using OpenApiGenerator.Core.Json;

namespace OpenApiGenerator.Core.Models;

Expand All @@ -12,6 +13,7 @@ public readonly record struct ModelData(
string Namespace,
NamingConvention NamingConvention,
ModelStyle Style,
JsonSerializerType JsonSerializerType,
ImmutableArray<PropertyData> Properties,
string Summary,
ImmutableArray<ModelData> AdditionalModels,
Expand Down Expand Up @@ -45,6 +47,7 @@ public static ModelData FromKey(
Parents: parents.ToImmutableArray(),
Namespace: settings.Namespace,
NamingConvention: settings.NamingConvention,
JsonSerializerType: settings.JsonSerializerType,
Style: settings.ModelStyle,
Properties: ImmutableArray<PropertyData>.Empty,
Summary: string.Empty,
Expand All @@ -65,6 +68,7 @@ public static ModelData FromSchema(
Parents: parents.ToImmutableArray(),
Namespace: settings.Namespace,
NamingConvention: settings.NamingConvention,
JsonSerializerType: settings.JsonSerializerType,
Style: settings.ModelStyle,
Properties: ImmutableArray<PropertyData>.Empty,
Summary: schema.Value.GetSummary(),
Expand Down
2 changes: 2 additions & 0 deletions src/libs/OpenApiGenerator.Core/Models/Settings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using OpenApiGenerator.Core.Json;

namespace OpenApiGenerator.Core.Models;

Expand All @@ -7,6 +8,7 @@ public readonly record struct Settings(
string Namespace,
string ClassName,
NamingConvention NamingConvention,
JsonSerializerType JsonSerializerType,

ImmutableArray<string> IncludeOperationIds,

Expand Down
2 changes: 2 additions & 0 deletions src/libs/OpenApiGenerator/OpenApiGenerator.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<CompilerVisibleProperty Include="OpenApiGenerator_ClassName"/>
<!-- InnerClasses/ConcatNames. Default: InnerClasses -->
<CompilerVisibleProperty Include="OpenApiGenerator_NamingConvention"/>
<!-- SystemTextJson/NewtonsoftJson. Default: SystemTextJson -->
<CompilerVisibleProperty Include="OpenApiGenerator_JsonSerializerType"/>

<!-- List of ids separated by ;. Default: Empty(all models) -->
<CompilerVisibleProperty Include="OpenApiGenerator_IncludeOperationIds"/>
Expand Down
6 changes: 6 additions & 0 deletions src/libs/OpenApiGenerator/OptionsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using OpenApiGenerator.Core.Models;
using OpenApiGenerator.Core.Extensions;
using OpenApiGenerator.Core.Json;

namespace OpenApiGenerator;

Expand All @@ -30,6 +31,11 @@ public static Settings GetSettings(
$"{default(NamingConvention):G}",
ignoreCase: true,
out var namingConvention) ? namingConvention : default,
JsonSerializerType: Enum.TryParse<JsonSerializerType>(
options.GetGlobalOption(nameof(Settings.JsonSerializerType), prefix) ??
$"{default(JsonSerializerType):G}",
ignoreCase: true,
out var jsonSerializerType) ? jsonSerializerType : default,

IncludeOperationIds: (options.GetGlobalOption(nameof(Settings.IncludeOperationIds), prefix)?.Split(';') ??
Array.Empty<string>()).ToImmutableArray(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public sealed partial class CreateModelResponse
/// Status creating the model
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("status")]
public CreateModelResponseStatus? Status { get; set; }
public string? Status { get; set; }

/// <summary>
/// Additional properties that are not explicitly defined in the schema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,19 @@ namespace G
/// <summary>
/// Status creating the model
/// </summary>
[global::System.Runtime.Serialization.DataContract]
public enum CreateModelResponseStatus
public abstract class CreateModelResponseStatus
{
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="creating system layer")]
CreatingSystemLayer,
public const string CreatingSystemLayer = "creating system layer";
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="parsing modelfile")]
ParsingModelfile,
public const string ParsingModelfile = "parsing modelfile";
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="success")]
Success,
public const string Success = "success";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public sealed partial class GenerateChatCompletionRequest
/// Note: it's important to instruct the model to use JSON in the prompt. Otherwise, the model may generate large amounts whitespace.
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("format")]
public GenerateChatCompletionRequestFormat? Format { get; set; }
public string? Format { get; set; }

/// <summary>
/// Additional model parameters listed in the documentation for the Modelfile such as `temperature`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ namespace G
/// Enable JSON mode by setting the format parameter to json. This will structure the response as valid JSON.
/// Note: it's important to instruct the model to use JSON in the prompt. Otherwise, the model may generate large amounts whitespace.
/// </summary>
[global::System.Runtime.Serialization.DataContract]
public enum GenerateChatCompletionRequestFormat
public abstract class GenerateChatCompletionRequestFormat
{
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="json")]
Json,
public const string Json = "json";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public sealed partial class GenerateCompletionRequest
/// Note: it's important to instruct the model to use JSON in the prompt. Otherwise, the model may generate large amounts whitespace.
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("format")]
public GenerateCompletionRequestFormat? Format { get; set; }
public string? Format { get; set; }

/// <summary>
/// If `true` no formatting will be applied to the prompt and no context will be returned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ namespace G
/// Enable JSON mode by setting the format parameter to json. This will structure the response as valid JSON.
/// Note: it's important to instruct the model to use JSON in the prompt. Otherwise, the model may generate large amounts whitespace.
/// </summary>
[global::System.Runtime.Serialization.DataContract]
public enum GenerateCompletionRequestFormat
public abstract class GenerateCompletionRequestFormat
{
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="json")]
Json,
public const string Json = "json";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public sealed partial class Message
/// The role of the message
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("role")]
public required MessageRole Role { get; set; }
public required string Role { get; set; }

/// <summary>
/// The content of the message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,19 @@ namespace G
/// <summary>
/// The role of the message
/// </summary>
[global::System.Runtime.Serialization.DataContract]
public enum MessageRole
public abstract class MessageRole
{
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="system")]
System,
public const string System = "system";
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="user")]
User,
public const string User = "user";
/// <summary>
///
/// </summary>
[global::System.Runtime.Serialization.EnumMember(Value="assistant")]
Assistant,
public const string Assistant = "assistant";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public sealed partial class PullModelResponse
/// <br/>Example: pulling manifest
/// </summary>
[global::System.Text.Json.Serialization.JsonPropertyName("status")]
public PullModelResponseStatus? Status { get; set; }
public string? Status { get; set; }

/// <summary>
/// The model's digest.
Expand Down
Loading

0 comments on commit 3ef6e91

Please sign in to comment.