Skip to content

Serialize configuration and tspCodeModel from swagger #5289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
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
18 changes: 0 additions & 18 deletions src/AutoRest.CSharp/AzurePlugin/AzurePluginTarget.cs

This file was deleted.

5 changes: 3 additions & 2 deletions src/AutoRest.CSharp/Common/AutoRest/Plugins/CSharpGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task<GeneratedCodeWorkspace> ExecuteAsync(CodeModel codeModel)
{
CodeModelTransformer.TransformForMgmt(codeModel);
var inputNamespace = new CodeModelConverter(codeModel, schemaUsageProvider).CreateNamespace();
await AzurePluginTarget.ExecuteAsync(project, inputNamespace);
await MicrosoftTypeSpecGeneratorTarget.ExecuteAsync(project, inputNamespace);
}
else
{
Expand Down Expand Up @@ -142,7 +142,8 @@ public async Task<bool> Execute(IPluginCommunication autoRest)
}

// generate csproj if necessary
if (!Configuration.SkipCSProj)
// when we generate via azure plugin, the csproj should be handled by the azure plugin, therefore here we skip it
if (!Configuration.SkipCSProj && !Configuration.UseAzurePlugin)
{
bool needAzureKeyAuth = codeModel.Security.Schemes.Any(scheme => scheme is KeySecurityScheme);
bool includeDfe = codeModelYaml.Contains("x-ms-format: dfe-", StringComparison.Ordinal);
Expand Down
45 changes: 39 additions & 6 deletions src/AutoRest.CSharp/Common/Input/CodeModelConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,11 @@ private InputEnumType CreateEnumType(Schema schema, PrimitiveSchema choiceType,
{
var usage = _schemaUsageProvider.GetUsage(schema);
var valueType = (InputPrimitiveType)CreateType(choiceType, schema.Extensions?.Format, false);
// the enum in typespec model only supports string int32 float32 and boolean
if (valueType.Kind != InputPrimitiveTypeKind.String && valueType.Kind != InputPrimitiveTypeKind.Int32 && valueType.Kind != InputPrimitiveTypeKind.Float32 && valueType.Kind != InputPrimitiveTypeKind.Boolean)
{
throw new NotSupportedException($"Enum type {valueType} is not supported");
}
var inputEnumType = new InputEnumType(
Name: schema.Name,
CrossLanguageDefinitionId: GetCrossLanguageDefinitionId(schema),
Expand Down Expand Up @@ -842,12 +847,40 @@ private static string GetCrossLanguageDefinitionId(Schema schema)
private static InputEnumTypeValue CreateEnumValue(ChoiceValue choiceValue, InputPrimitiveType valueType)
{
// in code model, the value of choices are defined to be strings. We need to convert them back to their real values
var value = ConvertRawValue(valueType, choiceValue.Value);
return new(
Name: choiceValue.Language.Default.Name,
Summary: string.Empty,
Doc: choiceValue.Language.Default.Description,
Value: value!);
var value = ConvertRawEnumValue(valueType, choiceValue.Value);
var name = choiceValue.Language.Default.Name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets consider making this a singleton

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created this issue to track: #5295

var doc = choiceValue.Language.Default.Description;
switch (valueType.Kind)
{
case InputPrimitiveTypeKind.String:
return new InputEnumTypeStringValue(name, (string)value, string.Empty, doc);
case InputPrimitiveTypeKind.Int32:
return new InputEnumTypeIntegerValue(name, (int)value, string.Empty, doc);
case InputPrimitiveTypeKind.Float32:
return new InputEnumTypeFloatValue(name, (float)value, string.Empty, doc);
default:
return new InputEnumTypeStringValue(name, value.ToString()!, string.Empty, doc);
}

static object ConvertRawEnumValue(InputPrimitiveType inputType, object originalValue)
{
if (originalValue is string strValue)
{
switch (inputType)
{
case InputPrimitiveType { Kind: InputPrimitiveTypeKind.Int32 }:
return int.TryParse(strValue, out var intValue) ? intValue : default(int);
case InputPrimitiveType { Kind: InputPrimitiveTypeKind.Float32 }:
return float.TryParse(strValue, out var floatValue) ? floatValue : default(float);
case InputPrimitiveType { Kind: InputPrimitiveTypeKind.Boolean }:
return bool.TryParse(strValue, out var boolValue) ? boolValue : default(bool);
default:
return strValue;
}
}

return originalValue;
}
}

private static RequestLocation GetRequestLocation(RequestParameter requestParameter) => requestParameter.In switch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace AutoRest.CSharp.Common.Input
{
public class InputDecoratorInfo
{
public InputDecoratorInfo(string name, IReadOnlyDictionary<string, BinaryData>? arguments)
public InputDecoratorInfo(string name, IReadOnlyDictionary<string, BinaryData> arguments)
{
Name = name;
Arguments = arguments;
}
public string Name { get; }
public IReadOnlyDictionary<string, BinaryData>? Arguments { get; }
public IReadOnlyDictionary<string, BinaryData> Arguments { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace AutoRest.CSharp.Common.Input;

internal record InputEnumTypeValue(string Name, object Value, string? Summary, string? Doc)
internal abstract record InputEnumTypeValue(string Name, object Value, string? Summary, string? Doc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think we should take this change to MTG to avoid instantiation of this.

Copy link
Member Author

@ArcturusZhang ArcturusZhang Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep - this part is done in a really messy way, as well as in MTG.
I think I would like to figure it out in MTG in the same time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and to clarify, I think "using the input library from MTG" should not be part of our plan - it will be a huge change and we might encounter various of issues. At least in short time, we do not need to consider to use the types from MTG - having these types defined in this library actually has its advantages.

{
public virtual string GetJsonValueString() => GetValueString();
public string GetValueString() => (Value.ToString() ?? string.Empty);
Expand Down
1 change: 0 additions & 1 deletion src/AutoRest.CSharp/Common/Input/InputTypes/InputType.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using AutoRest.CSharp.Common.Input.InputTypes;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using AutoRest.CSharp.Utilities;

namespace AutoRest.CSharp.Common.Input
{
internal class TypeSpecInputDateTimeTypeConverter : JsonConverter<InputDateTimeType>
{
internal const string UtcDateTimeKind = "utcDateTime";
internal const string OffsetDateTimeKind = "offsetDateTime";

private readonly TypeSpecReferenceHandler _referenceHandler;
public TypeSpecInputDateTimeTypeConverter(TypeSpecReferenceHandler referenceHandler)
{
Expand All @@ -19,9 +23,6 @@ public TypeSpecInputDateTimeTypeConverter(TypeSpecReferenceHandler referenceHand
public override InputDateTimeType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.ReadReferenceAndResolve<InputDateTimeType>(_referenceHandler.CurrentResolver) ?? CreateDateTimeType(ref reader, null, null, options, _referenceHandler.CurrentResolver);

public override void Write(Utf8JsonWriter writer, InputDateTimeType value, JsonSerializerOptions options)
=> throw new NotSupportedException("Writing not supported");

public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, string? id, string? name, JsonSerializerOptions options, ReferenceResolver resolver)
{
var isFirstProperty = id == null;
Expand Down Expand Up @@ -65,5 +66,26 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st
}
return dateTimeType;
}

public override void Write(Utf8JsonWriter writer, InputDateTimeType value, JsonSerializerOptions options)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets add a tracking item to consider using the MTG.Input library instead of having its own.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here: #5292

=> writer.WriteObjectOrReference<InputDateTimeType>(value, options, _referenceHandler.CurrentResolver, WriteInputDateTimeType);

private static void WriteInputDateTimeType(Utf8JsonWriter writer, InputDateTimeType value, JsonSerializerOptions options)
{
// kind
writer.WriteString("kind", UtcDateTimeKind); // TODO -- currently the two different kinds have exactly the same properties, therefore here we no longer have the ability to distinguish
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the plan for this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is possible that we make this class abstract, and make UtcDateTimeType and OffsetDateTimeType to derive from it, like what we have done for InputType.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I think we should also do the same in MTG.

// name
writer.WriteString("name", value.Name);
// encode
writer.WriteString("encode", value.Encode.ToString().FirstCharToLowerCase());
// wireType
writer.WriteObject("wireType", value.WireType, options);
// crossLanguageDefinitionId
writer.WriteString("crossLanguageDefinitionId", value.CrossLanguageDefinitionId);
// baseType
writer.WriteObjectIfPresent("baseType", value.BaseType, options);
// decorators
writer.WriteArray("decorators", value.Decorators, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ public TypeSpecInputDecoratorInfoConverter(TypeSpecReferenceHandler referenceHan
public override InputDecoratorInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.ReadReferenceAndResolve<InputDecoratorInfo>(_referenceHandler.CurrentResolver) ?? CreateDecoratorInfo(ref reader, null, options, _referenceHandler.CurrentResolver);

public override void Write(Utf8JsonWriter writer, InputDecoratorInfo value, JsonSerializerOptions options)
=> throw new NotSupportedException("Writing not supported");

private static InputDecoratorInfo? CreateDecoratorInfo(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver)
{
var isFirstProperty = id == null;
Expand All @@ -40,13 +37,24 @@ public override void Write(Utf8JsonWriter writer, InputDecoratorInfo value, Json
}
}
reader.Read();
var decoratorInfo = new InputDecoratorInfo(name ?? throw new JsonException("InputDecoratorInfo must have name"), arguments);
var decoratorInfo = new InputDecoratorInfo(name ?? throw new JsonException("InputDecoratorInfo must have name"), arguments ?? new Dictionary<string, BinaryData>());

if (id != null)
{
resolver.AddReference(id, decoratorInfo);
}
return decoratorInfo;
}

public override void Write(Utf8JsonWriter writer, InputDecoratorInfo value, JsonSerializerOptions options)
{
// the decorators do not need an id
writer.WriteStartObject();

writer.WriteString("name", value.Name);
writer.WriteDictionary("arguments", value.Arguments);

writer.WriteEndObject();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace AutoRest.CSharp.Common.Input
{
internal sealed class TypeSpecInputDictionaryTypeConverter : JsonConverter<InputDictionaryType>
{
internal const string DictionaryKind = "dict";

private readonly TypeSpecReferenceHandler _referenceHandler;

public TypeSpecInputDictionaryTypeConverter(TypeSpecReferenceHandler referenceHandler)
Expand All @@ -20,9 +22,6 @@ public TypeSpecInputDictionaryTypeConverter(TypeSpecReferenceHandler referenceHa
public override InputDictionaryType? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.ReadReferenceAndResolve<InputDictionaryType>(_referenceHandler.CurrentResolver) ?? CreateDictionaryType(ref reader, null, options, _referenceHandler.CurrentResolver);

public override void Write(Utf8JsonWriter writer, InputDictionaryType value, JsonSerializerOptions options)
=> throw new NotSupportedException("Writing not supported");

public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver)
{
var isFirstProperty = id == null;
Expand Down Expand Up @@ -56,5 +55,20 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader
}
return dictType;
}

public override void Write(Utf8JsonWriter writer, InputDictionaryType value, JsonSerializerOptions options)
=> writer.WriteObjectOrReference(value, options, _referenceHandler.CurrentResolver, WriteInputDictionaryTypeProperties);

private static void WriteInputDictionaryTypeProperties(Utf8JsonWriter writer, InputDictionaryType value, JsonSerializerOptions options)
{
// kind
writer.WriteString("kind", DictionaryKind);
// keyType
writer.WriteObject("keyType", value.KeyType, options);
// valueType
writer.WriteObject("valueType", value.ValueType, options);
// decorators
writer.WriteArray("decorators", value.Decorators, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace AutoRest.CSharp.Common.Input
{
internal class TypeSpecInputDurationTypeConverter : JsonConverter<InputDurationType>
{
internal const string DurationKind = "duration";

private readonly TypeSpecReferenceHandler _referenceHandler;
public TypeSpecInputDurationTypeConverter(TypeSpecReferenceHandler referenceHandler)
{
Expand All @@ -19,9 +21,6 @@ public TypeSpecInputDurationTypeConverter(TypeSpecReferenceHandler referenceHand
public override InputDurationType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.ReadReferenceAndResolve<InputDurationType>(_referenceHandler.CurrentResolver) ?? CreateDurationType(ref reader, null, null, options, _referenceHandler.CurrentResolver);

public override void Write(Utf8JsonWriter writer, InputDurationType value, JsonSerializerOptions options)
=> throw new NotSupportedException("Writing not supported");

public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, string? id, string? name, JsonSerializerOptions options, ReferenceResolver resolver)
{
var isFirstProperty = id == null;
Expand Down Expand Up @@ -61,9 +60,11 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st
return dateTimeType;
}

private const string DurationConstantEncode = "duration-constant";

private static DurationKnownEncoding CreateDurationKnownEncoding(string encode)
{
if (encode == "duration-constant")
if (encode == DurationConstantEncode)
{
return DurationKnownEncoding.DurationConstant;
}
Expand All @@ -73,5 +74,30 @@ private static DurationKnownEncoding CreateDurationKnownEncoding(string encode)
}
throw new JsonException($"Encoding of Duration type {encode} is unknown.");
}

public override void Write(Utf8JsonWriter writer, InputDurationType value, JsonSerializerOptions options)
=> writer.WriteObjectOrReference(value, options, _referenceHandler.CurrentResolver, WriteInputDurationTypeProperties);

private static void WriteInputDurationTypeProperties(Utf8JsonWriter writer, InputDurationType value, JsonSerializerOptions options)
{
// kind
writer.WriteString("kind", DurationKind);
// name
writer.WriteString("name", value.Name);
// encode
writer.WriteString("encode", value.Encode switch
{
DurationKnownEncoding.DurationConstant => DurationConstantEncode,
_ => value.Encode.ToString().ToLowerInvariant(),
});
// wireType
writer.WriteObject("wireType", value.WireType, options);
// crossLanguageDefinitionId
writer.WriteString("crossLanguageDefinitionId", value.CrossLanguageDefinitionId);
// baseType
writer.WriteObjectIfPresent("baseType", value.BaseType, options);
// decorators
writer.WriteArray("decorators", value.Decorators, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace AutoRest.CSharp.Common.Input
{
internal sealed class TypeSpecInputEnumTypeConverter : JsonConverter<InputEnumType>
{
internal const string EnumKind = "enum";

private readonly TypeSpecReferenceHandler _referenceHandler;

public TypeSpecInputEnumTypeConverter(TypeSpecReferenceHandler referenceHandler)
Expand All @@ -21,9 +23,6 @@ public TypeSpecInputEnumTypeConverter(TypeSpecReferenceHandler referenceHandler)
public override InputEnumType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.ReadReferenceAndResolve<InputEnumType>(_referenceHandler.CurrentResolver) ?? CreateEnumType(ref reader, null, null, options, _referenceHandler.CurrentResolver);

public override void Write(Utf8JsonWriter writer, InputEnumType value, JsonSerializerOptions options)
=> throw new NotSupportedException("Writing not supported");

public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id, string? name, JsonSerializerOptions options, ReferenceResolver resolver)
{
var isFirstProperty = id == null && name == null;
Expand Down Expand Up @@ -94,5 +93,38 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id
}
return enumType;
}

public override void Write(Utf8JsonWriter writer, InputEnumType value, JsonSerializerOptions options)
=> writer.WriteObjectOrReference(value, options, _referenceHandler.CurrentResolver, WriteInputEnumTypeProperties);

private static void WriteInputEnumTypeProperties(Utf8JsonWriter writer, InputEnumType value, JsonSerializerOptions options)
{
// kind
writer.WriteString("kind", EnumKind);
// name
writer.WriteString("name", value.Name);
// crossLanguageDefinitionId
writer.WriteString("crossLanguageDefinitionId", value.CrossLanguageDefinitionId);
// valueType
writer.WriteObject("valueType", value.ValueType, options);
// values
writer.WriteArray("values", value.Values, options);
// access
writer.WriteStringIfPresent("access", value.Accessibility);
// namespace
writer.WriteString("namespace", string.Empty); // here the writing is a shimming layer from swagger to typespec. Swagger does not have the concept of namespace
// deprecation
writer.WriteStringIfPresent("deprecation", value.Deprecated);
// summary
writer.WriteStringIfPresent("summary", value.Summary);
// doc
writer.WriteStringIfPresent("doc", value.Doc);
// isFixed
writer.WriteBoolean("isFixed", !value.IsExtensible);
// usage
writer.WriteString("usage", value.Usage.ToString());
// decorators
writer.WriteArray("decorators", value.Decorators, options);
}
}
}
Loading
Loading