Repository: microsoft/kiota (csharp)

Issue:
Changes in https://github.com/microsoft/kiota/pull/3921 result in incrrorect generation of inline anyof and array enum types.
Latests generation at https://dev.azure.com/microsoftgraph/Graph%20Developer%20Experiences/_build/results?buildId=130660&view=logs&j=0c914960-8b50-5299-c9aa-dd3c9595168e&t=97dbd468-8cc6-5acc-f2af-de93eaf8bad9 fails due to changes in https://github.com/microsoft/kiota/pull/3921

Referenced types of enum in an anyOf or array are incorrectly generated as inline types. 

e.g. the reason property is generated as `RejectPostRequestBody_reason.cs` rather than a collection of micrososft.graph.rejectedReasons

```openapi
requestBody:
        description: Action parameters
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  anyOf:
                    - $ref: '#/components/schemas/microsoft.graph.rejectReason'
                    - type: object
                      nullable: true
                callbackUri:
                  type: string
                  nullable: true
        required: true
```

Pull request description:
fixes #3935

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c34afd5d9d..6107044483 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Changed
 
 - Fixed a bug where the discriminator validation rule would report false positives on nullable union types.
+- Fixed a bug where the order of enum declaration might results in a missing enum type. [#3935](https://github.com/microsoft/kiota/issues/3935)
 
 ## [1.9.1] - 2023-12-13
 
diff --git a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs
index 2a37aaa315..4c705bdeeb 100644
--- a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs
+++ b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs
@@ -125,18 +125,19 @@ public static bool IsEnum(this OpenApiSchema schema)
     {
         if (schema is null) return false;
         return schema.Enum.OfType<OpenApiString>().Any(static x => !string.IsNullOrEmpty(x.Value)) &&
-                (string.IsNullOrEmpty(schema.Type) || "string".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)) ||
-                schema.AnyOf.Where(static x => x.IsSemanticallyMeaningful(true)).Count(static x => x.IsEnum()) == 1 && !schema.AnyOf.Where(static x => x.IsSemanticallyMeaningful(true)).Any(static x => !x.IsEnum()) ||
-                schema.OneOf.Where(static x => x.IsSemanticallyMeaningful(true)).Count(static x => x.IsEnum()) == 1 && !schema.OneOf.Where(static x => x.IsSemanticallyMeaningful(true)).Any(static x => !x.IsEnum())
-        ; // number and boolean enums are not supported
+                (string.IsNullOrEmpty(schema.Type) || "string".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)); // number and boolean enums are not supported
     }
     public static bool IsComposedEnum(this OpenApiSchema schema)
     {
-        return (schema.IsInclusiveUnion() && schema.AnyOf.Any(static x => x.IsEnum())) || (schema.IsExclusiveUnion() && schema.OneOf.Any(static x => x.IsEnum()));
+        if (schema is null) return false;
+        return schema.AnyOf.Count(static x => !x.IsSemanticallyMeaningful(true)) == 1 && schema.AnyOf.Count(static x => x.IsEnum()) == 1 ||
+                schema.OneOf.Count(static x => !x.IsSemanticallyMeaningful(true)) == 1 && schema.OneOf.Count(static x => x.IsEnum()) == 1;
     }
-    private static bool IsSemanticallyMeaningful(this OpenApiSchema schema, bool ignoreNullableObjects = false)
+    public static bool IsSemanticallyMeaningful(this OpenApiSchema schema, bool ignoreNullableObjects = false)
     {
+        if (schema is null) return false;
         return schema.Properties.Any() ||
+                schema.Enum is { Count: > 0 } ||
                 schema.Items != null ||
                 (!string.IsNullOrEmpty(schema.Type) &&
                     ((ignoreNullableObjects && !"object".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)) ||
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index c876f9d66d..b692c2f289 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -1830,8 +1830,9 @@ private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNo
 
         if (!string.IsNullOrEmpty(schema.Type) || !string.IsNullOrEmpty(schema.Format))
             return GetPrimitiveType(schema, string.Empty);
-        if (schema.AnyOf.Any() || schema.OneOf.Any() || schema.AllOf.Any()) // we have an empty node because of some local override for schema properties and need to unwrap it.
-            return CreateModelDeclarations(currentNode, (schema.AnyOf.FirstOrDefault() ?? schema.OneOf.FirstOrDefault() ?? schema.AllOf.FirstOrDefault())!, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody);
+        if ((schema.AnyOf.Any() || schema.OneOf.Any() || schema.AllOf.Any()) &&
+           (schema.AnyOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)) ?? schema.OneOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)) ?? schema.AllOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true))) is { } childSchema) // we have an empty node because of some local override for schema properties and need to unwrap it.
+            return CreateModelDeclarations(currentNode, childSchema, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody);
         return null;
     }
     private CodeTypeBase? CreateCollectionModelDeclaration(OpenApiUrlTreeNode currentNode, OpenApiSchema schema, OpenApiOperation? operation, CodeNamespace codeNamespace, string typeNameForInlineSchema, bool isRequestBody)


Test patch:
diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs
index 1c1985b8a5..19accd89df 100644
--- a/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs
+++ b/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs
@@ -557,7 +557,7 @@ public void IsEnumIgnoresNullableUnions()
                 }
             }
         };
