From 3f438acdcc043bd6bc21887c5843b4e3bbb6e51c Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 10:52:32 -0500 Subject: [PATCH 01/13] - code linting Signed-off-by: Vincent Biret --- .../Refiners/TypeScriptRefiner.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index ae38eabcfe..1fff00e4f9 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -259,7 +259,7 @@ private static void CorrectCodeFileUsing(CodeElement currentElement) // correct the using values // eliminate the using referring the elements in the same file - HashSet elementSet = codeFile.GetChildElements(true).Select(x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase); + var elementSet = codeFile.GetChildElements(true).Select(static x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase); foreach (var element in codeFile.GetChildElements(true)) { var startBlockUsings = element switch @@ -271,27 +271,28 @@ private static void CorrectCodeFileUsing(CodeElement currentElement) _ => Enumerable.Empty() }; - var foundUsings = startBlockUsings - .Where(static x => x.Declaration != null && x.Declaration.TypeDefinition != null) - .Where(y => y.Declaration!.TypeDefinition!.GetImmediateParentOfType() == codeNamespace) - .Where(y => elementSet.Contains(y.Declaration!.TypeDefinition!.Name)); + var foundUsingsNames = startBlockUsings + .Select(static x => x.Declaration?.TypeDefinition) + .OfType() + .Where(x => x.GetImmediateParentOfType() == codeNamespace) + .Where(x => elementSet.Contains(x.Name)) + .Select(static x => x.Name); - foreach (var x in foundUsings) + foreach (var x in foundUsingsNames) { - var declarationName = x.Declaration!.Name; switch (element) { case CodeFunction ci: - ci.RemoveUsingsByDeclarationName(declarationName); + ci.RemoveUsingsByDeclarationName(x); break; case CodeInterface ci: - ci.RemoveUsingsByDeclarationName(declarationName); + ci.RemoveUsingsByDeclarationName(x); break; case CodeEnum ci: - ci.RemoveUsingsByDeclarationName(declarationName); + ci.RemoveUsingsByDeclarationName(x); break; case CodeClass ci: - ci.RemoveUsingsByDeclarationName(declarationName); + ci.RemoveUsingsByDeclarationName(x); break; } } From ad0a4e96b8a08528e18c3a6ac4310fc3878d2bca Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 11:19:42 -0500 Subject: [PATCH 02/13] - code linting Signed-off-by: Vincent Biret --- src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 10975ed154..a197def95c 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -306,7 +306,7 @@ protected static void ReplaceReservedNames(CodeElement current, IReservedNamesPr // in the CodeNamespace if-block so we also need to update the using references if (!codeElementExceptions?.Contains(typeof(CodeNamespace)) ?? true) ReplaceReservedCodeUsingNamespaceSegmentNames(currentDeclaration, provider, replacement); - if (currentDeclaration.Inherits?.Name is string inheritName && provider.ReservedNames.Contains(inheritName) && (currentDeclaration.Inherits is not CodeType)) + if (currentDeclaration.Inherits is not null && provider.ReservedNames.Contains(currentDeclaration.Inherits.Name)) currentDeclaration.Inherits.Name = replacement(currentDeclaration.Inherits.Name); } else if (current is CodeNamespace currentNamespace && @@ -316,10 +316,11 @@ protected static void ReplaceReservedNames(CodeElement current, IReservedNamesPr ReplaceReservedNamespaceSegments(currentNamespace, provider, replacement); else if (current is CodeMethod currentMethod && isNotInExceptions && - shouldReplace) + shouldReplace && + provider.ReservedNames.Contains(currentMethod.Name) && + current.Parent is IBlock parentBlock) { - if (provider.ReservedNames.Contains(currentMethod.Name)) - currentMethod.Name = replacement.Invoke(currentMethod.Name); + parentBlock.RenameChildElement(current.Name, replacement.Invoke(currentMethod.Name)); } else if (current is CodeProperty currentProperty && isNotInExceptions && From fe3971b41912c0f6eacc8051b3ea81222f5be09f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 13:36:04 -0500 Subject: [PATCH 03/13] - changes request builders to files even when no query parameters are present Signed-off-by: Vincent Biret --- src/Kiota.Builder/CodeDOM/CodeBlock.cs | 9 --------- src/Kiota.Builder/Refiners/TypeScriptRefiner.cs | 17 +++++++---------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Kiota.Builder/CodeDOM/CodeBlock.cs b/src/Kiota.Builder/CodeDOM/CodeBlock.cs index f4668e285d..9b9ad01bfe 100644 --- a/src/Kiota.Builder/CodeDOM/CodeBlock.cs +++ b/src/Kiota.Builder/CodeDOM/CodeBlock.cs @@ -156,15 +156,6 @@ public IEnumerable FindChildrenByName(string childName) where T : ICodeEle return Enumerable.Empty(); } - - public IEnumerable FindChildrenByName(IEnumerable childrenName, bool findInChildElements = true) where T : ICodeElement - { - ArgumentNullException.ThrowIfNull(childrenName); - - return childrenName.Where(static x => !string.IsNullOrEmpty(x)) - .Select(x => FindChildByName(x, findInChildElements)); - } - public T? FindChildByName(string childName, bool findInChildElements = true) where T : ICodeElement { ArgumentException.ThrowIfNullOrEmpty(childName); diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 1fff00e4f9..9afab00685 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -220,7 +220,7 @@ private static void GenerateModelCodeFile(CodeInterface codeInterface, CodeNames private static void GenerateRequestBuilderCodeFile(CodeClass codeClass, CodeNamespace codeNamespace) { - var elementNames = codeClass.Methods + var queryParameterInterfaces = codeClass.Methods .Where(static x => x.IsOfKind(CodeMethodKind.RequestGenerator)) .SelectMany(static x => x.Parameters) .Where(static x => x.IsOfKind(CodeParameterKind.RequestConfiguration)) @@ -228,23 +228,20 @@ private static void GenerateRequestBuilderCodeFile(CodeClass codeClass, CodeName .OfType() .Select(static x => x.GenericTypeParameterValues.FirstOrDefault()?.Name) .OfType() - .ToArray(); - - if (elementNames.Length == 0) - return; - - var queryParamClasses = codeNamespace.FindChildrenByName(elementNames, false) + .Select(x => codeNamespace.FindChildByName(x, false)) .OfType() .ToArray(); - var queryParametersMapperConstants = elementNames - .Select(static x => $"{x.ToFirstCharacterLowerCase()}Mapper") + // what about inline request and response body types? + + var queryParametersMapperConstants = queryParameterInterfaces + .Select(static x => $"{x.Name.ToFirstCharacterLowerCase()}Mapper") .Select(x => codeNamespace.FindChildByName(x, false)) .OfType() .ToArray(); var elements = new CodeElement[] { codeClass } - .Union(queryParamClasses) + .Union(queryParameterInterfaces) .Union(queryParametersMapperConstants) .ToArray(); From 2a024adb81eca0fd30ff11f24ac5b9454713e654 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 14:11:59 -0500 Subject: [PATCH 04/13] - collocates inline bodies with request builders Signed-off-by: Vincent Biret --- .../Refiners/TypeScriptRefiner.cs | 74 +++++++++++++++++-- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 9afab00685..96ce0a1dc0 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -121,10 +121,9 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "ParseNode", addUsings: false ); - static string factoryNameCallbackFromTypeName(string? x) => $"create{x.ToFirstCharacterUpperCase()}FromDiscriminatorValue"; ReplaceLocalMethodsByGlobalFunctions( generatedCode, - static x => factoryNameCallbackFromTypeName(x.Parent?.Name), + static x => GetFactoryFunctionNameFromTypeName(x.Parent?.Name), static x => { var result = new List() { @@ -143,7 +142,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance }, CodeMethodKind.Factory ); - static string factoryNameCallbackFromType(CodeType x) => factoryNameCallbackFromTypeName(x.TypeDefinition?.Name); + static string factoryNameCallbackFromType(CodeType x) => GetFactoryFunctionNameFromTypeName(x.TypeDefinition?.Name); cancellationToken.ThrowIfCancellationRequested(); AddStaticMethodsUsingsForDeserializer( generatedCode, @@ -220,8 +219,11 @@ private static void GenerateModelCodeFile(CodeInterface codeInterface, CodeNames private static void GenerateRequestBuilderCodeFile(CodeClass codeClass, CodeNamespace codeNamespace) { - var queryParameterInterfaces = codeClass.Methods - .Where(static x => x.IsOfKind(CodeMethodKind.RequestGenerator)) + var executorMethods = codeClass.Methods + .Where(static x => x.IsOfKind(CodeMethodKind.RequestExecutor)) + .ToArray(); + + var queryParameterInterfaces = executorMethods .SelectMany(static x => x.Parameters) .Where(static x => x.IsOfKind(CodeParameterKind.RequestConfiguration)) .Select(static x => x.Type) @@ -232,7 +234,53 @@ private static void GenerateRequestBuilderCodeFile(CodeClass codeClass, CodeName .OfType() .ToArray(); - // what about inline request and response body types? + var inlineRequestBodyInterfaces = executorMethods + .SelectMany(static x => x.Parameters) + .Where(static x => x.IsOfKind(CodeParameterKind.RequestBody)) + .Select(static x => x.Type.Name) + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType() + .ToArray(); + + var inlineRequestBodySerializerFunctions = inlineRequestBodyInterfaces + .Select(static x => $"{ModelSerializerPrefix}{x.Name.ToFirstCharacterUpperCase()}") + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType() + .ToArray(); + + var inlineRequestBodyDeserializerFunctions = inlineRequestBodyInterfaces + .Select(static x => $"{ModelDeserializerPrefix}{x.Name.ToFirstCharacterUpperCase()}") + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType() + .ToArray(); + + var inlineRequestBodyFactoryFunctions = inlineRequestBodyInterfaces + .Select(static x => GetFactoryFunctionNameFromTypeName(x.Name)) + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType(); + + var inlineResponseBodyInterfaces = executorMethods + .Select(static x => x.ReturnType.Name) + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType() + .ToArray(); + + var inlineResponseBodyDeserializerFunctions = inlineResponseBodyInterfaces + .Select(static x => $"{ModelDeserializerPrefix}{x.Name.ToFirstCharacterUpperCase()}") + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType() + .ToArray(); + + var inlineResponseBodySerializerFunctions = inlineResponseBodyInterfaces + .Select(static x => $"{ModelSerializerPrefix}{x.Name.ToFirstCharacterUpperCase()}") + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType() + .ToArray(); + + var inlineResponseBodyFactoryFunctions = inlineResponseBodyInterfaces + .Select(static x => GetFactoryFunctionNameFromTypeName(x.Name)) + .Select(x => codeNamespace.FindChildByName(x, false)) + .OfType(); var queryParametersMapperConstants = queryParameterInterfaces .Select(static x => $"{x.Name.ToFirstCharacterLowerCase()}Mapper") @@ -243,6 +291,15 @@ private static void GenerateRequestBuilderCodeFile(CodeClass codeClass, CodeName var elements = new CodeElement[] { codeClass } .Union(queryParameterInterfaces) .Union(queryParametersMapperConstants) + .Union(inlineRequestBodyInterfaces) + .Union(inlineRequestBodySerializerFunctions) + .Union(inlineRequestBodyDeserializerFunctions) + .Union(inlineRequestBodyFactoryFunctions) + .Union(inlineResponseBodyInterfaces) + .Union(inlineResponseBodySerializerFunctions) + .Union(inlineResponseBodyDeserializerFunctions) + .Union(inlineResponseBodyFactoryFunctions) + .Distinct() .ToArray(); codeNamespace.TryAddCodeFile(codeClass.Name, elements); @@ -1009,7 +1066,7 @@ private static void ProcessModelClassProperties(CodeClass modelClass, CodeInterf SetUsingsOfPropertyInSerializationFunctions($"{ModelSerializerPrefix}{propertyClass.Name.ToFirstCharacterUpperCase()}", serializer, propertyClass, interfaceNamingCallback); // In case of a deserializer function, for creating each object property the Parsable factory will be called. That is, `create{ModelName}FromDiscriminatorValue`. - SetUsingsOfPropertyInSerializationFunctions($"create{propertyClass.Name.ToFirstCharacterUpperCase()}FromDiscriminatorValue", deserializer, propertyClass, interfaceNamingCallback); + SetUsingsOfPropertyInSerializationFunctions(GetFactoryFunctionNameFromTypeName(propertyClass.Name), deserializer, propertyClass, interfaceNamingCallback); } // Add the property of the model class to the model interface. @@ -1017,6 +1074,9 @@ private static void ProcessModelClassProperties(CodeClass modelClass, CodeInterf modelInterface.AddProperty(newProperty); } } + private const string FactoryPrefix = "create"; + private const string FactorySuffix = "FromDiscriminatorValue"; + private static string GetFactoryFunctionNameFromTypeName(string? typeName) => string.IsNullOrEmpty(typeName) ? string.Empty : $"{FactoryPrefix}{typeName.ToFirstCharacterUpperCase()}{FactorySuffix}"; private static (CodeInterface?, CodeUsing?) ReturnUpdatedModelInterfaceTypeAndUsing(CodeClass sourceClass, CodeType originalType, Func interfaceNamingCallback) { From b874b2ca9daac62c3082b2a69de323d818784028 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 14:46:48 -0500 Subject: [PATCH 05/13] - code linting Signed-off-by: Vincent Biret --- .../Writers/Php/CodeMethodWriterTests.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs index f9d62812c0..68b4d16b98 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs @@ -227,7 +227,7 @@ public void Dispose() } [Fact] - public async void WriteRequestExecutor() + public async Task WriteRequestExecutor() { setup(); CodeProperty[] properties = @@ -319,7 +319,7 @@ public async Task WriteErrorMessageOverride() Assert.Contains("return $primaryError->getMessage() ?? '';", result); } [Fact] - public async void WritesRequestExecutorForEnumTypes() + public async Task WritesRequestExecutorForEnumTypes() { setup(); CodeProperty[] properties = @@ -457,7 +457,7 @@ public async void WritesRequestExecutorForEnumTypes() [Theory] [MemberData(nameof(SerializerProperties))] - public async void WriteSerializer(CodeProperty property, string expected) + public async Task WriteSerializer(CodeProperty property, string expected) { setup(true); var codeMethod = new CodeMethod @@ -1067,7 +1067,7 @@ public async Task WriteDeserializerMergeWhenHasParent() } [Fact] - public async void WriteConstructorBody() + public async Task WriteConstructorBody() { setup(); parentClass.Kind = CodeClassKind.Model; @@ -1193,7 +1193,7 @@ public void WriteGetter() } [Fact] - public async void WriteGetterAdditionalData() + public async Task WriteGetterAdditionalData() { setup(); var property = new CodeProperty @@ -1291,7 +1291,7 @@ public void WriteRequestBuilderWithParametersBody() } [Fact] - public async void WriteRequestBuilderConstructor() + public async Task WriteRequestBuilderConstructor() { setup(); method.Kind = CodeMethodKind.Constructor; @@ -1488,7 +1488,7 @@ public void WritesModelFactoryBodyForIntersectionModels() } [Fact] - public async void WriteFactoryMethod() + public async Task WriteFactoryMethod() { setup(); var parentModel = root.AddClass(new CodeClass @@ -1545,7 +1545,7 @@ public async void WriteFactoryMethod() Assert.Contains("$mappingValueNode = $parseNode->getChildNode(\"@odata.type\");", result); } [Fact] - public async void WriteApiConstructor() + public async Task WriteApiConstructor() { setup(); parentClass.AddProperty(new CodeProperty @@ -1598,7 +1598,7 @@ public async void WriteApiConstructor() } [Fact] - public async void WritesApiClientWithBackingStoreConstructor() + public async Task WritesApiClientWithBackingStoreConstructor() { setup(); var constructor = new CodeMethod @@ -1660,7 +1660,7 @@ public async void WritesApiClientWithBackingStoreConstructor() } [Fact] - public async void WritesModelWithBackingStoreConstructor() + public async Task WritesModelWithBackingStoreConstructor() { setup(); parentClass.Kind = CodeClassKind.Model; @@ -1760,7 +1760,7 @@ public async void WritesModelWithBackingStoreConstructor() [Theory] [MemberData(nameof(GetterWithBackingStoreProperties))] - public async void WritesGettersWithBackingStore(CodeProperty property, params string[] expected) + public async Task WritesGettersWithBackingStore(CodeProperty property, params string[] expected) { setup(); parentClass.Kind = CodeClassKind.Model; @@ -1794,7 +1794,7 @@ public async void WritesGettersWithBackingStore(CodeProperty property, params st } [Fact] - public async void WritesSettersWithBackingStore() + public async Task WritesSettersWithBackingStore() { setup(); parentClass.Kind = CodeClassKind.Model; @@ -1832,7 +1832,7 @@ public async void WritesSettersWithBackingStore() } [Fact] - public async void ReplaceBinaryTypeWithStreamInterface() + public async Task ReplaceBinaryTypeWithStreamInterface() { setup(); var binaryProperty = new CodeProperty @@ -2281,7 +2281,7 @@ private void AddSerializationProperties() }); } [Fact] - public async void WritesRequestConfigurationConstructor() + public async Task WritesRequestConfigurationConstructor() { setup(); var queryParamClass = new CodeClass { Name = "TestRequestQueryParameter", Kind = CodeClassKind.QueryParameters }; @@ -2326,7 +2326,7 @@ public async void WritesRequestConfigurationConstructor() } [Fact] - public async void WritesQueryParameterFactoryMethod() + public async Task WritesQueryParameterFactoryMethod() { setup(); var queryParamClass = new CodeClass { Name = "TestRequestQueryParameter", Kind = CodeClassKind.QueryParameters }; @@ -2377,7 +2377,7 @@ public async void WritesQueryParameterFactoryMethod() } [Fact] - public async void WritesQueryParameterConstructor() + public async Task WritesQueryParameterConstructor() { setup(); parentClass.Kind = CodeClassKind.QueryParameters; From 0508f783214a4764450b63a79620553256e8967e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 14:48:33 -0500 Subject: [PATCH 06/13] - code linting Signed-off-by: Vincent Biret --- .../Writers/Php/CodeClassDeclarationWriterTests.cs | 2 +- .../Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodeClassDeclarationWriterTests.cs index 582208c25c..c6ef15c76a 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodeClassDeclarationWriterTests.cs @@ -156,7 +156,7 @@ public void ExtendABaseClass() } [Fact] - public async void AddsImportsToRequestConfigClasses() + public async Task AddsImportsToRequestConfigClasses() { var queryParamClass = new CodeClass { Name = "TestRequestQueryParameter", Kind = CodeClassKind.QueryParameters }; var modelsNamespace = root.AddNamespace("Models"); diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs index d33c57a4dd..22c125f34b 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs @@ -225,7 +225,7 @@ public void WriteQueryParameter() } [Fact] - public async void WriteRequestOption() + public async Task WriteRequestOption() { var options = new CodeProperty { From 3d096e0440b50da632cbd9f7aa37ea0b6e6f724b Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 14:53:42 -0500 Subject: [PATCH 07/13] - code linting Signed-off-by: Vincent Biret --- src/Kiota.Builder/Refiners/PhpRefiner.cs | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 13d25bd18b..93df413e31 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -175,31 +175,31 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance } }; private static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { - new (x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), "Microsoft\\Kiota\\Abstractions", "RequestAdapter"), - new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), "Microsoft\\Kiota\\Abstractions", "HttpMethod", "RequestInformation"), new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(static y => y.IsOfKind(CodePropertyKind.AdditionalData)), "Microsoft\\Kiota\\Abstractions\\Serialization", "AdditionalDataHolder"), - new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), "Microsoft\\Kiota\\Abstractions\\Serialization", "SerializationWriter"), - new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), "Microsoft\\Kiota\\Abstractions\\Serialization", "ParseNode"), - new (x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), "Microsoft\\Kiota\\Abstractions\\Serialization", "Parsable"), - new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor) && + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor) && method.Parameters.Any(y => y.IsOfKind(CodeParameterKind.BackingStore)), "Microsoft\\Kiota\\Abstractions\\Store", "BackingStoreFactory", "BackingStoreFactorySingleton"), - new (x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.BackingStore), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.BackingStore), "Microsoft\\Kiota\\Abstractions\\Store", "BackingStore", "BackedModel", "BackingStoreFactorySingleton" ), - new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "Http\\Promise", "Promise"), - new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "", "Exception"), - new (x => x is CodeEnum, "Microsoft\\Kiota\\Abstractions\\", "Enum"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "Http\\Promise", "Promise"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "", "Exception"), + new (static x => x is CodeEnum, "Microsoft\\Kiota\\Abstractions\\", "Enum"), new(static x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTime", StringComparison.OrdinalIgnoreCase), "", "\\DateTime"), new(static x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase), "", "\\DateTime"), - new(x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor), "Microsoft\\Kiota\\Abstractions", "ApiClientBuilder"), - new(x => x is CodeProperty property && property.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(property.SerializationName), "Microsoft\\Kiota\\Abstractions", "QueryParameter"), - new(x => x is CodeClass codeClass && codeClass.IsOfKind(CodeClassKind.RequestConfiguration), "Microsoft\\Kiota\\Abstractions", "RequestOption"), + new(static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor), "Microsoft\\Kiota\\Abstractions", "ApiClientBuilder"), + new(static x => x is CodeProperty property && property.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(property.SerializationName), "Microsoft\\Kiota\\Abstractions", "QueryParameter"), + new(static x => x is CodeClass codeClass && codeClass.IsOfKind(CodeClassKind.RequestConfiguration), "Microsoft\\Kiota\\Abstractions", "RequestOption"), new (static x => x is CodeClass { OriginalComposedType: CodeIntersectionType intersectionType } && intersectionType.Types.Any(static y => !y.IsExternal), "Microsoft\\Kiota\\Abstractions\\Serialization", "ParseNodeHelper"), }; From eb48f446d0724924e2893458853c914653d9072a Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 23 Nov 2023 14:54:47 -0500 Subject: [PATCH 08/13] - fixes failing tests Signed-off-by: Vincent Biret --- src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs | 12 ++++++++---- .../Refiners/GoLanguageRefinerTests.cs | 4 ++-- .../Refiners/TypeScriptLanguageRefinerTests.cs | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index a197def95c..6d866743a1 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -160,6 +160,8 @@ current.Parent is CodeClass parentClass && protected static void AddGetterAndSetterMethods(CodeElement current, HashSet propertyKindsToAddAccessors, Func refineAccessorName, bool removeProperty, bool parameterAsOptional, string getterPrefix, string setterPrefix, string fieldPrefix = "_", AccessModifier propertyAccessModifier = AccessModifier.Private) { ArgumentNullException.ThrowIfNull(refineAccessorName); + var isSetterPrefixEmpty = string.IsNullOrEmpty(setterPrefix); + var isGetterPrefixEmpty = string.IsNullOrEmpty(getterPrefix); if (propertyKindsToAddAccessors is null || propertyKindsToAddAccessors.Count == 0) return; if (current is CodeProperty currentProperty && !currentProperty.ExistsInBaseType && @@ -179,7 +181,7 @@ current.Parent is CodeClass parentClass && currentProperty.Getter = parentClass.AddMethod(new CodeMethod { - Name = $"get-{accessorName}", + Name = $"{(isGetterPrefixEmpty ? "get-" : getterPrefix)}{accessorName}", Access = AccessModifier.Public, IsAsync = false, Kind = CodeMethodKind.Getter, @@ -191,10 +193,11 @@ current.Parent is CodeClass parentClass && AccessedProperty = currentProperty, Deprecation = currentProperty.Deprecation, }).First(); - currentProperty.Getter.Name = $"{getterPrefix}{accessorName}"; // so we don't get an exception for duplicate names when no prefix + if (isGetterPrefixEmpty) + currentProperty.Getter.Name = $"{getterPrefix}{accessorName}"; // so we don't get an exception for duplicate names when no prefix currentProperty.Setter = parentClass.AddMethod(new CodeMethod { - Name = $"set-{accessorName}", + Name = $"{(isSetterPrefixEmpty ? "set-" : setterPrefix)}{accessorName}", Access = AccessModifier.Public, IsAsync = false, Kind = CodeMethodKind.Setter, @@ -211,7 +214,8 @@ current.Parent is CodeClass parentClass && }, Deprecation = currentProperty.Deprecation, }).First(); - currentProperty.Setter.Name = $"{setterPrefix}{accessorName}"; // so we don't get an exception for duplicate names when no prefix + if (isSetterPrefixEmpty) + currentProperty.Setter.Name = $"{setterPrefix}{accessorName}"; // so we don't get an exception for duplicate names when no prefix currentProperty.Setter.AddParameter(new CodeParameter { diff --git a/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs index 93faf3ce0c..f5d0297b00 100644 --- a/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs @@ -250,8 +250,8 @@ public async Task EnsuresMethodNamesAreNotOverLoaded() Assert.Empty(root.GetChildElements(true).OfType()); await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Go }, root); - Assert.Equal("SetProperty_a", model.FindChildByName("set-property_a").Name); - Assert.Equal("SetPropertyA", model.FindChildByName("set-propertyA").Name); + Assert.Equal("SetProperty_a", model.FindChildByName("setProperty_a").Name); + Assert.Equal("SetPropertyA", model.FindChildByName("setPropertyA").Name); } [Fact] public async Task ReplacesModelsByInnerInterfaces() diff --git a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs index 5761a4a6c0..b6127bf26e 100644 --- a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs @@ -657,7 +657,8 @@ public async Task ReplaceRequestConfigsQueryParams() await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, testNS); Assert.DoesNotContain(testNS.Interfaces, static x => x.Name.Equals("requestConfig", StringComparison.OrdinalIgnoreCase)); Assert.Contains(testNS.Interfaces, static x => x.Name.Equals("queryParams", StringComparison.OrdinalIgnoreCase)); - Assert.NotEmpty(testNS.Classes); + Assert.Empty(testNS.Classes); + Assert.NotEmpty(testNS.Files); Assert.Empty(requestBuilder.InnerClasses); Assert.DoesNotContain(testNS.Classes, static x => x.Name.Equals("requestConfig", StringComparison.OrdinalIgnoreCase)); Assert.DoesNotContain(testNS.Classes, static x => x.Name.Equals("queryParams", StringComparison.OrdinalIgnoreCase)); From d0621490c60bb5ca75378cbd8acee5073ed3e687 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Nov 2023 14:21:58 -0500 Subject: [PATCH 09/13] - code linting --- src/Kiota.Builder/Refiners/TypeScriptRefiner.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 96ce0a1dc0..e4bdd82a01 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -78,10 +78,10 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance true ); AddGetterAndSetterMethods(generatedCode, - new() { + [ CodePropertyKind.Custom, CodePropertyKind.AdditionalData, - }, + ], static (_, s) => s.ToCamelCase(UnderscoreArray), false, false, @@ -110,11 +110,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance } ); AddSerializationModulesImport(generatedCode, - new[] { $"{AbstractionsPackageName}.registerDefaultSerializer", + [ $"{AbstractionsPackageName}.registerDefaultSerializer", $"{AbstractionsPackageName}.enableBackingStoreForSerializationWriterFactory", - $"{AbstractionsPackageName}.SerializationWriterFactoryRegistry"}, - new[] { $"{AbstractionsPackageName}.registerDefaultDeserializer", - $"{AbstractionsPackageName}.ParseNodeFactoryRegistry" }); + $"{AbstractionsPackageName}.SerializationWriterFactoryRegistry"], + [ $"{AbstractionsPackageName}.registerDefaultDeserializer", + $"{AbstractionsPackageName}.ParseNodeFactoryRegistry" ]); cancellationToken.ThrowIfCancellationRequested(); AddDiscriminatorMappingsUsingsToParentClasses( generatedCode, @@ -190,7 +190,7 @@ private void MergeElementsToFile(CodeElement currentElement) private static void GenerateModelCodeFile(CodeInterface codeInterface, CodeNamespace codeNamespace) { - List functions = new List(); + var functions = new List(); foreach (var element in codeNamespace.GetChildElements(true)) { From dd0db64b568234b5dab26af2f17f3593aed59640 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Nov 2023 14:22:15 -0500 Subject: [PATCH 10/13] - fixes a bug where reserved name rename would not rename objects properly --- src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 6d866743a1..6c85382200 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -310,8 +310,7 @@ protected static void ReplaceReservedNames(CodeElement current, IReservedNamesPr // in the CodeNamespace if-block so we also need to update the using references if (!codeElementExceptions?.Contains(typeof(CodeNamespace)) ?? true) ReplaceReservedCodeUsingNamespaceSegmentNames(currentDeclaration, provider, replacement); - if (currentDeclaration.Inherits is not null && provider.ReservedNames.Contains(currentDeclaration.Inherits.Name)) - currentDeclaration.Inherits.Name = replacement(currentDeclaration.Inherits.Name); + // we don't need to rename the inheritance name as it's either external and shouldn't change or it's generated and the code type maps directly to the source } else if (current is CodeNamespace currentNamespace && isNotInExceptions && @@ -326,13 +325,7 @@ protected static void ReplaceReservedNames(CodeElement current, IReservedNamesPr { parentBlock.RenameChildElement(current.Name, replacement.Invoke(currentMethod.Name)); } - else if (current is CodeProperty currentProperty && - isNotInExceptions && - shouldReplace && - currentProperty.Type is CodeType propertyType && - !propertyType.IsExternal && - provider.ReservedNames.Contains(currentProperty.Type.Name)) - propertyType.Name = replacement.Invoke(propertyType.Name); + // we don't need to property type name as it's either external and shouldn't change or it's generated and the code type maps directly to the source // Check if the current name meets the following conditions to be replaced // 1. In the list of reserved names From 788acfcdfccc90854c51e31e06f92eff3e852f94 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Nov 2023 14:25:10 -0500 Subject: [PATCH 11/13] - adds changelog entry for TypeScript escape fixes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d92ee4710..04bbf4a2d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Groups request builders and inline request/response bodies in the same file in TypeScript. +- Fixed a bug where reserved name rename would not rename objects properly. [#3609](https://github.com/microsoft/kiota/issues/3609) - Switched to a Jammy Chiseled base image for docker containers. - Fixed a bug where path parameters deduplication would create collisions on sub path segments. [#3757](https://github.com/microsoft/kiota/issues/3757) - Moved from net7 to net8. From c8f28505e07982bd78485fe74eeff7bc9025d91b Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Nov 2023 14:28:35 -0500 Subject: [PATCH 12/13] - formatting Signed-off-by: Vincent Biret --- src/Kiota.Builder/Refiners/TypeScriptRefiner.cs | 10 +++++----- .../Writers/TypeScript/CodeFunctionWriter.cs | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index e4bdd82a01..183ebb2573 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -110,11 +110,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance } ); AddSerializationModulesImport(generatedCode, - [ $"{AbstractionsPackageName}.registerDefaultSerializer", - $"{AbstractionsPackageName}.enableBackingStoreForSerializationWriterFactory", - $"{AbstractionsPackageName}.SerializationWriterFactoryRegistry"], - [ $"{AbstractionsPackageName}.registerDefaultDeserializer", - $"{AbstractionsPackageName}.ParseNodeFactoryRegistry" ]); + [$"{AbstractionsPackageName}.registerDefaultSerializer", + $"{AbstractionsPackageName}.enableBackingStoreForSerializationWriterFactory", + $"{AbstractionsPackageName}.SerializationWriterFactoryRegistry"], + [$"{AbstractionsPackageName}.registerDefaultDeserializer", + $"{AbstractionsPackageName}.ParseNodeFactoryRegistry"]); cancellationToken.ThrowIfCancellationRequested(); AddDiscriminatorMappingsUsingsToParentClasses( generatedCode, diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index c5b3c996a3..e0dd329e71 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -105,8 +105,6 @@ private void WriteSerializerFunction(CodeFunction codeElement, LanguageWriter wr if (param == null || param.Type is not CodeType codeType || codeType.TypeDefinition is not CodeInterface codeInterface) throw new InvalidOperationException("Interface parameter not found for code interface"); - writer.IncreaseIndent(); - if (codeInterface.StartBlock.Implements.FirstOrDefault(static x => x.TypeDefinition is CodeInterface) is CodeType inherits) { writer.WriteLine($"serialize{inherits.TypeDefinition!.Name.ToFirstCharacterUpperCase()}(writer, {param.Name.ToFirstCharacterLowerCase()})"); @@ -119,7 +117,6 @@ private void WriteSerializerFunction(CodeFunction codeElement, LanguageWriter wr if (codeInterface.GetPropertyOfKind(CodePropertyKind.AdditionalData) is CodeProperty additionalDataProperty) writer.WriteLine($"writer.writeAdditionalData({codeInterface.Name.ToFirstCharacterLowerCase()}.{additionalDataProperty.Name.ToFirstCharacterLowerCase()});"); - writer.DecreaseIndent(); } private static bool IsCodePropertyCollectionOfEnum(CodeProperty property) From 5c88a03b5d1b7652f578b7588664f79e77c21b71 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 24 Nov 2023 15:11:59 -0500 Subject: [PATCH 13/13] - fixes a regression in ruby where escaping reserved names wouldn't work anymore Signed-off-by: Vincent Biret --- src/Kiota.Builder/Refiners/RubyRefiner.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index e180f072da..84286899cf 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -65,10 +65,10 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); cancellationToken.ThrowIfCancellationRequested(); ReplacePropertyNames(generatedCode, - new() { + [ CodePropertyKind.Custom, CodePropertyKind.QueryParameter, - }, + ], static s => s.ToSnakeCase()); AddParentClassToErrorClasses( generatedCode, @@ -76,12 +76,13 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "MicrosoftKiotaAbstractions", true ); + ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}_escaped"); AddGetterAndSetterMethods(generatedCode, - new() { + [ CodePropertyKind.Custom, CodePropertyKind.AdditionalData, CodePropertyKind.BackingStore, - }, + ], static (_, s) => s.ToSnakeCase(), _configuration.UsesBackingStore, true, @@ -92,9 +93,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance generatedCode, true, false, - new[] { CodeClassKind.RequestConfiguration }); + [CodeClassKind.RequestConfiguration]); ShortenLongNamespaceNames(generatedCode); - ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}_escaped"); if (generatedCode.FindNamespaceByName(_configuration.ClientNamespaceName)?.Parent is CodeNamespace parentOfClientNS) AddNamespaceModuleImports(parentOfClientNS, generatedCode); var defaultConfiguration = new GenerationConfiguration();