From 1ad0df1c362334c3fe620df32a32b20cda80a01f Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Wed, 25 Sep 2024 06:31:13 +0300 Subject: [PATCH 01/10] fix composed types --- .../Refiners/TypeScriptRefiner.cs | 2 +- .../Writers/TypeScript/CodeFunctionWriter.cs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index a36e5b0efb..f12b6f9094 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -169,7 +169,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken GroupReusableModelsInSingleFile(modelsNamespace); RemoveSelfReferencingUsings(generatedCode); AddAliasToCodeFileUsings(generatedCode); - CorrectSerializerParameters(generatedCode); + //CorrectSerializerParameters(generatedCode); cancellationToken.ThrowIfCancellationRequested(); }, cancellationToken); } diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 5f156ba4df..44693896e6 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -90,10 +90,10 @@ private void WriteComposedTypeSerializer(CodeFunction codeElement, LanguageWrite { var paramName = composedParam.Name.ToFirstCharacterLowerCase(); writer.WriteLine($"if ({paramName} === undefined || {paramName} === null) return;"); - writer.StartBlock($"switch (typeof {paramName}) {{"); + writer.StartBlock($"switch (true) {{"); foreach (var type in composedType.Types.Where(x => IsPrimitiveType(x, composedType, false))) { - WriteCaseStatementForPrimitiveTypeSerialization(type, "key", paramName, codeElement, writer); + WriteCaseStatementForPrimitiveTypeSerialization(type, "undefined", paramName, codeElement, writer); } writer.CloseBlock(); return; @@ -110,7 +110,6 @@ private void WriteComposedTypeSerializer(CodeFunction codeElement, LanguageWrite private void WriteSerializationFunctionForCodeIntersectionType(CodeComposedTypeBase composedType, CodeParameter composedParam, CodeFunction method, LanguageWriter writer) { - // Serialization/Deserialization functions can be called for object types only foreach (var mappedType in composedType.Types.Where(x => !IsPrimitiveType(x, composedType))) { var functionName = GetSerializerFunctionName(method, mappedType); @@ -173,15 +172,18 @@ private void WriteDiscriminatorSwitchBlock(DiscriminatorInformation discriminato writer.CloseBlock(); } - private void WriteCaseStatementForPrimitiveTypeSerialization(CodeTypeBase type, string key, string value, CodeFunction method, LanguageWriter writer) + private void WriteCaseStatementForPrimitiveTypeSerialization(CodeTypeBase type, string key, string modelParamName, CodeFunction method, LanguageWriter writer) { var nodeType = conventions.GetTypeString(type, method, false); var serializationName = GetSerializationMethodName(type, method.OriginalLocalMethod); if (string.IsNullOrEmpty(serializationName) || string.IsNullOrEmpty(nodeType)) return; - writer.StartBlock($"case \"{nodeType}\":"); - writer.WriteLine($"writer.{serializationName}({key}, {value});"); - writer.WriteLine($"break;"); + writer.StartBlock(type.IsCollection + ? $"case Array.isArray({modelParamName}) && ({modelParamName}).every(item => typeof item === '{nodeType}') :" + : $"case typeof {modelParamName} === \"{nodeType}\":"); + + writer.WriteLine($"writer.{serializationName}({key}, {modelParamName} as {conventions.GetTypeString(type, method)});"); + writer.WriteLine("break;"); writer.DecreaseIndent(); } @@ -432,7 +434,7 @@ private void WriteComposedTypeSwitchClause(CodeComposedTypeBase composedType, Co if (string.IsNullOrEmpty(serializationName) || string.IsNullOrEmpty(nodeType)) return; writer.StartBlock(type.IsCollection - ? $"Array.isArray({modelParamName}.{codePropertyName}) && ({modelParamName}.{codePropertyName}).every(item => typeof item === '{nodeType}') :" + ? $"case Array.isArray({modelParamName}.{codePropertyName}) && ({modelParamName}.{codePropertyName}).every(item => typeof item === '{nodeType}') :" : $"case typeof {modelParamName}.{codePropertyName} === \"{nodeType}\":"); writer.WriteLine($"writer.{serializationName}(\"{codeProperty.WireName}\", {spreadOperator}{modelParamName}.{codePropertyName}{defaultValueSuffix} as {nodeType});"); From 5ce4e1d9ee27e58909c3f09583538a9ba0abd548 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:46:57 +0300 Subject: [PATCH 02/10] Adds Parsable Info --- .../Refiners/TypeScriptRefiner.cs | 21 -------------- .../Writers/TypeScript/CodeFunctionWriter.cs | 7 ++++- .../TypeScript/TypeScriptConventionService.cs | 29 ++++++++++++------- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index f12b6f9094..13862cb433 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -169,31 +169,10 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken GroupReusableModelsInSingleFile(modelsNamespace); RemoveSelfReferencingUsings(generatedCode); AddAliasToCodeFileUsings(generatedCode); - //CorrectSerializerParameters(generatedCode); cancellationToken.ThrowIfCancellationRequested(); }, cancellationToken); } - private static void CorrectSerializerParameters(CodeElement currentElement) - { - if (currentElement is CodeFunction currentFunction && - currentFunction.OriginalLocalMethod.Kind is CodeMethodKind.Serializer) - { - foreach (var parameter in currentFunction.OriginalLocalMethod.Parameters - .Where(p => GetOriginalComposedType(p.Type) is CodeComposedTypeBase composedType && - composedType.IsComposedOfObjectsAndPrimitives(IsPrimitiveType))) - { - var composedType = GetOriginalComposedType(parameter.Type)!; - var newType = (CodeComposedTypeBase)composedType.Clone(); - var nonPrimitiveTypes = composedType.Types.Where(x => !IsPrimitiveType(x, composedType)).ToArray(); - newType.SetTypes(nonPrimitiveTypes); - parameter.Type = newType; - } - } - - CrawlTree(currentElement, CorrectSerializerParameters); - } - private static void AddAliasToCodeFileUsings(CodeElement currentElement) { if (currentElement is CodeFile codeFile) diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 44693896e6..85996980ae 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -70,6 +70,11 @@ private void WriteComposedTypeDeserializer(CodeFunction codeElement, LanguageWri if (GetOriginalComposedType(composedParam) is not { } composedType) return; writer.StartBlock("return {"); + if (composedType.Types.Any(x => IsPrimitiveType(x, composedType, false))) + { + var expression = string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType, false)).Select(codeType => $"n.{conventions.GetDeserializationMethodName(codeType, codeElement.OriginalLocalMethod, composedType.IsCollection)}")); + writer.WriteLine($"\"\": n => {{ {composedParam.Name.ToFirstCharacterLowerCase()} = {expression}}},"); + } foreach (var mappedType in composedType.Types.Where(x => !IsPrimitiveType(x, composedType, false))) { var functionName = GetDeserializerFunctionName(codeElement, mappedType); @@ -181,7 +186,7 @@ private void WriteCaseStatementForPrimitiveTypeSerialization(CodeTypeBase type, writer.StartBlock(type.IsCollection ? $"case Array.isArray({modelParamName}) && ({modelParamName}).every(item => typeof item === '{nodeType}') :" : $"case typeof {modelParamName} === \"{nodeType}\":"); - + writer.WriteLine($"writer.{serializationName}({key}, {modelParamName} as {conventions.GetTypeString(type, method)});"); writer.WriteLine("break;"); writer.DecreaseIndent(); diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index 3e4bced511..928c7c6621 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -81,19 +81,24 @@ public override string GetAccessModifier(AccessModifier access) }; } - private static bool ShouldIncludeCollectionInformationForParameter(CodeParameter parameter) - { - return !(GetOriginalComposedType(parameter) is not null - && parameter.Parent is CodeMethod codeMethod - && (codeMethod.IsOfKind(CodeMethodKind.Serializer) || codeMethod.IsOfKind(CodeMethodKind.Deserializer))); - } - public override string GetParameterSignature(CodeParameter parameter, CodeElement targetElement, LanguageWriter? writer = null) { ArgumentNullException.ThrowIfNull(parameter); - var includeCollectionInformation = ShouldIncludeCollectionInformationForParameter(parameter); - var paramType = GetTypescriptTypeString(parameter.Type, targetElement, includeCollectionInformation: includeCollectionInformation, inlineComposedTypeString: true); - var isComposedOfPrimitives = GetOriginalComposedType(parameter.Type) is CodeComposedTypeBase composedType && composedType.IsComposedOfPrimitives(IsPrimitiveType); + var paramType = GetTypescriptTypeString(parameter.Type, targetElement, includeCollectionInformation: true, inlineComposedTypeString: true); + var composedType = GetOriginalComposedType(parameter.Type); + var isComposedOfPrimitives = composedType != null && composedType.IsComposedOfPrimitives(IsPrimitiveType); + + // add a 'Parsable' suffix to composed parameters of primitives only if they are not deserialization targets + var parsableTypes = ( + composedType != null && composedType.IsComposedOfPrimitives(IsPrimitiveTypeOrPrimitiveCollection), + parameter.Parent is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer) + ) switch + { + (true, false) => string.Empty, + (true, true) => "Parsable | ", + _ => string.Empty, + }; + var defaultValueSuffix = (string.IsNullOrEmpty(parameter.DefaultValue), parameter.Kind, isComposedOfPrimitives) switch { (false, CodeParameterKind.DeserializationTarget, false) when parameter.Parent is CodeMethod codeMethod && codeMethod.Kind is CodeMethodKind.Serializer @@ -107,7 +112,7 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen (false, CodeParameterKind.DeserializationTarget) => ("Partial<", ">"), _ => (string.Empty, string.Empty), }; - return $"{parameter.Name.ToFirstCharacterLowerCase()}{(parameter.Optional && parameter.Type.IsNullable ? "?" : string.Empty)}: {partialPrefix}{paramType}{partialSuffix}{(parameter.Type.IsNullable ? " | undefined" : string.Empty)}{defaultValueSuffix}"; + return $"{parameter.Name.ToFirstCharacterLowerCase()}{(parameter.Optional && parameter.Type.IsNullable ? "?" : string.Empty)}: {partialPrefix}{parsableTypes}{paramType}{partialSuffix}{(parameter.Type.IsNullable ? " | undefined" : string.Empty)}{defaultValueSuffix}"; } public override string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool includeCollectionInformation = true, LanguageWriter? writer = null) @@ -235,6 +240,8 @@ TYPE_LOWERCASE_BOOLEAN or public static bool IsPrimitiveType(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase) => IsPrimitiveType(codeType, codeComposedTypeBase, true); + public static bool IsPrimitiveTypeOrPrimitiveCollection(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase) => IsPrimitiveType(codeType, codeComposedTypeBase, false); + public static bool IsPrimitiveType(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase, bool includeCollectionInformation) => IsPrimitiveType(GetTypescriptTypeString(codeType, codeComposedTypeBase, includeCollectionInformation)); internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription?.Replace("\\", "/", StringComparison.OrdinalIgnoreCase) ?? string.Empty; From 02a6c0754d461763741ab74dd69dc0a8a42feb80 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:55:47 +0300 Subject: [PATCH 03/10] Fix composed serializers Fix import statements fix - rewrite to if statements --- .../Refiners/TypeScriptRefiner.cs | 2 +- .../TypeScript/CodeFileDeclarationWriter.cs | 2 +- .../Writers/TypeScript/CodeFunctionWriter.cs | 44 ++++++++++--------- .../Writers/TypeScript/CodeMethodWriter.cs | 13 +++--- .../TypeScript/TypeScriptConventionService.cs | 22 +++++++--- .../TypeScript/CodeFunctionWriterTests.cs | 10 ++--- 6 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 13862cb433..4b634c7d08 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -1461,7 +1461,7 @@ private static void AddDeserializerUsingToDiscriminatorFactoryForComposedTypePar function.AddUsing(new CodeUsing { - Name = modelDeserializerFunction.Parent.Name, + Name = modelDeserializerFunction.Name, Declaration = new CodeType { Name = modelDeserializerFunction.Name, diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs index cf712fc289..e4ba3e766b 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs @@ -40,7 +40,7 @@ public override void WriteCodeElement(CodeFileDeclaration codeElement, LanguageW .Where(static x => x is { IsExternal: false, Declaration.TypeDefinition: not null }) .GroupBy(static x => $"{x.Declaration!.TypeDefinition!.GetImmediateParentOfType().Name}.{x.Declaration?.Name.ToLowerInvariant()}") - .Select(static x => x.OrderBy(static x => x.Parent?.Name).First())); + .Select(static x => x.OrderByDescending(static x => x.Alias, StringComparer.OrdinalIgnoreCase).First())); _codeUsingWriter.WriteCodeElement(filteredUsing, ns, writer); } diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 85996980ae..3af93b703e 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -29,7 +29,7 @@ public override void WriteCodeElement(CodeFunction codeElement, LanguageWriter w FactoryMethodReturnType : GetTypescriptTypeString(codeMethod.ReturnType, codeElement, inlineComposedTypeString: true); var isVoid = "void".EqualsIgnoreCase(returnType); - CodeMethodWriter.WriteMethodDocumentationInternal(codeElement.OriginalLocalMethod, writer, isVoid, conventions); + CodeMethodWriter.WriteMethodDocumentationInternal(codeElement.GetImmediateParentOfType(), codeElement.OriginalLocalMethod, writer, isVoid, conventions); CodeMethodWriter.WriteMethodTypecheckIgnoreInternal(codeElement.OriginalLocalMethod, writer); CodeMethodWriter.WriteMethodPrototypeInternal(codeElement.OriginalLocalMethod, writer, returnType, isVoid, conventions, true); @@ -73,7 +73,7 @@ private void WriteComposedTypeDeserializer(CodeFunction codeElement, LanguageWri if (composedType.Types.Any(x => IsPrimitiveType(x, composedType, false))) { var expression = string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType, false)).Select(codeType => $"n.{conventions.GetDeserializationMethodName(codeType, codeElement.OriginalLocalMethod, composedType.IsCollection)}")); - writer.WriteLine($"\"\": n => {{ {composedParam.Name.ToFirstCharacterLowerCase()} = {expression}}},"); + writer.WriteLine($"\"\" : n => {{ {composedParam.Name.ToFirstCharacterLowerCase()} = {expression}}},"); } foreach (var mappedType in composedType.Types.Where(x => !IsPrimitiveType(x, composedType, false))) { @@ -95,12 +95,13 @@ private void WriteComposedTypeSerializer(CodeFunction codeElement, LanguageWrite { var paramName = composedParam.Name.ToFirstCharacterLowerCase(); writer.WriteLine($"if ({paramName} === undefined || {paramName} === null) return;"); - writer.StartBlock($"switch (true) {{"); + bool isFirst = true; foreach (var type in composedType.Types.Where(x => IsPrimitiveType(x, composedType, false))) { - WriteCaseStatementForPrimitiveTypeSerialization(type, "undefined", paramName, codeElement, writer); + var ifElse = isFirst ? "" : "else "; + WriteCaseStatementForPrimitiveTypeSerialization(type, "undefined", paramName, codeElement, writer, ifElse); + isFirst = false; } - writer.CloseBlock(); return; } @@ -177,19 +178,18 @@ private void WriteDiscriminatorSwitchBlock(DiscriminatorInformation discriminato writer.CloseBlock(); } - private void WriteCaseStatementForPrimitiveTypeSerialization(CodeTypeBase type, string key, string modelParamName, CodeFunction method, LanguageWriter writer) + private void WriteCaseStatementForPrimitiveTypeSerialization(CodeTypeBase type, string key, string modelParamName, CodeFunction method, LanguageWriter writer, String prefix) { var nodeType = conventions.GetTypeString(type, method, false); var serializationName = GetSerializationMethodName(type, method.OriginalLocalMethod); if (string.IsNullOrEmpty(serializationName) || string.IsNullOrEmpty(nodeType)) return; writer.StartBlock(type.IsCollection - ? $"case Array.isArray({modelParamName}) && ({modelParamName}).every(item => typeof item === '{nodeType}') :" - : $"case typeof {modelParamName} === \"{nodeType}\":"); + ? $"{prefix}if (Array.isArray({modelParamName}) && ({modelParamName}).every(item => typeof item === '{nodeType}')) {{" + : $"{prefix}if (typeof {modelParamName} === \"{nodeType}\" ) {{"); writer.WriteLine($"writer.{serializationName}({key}, {modelParamName} as {conventions.GetTypeString(type, method)});"); - writer.WriteLine("break;"); - writer.DecreaseIndent(); + writer.CloseBlock(); } private static void WriteApiConstructorBody(CodeFile parentFile, CodeMethod method, LanguageWriter writer) @@ -336,7 +336,10 @@ private string FindFunctionInNameSpace(string functionName, CodeElement codeElem var codeFunction = Array.Find(codeFunctions, func => func.GetImmediateParentOfType().Name == myNamespace.Name) ?? throw new InvalidOperationException($"Function {functionName} not found in namespace {myNamespace.Name}"); - return conventions.GetTypeString(new CodeType { TypeDefinition = codeFunction }, codeElement, false); + + var targetElement = codeElement.GetImmediateParentOfType(); + + return GetTypescriptTypeString(new CodeType { TypeDefinition = codeFunction }, targetElement, includeCollectionInformation: false); } private void WriteSerializerFunction(CodeFunction codeElement, LanguageWriter writer) @@ -420,30 +423,31 @@ private void WritePropertySerializationStatement(CodeProperty codeProperty, stri private void WriteSerializationStatementForComposedTypeProperty(CodeComposedTypeBase composedType, string modelParamName, CodeFunction method, LanguageWriter writer, CodeProperty codeProperty, string? serializeName) { var defaultValueSuffix = GetDefaultValueLiteralForProperty(codeProperty) is string dft && !string.IsNullOrEmpty(dft) && !dft.EqualsIgnoreCase("\"null\"") ? $" ?? {dft}" : string.Empty; - writer.StartBlock("switch (true) {"); - WriteComposedTypeSwitchClause(composedType, method, writer, codeProperty, modelParamName, defaultValueSuffix); + WriteComposedTypeIfClause(composedType, method, writer, codeProperty, modelParamName, defaultValueSuffix); WriteComposedTypeDefaultClause(composedType, writer, codeProperty, modelParamName, defaultValueSuffix, serializeName); - writer.CloseBlock(); } - private void WriteComposedTypeSwitchClause(CodeComposedTypeBase composedType, CodeFunction method, LanguageWriter writer, CodeProperty codeProperty, string modelParamName, string defaultValueSuffix) + private void WriteComposedTypeIfClause(CodeComposedTypeBase composedType, CodeFunction method, LanguageWriter writer, CodeProperty codeProperty, string modelParamName, string defaultValueSuffix) { var codePropertyName = codeProperty.Name.ToFirstCharacterLowerCase(); var isCollectionOfEnum = IsCollectionOfEnum(codeProperty); var spreadOperator = isCollectionOfEnum ? "..." : string.Empty; + bool isFirst = true; foreach (var type in composedType.Types.Where(x => IsPrimitiveType(x, composedType))) { + var isElse = isFirst ? "" : "else "; var nodeType = conventions.GetTypeString(type, method, false); var serializationName = GetSerializationMethodName(type, method.OriginalLocalMethod); if (string.IsNullOrEmpty(serializationName) || string.IsNullOrEmpty(nodeType)) return; writer.StartBlock(type.IsCollection - ? $"case Array.isArray({modelParamName}.{codePropertyName}) && ({modelParamName}.{codePropertyName}).every(item => typeof item === '{nodeType}') :" - : $"case typeof {modelParamName}.{codePropertyName} === \"{nodeType}\":"); + ? $"{isElse}if (Array.isArray({modelParamName}.{codePropertyName}) && ({modelParamName}.{codePropertyName}).every(item => typeof item === '{nodeType}')) {{" + : $"{isElse}if ( typeof {modelParamName}.{codePropertyName} === \"{nodeType}\") {{"); writer.WriteLine($"writer.{serializationName}(\"{codeProperty.WireName}\", {spreadOperator}{modelParamName}.{codePropertyName}{defaultValueSuffix} as {nodeType});"); - writer.CloseBlock("break;"); + writer.CloseBlock(); + isFirst = false; } } @@ -453,7 +457,7 @@ private static void WriteComposedTypeDefaultClause(CodeComposedTypeBase composed var nonPrimitiveTypes = composedType.Types.Where(x => !IsPrimitiveType(x, composedType)).ToArray(); if (nonPrimitiveTypes.Length > 0) { - writer.StartBlock("default:"); + writer.StartBlock("else {"); foreach (var groupedTypes in nonPrimitiveTypes.GroupBy(static x => x.IsCollection)) { var collectionCodeType = (composedType.Clone() as CodeComposedTypeBase)!; @@ -466,7 +470,7 @@ private static void WriteComposedTypeDefaultClause(CodeComposedTypeBase composed writer.WriteLine($"writer.{writerFunction}<{propTypeName}>(\"{codeProperty.WireName}\", {modelParamName}.{codePropertyName}{defaultValueSuffix} as {propTypeName}{groupSymbol}{propertyTypes}, {serializeName});"); } - writer.CloseBlock("break;"); + writer.CloseBlock(); } } diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs index ce8ae9769b..3741c468a8 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs @@ -16,19 +16,20 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri ArgumentNullException.ThrowIfNull(writer); if (codeElement.Parent is CodeFunction) return; - var returnType = GetTypescriptTypeString(codeElement.ReturnType, codeElement, inlineComposedTypeString: true); + var codeFile = codeElement.GetImmediateParentOfType(); + var returnType = GetTypescriptTypeString(codeElement.ReturnType, codeFile, inlineComposedTypeString: true); var isVoid = "void".EqualsIgnoreCase(returnType); - WriteMethodDocumentation(codeElement, writer, isVoid); + WriteMethodDocumentation(codeFile, codeElement, writer, isVoid); WriteMethodPrototype(codeElement, writer, returnType, isVoid); if (codeElement.Parent is CodeClass) throw new InvalidOperationException("No method implementations are generated in typescript: either functions or constants."); } - private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer, bool isVoid) + private void WriteMethodDocumentation(CodeFile codeFile, CodeMethod code, LanguageWriter writer, bool isVoid) { - WriteMethodDocumentationInternal(code, writer, isVoid, conventions); + WriteMethodDocumentationInternal(codeFile, code, writer, isVoid, conventions); } - internal static void WriteMethodDocumentationInternal(CodeMethod code, LanguageWriter writer, bool isVoid, TypeScriptConventionService typeScriptConventionService) + internal static void WriteMethodDocumentationInternal(CodeFile codeFile, CodeMethod code, LanguageWriter writer, bool isVoid, TypeScriptConventionService typeScriptConventionService) { var returnRemark = (isVoid, code.IsAsync) switch { @@ -41,7 +42,7 @@ internal static void WriteMethodDocumentationInternal(CodeMethod code, LanguageW code.Parameters .Where(static x => x.Documentation.DescriptionAvailable) .OrderBy(static x => x.Name) - .Select(x => $"@param {x.Name} {x.Documentation.GetDescription(type => GetTypescriptTypeString(type, code, inlineComposedTypeString: true), ReferenceTypePrefix, ReferenceTypeSuffix, RemoveInvalidDescriptionCharacters)}") + .Select(x => $"@param {x.Name} {x.Documentation.GetDescription(type => GetTypescriptTypeString(type, codeFile, inlineComposedTypeString: true), ReferenceTypePrefix, ReferenceTypeSuffix, RemoveInvalidDescriptionCharacters)}") .Union([returnRemark]) .Union(GetThrownExceptionsRemarks(code))); } diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index 928c7c6621..b8321afccc 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -84,17 +84,25 @@ public override string GetAccessModifier(AccessModifier access) public override string GetParameterSignature(CodeParameter parameter, CodeElement targetElement, LanguageWriter? writer = null) { ArgumentNullException.ThrowIfNull(parameter); - var paramType = GetTypescriptTypeString(parameter.Type, targetElement, includeCollectionInformation: true, inlineComposedTypeString: true); var composedType = GetOriginalComposedType(parameter.Type); + var paramType = GetTypescriptTypeString(parameter.Type, targetElement, includeCollectionInformation: true, inlineComposedTypeString: true); + + if (composedType != null && parameter.Parent is CodeMethod cm && cm.IsOfKind(CodeMethodKind.Serializer)) + { + // eliminate primitive types from serializers with composed type signature + var newType = (CodeComposedTypeBase)composedType.Clone(); + var nonPrimitiveTypes = composedType.Types.Where(x => !IsPrimitiveTypeOrPrimitiveCollection(x, composedType)).ToArray(); + newType.SetTypes(nonPrimitiveTypes); + paramType = GetTypescriptTypeString(newType, targetElement, includeCollectionInformation: true, inlineComposedTypeString: true); + } var isComposedOfPrimitives = composedType != null && composedType.IsComposedOfPrimitives(IsPrimitiveType); - // add a 'Parsable' suffix to composed parameters of primitives only if they are not deserialization targets + // add a 'Parsable' type to the parameter if it is composed of non-Parsable types var parsableTypes = ( - composedType != null && composedType.IsComposedOfPrimitives(IsPrimitiveTypeOrPrimitiveCollection), - parameter.Parent is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer) + composedType != null, + parameter.Parent is CodeMethod method && (method.IsOfKind(CodeMethodKind.Deserializer, CodeMethodKind.Serializer)) ) switch { - (true, false) => string.Empty, (true, true) => "Parsable | ", _ => string.Empty, }; @@ -240,10 +248,10 @@ TYPE_LOWERCASE_BOOLEAN or public static bool IsPrimitiveType(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase) => IsPrimitiveType(codeType, codeComposedTypeBase, true); - public static bool IsPrimitiveTypeOrPrimitiveCollection(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase) => IsPrimitiveType(codeType, codeComposedTypeBase, false); - public static bool IsPrimitiveType(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase, bool includeCollectionInformation) => IsPrimitiveType(GetTypescriptTypeString(codeType, codeComposedTypeBase, includeCollectionInformation)); + private static bool IsPrimitiveTypeOrPrimitiveCollection(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase) => IsPrimitiveType(codeType, codeComposedTypeBase, false); + internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription?.Replace("\\", "/", StringComparison.OrdinalIgnoreCase) ?? string.Empty; public override bool WriteShortDescription(IDocumentedElement element, LanguageWriter writer, string prefix = "", string suffix = "") { diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs index b2894a186a..6eee533f97 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs @@ -1252,10 +1252,8 @@ public async Task Writes_UnionOfPrimitiveValues_SerializerFunctionAsync() writer.Write(serializerFunction); var serializerFunctionStr = tw.ToString(); Assert.Contains("return", serializerFunctionStr); - Assert.Contains("switch", serializerFunctionStr); - Assert.Contains("case \"number\":", serializerFunctionStr); - Assert.Contains("case \"string\":", serializerFunctionStr); - Assert.Contains("break", serializerFunctionStr); + Assert.Contains("typeof primitives === \"number\"", serializerFunctionStr); + Assert.Contains("typeof primitives === \"string\"", serializerFunctionStr); AssertExtensions.CurlyBracesAreClosed(serializerFunctionStr, 1); } @@ -1454,9 +1452,9 @@ public async Task Writes_CodeUnionBetweenObjectsAndPrimitiveTypes_SerializerAsyn writer.Write(serializeFunction); var result = tw.ToString(); - Assert.Contains("case typeof parentClass.property === \"string\"", result); + Assert.Contains("typeof parentClass.property === \"string\"", result); Assert.Contains("writer.writeStringValue(\"property\", parentClass.property as string);", result); - Assert.Contains("case typeof parentClass.property === \"number\"", result); + Assert.Contains("typeof parentClass.property === \"number\"", result); Assert.Contains("writer.writeNumberValue(\"property\", parentClass.property as number);", result); Assert.Contains( "writer.writeCollectionOfObjectValues(\"property\", parentClass.property as ArrayOfObjects[] | undefined | null", From a1d616a5fa450b28cd05a6bb3169970973b75756 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:08:05 +0300 Subject: [PATCH 04/10] Enable intergration tests --- it/config.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/it/config.json b/it/config.json index 00a3447d85..78f4d857ab 100644 --- a/it/config.json +++ b/it/config.json @@ -217,10 +217,6 @@ { "Language": "php", "Rationale": "https://github.com/microsoft/kiota/issues/5354" - }, - { - "Language": "typescript", - "Rationale": "https://github.com/microsoft/kiota/issues/5353" } ], "IdempotencySuppressions": [ From 42840b37c395fb984bd2d2903c668deb157a9ebd Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:04:13 +0300 Subject: [PATCH 05/10] fix missing refrences --- .../Writers/TypeScript/CodeFunctionWriter.cs | 39 ++++++++++--------- .../TypeScript/TypeScriptConventionService.cs | 16 ++++---- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 3af93b703e..41857b0d3f 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -29,7 +29,8 @@ public override void WriteCodeElement(CodeFunction codeElement, LanguageWriter w FactoryMethodReturnType : GetTypescriptTypeString(codeMethod.ReturnType, codeElement, inlineComposedTypeString: true); var isVoid = "void".EqualsIgnoreCase(returnType); - CodeMethodWriter.WriteMethodDocumentationInternal(codeElement.GetImmediateParentOfType(), codeElement.OriginalLocalMethod, writer, isVoid, conventions); + var codeFile = codeElement.GetImmediateParentOfType(); + CodeMethodWriter.WriteMethodDocumentationInternal(codeFile, codeElement.OriginalLocalMethod, writer, isVoid, conventions); CodeMethodWriter.WriteMethodTypecheckIgnoreInternal(codeElement.OriginalLocalMethod, writer); CodeMethodWriter.WriteMethodPrototypeInternal(codeElement.OriginalLocalMethod, writer, returnType, isVoid, conventions, true); @@ -38,13 +39,13 @@ public override void WriteCodeElement(CodeFunction codeElement, LanguageWriter w switch (codeMethod.Kind) { case CodeMethodKind.Deserializer: - WriteDeserializerFunction(codeElement, writer); + WriteDeserializerFunction(codeElement, codeFile, writer); break; case CodeMethodKind.Serializer: WriteSerializerFunction(codeElement, writer); break; case CodeMethodKind.Factory: - WriteFactoryMethod(codeElement, writer); + WriteFactoryMethod(codeElement, codeFile, writer); break; case CodeMethodKind.ClientConstructor: WriteApiConstructorBody(parentFile, codeMethod, writer); @@ -53,10 +54,10 @@ public override void WriteCodeElement(CodeFunction codeElement, LanguageWriter w } } - private string GetSerializationMethodsForPrimitiveUnionTypes(CodeComposedTypeBase composedType, string parseNodeParameterName, CodeFunction codeElement, bool nodeParameterCanBeNull = true) + private string GetSerializationMethodsForPrimitiveUnionTypes(CodeComposedTypeBase composedType, string parseNodeParameterName, CodeFunction codeElement, CodeFile codeFile, bool nodeParameterCanBeNull = true) { var optionalChainingSymbol = nodeParameterCanBeNull ? "?" : string.Empty; - return string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType)).Select(x => $"{parseNodeParameterName}{optionalChainingSymbol}." + conventions.GetDeserializationMethodName(x, codeElement.OriginalLocalMethod))); + return string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType)).Select(x => $"{parseNodeParameterName}{optionalChainingSymbol}." + conventions.GetDeserializationMethodName(x, codeFile))); } private static CodeParameter? GetComposedTypeParameter(CodeFunction codeElement) @@ -64,7 +65,7 @@ private string GetSerializationMethodsForPrimitiveUnionTypes(CodeComposedTypeBas return codeElement.OriginalLocalMethod.Parameters.FirstOrDefault(x => GetOriginalComposedType(x) is not null); } - private void WriteComposedTypeDeserializer(CodeFunction codeElement, LanguageWriter writer, CodeParameter composedParam) + private void WriteComposedTypeDeserializer(CodeFunction codeElement, LanguageWriter writer, CodeParameter composedParam, CodeFile codeFile) { if (GetOriginalComposedType(composedParam) is not { } composedType) return; @@ -72,7 +73,7 @@ private void WriteComposedTypeDeserializer(CodeFunction codeElement, LanguageWri writer.StartBlock("return {"); if (composedType.Types.Any(x => IsPrimitiveType(x, composedType, false))) { - var expression = string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType, false)).Select(codeType => $"n.{conventions.GetDeserializationMethodName(codeType, codeElement.OriginalLocalMethod, composedType.IsCollection)}")); + var expression = string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType, false)).Select(codeType => $"n.{conventions.GetDeserializationMethodName(codeType, codeFile, composedType.IsCollection)}")); writer.WriteLine($"\"\" : n => {{ {composedParam.Name.ToFirstCharacterLowerCase()} = {expression}}},"); } foreach (var mappedType in composedType.Types.Where(x => !IsPrimitiveType(x, composedType, false))) @@ -222,16 +223,16 @@ private static void WriteSerializationRegistration(HashSet serialization writer.WriteLine($"{methodName}({module});"); } - private void WriteFactoryMethod(CodeFunction codeElement, LanguageWriter writer) + private void WriteFactoryMethod(CodeFunction codeElement, CodeFile codeFile, LanguageWriter writer) { var returnType = conventions.GetTypeString(codeElement.OriginalLocalMethod.ReturnType, codeElement); if (codeElement.OriginalMethodParentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) WriteDefensiveStatements(codeElement.OriginalLocalMethod, writer); - WriteFactoryMethodBody(codeElement, returnType, writer); + WriteFactoryMethodBody(codeElement, returnType, codeFile, writer); } - private void WriteFactoryMethodBody(CodeFunction codeElement, string returnType, LanguageWriter writer) + private void WriteFactoryMethodBody(CodeFunction codeElement, string returnType, CodeFile codeFile, LanguageWriter writer) { var parseNodeParameter = codeElement.OriginalLocalMethod.Parameters.OfKind(CodeParameterKind.ParseNode); var composedType = GetOriginalComposedType(codeElement.OriginalLocalMethod.ReturnType); @@ -239,7 +240,7 @@ private void WriteFactoryMethodBody(CodeFunction codeElement, string returnType, switch (composedType) { case CodeComposedTypeBase type when type.IsComposedOfPrimitives(IsPrimitiveType): - string primitiveValuesUnionString = GetSerializationMethodsForPrimitiveUnionTypes(composedType, parseNodeParameter!.Name.ToFirstCharacterLowerCase(), codeElement); + string primitiveValuesUnionString = GetSerializationMethodsForPrimitiveUnionTypes(composedType, parseNodeParameter!.Name.ToFirstCharacterLowerCase(), codeElement, codeFile); writer.WriteLine($"return {primitiveValuesUnionString};"); break; case CodeUnionType _ when parseNodeParameter != null: @@ -524,19 +525,19 @@ _ when conventions.StreamTypeName.Equals(propertyType, StringComparison.OrdinalI }; } - private void WriteDeserializerFunction(CodeFunction codeFunction, LanguageWriter writer) + private void WriteDeserializerFunction(CodeFunction codeFunction, CodeFile codeFile, LanguageWriter writer) { var composedParam = GetComposedTypeParameter(codeFunction); if (composedParam is not null) { - WriteComposedTypeDeserializer(codeFunction, writer, composedParam); + WriteComposedTypeDeserializer(codeFunction, writer, composedParam, codeFile); return; } var param = codeFunction.OriginalLocalMethod.Parameters.FirstOrDefault(); if (param?.Type is CodeType codeType && codeType.TypeDefinition is CodeInterface codeInterface) { - WriteDeserializerFunctionProperties(param, codeInterface, codeFunction, writer); + WriteDeserializerFunctionProperties(param, codeInterface, codeFunction, codeFile, writer); } else { @@ -544,7 +545,7 @@ private void WriteDeserializerFunction(CodeFunction codeFunction, LanguageWriter } } - private void WriteDeserializerFunctionProperties(CodeParameter param, CodeInterface codeInterface, CodeFunction codeFunction, LanguageWriter writer) + private void WriteDeserializerFunctionProperties(CodeParameter param, CodeInterface codeInterface, CodeFunction codeFunction, CodeFile codeFile, LanguageWriter writer) { var properties = codeInterface.Properties.Where(static x => x.IsOfKind(CodePropertyKind.Custom, CodePropertyKind.BackingStore) && !x.ExistsInBaseType); @@ -557,7 +558,7 @@ private void WriteDeserializerFunctionProperties(CodeParameter param, CodeInterf foreach (var otherProp in properties) { - WritePropertyDeserializationBlock(otherProp, param, primaryErrorMapping, primaryErrorMappingKey, codeFunction, writer); + WritePropertyDeserializationBlock(otherProp, param, primaryErrorMapping, primaryErrorMappingKey, codeFile, writer); } writer.CloseBlock(); @@ -578,7 +579,7 @@ private static (string, string) GetPrimaryErrorMapping(CodeFunction codeFunction return (primaryErrorMapping, primaryErrorMappingKey); } - private void WritePropertyDeserializationBlock(CodeProperty otherProp, CodeParameter param, string primaryErrorMapping, string primaryErrorMappingKey, CodeFunction codeFunction, LanguageWriter writer) + private void WritePropertyDeserializationBlock(CodeProperty otherProp, CodeParameter param, string primaryErrorMapping, string primaryErrorMappingKey, CodeFile codeFile, LanguageWriter writer) { var suffix = otherProp.Name.Equals(primaryErrorMappingKey, StringComparison.Ordinal) ? primaryErrorMapping : string.Empty; var paramName = param.Name.ToFirstCharacterLowerCase(); @@ -590,12 +591,12 @@ private void WritePropertyDeserializationBlock(CodeProperty otherProp, CodeParam } else if (GetOriginalComposedType(otherProp.Type) is { } composedType) { - var expression = string.Join(" ?? ", composedType.Types.Select(codeType => $"n.{conventions.GetDeserializationMethodName(codeType, codeFunction.OriginalLocalMethod, composedType.IsCollection)}")); + var expression = string.Join(" ?? ", composedType.Types.Select(codeType => $"n.{conventions.GetDeserializationMethodName(codeType, codeFile, composedType.IsCollection)}")); writer.WriteLine($"\"{otherProp.WireName}\": n => {{ {paramName}.{propName} = {expression};{suffix} }},"); } else { - var objectSerializationMethodName = conventions.GetDeserializationMethodName(otherProp.Type, codeFunction.OriginalLocalMethod); + var objectSerializationMethodName = conventions.GetDeserializationMethodName(otherProp.Type, codeFile); var defaultValueSuffix = GetDefaultValueSuffix(otherProp); writer.WriteLine($"\"{otherProp.WireName}\": n => {{ {paramName}.{propName} = n.{objectSerializationMethodName}{defaultValueSuffix};{suffix} }},"); } diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index b8321afccc..651cfc1724 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -323,12 +323,12 @@ public static string GetFactoryMethodName(CodeTypeBase targetClassType, CodeElem return definitionClass.GetImmediateParentOfType(definitionClass)?.FindChildByName(factoryMethodName); } - public string GetDeserializationMethodName(CodeTypeBase codeType, CodeMethod method, bool? IsCollection = null) + public string GetDeserializationMethodName(CodeTypeBase codeType, CodeElement targetElement, bool? IsCollection = null) { ArgumentNullException.ThrowIfNull(codeType); - ArgumentNullException.ThrowIfNull(method); + ArgumentNullException.ThrowIfNull(targetElement); var isCollection = IsCollection == true || codeType.IsCollection; - var propertyType = GetTypescriptTypeString(codeType, method, false); + var propertyType = GetTypescriptTypeString(codeType, targetElement, false); CodeTypeBase _codeType = GetOriginalComposedType(codeType) is CodeComposedTypeBase composedType ? new CodeType() { Name = composedType.Name, TypeDefinition = composedType } : codeType; @@ -339,19 +339,19 @@ public string GetDeserializationMethodName(CodeTypeBase codeType, CodeMethod met (CodeEnum currentEnum, _, _) when currentEnum.CodeEnumObject is not null => $"{(currentEnum.Flags || isCollection ? "getCollectionOfEnumValues" : "getEnumValue")}<{currentEnum.Name.ToFirstCharacterUpperCase()}>({currentEnum.CodeEnumObject.Name.ToFirstCharacterUpperCase()})", (_, _, _) when StreamTypeName.Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "getByteArrayValue", (_, true, _) when currentType.TypeDefinition is null => $"getCollectionOfPrimitiveValues<{propertyType}>()", - (_, true, _) => $"getCollectionOfObjectValues<{propertyType.ToFirstCharacterUpperCase()}>({GetFactoryMethodName(_codeType, method)})", - _ => GetDeserializationMethodNameForPrimitiveOrObject(_codeType, propertyType, method) + (_, true, _) => $"getCollectionOfObjectValues<{propertyType.ToFirstCharacterUpperCase()}>({GetFactoryMethodName(_codeType, targetElement)})", + _ => GetDeserializationMethodNameForPrimitiveOrObject(_codeType, propertyType, targetElement) }; } - return GetDeserializationMethodNameForPrimitiveOrObject(_codeType, propertyType, method); + return GetDeserializationMethodNameForPrimitiveOrObject(_codeType, propertyType, targetElement); } - private static string GetDeserializationMethodNameForPrimitiveOrObject(CodeTypeBase propType, string propertyTypeName, CodeMethod method) + private static string GetDeserializationMethodNameForPrimitiveOrObject(CodeTypeBase propType, string propertyTypeName, CodeElement targetElement) { return propertyTypeName switch { TYPE_LOWERCASE_STRING or TYPE_STRING or TYPE_LOWERCASE_BOOLEAN or TYPE_BOOLEAN or TYPE_NUMBER or TYPE_GUID or TYPE_DATE or TYPE_DATE_ONLY or TYPE_TIME_ONLY or TYPE_DURATION => $"get{propertyTypeName.ToFirstCharacterUpperCase()}Value()", - _ => $"getObjectValue<{propertyTypeName.ToFirstCharacterUpperCase()}>({GetFactoryMethodName(propType, method)})" + _ => $"getObjectValue<{propertyTypeName.ToFirstCharacterUpperCase()}>({GetFactoryMethodName(propType, targetElement)})" }; } } From c80b0f35ef0309e3294ed9beee758f026e229626 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:42:17 +0300 Subject: [PATCH 06/10] fix composable discriminator --- src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs | 1 + .../Writers/TypeScript/TypeScriptConventionService.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs b/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs index d2b5241d37..754472bf65 100644 --- a/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs +++ b/src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs @@ -87,5 +87,6 @@ public bool IsComposedOfObjectsAndPrimitives(Func checkIfPrimitive(x, this)) && Types.Any(x => !checkIfPrimitive(x, this)); } + public bool IsComposedOfObjects(Func checkIfPrimitive) => Types.All(x => !checkIfPrimitive(x, this)); } diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index 651cfc1724..0e143113fc 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -99,7 +99,7 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen // add a 'Parsable' type to the parameter if it is composed of non-Parsable types var parsableTypes = ( - composedType != null, + composedType != null && !composedType.IsComposedOfObjects(IsPrimitiveType), parameter.Parent is CodeMethod method && (method.IsOfKind(CodeMethodKind.Deserializer, CodeMethodKind.Serializer)) ) switch { From 7792d1e022bac8933e9f52cc2dad1b42f28f4f7d Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:51:26 +0300 Subject: [PATCH 07/10] Fix --- src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 41857b0d3f..1710944648 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -54,7 +54,7 @@ public override void WriteCodeElement(CodeFunction codeElement, LanguageWriter w } } - private string GetSerializationMethodsForPrimitiveUnionTypes(CodeComposedTypeBase composedType, string parseNodeParameterName, CodeFunction codeElement, CodeFile codeFile, bool nodeParameterCanBeNull = true) + private string GetSerializationMethodsForPrimitiveUnionTypes(CodeComposedTypeBase composedType, string parseNodeParameterName, CodeFile codeFile, bool nodeParameterCanBeNull = true) { var optionalChainingSymbol = nodeParameterCanBeNull ? "?" : string.Empty; return string.Join(" ?? ", composedType.Types.Where(x => IsPrimitiveType(x, composedType)).Select(x => $"{parseNodeParameterName}{optionalChainingSymbol}." + conventions.GetDeserializationMethodName(x, codeFile))); @@ -240,7 +240,7 @@ private void WriteFactoryMethodBody(CodeFunction codeElement, string returnType, switch (composedType) { case CodeComposedTypeBase type when type.IsComposedOfPrimitives(IsPrimitiveType): - string primitiveValuesUnionString = GetSerializationMethodsForPrimitiveUnionTypes(composedType, parseNodeParameter!.Name.ToFirstCharacterLowerCase(), codeElement, codeFile); + string primitiveValuesUnionString = GetSerializationMethodsForPrimitiveUnionTypes(composedType, parseNodeParameter!.Name.ToFirstCharacterLowerCase(), codeFile); writer.WriteLine($"return {primitiveValuesUnionString};"); break; case CodeUnionType _ when parseNodeParameter != null: From 5632123e801bcb1652c79effc33ccd44f314589d Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:37:39 +0300 Subject: [PATCH 08/10] fix serializer deployment --- .../Writers/TypeScript/TypeScriptConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index 0e143113fc..90a6ac83e3 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -93,7 +93,7 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen var newType = (CodeComposedTypeBase)composedType.Clone(); var nonPrimitiveTypes = composedType.Types.Where(x => !IsPrimitiveTypeOrPrimitiveCollection(x, composedType)).ToArray(); newType.SetTypes(nonPrimitiveTypes); - paramType = GetTypescriptTypeString(newType, targetElement, includeCollectionInformation: true, inlineComposedTypeString: true); + paramType = GetTypescriptTypeString(newType, targetElement, includeCollectionInformation: false, inlineComposedTypeString: true); } var isComposedOfPrimitives = composedType != null && composedType.IsComposedOfPrimitives(IsPrimitiveType); From 746ff2dd5f06088715331cfd3a3e7d2f3c1ba562 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:51:47 +0300 Subject: [PATCH 09/10] fix usings order --- .../Writers/TypeScript/CodeFileDeclarationWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs index e4ba3e766b..239bfa52cf 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFileDeclarationWriter.cs @@ -40,7 +40,7 @@ public override void WriteCodeElement(CodeFileDeclaration codeElement, LanguageW .Where(static x => x is { IsExternal: false, Declaration.TypeDefinition: not null }) .GroupBy(static x => $"{x.Declaration!.TypeDefinition!.GetImmediateParentOfType().Name}.{x.Declaration?.Name.ToLowerInvariant()}") - .Select(static x => x.OrderByDescending(static x => x.Alias, StringComparer.OrdinalIgnoreCase).First())); + .Select(static x => x.OrderByDescending(static x => x.Alias, StringComparer.OrdinalIgnoreCase).ThenBy(static x => x.Parent?.Name, StringComparer.OrdinalIgnoreCase).First())); _codeUsingWriter.WriteCodeElement(filteredUsing, ns, writer); } From 698d728669c60fd19a6f2e56a9b6318a3b55cea1 Mon Sep 17 00:00:00 2001 From: rkodev <43806892+rkodev@users.noreply.github.com> Date: Mon, 11 Nov 2024 20:28:15 +0300 Subject: [PATCH 10/10] Adds changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae196fe262..55b6590f54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Fixed Python error when a class inherits from a base class and implements an interface. [5637](https://github.com/microsoft/kiota/issues/5637) +- Fix anyOf/oneOf generation in TypeScript. [5353](https://github.com/microsoft/kiota/issues/5353) ## [1.20.0] - 2024-11-07