diff --git a/CHANGELOG.md b/CHANGELOG.md index 5de990cbd7..2732e6fce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Localhost based descriptions are not cached anymore to facilitate development workflows. [#3316](https://github.com/microsoft/kiota/issues/3316) -- Changed parameter order in with_url method body to match the signature of RequestBuilder constructor in Python. [#3328](https://github.com/microsoft/kiota/issues/3328 +- Fixed a bug where inline composed types for components schemas would have the wrong name. [#3067](https://github.com/microsoft/kiota/issues/3067) +- Changed parameter order in with_url method body to match the signature of RequestBuilder constructor in Python. [#3328](https://github.com/microsoft/kiota/issues/3328) - Removed redundant undefined qualifier in TypeScript for properties. [#3244](https://github.com/microsoft/kiota/issues/3244) - The default status code response is now used as 4XX and 5XX when those class responses are not provided in the description. [#3245](https://github.com/microsoft/kiota/issues/3245) - Adds codes files in typescript to reduce number of generated files. [#2116](https://github.com/microsoft/kiota/issues/2116) diff --git a/it/config.json b/it/config.json index 44b1e2d3f2..8e654b74f0 100644 --- a/it/config.json +++ b/it/config.json @@ -259,32 +259,32 @@ ], "IdempotencySuppressions": [ { - "Language": "typescript", - "Rationale": "https://github.com/microsoft/kiota/issues/1812" + "Language": "csharp", + "Rationale": "https://github.com/microsoft/kiota/issues/2952" }, { "Language": "go", - "Rationale": "https://github.com/microsoft/kiota/issues/3067" + "Rationale": "https://github.com/microsoft/kiota/issues/2834" }, { "Language": "php", - "Rationale": "https://github.com/microsoft/kiota/issues/3067" + "Rationale": "https://github.com/microsoft/kiota/issues/2964" }, { "Language": "java", - "Rationale": "https://github.com/microsoft/kiota/issues/3067" + "Rationale": "https://github.com/microsoft/kiota/issues/2842" }, { - "Language": "csharp", - "Rationale": "https://github.com/microsoft/kiota/issues/3067" + "Language": "python", + "Rationale": "https://github.com/microsoft/kiota/issues/2842" }, { - "Language": "ruby", - "Rationale": "https://github.com/microsoft/kiota/issues/1816" + "Language": "typescript", + "Rationale": "https://github.com/microsoft/kiota/issues/1812" }, { - "Language": "python", - "Rationale": "https://github.com/microsoft/kiota/issues/3067" + "Language": "ruby", + "Rationale": "https://github.com/microsoft/kiota/issues/1816" } ] }, @@ -324,14 +324,10 @@ } ], "IdempotencySuppressions": [ - { - "Language": "php", - "Rationale": "https://github.com/microsoft/kiota/issues/3067" - }, { "Language": "typescript", "Rationale": "https://github.com/microsoft/kiota/issues/1812" } ] } -} +} \ No newline at end of file diff --git a/src/Kiota.Builder/BaseCodeParameterOrderComparer.cs b/src/Kiota.Builder/BaseCodeParameterOrderComparer.cs index 44790144fb..eab584983c 100644 --- a/src/Kiota.Builder/BaseCodeParameterOrderComparer.cs +++ b/src/Kiota.Builder/BaseCodeParameterOrderComparer.cs @@ -28,15 +28,12 @@ protected virtual int GetKindOrderHint(CodeParameterKind kind) CodeParameterKind.Path => 4, CodeParameterKind.RequestConfiguration => 5, CodeParameterKind.RequestBody => 6, -#pragma warning disable CS0618 - CodeParameterKind.ResponseHandler => 7, -#pragma warning restore CS0618 - CodeParameterKind.Serializer => 8, - CodeParameterKind.BackingStore => 9, - CodeParameterKind.SetterValue => 10, - CodeParameterKind.ParseNode => 11, - CodeParameterKind.Custom => 12, - _ => 13, + CodeParameterKind.Serializer => 7, + CodeParameterKind.BackingStore => 8, + CodeParameterKind.SetterValue => 9, + CodeParameterKind.ParseNode => 10, + CodeParameterKind.Custom => 11, + _ => 12, }; } private const int OptionalWeight = 10000; diff --git a/src/Kiota.Builder/CodeDOM/CodeBlock.cs b/src/Kiota.Builder/CodeDOM/CodeBlock.cs index 8931e9d2fd..230131c4ef 100644 --- a/src/Kiota.Builder/CodeDOM/CodeBlock.cs +++ b/src/Kiota.Builder/CodeDOM/CodeBlock.cs @@ -75,6 +75,7 @@ private T HandleDuplicatedExceptions(T element, CodeElement returnedValue) wh if (returnedValue == element) return element; if (element is CodeMethod currentMethod) + { if (currentMethod.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility) && returnedValue is CodeProperty cProp && cProp.IsOfKind(CodePropertyKind.RequestBuilder) && @@ -99,6 +100,17 @@ returnedValue is CodeProperty cProp && return result2; } } + } + else if (element is CodeProperty currentProperty && + currentProperty.Kind is CodePropertyKind.Custom && + returnedValue is CodeClass returnedClass && returnedClass.Kind is CodeClassKind.Model && + InnerChildElements.TryAdd($"{element.Name}-property", currentProperty)) + return element; // inline type property: transforming union type to wrapper class + else if (element is CodeClass currentClass && + currentClass.Kind is CodeClassKind.Model && + returnedValue is CodeProperty returnedProperty && returnedProperty.Kind is CodePropertyKind.Custom && + InnerChildElements.TryAdd($"{element.Name}-model", currentClass)) + return element; // inline type property: transforming wrapper class to union type if (element.GetType() == returnedValue.GetType()) return (T)returnedValue; diff --git a/src/Kiota.Builder/CodeDOM/CodeClass.cs b/src/Kiota.Builder/CodeDOM/CodeClass.cs index 58d84b8491..5ad49b2aef 100644 --- a/src/Kiota.Builder/CodeDOM/CodeClass.cs +++ b/src/Kiota.Builder/CodeDOM/CodeClass.cs @@ -183,7 +183,7 @@ public bool ContainsPropertyWithWireName(string wireName) } public IEnumerable AddInnerClass(params CodeClass[] codeClasses) { - if (codeClasses == null || codeClasses.Any(x => x == null)) + if (codeClasses == null || codeClasses.Any(static x => x == null)) throw new ArgumentNullException(nameof(codeClasses)); if (!codeClasses.Any()) throw new ArgumentOutOfRangeException(nameof(codeClasses)); diff --git a/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs b/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs index c885ce5c93..aa600049a0 100644 --- a/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs +++ b/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -6,18 +7,28 @@ namespace Kiota.Builder.CodeDOM; /// /// The base class for composed types like union or exclusion. /// -public abstract class CodeComposedTypeBase : CodeTypeBase, IDiscriminatorInformationHolder +public abstract class CodeComposedTypeBase : CodeTypeBase, IDiscriminatorInformationHolder, IDeprecableElement { + private static string NormalizeKey(CodeType codeType) => $"{codeType.Name}_{codeType.CollectionKind}"; public void AddType(params CodeType[] codeTypes) { + ArgumentNullException.ThrowIfNull(codeTypes); + if (Array.Exists(codeTypes, static x => x == null)) + throw new ArgumentNullException(nameof(codeTypes), "One of the provided types was null"); EnsureElementsAreChildren(codeTypes); - foreach (var codeType in codeTypes.Where(x => x != null && !Types.Contains(x))) - types.Add(codeType); + foreach (var codeType in codeTypes) + if (!types.TryAdd(NormalizeKey(codeType), codeType)) + throw new InvalidOperationException($"The type {codeType.Name} was already added"); } - private readonly List types = new(); + public bool ContainsType(CodeType codeType) + { + ArgumentNullException.ThrowIfNull(codeType); + return types.ContainsKey(NormalizeKey(codeType)); + } + private readonly ConcurrentDictionary types = new(StringComparer.OrdinalIgnoreCase); public IEnumerable Types { - get => types; + get => types.Values.OrderBy(NormalizeKey, StringComparer.OrdinalIgnoreCase); } private DiscriminatorInformation? _discriminatorInformation; /// @@ -45,6 +56,7 @@ protected override TChildType BaseClone(CodeTypeBase source, bool cl if (sourceComposed.Types?.Any() ?? false) AddType(sourceComposed.Types.ToArray()); DiscriminatorInformation = (DiscriminatorInformation)sourceComposed.DiscriminatorInformation.Clone(); + Deprecation = sourceComposed.Deprecation; return this is TChildType casted ? casted : throw new InvalidCastException($"Cannot cast {GetType().Name} to {typeof(TChildType).Name}"); } /// @@ -54,4 +66,9 @@ public CodeNamespace? TargetNamespace { get; set; } + public DeprecationInformation? Deprecation + { + get; + set; + } } diff --git a/src/Kiota.Builder/CodeDOM/CodeIntersectionType.cs b/src/Kiota.Builder/CodeDOM/CodeIntersectionType.cs index 80174fc3e3..d167be4d5e 100644 --- a/src/Kiota.Builder/CodeDOM/CodeIntersectionType.cs +++ b/src/Kiota.Builder/CodeDOM/CodeIntersectionType.cs @@ -5,17 +5,10 @@ namespace Kiota.Builder.CodeDOM; /// /// The base class for exclusion types. (one of the properties at a time) /// -public class CodeIntersectionType : CodeComposedTypeBase, ICloneable, IDeprecableElement +public class CodeIntersectionType : CodeComposedTypeBase, ICloneable { - public DeprecationInformation? Deprecation - { - get; set; - } - public override object Clone() { - var value = new CodeIntersectionType().BaseClone(this); - value.Deprecation = Deprecation; - return value; + return new CodeIntersectionType().BaseClone(this); } } diff --git a/src/Kiota.Builder/CodeDOM/CodeParameter.cs b/src/Kiota.Builder/CodeDOM/CodeParameter.cs index d99f99e7fc..5c5826337b 100644 --- a/src/Kiota.Builder/CodeDOM/CodeParameter.cs +++ b/src/Kiota.Builder/CodeDOM/CodeParameter.cs @@ -12,8 +12,6 @@ public enum CodeParameterKind /// The request headers when used as a executor/generator parameter. Most languages use the intermediate RequestConfiguration wrapper class. /// Headers, - [Obsolete("The parameter kind is replaced by a request option instead")] - ResponseHandler, RequestBody, SetterValue, RequestAdapter, diff --git a/src/Kiota.Builder/CodeDOM/CodeUnionType.cs b/src/Kiota.Builder/CodeDOM/CodeUnionType.cs index 7f29399a18..0d05d83ab4 100644 --- a/src/Kiota.Builder/CodeDOM/CodeUnionType.cs +++ b/src/Kiota.Builder/CodeDOM/CodeUnionType.cs @@ -5,16 +5,10 @@ namespace Kiota.Builder.CodeDOM; /// /// The base class for union types. (anyOf multiple properties at a time) /// -public class CodeUnionType : CodeComposedTypeBase, ICloneable, IDeprecableElement +public class CodeUnionType : CodeComposedTypeBase, ICloneable { - public DeprecationInformation? Deprecation - { - get; set; - } public override object Clone() { - var value = new CodeUnionType().BaseClone(this); - value.Deprecation = Deprecation; - return value; + return new CodeUnionType().BaseClone(this); } } diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index 710eebfa38..7af65ef437 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -1334,21 +1334,6 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, OperationTyp AddRequestBuilderMethodParameters(currentNode, operationType, operation, requestConfigClass, executorMethod); parentClass.AddMethod(executorMethod); -#pragma warning disable CS0618 - var handlerParam = new CodeParameter - { - Name = "responseHandler", - Optional = true, - Kind = CodeParameterKind.ResponseHandler, - Documentation = new() - { - Description = "Response handler to use in place of the default response handling provided by the core service", - }, - Type = new CodeType { Name = "IResponseHandler", IsExternal = true }, - }; - executorMethod.AddParameter(handlerParam);// Add response handler parameter -#pragma warning restore CS0618 - var cancellationParam = new CodeParameter { Name = "cancellationToken", @@ -1602,9 +1587,9 @@ private CodeTypeBase CreateInheritedModelDeclaration(OpenApiUrlTreeNode currentN if (parentSchema.Items?.Reference?.Id?.EndsWith(title, StringComparison.OrdinalIgnoreCase) ?? false) return parentSchema.Items.Reference.Id; return parentSchema.GetSchemaReferenceIds().FirstOrDefault(refId => refId.EndsWith(title, StringComparison.OrdinalIgnoreCase)); } - private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNode, OpenApiSchema schema, OpenApiOperation? operation, string suffixForInlineSchema, CodeNamespace codeNamespace, bool isRequestBody) + private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNode, OpenApiSchema schema, OpenApiOperation? operation, string suffixForInlineSchema, CodeNamespace codeNamespace, bool isRequestBody, string typeNameForInlineSchema) { - var typeName = currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: suffixForInlineSchema, schema: schema, requestBody: isRequestBody).CleanupSymbolName(); + var typeName = string.IsNullOrEmpty(typeNameForInlineSchema) ? currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: suffixForInlineSchema, schema: schema, requestBody: isRequestBody).CleanupSymbolName() : typeNameForInlineSchema; var typesCount = schema.AnyOf?.Count ?? schema.OneOf?.Count ?? 0; if (typesCount == 1 && schema.Nullable && schema.IsInclusiveUnion() || // nullable on the root schema outside of anyOf typesCount == 2 && (schema.AnyOf?.Any(static x => // nullable on a schema in the anyOf @@ -1654,16 +1639,18 @@ private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNo if (string.IsNullOrEmpty(className)) if (GetPrimitiveType(currentSchema) is CodeType primitiveType && !string.IsNullOrEmpty(primitiveType.Name)) { - unionType.AddType(primitiveType); + if (!unionType.ContainsType(primitiveType)) + unionType.AddType(primitiveType); continue; } else className = $"{unionType.Name}Member{++membersWithNoName}"; - var codeDeclaration = AddModelDeclarationIfDoesntExist(currentNode, currentSchema, className, shortestNamespace); - unionType.AddType(new CodeType + var declarationType = new CodeType { - TypeDefinition = codeDeclaration, - }); + TypeDefinition = AddModelDeclarationIfDoesntExist(currentNode, currentSchema, className, shortestNamespace), + }; + if (!unionType.ContainsType(declarationType)) + unionType.AddType(declarationType); } return unionType; } @@ -1696,7 +1683,7 @@ private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNo if ((schema.IsInclusiveUnion() || schema.IsExclusiveUnion()) && string.IsNullOrEmpty(schema.Format) && !schema.IsODataPrimitiveType()) { // OData types are oneOf string, type + format, enum - return CreateComposedModelDeclaration(currentNode, schema, operation, suffix, codeNamespace, isRequestBody); + return CreateComposedModelDeclaration(currentNode, schema, operation, suffix, codeNamespace, isRequestBody, typeNameForInlineSchema); } if (schema.IsObject() || schema.Properties.Any() || schema.IsEnum() || !string.IsNullOrEmpty(schema.AdditionalProperties?.Type)) @@ -2067,9 +2054,7 @@ private void CreatePropertiesForModelClass(OpenApiUrlTreeNode currentNode, OpenA .Select(x => { var propertySchema = x.Value; - var className = propertySchema.GetSchemaName().CleanupSymbolName(); - if (string.IsNullOrEmpty(className)) - className = $"{model.Name}_{x.Key.CleanupSymbolName()}"; + var className = $"{model.Name}_{x.Key.CleanupSymbolName()}"; var shortestNamespaceName = GetModelsNamespaceNameFromReferenceId(propertySchema.Reference?.Id); var targetNamespace = string.IsNullOrEmpty(shortestNamespaceName) ? ns : rootNamespace?.FindOrAddNamespace(shortestNamespaceName) ?? ns; diff --git a/src/Kiota.Builder/Refiners/CSharpRefiner.cs b/src/Kiota.Builder/Refiners/CSharpRefiner.cs index 308fe9b6a7..7472c4c922 100644 --- a/src/Kiota.Builder/Refiners/CSharpRefiner.cs +++ b/src/Kiota.Builder/Refiners/CSharpRefiner.cs @@ -107,7 +107,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance generatedCode, "IParseNode" ); - RemoveHandlerFromRequestBuilder(generatedCode); }, cancellationToken); } protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 553b727766..0e725475c2 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -486,6 +486,7 @@ private static CodeTypeBase ConvertComposedTypeToWrapper(CodeClass codeClass, Co { Description = description, }, + Deprecation = codeComposedType.Deprecation, }).Last(); } else if (codeComposedType.TargetNamespace is CodeNamespace targetNamespace) @@ -1377,21 +1378,6 @@ mappingClass.Parent is CodeNamespace mappingNamespace && } CrawlTree(currentElement, RemoveDiscriminatorMappingsTargetingSubNamespaces); } - protected void RemoveHandlerFromRequestBuilder(CodeElement currentElement) - { - if (currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.RequestBuilder)) - { - var codeMethods = currentClass.Methods.Where(x => x.Kind == CodeMethodKind.RequestExecutor); - foreach (var codeMethod in codeMethods) - { -#pragma warning disable CS0618 - codeMethod.RemoveParametersByKind(CodeParameterKind.ResponseHandler); -#pragma warning restore CS0618 - } - } - - CrawlTree(currentElement, RemoveHandlerFromRequestBuilder); - } protected static void MoveRequestBuilderPropertiesToBaseType(CodeElement currentElement, CodeUsing baseTypeUsing, AccessModifier? accessModifier = null) { ArgumentNullException.ThrowIfNull(baseTypeUsing); diff --git a/src/Kiota.Builder/Refiners/GoRefiner.cs b/src/Kiota.Builder/Refiners/GoRefiner.cs index 4a183e16ff..2e326e1cfd 100644 --- a/src/Kiota.Builder/Refiners/GoRefiner.cs +++ b/src/Kiota.Builder/Refiners/GoRefiner.cs @@ -164,7 +164,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance generatedCode, x => $"{x.Name}able" ); - RemoveHandlerFromRequestBuilder(generatedCode); AddContextParameterToGeneratorMethods(generatedCode); CorrectTypes(generatedCode); CorrectCoreTypesForBackingStore(generatedCode, $"{conventions.StoreHash}.BackingStoreFactoryInstance()", false); diff --git a/src/Kiota.Builder/Refiners/JavaRefiner.cs b/src/Kiota.Builder/Refiners/JavaRefiner.cs index a520c844db..83818c2d6f 100644 --- a/src/Kiota.Builder/Refiners/JavaRefiner.cs +++ b/src/Kiota.Builder/Refiners/JavaRefiner.cs @@ -137,7 +137,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "ParseNode", addUsings: true ); - RemoveHandlerFromRequestBuilder(generatedCode); SplitLongDiscriminatorMethods(generatedCode); AddPrimaryErrorMessage(generatedCode, "getMessage", diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 4850e151fa..4f3fc3888b 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -102,7 +102,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddPropertiesAndMethodTypesImports(generatedCode, true, false, true); CorrectBackingStoreSetterParam(generatedCode); CorrectCoreTypesForBackingStore(generatedCode, "BackingStoreFactorySingleton::getInstance()->createBackingStore()"); - RemoveHandlerFromRequestBuilder(generatedCode); cancellationToken.ThrowIfCancellationRequested(); AliasUsingWithSameSymbol(generatedCode); RemoveRequestConfigurationClassesCommonProperties(generatedCode, diff --git a/src/Kiota.Builder/Refiners/PythonRefiner.cs b/src/Kiota.Builder/Refiners/PythonRefiner.cs index 42a2058aa5..46c7d678a4 100644 --- a/src/Kiota.Builder/Refiners/PythonRefiner.cs +++ b/src/Kiota.Builder/Refiners/PythonRefiner.cs @@ -122,7 +122,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance addUsings: true, includeParentNamespace: true ); - RemoveHandlerFromRequestBuilder(generatedCode); }, cancellationToken); } diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index 555e457adb..498857712f 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -122,7 +122,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "ParseNode", addUsings: true ); - RemoveHandlerFromRequestBuilder(generatedCode); }, cancellationToken); } private static void ShortenLongNamespaceNames(CodeElement currentElement) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 32b6d1f586..1b23f70e87 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -17,7 +17,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance { cancellationToken.ThrowIfCancellationRequested(); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor); - RemoveHandlerFromRequestBuilder(generatedCode); ReplaceReservedNames(generatedCode, new TypeScriptReservedNamesProvider(), static x => $"{x}Escaped"); ReplaceReservedExceptionPropertyNames(generatedCode, new TypeScriptExceptionsReservedNamesProvider(), static x => $"{x}Escaped"); MoveRequestBuilderPropertiesToBaseType(generatedCode, diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs index 1d6af02b91..dd95265e3c 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs @@ -127,7 +127,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla var includeElse = false; foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .OrderBy(static x => x, CodePropertyTypeForwardComparer) - .ThenBy(static x => x.Name)) + .ThenBy(static x => x.Name, StringComparer.Ordinal)) { if (property.Type is CodeType propertyType) if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) @@ -159,7 +159,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => x.Type is not CodeType propertyType || propertyType.IsCollection || propertyType.TypeDefinition is not CodeClass) .OrderBy(static x => x, CodePropertyTypeBackwardComparer) - .ThenBy(static x => x.Name)) + .ThenBy(static x => x.Name, StringComparer.Ordinal)) { if (property.Type is CodeType propertyType) { @@ -331,7 +331,7 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod foreach (var otherProp in parentClass .GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => !x.ExistsInBaseType) - .OrderBy(static x => x.Name)) + .OrderBy(static x => x.Name, StringComparer.Ordinal)) { writer.WriteLine($"{{\"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},"); } diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 08857a7638..457127d7ac 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -275,6 +275,71 @@ public async Task ParsesEnumFlagsInformation() Assert.NotNull(enumDef); Assert.True(enumDef.Flags); } + [Fact] + public async Task NamesComponentsInlineSchemasProperly() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStream(@"openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: 1.0.1 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /users: + get: + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.directoryObject' +components: + schemas: + microsoft.graph.directoryObject: + title: directoryObject + type: object + properties: + deletedDateTime: + oneOf: + - type: string + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + format: date-time + nullable: true + - type: number + format: int64 + - type: object + properties: + day: + type: integer + format: int32 + month: + type: integer + format: int32 + year: + type: integer + format: int32"); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + var modelsNS = codeModel.FindNamespaceByName("ApiSdk.models.microsoft.graph"); + Assert.NotNull(modelsNS); + var doClass = modelsNS.FindChildByName("DirectoryObject", false); + Assert.NotNull(doClass); + var deletedDateTimeProperty = doClass.FindChildByName("DeletedDateTime", false); + Assert.NotNull(deletedDateTimeProperty); + var unionType = deletedDateTimeProperty.Type as CodeUnionType; + Assert.NotNull(unionType); + Assert.Equal("directoryObject_deletedDateTime", unionType.Name, StringComparer.OrdinalIgnoreCase); + Assert.Equal(3, unionType.Types.Count()); + Assert.Equal("DateTimeOffset", unionType.Types.First().Name, StringComparer.OrdinalIgnoreCase); + Assert.Equal("directoryObject_deletedDateTimeMember1", unionType.Types.ElementAt(1).Name, StringComparer.OrdinalIgnoreCase); + Assert.Equal("int64", unionType.Types.ElementAt(2).Name, StringComparer.OrdinalIgnoreCase); + Assert.Null(modelsNS.FindChildByName("users")); + } [Theory] [InlineData("description: 'Represents an Azure Active Directory user.'")] [InlineData("title: 'user'")]