diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 0d4ea1d3b8..24a60863c6 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -91,10 +91,10 @@ private void WriteComposedTypeSerializer(CodeFunction codeElement, LanguageWrite return; } - WriteComposedTypeSerialization(composedType, composedParam, codeElement, writer); + WriteComposedTypeSerialization(composedParam, codeElement, writer); } - private void WriteComposedTypeSerialization(CodeComposedTypeBase composedType, CodeParameter composedParam, CodeFunction codeElement, LanguageWriter writer) + private void WriteComposedTypeSerialization(CodeParameter composedParam, CodeFunction codeElement, LanguageWriter writer) { var discriminatorPropertyName = codeElement.OriginalMethodParentClass.DiscriminatorInformation.DiscriminatorPropertyName ?? throw new InvalidOperationException("Discriminator property name is required for composed type serialization"); var paramName = composedParam.Name.ToFirstCharacterLowerCase(); @@ -247,10 +247,21 @@ private string GetParseNodeParameterForPrimitiveValues(CodeFunction codeElement, private string GetFunctionName(CodeElement codeElement, string returnType, CodeMethodKind kind) { - var codeNamespace = codeElement.GetImmediateParentOfType().GetRootNamespace(); var functionName = GetFunctionName(returnType, kind); - var parent = codeNamespace.FindChildByName(functionName); - return ConventionServiceInstance.GetTypeString(new CodeType { TypeDefinition = parent }, codeElement, false); + var parentNamespace = codeElement.GetImmediateParentOfType(); + var codeFunction = FindCodeFunctionInParentNamespaces(functionName, parentNamespace); + return ConventionServiceInstance.GetTypeString(new CodeType { TypeDefinition = codeFunction }, codeElement, false); + } + + private CodeFunction? FindCodeFunctionInParentNamespaces(string functionName, CodeNamespace? parentNamespace) + { + CodeFunction? codeFunction; + do + { + codeFunction = parentNamespace?.FindChildByName(functionName); + parentNamespace = parentNamespace?.Parent?.GetImmediateParentOfType(); + } while (codeFunction is null && parentNamespace is not null); + return codeFunction; } private static string GetFunctionName(string returnType, CodeMethodKind functionKind) diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs index e6dca21b50..29c9ffc470 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs @@ -1233,5 +1233,46 @@ public async Task Writes_UnionOfPrimitiveValues_SerializerFunction() Assert.Contains("break", serializerFunctionStr); AssertExtensions.CurlyBracesAreClosed(serializerFunctionStr, 1); } + + [Fact] + public async Task Writes_UnionOfObjects_SerializerFunctions() + { + var generationConfiguration = new GenerationConfiguration { Language = GenerationLanguage.TypeScript }; + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await File.WriteAllTextAsync(tempFilePath, PetsUnion.OpenApiYaml); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Pets", OpenAPIFilePath = "https://api.apis.guru/v2/specs/github.com/api.github.com/1.1.4/openapi.json", Serializers = ["none"], Deserializers = ["none"] }, _httpClient); + await using var fs = new FileStream(tempFilePath, FileMode.Open); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + builder.SetApiRootUrl(); + var codeModel = builder.CreateSourceModel(node); + var rootNS = codeModel.FindNamespaceByName("ApiSdk"); + Assert.NotNull(rootNS); + var clientBuilder = rootNS.FindChildByName("Pets", false); + Assert.NotNull(clientBuilder); + var constructor = clientBuilder.Methods.FirstOrDefault(static x => x.IsOfKind(CodeMethodKind.ClientConstructor)); + Assert.NotNull(constructor); + Assert.Empty(constructor.SerializerModules); + Assert.Empty(constructor.DeserializerModules); + await ILanguageRefiner.Refine(generationConfiguration, rootNS); + Assert.NotNull(rootNS); + var modelsNS = rootNS.FindNamespaceByName("ApiSdk.pets"); + Assert.NotNull(modelsNS); + var modelCodeFile = modelsNS.FindChildByName("petsRequestBuilder", false); + Assert.NotNull(modelCodeFile); + + // Test Serializer function + var serializerFunction = modelCodeFile.GetChildElements().Where(x => x is CodeFunction function && GetOriginalComposedType(function.OriginalLocalMethod.Parameters.FirstOrDefault(x => GetOriginalComposedType(x) is not null)) is not null).FirstOrDefault(); + Assert.True(serializerFunction is not null); + writer.Write(serializerFunction); + var serializerFunctionStr = tw.ToString(); + Assert.Contains("return", serializerFunctionStr); + Assert.Contains("switch", serializerFunctionStr); + Assert.Contains("case \"Cat\":", serializerFunctionStr); + Assert.Contains("case \"Dog\":", serializerFunctionStr); + Assert.Contains("break", serializerFunctionStr); + AssertExtensions.CurlyBracesAreClosed(serializerFunctionStr, 1); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptConventionServiceTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptConventionServiceTests.cs index 0c200931b2..dc5ee29954 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptConventionServiceTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptConventionServiceTests.cs @@ -1,9 +1,7 @@ using System; -using Kiota.Builder; using Kiota.Builder.CodeDOM; using Kiota.Builder.Writers.TypeScript; using Xunit; -using static Kiota.Builder.CodeDOM.CodeTypeBase; namespace Kiota.Builder.Tests.Writers.TypeScript; @@ -29,4 +27,18 @@ public void GetParentOfTypeOrNull_ShouldReturnParent_WhenParentOfTypeExists() var codeElement = new CodeProperty { Name = "Test Property", Parent = parent, Type = new CodeType { Name = "test" } }; Assert.Equal(parent, TypeScriptConventionService.GetParentOfTypeOrNull(codeElement)); } + + [Fact] + public void TranslateType_ThrowsArgumentNullException_WhenComposedTypeIsNull() + { + Assert.Throws(() => TypeScriptConventionService.TranslateType(null)); + } + + [Fact] + public void TranslateType_ReturnsCorrectTranslation_WhenComposedTypeIsNotNull() + { + var composedType = new CodeUnionType { Name = "test" }; + var result = TypeScriptConventionService.TranslateType(composedType); + Assert.Equal("Test", result); + } }