-        Assert.True(schema.IsEnum());
+        Assert.False(schema.IsEnum());
     }
     [Fact]
     public void IsEnumFailsOnNullableInheritance()
@@ -591,7 +591,7 @@ public void IsEnumIgnoresNullableExclusiveUnions()
                 }
             }
         };
-        Assert.True(schema.IsEnum());
+        Assert.False(schema.IsEnum());
     }
     private static readonly OpenApiSchema numberSchema = new OpenApiSchema
     {
diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
index 5d7da8d05d..6807d654ba 100644
--- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
+++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
@@ -7299,6 +7299,132 @@ public async Task InheritanceWithAllOfWith3Parts()
         Assert.Single(resultClass.Properties.Where(x => x.Name.Equals("groupprop1", StringComparison.OrdinalIgnoreCase)));
         Assert.Single(resultClass.Properties.Where(x => x.Name.Equals("groupprop2", StringComparison.OrdinalIgnoreCase)));
     }
+    [Fact]
+    public async Task EnumsWithNullableDoesNotResultInInlineType()
+    {
+        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:
+  '/communications/calls/{call-id}/reject':
+    post:
+      requestBody:
+        description: Action parameters
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                reason:
+                  anyOf:
+                    - $ref: '#/components/schemas/microsoft.graph.rejectReason'
+                    - type: object
+                      nullable: true
+                callbackUri:
+                  type: string
+                  nullable: true
+        required: true
+      responses:
+        '204':
+          description: Success,
+components:
+  schemas:
+    microsoft.graph.rejectReason:
+      title: rejectReason
+      enum:
+        - none
+        - busy
+        - forbidden
+        - unknownFutureValue
+      type: string");
+        var mockLogger = new Mock<ILogger<KiotaBuilder>>();
+        var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath, IncludeAdditionalData = false }, _httpClient);
+        var document = await builder.CreateOpenApiDocumentAsync(fs);
+        var node = builder.CreateUriSpace(document);
+        var codeModel = builder.CreateSourceModel(node);
+        Assert.NotNull(codeModel);
+        var requestBuilderNS = codeModel.FindNamespaceByName("ApiSdk.communications.calls.item.reject");
+        Assert.NotNull(requestBuilderNS);
+        var requestBuilderClass = requestBuilderNS.FindChildByName<CodeClass>("RejectRequestBuilder", false);
+        Assert.NotNull(requestBuilderClass);
+        var reasonCandidate = requestBuilderNS.FindChildByName<CodeEnum>("RejectPostRequestBody_reason", false);
+        Assert.Null(reasonCandidate);
+        var modelsNS = codeModel.FindNamespaceByName("ApiSdk.Models");
+        Assert.NotNull(modelsNS);
+        var graphModelsNS = modelsNS.FindNamespaceByName("ApiSdk.Models.Microsoft.Graph");
+        Assert.NotNull(graphModelsNS);
+        var rejectReasonEnum = graphModelsNS.FindChildByName<CodeEnum>("RejectReason", false);
+        Assert.NotNull(rejectReasonEnum);
+    }
+
+    [Fact]
+    public async Task EnumsWithNullableDoesNotResultInInlineTypeInReveredOrder()
+    {
+        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:
+  '/communications/calls/{call-id}/reject':
+    post:
+      requestBody:
+        description: Action parameters
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                reason:
+                  anyOf:
+                    - type: object
+                      nullable: true
+                    - $ref: '#/components/schemas/microsoft.graph.rejectReason'
+                callbackUri:
+                  type: string
+                  nullable: true
+        required: true
+      responses:
+        '204':
+          description: Success,
+components:
+  schemas:
+    microsoft.graph.rejectReason:
+      title: rejectReason
+      enum:
+        - none
+        - busy
+        - forbidden
+        - unknownFutureValue
+      type: string");
+        var mockLogger = new Mock<ILogger<KiotaBuilder>>();
+        var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath, IncludeAdditionalData = false }, _httpClient);
+        var document = await builder.CreateOpenApiDocumentAsync(fs);
+        var node = builder.CreateUriSpace(document);
+        var codeModel = builder.CreateSourceModel(node);
+        Assert.NotNull(codeModel);
+        var requestBuilderNS = codeModel.FindNamespaceByName("ApiSdk.communications.calls.item.reject");
+        Assert.NotNull(requestBuilderNS);
+        var requestBuilderClass = requestBuilderNS.FindChildByName<CodeClass>("RejectRequestBuilder", false);
+        Assert.NotNull(requestBuilderClass);
+        var reasonCandidate = requestBuilderNS.FindChildByName<CodeEnum>("RejectPostRequestBody_reason", false);
+        Assert.Null(reasonCandidate);
+        var modelsNS = codeModel.FindNamespaceByName("ApiSdk.Models");
+        Assert.NotNull(modelsNS);
+        var graphModelsNS = modelsNS.FindNamespaceByName("ApiSdk.Models.Microsoft.Graph");
+        Assert.NotNull(graphModelsNS);
+        var rejectReasonEnum = graphModelsNS.FindChildByName<CodeEnum>("RejectReason", false);
+        Assert.NotNull(rejectReasonEnum);
+    }
+
     [Fact]
     public async Task AnyTypeResponse()
     {