From ae642b0b87d547c484163e8f0bfd1eada7f883a6 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Thu, 8 Dec 2022 16:07:59 +0300 Subject: [PATCH 01/14] Fix minor issues with PHP generation. --- src/Kiota.Builder/Kiota.Builder.csproj | 2 +- .../PathSegmenters/PHPPathSegmenter.cs | 4 +- .../Refiners/CommonLanguageRefiner.cs | 44 ++++++++++--------- src/Kiota.Builder/Refiners/PhpRefiner.cs | 11 +++-- .../Writers/Php/CodeMethodWriter.cs | 4 +- .../Writers/Php/PhpConventionService.cs | 13 +++--- 6 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj index cf2cde1400..c19ef3477c 100644 --- a/src/Kiota.Builder/Kiota.Builder.csproj +++ b/src/Kiota.Builder/Kiota.Builder.csproj @@ -1,7 +1,7 @@  - Latest + preview net7.0 true https://github.com/microsoft/kiota diff --git a/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs index c4d81c3835..826b85e1ec 100644 --- a/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs +++ b/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs @@ -1,4 +1,5 @@ -using Kiota.Builder.CodeDOM; +using System.Linq; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; namespace Kiota.Builder.PathSegmenters @@ -8,6 +9,7 @@ public class PhpPathSegmenter : CommonPathSegmenter public PhpPathSegmenter(string rootPath, string clientNamespaceName) : base(rootPath, clientNamespaceName) { } public override string FileSuffix => ".php"; public override string NormalizeNamespaceSegment(string segmentName) => segmentName.ToFirstCharacterUpperCase(); + protected static new string GetLastFileNameSegment(CodeElement currentElement) => currentElement.Name.Split('.', '\\').Last(); public override string NormalizeFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToFirstCharacterUpperCase(); } } diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index cc982ac4fc..8f433acb0a 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -683,35 +683,37 @@ protected static void AddParentClassToErrorClasses(CodeElement currentElement, s protected static void AddDiscriminatorMappingsUsingsToParentClasses(CodeElement currentElement, string parseNodeInterfaceName, bool addFactoryMethodImport = false, bool addUsings = true) { if(currentElement is CodeMethod currentMethod && currentMethod.Parent is CodeClass parentClass && - parentClass.StartBlock is ClassDeclaration declaration) { + parentClass.StartBlock is ClassDeclaration declaration) { + var parentClassNamespace = parentClass.GetImmediateParentOfType(); if(currentMethod.IsOfKind(CodeMethodKind.Factory) && (parentClass.DiscriminatorInformation?.HasBasicDiscriminatorInformation ?? false)) { - if(addUsings) - declaration.AddUsings(parentClass.DiscriminatorInformation.DiscriminatorMappings - .Select(static x => x.Value) - .OfType() - .Where(static x => x.TypeDefinition != null) - .Select(x => new CodeUsing { - Name = x.TypeDefinition.GetImmediateParentOfType().Name, - Declaration = new CodeType { - Name = x.TypeDefinition.Name, - TypeDefinition = x.TypeDefinition, - }, + if(addUsings) + declaration.AddUsings(parentClass.DiscriminatorInformation.DiscriminatorMappings + .Select(static x => x.Value) + .OfType() + .Where(static x => x.TypeDefinition != null) + .Where(x => !x.TypeDefinition.GetImmediateParentOfType().Name.Equals(parentClassNamespace.Name, StringComparison.OrdinalIgnoreCase)) + .Select(x => new CodeUsing { + Name = x.TypeDefinition.GetImmediateParentOfType().Name, + Declaration = new CodeType { + Name = x.TypeDefinition.Name, + TypeDefinition = x.TypeDefinition, + }, }).ToArray()); - if (currentMethod.Parameters.OfKind(CodeParameterKind.ParseNode, out var parameter)) - parameter.Type.Name = parseNodeInterfaceName; + if (currentMethod.Parameters.OfKind(CodeParameterKind.ParseNode, out var parameter)) + parameter.Type.Name = parseNodeInterfaceName; } else if (addFactoryMethodImport && currentMethod.IsOfKind(CodeMethodKind.RequestExecutor) && currentMethod.ReturnType is CodeType type && type.TypeDefinition is CodeClass modelClass && modelClass.GetChildElements(true).OfType().FirstOrDefault(static x => x.IsOfKind(CodeMethodKind.Factory)) is CodeMethod factoryMethod) { - declaration.AddUsings(new CodeUsing { - Name = modelClass.GetImmediateParentOfType().Name, - Declaration = new CodeType { - Name = factoryMethod.Name, - TypeDefinition = factoryMethod, - } - }); + declaration.AddUsings(new CodeUsing { + Name = modelClass.GetImmediateParentOfType().Name, + Declaration = new CodeType { + Name = factoryMethod.Name, + TypeDefinition = factoryMethod, + } + }); } } CrawlTree(currentElement, x => AddDiscriminatorMappingsUsingsToParentClasses(x, parseNodeInterfaceName, addFactoryMethodImport, addUsings)); diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index effbae3933..1d9cbecb87 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -33,7 +34,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddDiscriminatorMappingsUsingsToParentClasses( generatedCode, "ParseNode", - addUsings: false + addUsings: true ); cancellationToken.ThrowIfCancellationRequested(); CorrectParameterType(generatedCode); @@ -240,15 +241,17 @@ private static void AliasUsingWithSameSymbol(CodeElement currentElement) { .Where(x => x.Declaration .Name .Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase))); - foreach (var usingElement in duplicatedSymbolsUsings) + var symbolsUsing = duplicatedSymbolsUsings as CodeUsing[] ?? duplicatedSymbolsUsings.ToArray(); + //currentClass.StartBlock.RemoveUsings(symbolsUsing.ToArray()); + foreach (var usingElement in symbolsUsing) { var declaration = usingElement.Declaration.TypeDefinition?.Name; if (string.IsNullOrEmpty(declaration)) continue; - var replacement = string.Join(string.Empty, usingElement.Declaration.TypeDefinition.GetImmediateParentOfType().Name + var replacement = string.Join("\\", usingElement.Declaration.TypeDefinition.GetImmediateParentOfType().Name .Split(new[]{'\\', '.'}, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.ToFirstCharacterUpperCase()) .ToArray()); - usingElement.Alias = $"{replacement}{declaration.ToFirstCharacterUpperCase()}"; + usingElement.Declaration.Name = $"{(string.IsNullOrEmpty(replacement) ? string.Empty : $"\\{replacement}")}\\{declaration.ToFirstCharacterUpperCase()}"; } } CrawlTree(currentElement, AliasUsingWithSameSymbol); diff --git a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs index 429b069ffa..6b2e02934e 100644 --- a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs @@ -535,7 +535,7 @@ protected string GetSendRequestMethodName(bool isVoid, bool isStream, bool isCol return "sendAsync"; } - private static void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer){ + private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer){ var parseNodeParameter = codeElement.Parameters.OfKind(CodeParameterKind.ParseNode); if(parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType && parseNodeParameter != null) { writer.WriteLines($"$mappingValueNode = ${parseNodeParameter.Name.ToFirstCharacterLowerCase()}->getChildNode(\"{parentClass.DiscriminatorInformation.DiscriminatorPropertyName}\");", @@ -545,7 +545,7 @@ private static void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass par writer.WriteLine("switch ($mappingValue) {"); writer.IncreaseIndent(); foreach(var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings) { - writer.WriteLine($"case '{mappedType.Key}': return new {mappedType.Value.AllTypes.First().Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"case '{mappedType.Key}': return new {conventions.GetTypeString(mappedType.Value.AllTypes.First(), parentClass)}();"); } writer.CloseBlock(); writer.CloseBlock(); diff --git a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs index dc39b6023e..48435097c5 100644 --- a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs +++ b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs @@ -50,7 +50,7 @@ public override string GetTypeString(CodeTypeBase code, CodeElement targetElemen var typeName = TranslateType(currentType); if (!currentType.IsExternal && IsSymbolDuplicated(typeName, targetElement)) { - return $"{MakeNamespaceAliasVariable(currentType.TypeDefinition.GetImmediateParentOfType().Name.ToFirstCharacterUpperCase())}{typeName.ToFirstCharacterUpperCase()}"; + return $"\\{currentType.TypeDefinition.GetImmediateParentOfType().Name.ReplaceDotsWithSlashInNamespaces()}\\{typeName.ToFirstCharacterUpperCase()}"; } } return code is {IsCollection: true} ? "array" : TranslateType(code); @@ -172,6 +172,7 @@ public void WriteNamespaceAndImports(ClassDeclaration codeElement, LanguageWrite codeElement.Usings? .Where(x => x.Declaration != null && (x.Declaration.IsExternal || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase))) + .Where(x => string.IsNullOrEmpty(x.Alias)) .Select(x => { string namespaceValue; @@ -179,11 +180,11 @@ public void WriteNamespaceAndImports(ClassDeclaration codeElement, LanguageWrite { namespaceValue = string.IsNullOrEmpty(x.Declaration.Name) ? string.Empty : $"{x.Declaration.Name.ReplaceDotsWithSlashInNamespaces()}\\"; return - $"use {namespaceValue}{x.Name.ReplaceDotsWithSlashInNamespaces()}{(!string.IsNullOrEmpty(x.Alias) ? $" as {x.Alias}" : string.Empty)};"; + $"use {namespaceValue}{x.Name.ReplaceDotsWithSlashInNamespaces()};"; } namespaceValue = string.IsNullOrEmpty(x.Name) ? string.Empty : $"{x.Name.ReplaceDotsWithSlashInNamespaces()}\\"; return - $"use {namespaceValue}{x.Declaration.Name.ReplaceDotsWithSlashInNamespaces()}{(!string.IsNullOrEmpty(x.Alias) ? $" as {x.Alias}" : string.Empty)};"; + $"use {namespaceValue}{x.Declaration.Name.ReplaceDotsWithSlashInNamespaces()};"; }) .Distinct() .OrderBy(x => x) @@ -217,10 +218,10 @@ internal void AddParametersAssignment(LanguageWriter writer, CodeTypeBase pathPa } private static bool IsSymbolDuplicated(string symbol, CodeElement targetElement) { - var targetClass = targetElement as CodeClass ?? targetElement.GetImmediateParentOfType(); - if (targetClass.Parent is CodeClass parentClass) + var targetClass = targetElement as CodeClass ?? targetElement?.GetImmediateParentOfType(); + if (targetClass?.Parent is CodeClass parentClass) targetClass = parentClass; - return targetClass.StartBlock + return targetClass?.StartBlock ?.Usings ?.Where(x => !x.IsExternal && symbol.Equals(x.Declaration.TypeDefinition.Name, StringComparison.OrdinalIgnoreCase)) ?.Distinct(_usingDeclarationNameComparer) From 736945b9082c780bafb7082d505617f8bb50b8e3 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 00:47:28 +0300 Subject: [PATCH 02/14] Fix imports issue. --- src/Kiota.Builder/Refiners/PhpRefiner.cs | 31 +++++++++++----------- src/Kiota.Builder/Writers/Php/PhpWriter.cs | 1 + 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 1d9cbecb87..6fe228e7a3 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -19,6 +19,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance { return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); + // Imports should be done before adding getters and setters since AddGetterAndSetterMethods can remove properties from classes when backing store is enabled ReplaceReservedNames(generatedCode, new PhpReservedNamesProvider(), reservedWord => $"Escaped{reservedWord.ToFirstCharacterUpperCase()}"); AddParentClassToErrorClasses( generatedCode, @@ -31,17 +32,17 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance ConvertUnionTypesToWrapper(generatedCode, _configuration.UsesBackingStore, false); - AddDiscriminatorMappingsUsingsToParentClasses( - generatedCode, - "ParseNode", - addUsings: true - ); cancellationToken.ThrowIfCancellationRequested(); CorrectParameterType(generatedCode); MakeModelPropertiesNullable(generatedCode); ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, false, "ById"); cancellationToken.ThrowIfCancellationRequested(); - AddPropertiesAndMethodTypesImports(generatedCode, true, false, true); + MoveClassesWithNamespaceNamesUnderNamespace(generatedCode); + AddDiscriminatorMappingsUsingsToParentClasses( + generatedCode, + "ParseNode", + addUsings: true + ); var defaultConfiguration = new GenerationConfiguration(); ReplaceDefaultSerializationModules(generatedCode, defaultConfiguration.Serializers, @@ -56,7 +57,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "Microsoft\\Kiota\\Serialization\\Text\\TextParseNodeFactory"} ); cancellationToken.ThrowIfCancellationRequested(); - AliasUsingWithSameSymbol(generatedCode); AddSerializationModulesImport(generatedCode, new []{"Microsoft\\Kiota\\Abstractions\\ApiClientBuilder"}, null, '\\'); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); cancellationToken.ThrowIfCancellationRequested(); @@ -64,7 +64,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance true, string.Empty, true); - // Imports should be done before adding getters and setters since AddGetterAndSetterMethods can remove properties from classes when backing store is enabled AddDefaultImports(generatedCode, defaultUsingEvaluators); AddGetterAndSetterMethods(generatedCode, new() { @@ -78,10 +77,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "set"); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); ReplaceBinaryByNativeType(generatedCode, "StreamInterface", "Psr\\Http\\Message", true, _configuration.UsesBackingStore); - cancellationToken.ThrowIfCancellationRequested(); - MoveClassesWithNamespaceNamesUnderNamespace(generatedCode); CorrectCoreTypesForBackingStore(generatedCode, "BackingStoreFactorySingleton::getInstance()->createBackingStore()"); CorrectBackingStoreSetterParam(generatedCode); + AddPropertiesAndMethodTypesImports(generatedCode, true, false, true); + AliasUsingWithSameSymbol(generatedCode); + cancellationToken.ThrowIfCancellationRequested(); }, cancellationToken); } private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) @@ -138,7 +138,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "Microsoft\\Kiota\\Abstractions", "HttpMethod", "RequestInformation", "RequestOption"), new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "Microsoft\\Kiota\\Abstractions", "ResponseHandler"), - new (x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), + new (x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(y => y.IsOfKind(CodePropertyKind.AdditionalData)), "Microsoft\\Kiota\\Abstractions\\Serialization", "AdditionalDataHolder"), new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), "Microsoft\\Kiota\\Abstractions\\Serialization", "SerializationWriter"), @@ -156,8 +156,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "Http\\Promise", "Promise", "RejectedPromise"), new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "", "Exception"), new (x => x is CodeEnum, "Microsoft\\Kiota\\Abstractions\\", "Enum"), - new(x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTime", StringComparison.OrdinalIgnoreCase), "", "DateTime"), - new(x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase), "", "DateTime"), + new(x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTime", StringComparison.OrdinalIgnoreCase), "", "\\DateTime"), + new(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") @@ -242,7 +242,7 @@ private static void AliasUsingWithSameSymbol(CodeElement currentElement) { .Name .Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase))); var symbolsUsing = duplicatedSymbolsUsings as CodeUsing[] ?? duplicatedSymbolsUsings.ToArray(); - //currentClass.StartBlock.RemoveUsings(symbolsUsing.ToArray()); + // currentClass.StartBlock.RemoveUsings(symbolsUsing.ToArray()); foreach (var usingElement in symbolsUsing) { var declaration = usingElement.Declaration.TypeDefinition?.Name; @@ -251,7 +251,8 @@ private static void AliasUsingWithSameSymbol(CodeElement currentElement) { .Split(new[]{'\\', '.'}, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.ToFirstCharacterUpperCase()) .ToArray()); - usingElement.Declaration.Name = $"{(string.IsNullOrEmpty(replacement) ? string.Empty : $"\\{replacement}")}\\{declaration.ToFirstCharacterUpperCase()}"; + usingElement.Alias = $"{(string.IsNullOrEmpty(replacement) ? string.Empty : $"\\{replacement}")}\\{declaration.ToFirstCharacterUpperCase()}"; + usingElement.Declaration.Name = usingElement.Alias; } } CrawlTree(currentElement, AliasUsingWithSameSymbol); diff --git a/src/Kiota.Builder/Writers/Php/PhpWriter.cs b/src/Kiota.Builder/Writers/Php/PhpWriter.cs index f48aea87d8..bfb876c678 100644 --- a/src/Kiota.Builder/Writers/Php/PhpWriter.cs +++ b/src/Kiota.Builder/Writers/Php/PhpWriter.cs @@ -13,6 +13,7 @@ public PhpWriter(string rootPath, string clientNamespaceName, bool useBackingSto AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService, useBackingStore)); AddOrReplaceCodeElementWriter(new CodeBlockEndWriter()); AddOrReplaceCodeElementWriter(new CodeEnumWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeTypeWriter(conventionService)); } } } From 7211351e4b64feb3ae623ef089e05869edc06d2a Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 01:34:50 +0300 Subject: [PATCH 03/14] Add hack to remove go from PHP imports. --- src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs | 4 ++-- src/Kiota.Builder/Refiners/PhpRefiner.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 8f433acb0a..7a78efc629 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -680,7 +680,7 @@ protected static void AddParentClassToErrorClasses(CodeElement currentElement, s } CrawlTree(currentElement, x => AddParentClassToErrorClasses(x, parentClassName, parentClassNamespace)); } - protected static void AddDiscriminatorMappingsUsingsToParentClasses(CodeElement currentElement, string parseNodeInterfaceName, bool addFactoryMethodImport = false, bool addUsings = true) { + protected static void AddDiscriminatorMappingsUsingsToParentClasses(CodeElement currentElement, string parseNodeInterfaceName, bool addFactoryMethodImport = false, bool addUsings = true, bool allowImportFromSameNamespace = true) { if(currentElement is CodeMethod currentMethod && currentMethod.Parent is CodeClass parentClass && parentClass.StartBlock is ClassDeclaration declaration) { @@ -692,7 +692,7 @@ currentMethod.Parent is CodeClass parentClass && .Select(static x => x.Value) .OfType() .Where(static x => x.TypeDefinition != null) - .Where(x => !x.TypeDefinition.GetImmediateParentOfType().Name.Equals(parentClassNamespace.Name, StringComparison.OrdinalIgnoreCase)) + .Where(x => allowImportFromSameNamespace || !x.TypeDefinition.GetImmediateParentOfType().Name.Equals(parentClassNamespace.Name, StringComparison.OrdinalIgnoreCase)) .Select(x => new CodeUsing { Name = x.TypeDefinition.GetImmediateParentOfType().Name, Declaration = new CodeType { diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 6fe228e7a3..5d644e34a2 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -41,7 +41,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddDiscriminatorMappingsUsingsToParentClasses( generatedCode, "ParseNode", - addUsings: true + addUsings: true, + allowImportFromSameNamespace: false ); var defaultConfiguration = new GenerationConfiguration(); ReplaceDefaultSerializationModules(generatedCode, From 2ca61d17079f2f4992b645e7e76e972e5cac7716 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 16:05:34 +0300 Subject: [PATCH 04/14] Fix imports for classes with the same namespace as current. --- src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs | 4 ++-- src/Kiota.Builder/Refiners/PhpRefiner.cs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 7a78efc629..8f433acb0a 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -680,7 +680,7 @@ protected static void AddParentClassToErrorClasses(CodeElement currentElement, s } CrawlTree(currentElement, x => AddParentClassToErrorClasses(x, parentClassName, parentClassNamespace)); } - protected static void AddDiscriminatorMappingsUsingsToParentClasses(CodeElement currentElement, string parseNodeInterfaceName, bool addFactoryMethodImport = false, bool addUsings = true, bool allowImportFromSameNamespace = true) { + protected static void AddDiscriminatorMappingsUsingsToParentClasses(CodeElement currentElement, string parseNodeInterfaceName, bool addFactoryMethodImport = false, bool addUsings = true) { if(currentElement is CodeMethod currentMethod && currentMethod.Parent is CodeClass parentClass && parentClass.StartBlock is ClassDeclaration declaration) { @@ -692,7 +692,7 @@ currentMethod.Parent is CodeClass parentClass && .Select(static x => x.Value) .OfType() .Where(static x => x.TypeDefinition != null) - .Where(x => allowImportFromSameNamespace || !x.TypeDefinition.GetImmediateParentOfType().Name.Equals(parentClassNamespace.Name, StringComparison.OrdinalIgnoreCase)) + .Where(x => !x.TypeDefinition.GetImmediateParentOfType().Name.Equals(parentClassNamespace.Name, StringComparison.OrdinalIgnoreCase)) .Select(x => new CodeUsing { Name = x.TypeDefinition.GetImmediateParentOfType().Name, Declaration = new CodeType { diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 5d644e34a2..6fe228e7a3 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -41,8 +41,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddDiscriminatorMappingsUsingsToParentClasses( generatedCode, "ParseNode", - addUsings: true, - allowImportFromSameNamespace: false + addUsings: true ); var defaultConfiguration = new GenerationConfiguration(); ReplaceDefaultSerializationModules(generatedCode, From 9e56d227b13ab7b2768ce2f3c8088ed69783c5fb Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 16:24:20 +0300 Subject: [PATCH 05/14] Remove commented out code. --- src/Kiota.Builder/Refiners/PhpRefiner.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 6fe228e7a3..c9695df5a1 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -242,7 +242,6 @@ private static void AliasUsingWithSameSymbol(CodeElement currentElement) { .Name .Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase))); var symbolsUsing = duplicatedSymbolsUsings as CodeUsing[] ?? duplicatedSymbolsUsings.ToArray(); - // currentClass.StartBlock.RemoveUsings(symbolsUsing.ToArray()); foreach (var usingElement in symbolsUsing) { var declaration = usingElement.Declaration.TypeDefinition?.Name; From 8b630472fc96600f9566397c2646249601a9fa35 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 16:30:51 +0300 Subject: [PATCH 06/14] Map Guid to String. --- src/Kiota.Builder/Writers/Php/PhpConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs index 48435097c5..3638e28bd9 100644 --- a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs +++ b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs @@ -63,7 +63,7 @@ public override string TranslateType(CodeType type) { "boolean" => "bool", "double" => "float", - "decimal" or "byte" => "string", + "decimal" or "byte" or "guid" => "string", "integer" or "int32" or "int64" or "sbyte" => "int", "object" or "string" or "array" or "float" or "void" => typeName.ToLowerInvariant(), "binary" => "StreamInterface", From f73eb29f3b6d9abfd16c417a7b99044f4d1f3c42 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 16:32:42 +0300 Subject: [PATCH 07/14] Restore to Latest --- src/Kiota.Builder/Kiota.Builder.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj index c19ef3477c..cf2cde1400 100644 --- a/src/Kiota.Builder/Kiota.Builder.csproj +++ b/src/Kiota.Builder/Kiota.Builder.csproj @@ -1,7 +1,7 @@  - preview + Latest net7.0 true https://github.com/microsoft/kiota From 2221ef69bc5ba210c61fe2618670e3cd67b57814 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 16:50:35 +0300 Subject: [PATCH 08/14] Address feedback. --- src/Kiota.Builder/Refiners/PhpRefiner.cs | 6 +++--- src/Kiota.Builder/Writers/Php/PhpConventionService.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index c9695df5a1..fe8f36c0b0 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -138,7 +138,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "Microsoft\\Kiota\\Abstractions", "HttpMethod", "RequestInformation", "RequestOption"), new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "Microsoft\\Kiota\\Abstractions", "ResponseHandler"), - new (x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(y => y.IsOfKind(CodePropertyKind.AdditionalData)), + 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), "Microsoft\\Kiota\\Abstractions\\Serialization", "SerializationWriter"), @@ -156,8 +156,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "Http\\Promise", "Promise", "RejectedPromise"), new (x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), "", "Exception"), new (x => x is CodeEnum, "Microsoft\\Kiota\\Abstractions\\", "Enum"), - new(x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTime", StringComparison.OrdinalIgnoreCase), "", "\\DateTime"), - new(x => x is CodeProperty {Type.Name: {}} property && property.Type.Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase), "", "\\DateTime"), + 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") diff --git a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs index 3638e28bd9..38ec86f440 100644 --- a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs +++ b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs @@ -172,7 +172,7 @@ public void WriteNamespaceAndImports(ClassDeclaration codeElement, LanguageWrite codeElement.Usings? .Where(x => x.Declaration != null && (x.Declaration.IsExternal || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase))) - .Where(x => string.IsNullOrEmpty(x.Alias)) + .Where(static x => string.IsNullOrEmpty(x.Alias)) .Select(x => { string namespaceValue; From 82e44f8ecdd5158311e0310e9dc5b6b84aa1649c Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Fri, 9 Dec 2022 17:20:36 +0300 Subject: [PATCH 09/14] Update CHANGELOG.md to reflect the latest changes on PHP generation. --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9db8e0edc..9662b84321 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Adds support for external documentation links on request execution methods. [#2036](https://github.com/microsoft/kiota/issues/2036) ### Changed - +- Fixed issue with wrong imports for PHP. [#2049](https://github.com/microsoft/kiota/pull/2049) +- Fix issue where discriminator types were never getting imported for PHP. [#2049](https://github.com/microsoft/kiota/pull/2049) +- Fix issue where class aliasing was never working as expected for PHP. [#2049](https://github.com/microsoft/kiota/pull/2049) - Fixed colliding imports for factory methods in TypeScript. [#2009](https://github.com/microsoft/kiota/issues/2009) - Switched to lazy loading module imports in Python. [#2007](https://github.com/microsoft/kiota/issues/2007) - Caters for type names being used from System namespace in CSharp generation [#2021](https://github.com/microsoft/kiota/issues/2021) From eee29ecc718d0b07e33588500514ac83fe9e6e08 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Tue, 13 Dec 2022 14:50:47 +0300 Subject: [PATCH 10/14] Update the tests. --- .../Refiners/GoLanguageRefinerTests.cs | 4 +- .../Refiners/PhpLanguageRefinerTests.cs | 55 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs index 0a99c4e03e..a89ff9da01 100644 --- a/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs @@ -6,6 +6,7 @@ using Kiota.Builder.Refiners; using Xunit; +using Xunit.Abstractions; namespace Kiota.Builder.Tests.Refiners; public class GoLanguageRefinerTests { @@ -250,7 +251,8 @@ public async Task AddsUsingsForDiscriminatorTypes() { TypeDefinition = childModel, }); Assert.Empty(parentModel.StartBlock.Usings); - root.AddNamespace("ApiSdk/models"); // so the interface copy refiner goes through + var ns = root.AddNamespace("ApiSdk/models"); + ns.AddClass(childModel);// so the interface copy refiner goes through await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Go }, root); Assert.Equal(childModel, parentModel.StartBlock.Usings.First(x => x.Declaration.Name.Equals("childModel", StringComparison.OrdinalIgnoreCase)).Declaration.TypeDefinition); Assert.Null(parentModel.StartBlock.Usings.FirstOrDefault(x => x.Declaration.Name.Equals("factory", StringComparison.OrdinalIgnoreCase))); diff --git a/tests/Kiota.Builder.Tests/Refiners/PhpLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/PhpLanguageRefinerTests.cs index 869c520283..a6eec2d80f 100644 --- a/tests/Kiota.Builder.Tests/Refiners/PhpLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/PhpLanguageRefinerTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Threading; using System.Threading.Tasks; using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; @@ -119,5 +120,59 @@ public async Task ChangesBackingStoreParameterTypeInApiClientConstructor() Assert.Equal("BackingStoreFactory", backingStoreParameter.Type.Name); Assert.Equal("null", backingStoreParameter.DefaultValue); } + + [Fact] + public async Task ImportsClassForDiscriminatorReturns() + { + var modelClass = new CodeClass + { + Name = "Entity", + Parent = root, + Kind = CodeClassKind.Model, + DiscriminatorInformation = new DiscriminatorInformation + { + Name = "createFromDiscriminatorValue", DiscriminatorPropertyName = "@odata.type", + } + }; + var parentClass = new CodeClass { Name = "ParentClass", Kind = CodeClassKind.Model, Parent = root }; + var subNamespace = root.AddNamespace("Security"); + subNamespace.Parent = root; + root.AddClass(modelClass); + + var securityClass = new CodeClass { Name = "Security", Parent = subNamespace, Kind = CodeClassKind.Model }; + var codeMethod = new CodeMethod + { + Name = "createFromDiscriminatorValue", + Kind = CodeMethodKind.Factory, + ReturnType = new CodeType { TypeDefinition = modelClass, Name = "Entity" } + }; + codeMethod.AddParameter(new CodeParameter + { + Name = "parseNode", + Type = new CodeType { Name = "ParseNode", IsExternal = true, }, + Kind = CodeParameterKind.ParseNode + }); + modelClass.DiscriminatorInformation.AddDiscriminatorMapping("#models.security", + new CodeType { Name = "Security", TypeDefinition = securityClass, }); + var tagClass = new CodeClass { Name = "Tag", Kind = CodeClassKind.Model, Parent = modelClass.Parent }; + root.AddClass(tagClass); + + modelClass.DiscriminatorInformation.AddDiscriminatorMapping("#models.security.Tag", + new CodeType { Name = "Tag", TypeDefinition = tagClass, }); + modelClass.DiscriminatorInformation.AddDiscriminatorMapping("#models.ParentClass", + new CodeType { Name = "ParentClass", TypeDefinition = parentClass, }); + + modelClass.DiscriminatorInformation.AddDiscriminatorMapping("#models.entity", + new CodeType { Name = "Entity", TypeDefinition = modelClass, }); + modelClass.AddMethod(codeMethod); + securityClass.StartBlock.Inherits = new CodeType + { + Name = "Entity", IsExternal = false, TypeDefinition = modelClass + }; + Assert.Empty(modelClass.Usings); + subNamespace.AddClass(securityClass); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.PHP }, root); + Assert.Equal(2, modelClass.Usings.Count()); + } } } From 1db34a85087fb553a2fd8a6fe973eff5c28cd758 Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Tue, 13 Dec 2022 14:55:45 +0300 Subject: [PATCH 11/14] Work on feedback. --- src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index e1f6af19d8..10a5df8510 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -719,7 +719,7 @@ currentMethod.Parent is CodeClass parentClass && .Select(static x => x.Value) .OfType() .Where(static x => x.TypeDefinition != null) - .Where(x => !x.TypeDefinition.GetImmediateParentOfType().Name.Equals(parentClassNamespace.Name, StringComparison.OrdinalIgnoreCase)) + .Where(x => x.TypeDefinition.GetImmediateParentOfType() != parentClassNamespace) .Select(x => new CodeUsing { Name = x.TypeDefinition.GetImmediateParentOfType().Name, Declaration = new CodeType { From 7b4e4c2a0eb3c4c494dcbe15d08422ff2d6824cf Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Tue, 13 Dec 2022 15:01:01 +0300 Subject: [PATCH 12/14] Remove unused method. --- src/Kiota.Builder/Writers/Php/PhpConventionService.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs index 38ec86f440..4ad61cb03a 100644 --- a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs +++ b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs @@ -227,11 +227,5 @@ private static bool IsSymbolDuplicated(string symbol, CodeElement targetElement) ?.Distinct(_usingDeclarationNameComparer) ?.Count() > 1; } - - private static string MakeNamespaceAliasVariable(string name) - { - var parts = name.Split(new[]{'\\', '.'}, StringSplitOptions.RemoveEmptyEntries); - return string.Join(string.Empty, parts.Select(x => x.ToFirstCharacterUpperCase()).ToArray()); - } } } From 99fc8f523c8399b18a1478d70af433f71bab7aca Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 13 Dec 2022 09:04:37 -0500 Subject: [PATCH 13/14] - fixes ambiguous method reference --- src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs index 826b85e1ec..b93ea62c58 100644 --- a/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs +++ b/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs @@ -9,7 +9,7 @@ public class PhpPathSegmenter : CommonPathSegmenter public PhpPathSegmenter(string rootPath, string clientNamespaceName) : base(rootPath, clientNamespaceName) { } public override string FileSuffix => ".php"; public override string NormalizeNamespaceSegment(string segmentName) => segmentName.ToFirstCharacterUpperCase(); - protected static new string GetLastFileNameSegment(CodeElement currentElement) => currentElement.Name.Split('.', '\\').Last(); + protected static new string GetLastFileNameSegment(CodeElement currentElement) => currentElement.Name.Split(new char[] {'.', '\\'}, StringSplitOptions.RemoveEmptyEntries).Last(); public override string NormalizeFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToFirstCharacterUpperCase(); } } From 6fdfabfa849669d138ed70076d9274dcf1ddf067 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 13 Dec 2022 09:11:54 -0500 Subject: [PATCH 14/14] - adds missing using --- src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs index b93ea62c58..70eeac76f0 100644 --- a/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs +++ b/src/Kiota.Builder/PathSegmenters/PHPPathSegmenter.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions;