From 58654d6ba08f0532c45b4f4761b9c06ad261bdd0 Mon Sep 17 00:00:00 2001 From: m-nash <64171366+m-nash@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:56:45 -0700 Subject: [PATCH] Initial changes for serialization helpers (#3590) Fixes https://github.com/microsoft/typespec/issues/3580 Fixes https://github.com/microsoft/typespec/issues/3536 --- cspell.yaml | 9 + .../src/ClientModelPlugin.cs | 9 +- ...rosoft.Generator.CSharp.ClientModel.csproj | 2 +- .../src/OutputTypes/ScmKnownParameters.cs | 31 + .../src/OutputTypes/ScmOutputLibrary.cs | 21 + .../ClientPipelineExtensionsProvider.cs | 2 +- .../ModelSerializationExtensionsProvider.cs | 609 ++++++++++++++++++ .../MrwSerializationTypeProvider.cs | 29 +- .../src/Providers/TypeFormattersProvider.cs | 369 +++++++++++ .../src/ScmTypeFactory.cs | 5 +- ...mExtensibleSnippets.SystemModelSnippets.cs | 3 +- .../ModelReaderWriterOptionsSnippet.cs | 17 + .../src/Utilities/FormattableStringHelpers.cs | 6 +- .../Utf8JsonWriterSnippetExtensions.cs | 19 + ....Generator.CSharp.ClientModel.Tests.csproj | 1 + .../test/MrwSerializationTypeProviderTests.cs | 14 +- .../test/TypeFormatterTests.cs | 144 +++++ .../src/CSharpGen.cs | 8 +- .../src/CodeModelPlugin.cs | 2 + .../src/OutputTypes/CSharpMethodCollection.cs | 9 +- .../src/OutputTypes/OutputLibrary.cs | 15 + .../OutputTypes/PropertyDescriptionBuilder.cs | 140 ++-- .../src/OutputTypes/TypeFactory.cs | 3 +- .../PostProcessing/GeneratedCodeWorkspace.cs | 2 +- .../src/Providers/ArgumentProvider.cs | 33 +- .../ChangeTrackingDictionaryProvider.cs | 44 +- .../Providers/ChangeTrackingListProvider.cs | 42 +- .../src/Providers/ClientProvider.cs | 2 +- .../src/Providers/EnumProvider.cs | 4 +- .../src/Providers/ExtensibleEnumProvider.cs | 18 +- .../src/Providers/FixedEnumProvider.cs | 2 +- .../FixedEnumSerializationProvider.cs | 4 +- .../src/Providers/MethodProvider.cs | 49 +- .../src/Providers/ModelProvider.cs | 7 +- .../src/Providers/OptionalProvider.cs | 21 +- .../src/Providers/PropertyProvider.cs | 12 +- .../src/Providers/TypeProvider.cs | 13 +- .../src/Providers/XmlDocProvider.cs | 4 + .../src/Statements/IfElseStatement.cs | 24 +- .../src/Statements/SwitchCaseStatement.cs | 29 +- .../src/Statements/SwitchStatement.cs | 3 +- .../src/Statements/XmlDocInheritStatement.cs | 13 + .../src/Statements/XmlDocStatement.cs | 166 ++++- .../src/Statements/XmlDocSummaryStatement.cs | 4 +- .../src/TypedSnippets/ObjectSnippet.cs | 12 + .../src/Utilities/FormattableStringHelpers.cs | 3 +- .../src/Writers/CodeWriter.cs | 8 +- .../src/Writers/TypeProviderWriter.cs | 5 + .../test/CSharpMethodCollectionTests.cs | 2 +- .../test/CodeWriterExtensionTests.cs | 31 - .../Microsoft.Generator.CSharp.Tests.csproj | 2 +- .../test/Mocks/MockTypeFactory.cs | 2 +- .../test/Mocks/MockTypeProvider.cs | 13 + .../EnumTypeProviderTests.cs | 2 +- .../ModelTypeProviderTests.cs | 2 +- .../PropertyDescriptionTests.cs | 25 +- .../test/{ => Statements}/StatementTests.cs | 2 +- .../Statements/XmlDocParamStatementTests.cs | 29 + .../test/Statements/XmlDocStatementTests.cs | 49 ++ .../test/TypeFactoryTests.cs | 2 +- .../Local/TestProjects.Local.Tests.csproj | 1 + .../src/Generated/Internal/Argument.cs | 26 - .../Internal/ChangeTrackingDictionary.cs | 13 - .../Generated/Internal/ChangeTrackingList.cs | 11 - .../Internal/ModelSerializationExtensions.cs | 251 ++++++++ .../src/Generated/Internal/Optional.cs | 11 +- .../src/Generated/Internal/TypeFormatters.cs | 150 +++++ .../Generated/Models/FloatExtensibleEnum.cs | 3 + .../Models/FloatExtensibleEnumWithIntValue.cs | 3 + .../src/Generated/Models/FloatFixedEnum.cs | 4 + .../Models/FloatFixedEnumExtensions.cs | 2 - .../Models/FloatFixedEnumWithIntValue.cs | 4 + .../FloatFixedEnumWithIntValueExtensions.cs | 1 - .../Generated/Models/Friend.Serialization.cs | 31 +- .../src/Generated/Models/Friend.cs | 1 + .../src/Generated/Models/IntExtensibleEnum.cs | 3 + .../src/Generated/Models/IntFixedEnum.cs | 4 + .../Models/IntFixedEnumExtensions.cs | 1 - ...equiredNullableProperties.Serialization.cs | 35 +- .../ModelWithRequiredNullableProperties.cs | 1 + .../Models/ProjectedModel.Serialization.cs | 31 +- .../src/Generated/Models/ProjectedModel.cs | 1 + ...rnsAnonymousModelResponse.Serialization.cs | 29 +- .../Models/ReturnsAnonymousModelResponse.cs | 2 +- .../Models/RoundTripModel.Serialization.cs | 54 +- .../src/Generated/Models/RoundTripModel.cs | 174 +++-- .../Generated/Models/StringExtensibleEnum.cs | 3 + .../src/Generated/Models/StringFixedEnum.cs | 4 + .../Models/StringFixedEnumExtensions.cs | 2 - .../Generated/Models/Thing.Serialization.cs | 43 +- .../src/Generated/Models/Thing.cs | 42 +- .../Models/ThingOptionalLiteralFloat.cs | 3 + .../Models/ThingOptionalLiteralInt.cs | 3 + .../Models/ThingOptionalLiteralString.cs | 3 + .../Models/ThingRequiredLiteralFloat.cs | 3 + .../Models/ThingRequiredLiteralInt.cs | 3 + .../Models/ThingRequiredLiteralString.cs | 3 + .../src/Generated/UnbrandedTypeSpecClient.cs | 120 +--- .../src/UnbrandedTypeSpec.csproj | 16 + 99 files changed, 2475 insertions(+), 772 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/{Models/Types => Providers}/ClientPipelineExtensionsProvider.cs (98%) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/{Models/Types => Providers}/MrwSerializationTypeProvider.cs (92%) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ModelReaderWriterOptionsSnippet.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/Utf8JsonWriterSnippetExtensions.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TypeFormatterTests.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocInheritStatement.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ObjectSnippet.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeProvider.cs rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/{Models/Types => Providers}/EnumTypeProviderTests.cs (99%) rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/{Models/Types => Providers}/ModelTypeProviderTests.cs (99%) rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/{Models => Providers}/PropertyDescriptionTests.cs (78%) rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/{ => Statements}/StatementTests.cs (99%) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocParamStatementTests.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocStatementTests.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/TypeFormatters.cs create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/UnbrandedTypeSpec.csproj diff --git a/cspell.yaml b/cspell.yaml index 0ffb1bb753..7abdd42500 100644 --- a/cspell.yaml +++ b/cspell.yaml @@ -146,6 +146,15 @@ ignorePaths: - .editorconfig - .github/CODEOWNERS - packages/samples/test/output/** + - "**/BenchmarkDotNet.Artifacts/**" + - cspell.yaml +overrides: + - filename: "packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TypeFormatterTests.cs" + words: + - BAUG + - filename: "packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocStatement.cs" + words: + - apos useGitignore: true enableGlobDot: true enableFiletypes: diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ClientModelPlugin.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ClientModelPlugin.cs index a16f0f073d..9d2c2465c7 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ClientModelPlugin.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ClientModelPlugin.cs @@ -2,10 +2,13 @@ // Licensed under the MIT License. using System; +using System.ClientModel; using System.Collections.Generic; using System.ComponentModel.Composition; -using Microsoft.Generator.CSharp.Input; +using Microsoft.CodeAnalysis; +using Microsoft.Generator.CSharp.ClientModel.Providers; using Microsoft.Generator.CSharp.ClientModel.Snippets; +using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Providers; using Microsoft.Generator.CSharp.Snippets; @@ -17,7 +20,7 @@ public class ClientModelPlugin : CodeModelPlugin internal static ClientModelPlugin Instance => _instance ?? throw new InvalidOperationException("ClientModelPlugin is not loaded."); public override ApiTypes ApiTypes { get; } - private OutputLibrary? _scmOutputLibrary; + private ScmOutputLibrary? _scmOutputLibrary; public override OutputLibrary OutputLibrary => _scmOutputLibrary ??= new(); public override TypeProviderWriter GetWriter(TypeProvider provider) => new(provider); @@ -26,6 +29,8 @@ public class ClientModelPlugin : CodeModelPlugin public override ExtensibleSnippets ExtensibleSnippets { get; } + public override IReadOnlyList AdditionalMetadataReferences => [MetadataReference.CreateFromFile(typeof(ClientResult).Assembly.Location)]; + /// /// Returns the serialization type providers for the given model type provider. /// diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Microsoft.Generator.CSharp.ClientModel.csproj b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Microsoft.Generator.CSharp.ClientModel.csproj index fa4d734d76..d54fd1d85d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Microsoft.Generator.CSharp.ClientModel.csproj +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Microsoft.Generator.CSharp.ClientModel.csproj @@ -18,7 +18,7 @@ - + diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs new file mode 100644 index 0000000000..05b80fd551 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmKnownParameters.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Text.Json; +using System.Xml; +using System.Xml.Linq; +using Microsoft.Generator.CSharp.Providers; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel +{ + internal static class ScmKnownParameters + { + private static readonly CSharpType modelReaderWriterOptionsType = typeof(ModelReaderWriterOptions); + private static readonly CSharpType nullableModelReaderWriterOptionsType = new CSharpType(typeof(ModelReaderWriterOptions), isNullable: true); + + public static readonly ParameterProvider XmlWriter = new ParameterProvider("writer", FormattableStringHelpers.Empty, typeof(XmlWriter)); + public static readonly ParameterProvider NameHint = new ParameterProvider("nameHint", FormattableStringHelpers.Empty, typeof(string)); + public static readonly ParameterProvider XElement = new ParameterProvider("element", FormattableStringHelpers.Empty, typeof(XElement)); + + public static readonly ParameterProvider Utf8JsonWriter = new ParameterProvider("writer", FormattableStringHelpers.Empty, typeof(Utf8JsonWriter)); + public static readonly ParameterProvider Utf8JsonReader = new ParameterProvider("reader", FormattableStringHelpers.Empty, typeof(Utf8JsonReader), isRef: true); + public static readonly ParameterProvider JsonOptions = new ParameterProvider("options", FormattableStringHelpers.Empty, typeof(JsonSerializerOptions)); + public static readonly ParameterProvider Options = new ParameterProvider("options", FormattableStringHelpers.Empty, modelReaderWriterOptionsType); + public static readonly ParameterProvider OptionalOptions = new ParameterProvider("options", FormattableStringHelpers.Empty, nullableModelReaderWriterOptionsType, DefaultOf(nullableModelReaderWriterOptionsType)); + public static readonly ParameterProvider JsonElement = new ParameterProvider("element", FormattableStringHelpers.Empty, typeof(JsonElement)); + public static readonly ParameterProvider Data = new ParameterProvider("data", FormattableStringHelpers.Empty, typeof(BinaryData)); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs new file mode 100644 index 0000000000..e39c6153c9 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/OutputTypes/ScmOutputLibrary.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Providers; + +namespace Microsoft.Generator.CSharp.ClientModel +{ + public class ScmOutputLibrary : OutputLibrary + { + protected override IReadOnlyList BuildTypes() + { + List types = new List(); + types.AddRange(base.BuildTypes()); + types.Add(ModelSerializationExtensionsProvider.Instance); + types.Add(TypeFormattersProvider.Instance); + return types; + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Models/Types/ClientPipelineExtensionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs similarity index 98% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Models/Types/ClientPipelineExtensionsProvider.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs index 5e8382729a..0816a1c8e9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Models/Types/ClientPipelineExtensionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineExtensionsProvider.cs @@ -9,7 +9,7 @@ using Microsoft.Generator.CSharp.Providers; using Microsoft.Generator.CSharp.Snippets; -namespace Microsoft.Generator.CSharp.ClientModel +namespace Microsoft.Generator.CSharp.ClientModel.Providers { internal class ClientPipelineExtensionsProvider : TypeProvider { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs new file mode 100644 index 0000000000..e534f789f8 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ModelSerializationExtensionsProvider.cs @@ -0,0 +1,609 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text.Json; +using Microsoft.Generator.CSharp.ClientModel.Snippets; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; +using Microsoft.Generator.CSharp.TypedSnippets; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Providers +{ + internal class ModelSerializationExtensionsProvider : TypeProvider + { + private static readonly Lazy _instance = new Lazy(() => new ModelSerializationExtensionsProvider()); + public static ModelSerializationExtensionsProvider Instance => _instance.Value; + private class WriteObjectValueTemplate { } + + private readonly CSharpType _t = typeof(WriteObjectValueTemplate<>).GetGenericArguments()[0]; + + private readonly MethodSignatureModifiers _methodModifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Extension; + private readonly TypeFormattersProvider _typeFormattersProvider; + private readonly ParameterProvider _formatParameter = new ParameterProvider("format", FormattableStringHelpers.Empty, typeof(string)); + private readonly ParameterProvider _propertyParameter = new ParameterProvider("property", FormattableStringHelpers.Empty, typeof(JsonProperty)); + + protected override string GetFileName() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); + + public ModelSerializationExtensionsProvider() + { + _typeFormattersProvider = TypeFormattersProvider.Instance; + + _wireOptionsField = new FieldProvider( + modifiers: FieldModifiers.Internal | FieldModifiers.Static | FieldModifiers.ReadOnly, + type: typeof(ModelReaderWriterOptions), + name: _wireOptionsName, + initializationValue: New.Instance(typeof(ModelReaderWriterOptions), Literal("W"))); + } + + protected override TypeSignatureModifiers GetDeclarationModifiers() + { + return TypeSignatureModifiers.Internal | TypeSignatureModifiers.Static; + } + + private const string _wireOptionsName = "WireOptions"; + private readonly FieldProvider _wireOptionsField; + + private ModelReaderWriterOptionsSnippet? _wireOptions; + public ModelReaderWriterOptionsSnippet WireOptions => _wireOptions ??= new ModelReaderWriterOptionsSnippet(new MemberExpression(Type, _wireOptionsName)); + + public override string Name => "ModelSerializationExtensions"; + + protected override FieldProvider[] BuildFields() + { + return [_wireOptionsField]; + } + + protected override MethodProvider[] BuildMethods() + { + var writer = new Utf8JsonWriterSnippet(ScmKnownParameters.Utf8JsonWriter); + var dateTimeOffsetValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(DateTimeOffset)); + var writeStringDateTimeOffset = new MethodProvider( + new MethodSignature( + Name: _writeStringValueMethodName, + Modifiers: _methodModifiers, + ReturnType: null, + Parameters: [ScmKnownParameters.Utf8JsonWriter, dateTimeOffsetValueParameter, _formatParameter], + Summary: null, Description: null, ReturnDescription: null), + writer.WriteStringValue(_typeFormattersProvider.ToString(dateTimeOffsetValueParameter, _formatParameter)), + this); + + var dateTimeValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(DateTime)); + var writeStringDateTime = new MethodProvider( + new MethodSignature( + Name: _writeStringValueMethodName, + Modifiers: _methodModifiers, + ReturnType: null, + Parameters: [ScmKnownParameters.Utf8JsonWriter, dateTimeValueParameter, _formatParameter], + Summary: null, Description: null, ReturnDescription: null), + writer.WriteStringValue(_typeFormattersProvider.ToString(dateTimeValueParameter, _formatParameter)), + this); + + var timeSpanValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(TimeSpan)); + var writeStringTimeSpan = new MethodProvider( + new MethodSignature( + Name: _writeStringValueMethodName, + Modifiers: _methodModifiers, + ReturnType: null, + Parameters: [ScmKnownParameters.Utf8JsonWriter, timeSpanValueParameter, _formatParameter], + Summary: null, Description: null, ReturnDescription: null), + writer.WriteStringValue(_typeFormattersProvider.ToString(timeSpanValueParameter, _formatParameter)), + this); + + var charValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(char)); + var value = new CharSnippet(charValueParameter); + var writeStringChar = new MethodProvider( + new MethodSignature( + Name: _writeStringValueMethodName, + Modifiers: _methodModifiers, + ReturnType: null, + Parameters: [ScmKnownParameters.Utf8JsonWriter, charValueParameter], + Summary: null, Description: null, ReturnDescription: null), + writer.WriteStringValue(value.InvokeToString(new MemberExpression(typeof(CultureInfo), nameof(CultureInfo.InvariantCulture)))), + this); + + return + [ + BuildGetObjectMethodProvider(), + BuildGetBytesFromBase64(), + BuildGetDateTimeOffsetMethodProvider(), + BuildGetTimeSpanMethodProvider(), + BuildGetCharMethodProvider(), + BuildThrowNonNullablePropertyIsNullMethodProvider(), + BuildGetRequiredStringMethodProvider(), + writeStringDateTimeOffset, + writeStringDateTime, + writeStringTimeSpan, + writeStringChar, + BuildWriteBase64StringValueMethodProvider(), + BuildWriteNumberValueMethodProvider(), + BuildWriteObjectValueMethodGeneric(), + BuildWriteObjectValueMethodProvider() + ]; + } + + #region JsonElementExtensions MethodProvider builders + private const string _getBytesFromBase64MethodName = "GetBytesFromBase64"; + private const string _getCharMethodName = "GetChar"; + private const string _getDateTimeOffsetMethodName = "GetDateTimeOffset"; + private const string _getObjectMethodName = "GetObject"; + private const string _getTimeSpanMethodName = "GetTimeSpan"; + private const string _throwNonNullablePropertyIsNullMethodName = "ThrowNonNullablePropertyIsNull"; + private const string _getRequiredStringMethodName = "GetRequiredString"; + + private MethodProvider BuildGetObjectMethodProvider() + { + var signature = new MethodSignature( + Name: _getObjectMethodName, + Summary: null, + Description: null, + Modifiers: _methodModifiers, + ReturnType: typeof(object), + ReturnDescription: null, + Parameters: new[] { ScmKnownParameters.JsonElement }); + var element = new JsonElementSnippet(ScmKnownParameters.JsonElement); + var body = new SwitchStatement(element.ValueKind) + { + new(JsonValueKindSnippet.String, Return(element.GetString())), + new(JsonValueKindSnippet.Number, new MethodBodyStatement[] + { + new IfStatement(element.TryGetInt32(out var intValue)) + { + Return(intValue) + }, + new IfStatement(element.TryGetInt64(out var longValue)) + { + Return(longValue) + }, + Return(element.GetDouble()) + }), + new(JsonValueKindSnippet.True, Return(True)), + new(JsonValueKindSnippet.False, Return(False)), + new([JsonValueKindSnippet.Undefined, JsonValueKindSnippet.Null], Return(Null)), + new(JsonValueKindSnippet.Object, new MethodBodyStatement[] + { + Var("dictionary", New.Dictionary(typeof(string), typeof(object)), out var dictionary), + new ForeachStatement("jsonProperty", element.EnumerateObject(), out var jsonProperty) + { + dictionary.Add(jsonProperty.Property(nameof(JsonProperty.Name)), new JsonElementSnippet(jsonProperty.Property(nameof(JsonProperty.Value))).Untyped.Invoke("GetObject")) + }, + Return(dictionary) + }), + new(JsonValueKindSnippet.Array, new MethodBodyStatement[] + { + Var("list", New.List(typeof(object)), out var list), + new ForeachStatement("item", element.EnumerateArray(), out var item) + { + list.Add(new JsonElementSnippet(item).Untyped.Invoke("GetObject")) + }, + Return(list.ToArray()) + }), + SwitchCaseStatement.Default(Throw(New.NotSupportedException(new FormattableStringExpression("Not supported value kind {0}", [element.ValueKind])))) + }; + return new MethodProvider(signature, body, this); + } + + public InvokeStaticMethodExpression GetObject(JsonElementSnippet element) + => new InvokeStaticMethodExpression(Type, _getObjectMethodName, new ValueExpression[] { element }, CallAsExtension: true); + + private MethodProvider BuildGetBytesFromBase64() + { + var signature = new MethodSignature( + Name: _getBytesFromBase64MethodName, + Modifiers: _methodModifiers, + Parameters: [ScmKnownParameters.JsonElement, _formatParameter], + ReturnType: typeof(byte[]), + Summary: null, Description: null, ReturnDescription: null); + var element = new JsonElementSnippet(ScmKnownParameters.JsonElement); + var format = new StringSnippet(_formatParameter); + var body = new MethodBodyStatement[] + { + new IfStatement(element.ValueKindEqualsNull()) + { + Return(Null) + }, + EmptyLineStatement, + Return(new SwitchExpression(format, + new SwitchCaseExpression(Literal("U"), _typeFormattersProvider.FromBase64UrlString(GetRequiredString(element))), + new SwitchCaseExpression(Literal("D"), element.GetBytesFromBase64()), + SwitchCaseExpression.Default(ThrowExpression(New.ArgumentException(format, new FormattableStringExpression("Format is not supported: '{0}'", [format])))) + )) + }; + + return new MethodProvider(signature, body, this); + } + + public InvokeStaticMethodExpression GetBytesFromBase64(JsonElementSnippet element, string? format) + => new InvokeStaticMethodExpression(Type, _getBytesFromBase64MethodName, new ValueExpression[] { element, Literal(format) }, CallAsExtension: true); + + private MethodProvider BuildGetDateTimeOffsetMethodProvider() + { + var signature = new MethodSignature( + Name: _getDateTimeOffsetMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { ScmKnownParameters.JsonElement, _formatParameter }, + ReturnType: typeof(DateTimeOffset), + Summary: null, Description: null, ReturnDescription: null); + var element = new JsonElementSnippet(ScmKnownParameters.JsonElement); + var format = new StringSnippet(_formatParameter); + var body = new SwitchExpression(format, + SwitchCaseExpression.When(Literal("U"), Equal(element.ValueKind, JsonValueKindSnippet.Number), DateTimeOffsetSnippet.FromUnixTimeSeconds(element.GetInt64())), + // relying on the param check of the inner call to throw ArgumentNullException if GetString() returns null + SwitchCaseExpression.Default(_typeFormattersProvider.ParseDateTimeOffset(element.GetString(), format)) + ); + + return new MethodProvider(signature, body, this); + } + + public InvokeStaticMethodExpression GetDateTimeOffset(JsonElementSnippet element, string? format) + => new InvokeStaticMethodExpression(Type, _getDateTimeOffsetMethodName, new ValueExpression[] { element, Literal(format) }, CallAsExtension: true); + + private MethodProvider BuildGetTimeSpanMethodProvider() + { + var signature = new MethodSignature( + Name: _getTimeSpanMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { ScmKnownParameters.JsonElement, _formatParameter }, + ReturnType: typeof(TimeSpan), + Summary: null, Description: null, ReturnDescription: null); + var element = new JsonElementSnippet(ScmKnownParameters.JsonElement); + // relying on the param check of the inner call to throw ArgumentNullException if GetString() returns null + var body = _typeFormattersProvider.ParseTimeSpan(element.GetString(), _formatParameter); + + return new MethodProvider(signature, body, this); + } + + public InvokeStaticMethodExpression GetTimeSpan(JsonElementSnippet element, string? format) + => new InvokeStaticMethodExpression(Type, _getTimeSpanMethodName, new ValueExpression[] { element, Literal(format) }, CallAsExtension: true); + + private MethodProvider BuildGetCharMethodProvider() + { + var signature = new MethodSignature( + Name: _getCharMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { ScmKnownParameters.JsonElement }, + ReturnType: typeof(char), + Summary: null, Description: null, ReturnDescription: null); + var element = new JsonElementSnippet(ScmKnownParameters.JsonElement); + var body = new IfElseStatement( + element.ValueKindEqualsString(), + new MethodBodyStatement[] + { + Var("text", element.GetString(), out var text), + new IfStatement(Equal(text, Null).Or(NotEqual(text.Length, Literal(1)))) + { + Throw(New.NotSupportedException(new FormattableStringExpression("Cannot convert \\\"{0}\\\" to a char", [text]))) + }, + Return(text.Index(0)) + }, + Throw(New.NotSupportedException(new FormattableStringExpression("Cannot convert {0} to a char", [element.ValueKind]))) + ); + + return new MethodProvider(signature, body, this); + } + + public InvokeStaticMethodExpression GetChar(JsonElementSnippet element) + => new InvokeStaticMethodExpression(Type, _getCharMethodName, new ValueExpression[] { element }, CallAsExtension: true); + + private MethodProvider BuildThrowNonNullablePropertyIsNullMethodProvider() + { + var signature = new MethodSignature( + Name: _throwNonNullablePropertyIsNullMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { _propertyParameter }, + ReturnType: null, + Attributes: new[] + { + new AttributeStatement(typeof(ConditionalAttribute), Literal("DEBUG")) + }, + Summary: null, Description: null, ReturnDescription: null); + var property = new JsonPropertySnippet(_propertyParameter); + var body = Throw(New.JsonException(new FormattableStringExpression("A property '{0}' defined as non-nullable but received as null from the service. This exception only happens in DEBUG builds of the library and would be ignored in the release build", [property.Name]))); + + return new MethodProvider(signature, body, this); + } + + public MethodBodyStatement ThrowNonNullablePropertyIsNull(JsonPropertySnippet property) + => new InvokeStaticMethodStatement(Type, _throwNonNullablePropertyIsNullMethodName, [property], callAsExtension: true); + + private MethodProvider BuildGetRequiredStringMethodProvider() + { + var signature = new MethodSignature( + Name: _getRequiredStringMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { ScmKnownParameters.JsonElement }, + ReturnType: typeof(string), + Summary: null, Description: null, ReturnDescription: null); + var element = new JsonElementSnippet(ScmKnownParameters.JsonElement); + var body = new MethodBodyStatement[] + { + Var("value", element.GetString(), out var value), + new IfStatement(Equal(value, Null)) + { + Throw(New.InvalidOperationException(new FormattableStringExpression("The requested operation requires an element of type 'String', but the target element has type '{0}'.", [element.ValueKind]))) + }, + Return(value) + }; + + return new MethodProvider(signature, body, this); + } + + public InvokeStaticMethodExpression GetRequiredString(JsonElementSnippet element) + => new InvokeStaticMethodExpression(Type, _getRequiredStringMethodName, [element], CallAsExtension: true); + #endregion + + #region Utf8JsonWriterExtensions MethodProvider builders + private const string _writeStringValueMethodName = "WriteStringValue"; + private const string _writeBase64StringValueMethodName = "WriteBase64StringValue"; + private const string _writeNumberValueMethodName = "WriteNumberValue"; + private const string _writeObjectValueMethodName = "WriteObjectValue"; + + public MethodBodyStatement WriteStringValue(Utf8JsonWriterSnippet writer, ValueExpression value, string? format) + => new InvokeStaticMethodStatement(Type, _writeStringValueMethodName, new[] { writer, value, Literal(format) }, callAsExtension: true); + + private MethodProvider BuildWriteBase64StringValueMethodProvider() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(byte[])); + var signature = new MethodSignature( + Name: _writeBase64StringValueMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { ScmKnownParameters.Utf8JsonWriter, valueParameter, _formatParameter }, + ReturnType: null, + Summary: null, Description: null, ReturnDescription: null); + var writer = new Utf8JsonWriterSnippet(ScmKnownParameters.Utf8JsonWriter); + var value = (ValueExpression)valueParameter; + var format = new StringSnippet(_formatParameter); + var body = new MethodBodyStatement[] + { + new IfStatement(Equal(value, Null)) + { + writer.WriteNullValue(), + Return() + }, + new SwitchStatement(format) + { + new(Literal("U"), new MethodBodyStatement[] + { + writer.WriteStringValue(_typeFormattersProvider.ToBase64UrlString(value)), + Break + }), + new(Literal("D"), new MethodBodyStatement[] + { + writer.WriteBase64StringValue(value), + Break + }), + SwitchCaseStatement.Default(Throw(New.ArgumentException(format, new FormattableStringExpression("Format is not supported: '{0}'", [format])))) + } + }; + + return new MethodProvider(signature, body, this); + } + + public MethodBodyStatement WriteBase64StringValue(Utf8JsonWriterSnippet writer, ValueExpression value, string? format) + => new InvokeStaticMethodStatement(Type, _writeBase64StringValueMethodName, new[] { writer, value, Literal(format) }, callAsExtension: true); + + private MethodProvider BuildWriteNumberValueMethodProvider() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(DateTimeOffset)); + var signature = new MethodSignature( + Name: _writeNumberValueMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { ScmKnownParameters.Utf8JsonWriter, valueParameter, _formatParameter }, + ReturnType: null, + Summary: null, Description: null, ReturnDescription: null); + var writer = new Utf8JsonWriterSnippet(ScmKnownParameters.Utf8JsonWriter); + var value = new DateTimeOffsetSnippet(valueParameter); + var format = new StringSnippet(_formatParameter); + var body = new MethodBodyStatement[] + { + new IfStatement(NotEqual(format, Literal("U"))) + { + Throw(New.ArgumentOutOfRangeException(format, "Only 'U' format is supported when writing a DateTimeOffset as a Number.")), + }, + writer.WriteNumberValue(value.ToUnixTimeSeconds()) + }; + + return new MethodProvider(signature, body, this); + } + + public MethodBodyStatement WriteNumberValue(Utf8JsonWriterSnippet writer, ValueExpression value, string? format) + => new InvokeStaticMethodStatement(Type, _writeNumberValueMethodName, new[] { writer, value, Literal(format) }, callAsExtension: true); + + private MethodProvider BuildWriteObjectValueMethodProvider() + { + ValueExpression value; + Utf8JsonWriterSnippet writer; + ParameterReferenceSnippet options; + MethodSignature signature = GetWriteObjectValueMethodSignature(null, out value, out writer, out options); + return new MethodProvider(signature, new MethodBodyStatement[] + { + writer.WriteObjectValue(new ObjectSnippet(value), options) + }, + this); + } + + private MethodProvider BuildWriteObjectValueMethodGeneric() + { + ValueExpression value; + Utf8JsonWriterSnippet writer; + ParameterReferenceSnippet options; + MethodSignature signature = GetWriteObjectValueMethodSignature(_t, out value, out writer, out options); + List cases = new List + { + new(Null, new MethodBodyStatement[] + { + writer.WriteNullValue(), + Break + }) + }; + cases.Add( + BuildWriteObjectValueSwitchCase(new CSharpType(typeof(IJsonModel<>), _t), "jsonModel", jsonModel => new MethodBodyStatement[] + { + new InvokeInstanceMethodStatement(jsonModel, nameof(IJsonModel.Write), writer, NullCoalescing(options, ModelReaderWriterOptionsSnippet.Wire)), + Break + })); + cases.AddRange(new[] + { + // byte[] case + BuildWriteObjectValueSwitchCase(typeof(byte[]), "bytes", bytes => new MethodBodyStatement[] + { + writer.WriteBase64StringValue(bytes), + Break + }), + // BinaryData case + BuildWriteObjectValueSwitchCase(typeof(BinaryData), "bytes", bytes => new MethodBodyStatement[] + { + writer.WriteBase64StringValue(bytes), + Break + }), + // JsonElement case + BuildWriteObjectValueSwitchCase(typeof(JsonElement), "json", json => new MethodBodyStatement[] + { + new JsonElementSnippet(json).WriteTo(writer), + Break + }), + // int case + BuildWriteObjectValueSwitchCase(typeof(int), "i", i => new MethodBodyStatement[] + { + writer.WriteNumberValue(i), + Break + }), + // decimal case + BuildWriteObjectValueSwitchCase(typeof(decimal), "d", dec => new MethodBodyStatement[] + { + writer.WriteNumberValue(dec), + Break + }), + // double case + BuildWriteObjectValueSwitchCase(typeof(double), "d", d => new MethodBodyStatement[] + { + new IfElseStatement( + DoubleSnippet.IsNan(d), + writer.WriteStringValue(Literal("NaN")), + writer.WriteNumberValue(d)), + Break + }), + // float case + BuildWriteObjectValueSwitchCase(typeof(float), "f", f => new MethodBodyStatement[] + { + writer.WriteNumberValue(f), + Break + }), + // long case + BuildWriteObjectValueSwitchCase(typeof(long), "l", l => new MethodBodyStatement[] + { + writer.WriteNumberValue(l), + Break + }), + // string case + BuildWriteObjectValueSwitchCase(typeof(string), "s", s => new MethodBodyStatement[] + { + writer.WriteStringValue(s), + Break + }), + // bool case + BuildWriteObjectValueSwitchCase(typeof(bool), "b", b => new MethodBodyStatement[] + { + writer.WriteBooleanValue(b), + Break + }), + // Guid case + BuildWriteObjectValueSwitchCase(typeof(Guid), "g", g => new MethodBodyStatement[] + { + writer.WriteStringValue(g), + Break + }), + // DateTimeOffset case + BuildWriteObjectValueSwitchCase(typeof(DateTimeOffset), "dateTimeOffset", dateTimeOffset => new MethodBodyStatement[] + { + writer.WriteStringValue(dateTimeOffset, "O"), + Break + }), + // DateTime case + BuildWriteObjectValueSwitchCase(typeof(DateTime), "dateTime", dateTime => new MethodBodyStatement[] + { + writer.WriteStringValue(dateTime, "O"), + Break + }), + // IEnumerable> case + BuildWriteObjectValueSwitchCase(typeof(IEnumerable>), "enumerable", enumerable => new MethodBodyStatement[] + { + writer.WriteStartObject(), + new ForeachStatement("pair", new EnumerableSnippet(typeof(KeyValuePair), enumerable), out var pair) + { + writer.WritePropertyName(pair.Property(nameof(KeyValuePair.Key))), + writer.WriteObjectValue(new ObjectSnippet(pair.Property(nameof(KeyValuePair.Value))), options) + }, + writer.WriteEndObject(), + Break + }), + // IEnumerable case + BuildWriteObjectValueSwitchCase(typeof(IEnumerable), "objectEnumerable", objectEnumerable => new MethodBodyStatement[] + { + writer.WriteStartArray(), + new ForeachStatement("item", new EnumerableSnippet(typeof(object), objectEnumerable), out var item) + { + writer.WriteObjectValue(new ObjectSnippet(item), options) + }, + writer.WriteEndArray(), + Break + }), + // TimeSpan case + BuildWriteObjectValueSwitchCase(typeof(TimeSpan), "timeSpan", timeSpan => new MethodBodyStatement[] + { + writer.WriteStringValue(timeSpan, "P"), + Break + }), + // default + SwitchCaseStatement.Default(Throw(New.NotSupportedException(new FormattableStringExpression("Not supported type {0}", [value.InvokeGetType()])))) + }); + + return new MethodProvider(signature, new SwitchStatement(value, cases), this); + + static SwitchCaseStatement BuildWriteObjectValueSwitchCase(CSharpType type, string varName, Func bodyFunc) + { + var declaration = new DeclarationExpression(type, varName, out var variable); + var body = bodyFunc(variable); + + return new(declaration, body); + } + } + + private MethodSignature GetWriteObjectValueMethodSignature(CSharpType? genericArgument, out ValueExpression value, out Utf8JsonWriterSnippet writer, out ParameterReferenceSnippet options) + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, genericArgument ?? typeof(object)); + var optionsParameter = new ParameterProvider("options", FormattableStringHelpers.Empty, typeof(ModelReaderWriterOptions), DefaultOf(new CSharpType(typeof(ModelReaderWriterOptions)).WithNullable(true))); + var parameters = new[] { ScmKnownParameters.Utf8JsonWriter, valueParameter, optionsParameter }; + var signature = new MethodSignature( + Name: _writeObjectValueMethodName, + Summary: null, + Description: null, + Modifiers: _methodModifiers, + ReturnType: null, + ReturnDescription: null, + Parameters: parameters, + GenericArguments: genericArgument != null ? new[] { genericArgument } : null); + value = (ValueExpression)valueParameter; + writer = new Utf8JsonWriterSnippet(ScmKnownParameters.Utf8JsonWriter); + options = new ParameterReferenceSnippet(optionsParameter); + return signature; + } + + public MethodBodyStatement WriteObjectValue(Utf8JsonWriterSnippet writer, TypedSnippet value, ValueExpression? options = null) + { + var parameters = options is null + ? new ValueExpression[] { writer, value } + : new ValueExpression[] { writer, value, options }; + return new InvokeStaticMethodStatement(Type, _writeObjectValueMethodName, parameters, callAsExtension: true, typeArguments: [value.Type]); + } + #endregion + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Models/Types/MrwSerializationTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs similarity index 92% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Models/Types/MrwSerializationTypeProvider.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs index 440677fde0..135ffeccf3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Models/Types/MrwSerializationTypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/MrwSerializationTypeProvider.cs @@ -15,7 +15,7 @@ using Microsoft.Generator.CSharp.Statements; using static Microsoft.Generator.CSharp.Snippets.Snippet; -namespace Microsoft.Generator.CSharp.ClientModel +namespace Microsoft.Generator.CSharp.ClientModel.Providers { /// /// This class provides the set of serialization models, methods, and interfaces for a given model. @@ -179,7 +179,8 @@ internal MethodProvider BuildJsonModelWriteMethod() ( new MethodSignature(nameof(IJsonModel.Write), null, null, MethodSignatureModifiers.None, null, null, new[] { utf8JsonWriterParameter, _serializationOptionsParameter }, ExplicitInterface: _iJsonModelTInterface), // TO-DO: Add body for json properties' serialization https://github.com/microsoft/typespec/issues/3330 - Snippet.EmptyStatement + Snippet.EmptyStatement, + this ); } @@ -195,7 +196,8 @@ internal MethodProvider BuildJsonModelCreateMethod() ( new MethodSignature(nameof(IJsonModel.Create), null, null, MethodSignatureModifiers.None, typeOfT, null, new[] { utf8JsonReaderParameter, _serializationOptionsParameter }, ExplicitInterface: _iJsonModelTInterface), // TO-DO: Call the base model ctor for now until the model properties are serialized https://github.com/microsoft/typespec/issues/3330 - Snippet.Return(new NewInstanceExpression(typeOfT, Array.Empty())) + Snippet.Return(new NewInstanceExpression(typeOfT, Array.Empty())), + this ); } @@ -210,7 +212,8 @@ internal MethodProvider BuildIModelWriteMethod() ( new MethodSignature(nameof(IPersistableModel.Write), null, null, MethodSignatureModifiers.None, returnType, null, new[] { _serializationOptionsParameter }, ExplicitInterface: _iPersistableModelTInterface), // TO-DO: Call the base model ctor for now until the model properties are serialized https://github.com/microsoft/typespec/issues/3330 - Snippet.Return(new NewInstanceExpression(returnType, [Snippet.Literal(_iPersistableModelTInterface.Name)])) + Snippet.Return(new NewInstanceExpression(returnType, [Snippet.Literal(_iPersistableModelTInterface.Name)])), + this ); } @@ -224,9 +227,10 @@ internal MethodProvider BuildIModelCreateMethod() var typeOfT = GetModelArgumentType(_iPersistableModelTInterface); return new MethodProvider ( - new MethodSignature(nameof(IPersistableModel.Create), null, null, MethodSignatureModifiers.None, typeOfT, null, new[] { dataParameter, _serializationOptionsParameter }, ExplicitInterface: _iPersistableModelTInterface), - // TO-DO: Call the base model ctor for now until the model properties are serialized https://github.com/microsoft/typespec/issues/3330 - Snippet.Return(new NewInstanceExpression(typeOfT, Array.Empty())) + new MethodSignature(nameof(IPersistableModel.Create), null, null, MethodSignatureModifiers.None, typeOfT, null, new[] { dataParameter, _serializationOptionsParameter }, ExplicitInterface: _iPersistableModelTInterface), + // TO-DO: Call the base model ctor for now until the model properties are serialized https://github.com/microsoft/typespec/issues/3330 + Snippet.Return(new NewInstanceExpression(typeOfT, Array.Empty())), + this ); } @@ -239,8 +243,9 @@ internal MethodProvider BuildIModelGetFormatFromOptionsMethod() // ModelReaderWriterFormat IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) return new MethodProvider ( - new MethodSignature(nameof(IPersistableModel.GetFormatFromOptions), null, null, MethodSignatureModifiers.None, typeof(string), null, new[] { _serializationOptionsParameter }, ExplicitInterface: _iPersistableModelTInterface), - jsonWireFormat + new MethodSignature(nameof(IPersistableModel.GetFormatFromOptions), null, null, MethodSignatureModifiers.None, typeof(string), null, new[] { _serializationOptionsParameter }, ExplicitInterface: _iPersistableModelTInterface), + jsonWireFormat, + this ); } @@ -262,7 +267,8 @@ internal MethodProvider BuildSerializationConstructor() bodyStatements: new MethodBodyStatement[] { GetPropertyInitializers(serializationCtorParameters) - }); + }, + this); } private MethodBodyStatement GetPropertyInitializers(IReadOnlyList parameters) @@ -326,7 +332,8 @@ private MethodProvider BuildEmptyConstructor() var accessibility = _isStruct ? MethodSignatureModifiers.Public : MethodSignatureModifiers.Internal; return new MethodProvider( signature: new ConstructorSignature(Type, $"Initializes a new instance of {Type:C} for deserialization.", null, accessibility, Array.Empty()), - bodyStatements: new MethodBodyStatement()); + bodyStatements: new MethodBodyStatement(), + this); } /// diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs new file mode 100644 index 0000000000..87c253108e --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/TypeFormattersProvider.cs @@ -0,0 +1,369 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Xml; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Providers +{ + internal class TypeFormattersProvider : TypeProvider + { + private static readonly Lazy _instance = new(() => new TypeFormattersProvider()); + public static TypeFormattersProvider Instance => _instance.Value; + private readonly ValueExpression _invariantCultureExpression = new MemberExpression(typeof(CultureInfo), nameof(CultureInfo.InvariantCulture)); + private const string _toStringMethodName = "ToString"; + + internal TypeFormattersProvider() + { + } + + protected override TypeSignatureModifiers GetDeclarationModifiers() + { + return TypeSignatureModifiers.Internal | TypeSignatureModifiers.Static; + } + + protected override string GetFileName() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); + + public override string Name => "TypeFormatters"; + + private readonly FieldProvider _roundtripZFormatField = new(FieldModifiers.Private | FieldModifiers.Const, typeof(string), "RoundtripZFormat", initializationValue: Literal("yyyy-MM-ddTHH:mm:ss.fffffffZ")); + private readonly FieldProvider _defaultNumberFormatField = new(FieldModifiers.Public | FieldModifiers.Const, typeof(string), "DefaultNumberFormat", initializationValue: Literal("G")); + + protected override FieldProvider[] BuildFields() + { + return [_roundtripZFormatField, _defaultNumberFormatField]; + } + + private readonly MethodSignatureModifiers _methodModifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static; + + protected override MethodProvider[] BuildMethods() + { + var boolValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(bool)); + var boolSignature = new MethodSignature( + Name: _toStringMethodName, + Parameters: [boolValueParameter], + Modifiers: _methodModifiers, + ReturnType: typeof(string), + Summary: null, Description: null, ReturnDescription: null); + var boolValue = new BoolSnippet(boolValueParameter); + var toStringBool = new MethodProvider( + boolSignature, + new TernaryConditionalExpression(boolValue, Literal("true"), Literal("false")), + this); + + var dateTimeParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(DateTime)); + var formatParameter = new ParameterProvider("format", FormattableStringHelpers.Empty, typeof(string)); + var dateTimeSignature = boolSignature with + { + Parameters = [dateTimeParameter, formatParameter] + }; + var dateTimeValue = (ValueExpression)dateTimeParameter; + var dateTimeValueKind = dateTimeValue.Property(nameof(DateTime.Kind)); + var format = new StringSnippet(formatParameter); + var sdkName = "Generated clients require"; + var toStringDateTime = new MethodProvider( + dateTimeSignature, + new SwitchExpression(dateTimeValueKind, new SwitchCaseExpression[] + { + new(new MemberExpression(typeof(DateTimeKind), nameof(DateTimeKind.Utc)), ToString(dateTimeValue.CastTo(typeof(DateTimeOffset)), format)), + SwitchCaseExpression.Default(ThrowExpression(New.NotSupportedException(new FormattableStringExpression($"DateTime {{0}} has a Kind of {{1}}. {sdkName} it to be UTC. You can call DateTime.SpecifyKind to change Kind property value to DateTimeKind.Utc.", [dateTimeValue, dateTimeValueKind])))) + }), + this); + + var dateTimeOffsetParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(DateTimeOffset)); + var dateTimeOffsetSignature = boolSignature with + { + Parameters = [dateTimeOffsetParameter, formatParameter] + }; + var dateTimeOffsetValue = new DateTimeOffsetSnippet(dateTimeOffsetParameter); + var roundtripZFormat = new StringSnippet(_roundtripZFormatField); + var toStringDateTimeOffset = new MethodProvider( + dateTimeOffsetSignature, + new SwitchExpression(format, + [ + new(Literal("D"), dateTimeOffsetValue.InvokeToString(Literal("yyyy-MM-dd"), _invariantCultureExpression)), + new(Literal("U"), dateTimeOffsetValue.ToUnixTimeSeconds().InvokeToString(_invariantCultureExpression)), + new(Literal("O"), dateTimeOffsetValue.ToUniversalTime().InvokeToString(roundtripZFormat, _invariantCultureExpression)), + new(Literal("o"), dateTimeOffsetValue.ToUniversalTime().InvokeToString(roundtripZFormat, _invariantCultureExpression)), + new(Literal("R"), dateTimeOffsetValue.InvokeToString(Literal("r"), _invariantCultureExpression)), + SwitchCaseExpression.Default(dateTimeOffsetValue.InvokeToString(format, _invariantCultureExpression)) + ]), + this); + + var timeSpanParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(TimeSpan)); + var timeSpanSignature = boolSignature with + { + Parameters = [timeSpanParameter, formatParameter] + }; + var timeSpanValue = new TimeSpanSnippet(timeSpanParameter); + var toStringTimeSpan = new MethodProvider( + timeSpanSignature, + new SwitchExpression(format, + [ + new(Literal("P"), new InvokeStaticMethodExpression(typeof(XmlConvert), nameof(XmlConvert.ToString), [timeSpanValue])), + SwitchCaseExpression.Default(timeSpanValue.InvokeToString(format, _invariantCultureExpression)) + ]), + this); + + var byteArrayParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(byte[])); + var byteArraySignature = boolSignature with + { + Parameters = [byteArrayParameter, formatParameter] + }; + var byteArrayValue = (ValueExpression)byteArrayParameter; + var toStringByteArray = new MethodProvider( + byteArraySignature, + new SwitchExpression(format, + [ + new(Literal("U"), ToBase64UrlString(byteArrayValue)), + new(Literal("D"), new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.ToBase64String), new[] {byteArrayValue})), + SwitchCaseExpression.Default(ThrowExpression(New.ArgumentException(format, new FormattableStringExpression("Format is not supported: '{0}'", [format])))) + ]), + this); + + return + [ + toStringBool, + toStringDateTime, + toStringDateTimeOffset, + toStringTimeSpan, + toStringByteArray, + BuildToBase64UrlStringMethodProvider(), + BuildFromBase64UrlString(), + BuildParseDateTimeOffsetMethodProvider(), + BuildParseTimeSpanMethodProvider(), + BuildConvertToStringMethodProvider() + ]; + } + + public StringSnippet ToString(ValueExpression value) + => new(new InvokeStaticMethodExpression(Type, _toStringMethodName, new[] { value })); + + public StringSnippet ToString(ValueExpression value, ValueExpression format) + => new(new InvokeStaticMethodExpression(Type, _toStringMethodName, new[] { value, format })); + + private const string _toBase64UrlStringMethodName = "ToBase64UrlString"; + + private MethodProvider BuildToBase64UrlStringMethodProvider() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(byte[])); + var signature = new MethodSignature( + Name: _toBase64UrlStringMethodName, + Parameters: new[] { valueParameter }, + ReturnType: typeof(string), + Modifiers: _methodModifiers, + Summary: null, Description: null, ReturnDescription: null); + + var value = (ValueExpression)valueParameter; + var valueLength = new IntSnippet(value.Property("Length")); + var body = new List + { + Declare("numWholeOrPartialInputBlocks", new IntSnippet(new BinaryOperatorExpression("/", new KeywordExpression("checked", new BinaryOperatorExpression("+", valueLength, Int(2))), Int(3))), out var numWholeOrPartialInputBlocks), + Declare("size", new IntSnippet(new KeywordExpression("checked", new BinaryOperatorExpression("*", numWholeOrPartialInputBlocks, Int(4)))), out var size), + }; + var output = new VariableReferenceSnippet(typeof(char[]), "output"); + body.Add(new MethodBodyStatement[] + { + Declare(output, New.Array(typeof(char), size)), + EmptyLineStatement, + Declare("numBase64Chars", new IntSnippet(new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.ToBase64CharArray), new[] { value, Int(0), valueLength, output, Int(0) })), out var numBase64Chars), + EmptyLineStatement, + Declare("i", Int(0), out var i), + new ForStatement(null, LessThan(i, numBase64Chars), new UnaryOperatorExpression("++", i, true)) + { + Declare("ch", new CharSnippet(new IndexerExpression(output, i)), out var ch), + new IfElseStatement(new IfStatement(Equal(ch, Literal('+'))) + { + Assign(new IndexerExpression(output, i), Literal('-')) + }, new IfElseStatement(new IfStatement(Equal(ch, Literal('/'))) + { + Assign(new IndexerExpression(output, i), Literal('_')) + }, new IfStatement(Equal(ch, Literal('='))) + { + Break + })) + }, + EmptyLineStatement, + Return(New.Instance(typeof(string), output, Int(0), i)) + }); + + return new MethodProvider(signature, body, this); + } + + public StringSnippet ToBase64UrlString(ValueExpression value) + => new(new InvokeStaticMethodExpression(Type, _toBase64UrlStringMethodName, new[] { value })); + + private const string _fromBase64UrlStringMethodName = "FromBase64UrlString"; + + private MethodProvider BuildFromBase64UrlString() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(string)); + var signature = new MethodSignature( + Name: _fromBase64UrlStringMethodName, + Parameters: [valueParameter], + Modifiers: _methodModifiers, + ReturnType: typeof(byte[]), + Summary: null, Description: null, ReturnDescription: null); + var value = new StringSnippet(valueParameter); + + var body = new List + { + Declare("paddingCharsToAdd", new IntSnippet(new SwitchExpression(new BinaryOperatorExpression("%", value.Length, Literal(4)), new SwitchCaseExpression[] + { + new SwitchCaseExpression(Int(0), Int(0)), + new SwitchCaseExpression(Int(2), Int(2)), + new SwitchCaseExpression(Int(3), Int(1)), + SwitchCaseExpression.Default(ThrowExpression(New.InvalidOperationException(Literal("Malformed input")))) + })), out var paddingCharsToAdd) + }; + var output = new VariableReferenceSnippet(typeof(char[]), "output"); + var outputLength = output.Property("Length"); + body.Add(new MethodBodyStatement[] + { + Declare(output, New.Array(typeof(char), new BinaryOperatorExpression("+", value.Length, paddingCharsToAdd))), + Declare("i", Int(0), out var i), + new ForStatement(null, LessThan(i, value.Length), new UnaryOperatorExpression("++", i, true)) + { + Declare("ch", value.Index(i), out var ch), + new IfElseStatement(new IfStatement(Equal(ch, Literal('-'))) + { + Assign(new IndexerExpression(output, i), Literal('+')) + }, new IfElseStatement(new IfStatement(Equal(ch, Literal('_'))) + { + Assign(new IndexerExpression(output, i), Literal('/')) + }, Assign(new IndexerExpression(output, i), ch))) + }, + EmptyLineStatement, + new ForStatement(null, LessThan(i, outputLength), new UnaryOperatorExpression("++", i, true)) + { + Assign(new IndexerExpression(output, i), Literal('=')) + }, + EmptyLineStatement, + Return(new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.FromBase64CharArray), new[] { output, Int(0), outputLength })) + }); + + return new MethodProvider(signature, body, this); + } + + public ValueExpression FromBase64UrlString(ValueExpression value) + => new InvokeStaticMethodExpression(Type, _fromBase64UrlStringMethodName, new[] { value }); + + private const string _parseDateTimeOffsetMethodName = "ParseDateTimeOffset"; + private MethodProvider BuildParseDateTimeOffsetMethodProvider() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(string)); + var formatParameter = new ParameterProvider("format", FormattableStringHelpers.Empty, typeof(string), null); + var signature = new MethodSignature( + Name: _parseDateTimeOffsetMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { valueParameter, formatParameter }, + ReturnType: typeof(DateTimeOffset), + Summary: null, Description: null, ReturnDescription: null); + + var value = new StringSnippet(valueParameter); + var format = new StringSnippet(formatParameter); + var invariantCulture = new MemberExpression(typeof(CultureInfo), nameof(CultureInfo.InvariantCulture)); + return new MethodProvider( + signature, + new SwitchExpression(format, new SwitchCaseExpression[] + { + new(Literal("U"), DateTimeOffsetSnippet.FromUnixTimeSeconds(LongSnippet.Parse(value, invariantCulture))), + SwitchCaseExpression.Default(DateTimeOffsetSnippet.Parse(value, invariantCulture, new MemberExpression(typeof(DateTimeStyles), nameof(DateTimeStyles.AssumeUniversal)))) + }), + this); + } + + public DateTimeOffsetSnippet ParseDateTimeOffset(ValueExpression value, ValueExpression format) + => new(new InvokeStaticMethodExpression(Type, _parseDateTimeOffsetMethodName, new[] { value, format })); + + private const string _parseTimeSpanMethodName = "ParseTimeSpan"; + private MethodProvider BuildParseTimeSpanMethodProvider() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(string)); + var formatParameter = new ParameterProvider("format", FormattableStringHelpers.Empty, typeof(string)); + var signature = new MethodSignature( + Name: _parseTimeSpanMethodName, + Modifiers: _methodModifiers, + Parameters: new[] { valueParameter, formatParameter }, + ReturnType: typeof(TimeSpan), + Summary: null, Description: null, ReturnDescription: null); + + var value = new StringSnippet(valueParameter); + var format = new StringSnippet(formatParameter); + return new MethodProvider( + signature, + new SwitchExpression(format, new SwitchCaseExpression[] + { + new(Literal("P"), new InvokeStaticMethodExpression(typeof(XmlConvert), nameof(XmlConvert.ToTimeSpan), [value])), + SwitchCaseExpression.Default(TimeSpanSnippet.ParseExact(value, format, new MemberExpression(typeof(CultureInfo), nameof(CultureInfo.InvariantCulture)))) + }), + this); + } + + public TimeSpanSnippet ParseTimeSpan(ValueExpression value, ValueExpression format) + => new(new InvokeStaticMethodExpression(Type, _parseTimeSpanMethodName, new[] { value, format })); + + private const string _convertToStringMethodName = "ConvertToString"; + private MethodProvider BuildConvertToStringMethodProvider() + { + var valueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(object)); + var nullableStringType = new CSharpType(typeof(string), true); + var formatParameter = new ParameterProvider("format", FormattableStringHelpers.Empty, nullableStringType, DefaultOf(nullableStringType)); + var signature = new MethodSignature( + Name: _convertToStringMethodName, + Modifiers: MethodSignatureModifiers.Public | MethodSignatureModifiers.Static, + Parameters: new[] { valueParameter, formatParameter }, + ReturnType: typeof(string), + Summary: null, Description: null, ReturnDescription: null); + + var value = (ValueExpression)valueParameter; + var format = new StringSnippet(formatParameter); + var body = new SwitchExpression(value, new SwitchCaseExpression[] + { + new SwitchCaseExpression(Null, Literal("null")), + new SwitchCaseExpression(new DeclarationExpression(typeof(string), "s", out var s), s), + new SwitchCaseExpression(new DeclarationExpression(typeof(bool), "b", out var b), ToString(b)), + new SwitchCaseExpression(GetTypePattern(new CSharpType[] {typeof(int),typeof(float), typeof(double), typeof(long), typeof(decimal)}), value.CastTo(typeof(IFormattable)).Invoke(nameof(IFormattable.ToString), _defaultNumberFormatField, _invariantCultureExpression)), + // TODO -- figure out how to write this line + SwitchCaseExpression.When(new DeclarationExpression(typeof(byte[]), "b", out var bytes), NotEqual(format, Null), ToString(bytes, format)), + new SwitchCaseExpression(new DeclarationExpression(typeof(IEnumerable), "s", out var enumerable), StringSnippet.Join(Literal(","), enumerable)), + SwitchCaseExpression.When(new DeclarationExpression(typeof(DateTimeOffset), "dateTime", out var dateTime), NotEqual(format, Null), ToString(dateTime, format)), + SwitchCaseExpression.When(new DeclarationExpression(typeof(TimeSpan), "timeSpan", out var timeSpan), NotEqual(format, Null), ToString(timeSpan, format)), + new SwitchCaseExpression(new DeclarationExpression(typeof(TimeSpan), "timeSpan", out var timeSpanNoFormat), new InvokeStaticMethodExpression(typeof(XmlConvert), nameof(XmlConvert.ToString), [timeSpanNoFormat])), + new SwitchCaseExpression(new DeclarationExpression(typeof(Guid), "guid", out var guid), guid.Untyped.Invoke("ToString")), + new SwitchCaseExpression(new DeclarationExpression(typeof(BinaryData), "binaryData", out var binaryData), ConvertToString(new BinaryDataSnippet(binaryData).ToArray(), format)), + SwitchCaseExpression.Default(value.InvokeToString()) + }); + + return new(signature, body, this); + } + + private static ValueExpression GetTypePattern(IReadOnlyList types) + { + ValueExpression result = types[^1]; + + for (int i = types.Count - 2; i >= 0; i--) + { + result = new BinaryOperatorExpression(" or ", types[i], result); // chain them together + } + + return result; + } + + public StringSnippet ConvertToString(ValueExpression value, ValueExpression? format = null) + { + var arguments = format != null + ? new[] { value, format } + : new[] { value }; + return new(new InvokeStaticMethodExpression(Type, _convertToStringMethodName, arguments)); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs index b2537161bb..6802373ef9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs @@ -75,12 +75,13 @@ public override ParameterProvider CreateCSharpParam(InputParameter inputParamete /// a method collection will be created consisting of a method. Otherwise, null will be returned. /// /// The input operation to create methods for. - public override CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation) + /// The enclosing type of the operation. + public override CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation, TypeProvider enclosingType) { switch (GetOperationKind(operation)) { case var value when value == OperationKinds.Default: - return CSharpMethodCollection.DefaultCSharpMethodCollection(operation); + return CSharpMethodCollection.DefaultCSharpMethodCollection(operation, enclosingType); default: return null; } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Snippets/SystemExtensibleSnippets.SystemModelSnippets.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Snippets/SystemExtensibleSnippets.SystemModelSnippets.cs index 0da82862ba..e3bd5f78c5 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Snippets/SystemExtensibleSnippets.SystemModelSnippets.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Snippets/SystemExtensibleSnippets.SystemModelSnippets.cs @@ -21,7 +21,8 @@ public override MethodProvider BuildFromOperationResponseMethod(TypeProvider typ { Snippet.UsingVar("document", JsonDocumentSnippet.Parse(new PipelineResponseSnippet(result).Content), out var document), Snippet.Return(TypeProviderSnippet.Deserialize(typeProvider, document.RootElement)) - }); + }, + typeProvider); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ModelReaderWriterOptionsSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ModelReaderWriterOptionsSnippet.cs new file mode 100644 index 0000000000..fb5023a117 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/TypedSnippets/ModelReaderWriterOptionsSnippet.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Snippets; + +namespace Microsoft.Generator.CSharp.ClientModel.Snippets +{ + internal sealed record ModelReaderWriterOptionsSnippet(ValueExpression Untyped) : TypedSnippet(Untyped) + { + public static readonly ModelReaderWriterOptionsSnippet Wire = ModelSerializationExtensionsProvider.Instance.WireOptions; + + public ValueExpression Format => new MemberExpression(this, nameof(ModelReaderWriterOptions.Format)); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/FormattableStringHelpers.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/FormattableStringHelpers.cs index 4f5f405e53..9a58515ce7 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/FormattableStringHelpers.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/FormattableStringHelpers.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; -using Microsoft.Generator.CSharp.Input; -using System.Text.RegularExpressions; using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using Microsoft.Generator.CSharp.Input; namespace Microsoft.Generator.CSharp.ClientModel { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/Utf8JsonWriterSnippetExtensions.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/Utf8JsonWriterSnippetExtensions.cs new file mode 100644 index 0000000000..cee3ad2ccc --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Utilities/Utf8JsonWriterSnippetExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; + +namespace Microsoft.Generator.CSharp.ClientModel +{ + internal static class Utf8JsonWriterSnippetExtensions + { + public static MethodBodyStatement WriteObjectValue(this Utf8JsonWriterSnippet snippet, TypedSnippet value, ValueExpression? options = null) + => ModelSerializationExtensionsProvider.Instance.WriteObjectValue(snippet, value, options: options); + + public static MethodBodyStatement WriteStringValue(this Utf8JsonWriterSnippet snippet, ValueExpression value, string? format) + => ModelSerializationExtensionsProvider.Instance.WriteStringValue(snippet, value, format); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj index eef25b5d96..7678639543 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj @@ -19,6 +19,7 @@ + PreserveNewest diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/MrwSerializationTypeProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/MrwSerializationTypeProviderTests.cs index b181822e6b..fb483735fb 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/MrwSerializationTypeProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/MrwSerializationTypeProviderTests.cs @@ -1,20 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using Microsoft.CodeAnalysis; -using Microsoft.Generator.CSharp.Expressions; -using Microsoft.Generator.CSharp.Input; -using Microsoft.Generator.CSharp.Providers; -using Moq; -using NUnit.Framework; using System; -using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; -using System.Formats.Asn1; using System.IO; using System.Linq; using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Input; +using Microsoft.Generator.CSharp.Providers; +using Moq; +using NUnit.Framework; namespace Microsoft.Generator.CSharp.ClientModel.Tests { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TypeFormatterTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TypeFormatterTests.cs new file mode 100644 index 0000000000..d497fe561a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TypeFormatterTests.cs @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Text.Json; +using UnbrandedTypeSpec; +using NUnit.Framework; + +namespace Microsoft.Generator.CSharp.ClientModel.Tests +{ + public class TypeFormatterTests + { + public static object[] DateTimeOffsetCases = + { + new object[] { "O", new DateTimeOffset(2020, 05, 04, 03, 02, 01, 123, default), "2020-05-04T03:02:01.1230000Z" }, + new object[] { "O", new DateTimeOffset(2020, 05, 04, 03, 02, 01, 123, new TimeSpan(1, 0, 0)), "2020-05-04T02:02:01.1230000Z" }, + new object[] { "O", new DateTimeOffset(3155378975999999999, default), "9999-12-31T23:59:59.9999999Z" }, + new object[] { "O", new DateTimeOffset(3155378975999999999, new TimeSpan(1, 0, 0)), "9999-12-31T22:59:59.9999999Z" }, + + new object[] { "o", new DateTimeOffset(2020, 05, 04, 03, 02, 01, 123, default), "2020-05-04T03:02:01.1230000Z" }, + + new object[] { "D", new DateTimeOffset(2020, 05, 04, 0,0,0,0, default), "2020-05-04" }, + + new object[] { "U", new DateTimeOffset(2020, 05, 04, 03, 02, 01, 0, default), "1588561321" }, + + new object[] { "R", new DateTimeOffset(2020, 05, 04, 03, 02, 01, 0, default), "Mon, 04 May 2020 03:02:01 GMT" }, + new object[] { "R", new DateTimeOffset(2020, 05, 04, 03, 02, 01, 0, new TimeSpan(1, 0, 0)), "Mon, 04 May 2020 02:02:01 GMT" }, + }; + + public static object[] TimeSpanCases = + { + new object[] { "P", new TimeSpan(1, 2, 59, 59), "P1DT2H59M59S" }, + new object[] { "c", new TimeSpan(1, 2, 59, 59, 500), "1.02:59:59.5000000" } + }; + + public static object[] BinaryDataCases = + { + new object[] { "D", BinaryData.FromString("test"), "dGVzdA==" }, + new object[] { "U", BinaryData.FromString("test"), "dGVzdA" } + }; + + public static object[] TimeSpanWithoutFormatCases = + { + new object?[] { null, new TimeSpan(1, 2, 59, 59), "P1DT2H59M59S" }, + }; + + private static readonly object[] GuidCases = new object[] + { + new object?[] { null, Guid.Parse("11111111-1111-1111-1111-111112111111"), "11111111-1111-1111-1111-111112111111" } + }; + + [TestCaseSource(nameof(DateTimeOffsetCases))] + public void FormatsDatesAsString(string format, DateTimeOffset date, string expected) + { + var formatted = TypeFormatters.ToString(date, format); + Assert.AreEqual(expected, formatted); + Assert.AreEqual(date, TypeFormatters.ParseDateTimeOffset(formatted, format)); + } + + [TestCaseSource(nameof(DateTimeOffsetCases))] + public void FormatsDatesAsJson(string format, DateTimeOffset date, string expected) + { + using MemoryStream memoryStream = new MemoryStream(); + using (var writer = new Utf8JsonWriter(memoryStream)) + { + if (format == "U") + { + writer.WriteNumberValue(date, format); + } + else + { + writer.WriteStringValue(date, format); + } + } + + var formatted = JsonDocument.Parse(memoryStream.ToArray()).RootElement; + Assert.AreEqual(expected, formatted.ToString()); + Assert.AreEqual(date, formatted.GetDateTimeOffset(format)); + } + + [TestCase("2020-05-04T03:02:01.1230000+08:00")] + [TestCase("2020-05-04T03:02:01.1230000-08:00")] + [TestCase("2020-05-04T03:02:01.1230000+00:00")] + [TestCase("2020-05-04T03:02:01.1230000")] + [TestCase("Mon, 04 May 2020 03:02:01 GMT")] + [TestCase("Mon, 04 May 2020 03:02:01")] + public void TestEqualAfterConvertingToUtc(string dateString) + { + string[] formats = { "O", "o" }; + + foreach (string format in formats) + { + var originalDate = DateTimeOffset.Parse(dateString); + var originalTimeMillis = originalDate.ToUnixTimeMilliseconds(); + + var formatted = TypeFormatters.ToString(originalDate, format); + var utcDate = DateTimeOffset.Parse(formatted); + Assert.AreEqual(originalTimeMillis, utcDate.ToUnixTimeMilliseconds()); + } + } + + [TestCaseSource(nameof(TimeSpanCases))] + public void FormatsTimeSpanAsJson(string format, TimeSpan duration, string expected) + { + using MemoryStream memoryStream = new MemoryStream(); + using (var writer = new Utf8JsonWriter(memoryStream)) + { + writer.WriteStringValue(duration, format); + } + + var formatted = JsonDocument.Parse(memoryStream.ToArray()).RootElement; + Assert.AreEqual(expected, formatted.ToString()); + Assert.AreEqual(duration, formatted.GetTimeSpan(format)); + } + + [TestCase(null, null, "null")] + [TestCase(null, "str", "str")] + [TestCase(null, true, "true")] + [TestCase(null, false, "false")] + [TestCase(null, 42, "42")] + [TestCase(null, -42, "-42")] + [TestCase(null, 3.14f, "3.14")] + [TestCase(null, -3.14f, "-3.14")] + [TestCase(null, 3.14, "3.14")] + [TestCase(null, -3.14, "-3.14")] + [TestCase(null, 299792458L, "299792458")] + [TestCase(null, -299792458L, "-299792458")] + [TestCase("D", new byte[] { 1, 2, 3 }, "AQID")] + [TestCase("U", new byte[] { 4, 5, 6 }, "BAUG")] + [TestCase(null, new string[] { "a", "b" }, "a,b")] + [TestCaseSource(nameof(DateTimeOffsetCases))] + [TestCaseSource(nameof(TimeSpanWithoutFormatCases))] + [TestCaseSource(nameof(TimeSpanCases))] + [TestCaseSource(nameof(GuidCases))] + [TestCaseSource(nameof(BinaryDataCases))] + public void ValidateConvertToString(string? format, object? value, string expected) + { + var result = TypeFormatters.ConvertToString(value, format); + + Assert.AreEqual(expected, result); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CSharpGen.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CSharpGen.cs index 6f4da23564..34487ec951 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CSharpGen.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CSharpGen.cs @@ -58,10 +58,10 @@ public async Task ExecuteAsync() } Directory.CreateDirectory(Path.Combine(outputPath, "src", "Generated", "Internal")); - generateFilesTasks.Add(workspace.AddGeneratedFile(CodeModelPlugin.Instance.GetWriter(ChangeTrackingListProvider.Instance).Write())); - generateFilesTasks.Add(workspace.AddGeneratedFile(CodeModelPlugin.Instance.GetWriter(ChangeTrackingDictionaryProvider.Instance).Write())); - generateFilesTasks.Add(workspace.AddGeneratedFile(CodeModelPlugin.Instance.GetWriter(ArgumentProvider.Instance).Write())); - generateFilesTasks.Add(workspace.AddGeneratedFile(CodeModelPlugin.Instance.GetWriter(OptionalProvider.Instance).Write())); + foreach (var type in output.Types) + { + generateFilesTasks.Add(workspace.AddGeneratedFile(CodeModelPlugin.Instance.GetWriter(type).Write())); + } // Add all the generated files to the workspace await Task.WhenAll(generateFilesTasks); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CodeModelPlugin.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CodeModelPlugin.cs index 9c840c1860..593cbad430 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CodeModelPlugin.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/CodeModelPlugin.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis; using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Providers; using Microsoft.Generator.CSharp.Snippets; @@ -39,6 +40,7 @@ public CodeModelPlugin(GeneratorContext context) public abstract OutputLibrary OutputLibrary { get; } public InputLibrary InputLibrary => _inputLibrary.Value; public virtual TypeProviderWriter GetWriter(TypeProvider provider) => new(provider); + public virtual IReadOnlyList AdditionalMetadataReferences => Array.Empty(); /// /// Returns the serialization type providers for the given model type provider. diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpMethodCollection.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpMethodCollection.cs index 9489ccd281..ccd08328b7 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpMethodCollection.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpMethodCollection.cs @@ -27,9 +27,10 @@ private CSharpMethodCollection(IReadOnlyList methods) /// with a single method that creates a message. /// /// The to convert. - public static CSharpMethodCollection DefaultCSharpMethodCollection(InputOperation operation) + /// The that will contain the methods. + public static CSharpMethodCollection DefaultCSharpMethodCollection(InputOperation operation, TypeProvider enclosingType) { - var createMessageMethod = BuildCreateMessageMethod(operation); + var createMessageMethod = BuildCreateMessageMethod(operation, enclosingType); var cSharpMethods = new List() { createMessageMethod }; // TO-DO: Add Protocol and Convenience methods https://github.com/Azure/autorest.csharp/issues/4585, https://github.com/Azure/autorest.csharp/issues/4586 return new CSharpMethodCollection(cSharpMethods); @@ -45,7 +46,7 @@ public int Count get { return _cSharpMethods.Count; } } - private static MethodProvider BuildCreateMessageMethod(InputOperation operation) + private static MethodProvider BuildCreateMessageMethod(InputOperation operation, TypeProvider enclosingType) { // TO-DO: properly build method https://github.com/Azure/autorest.csharp/issues/4583 List methodParameters = new(); @@ -59,7 +60,7 @@ private static MethodProvider BuildCreateMessageMethod(InputOperation operation) var methodSignature = new MethodSignature(methodSignatureName, FormattableStringHelpers.FromString(operation.Summary), FormattableStringHelpers.FromString(operation.Description), methodModifier, null, null, Parameters: methodParameters); var methodBody = Snippet.EmptyStatement; - return new MethodProvider(methodSignature, methodBody); + return new MethodProvider(methodSignature, methodBody, enclosingType); } /// diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/OutputLibrary.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/OutputLibrary.cs index 74702196a0..85bfff6e87 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/OutputLibrary.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/OutputLibrary.cs @@ -80,5 +80,20 @@ public virtual ClientProvider[] BuildClients() return clientProviders; } + + //TODO should combine all typeproviders into one list vs models + enums + clients since they are all the same + //https://github.com/microsoft/typespec/issues/3589 + private IReadOnlyList? _types; + public virtual IReadOnlyList Types => _types ??= BuildTypes(); + protected virtual IReadOnlyList BuildTypes() + { + return + [ + ChangeTrackingListProvider.Instance, + ChangeTrackingDictionaryProvider.Instance, + ArgumentProvider.Instance, + OptionalProvider.Instance + ]; + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/PropertyDescriptionBuilder.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/PropertyDescriptionBuilder.cs index 0ee56b02d2..a9be70aec7 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/PropertyDescriptionBuilder.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/PropertyDescriptionBuilder.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using Microsoft.Generator.CSharp.Input; +using Microsoft.Generator.CSharp.Statements; namespace Microsoft.Generator.CSharp { @@ -19,25 +21,10 @@ internal static class PropertyDescriptionBuilder /// The serialization format of the property. /// Flag used to determine if the property is read-only. /// The formatted property description string. - internal static IReadOnlyList BuildPropertyDescription(InputModelProperty property, CSharpType type, SerializationFormat serializationFormat, bool isPropertyReadOnly) + internal static XmlDocSummaryStatement BuildPropertyDescription(InputModelProperty property, CSharpType type, SerializationFormat serializationFormat, FormattableString description) { - List description = new List(); - - if (string.IsNullOrEmpty(property.Description)) - { - description.Add(CreateDefaultPropertyDescription(property.Name, isPropertyReadOnly)); - } - else - { - description.Add(FormattableStringHelpers.FromString(property.Description)); - } - - if (type.ContainsBinaryData) - { - description.AddRange(CreateBinaryDataExtraDescription(type, serializationFormat)); - } - - return description; + var innerStatements = type.ContainsBinaryData ? CreateBinaryDataExtraDescription(type, serializationFormat) : Array.Empty(); + return new XmlDocSummaryStatement([description], [.. innerStatements]); } /// @@ -48,35 +35,35 @@ internal static IReadOnlyList BuildPropertyDescription(InputM /// the list of union type items. /// A list of FormattableString representing the description of each union item. /// - internal static IReadOnlyList GetUnionTypesDescriptions(IReadOnlyList unionItems) + internal static IReadOnlyList GetUnionTypesDescriptions(IReadOnlyList unionItems) { - var values = new List(); + var values = new List(); foreach (CSharpType item in unionItems) { - FormattableString description; + XmlDocStatement description; if (item.IsLiteral && item.Literal != null) { var literalValue = item.Literal; if (item.FrameworkType == typeof(string)) { - description = $"{literalValue:L}"; + description = new XmlDocStatement("description", [$"{literalValue:L}"]); } else { - description = $"{literalValue}"; + description = new XmlDocStatement("description", [$"{literalValue}"]); } } else { - description = $"{item:C}"; + description = new XmlDocStatement("description", [$"{item:C}"]); } values.Add(description); } - return values.Distinct().ToList(); + return values; } /// @@ -102,11 +89,11 @@ internal static FormattableString CreateDefaultPropertyDescription(string name, /// The CSharpType of the property. /// The serialization format of the property. /// The formatted description string for the property. - private static IReadOnlyList CreateBinaryDataExtraDescription(CSharpType type, SerializationFormat serializationFormat) + private static IReadOnlyList CreateBinaryDataExtraDescription(CSharpType type, SerializationFormat serializationFormat) { string typeSpecificDesc; var unionTypes = GetUnionTypes(type); - IReadOnlyList unionTypeDescriptions = Array.Empty(); + IReadOnlyList unionTypeDescriptions = Array.Empty(); if (unionTypes.Any()) { @@ -129,7 +116,7 @@ private static IReadOnlyList CreateBinaryDataExtraDescription return ConstructBinaryDataDescription(typeSpecificDesc, serializationFormat, unionTypeDescriptions); } - return Array.Empty(); + return Array.Empty(); } // recursively get the union types if any. @@ -147,80 +134,65 @@ private static IReadOnlyList GetUnionTypes(CSharpType type) return Array.Empty(); } - private static IReadOnlyList ConstructBinaryDataDescription(string typeSpecificDesc, SerializationFormat serializationFormat, IReadOnlyList unionTypeDescriptions) + private static IReadOnlyList ConstructBinaryDataDescription(string typeSpecificDesc, SerializationFormat serializationFormat, IReadOnlyList unionTypeDescriptions) { - List result = new List(); - List unionTypesAdditionalDescription = new List(); + List result = new List(); + XmlDocStatement? unionRemarks = null; if (unionTypeDescriptions.Count > 0) { - unionTypesAdditionalDescription.Add($""); - unionTypesAdditionalDescription.Add($"Supported types:"); - unionTypesAdditionalDescription.Add($""); - foreach (FormattableString unionTypeDescription in unionTypeDescriptions) + XmlDocStatement[] listItems = new XmlDocStatement[unionTypeDescriptions.Count]; + for (int i = 0; i < unionTypeDescriptions.Count; i++) { - unionTypesAdditionalDescription.Add($""); - unionTypesAdditionalDescription.Add(unionTypeDescription); - unionTypesAdditionalDescription.Add($""); + listItems[i] = new XmlDocStatement("item", [], innerStatements: unionTypeDescriptions[i]); } - unionTypesAdditionalDescription.Add($""); - unionTypesAdditionalDescription.Add($""); + var listXmlDoc = new XmlDocStatement("", "", [], innerStatements: listItems); + unionRemarks = new XmlDocStatement("remarks", [$"Supported types:"], innerStatements: listXmlDoc); } switch (serializationFormat) { case SerializationFormat.Bytes_Base64Url: case SerializationFormat.Bytes_Base64: - result.Add($""); - result.Add($"To assign a byte[] to {typeSpecificDesc} use ."); - result.Add($"The byte[] will be serialized to a Base64 encoded string."); - result.Add($""); - result.Add($""); - if (unionTypesAdditionalDescription.Count > 0) + result.Add(new XmlDocStatement("para", + [ + $"To assign a byte[] to {typeSpecificDesc} use .", + $"The byte[] will be serialized to a Base64 encoded string." + ])); + if (unionRemarks is not null) { - result.AddRange(unionTypesAdditionalDescription); + result.Add(new XmlDocStatement("para", [], innerStatements: unionRemarks)); } - result.Add($"Examples:"); - result.Add($""); - result.Add($""); - result.Add($"BinaryData.FromBytes(new byte[] {{ 1, 2, 3 }})"); - result.Add($"Creates a payload of \"AQID\"."); - result.Add($""); - result.Add($""); - result.Add($""); + var listItems = new XmlDocStatement("item", [], + new XmlDocStatement("term", [$"BinaryData.FromBytes(new byte[] {{ 1, 2, 3 }})"]), + new XmlDocStatement("description", [$"Creates a payload of \"AQID\"."])); + var listXmlDoc = new XmlDocStatement("", "", [], innerStatements: listItems); + result.Add(new XmlDocStatement("para", [$"Examples:"], innerStatements: listXmlDoc)); break; default: - result.Add($""); - result.Add($"To assign an object to {typeSpecificDesc} use ."); - result.Add($""); - result.Add($""); - result.Add($"To assign an already formatted json string to this property use ."); - result.Add($""); - result.Add($""); - if (unionTypesAdditionalDescription.Count > 0) + result.Add(new XmlDocStatement("para", [$"To assign an object to {typeSpecificDesc} use ."])); + result.Add(new XmlDocStatement("para", [$"To assign an already formatted json string to this property use ."])); + if (unionRemarks is not null) { - result.AddRange(unionTypesAdditionalDescription); + result.Add(new XmlDocStatement("para", [], innerStatements: unionRemarks)); } - result.Add($"Examples:"); - result.Add($""); - result.Add($""); - result.Add($"BinaryData.FromObjectAsJson(\"foo\")"); - result.Add($"Creates a payload of \"foo\"."); - result.Add($""); - result.Add($""); - result.Add($"BinaryData.FromString(\"\\\"foo\\\"\")"); - result.Add($"Creates a payload of \"foo\"."); - result.Add($""); - result.Add($""); - result.Add($"BinaryData.FromObjectAsJson(new {{ key = \"value\" }})"); - result.Add($"Creates a payload of {{ \"key\": \"value\" }}."); - result.Add($""); - result.Add($""); - result.Add($"BinaryData.FromString(\"{{\\\"key\\\": \\\"value\\\"}}\")"); - result.Add($"Creates a payload of {{ \"key\": \"value\" }}."); - result.Add($""); - result.Add($""); - result.Add($""); + XmlDocStatement[] bdListItems = + [ + new XmlDocStatement("item", [], + new XmlDocStatement("term", [$"BinaryData.FromObjectAsJson(\"foo\")"]), + new XmlDocStatement("description", [$"Creates a payload of \"foo\"."])), + new XmlDocStatement("item", [], + new XmlDocStatement("term", [$"BinaryData.FromString(\"\\\"foo\\\"\")"]), + new XmlDocStatement("description", [$"Creates a payload of \"foo\"."])), + new XmlDocStatement("item", [], + new XmlDocStatement("term", [$"BinaryData.FromObjectAsJson(new {{ key = \"value\" }})"]), + new XmlDocStatement("description", [$"Creates a payload of {{ \"key\": \"value\" }}."])), + new XmlDocStatement("item", [], + new XmlDocStatement("term", [$"BinaryData.FromString(\"{{\\\"key\\\": \\\"value\\\"}}\")"]), + new XmlDocStatement("description", [$"Creates a payload of {{ \"key\": \"value\" }}."])), + ]; + var bdList = new XmlDocStatement("", "", [], innerStatements: bdListItems); + result.Add(new XmlDocStatement("para", [$"Examples:"], innerStatements: bdList)); break; } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/TypeFactory.cs index 03195f2106..6b7dc04da9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/TypeFactory.cs @@ -28,10 +28,11 @@ public abstract class TypeFactory /// Factory method for creating a based on an input operation . /// /// The to convert. + /// The that will contain the methods. /// An instance of containing the chain of methods /// associated with the input operation, or null if no methods are constructed. /// - public abstract CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation); + public abstract CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation, TypeProvider enclosingType); /// /// Factory method for retrieving the serialization format for a given input type. diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/PostProcessing/GeneratedCodeWorkspace.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/PostProcessing/GeneratedCodeWorkspace.cs index 10e8eca015..d69f69f01a 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/PostProcessing/GeneratedCodeWorkspace.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/PostProcessing/GeneratedCodeWorkspace.cs @@ -110,7 +110,7 @@ private static Project CreateGeneratedCodeProject() Project generatedCodeProject = workspace.AddProject(GeneratedCodeProjectName, LanguageNames.CSharp); generatedCodeProject = generatedCodeProject - .AddMetadataReferences(_assemblyMetadataReferences.Value) + .AddMetadataReferences(_assemblyMetadataReferences.Value.Concat(CodeModelPlugin.Instance.AdditionalMetadataReferences)) .WithCompilationOptions(new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, metadataReferenceResolver: _metadataReferenceResolver.Value, nullableContextOptions: NullableContextOptions.Disable)); return generatedCodeProject; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ArgumentProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ArgumentProvider.cs index 659e111fca..0f6c1d7795 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ArgumentProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ArgumentProvider.cs @@ -95,7 +95,8 @@ private MethodProvider BuildAssertNull() { ThrowArgumentException(NullCoalescing(message, Literal("Value must be null."))) } - }); + }, + this); } private MethodProvider BuildCheckNotNullOrEmptyString() @@ -107,7 +108,8 @@ private MethodProvider BuildCheckNotNullOrEmptyString() { AssertNotNullOrEmpty(value, _nameParamRef), Return(value) - }); + }, + this); } private MethodProvider BuildCheckNotNull() @@ -119,7 +121,8 @@ private MethodProvider BuildCheckNotNull() { AssertNotNull(value, _nameParamRef), Return(value) - }); + }, + this); } private MethodProvider BuildAssertEnumDefined() @@ -135,7 +138,8 @@ private MethodProvider BuildAssertEnumDefined() { ThrowArgumentException(new FormattableStringExpression("Value not defined for {0}.", [new MemberExpression(enumType, "FullName")])) } - }); + }, + this); } private MethodProvider BuildAssertInRange() @@ -156,7 +160,8 @@ private MethodProvider BuildAssertInRange() { Throw(New.ArgumentOutOfRangeException(_nameParamRef, "Value is greater than the maximum allowed.", false)) } - }); + }, + this); } private ValueExpression GetCompareToExpression(ValueExpression left, ValueExpression right) @@ -177,7 +182,8 @@ private MethodProvider BuildAssertNotDefault() { ThrowArgumentException("Value cannot be empty.") } - }); + }, + this); } private MethodProvider BuildAssertNotNullOrWhiteSpace() @@ -192,7 +198,8 @@ private MethodProvider BuildAssertNotNullOrWhiteSpace() { ThrowArgumentException("Value cannot be empty or contain only white-space characters.") } - }); + }, + this); } private MethodProvider BuildAssertNotNullOrEmptyString() @@ -207,7 +214,8 @@ private MethodProvider BuildAssertNotNullOrEmptyString() { ThrowArgumentException("Value cannot be an empty string.") } - }); + }, + this); } private MethodProvider BuildAssertNotNullOrEmptyCollection() @@ -231,7 +239,8 @@ private MethodProvider BuildAssertNotNullOrEmptyCollection() { ThrowArgumentException(throwMessage) } - }); + }, + this); } private static BoolSnippet IsCollectionEmpty(ParameterProvider valueParam, VariableReferenceSnippet collection) @@ -257,7 +266,8 @@ private MethodProvider BuildAssertNotNullStruct() { Throw(New.ArgumentNullException(_nameParamRef, false)) } - }); + }, + this); } private MethodProvider BuildAssertNotNull() @@ -267,7 +277,8 @@ private MethodProvider BuildAssertNotNull() return new MethodProvider(signature, new MethodBodyStatement[] { AssertNotNullSnippet(valueParam) - }); + }, + this); } private IfStatement AssertNotNullSnippet(ParameterProvider valueParam) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingDictionaryProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingDictionaryProvider.cs index 1873406321..9fcaebc4d3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingDictionaryProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingDictionaryProvider.cs @@ -99,7 +99,8 @@ private MethodProvider ConstructorWithReadOnlyDictionary() { _innerDictionary.Add(pair) } - }); + }, + this); } private MethodProvider ConstructorWithDictionary() @@ -114,13 +115,14 @@ private MethodProvider ConstructorWithDictionary() Return() }, Assign(_innerDictionary, New.Instance(_dictionary, dictionary)) - }); + }, + this); } private MethodProvider DefaultConstructor() { var signature = new ConstructorSignature(Type, null, null, MethodSignatureModifiers.Public, Array.Empty()); - return new MethodProvider(signature, Array.Empty()); + return new MethodProvider(signature, Array.Empty(), this); } protected override PropertyProvider[] BuildProperties() @@ -256,7 +258,8 @@ private MethodProvider BuildTryGetValue() Return(False) }, Return(EnsureDictionary.Invoke("TryGetValue", new ParameterReferenceSnippet(keyParam), new KeywordExpression("out", value))) - }); + }, + this); } private MethodProvider BuildRemoveKey() @@ -270,7 +273,8 @@ private MethodProvider BuildRemoveKey() Return(False) }, Return(EnsureDictionary.Invoke("Remove", new ParameterReferenceSnippet(keyParam))) - }); + }, + this); } private MethodProvider BuildContainsKey() @@ -284,7 +288,8 @@ private MethodProvider BuildContainsKey() Return(False) }, Return(EnsureDictionary.Invoke("ContainsKey", new ParameterReferenceSnippet(keyParam))) - }); + }, + this); } private MethodProvider BuildAdd() @@ -295,7 +300,8 @@ private MethodProvider BuildAdd() return new MethodProvider(signature, new MethodBodyStatement[] { EnsureDictionary.Invoke("Add", new ParameterReferenceSnippet(keyParam), new ParameterReferenceSnippet(valueParam)).ToStatement() - }); + }, + this); } private MethodProvider BuildRemovePair() @@ -310,7 +316,8 @@ private MethodProvider BuildRemovePair() Return(False) }, Return(EnsureDictionary.Invoke("Remove", item)) - }); + }, + this); } private MethodProvider BuildCopyTo() @@ -328,7 +335,8 @@ private MethodProvider BuildCopyTo() Return() }, EnsureDictionary.Invoke("CopyTo", array, index).ToStatement() - }); + }, + this); } private MethodProvider BuildContains() @@ -343,7 +351,8 @@ private MethodProvider BuildContains() Return(False) }, Return(EnsureDictionary.Invoke("Contains", item)) - }); + }, + this); } private MethodProvider BuildClear() @@ -352,7 +361,8 @@ private MethodProvider BuildClear() return new MethodProvider(signature, new MethodBodyStatement[] { EnsureDictionary.Invoke("Clear").ToStatement() - }); + }, + this); } private MethodProvider BuildAddPair() @@ -363,7 +373,8 @@ private MethodProvider BuildAddPair() return new MethodProvider(signature, new MethodBodyStatement[] { EnsureDictionary.Invoke("Add", item).ToStatement() - }); + }, + this); } private MethodProvider BuildGetEnumerator() @@ -372,7 +383,8 @@ private MethodProvider BuildGetEnumerator() return new MethodProvider(signature, new MethodBodyStatement[] { Return(This.Invoke("GetEnumerator")) - }); + }, + this); } private MethodProvider BuildGetEnumeratorGeneric() @@ -386,7 +398,8 @@ private MethodProvider BuildGetEnumeratorGeneric() Return(new InvokeStaticMethodExpression(null, "enumerateEmpty", Array.Empty())) }, Return(EnsureDictionary.Invoke("GetEnumerator")) - }); + }, + this); } private MethodProvider BuildEnsureDictionary() @@ -394,7 +407,8 @@ private MethodProvider BuildEnsureDictionary() return new MethodProvider(_ensureDictionarySignature, new MethodBodyStatement[] { Return(new BinaryOperatorExpression("??=", _innerDictionary, New.Instance(_dictionary))) - }); + }, + this); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs index d795f80a93..43bf649287 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ChangeTrackingListProvider.cs @@ -84,9 +84,9 @@ protected override MethodProvider[] BuildConstructors() return [ - new MethodProvider(new ConstructorSignature(Type, null, null, MethodSignatureModifiers.Public, Array.Empty()), EmptyStatement), - new MethodProvider(iListSignature, iListBody), - new MethodProvider(iReadOnlyListSignature, iReadOnlyListBody) + new MethodProvider(new ConstructorSignature(Type, null, null, MethodSignatureModifiers.Public, Array.Empty()), EmptyStatement, this), + new MethodProvider(iListSignature, iListBody, this), + new MethodProvider(iReadOnlyListSignature, iReadOnlyListBody, this) ]; } @@ -185,7 +185,8 @@ private MethodProvider BuildRemoveAt() Throw(New.Instance(typeof(ArgumentOutOfRangeException), Nameof(indexVariable))) }, new InvokeInstanceMethodStatement(EnsureList, "RemoveAt", new ValueExpression[] { indexVariable }, false) - }); + }, + this); } private MethodProvider BuildInsert() @@ -193,7 +194,8 @@ private MethodProvider BuildInsert() return new MethodProvider(new MethodSignature("Insert", null, null, MethodSignatureModifiers.Public, null, null, new ParameterProvider[] { _indexParam, _tParam }), new MethodBodyStatement[] { new InvokeInstanceMethodStatement(EnsureList, "Insert", new ValueExpression[] { new ParameterReferenceSnippet(_indexParam), new ParameterReferenceSnippet(_tParam) }, false) - }); + }, + this); } private MethodProvider BuildIndexOf() @@ -206,7 +208,8 @@ private MethodProvider BuildIndexOf() Return(Literal(-1)) }, Return(EnsureList.Invoke(signature)) - }); + }, + this); } private MethodProvider BuildRemove() @@ -219,7 +222,8 @@ private MethodProvider BuildRemove() Return(False) }, Return(EnsureList.Invoke(signature)) - }); + }, + this); } private MethodProvider BuildCopyTo() @@ -233,7 +237,8 @@ private MethodProvider BuildCopyTo() Return() }, new InvokeInstanceMethodStatement(EnsureList, "CopyTo", new ValueExpression[] { new ParameterReferenceSnippet(arrayParam), new ParameterReferenceSnippet(arrayIndexParam) }, false) - }); + }, + this); } private MethodProvider BuildContains() @@ -246,7 +251,8 @@ private MethodProvider BuildContains() Return(False) }, Return(EnsureList.Invoke(signature)) - }); + }, + this); } private MethodProvider BuildClear() @@ -254,7 +260,8 @@ private MethodProvider BuildClear() return new MethodProvider(new MethodSignature("Clear", null, null, MethodSignatureModifiers.Public, null, null, Array.Empty()), new MethodBodyStatement[] { new InvokeInstanceMethodStatement(EnsureList, "Clear") - }); + }, + this); } private MethodProvider BuildAdd() @@ -263,7 +270,8 @@ private MethodProvider BuildAdd() return new MethodProvider(new MethodSignature("Add", null, null, MethodSignatureModifiers.Public, null, null, new ParameterProvider[] { genericParameter }), new MethodBodyStatement[] { new InvokeInstanceMethodStatement(EnsureList, "Add", new ParameterReferenceSnippet(genericParameter)) - }); + }, + this); } private MethodProvider BuildGetEnumerator() @@ -271,7 +279,8 @@ private MethodProvider BuildGetEnumerator() return new MethodProvider(new MethodSignature("GetEnumerator", null, null, MethodSignatureModifiers.None, typeof(IEnumerator), null, Array.Empty(), ExplicitInterface: typeof(IEnumerable)), new MethodBodyStatement[] { Return(This.Invoke(_getEnumeratorSignature)) - }); + }, + this); } private MethodProvider BuildGetEnumeratorOfT() @@ -284,7 +293,8 @@ private MethodProvider BuildGetEnumeratorOfT() Return(new InvokeStaticMethodExpression(null, "enumerateEmpty", Array.Empty())) }, Return(EnsureList.Invoke(_getEnumeratorSignature)) - }); + }, + this); } private MethodProvider BuildReset() @@ -292,7 +302,8 @@ private MethodProvider BuildReset() return new MethodProvider(new MethodSignature("Reset", null, null, MethodSignatureModifiers.Public, null, null, Array.Empty()), new MethodBodyStatement[] { Assign(_innerList, Null) - }); + }, + this); } private MethodProvider BuildEnsureList() @@ -300,7 +311,8 @@ private MethodProvider BuildEnsureList() return new MethodProvider(_ensureListSignature, new MethodBodyStatement[] { Return(new BinaryOperatorExpression("??=", _innerList, New.Instance(new CSharpType(typeof(List<>), _t)))) - }); + }, + this); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ClientProvider.cs index 5b93a81300..41789fe513 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ClientProvider.cs @@ -28,7 +28,7 @@ protected override MethodProvider[] BuildMethods() // Build methods for all the operations foreach (var operation in _inputClient.Operations) { - var methodCollection = CodeModelPlugin.Instance.TypeFactory.CreateCSharpMethodCollection(operation); + var methodCollection = CodeModelPlugin.Instance.TypeFactory.CreateCSharpMethodCollection(operation, this); if (methodCollection != null) { methods.AddRange(methodCollection); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs index 99aebabc45..df7ac1afdd 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs @@ -29,7 +29,7 @@ protected EnumProvider(InputEnumType input) IsFloatValueType = ValueType.Equals(typeof(float)) || ValueType.Equals(typeof(double)); IsNumericValueType = IsIntValueType || IsFloatValueType; - Description = input.Description != null ? FormattableStringHelpers.FromString(input.Description) : FormattableStringHelpers.Empty; + Description = input.Description != null ? FormattableStringHelpers.FromString(input.Description) : $"The {Name}."; } protected override string GetFileName() => Path.Combine("src", "Generated", "Models", $"{Name}.cs"); @@ -42,7 +42,7 @@ protected EnumProvider(InputEnumType input) internal bool IsNumericValueType { get; } public override string Name { get; } public override string Namespace { get; } - public override FormattableString Description { get; } + protected override FormattableString Description { get; } /// /// The serialization provider for this enum. diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs index fad9df0ba8..42cef1b8a6 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs @@ -110,7 +110,7 @@ protected override MethodProvider[] BuildConstructors() Assign(valueField, valueParameter) }; - return [new MethodProvider(signature, body)]; + return [new MethodProvider(signature, body, this)]; } protected override MethodProvider[] BuildMethods() @@ -130,7 +130,7 @@ protected override MethodProvider[] BuildMethods() ReturnDescription: null, Parameters: [leftParameter, rightParameter]); - methods.Add(new(equalitySignature, left.InvokeEquals(right))); + methods.Add(new(equalitySignature, left.InvokeEquals(right), this)); var inequalitySignature = equalitySignature with { @@ -138,7 +138,7 @@ protected override MethodProvider[] BuildMethods() Description = $"Determines if two {Type:C} values are not the same.", }; - methods.Add(new(inequalitySignature, Not(left.InvokeEquals(right)))); + methods.Add(new(inequalitySignature, Not(left.InvokeEquals(right)), this)); var valueParameter = new ParameterProvider("value", $"The value.", ValueType); var castSignature = new MethodSignature( @@ -150,7 +150,7 @@ protected override MethodProvider[] BuildMethods() ReturnDescription: null, Parameters: [valueParameter]); - methods.Add(new(castSignature, New.Instance(Type, valueParameter))); + methods.Add(new(castSignature, New.Instance(Type, valueParameter), this)); var objParameter = new ParameterProvider("obj", $"The object to compare.", typeof(object)); var equalsSignature = new MethodSignature( @@ -165,7 +165,7 @@ protected override MethodProvider[] BuildMethods() // writes the method: // public override bool Equals(object obj) => obj is EnumType other && Equals(other); - methods.Add(new(equalsSignature, And(Is(objParameter, new DeclarationExpression(Type, "other", out var other)), new BoolSnippet(new InvokeInstanceMethodExpression(null, nameof(object.Equals), [other]))))); + methods.Add(new(equalsSignature, And(Is(objParameter, new DeclarationExpression(Type, "other", out var other)), new BoolSnippet(new InvokeInstanceMethodExpression(null, nameof(object.Equals), [other]))), this)); var otherParameter = new ParameterProvider("other", $"The instance to compare.", Type); equalsSignature = equalsSignature with @@ -184,7 +184,7 @@ protected override MethodProvider[] BuildMethods() var equalsExpressionBody = IsStringValueType ? new InvokeStaticMethodExpression(ValueType, nameof(object.Equals), [valueField, otherValue, FrameworkEnumValue(StringComparison.InvariantCultureIgnoreCase)]) : new InvokeStaticMethodExpression(ValueType, nameof(object.Equals), [valueField, otherValue]); - methods.Add(new(equalsSignature, equalsExpressionBody)); + methods.Add(new(equalsSignature, equalsExpressionBody, this)); var getHashCodeSignature = new MethodSignature( Name: nameof(object.GetHashCode), @@ -203,7 +203,7 @@ protected override MethodProvider[] BuildMethods() var getHashCodeExpressionBody = IsStringValueType ? NullCoalescing(valueField.NullConditional().InvokeGetHashCode(), Int(0)) : valueField.Untyped.InvokeGetHashCode(); - methods.Add(new(getHashCodeSignature, getHashCodeExpressionBody)); + methods.Add(new(getHashCodeSignature, getHashCodeExpressionBody, this, XmlDocProvider.InheritDocs)); var toStringSignature = new MethodSignature( Name: nameof(object.ToString), @@ -222,7 +222,7 @@ protected override MethodProvider[] BuildMethods() ValueExpression toStringExpressionBody = IsStringValueType ? valueField : valueField.Untyped.Invoke(nameof(object.ToString), new MemberExpression(typeof(CultureInfo), nameof(CultureInfo.InvariantCulture))); - methods.Add(new(toStringSignature, toStringExpressionBody)); + methods.Add(new(toStringSignature, toStringExpressionBody, this, XmlDocProvider.InheritDocs)); // for string-based extensible enums, we are using `ToString` as its serialization // for non-string-based extensible enums, we need a method to serialize them @@ -241,7 +241,7 @@ protected override MethodProvider[] BuildMethods() // internal float ToSerialSingle() => _value; // when ValueType is float // internal int ToSerialInt32() => _value; // when ValueType is int // etc - methods.Add(new(toSerialSignature, valueField)); + methods.Add(new(toSerialSignature, valueField, this)); } return methods.ToArray(); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs index 20f0737cb1..a431e946a4 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs @@ -47,7 +47,7 @@ protected override IReadOnlyList BuildMembers() modifiers, ValueType, name, - FormattableStringHelpers.FromString(inputValue.Description), + inputValue.Description is null ? $"{name}" : FormattableStringHelpers.FromString(inputValue.Description), initializationValue); values[i] = new EnumTypeMember(name, field, inputValue.Value); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs index 91b88a2ce5..619cb7733d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs @@ -74,7 +74,7 @@ protected override MethodProvider[] BuildMethods() } var defaultCase = SwitchCaseExpression.Default(ThrowExpression(New.ArgumentOutOfRangeException(_enumType, serializationValueParameter))); var serializationBody = new SwitchExpression(serializationValueParameter, [.. knownCases, defaultCase]); - methods.Add(new(serializationSignature, serializationBody)); + methods.Add(new(serializationSignature, serializationBody, this)); } // deserialization method (we always need a deserialization) @@ -123,7 +123,7 @@ protected override MethodProvider[] BuildMethods() // add a fallback throw statement to ensure every path of this method returns a value deserializationBody.Add(Throw(New.ArgumentOutOfRangeException(_enumType, deserializationValueParameter))); - methods.Add(new(deserializationSignature, deserializationBody)); + methods.Add(new(deserializationSignature, deserializationBody, this)); return methods.ToArray(); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs index 7a92869f9e..585657326f 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/MethodProvider.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Collections.Generic; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Statements; @@ -17,20 +16,47 @@ public sealed class MethodProvider public MethodSignatureBase Signature { get; } public MethodBodyStatement? BodyStatements { get; } public ValueExpression? BodyExpression { get; } - public XmlDocProvider XmlDocs { get; } + public XmlDocProvider? XmlDocs { get; } /// /// Initializes a new instance of the class with a body statement and method signature. /// /// The method signature. /// The method body. - public MethodProvider(MethodSignatureBase signature, MethodBodyStatement bodyStatements) + /// The enclosing type. + /// The XML documentation provider. + public MethodProvider(MethodSignatureBase signature, MethodBodyStatement bodyStatements, TypeProvider enclosingType, XmlDocProvider? xmlDocProvider = default) { Signature = signature; bool skipParamValidation = !signature.Modifiers.HasFlag(MethodSignatureModifiers.Public); var paramHash = GetParamhash(skipParamValidation); BodyStatements = GetBodyStatementWithValidation(bodyStatements, paramHash); - XmlDocs = BuildXmlDocs(paramHash); + XmlDocs = xmlDocProvider ?? (IsMethodPublic(enclosingType.DeclarationModifiers, signature.Modifiers) ? BuildXmlDocs(paramHash) : null); + } + + /// + /// Initializes a new instance of the class with a body expression and method signature. + /// + /// The method signature. + /// The method body expression. + /// The enclosing type. + /// The XML documentation provider. + public MethodProvider(MethodSignatureBase signature, ValueExpression bodyExpression, TypeProvider enclosingType, XmlDocProvider? xmlDocProvider = default) + { + Signature = signature; + BodyExpression = bodyExpression; + XmlDocs = xmlDocProvider ?? (IsMethodPublic(enclosingType.DeclarationModifiers, signature.Modifiers) ? BuildXmlDocs(null) : null); + } + + private static bool IsMethodPublic(TypeSignatureModifiers typeModifiers, MethodSignatureModifiers methodModifiers) + { + if (!typeModifiers.HasFlag(TypeSignatureModifiers.Public)) + return false; + + if (methodModifiers.HasFlag(MethodSignatureModifiers.Public) || (methodModifiers.HasFlag(MethodSignatureModifiers.Protected) && !methodModifiers.HasFlag(MethodSignatureModifiers.Private))) + return true; + + return false; } private Dictionary>? GetParamhash(bool skipParamValidation) @@ -52,19 +78,6 @@ public MethodProvider(MethodSignatureBase signature, MethodBodyStatement bodySta return paramHash; } - /// - /// Initializes a new instance of the class with a body expression and method signature. - /// - /// The method signature. - /// The method body expression. - public MethodProvider(MethodSignatureBase signature, ValueExpression bodyExpression) - { - Signature = signature; - BodyExpression = bodyExpression; - XmlDocs = BuildXmlDocs(null); - } - - private MethodBodyStatement GetBodyStatementWithValidation(MethodBodyStatement bodyStatements, Dictionary>? paramHash) { if (paramHash is null) @@ -99,7 +112,7 @@ private MethodBodyStatement GetBodyStatementWithValidation(MethodBodyStatement b return statements; } - private XmlDocProvider BuildXmlDocs(Dictionary>? paramHash) + private XmlDocProvider? BuildXmlDocs(Dictionary>? paramHash) { var docs = new XmlDocProvider(); if (Signature.SummaryText is not null) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ModelProvider.cs index 5dd7d7de4d..46f657e567 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ModelProvider.cs @@ -18,7 +18,7 @@ public sealed class ModelProvider : TypeProvider private readonly InputModelType _inputModel; public override string Name { get; } public override string Namespace { get; } - public override FormattableString Description { get; } + protected override FormattableString Description { get; } private readonly bool _isStruct; private readonly TypeSignatureModifiers _declarationModifiers; @@ -35,7 +35,7 @@ public ModelProvider(InputModelType inputModel) _inputModel = inputModel; Name = inputModel.Name.ToCleanName(); Namespace = GetDefaultModelNamespace(CodeModelPlugin.Instance.Configuration.Namespace); - Description = inputModel.Description != null ? FormattableStringHelpers.FromString(inputModel.Description) : FormattableStringHelpers.Empty; + Description = inputModel.Description != null ? FormattableStringHelpers.FromString(inputModel.Description) : $"The {Name}."; // TODO -- support generating models as structs. Tracking issue: https://github.com/microsoft/typespec/issues/3453 _declarationModifiers = TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class; if (inputModel.Accessibility == "internal") @@ -98,7 +98,8 @@ protected override MethodProvider[] BuildConstructors() bodyStatements: new MethodBodyStatement[] { GetPropertyInitializers(constructorParameters) - }); + }, + this); return [constructor]; } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/OptionalProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/OptionalProvider.cs index 2ef8468cee..4b51fd1549 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/OptionalProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/OptionalProvider.cs @@ -82,7 +82,8 @@ private MethodProvider IsStringDefined() return new MethodProvider(signature, new MethodBodyStatement[] { Return(NotEqual(new ParameterReferenceSnippet(valueParam), Null)) - }); + }, + this); } private MethodProvider IsJsonElementDefined() @@ -92,7 +93,8 @@ private MethodProvider IsJsonElementDefined() return new MethodProvider(signature, new MethodBodyStatement[] { Return(new JsonElementSnippet(new ParameterReferenceSnippet(valueParam)).ValueKindNotEqualsUndefined()) - }); + }, + this); } private MethodProvider IsObjectDefined() @@ -102,7 +104,8 @@ private MethodProvider IsObjectDefined() return new MethodProvider(signature, new MethodBodyStatement[] { Return(NotEqual(new ParameterReferenceSnippet(valueParam), Null)) - }); + }, + this); } private MethodProvider IsStructDefined() @@ -112,7 +115,8 @@ private MethodProvider IsStructDefined() return new MethodProvider(signature, new MethodBodyStatement[] { Return(new MemberExpression(new ParameterReferenceSnippet(valueParam), "HasValue")) - }); + }, + this); } private MethodProvider BuildIsReadOnlyDictionaryDefined() @@ -126,7 +130,8 @@ private MethodProvider BuildIsReadOnlyDictionaryDefined() { Return(Not(BoolSnippet.Is(new ParameterReferenceSnippet(collectionParam), changeTrackingDeclarationExpression) .And(new MemberExpression(changeTrackingReference, "IsUndefined")))) - }); + }, + this); } private MethodProvider BuildIsDictionaryDefined() @@ -140,7 +145,8 @@ private MethodProvider BuildIsDictionaryDefined() { Return(Not(BoolSnippet.Is(new ParameterReferenceSnippet(collectionParam), changeTrackingDeclarationExpression) .And(new MemberExpression(changeTrackingReference, "IsUndefined")))) - }); + }, + this); } private MethodProvider BuildIsListDefined() @@ -154,7 +160,8 @@ private MethodProvider BuildIsListDefined() { Return(Not(BoolSnippet.Is(new ParameterReferenceSnippet(collectionParam), changeTrackingDeclarationExpression) .And(new MemberExpression(changeTrackingReference, "IsUndefined")))) - }); + }, + this); } internal BoolSnippet IsDefined(TypedSnippet value) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/PropertyProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/PropertyProvider.cs index a98875f901..e425c02519 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/PropertyProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/PropertyProvider.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Diagnostics; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Input; @@ -14,7 +13,8 @@ namespace Microsoft.Generator.CSharp.Providers [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] public class PropertyProvider { - public IReadOnlyList Description { get; } + public FormattableString Description { get; } + public XmlDocSummaryStatement XmlDocSummary { get; } public MethodSignatureModifiers Modifiers { get; } public CSharpType Type { get; } public string Name { get; } @@ -31,15 +31,17 @@ public PropertyProvider(InputModelProperty inputProperty) Type = propertyType; Modifiers = MethodSignatureModifiers.Public; - Description = PropertyDescriptionBuilder.BuildPropertyDescription(inputProperty, propertyType, serializationFormat, !propHasSetter); Name = inputProperty.Name.FirstCharToUpperCase(); Body = new AutoPropertyBody(propHasSetter, setterModifier, GetPropertyInitializationValue(propertyType, inputProperty)); + Description = string.IsNullOrEmpty(inputProperty.Description) ? PropertyDescriptionBuilder.CreateDefaultPropertyDescription(Name, !Body.HasSetter) : $"{inputProperty.Description}"; + XmlDocSummary = PropertyDescriptionBuilder.BuildPropertyDescription(inputProperty, propertyType, serializationFormat, Description); XmlDocs = GetXmlDocs(); } public PropertyProvider(FormattableString? description, MethodSignatureModifiers modifiers, CSharpType type, string name, PropertyBody body, CSharpType? explicitInterface = null) { - Description = [description ?? PropertyDescriptionBuilder.CreateDefaultPropertyDescription(name, !body.HasSetter)]; + Description = description ?? PropertyDescriptionBuilder.CreateDefaultPropertyDescription(name, !body.HasSetter); + XmlDocSummary = new XmlDocSummaryStatement([Description]); Modifiers = modifiers; Type = type; Name = name; @@ -54,7 +56,7 @@ private XmlDocProvider GetXmlDocs() return new XmlDocProvider() { - Summary = new XmlDocSummaryStatement(Description), + Summary = XmlDocSummary, }; } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs index 8a7728d1c8..a34044c276 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Statements; namespace Microsoft.Generator.CSharp.Providers { @@ -18,7 +19,10 @@ public abstract class TypeProvider public abstract string Name { get; } public virtual string Namespace => CodeModelPlugin.Instance.Configuration.Namespace; - public virtual FormattableString Description { get; } = FormattableStringHelpers.Empty; + protected virtual FormattableString Description { get; } = FormattableStringHelpers.Empty; + + private XmlDocProvider? _xmlDocs; + public XmlDocProvider XmlDocs => _xmlDocs ??= BuildXmlDocs(); internal virtual Type? SerializeAs => null; @@ -107,6 +111,13 @@ private TypeSignatureModifiers GetDeclarationModifiersInternal() protected virtual TypeProvider[] BuildNestedTypes() => Array.Empty(); + protected virtual XmlDocProvider BuildXmlDocs() + { + var docs = new XmlDocProvider(); + docs.Summary = new XmlDocSummaryStatement([Description]); + return docs; + } + public static string GetDefaultModelNamespace(string defaultNamespace) { if (CodeModelPlugin.Instance.Configuration.UseModelNamespace) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/XmlDocProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/XmlDocProvider.cs index 50b6aecdaf..2725a48e4a 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/XmlDocProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/XmlDocProvider.cs @@ -14,9 +14,13 @@ public XmlDocProvider() Exceptions = new List(); } + private static XmlDocProvider? _inheritDocs; + public static XmlDocProvider InheritDocs => _inheritDocs ??= new XmlDocProvider { Inherit = new XmlDocInheritStatement() }; + public XmlDocSummaryStatement? Summary { get; set; } public IList Params { get; } public XmlDocReturnsStatement? Returns { get; set; } public IList Exceptions { get; } + public XmlDocInheritStatement? Inherit { get; set; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/IfElseStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/IfElseStatement.cs index bd077d0b32..4c1cc85a78 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/IfElseStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/IfElseStatement.cs @@ -17,31 +17,15 @@ public IfElseStatement(IfStatement ifStatement, MethodBodyStatement? elseStateme } public IfElseStatement(ValueExpression condition, MethodBodyStatement ifStatement, MethodBodyStatement? elseStatement, bool inline = false, bool addBraces = true) - : this(new IfStatement(condition, inline, addBraces) { ifStatement }, elseStatement) {} + : this(new IfStatement(condition, inline, addBraces) { ifStatement }, elseStatement) { } internal override void Write(CodeWriter writer) { If.Write(writer); - if (Else is null) + if (Else is not null) { - return; - } - - if (If.Inline || !If.AddBraces) - { - using (writer.AmbientScope()) - { - writer.AppendRaw("else "); - if (!If.Inline) - { - writer.WriteLine(); - } - Else.Write(writer); - } - } - else - { - using (writer.Scope($"else")) + writer.WriteLine($"else"); + using (writer.Scope()) { Else.Write(writer); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchCaseStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchCaseStatement.cs index c1b098d9a4..c8ce2fd030 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchCaseStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchCaseStatement.cs @@ -12,20 +12,16 @@ public sealed class SwitchCaseStatement : MethodBodyStatement { public IReadOnlyList Matches { get; } public MethodBodyStatement Statement { get; } - public bool Inline { get; } - public bool AddScope { get; } - public SwitchCaseStatement(IReadOnlyList matches, MethodBodyStatement statement, bool inline = false, bool addScope = false) + public SwitchCaseStatement(IReadOnlyList matches, MethodBodyStatement statement) { Matches = matches; Statement = statement; - Inline = inline; - AddScope = addScope; } - public SwitchCaseStatement(ValueExpression match, MethodBodyStatement statement, bool inline = false, bool addScope = false) : this(new[] { match }, statement, inline, addScope) { } + public SwitchCaseStatement(ValueExpression match, MethodBodyStatement statement) : this([match], statement) { } - public static SwitchCaseStatement Default(MethodBodyStatement statement, bool inline = false, bool addScope = false) => new(Array.Empty(), statement, inline, addScope); + public static SwitchCaseStatement Default(MethodBodyStatement statement) => new(Array.Empty(), statement); internal override void Write(CodeWriter writer) { @@ -47,23 +43,8 @@ internal override void Write(CodeWriter writer) writer.AppendRaw("default"); } - writer.AppendRaw(": "); - if (!Inline) - { - writer.WriteLine(); - } - - if (AddScope) - { - using (writer.Scope()) - { - Statement.Write(writer); - } - } - else - { - Statement.Write(writer); - } + using var scope = writer.ScopeRaw(":", "", false); + Statement.Write(writer); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchStatement.cs index 17df9fdcc1..df6e19e735 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/SwitchStatement.cs @@ -35,12 +35,11 @@ internal override void Write(CodeWriter writer) writer.Append($"switch ("); MatchExpression.Write(writer); writer.WriteRawLine(")"); - writer.WriteRawLine("{"); + using var scope = writer.Scope(); foreach (var switchCase in Cases) { switchCase.Write(writer); } - writer.WriteRawLine("}"); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocInheritStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocInheritStatement.cs new file mode 100644 index 0000000000..b2bf6f6bce --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocInheritStatement.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Generator.CSharp.Statements +{ + public sealed class XmlDocInheritStatement : MethodBodyStatement + { + internal override void Write(CodeWriter writer) + { + writer.WriteLine($"/// "); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocStatement.cs index 053c34df64..de7171531d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocStatement.cs @@ -3,46 +3,103 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; namespace Microsoft.Generator.CSharp.Statements { public class XmlDocStatement : MethodBodyStatement { private const string SingleArgFormat = "{0}"; + private List _lines; public string StartTag { get; init; } public string EndTag { get; init; } - public IReadOnlyList Lines { get; init; } + public IReadOnlyList Lines => _lines; + public IReadOnlyList InnerStatements { get; } - public XmlDocStatement(string startTag, string endTag, IReadOnlyList lines) + public XmlDocStatement(string tagName, IEnumerable lines, params XmlDocStatement[] innerStatements) + : this($"<{tagName}>", $"", lines, innerStatements) + { + } + + public XmlDocStatement(string startTag, string endTag, IEnumerable lines, params XmlDocStatement[] innerStatements) { StartTag = startTag; EndTag = endTag; - Lines = lines; + _lines = EscapeLines(lines); + InnerStatements = innerStatements; + } + + private List EscapeLines(IEnumerable lines) + { + List escapedLines = new List(); + foreach (var line in lines) + { + escapedLines.Add(FormattableStringFactory.Create(EscapeLine(line.Format), EscapeArguments(line.GetArguments()))); + } + return escapedLines; + } + + private static object?[] EscapeArguments(object?[] objects) + { + if (objects is null) + return Array.Empty(); + + object?[] args = new object?[objects.Length]; + for (int i = 0; i < objects.Length; i++) + { + if (objects[i] is string str) + { + args[i] = EscapeLine(str); + } + else + { + args[i] = objects[i]; + } + } + return args; } internal override void Write(CodeWriter writer) { using var scope = new CodeWriter.XmlDocWritingScope(writer); + if (Lines.Count > 1 || InnerStatements.Count > 0) + { + WriteMultiLine(writer); + } + else + { + WriteSingleLine(writer); + } + } + + private void WriteSingleLine(CodeWriter writer) + { if (Lines.Count == 0 || IsEmptySingleLine(Lines)) { writer.WriteLine($"/// {StartTag}{EndTag}"); } - else if (Lines.Count == 1) + else { string periodOrEmpty = GetPeriodOrEmpty(Lines[0]); writer.WriteLine($"/// {StartTag} {Lines[0]}{periodOrEmpty} {EndTag}"); } - else + } + + private void WriteMultiLine(CodeWriter writer) + { + writer.WriteLine($"/// {StartTag}"); + foreach (var line in Lines) { - writer.WriteLine($"/// {StartTag}"); - foreach (var line in Lines) - { - writer.WriteLine($"/// {line}"); - } - writer.WriteLine($"/// {EndTag}"); + writer.WriteLine($"/// {line}"); + } + foreach (var inner in InnerStatements) + { + inner.Write(writer); } + writer.WriteLine($"/// {EndTag}"); } private string GetPeriodOrEmpty(FormattableString formattableString) @@ -79,5 +136,92 @@ private static bool IsEmptySingleLine(IReadOnlyList lines) var firstArg = lines[0].GetArgument(0); return firstArg is not null && firstArg.Equals(string.Empty); } + + private const string EscapedAmpersand = "&"; + private const string EscapedLessThan = "<"; + private const string EscapedGreaterThan = ">"; + private const string EscapedApostrophe = "'"; + private const string EscapedQuote = """; + public static string EscapeLine(string s) + { + if (string.IsNullOrEmpty(s)) + return s; + + var span = s.AsSpan(); + Dictionary replacements = new Dictionary(); + for (int i = 0; i < span.Length; i++) + { + switch (span[i]) + { + case '&': + if (IsAlreadyEscaped(ref span, i, out int escapeLength)) + { + i += escapeLength; + } + else + { + replacements.Add(i, EscapedAmpersand); + } + break; + case '<': + if (!SkipValidTag(ref span, ref i)) + { + replacements.Add(i, EscapedLessThan); + } + break; + case '>': + replacements.Add(i, EscapedGreaterThan); + break; + } + } + if (replacements.Count > 0) + { + StringBuilder sb = new StringBuilder(); + int lastStart = 0; + foreach (var kv in replacements) + { + sb.Append(span.Slice(lastStart, kv.Key - lastStart)); + sb.Append(kv.Value); + lastStart = kv.Key + 1; + } + sb.Append(span.Slice(lastStart)); + return sb.ToString(); + } + return s; + } + + private const string SeeCref = " span, ref int i) + { + var slice = span.Slice(i); + if (slice.StartsWith(SeeCref.AsSpan(), StringComparison.Ordinal)) + { + i += slice.IndexOf('>'); + return true; + } + return false; + } + + private static bool IsAlreadyEscaped(ref ReadOnlySpan span, int i, out int escapeLength) + { + return IsEscapedMatch(ref span, i, EscapedAmpersand, out escapeLength) || + IsEscapedMatch(ref span, i, EscapedLessThan, out escapeLength) || + IsEscapedMatch(ref span, i, EscapedGreaterThan, out escapeLength) || + IsEscapedMatch(ref span, i, EscapedApostrophe, out escapeLength) || + IsEscapedMatch(ref span, i, EscapedQuote, out escapeLength); + } + + private static bool IsEscapedMatch(ref ReadOnlySpan span, int i, string escapedChar, out int escapeLength) + { + escapeLength = 0; + if (span.Length < i + escapedChar.Length) + return false; + + var slice = span.Slice(i, escapedChar.Length); + var isMatch = slice.Equals(escapedChar.AsSpan(), StringComparison.Ordinal); + if (isMatch) + escapeLength = slice.Length; + return isMatch; + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocSummaryStatement.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocSummaryStatement.cs index ddc64d5f24..ac4f4e9212 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocSummaryStatement.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Statements/XmlDocSummaryStatement.cs @@ -8,8 +8,8 @@ namespace Microsoft.Generator.CSharp.Statements { public sealed class XmlDocSummaryStatement : XmlDocStatement { - public XmlDocSummaryStatement(IReadOnlyList lines) - : base("", "", lines) + public XmlDocSummaryStatement(IReadOnlyList lines, params XmlDocStatement[] innerStatements) + : base("", "", lines, innerStatements: innerStatements) { } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ObjectSnippet.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ObjectSnippet.cs new file mode 100644 index 0000000000..6c40363a8a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypedSnippets/ObjectSnippet.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Snippets; + +namespace Microsoft.Generator.CSharp.TypedSnippets +{ + public sealed record ObjectSnippet(ValueExpression Untyped) : TypedSnippet(Untyped) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Utilities/FormattableStringHelpers.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Utilities/FormattableStringHelpers.cs index 77efa2737e..241fc18c0c 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Utilities/FormattableStringHelpers.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Utilities/FormattableStringHelpers.cs @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Security.AccessControl; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; -using System.Diagnostics.CodeAnalysis; using Microsoft.Generator.CSharp.Providers; namespace Microsoft.Generator.CSharp diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/CodeWriter.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/CodeWriter.cs index 4800b7642b..5ffbe9bb74 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/CodeWriter.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/CodeWriter.cs @@ -230,11 +230,17 @@ public void WriteMethod(MethodProvider method) } } - private void WriteXmlDocs(XmlDocProvider? docs) + internal void WriteXmlDocs(XmlDocProvider? docs) { if (docs is null) return; + if (docs.Inherit is not null) + { + docs.Inherit.Write(this); + return; //skip all other docs + } + if (docs.Summary is not null) { docs.Summary.Write(this); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/TypeProviderWriter.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/TypeProviderWriter.cs index 13f04e1905..4b9f7e5639 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/TypeProviderWriter.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Writers/TypeProviderWriter.cs @@ -32,6 +32,10 @@ private CodeFile Write(CodeWriter writer) private void WriteType(CodeWriter writer) { + if (_provider.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)) + { + writer.WriteXmlDocs(_provider.XmlDocs); + } writer.WriteTypeModifiers(_provider.DeclarationModifiers); // class, struct, enum and interface is written as modifiers in this part writer.Append($"{_provider.Type:D}") .AppendRawIf(" : ", _provider.Inherits != null || _provider.Implements.Any()) @@ -104,6 +108,7 @@ private void WriteEnumContent(CodeWriter writer) { for (int i = 0; i < _provider.Fields.Count; i++) { + writer.WriteXmlDocs(_provider.Fields[i].XmlDocs); writer.Append($"{_provider.Fields[i].Name}"); if (_provider.Fields[i].InitializationValue != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpMethodCollectionTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpMethodCollectionTests.cs index df1ffec017..e4d12ee87d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpMethodCollectionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpMethodCollectionTests.cs @@ -50,7 +50,7 @@ public void Teardown() public void TestDefaultCSharpMethodCollection(InputOperation inputOperation) { - var methodCollection = CSharpMethodCollection.DefaultCSharpMethodCollection(inputOperation); + var methodCollection = CSharpMethodCollection.DefaultCSharpMethodCollection(inputOperation, new MockTypeProvider()); Assert.IsNotNull(methodCollection); Assert.AreEqual(1, methodCollection?.Count); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CodeWriterExtensionTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CodeWriterExtensionTests.cs index 2252c1b26a..6b1aa4b14c 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CodeWriterExtensionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CodeWriterExtensionTests.cs @@ -102,36 +102,5 @@ public void TestWriteValueExpression_DefaultCollectionInitializerExpression(stri Assert.AreEqual(sb.ToString(), codeWriter.ToString()); } - - // Construct a mock method with a body. The body can be either a list of statements or a single expression - // depending on the value of the useExpressionAsBody parameter. - private static MethodProvider ConstructMockMethod() - { - // create method signature - var methodName = "TestMethod"; - FormattableString summary = $"Sample summary for {methodName}"; - FormattableString description = $"Sample description for {methodName}"; - FormattableString returnDescription = $"Sample return description for {methodName}"; - var methodSignatureModifiers = MethodSignatureModifiers.Public; - var returnType = new CSharpType(typeof(BinaryData)); - var parameters = new List() - { - new ParameterProvider("param1", $"Sample description for param1", new CSharpType(typeof(string))) { Validation = ParameterValidationType.AssertNotNull } - }; - - var responseVar = new VariableReferenceSnippet(returnType, "responseParamName"); - var responseRef = Snippet.Var(responseVar, BinaryDataSnippet.FromBytes(Snippet.Literal("sample response"))); - var resultStatements = new List() - { - responseRef, - new KeywordStatement("return", responseVar) - }; - - var method = new MethodProvider( - new MethodSignature(methodName, summary, description, methodSignatureModifiers, returnType, returnDescription, parameters), - resultStatements); - - return method; - } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj index 48aa3d8ef1..07534ee448 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Microsoft.Generator.CSharp.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeFactory.cs index fe74d8e11b..ffca911560 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeFactory.cs @@ -10,7 +10,7 @@ namespace Microsoft.Generator.CSharp.Tests { internal class MockTypeFactory : TypeFactory { - public override CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation) + public override CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation, TypeProvider enclosingType) { throw new NotImplementedException(); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeProvider.cs new file mode 100644 index 0000000000..648b4c66de --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Mocks/MockTypeProvider.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Generator.CSharp.Providers; + +namespace Microsoft.Generator.CSharp.Tests +{ + internal class MockTypeProvider : TypeProvider + { + public override string Name => throw new NotImplementedException(); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/Types/EnumTypeProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumTypeProviderTests.cs similarity index 99% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/Types/EnumTypeProviderTests.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumTypeProviderTests.cs index ebc6af5175..ef12a7f0fc 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/Types/EnumTypeProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumTypeProviderTests.cs @@ -12,7 +12,7 @@ using Moq; using NUnit.Framework; -namespace Microsoft.Generator.CSharp.Tests +namespace Microsoft.Generator.CSharp.Tests.Providers { public class EnumTypeProviderTests { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/Types/ModelTypeProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/ModelTypeProviderTests.cs similarity index 99% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/Types/ModelTypeProviderTests.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/ModelTypeProviderTests.cs index 1c7082f464..466412d11f 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/Types/ModelTypeProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/ModelTypeProviderTests.cs @@ -11,7 +11,7 @@ using Moq; using NUnit.Framework; -namespace Microsoft.Generator.CSharp.Tests +namespace Microsoft.Generator.CSharp.Tests.Providers { public class ModelTypeProviderTests { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/PropertyDescriptionTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/PropertyDescriptionTests.cs similarity index 78% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/PropertyDescriptionTests.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/PropertyDescriptionTests.cs index 664cfd0356..aaef9ad6d9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Models/PropertyDescriptionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/PropertyDescriptionTests.cs @@ -7,7 +7,7 @@ using Microsoft.Generator.CSharp.Statements; using NUnit.Framework; -namespace Microsoft.Generator.CSharp.Tests +namespace Microsoft.Generator.CSharp.Tests.Providers { internal class PropertyDescriptionTests { @@ -15,7 +15,10 @@ internal class PropertyDescriptionTests [TestCaseSource(nameof(BuildPropertyDescriptionTestCases))] public void BuildPropertyDescription(InputModelProperty inputModelProperty, CSharpType type) { - IReadOnlyList propertyDescription = PropertyDescriptionBuilder.BuildPropertyDescription(inputModelProperty, type, SerializationFormat.Default, false); + var propertySummaryStatement = PropertyDescriptionBuilder.BuildPropertyDescription(inputModelProperty, type, SerializationFormat.Default, PropertyDescriptionBuilder.CreateDefaultPropertyDescription(inputModelProperty.Name, false)); + CodeWriter codeWriter = new CodeWriter(); + propertySummaryStatement.Write(codeWriter); + string propertyDescription = codeWriter.ToString(false); var propertyDescriptionString = string.Join(Environment.NewLine, propertyDescription); Assert.IsNotNull(propertyDescription); Assert.IsNotEmpty(propertyDescriptionString); @@ -43,24 +46,24 @@ public void TestGetUnionTypesDescriptions() CSharpType.FromLiteral(new CSharpType(typeof(DateTimeOffset), false), dateTime) }; - IReadOnlyList descriptions = PropertyDescriptionBuilder.GetUnionTypesDescriptions(unionItems); + IReadOnlyList descriptions = PropertyDescriptionBuilder.GetUnionTypesDescriptions(unionItems); Assert.AreEqual(7, descriptions.Count); using var codeWriter = new CodeWriter(); - var xmlDoc = new XmlDocStatement($"", $"", descriptions); + var xmlDoc = new XmlDocStatement("test", [], innerStatements: [.. descriptions]); xmlDoc.Write(codeWriter); var actual = codeWriter.ToString(false); var expected = string.Join("\n", "/// ", - "/// ", - "/// ", - "/// where TKey is of type , where TValue is of type ", - "/// 21", - "/// \"test\"", - "/// True", - $"/// {dateTime}", + "/// . ", + "/// . ", + "/// where TKey is of type , where TValue is of type . ", + "/// 21. ", + "/// \"test\". ", + "/// True. ", + $"/// {dateTime}. ", "/// ") + "\n"; Assert.AreEqual(expected, actual); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/StatementTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs similarity index 99% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/StatementTests.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs index 5863a2c8f1..16b74e4936 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/StatementTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/StatementTests.cs @@ -9,7 +9,7 @@ using Microsoft.Generator.CSharp.Statements; using NUnit.Framework; -namespace Microsoft.Generator.CSharp.Tests +namespace Microsoft.Generator.CSharp.Tests.Statements { public class StatementTests { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocParamStatementTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocParamStatementTests.cs new file mode 100644 index 0000000000..5e06927f3b --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocParamStatementTests.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Generator.CSharp.Statements; +using NUnit.Framework; + +namespace Microsoft.Generator.CSharp.Tests.Statements +{ + public class XmlDocParamStatementTests + { + [Test] + public void InvalidDocComment() + { + var statement = new XmlDocParamStatement("foo", $"<|endoftext|>"); + var writer = new CodeWriter(); + statement.Write(writer); + Assert.AreEqual("/// <|endoftext|>. \n", writer.ToString(false)); + } + + [Test] + public void InvalidDocCommentWithExtra() + { + var statement = new XmlDocParamStatement("foo", $"description with xml <|endoftext|>"); + var writer = new CodeWriter(); + statement.Write(writer); + Assert.AreEqual("/// description with xml <|endoftext|>. \n", writer.ToString(false)); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocStatementTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocStatementTests.cs new file mode 100644 index 0000000000..1e8afc5ae5 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Statements/XmlDocStatementTests.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Generator.CSharp.Statements; +using NUnit.Framework; + +namespace Microsoft.Generator.CSharp.Tests.Statements +{ + public class XmlDocStatementTests + { + [Test] + public void InvalidDocComment() + { + var statement = new XmlDocStatement("", "", [$"<|endoftext|>"]); + var writer = new CodeWriter(); + statement.Write(writer); + Assert.AreEqual("/// <|endoftext|>. \n", writer.ToString(false)); + } + + [Test] + public void InvalidDocCommentWithCref() + { + var statement = new XmlDocStatement("", "", [$"{typeof(int):C} <|endoftext|>"]); + var writer = new CodeWriter(); + statement.Write(writer); + Assert.AreEqual("/// <|endoftext|>. \n", writer.ToString(false)); + } + + [Test] + public void InvalidDocCommentWithCrefMethod() + { + var statement = new XmlDocStatement("", "", [$" <|endoftext|>"]); + var writer = new CodeWriter(); + statement.Write(writer); + Assert.AreEqual("/// <|endoftext|>. \n", writer.ToString(false)); + } + + [Test] + public void InvalidDocInFormatArg() + { + var invalid = "<|endoftext|>"; + var statement = new XmlDocStatement("", "", [$"{invalid}"]); + var writer = new CodeWriter(); + statement.Write(writer); + Assert.AreEqual("/// <|endoftext|>. \n", writer.ToString(false)); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/TypeFactoryTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/TypeFactoryTests.cs index 8e915d67e9..e0e105254c 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/TypeFactoryTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/TypeFactoryTests.cs @@ -84,7 +84,7 @@ public override ParameterProvider CreateCSharpParam(InputParameter parameter) throw new NotImplementedException(); } - public override CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation) + public override CSharpMethodCollection? CreateCSharpMethodCollection(InputOperation operation, TypeProvider enclosingType) { throw new NotImplementedException(); } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/TestProjects.Local.Tests.csproj b/packages/http-client-csharp/generator/TestProjects/Local/TestProjects.Local.Tests.csproj index 0cae1828ec..06a165ca6d 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/TestProjects.Local.Tests.csproj +++ b/packages/http-client-csharp/generator/TestProjects/Local/TestProjects.Local.Tests.csproj @@ -5,6 +5,7 @@ false enable + diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Argument.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Argument.cs index 212a951692..62130911de 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Argument.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Argument.cs @@ -10,8 +10,6 @@ namespace UnbrandedTypeSpec { internal static partial class Argument { - /// The value. - /// The name. public static void AssertNotNull(T value, string name) { if (value is null) @@ -20,8 +18,6 @@ public static void AssertNotNull(T value, string name) } } - /// The value. - /// The name. public static void AssertNotNull(T? value, string name) where T : struct { @@ -31,8 +27,6 @@ public static void AssertNotNull(T? value, string name) } } - /// The value. - /// The name. public static void AssertNotNullOrEmpty(IEnumerable value, string name) { if (value is null) @@ -54,8 +48,6 @@ public static void AssertNotNullOrEmpty(IEnumerable value, string name) } } - /// The value. - /// The name. public static void AssertNotNullOrEmpty(string value, string name) { if (value is null) @@ -68,8 +60,6 @@ public static void AssertNotNullOrEmpty(string value, string name) } } - /// The value. - /// The name. public static void AssertNotNullOrWhiteSpace(string value, string name) { if (value is null) @@ -82,8 +72,6 @@ public static void AssertNotNullOrWhiteSpace(string value, string name) } } - /// The value. - /// The name. public static void AssertNotDefault(ref T value, string name) where T : struct, IEquatable { @@ -93,10 +81,6 @@ public static void AssertNotDefault(ref T value, string name) } } - /// The value. - /// The minimum value. - /// The maximum value. - /// The name. public static void AssertInRange(T value, T minimum, T maximum, string name) where T : notnull, IComparable { @@ -110,9 +94,6 @@ public static void AssertInRange(T value, T minimum, T maximum, string name) } } - /// The enum value. - /// The value. - /// The name. public static void AssertEnumDefined(Type enumType, object value, string name) { if (!Enum.IsDefined(enumType, value)) @@ -121,8 +102,6 @@ public static void AssertEnumDefined(Type enumType, object value, string name) } } - /// The value. - /// The name. public static T CheckNotNull(T value, string name) where T : class { @@ -130,17 +109,12 @@ public static T CheckNotNull(T value, string name) return value; } - /// The value. - /// The name. public static string CheckNotNullOrEmpty(string value, string name) { AssertNotNullOrEmpty(value, name); return value; } - /// The value. - /// The name. - /// The message. public static void AssertNull(T value, string name, string message = null) { if (value != null) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingDictionary.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingDictionary.cs index 44115fb65e..d1179e4029 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingDictionary.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingDictionary.cs @@ -17,7 +17,6 @@ public ChangeTrackingDictionary() { } - /// The inner dictionary. public ChangeTrackingDictionary(IDictionary dictionary) { if (dictionary == null) @@ -27,7 +26,6 @@ public ChangeTrackingDictionary(IDictionary dictionary) _innerDictionary = new Dictionary(dictionary); } - /// The inner dictionary. public ChangeTrackingDictionary(IReadOnlyDictionary dictionary) { if (dictionary == null) @@ -97,7 +95,6 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - /// The item to add. public void Add(KeyValuePair item) { EnsureDictionary().Add(item); @@ -108,7 +105,6 @@ public void Clear() EnsureDictionary().Clear(); } - /// The item to search for. public bool Contains(KeyValuePair item) { if (IsUndefined) @@ -118,8 +114,6 @@ public bool Contains(KeyValuePair item) return EnsureDictionary().Contains(item); } - /// The array to copy. - /// The index. public void CopyTo(KeyValuePair[] array, int index) { if (IsUndefined) @@ -129,7 +123,6 @@ public void CopyTo(KeyValuePair[] array, int index) EnsureDictionary().CopyTo(array, index); } - /// The item to remove. public bool Remove(KeyValuePair item) { if (IsUndefined) @@ -139,14 +132,11 @@ public bool Remove(KeyValuePair item) return EnsureDictionary().Remove(item); } - /// The key. - /// The value to add. public void Add(TKey key, TValue value) { EnsureDictionary().Add(key, value); } - /// The key to search for. public bool ContainsKey(TKey key) { if (IsUndefined) @@ -156,7 +146,6 @@ public bool ContainsKey(TKey key) return EnsureDictionary().ContainsKey(key); } - /// The key. public bool Remove(TKey key) { if (IsUndefined) @@ -166,8 +155,6 @@ public bool Remove(TKey key) return EnsureDictionary().Remove(key); } - /// The key to search for. - /// The value. public bool TryGetValue(TKey key, out TValue value) { if (IsUndefined) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingList.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingList.cs index 9e2ba9951e..6d53618e09 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingList.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ChangeTrackingList.cs @@ -17,7 +17,6 @@ public ChangeTrackingList() { } - /// The inner list. public ChangeTrackingList(IList innerList) { if (innerList != null) @@ -26,7 +25,6 @@ public ChangeTrackingList(IList innerList) } } - /// The inner list. public ChangeTrackingList(IReadOnlyList innerList) { if (innerList != null) @@ -88,7 +86,6 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - /// The item to add. public void Add(T item) { EnsureList().Add(item); @@ -99,7 +96,6 @@ public void Clear() EnsureList().Clear(); } - /// The item. public bool Contains(T item) { if (IsUndefined) @@ -109,8 +105,6 @@ public bool Contains(T item) return EnsureList().Contains(item); } - /// The array to copy to. - /// The array index. public void CopyTo(T[] array, int arrayIndex) { if (IsUndefined) @@ -120,7 +114,6 @@ public void CopyTo(T[] array, int arrayIndex) EnsureList().CopyTo(array, arrayIndex); } - /// The item. public bool Remove(T item) { if (IsUndefined) @@ -130,7 +123,6 @@ public bool Remove(T item) return EnsureList().Remove(item); } - /// The item. public int IndexOf(T item) { if (IsUndefined) @@ -140,14 +132,11 @@ public int IndexOf(T item) return EnsureList().IndexOf(item); } - /// The index. - /// The item. public void Insert(int index, T item) { EnsureList().Insert(index, item); } - /// The index. public void RemoveAt(int index) { if (IsUndefined) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs new file mode 100644 index 0000000000..6940524147 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/ModelSerializationExtensions.cs @@ -0,0 +1,251 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; + +namespace UnbrandedTypeSpec +{ + internal static partial class ModelSerializationExtensions + { + internal static readonly ModelReaderWriterOptions WireOptions = new ModelReaderWriterOptions("W"); + + public static object GetObject(this JsonElement element) + { + switch (element.ValueKind) + { + case JsonValueKind.String: + return element.GetString(); + case JsonValueKind.Number: + if (element.TryGetInt32(out int intValue)) + { + return intValue; + } + if (element.TryGetInt64(out long longValue)) + { + return longValue; + } + return element.GetDouble(); + case JsonValueKind.True: + return true; + case JsonValueKind.False: + return false; + case JsonValueKind.Undefined: + case JsonValueKind.Null: + return null; + case JsonValueKind.Object: + var dictionary = new Dictionary(); + foreach (var jsonProperty in element.EnumerateObject()) + { + dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject()); + } + return dictionary; + case JsonValueKind.Array: + var list = new List(); + foreach (var item in element.EnumerateArray()) + { + list.Add(item.GetObject()); + } + return list.ToArray(); + default: + throw new NotSupportedException($"Not supported value kind {element.ValueKind}"); + } + } + + public static byte[] GetBytesFromBase64(this JsonElement element, string format) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + + return format switch + { + "U" => TypeFormatters.FromBase64UrlString(element.GetRequiredString()), + "D" => element.GetBytesFromBase64(), + _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)) + }; + } + + public static DateTimeOffset GetDateTimeOffset(this JsonElement element, string format) => format switch + { + "U" when element.ValueKind == JsonValueKind.Number => DateTimeOffset.FromUnixTimeSeconds(element.GetInt64()), + _ => TypeFormatters.ParseDateTimeOffset(element.GetString(), format) + }; + + public static TimeSpan GetTimeSpan(this JsonElement element, string format) => TypeFormatters.ParseTimeSpan(element.GetString(), format); + + public static char GetChar(this JsonElement element) + { + if (element.ValueKind == JsonValueKind.String) + { + var text = element.GetString(); + if (text == null || text.Length != 1) + { + throw new NotSupportedException($"Cannot convert \"{text}\" to a char"); + } + return text[0]; + } + else + { + throw new NotSupportedException($"Cannot convert {element.ValueKind} to a char"); + } + } + + [Conditional("DEBUG")] + public static void ThrowNonNullablePropertyIsNull(this JsonProperty @property) + { + throw new JsonException($"A property '{@property.Name}' defined as non-nullable but received as null from the service. This exception only happens in DEBUG builds of the library and would be ignored in the release build"); + } + + public static string GetRequiredString(this JsonElement element) + { + var value = element.GetString(); + if (value == null) + { + throw new InvalidOperationException($"The requested operation requires an element of type 'String', but the target element has type '{element.ValueKind}'."); + } + return value; + } + + public static void WriteStringValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, DateTime value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, TimeSpan value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, char value) + { + writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture)); + } + + public static void WriteBase64StringValue(this Utf8JsonWriter writer, byte[] value, string format) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + switch (format) + { + case "U": + writer.WriteStringValue(TypeFormatters.ToBase64UrlString(value)); + break; + case "D": + writer.WriteBase64StringValue(value); + break; + default: + throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)); + } + } + + public static void WriteNumberValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) + { + if (format != "U") + { + throw new ArgumentOutOfRangeException(nameof(format), "Only 'U' format is supported when writing a DateTimeOffset as a Number."); + } + writer.WriteNumberValue(value.ToUnixTimeSeconds()); + } + + public static void WriteObjectValue(this Utf8JsonWriter writer, T value, ModelReaderWriterOptions options = null) + { + switch (value) + { + case null: + writer.WriteNullValue(); + break; + case IJsonModel jsonModel: + jsonModel.Write(writer, options ?? WireOptions); + break; + case byte[] bytes: + writer.WriteBase64StringValue(bytes); + break; + case BinaryData bytes0: + writer.WriteBase64StringValue(bytes0); + break; + case JsonElement json: + json.WriteTo(writer); + break; + case int i: + writer.WriteNumberValue(i); + break; + case decimal d: + writer.WriteNumberValue(d); + break; + case double d0: + if (double.IsNaN(d0)) + { + writer.WriteStringValue("NaN"); + } + else + { + writer.WriteNumberValue(d0); + } + break; + case float f: + writer.WriteNumberValue(f); + break; + case long l: + writer.WriteNumberValue(l); + break; + case string s: + writer.WriteStringValue(s); + break; + case bool b: + writer.WriteBooleanValue(b); + break; + case Guid g: + writer.WriteStringValue(g); + break; + case DateTimeOffset dateTimeOffset: + writer.WriteStringValue(dateTimeOffset, "O"); + break; + case DateTime dateTime: + writer.WriteStringValue(dateTime, "O"); + break; + case IEnumerable> enumerable: + writer.WriteStartObject(); + foreach (var pair in enumerable) + { + writer.WritePropertyName(pair.Key); + writer.WriteObjectValue(pair.Value, options); + } + writer.WriteEndObject(); + break; + case IEnumerable objectEnumerable: + writer.WriteStartArray(); + foreach (var item in objectEnumerable) + { + writer.WriteObjectValue(item, options); + } + writer.WriteEndArray(); + break; + case TimeSpan timeSpan: + writer.WriteStringValue(timeSpan, "P"); + break; + default: + throw new NotSupportedException($"Not supported type {value.GetType()}"); + } + } + + public static void WriteObjectValue(this Utf8JsonWriter writer, object value, ModelReaderWriterOptions options = null) + { + writer.WriteObjectValue(value, options); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Optional.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Optional.cs index 7a247f4bd1..62c1d8136f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Optional.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/Optional.cs @@ -9,44 +9,37 @@ namespace UnbrandedTypeSpec { internal static partial class Optional { - /// The collection. public static bool IsCollectionDefined(IEnumerable collection) { return !(collection is ChangeTrackingList changeTrackingList && changeTrackingList.IsUndefined); } - /// The collection. public static bool IsCollectionDefined(IDictionary collection) { return !(collection is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined); } - /// The value. public static bool IsCollectionDefined(IReadOnlyDictionary collection) { return !(collection is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined); } - /// The value. public static bool IsDefined(T? value) where T : struct { return value.HasValue; } - /// The value. public static bool IsDefined(object value) { return value != null; } - /// The value. - public static bool IsDefined(System.Text.Json.JsonElement value) + public static bool IsDefined(JsonElement value) { - return value.ValueKind != System.Text.Json.JsonValueKind.Undefined; + return value.ValueKind != JsonValueKind.Undefined; } - /// The value. public static bool IsDefined(string value) { return value != null; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/TypeFormatters.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/TypeFormatters.cs new file mode 100644 index 0000000000..9673e1dade --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Internal/TypeFormatters.cs @@ -0,0 +1,150 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; + +namespace UnbrandedTypeSpec +{ + internal static partial class TypeFormatters + { + private const string RoundtripZFormat = "yyyy-MM-ddTHH:mm:ss.fffffffZ"; + public const string DefaultNumberFormat = "G"; + + public static string ToString(bool value) => value ? "true" : "false"; + + public static string ToString(DateTime value, string format) => value.Kind switch + { + DateTimeKind.Utc => ToString((DateTimeOffset)value, format), + _ => throw new NotSupportedException($"DateTime {value} has a Kind of {value.Kind}. Generated clients require it to be UTC. You can call DateTime.SpecifyKind to change Kind property value to DateTimeKind.Utc.") + }; + + public static string ToString(DateTimeOffset value, string format) => format switch + { + "D" => value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), + "U" => value.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture), + "O" => value.ToUniversalTime().ToString(RoundtripZFormat, CultureInfo.InvariantCulture), + "o" => value.ToUniversalTime().ToString(RoundtripZFormat, CultureInfo.InvariantCulture), + "R" => value.ToString("r", CultureInfo.InvariantCulture), + _ => value.ToString(format, CultureInfo.InvariantCulture) + }; + + public static string ToString(TimeSpan value, string format) => format switch + { + "P" => System.Xml.XmlConvert.ToString(value), + _ => value.ToString(format, CultureInfo.InvariantCulture) + }; + + public static string ToString(byte[] value, string format) => format switch + { + "U" => ToBase64UrlString(value), + "D" => Convert.ToBase64String(value), + _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)) + }; + + public static string ToBase64UrlString(byte[] value) + { + int numWholeOrPartialInputBlocks = checked (value.Length + 2) / 3; + int size = checked (numWholeOrPartialInputBlocks * 4); + char[] output = new char[size]; + + int numBase64Chars = Convert.ToBase64CharArray(value, 0, value.Length, output, 0); + + int i = 0; + for (; i < numBase64Chars; i++) + { + char ch = output[i]; + if (ch == '+') + { + output[i] = '-'; + } + else + { + if (ch == '/') + { + output[i] = '_'; + } + else + { + if (ch == '=') + { + break; + } + } + } + } + + return new string(output, 0, i); + } + + public static byte[] FromBase64UrlString(string value) + { + int paddingCharsToAdd = (value.Length % 4) switch + { + 0 => 0, + 2 => 2, + 3 => 1, + _ => throw new InvalidOperationException("Malformed input") + }; + char[] output = new char[(value.Length + paddingCharsToAdd)]; + int i = 0; + for (; i < value.Length; i++) + { + char ch = value[i]; + if (ch == '-') + { + output[i] = '+'; + } + else + { + if (ch == '_') + { + output[i] = '/'; + } + else + { + output[i] = ch; + } + } + } + + for (; i < output.Length; i++) + { + output[i] = '='; + } + + return Convert.FromBase64CharArray(output, 0, output.Length); + } + + public static DateTimeOffset ParseDateTimeOffset(string value, string format) => format switch + { + "U" => DateTimeOffset.FromUnixTimeSeconds(long.Parse(value, CultureInfo.InvariantCulture)), + _ => DateTimeOffset.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) + }; + + public static TimeSpan ParseTimeSpan(string value, string format) => format switch + { + "P" => System.Xml.XmlConvert.ToTimeSpan(value), + _ => TimeSpan.ParseExact(value, format, CultureInfo.InvariantCulture) + }; + + public static string ConvertToString(object value, string format = null) => value switch + { + null => "null", + string s => s, + bool b => ToString(b), + int or float or double or long or decimal => ((IFormattable)value).ToString(DefaultNumberFormat, CultureInfo.InvariantCulture), + byte[] b0 when format != null => ToString(b0, format), + IEnumerable s0 => string.Join(",", s0), + DateTimeOffset dateTime when format != null => ToString(dateTime, format), + TimeSpan timeSpan when format != null => ToString(timeSpan, format), + TimeSpan timeSpan0 => System.Xml.XmlConvert.ToString(timeSpan0), + Guid guid => guid.ToString(), + BinaryData binaryData => ConvertToString(binaryData.ToArray(), format), + _ => value.ToString() + }; + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs index 088bac8817..a2834b06ed 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// Float based extensible enum. public readonly partial struct FloatExtensibleEnum : IEquatable { private readonly float _value; @@ -52,8 +53,10 @@ public FloatExtensibleEnum(float value) /// The instance to compare. public bool Equals(FloatExtensibleEnum other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal float ToSerialSingle() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs index 8f4fbb58c1..f84dcb4ccb 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// float fixed enum. public readonly partial struct FloatExtensibleEnumWithIntValue : IEquatable { private readonly float _value; @@ -52,8 +53,10 @@ public FloatExtensibleEnumWithIntValue(float value) /// The instance to compare. public bool Equals(FloatExtensibleEnumWithIntValue other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal float ToSerialSingle() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnum.cs index 6411a99c04..eb665d9cde 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnum.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnum.cs @@ -4,10 +4,14 @@ namespace UnbrandedTypeSpec.Models { + /// float fixed enum. public enum FloatFixedEnum { + /// OneDotOne. OneDotOne, + /// TwoDotTwo. TwoDotTwo, + /// FourDotFour. FourDotFour } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumExtensions.cs index e5809cd7e0..950c2a31de 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumExtensions.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumExtensions.cs @@ -8,7 +8,6 @@ namespace UnbrandedTypeSpec.Models { internal static partial class FloatFixedEnumExtensions { - /// The value to serialize. public static float ToSerialSingle(this FloatFixedEnum value) => value switch { FloatFixedEnum.OneDotOne => 1.1F, @@ -17,7 +16,6 @@ internal static partial class FloatFixedEnumExtensions _ => throw new ArgumentOutOfRangeException(nameof(value), value, "Unknown FloatFixedEnum value.") }; - /// The value to deserialize. public static FloatFixedEnum ToFloatFixedEnum(this float value) { if (value == 1.1F) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValue.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValue.cs index 7b00b4499f..c436bf279f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValue.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValue.cs @@ -4,10 +4,14 @@ namespace UnbrandedTypeSpec.Models { + /// float fixed enum. public enum FloatFixedEnumWithIntValue { + /// One. One = 1, + /// Two. Two = 2, + /// Four. Four = 4 } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValueExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValueExtensions.cs index f182b74821..9c2c355292 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValueExtensions.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValueExtensions.cs @@ -8,7 +8,6 @@ namespace UnbrandedTypeSpec.Models { internal static partial class FloatFixedEnumWithIntValueExtensions { - /// The value to deserialize. public static FloatFixedEnumWithIntValue ToFloatFixedEnumWithIntValue(this int value) { if (value == 1) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.Serialization.cs index 1e80e75d8e..ec8b9758bb 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.Serialization.cs @@ -9,51 +9,40 @@ namespace UnbrandedTypeSpec.Models { - public partial class Friend : System.ClientModel.Primitives.IJsonModel + /// + public partial class Friend : IJsonModel { - private IDictionary _serializedAdditionalRawData; + private IDictionary _serializedAdditionalRawData; - /// Initializes a new instance of . - /// name of the NotFriend. - /// Keeps track of any properties unknown to the library. - internal Friend(string name, IDictionary serializedAdditionalRawData) + internal Friend(string name, IDictionary serializedAdditionalRawData) { Name = name; _serializedAdditionalRawData = serializedAdditionalRawData; } - /// Initializes a new instance of for deserialization. internal Friend() { } - /// The JSON writer. - /// The client options for reading and writing models. - void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { } - /// The JSON reader. - /// The client options for reading and writing models. - Friend System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) + Friend IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { return new Friend(); } - /// The client options for reading and writing models. - System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) { - return new System.BinaryData("IPersistableModel"); + return new BinaryData("IPersistableModel"); } - /// The data to parse. - /// The client options for reading and writing models. - Friend System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) + Friend IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { return new Friend(); } - /// The client options for reading and writing models. - string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J"; + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.cs index f13f97e7da..b91f6bc8af 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Friend.cs @@ -7,6 +7,7 @@ namespace UnbrandedTypeSpec.Models { + /// this is not a friendly model but with a friendly name. public partial class Friend { /// Initializes a new instance of . diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs index 7c8b456129..33b8096b0a 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// Int based extensible enum. public readonly partial struct IntExtensibleEnum : IEquatable { private readonly int _value; @@ -52,8 +53,10 @@ public IntExtensibleEnum(int value) /// The instance to compare. public bool Equals(IntExtensibleEnum other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal int ToSerialInt32() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnum.cs index 7468e93245..e46586149e 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnum.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnum.cs @@ -4,10 +4,14 @@ namespace UnbrandedTypeSpec.Models { + /// int fixed enum. public enum IntFixedEnum { + /// One. One = 1, + /// Two. Two = 2, + /// Four. Four = 4 } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnumExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnumExtensions.cs index f94052f470..54fa602625 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnumExtensions.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnumExtensions.cs @@ -8,7 +8,6 @@ namespace UnbrandedTypeSpec.Models { internal static partial class IntFixedEnumExtensions { - /// The value to deserialize. public static IntFixedEnum ToIntFixedEnum(this int value) { if (value == 1) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.Serialization.cs index e0abfbe4c3..2d109c0740 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.Serialization.cs @@ -9,16 +9,12 @@ namespace UnbrandedTypeSpec.Models { - public partial class ModelWithRequiredNullableProperties : System.ClientModel.Primitives.IJsonModel + /// + public partial class ModelWithRequiredNullableProperties : IJsonModel { - private IDictionary _serializedAdditionalRawData; - - /// Initializes a new instance of . - /// required nullable primitive type. - /// required nullable extensible enum type. - /// required nullable fixed enum type. - /// Keeps track of any properties unknown to the library. - internal ModelWithRequiredNullableProperties(int? requiredNullablePrimitive, StringExtensibleEnum? requiredExtensibleEnum, StringFixedEnum? requiredFixedEnum, IDictionary serializedAdditionalRawData) + private IDictionary _serializedAdditionalRawData; + + internal ModelWithRequiredNullableProperties(int? requiredNullablePrimitive, StringExtensibleEnum? requiredExtensibleEnum, StringFixedEnum? requiredFixedEnum, IDictionary serializedAdditionalRawData) { RequiredNullablePrimitive = requiredNullablePrimitive; RequiredExtensibleEnum = requiredExtensibleEnum; @@ -26,38 +22,29 @@ internal ModelWithRequiredNullableProperties(int? requiredNullablePrimitive, Str _serializedAdditionalRawData = serializedAdditionalRawData; } - /// Initializes a new instance of for deserialization. internal ModelWithRequiredNullableProperties() { } - /// The JSON writer. - /// The client options for reading and writing models. - void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { } - /// The JSON reader. - /// The client options for reading and writing models. - ModelWithRequiredNullableProperties System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) + ModelWithRequiredNullableProperties IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { return new ModelWithRequiredNullableProperties(); } - /// The client options for reading and writing models. - System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) { - return new System.BinaryData("IPersistableModel"); + return new BinaryData("IPersistableModel"); } - /// The data to parse. - /// The client options for reading and writing models. - ModelWithRequiredNullableProperties System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) + ModelWithRequiredNullableProperties IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { return new ModelWithRequiredNullableProperties(); } - /// The client options for reading and writing models. - string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J"; + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.cs index 5db2cccc84..e84593a20e 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ModelWithRequiredNullableProperties.cs @@ -4,6 +4,7 @@ namespace UnbrandedTypeSpec.Models { + /// A model with a few required nullable properties. public partial class ModelWithRequiredNullableProperties { /// Initializes a new instance of . diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.Serialization.cs index 2ffe34d083..76e2dd9fe9 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.Serialization.cs @@ -9,51 +9,40 @@ namespace UnbrandedTypeSpec.Models { - public partial class ProjectedModel : System.ClientModel.Primitives.IJsonModel + /// + public partial class ProjectedModel : IJsonModel { - private IDictionary _serializedAdditionalRawData; + private IDictionary _serializedAdditionalRawData; - /// Initializes a new instance of . - /// name of the ModelWithProjectedName. - /// Keeps track of any properties unknown to the library. - internal ProjectedModel(string name, IDictionary serializedAdditionalRawData) + internal ProjectedModel(string name, IDictionary serializedAdditionalRawData) { Name = name; _serializedAdditionalRawData = serializedAdditionalRawData; } - /// Initializes a new instance of for deserialization. internal ProjectedModel() { } - /// The JSON writer. - /// The client options for reading and writing models. - void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { } - /// The JSON reader. - /// The client options for reading and writing models. - ProjectedModel System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) + ProjectedModel IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { return new ProjectedModel(); } - /// The client options for reading and writing models. - System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) { - return new System.BinaryData("IPersistableModel"); + return new BinaryData("IPersistableModel"); } - /// The data to parse. - /// The client options for reading and writing models. - ProjectedModel System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) + ProjectedModel IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { return new ProjectedModel(); } - /// The client options for reading and writing models. - string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J"; + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.cs index 5d734f9c5b..e2514aae63 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ProjectedModel.cs @@ -7,6 +7,7 @@ namespace UnbrandedTypeSpec.Models { + /// this is a model with a projected name. public partial class ProjectedModel { /// Initializes a new instance of . diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.Serialization.cs index 4314321707..556a1a3aab 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.Serialization.cs @@ -9,44 +9,35 @@ namespace UnbrandedTypeSpec.Models { - public partial class ReturnsAnonymousModelResponse : System.ClientModel.Primitives.IJsonModel + /// + public partial class ReturnsAnonymousModelResponse : IJsonModel { - private IDictionary _serializedAdditionalRawData; + private IDictionary _serializedAdditionalRawData; - /// Initializes a new instance of . - /// Keeps track of any properties unknown to the library. - internal ReturnsAnonymousModelResponse(IDictionary serializedAdditionalRawData) + internal ReturnsAnonymousModelResponse(IDictionary serializedAdditionalRawData) { _serializedAdditionalRawData = serializedAdditionalRawData; } - /// The JSON writer. - /// The client options for reading and writing models. - void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { } - /// The JSON reader. - /// The client options for reading and writing models. - ReturnsAnonymousModelResponse System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) + ReturnsAnonymousModelResponse IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { return new ReturnsAnonymousModelResponse(); } - /// The client options for reading and writing models. - System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) { - return new System.BinaryData("IPersistableModel"); + return new BinaryData("IPersistableModel"); } - /// The data to parse. - /// The client options for reading and writing models. - ReturnsAnonymousModelResponse System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) + ReturnsAnonymousModelResponse IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { return new ReturnsAnonymousModelResponse(); } - /// The client options for reading and writing models. - string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J"; + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.cs index 55a27f940c..d83a56f346 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ReturnsAnonymousModelResponse.cs @@ -4,9 +4,9 @@ namespace UnbrandedTypeSpec.Models { + /// The ReturnsAnonymousModelResponse. public partial class ReturnsAnonymousModelResponse { - /// Initializes a new instance of . internal ReturnsAnonymousModelResponse() { } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.Serialization.cs index 59c50b090d..501203fe8d 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.Serialization.cs @@ -9,37 +9,12 @@ namespace UnbrandedTypeSpec.Models { - public partial class RoundTripModel : System.ClientModel.Primitives.IJsonModel + /// + public partial class RoundTripModel : IJsonModel { - private IDictionary _serializedAdditionalRawData; + private IDictionary _serializedAdditionalRawData; - /// Initializes a new instance of . - /// Required string, illustrating a reference type property. - /// Required int, illustrating a value type property. - /// Required collection of enums. - /// Required dictionary of enums. - /// Required model. - /// this is an int based extensible enum. - /// this is a collection of int based extensible enum. - /// this is a float based extensible enum. - /// this is a float based extensible enum. - /// this is a collection of float based extensible enum. - /// this is a float based fixed enum. - /// this is a float based fixed enum. - /// this is a collection of float based fixed enum. - /// this is a int based fixed enum. - /// this is a collection of int based fixed enum. - /// this is a string based fixed enum. - /// required unknown. - /// optional unknown. - /// required record of unknown. - /// optional record of unknown. - /// required readonly record of unknown. - /// optional readonly record of unknown. - /// this is a model with required nullable properties. - /// Required bytes. - /// Keeps track of any properties unknown to the library. - internal RoundTripModel(string requiredString, int requiredInt, IList requiredCollection, IDictionary requiredDictionary, Thing requiredModel, IntExtensibleEnum intExtensibleEnum, IList intExtensibleEnumCollection, FloatExtensibleEnum floatExtensibleEnum, FloatExtensibleEnumWithIntValue floatExtensibleEnumWithIntValue, IList floatExtensibleEnumCollection, FloatFixedEnum floatFixedEnum, FloatFixedEnumWithIntValue floatFixedEnumWithIntValue, IList floatFixedEnumCollection, IntFixedEnum intFixedEnum, IList intFixedEnumCollection, StringFixedEnum? stringFixedEnum, System.BinaryData requiredUnknown, System.BinaryData optionalUnknown, IDictionary requiredRecordUnknown, IDictionary optionalRecordUnknown, IDictionary readOnlyRequiredRecordUnknown, IDictionary readOnlyOptionalRecordUnknown, ModelWithRequiredNullableProperties modelWithRequiredNullable, System.BinaryData requiredBytes, IDictionary serializedAdditionalRawData) + internal RoundTripModel(string requiredString, int requiredInt, IList requiredCollection, IDictionary requiredDictionary, Thing requiredModel, IntExtensibleEnum intExtensibleEnum, IList intExtensibleEnumCollection, FloatExtensibleEnum floatExtensibleEnum, FloatExtensibleEnumWithIntValue floatExtensibleEnumWithIntValue, IList floatExtensibleEnumCollection, FloatFixedEnum floatFixedEnum, FloatFixedEnumWithIntValue floatFixedEnumWithIntValue, IList floatFixedEnumCollection, IntFixedEnum intFixedEnum, IList intFixedEnumCollection, StringFixedEnum? stringFixedEnum, BinaryData requiredUnknown, BinaryData optionalUnknown, IDictionary requiredRecordUnknown, IDictionary optionalRecordUnknown, IDictionary readOnlyRequiredRecordUnknown, IDictionary readOnlyOptionalRecordUnknown, ModelWithRequiredNullableProperties modelWithRequiredNullable, BinaryData requiredBytes, IDictionary serializedAdditionalRawData) { RequiredString = requiredString; RequiredInt = requiredInt; @@ -68,38 +43,29 @@ internal RoundTripModel(string requiredString, int requiredInt, IList Initializes a new instance of for deserialization. internal RoundTripModel() { } - /// The JSON writer. - /// The client options for reading and writing models. - void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { } - /// The JSON reader. - /// The client options for reading and writing models. - RoundTripModel System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) + RoundTripModel IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { return new RoundTripModel(); } - /// The client options for reading and writing models. - System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) { - return new System.BinaryData("IPersistableModel"); + return new BinaryData("IPersistableModel"); } - /// The data to parse. - /// The client options for reading and writing models. - RoundTripModel System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) + RoundTripModel IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { return new RoundTripModel(); } - /// The client options for reading and writing models. - string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J"; + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.cs index 3dc41b8df5..a5101aa0e2 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/RoundTripModel.cs @@ -5,10 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using UnbrandedTypeSpec; namespace UnbrandedTypeSpec.Models { + /// this is a roundtrip model. public partial class RoundTripModel { /// Initializes a new instance of . @@ -22,7 +24,7 @@ public partial class RoundTripModel /// this is a model with required nullable properties. /// Required bytes. /// , , , , , , or is null. - public RoundTripModel(string requiredString, int requiredInt, IEnumerable requiredCollection, IDictionary requiredDictionary, Thing requiredModel, System.BinaryData requiredUnknown, IDictionary requiredRecordUnknown, ModelWithRequiredNullableProperties modelWithRequiredNullable, System.BinaryData requiredBytes) + public RoundTripModel(string requiredString, int requiredInt, IEnumerable requiredCollection, IDictionary requiredDictionary, Thing requiredModel, BinaryData requiredUnknown, IDictionary requiredRecordUnknown, ModelWithRequiredNullableProperties modelWithRequiredNullable, BinaryData requiredBytes) { Argument.AssertNotNull(requiredString, nameof(requiredString)); Argument.AssertNotNull(requiredCollection, nameof(requiredCollection)); @@ -44,9 +46,9 @@ public RoundTripModel(string requiredString, int requiredInt, IEnumerable(); RequiredUnknown = requiredUnknown; RequiredRecordUnknown = requiredRecordUnknown; - OptionalRecordUnknown = new ChangeTrackingDictionary(); - ReadOnlyRequiredRecordUnknown = new ChangeTrackingDictionary(); - ReadOnlyOptionalRecordUnknown = new ChangeTrackingDictionary(); + OptionalRecordUnknown = new ChangeTrackingDictionary(); + ReadOnlyRequiredRecordUnknown = new ChangeTrackingDictionary(); + ReadOnlyOptionalRecordUnknown = new ChangeTrackingDictionary(); ModelWithRequiredNullable = modelWithRequiredNullable; RequiredBytes = requiredBytes; } @@ -101,195 +103,171 @@ public RoundTripModel(string requiredString, int requiredInt, IEnumerable /// required unknown - /// - /// To assign an object to this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to this property use . + /// To assign an already formatted json string to this property use . /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public System.BinaryData RequiredUnknown { get; set; } + public BinaryData RequiredUnknown { get; set; } /// /// optional unknown - /// - /// To assign an object to this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to this property use . + /// To assign an already formatted json string to this property use . /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public System.BinaryData OptionalUnknown { get; set; } + public BinaryData OptionalUnknown { get; set; } /// /// required record of unknown - /// - /// To assign an object to the value of this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to the value of this property use . + /// To assign an already formatted json string to this property use . /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public IDictionary RequiredRecordUnknown { get; } + public IDictionary RequiredRecordUnknown { get; } /// /// optional record of unknown - /// - /// To assign an object to the value of this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to the value of this property use . + /// To assign an already formatted json string to this property use . /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public IDictionary OptionalRecordUnknown { get; } + public IDictionary OptionalRecordUnknown { get; } /// /// required readonly record of unknown - /// - /// To assign an object to the value of this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to the value of this property use . + /// To assign an already formatted json string to this property use . /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public IDictionary ReadOnlyRequiredRecordUnknown { get; } + public IDictionary ReadOnlyRequiredRecordUnknown { get; } /// /// optional readonly record of unknown - /// - /// To assign an object to the value of this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to the value of this property use . + /// To assign an already formatted json string to this property use . /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public IDictionary ReadOnlyOptionalRecordUnknown { get; } + public IDictionary ReadOnlyOptionalRecordUnknown { get; } /// this is a model with required nullable properties. public ModelWithRequiredNullableProperties ModelWithRequiredNullable { get; set; } @@ -297,19 +275,19 @@ public RoundTripModel(string requiredString, int requiredInt, IEnumerable /// Required bytes /// - /// To assign a byte[] to this property use . + /// To assign a byte[] to this property use . /// The byte[] will be serialized to a Base64 encoded string. /// /// /// Examples: /// /// - /// BinaryData.FromBytes(new byte[] { 1, 2, 3 }) - /// Creates a payload of "AQID". + /// BinaryData.FromBytes(new byte[] { 1, 2, 3 }). + /// Creates a payload of "AQID". /// /// /// /// - public System.BinaryData RequiredBytes { get; set; } + public BinaryData RequiredBytes { get; set; } } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringExtensibleEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringExtensibleEnum.cs index 85c7ea524e..844137b2b1 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringExtensibleEnum.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringExtensibleEnum.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// Extensible enum. public readonly partial struct StringExtensibleEnum : IEquatable { private readonly string _value; @@ -55,8 +56,10 @@ public StringExtensibleEnum(string value) /// The instance to compare. public bool Equals(StringExtensibleEnum other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + /// public override int GetHashCode() => _value?.GetHashCode() ?? 0; + /// public override string ToString() => _value; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnum.cs index 50aaf6c30e..0698cbd34f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnum.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnum.cs @@ -4,10 +4,14 @@ namespace UnbrandedTypeSpec.Models { + /// Simple enum. public enum StringFixedEnum { + /// One. One, + /// Two. Two, + /// Four. Four } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnumExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnumExtensions.cs index 149721ff2d..fb6e88e8ec 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnumExtensions.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnumExtensions.cs @@ -8,7 +8,6 @@ namespace UnbrandedTypeSpec.Models { internal static partial class StringFixedEnumExtensions { - /// The value to serialize. public static string ToSerialString(this StringFixedEnum value) => value switch { StringFixedEnum.One => "1", @@ -17,7 +16,6 @@ internal static partial class StringFixedEnumExtensions _ => throw new ArgumentOutOfRangeException(nameof(value), value, "Unknown StringFixedEnum value.") }; - /// The value to deserialize. public static StringFixedEnum ToStringFixedEnum(this string value) { if (StringComparer.OrdinalIgnoreCase.Equals(value, "1")) diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.Serialization.cs index 2b15ac6b98..6c72cd5337 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.Serialization.cs @@ -9,26 +9,12 @@ namespace UnbrandedTypeSpec.Models { - public partial class Thing : System.ClientModel.Primitives.IJsonModel + /// + public partial class Thing : IJsonModel { - private IDictionary _serializedAdditionalRawData; + private IDictionary _serializedAdditionalRawData; - /// Initializes a new instance of . - /// name of the Thing. - /// required Union. - /// required literal string. - /// required literal int. - /// required literal float. - /// required literal bool. - /// optional literal string. - /// optional literal int. - /// optional literal float. - /// optional literal bool. - /// description with xml <|endoftext|>. - /// optional nullable collection. - /// required nullable collection. - /// Keeps track of any properties unknown to the library. - internal Thing(string name, System.BinaryData requiredUnion, ThingRequiredLiteralString requiredLiteralString, ThingRequiredLiteralInt requiredLiteralInt, ThingRequiredLiteralFloat requiredLiteralFloat, bool requiredLiteralBool, ThingOptionalLiteralString optionalLiteralString, ThingOptionalLiteralInt optionalLiteralInt, ThingOptionalLiteralFloat optionalLiteralFloat, bool optionalLiteralBool, string requiredBadDescription, IList optionalNullableList, IList requiredNullableList, IDictionary serializedAdditionalRawData) + internal Thing(string name, BinaryData requiredUnion, ThingRequiredLiteralString requiredLiteralString, ThingRequiredLiteralInt requiredLiteralInt, ThingRequiredLiteralFloat requiredLiteralFloat, bool requiredLiteralBool, ThingOptionalLiteralString optionalLiteralString, ThingOptionalLiteralInt optionalLiteralInt, ThingOptionalLiteralFloat optionalLiteralFloat, bool optionalLiteralBool, string requiredBadDescription, IList optionalNullableList, IList requiredNullableList, IDictionary serializedAdditionalRawData) { Name = name; RequiredUnion = requiredUnion; @@ -46,38 +32,29 @@ internal Thing(string name, System.BinaryData requiredUnion, ThingRequiredLitera _serializedAdditionalRawData = serializedAdditionalRawData; } - /// Initializes a new instance of for deserialization. internal Thing() { } - /// The JSON writer. - /// The client options for reading and writing models. - void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { } - /// The JSON reader. - /// The client options for reading and writing models. - Thing System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) + Thing IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { return new Thing(); } - /// The client options for reading and writing models. - System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) { - return new System.BinaryData("IPersistableModel"); + return new BinaryData("IPersistableModel"); } - /// The data to parse. - /// The client options for reading and writing models. - Thing System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) + Thing IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { return new Thing(); } - /// The client options for reading and writing models. - string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J"; + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.cs index b1ff404e7b..b8f964a6e7 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/Thing.cs @@ -5,19 +5,21 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using UnbrandedTypeSpec; namespace UnbrandedTypeSpec.Models { + /// A model with a few properties of literal types. public partial class Thing { /// Initializes a new instance of . /// name of the Thing. /// required Union. - /// description with xml <|endoftext|>. + /// description with xml <|endoftext|>. /// required nullable collection. /// , or is null. - public Thing(string name, System.BinaryData requiredUnion, string requiredBadDescription, IEnumerable requiredNullableList) + public Thing(string name, BinaryData requiredUnion, string requiredBadDescription, IEnumerable requiredNullableList) { Argument.AssertNotNull(name, nameof(name)); Argument.AssertNotNull(requiredUnion, nameof(requiredUnion)); @@ -35,49 +37,47 @@ public Thing(string name, System.BinaryData requiredUnion, string requiredBadDes /// /// required Union - /// - /// To assign an object to this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// + /// To assign an object to this property use . + /// To assign an already formatted json string to this property use . /// /// /// Supported types: /// /// - /// + /// . /// /// - /// where T is of type + /// where T is of type . /// /// - /// + /// . /// /// /// + /// + /// /// Examples: /// /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". + /// BinaryData.FromObjectAsJson("foo"). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". + /// BinaryData.FromString("\"foo\""). + /// Creates a payload of "foo". /// /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromObjectAsJson(new { key = "value" }). + /// Creates a payload of { "key": "value" }. /// /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. + /// BinaryData.FromString("{\"key\": \"value\"}"). + /// Creates a payload of { "key": "value" }. /// /// /// /// - public System.BinaryData RequiredUnion { get; set; } + public BinaryData RequiredUnion { get; set; } /// required literal string. public ThingRequiredLiteralString RequiredLiteralString { get; } = "accept"; @@ -103,7 +103,7 @@ public Thing(string name, System.BinaryData requiredUnion, string requiredBadDes /// optional literal bool. public bool OptionalLiteralBool { get; set; } - /// description with xml <|endoftext|>. + /// description with xml <|endoftext|>. public string RequiredBadDescription { get; set; } /// optional nullable collection. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs index 0bfb22fe69..07d545a9fa 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// The Thing_optionalLiteralFloat. public readonly partial struct ThingOptionalLiteralFloat : IEquatable { private readonly float _value; @@ -45,8 +46,10 @@ public ThingOptionalLiteralFloat(float value) /// The instance to compare. public bool Equals(ThingOptionalLiteralFloat other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal float ToSerialSingle() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs index f9524c0106..0bb5abbb7c 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// The Thing_optionalLiteralInt. public readonly partial struct ThingOptionalLiteralInt : IEquatable { private readonly int _value; @@ -45,8 +46,10 @@ public ThingOptionalLiteralInt(int value) /// The instance to compare. public bool Equals(ThingOptionalLiteralInt other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal int ToSerialInt32() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralString.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralString.cs index 5f868c640d..5cbbd4a8ec 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralString.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralString.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// The Thing_optionalLiteralString. public readonly partial struct ThingOptionalLiteralString : IEquatable { private readonly string _value; @@ -48,8 +49,10 @@ public ThingOptionalLiteralString(string value) /// The instance to compare. public bool Equals(ThingOptionalLiteralString other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + /// public override int GetHashCode() => _value?.GetHashCode() ?? 0; + /// public override string ToString() => _value; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs index bc25084e49..8b0713c99e 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// The Thing_requiredLiteralFloat. public readonly partial struct ThingRequiredLiteralFloat : IEquatable { private readonly float _value; @@ -45,8 +46,10 @@ public ThingRequiredLiteralFloat(float value) /// The instance to compare. public bool Equals(ThingRequiredLiteralFloat other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal float ToSerialSingle() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs index 819c5f879d..2a067b2625 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// The Thing_requiredLiteralInt. public readonly partial struct ThingRequiredLiteralInt : IEquatable { private readonly int _value; @@ -45,8 +46,10 @@ public ThingRequiredLiteralInt(int value) /// The instance to compare. public bool Equals(ThingRequiredLiteralInt other) => Equals(_value, other._value); + /// public override int GetHashCode() => _value.GetHashCode(); + /// public override string ToString() => _value.ToString(CultureInfo.InvariantCulture); internal int ToSerialInt32() => _value; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralString.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralString.cs index 62a46a90d6..fbc90030db 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralString.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralString.cs @@ -8,6 +8,7 @@ namespace UnbrandedTypeSpec.Models { + /// The Thing_requiredLiteralString. public readonly partial struct ThingRequiredLiteralString : IEquatable { private readonly string _value; @@ -48,8 +49,10 @@ public ThingRequiredLiteralString(string value) /// The instance to compare. public bool Equals(ThingRequiredLiteralString other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + /// public override int GetHashCode() => _value?.GetHashCode() ?? 0; + /// public override string ToString() => _value; } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs index 51ef756e33..1926c151c3 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs @@ -7,160 +7,78 @@ namespace UnbrandedTypeSpec { + /// public partial class UnbrandedTypeSpecClient { - /// Return hi. - /// - /// - /// - /// - /// - internal void CreateSayHiRequest(System.Uri unbrandedTypeSpecUrl, string headParameter, string queryParameter, string optionalQuery, string accept) + internal void CreateSayHiRequest(Uri unbrandedTypeSpecUrl, string headParameter, string queryParameter, string optionalQuery, string accept) { } - /// Return hi again. - /// - /// - /// - /// - /// - /// - internal void CreateHelloAgainRequest(System.Uri unbrandedTypeSpecUrl, string p1, string contentType, string p2, RoundTripModel action, string accept) + internal void CreateHelloAgainRequest(Uri unbrandedTypeSpecUrl, string p1, string contentType, string p2, RoundTripModel action, string accept) { } - /// Return hi again. - /// - /// - /// - /// - /// - /// - internal void CreateNoContentTypeRequest(System.Uri unbrandedTypeSpecUrl, string p1, string p2, RoundTripModel action, string accept, string contentType) + internal void CreateNoContentTypeRequest(Uri unbrandedTypeSpecUrl, string p1, string p2, RoundTripModel action, string accept, string contentType) { } - /// Return hi in demo2. - /// - /// - internal void CreateHelloDemo2Request(System.Uri unbrandedTypeSpecUrl, string accept) + internal void CreateHelloDemo2Request(Uri unbrandedTypeSpecUrl, string accept) { } - /// Create with literal value. - /// - /// - /// - /// - internal void CreateCreateLiteralRequest(System.Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) + internal void CreateCreateLiteralRequest(Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) { } - /// Send literal parameters. - /// - /// - /// - /// - /// - internal void CreateHelloLiteralRequest(System.Uri unbrandedTypeSpecUrl, string p1, int p2, bool p3, string accept) + internal void CreateHelloLiteralRequest(Uri unbrandedTypeSpecUrl, string p1, int p2, bool p3, string accept) { } - /// top level method. - /// - /// - /// - internal void CreateTopActionRequest(System.Uri unbrandedTypeSpecUrl, DateTimeOffset action, string accept) + internal void CreateTopActionRequest(Uri unbrandedTypeSpecUrl, DateTimeOffset action, string accept) { } - /// top level method2. - /// - /// - internal void CreateTopAction2Request(System.Uri unbrandedTypeSpecUrl, string accept) + internal void CreateTopAction2Request(Uri unbrandedTypeSpecUrl, string accept) { } - /// top level patch. - /// - /// - /// - /// - internal void CreatePatchActionRequest(System.Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) + internal void CreatePatchActionRequest(Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) { } - /// body parameter without body decorator. - /// - /// A model with a few properties of literal types. - /// - /// - internal void CreateAnonymousBodyRequest(System.Uri unbrandedTypeSpecUrl, Thing Thing, string accept, string contentType) + internal void CreateAnonymousBodyRequest(Uri unbrandedTypeSpecUrl, Thing Thing, string accept, string contentType) { } - /// Model can have its friendly name. - /// - /// this is not a friendly model but with a friendly name. - /// - /// - internal void CreateFriendlyModelRequest(System.Uri unbrandedTypeSpecUrl, Friend Friend, string accept, string contentType) + internal void CreateFriendlyModelRequest(Uri unbrandedTypeSpecUrl, Friend Friend, string accept, string contentType) { } - /// addTimeHeader. - /// - /// - /// - internal void CreateAddTimeHeaderRequest(System.Uri unbrandedTypeSpecUrl, DateTimeOffset repeatabilityFirstSent, string accept) + internal void CreateAddTimeHeaderRequest(Uri unbrandedTypeSpecUrl, DateTimeOffset repeatabilityFirstSent, string accept) { } - /// Model can have its projected name. - /// - /// this is a model with a projected name. - /// - /// - internal void CreateProjectedNameModelRequest(System.Uri unbrandedTypeSpecUrl, ProjectedModel ProjectedModel, string accept, string contentType) + internal void CreateProjectedNameModelRequest(Uri unbrandedTypeSpecUrl, ProjectedModel ProjectedModel, string accept, string contentType) { } - /// return anonymous model. - /// - /// - internal void CreateReturnsAnonymousModelRequest(System.Uri unbrandedTypeSpecUrl, string accept) + internal void CreateReturnsAnonymousModelRequest(Uri unbrandedTypeSpecUrl, string accept) { } - /// get extensible enum. - /// - /// - internal void CreateGetUnknownValueRequest(System.Uri unbrandedTypeSpecUrl, string accept) + internal void CreateGetUnknownValueRequest(Uri unbrandedTypeSpecUrl, string accept) { } - /// When set protocol false and convenient true, then the protocol method should be internal. - /// - /// - /// - /// - internal void CreateInternalProtocolRequest(System.Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) + internal void CreateInternalProtocolRequest(Uri unbrandedTypeSpecUrl, Thing body, string accept, string contentType) { } - /// When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one. - /// - /// - internal void CreateStillConvenientRequest(System.Uri unbrandedTypeSpecUrl, string accept) + internal void CreateStillConvenientRequest(Uri unbrandedTypeSpecUrl, string accept) { } - /// head as boolean. - /// - /// - /// - internal void CreateHeadAsBooleanRequest(System.Uri unbrandedTypeSpecUrl, string id, string accept) + internal void CreateHeadAsBooleanRequest(Uri unbrandedTypeSpecUrl, string id, string accept) { } } diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/UnbrandedTypeSpec.csproj b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/UnbrandedTypeSpec.csproj new file mode 100644 index 0000000000..7d4666b709 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/UnbrandedTypeSpec.csproj @@ -0,0 +1,16 @@ + + + This is the UnbrandedTypeSpec client library for developing .NET applications with rich experience. + SDK Code Generation UnbrandedTypeSpec + 1.0.0-beta.1 + UnbrandedTypeSpec + netstandard2.0 + latest + true + + + + + + +