From 4cd9ec16a67fba2d4cab91c33743dafc6ba8c0a2 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Sat, 27 Jan 2024 23:09:24 +0100 Subject: [PATCH 001/194] Added dart placeholder files --- src/Kiota.Builder/GenerationLanguage.cs | 3 +- .../PathSegmenters/DartPathSegmenter.cs | 17 +++++++ .../Writers/Dart/CodeBlockEndWriter.cs | 17 +++++++ .../Dart/CodeClassDeclarationWriter.cs | 15 ++++++ .../Writers/Dart/CodeEnumWriter.cs | 12 +++++ .../Writers/Dart/CodeIndexerWriter.cs | 12 +++++ .../Writers/Dart/CodeMethodWriter.cs | 19 +++++++ .../Writers/Dart/CodePropertyWriter.cs | 12 +++++ .../Writers/Dart/DartConventionService.cs | 51 +++++++++++++++++++ src/Kiota.Builder/Writers/Dart/DartWriter.cs | 19 +++++++ src/Kiota.Builder/Writers/LanguageWriter.cs | 2 + 11 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs create mode 100644 src/Kiota.Builder/Writers/Dart/DartConventionService.cs create mode 100644 src/Kiota.Builder/Writers/Dart/DartWriter.cs diff --git a/src/Kiota.Builder/GenerationLanguage.cs b/src/Kiota.Builder/GenerationLanguage.cs index dbd236ade7..278bdcd8b2 100644 --- a/src/Kiota.Builder/GenerationLanguage.cs +++ b/src/Kiota.Builder/GenerationLanguage.cs @@ -9,5 +9,6 @@ public enum GenerationLanguage Go, Swift, Ruby, - CLI + CLI, + Dart, } diff --git a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs new file mode 100644 index 0000000000..541d8a0f0d --- /dev/null +++ b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs @@ -0,0 +1,17 @@ +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; + +namespace Kiota.Builder.PathSegmenters; + +public class DartPathSegmenter : CommonPathSegmenter +{ + public DartPathSegmenter(string rootPath, string clientNamespaceName) : base(rootPath, clientNamespaceName) { } + public override string FileSuffix => ".dart"; + + public override string NormalizeNamespaceSegment(string segmentName) + { + throw new System.NotImplementedException(); + } + + public override string NormalizeFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToCamelCase(); +} diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs new file mode 100644 index 0000000000..9ee143ac23 --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -0,0 +1,17 @@ +using System; +using Kiota.Builder.CodeDOM; + +namespace Kiota.Builder.Writers.Dart; +public class CodeBlockEndWriter : BaseElementWriter +{ + public CodeBlockEndWriter(DartConventionService conventionService) : base(conventionService) { } + public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.CloseBlock(); + if (codeElement?.Parent is CodeClass) + { + writer.CloseBlock(); + } + } +} diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs new file mode 100644 index 0000000000..8fb53c0fc9 --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -0,0 +1,15 @@ +using Kiota.Builder.CodeDOM; + +namespace Kiota.Builder.Writers.Dart; + +public class CodeClassDeclarationWriter : BaseElementWriter +{ + public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) + { + } + + public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) + { + throw new System.NotImplementedException(); + } +} diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs new file mode 100644 index 0000000000..a114396d0e --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -0,0 +1,12 @@ +using System; +using Kiota.Builder.CodeDOM; + +namespace Kiota.Builder.Writers.Dart; +public class CodeEnumWriter : BaseElementWriter +{ + public CodeEnumWriter(DartConventionService conventionService) : base(conventionService) { } + public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter writer) + { + throw new NotImplementedException(); + } +} diff --git a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs new file mode 100644 index 0000000000..d4df5fff00 --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs @@ -0,0 +1,12 @@ +using System; +using Kiota.Builder.CodeDOM; + +namespace Kiota.Builder.Writers.Dart; +public class CodeIndexerWriter : BaseElementWriter +{ + public CodeIndexerWriter(DartConventionService conventionService) : base(conventionService) { } + public override void WriteCodeElement(CodeIndexer codeElement, LanguageWriter writer) + { + throw new NotImplementedException(); + } +} diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs new file mode 100644 index 0000000000..9cf16e3b4d --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; +using Kiota.Builder.OrderComparers; + +namespace Kiota.Builder.Writers.Dart; +public class CodeMethodWriter : BaseElementWriter +{ + public CodeMethodWriter(DartConventionService conventionService) : base(conventionService) + { + } + + public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer) + { + throw new NotImplementedException(); + } +} diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs new file mode 100644 index 0000000000..f2cd85fb24 --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -0,0 +1,12 @@ +using System; +using Kiota.Builder.CodeDOM; + +namespace Kiota.Builder.Writers.Dart; +public class CodePropertyWriter : BaseElementWriter +{ + public CodePropertyWriter(DartConventionService conventionService) : base(conventionService) { } + public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter writer) + { + throw new NotImplementedException(); + } +} diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs new file mode 100644 index 0000000000..f3019ed076 --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -0,0 +1,51 @@ +using Kiota.Builder.CodeDOM; + +namespace Kiota.Builder.Writers.Dart; + +public class DartConventionService : CommonLanguageConventionService +{ + public override string GetAccessModifier(AccessModifier access) + { + throw new System.NotImplementedException(); + } + + public override string TranslateType(CodeType type) + { + throw new System.NotImplementedException(); + } + + public override void WriteShortDescription(string description, LanguageWriter writer) + { + throw new System.NotImplementedException(); + } + + public override string GetParameterSignature(CodeParameter parameter, CodeElement targetElement, LanguageWriter? writer = null) + { + throw new System.NotImplementedException(); + } + + public override string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool includeCollectionInformation = true, + LanguageWriter? writer = null) + { + throw new System.NotImplementedException(); + } + + public override string StreamTypeName + { + get; + } + + public override string VoidTypeName => "void"; + + public override string DocCommentPrefix => "///"; + + public override string ParseNodeInterfaceName + { + get; + } + + public override string TempDictionaryVarName + { + get; + } +} diff --git a/src/Kiota.Builder/Writers/Dart/DartWriter.cs b/src/Kiota.Builder/Writers/Dart/DartWriter.cs new file mode 100644 index 0000000000..ff43a5986e --- /dev/null +++ b/src/Kiota.Builder/Writers/Dart/DartWriter.cs @@ -0,0 +1,19 @@ +using Kiota.Builder.PathSegmenters; + +namespace Kiota.Builder.Writers.Dart; + +public class DartWriter : LanguageWriter +{ + public DartWriter(string outputPath, string clientNamespaceName) + { + PathSegmenter = new DartPathSegmenter(outputPath, clientNamespaceName); + var conventionService = new DartConventionService(); + AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeBlockEndWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeEnumWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeIndexerWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodePropertyWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeTypeWriter(conventionService)); + } +} diff --git a/src/Kiota.Builder/Writers/LanguageWriter.cs b/src/Kiota.Builder/Writers/LanguageWriter.cs index 54ece0b814..f8b3a275b1 100644 --- a/src/Kiota.Builder/Writers/LanguageWriter.cs +++ b/src/Kiota.Builder/Writers/LanguageWriter.cs @@ -8,6 +8,7 @@ using Kiota.Builder.PathSegmenters; using Kiota.Builder.Writers.Cli; using Kiota.Builder.Writers.CSharp; +using Kiota.Builder.Writers.Dart; using Kiota.Builder.Writers.Go; using Kiota.Builder.Writers.Java; using Kiota.Builder.Writers.Php; @@ -186,6 +187,7 @@ public static LanguageWriter GetLanguageWriter(GenerationLanguage language, stri GenerationLanguage.Go => new GoWriter(outputPath, clientNamespaceName, excludeBackwardCompatible), GenerationLanguage.CLI => new CliWriter(outputPath, clientNamespaceName), GenerationLanguage.Swift => new SwiftWriter(outputPath, clientNamespaceName), + GenerationLanguage.Dart => new DartWriter(outputPath, clientNamespaceName), _ => throw new InvalidEnumArgumentException($"{language} language currently not supported."), }; } From ffff17d40320737d09f1a70c9081886a3fe8731a Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Sat, 27 Jan 2024 23:42:38 +0100 Subject: [PATCH 002/194] Implemented some methods for testing generation, added run config --- .../PathSegmenters/DartPathSegmenter.cs | 8 +++---- .../Dart/CodeClassDeclarationWriter.cs | 8 +++++-- .../Writers/Dart/CodeMethodWriter.cs | 14 +++++++++---- .../Writers/Dart/CodePropertyWriter.cs | 11 +++++++++- .../Writers/Dart/DartConventionService.cs | 21 +++++++++++++------ src/kiota/Properties/launchSettings.json | 4 ++++ 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs index 541d8a0f0d..92b5a0b94c 100644 --- a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs +++ b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs @@ -6,12 +6,10 @@ namespace Kiota.Builder.PathSegmenters; public class DartPathSegmenter : CommonPathSegmenter { public DartPathSegmenter(string rootPath, string clientNamespaceName) : base(rootPath, clientNamespaceName) { } + public override string FileSuffix => ".dart"; - public override string NormalizeNamespaceSegment(string segmentName) - { - throw new System.NotImplementedException(); - } + public override string NormalizeNamespaceSegment(string segmentName) => segmentName.ToCamelCase(); - public override string NormalizeFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToCamelCase(); + public override string NormalizeFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToSnakeCase(); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 8fb53c0fc9..4e0271a334 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -1,4 +1,5 @@ -using Kiota.Builder.CodeDOM; +using System; +using Kiota.Builder.CodeDOM; namespace Kiota.Builder.Writers.Dart; @@ -10,6 +11,9 @@ public CodeClassDeclarationWriter(DartConventionService conventionService) : bas public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { - throw new System.NotImplementedException(); + ArgumentNullException.ThrowIfNull(codeElement); + ArgumentNullException.ThrowIfNull(writer); + + writer.WriteLine("class " + codeElement.Name + " {"); } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 9cf16e3b4d..3f69455038 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; -using Kiota.Builder.OrderComparers; namespace Kiota.Builder.Writers.Dart; public class CodeMethodWriter : BaseElementWriter @@ -14,6 +11,15 @@ public CodeMethodWriter(DartConventionService conventionService) : base(conventi public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer) { - throw new NotImplementedException(); + ArgumentNullException.ThrowIfNull(codeElement); + ArgumentNullException.ThrowIfNull(writer); + + var returnType = conventions.TranslateType(codeElement.ReturnType); + var methodName = codeElement.Name.ToFirstCharacterUpperCase(); + writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {returnType} {methodName}() {{"); + writer.IncreaseIndent(); + writer.WriteLine("throw \"not implemented\";"); + writer.DecreaseIndent(); + writer.WriteLine("}"); } } diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index f2cd85fb24..b3e45ee161 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -1,5 +1,6 @@ using System; using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodePropertyWriter : BaseElementWriter @@ -7,6 +8,14 @@ public class CodePropertyWriter : BaseElementWriter "_", + AccessModifier.Protected => "", + AccessModifier.Public => "", + _ => throw new ArgumentOutOfRangeException(nameof(access), access, null), + }; } public override string TranslateType(CodeType type) { - throw new System.NotImplementedException(); + ArgumentNullException.ThrowIfNull(type); + + return type.Name; } public override void WriteShortDescription(string description, LanguageWriter writer) @@ -32,7 +41,7 @@ public override string GetTypeString(CodeTypeBase code, CodeElement targetElemen public override string StreamTypeName { - get; + get => "Stream"; } public override string VoidTypeName => "void"; @@ -41,11 +50,11 @@ public override string StreamTypeName public override string ParseNodeInterfaceName { - get; + get => "IParseNode"; } public override string TempDictionaryVarName { - get; + get => "tempDictionary"; } } diff --git a/src/kiota/Properties/launchSettings.json b/src/kiota/Properties/launchSettings.json index cfdf1701e0..f08c0d3028 100644 --- a/src/kiota/Properties/launchSettings.json +++ b/src/kiota/Properties/launchSettings.json @@ -3,6 +3,10 @@ "kiota": { "commandName": "Project", "commandLineArgs": "--openapi C:\\src\\msgraph-sdk-powershell\\openApiDocs\\v1.0\\mail.yml -o C:\\Users\\darrmi\\source\\github\\darrelmiller\\OpenApiClient\\Generated -c GraphClient --loglevel Information" + }, + "dart": { + "commandName": "Project", + "commandLineArgs": "generate --openapi D:\\swagger.json -o D:\\generated --log-level Debug -l Dart" } } } From 54808476279f95b3a8ce2c834873709d90fe5d07 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Sun, 28 Jan 2024 17:31:16 +0100 Subject: [PATCH 003/194] Use CSharp as a baseline --- .../Writers/Dart/CodeBlockEndWriter.cs | 2 +- .../Dart/CodeClassDeclarationWriter.cs | 35 +- .../Writers/Dart/CodeEnumWriter.cs | 44 +- .../Writers/Dart/CodeIndexerWriter.cs | 14 +- .../Writers/Dart/CodeMethodWriter.cs | 644 +++++++++++++++++- .../Writers/Dart/CodePropertyWriter.cs | 68 +- .../Writers/Dart/DartConventionService.cs | 279 +++++++- src/Kiota.Builder/Writers/Dart/DartWriter.cs | 6 +- 8 files changed, 1041 insertions(+), 51 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index 9ee143ac23..905b859000 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -9,7 +9,7 @@ public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter write { ArgumentNullException.ThrowIfNull(writer); writer.CloseBlock(); - if (codeElement?.Parent is CodeClass) + if (codeElement?.Parent is CodeClass codeClass && codeClass.Parent is CodeNamespace) { writer.CloseBlock(); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 4e0271a334..c4da764b40 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -1,19 +1,42 @@ using System; +using System.Linq; using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Dart; - public class CodeClassDeclarationWriter : BaseElementWriter { - public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) - { - } - + public static string AutoGenerationHeader => "// "; + public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(codeElement); ArgumentNullException.ThrowIfNull(writer); + if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); + + if (codeElement.Parent?.Parent is CodeNamespace) + { + writer.WriteLine(AutoGenerationHeader); + codeElement.Usings + .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder + .Select(static x => x.Declaration?.IsExternal ?? false ? + $"using {x.Declaration.Name.NormalizeNameSpaceName(".")};" : + $"using {x.Name.NormalizeNameSpaceName(".")};") + .Distinct(StringComparer.Ordinal) + .OrderBy(static x => x, StringComparer.Ordinal) + .ToList() + .ForEach(x => writer.WriteLine(x)); + writer.StartBlock($"namespace {codeElement.Parent.Parent.Name} {{"); + } - writer.WriteLine("class " + codeElement.Name + " {"); + var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : new string?[] { conventions.GetTypeString(codeElement.Inherits, parentClass) }) + .Union(codeElement.Implements.Select(static x => x.Name)) + .OfType() + .Select(static x => x.ToFirstCharacterUpperCase()) + .ToArray(); + var derivation = derivedTypes.Length != 0 ? ": " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") + " " : string.Empty; + conventions.WriteLongDescription(parentClass.Documentation, writer); + conventions.WriteDeprecationAttribute(parentClass, writer); + writer.StartBlock($"public class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{"); } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index a114396d0e..3ddebab23c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -1,12 +1,54 @@ using System; +using System.Globalization; +using System.Linq; + using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeEnumWriter : BaseElementWriter { + public static string AutoGenerationHeader => "// "; public CodeEnumWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter writer) { - throw new NotImplementedException(); + ArgumentNullException.ThrowIfNull(codeElement); + ArgumentNullException.ThrowIfNull(writer); + if (!codeElement.Options.Any()) + return; + + var codeNamespace = codeElement.Parent as CodeNamespace; + if (codeNamespace != null) + { + writer.WriteLine(AutoGenerationHeader); + foreach (var x in codeElement.Usings + .Where(static x => x.Declaration?.IsExternal ?? true) + .Select(static x => $"using {(x.Declaration?.Name ?? x.Name).NormalizeNameSpaceName(".")};") + .Distinct(StringComparer.Ordinal) + .OrderBy(static x => x, StringComparer.Ordinal)) + writer.WriteLine(x); + writer.StartBlock($"namespace {codeNamespace.Name} {{"); + } + conventions.WriteShortDescription(codeElement.Documentation.Description, writer); + if (codeElement.Flags) + writer.WriteLine("[Flags]"); + conventions.WriteDeprecationAttribute(codeElement, writer); + writer.StartBlock($"public enum {codeElement.Name.ToFirstCharacterUpperCase()} {{"); + var idx = 0; + foreach (var option in codeElement.Options) + { + conventions.WriteShortDescription(option.Documentation.Description, writer); + + if (option.IsNameEscaped) + { + writer.WriteLine($"[EnumMember(Value = \"{option.SerializationName}\")]"); + } + writer.WriteLine($"{option.Name.ToFirstCharacterUpperCase()}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); + idx++; + } + if (codeNamespace != null) + writer.CloseBlock(); } + private static readonly Func GetEnumFlag = static idx => + (idx == 0 ? 1 : Math.Pow(2, idx)).ToString(CultureInfo.InvariantCulture); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs index d4df5fff00..6eccacb32e 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs @@ -1,5 +1,6 @@ using System; using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeIndexerWriter : BaseElementWriter @@ -7,6 +8,17 @@ public class CodeIndexerWriter : BaseElementWriter{codeElement.IndexParameter.Documentation.Description.CleanupXMLString()}"); + conventions.WriteDeprecationAttribute(codeElement, writer); + writer.StartBlock($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexParameter.Type, codeElement)} position] {{ get {{"); + if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp) + conventions.AddParametersAssignment(writer, pathParametersProp.Type, pathParametersProp.Name.ToFirstCharacterUpperCase(), string.Empty, (codeElement.IndexParameter.Type, codeElement.IndexParameter.SerializationName, "position")); + conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName, "return "); + writer.CloseBlock("} }"); } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 3f69455038..d7d235b8c4 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -1,25 +1,655 @@ using System; +using System.Collections.Generic; +using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.OrderComparers; namespace Kiota.Builder.Writers.Dart; public class CodeMethodWriter : BaseElementWriter { public CodeMethodWriter(DartConventionService conventionService) : base(conventionService) { - } + } public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(codeElement); + if (codeElement.ReturnType == null) throw new InvalidOperationException($"{nameof(codeElement.ReturnType)} should not be null"); ArgumentNullException.ThrowIfNull(writer); + if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("the parent of a method should be a class"); - var returnType = conventions.TranslateType(codeElement.ReturnType); - var methodName = codeElement.Name.ToFirstCharacterUpperCase(); - writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {returnType} {methodName}() {{"); + var returnType = conventions.GetTypeString(codeElement.ReturnType, codeElement); + var inherits = parentClass.StartBlock.Inherits != null && !parentClass.IsErrorDefinition; + var isVoid = conventions.VoidTypeName.Equals(returnType, StringComparison.OrdinalIgnoreCase); + WriteMethodDocumentation(codeElement, writer); + WriteMethodPrototype(codeElement, parentClass, writer, returnType, inherits, isVoid); writer.IncreaseIndent(); - writer.WriteLine("throw \"not implemented\";"); - writer.DecreaseIndent(); - writer.WriteLine("}"); + foreach (var parameter in codeElement.Parameters.Where(static x => !x.Optional && !x.IsOfKind(CodeParameterKind.RequestAdapter, CodeParameterKind.PathParameters, CodeParameterKind.RawUrl)).OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) + { + var parameterName = parameter.Name.ToFirstCharacterLowerCase(); + if (nameof(String).Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase) && parameter.Type.CollectionKind == CodeTypeBase.CodeTypeCollectionKind.None) + writer.WriteLine($"if(string.IsNullOrEmpty({parameterName})) throw new ArgumentNullException(nameof({parameterName}));"); + else + writer.WriteLine($"_ = {parameterName} ?? throw new ArgumentNullException(nameof({parameterName}));"); + } + HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); + writer.CloseBlock(); + } + + protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter writer, bool doesInherit, CodeClass parentClass, bool isVoid) + { + ArgumentNullException.ThrowIfNull(codeElement); + ArgumentNullException.ThrowIfNull(writer); + ArgumentNullException.ThrowIfNull(parentClass); + var returnType = conventions.GetTypeString(codeElement.ReturnType, codeElement); + var returnTypeWithoutCollectionInformation = conventions.GetTypeString(codeElement.ReturnType, codeElement, false); + var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody); + var requestConfig = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration); + var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType); + var requestParams = new RequestParams(requestBodyParam, requestConfig, requestContentType); + switch (codeElement.Kind) + { + case CodeMethodKind.Serializer: + WriteSerializerBody(doesInherit, codeElement, parentClass, writer); + break; + case CodeMethodKind.RequestGenerator: + WriteRequestGeneratorBody(codeElement, requestParams, parentClass, writer); + break; + case CodeMethodKind.RequestExecutor: + WriteRequestExecutorBody(codeElement, requestParams, parentClass, isVoid, returnTypeWithoutCollectionInformation, writer); + break; + case CodeMethodKind.Deserializer: + WriteDeserializerBody(doesInherit, codeElement, parentClass, writer); + break; + case CodeMethodKind.ClientConstructor: + WriteConstructorBody(parentClass, codeElement, writer); + WriteApiConstructorBody(parentClass, codeElement, writer); + break; + case CodeMethodKind.RawUrlBuilder: + WriteRawUrlBuilderBody(parentClass, codeElement, writer); + break; + case CodeMethodKind.Constructor: + case CodeMethodKind.RawUrlConstructor: + WriteConstructorBody(parentClass, codeElement, writer); + break; + case CodeMethodKind.RequestBuilderWithParameters: + WriteRequestBuilderBody(parentClass, codeElement, writer); + break; + case CodeMethodKind.Getter: + case CodeMethodKind.Setter: + throw new InvalidOperationException("getters and setters are automatically added on fields in dotnet"); + case CodeMethodKind.RequestBuilderBackwardCompatibility: + throw new InvalidOperationException("RequestBuilderBackwardCompatibility is not supported as the request builders are implemented by properties."); + case CodeMethodKind.ErrorMessageOverride: + throw new InvalidOperationException("ErrorMessageOverride is not supported as the error message is implemented by a property."); + case CodeMethodKind.CommandBuilder: + var origParams = codeElement.OriginalMethod?.Parameters ?? codeElement.Parameters; + requestBodyParam = origParams.OfKind(CodeParameterKind.RequestBody); + requestConfig = origParams.OfKind(CodeParameterKind.RequestConfiguration); + requestContentType = origParams.OfKind(CodeParameterKind.RequestBodyContentType); + requestParams = new RequestParams(requestBodyParam, requestConfig, requestContentType); + WriteCommandBuilderBody(codeElement, parentClass, requestParams, isVoid, returnType, writer); + break; + case CodeMethodKind.Factory: + WriteFactoryMethodBody(codeElement, parentClass, writer); + break; + case CodeMethodKind.ComposedTypeMarker: + throw new InvalidOperationException("ComposedTypeMarker is not required as interface is explicitly implemented."); + default: + writer.WriteLine("return null;"); + break; + } + } + private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) + { + var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); + var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property"); + writer.WriteLine($"return new {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterUpperCase()});"); + } + private static readonly CodePropertyTypeComparer CodePropertyTypeForwardComparer = new(); + private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true); + private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) + { + writer.StartBlock($"return {DiscriminatorMappingVarName} switch {{"); + foreach (var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings) + { + writer.WriteLine($"\"{mappedType.Key}\" => new {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); + } + writer.WriteLine($"_ => new {parentClass.Name.ToFirstCharacterUpperCase()}(),"); + writer.CloseBlock("};"); + } + private const string ResultVarName = "result"; + private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) + { + writer.WriteLine($"var {ResultVarName} = new {parentClass.Name.ToFirstCharacterUpperCase()}();"); + var includeElse = false; + foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .OrderBy(static x => x, CodePropertyTypeForwardComparer) + .ThenBy(static x => x.Name, StringComparer.Ordinal)) + { + if (property.Type is CodeType propertyType) + if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) + { + var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if(\"{mappedType.Key}\".Equals({DiscriminatorMappingVarName}, StringComparison.OrdinalIgnoreCase)) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = new {conventions.GetTypeString(propertyType, codeElement)}();"); + writer.CloseBlock(); + } + else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) + { + var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName}) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};"); + writer.CloseBlock(); + } + if (!includeElse) + includeElse = true; + } + writer.WriteLine($"return {ResultVarName};"); + } + private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) + { + writer.WriteLine($"var {ResultVarName} = new {parentClass.Name.ToFirstCharacterUpperCase()}();"); + var includeElse = false; + foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => x.Type is not CodeType propertyType || propertyType.IsCollection || propertyType.TypeDefinition is not CodeClass) + .OrderBy(static x => x, CodePropertyTypeBackwardComparer) + .ThenBy(static x => x.Name, StringComparer.Ordinal)) + { + if (property.Type is CodeType propertyType) + { + var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName}) {{"); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};"); + writer.CloseBlock(); + } + if (!includeElse) + includeElse = true; + } + var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => x.Type is CodeType xType && xType.TypeDefinition is CodeClass && !xType.IsCollection) + .Select(static x => new Tuple(x, (CodeType)x.Type)) + .ToArray(); + if (complexProperties.Length != 0) + { + if (includeElse) + { + writer.WriteLine("else {"); + writer.IncreaseIndent(); + } + foreach (var property in complexProperties) + writer.WriteLine($"{ResultVarName}.{property.Item1.Name.ToFirstCharacterUpperCase()} = new {conventions.GetTypeString(property.Item2, codeElement)}();"); + if (includeElse) + { + writer.CloseBlock(); + } + } + writer.WriteLine($"return {ResultVarName};"); + } + private const string DiscriminatorMappingVarName = "mappingValue"; + private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) + { + var parseNodeParameter = codeElement.Parameters.OfKind(CodeParameterKind.ParseNode) ?? throw new InvalidOperationException("Factory method should have a ParseNode parameter"); + + if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) + writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.GetChildNode(\"{parentClass.DiscriminatorInformation.DiscriminatorPropertyName}\")?.GetStringValue();"); + + if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) + WriteFactoryMethodBodyForInheritedModel(codeElement, parentClass, writer); + else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) + WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); + else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) + WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); + else + writer.WriteLine($"return new {parentClass.Name.ToFirstCharacterUpperCase()}();"); + } + private void WriteRequestBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) + { + var importSymbol = conventions.GetTypeString(codeElement.ReturnType, parentClass); + conventions.AddRequestBuilderBody(parentClass, importSymbol, writer, prefix: "return ", pathParameters: codeElement.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Path))); + } + private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) + { + if (parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is not CodeProperty requestAdapterProperty) return; + var pathParametersProperty = parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters); + var backingStoreParameter = method.Parameters.OfKind(CodeParameterKind.BackingStore); + var requestAdapterPropertyName = requestAdapterProperty.Name.ToFirstCharacterUpperCase(); + WriteSerializationRegistration(method.SerializerModules, writer, "RegisterDefaultSerializer"); + WriteSerializationRegistration(method.DeserializerModules, writer, "RegisterDefaultDeserializer"); + if (!string.IsNullOrEmpty(method.BaseUrl)) + { + writer.StartBlock($"if (string.IsNullOrEmpty({requestAdapterPropertyName}.BaseUrl)) {{"); + writer.WriteLine($"{requestAdapterPropertyName}.BaseUrl = \"{method.BaseUrl}\";"); + writer.CloseBlock(); + if (pathParametersProperty != null) + writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterUpperCase()}.TryAdd(\"baseurl\", {requestAdapterPropertyName}.BaseUrl);"); + } + if (backingStoreParameter != null) + writer.WriteLine($"{requestAdapterPropertyName}.EnableBackingStore({backingStoreParameter.Name});"); + } + private static void WriteSerializationRegistration(HashSet serializationClassNames, LanguageWriter writer, string methodName) + { + if (serializationClassNames != null) + foreach (var serializationClassName in serializationClassNames) + writer.WriteLine($"ApiClientBuilder.{methodName}<{serializationClassName}>();"); + } + private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer) + { + foreach (var propWithDefault in parentClass + .Properties + .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters)) + // do not apply the default value if the type is composed as the default value may not necessarily which type to use + .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) + .OrderByDescending(static x => x.Kind) + .ThenBy(static x => x.Name)) + { + var defaultValue = propWithDefault.DefaultValue; + if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) + { + defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; + } + writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterUpperCase()} = {defaultValue};"); + } + if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && + parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && + currentMethod.IsOfKind(CodeMethodKind.Constructor) && + currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParam) + { + var pathParameters = currentMethod.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Path)); + if (pathParameters.Any()) + conventions.AddParametersAssignment(writer, + pathParametersParam.Type, + pathParametersParam.Name.ToFirstCharacterLowerCase(), + pathParametersProp.Name.ToFirstCharacterUpperCase(), + currentMethod.Parameters + .Where(static x => x.IsOfKind(CodeParameterKind.Path)) + .Select(static x => (x.Type, string.IsNullOrEmpty(x.SerializationName) ? x.Name : x.SerializationName, x.Name.ToFirstCharacterLowerCase())) + .ToArray()); + } + } + private string DefaultDeserializerValue => $"new Dictionary>"; + private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) + { + if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) + WriteDeserializerBodyForUnionModel(codeElement, parentClass, writer); + else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) + WriteDeserializerBodyForIntersectionModel(parentClass, writer); + else + WriteDeserializerBodyForInheritedModel(shouldHide, codeElement, parentClass, writer); + } + private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) + { + var includeElse = false; + foreach (var otherPropName in parentClass + .GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => !x.ExistsInBaseType) + .Where(static x => x.Type is CodeType propertyType && !propertyType.IsCollection && propertyType.TypeDefinition is CodeClass) + .OrderBy(static x => x, CodePropertyTypeForwardComparer) + .ThenBy(static x => x.Name) + .Select(static x => x.Name.ToFirstCharacterUpperCase())) + { + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({otherPropName} != null) {{"); + writer.WriteLine($"return {otherPropName}.{method.Name.ToFirstCharacterUpperCase()}();"); + writer.CloseBlock(); + if (!includeElse) + includeElse = true; + } + writer.WriteLine($"return {DefaultDeserializerValue}();"); + } + private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) + { + var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => x.Type is CodeType propType && propType.TypeDefinition is CodeClass && !x.Type.IsCollection) + .ToArray(); + if (complexProperties.Length != 0) + { + var propertiesNames = complexProperties + .Select(static x => x.Name.ToFirstCharacterUpperCase()) + .OrderBy(static x => x) + .ToArray(); + var propertiesNamesAsConditions = propertiesNames + .Select(static x => $"{x} != null") + .Aggregate(static (x, y) => $"{x} || {y}"); + writer.StartBlock($"if({propertiesNamesAsConditions}) {{"); + var propertiesNamesAsArgument = propertiesNames + .Aggregate(static (x, y) => $"{x}, {y}"); + writer.WriteLine($"return ParseNodeHelper.MergeDeserializersForIntersectionWrapper({propertiesNamesAsArgument});"); + writer.CloseBlock(); + } + writer.WriteLine($"return {DefaultDeserializerValue}();"); + } + private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) + { + var parentSerializationInfo = shouldHide ? $"(base.{codeElement.Name.ToFirstCharacterUpperCase()}())" : string.Empty; + writer.StartBlock($"return {DefaultDeserializerValue}{parentSerializationInfo} {{"); + foreach (var otherProp in parentClass + .GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => !x.ExistsInBaseType) + .OrderBy(static x => x.Name, StringComparer.Ordinal)) + { + writer.WriteLine($"{{\"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},"); + } + writer.CloseBlock("};"); + } + private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod method) + { + var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; + var propertyType = conventions.GetTypeString(propType, method, false); + if (propType is CodeType currentType) + { + if (isCollection) + { + var collectionMethod = propType.IsArray ? "?.ToArray()" : "?.ToList()"; + if (currentType.TypeDefinition == null) + return $"GetCollectionOfPrimitiveValues<{propertyType}>(){collectionMethod}"; + else if (currentType.TypeDefinition is CodeEnum) + return $"GetCollectionOfEnumValues<{propertyType.TrimEnd('?')}>(){collectionMethod}"; + else + return $"GetCollectionOfObjectValues<{propertyType}>({propertyType}.CreateFromDiscriminatorValue){collectionMethod}"; + } + else if (currentType.TypeDefinition is CodeEnum enumType) + return $"GetEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>()"; + } + return propertyType switch + { + "byte[]" => "GetByteArrayValue()", + _ when conventions.IsPrimitiveType(propertyType) => $"Get{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value()", + _ => $"GetObjectValue<{propertyType.ToFirstCharacterUpperCase()}>({propertyType}.CreateFromDiscriminatorValue)", + }; + } + protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams requestParams, CodeClass parentClass, bool isVoid, string returnTypeWithoutCollectionInformation, LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(codeElement); + ArgumentNullException.ThrowIfNull(requestParams); + ArgumentNullException.ThrowIfNull(parentClass); + ArgumentNullException.ThrowIfNull(writer); + if (codeElement.HttpMethod == null) throw new InvalidOperationException("http method cannot be null"); + + var generatorMethodName = parentClass + .Methods + .FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestGenerator) && x.HttpMethod == codeElement.HttpMethod) + ?.Name; + var parametersList = new CodeParameter?[] { requestParams.requestBody, requestParams.requestContentType, requestParams.requestConfiguration } + .Select(static x => x?.Name).Where(static x => x != null).Aggregate(static (x, y) => $"{x}, {y}"); + writer.WriteLine($"var requestInfo = {generatorMethodName}({parametersList});"); + var errorMappingVarName = "default"; + if (codeElement.ErrorMappings.Any()) + { + errorMappingVarName = "errorMapping"; + writer.WriteLine($"var {errorMappingVarName} = new Dictionary> {{"); + writer.IncreaseIndent(); + foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) + { + writer.WriteLine($"{{\"{errorMapping.Key.ToUpperInvariant()}\", {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.CreateFromDiscriminatorValue}},"); + } + writer.CloseBlock("};"); + } + var returnTypeCodeType = codeElement.ReturnType as CodeType; + var returnTypeFactory = returnTypeCodeType?.TypeDefinition is CodeClass + ? $", {returnTypeWithoutCollectionInformation}.CreateFromDiscriminatorValue" + : null; + var prefix = (isVoid, codeElement.ReturnType.IsCollection) switch + { + (true, _) => string.Empty, + (_, true) => "var collectionResult = ", + (_, _) => "return ", + }; + writer.WriteLine($"{prefix}await RequestAdapter.{GetSendRequestMethodName(isVoid, codeElement, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, {errorMappingVarName}, cancellationToken).ConfigureAwait(false);"); + if (codeElement.ReturnType.IsCollection) + writer.WriteLine("return collectionResult?.ToList();"); + } + private const string RequestInfoVarName = "requestInfo"; + private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams requestParams, CodeClass currentClass, LanguageWriter writer) + { + if (codeElement.HttpMethod == null) throw new InvalidOperationException("http method cannot be null"); + if (currentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is not CodeProperty urlTemplateParamsProperty) throw new InvalidOperationException("path parameters property cannot be null"); + if (currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate) is not CodeProperty urlTemplateProperty) throw new InvalidOperationException("url template property cannot be null"); + + var operationName = codeElement.HttpMethod.ToString(); + writer.WriteLine($"var {RequestInfoVarName} = new RequestInformation(Method.{operationName?.ToUpperInvariant()}, {GetPropertyCall(urlTemplateProperty, "string.Empty")}, {GetPropertyCall(urlTemplateParamsProperty, "string.Empty")});"); + + if (requestParams.requestConfiguration != null) + writer.WriteLine($"{RequestInfoVarName}.Configure({requestParams.requestConfiguration.Name});"); + + if (codeElement.ShouldAddAcceptHeader) + writer.WriteLine($"{RequestInfoVarName}.Headers.TryAdd(\"Accept\", \"{codeElement.AcceptHeaderValue}\");"); + if (requestParams.requestBody != null) + { + var suffix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty; + if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase)) + { + if (requestParams.requestContentType is not null) + writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name});"); + else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType)) + writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");"); + } + else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty) + if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase))) + writer.WriteLine($"{RequestInfoVarName}.SetContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + else + writer.WriteLine($"{RequestInfoVarName}.SetContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + } + + writer.WriteLine($"return {RequestInfoVarName};"); + } + private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"{property.Name.ToFirstCharacterUpperCase()}"; + private void WriteSerializerBody(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) + { + if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) + WriteSerializerBodyForUnionModel(method, parentClass, writer); + else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) + WriteSerializerBodyForIntersectionModel(method, parentClass, writer); + else + WriteSerializerBodyForInheritedModel(shouldHide, method, parentClass, writer); + + if (parentClass.GetPropertyOfKind(CodePropertyKind.AdditionalData) is CodeProperty additionalDataProperty) + writer.WriteLine($"writer.WriteAdditionalData({additionalDataProperty.Name});"); + } + private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) + { + if (shouldHide) + writer.WriteLine("base.Serialize(writer);"); + foreach (var otherProp in parentClass + .GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => !x.ExistsInBaseType && !x.ReadOnly) + .OrderBy(static x => x.Name)) + { + var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); + writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterUpperCase()});"); + } + } + private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) + { + var includeElse = false; + foreach (var otherProp in parentClass + .GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => !x.ExistsInBaseType) + .OrderBy(static x => x, CodePropertyTypeForwardComparer) + .ThenBy(static x => x.Name)) + { + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});"); + writer.CloseBlock(); + if (!includeElse) + includeElse = true; + } + } + private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) + { + var includeElse = false; + foreach (var otherProp in parentClass + .GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => !x.ExistsInBaseType) + .Where(static x => x.Type is not CodeType propertyType || propertyType.IsCollection || propertyType.TypeDefinition is not CodeClass) + .OrderBy(static x => x, CodePropertyTypeBackwardComparer) + .ThenBy(static x => x.Name)) + { + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});"); + writer.CloseBlock(); + if (!includeElse) + includeElse = true; + } + var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .Where(static x => x.Type is CodeType propType && propType.TypeDefinition is CodeClass && !x.Type.IsCollection) + .ToArray(); + if (complexProperties.Length != 0) + { + if (includeElse) + { + writer.WriteLine("else {"); + writer.IncreaseIndent(); + } + var propertiesNames = complexProperties + .Select(static x => x.Name.ToFirstCharacterUpperCase()) + .OrderBy(static x => x) + .Aggregate(static (x, y) => $"{x}, {y}"); + writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {propertiesNames});"); + if (includeElse) + { + writer.CloseBlock(); + } + } + } + + protected virtual void WriteCommandBuilderBody(CodeMethod codeElement, CodeClass parentClass, RequestParams requestParams, bool isVoid, string returnType, LanguageWriter writer) + { + throw new InvalidOperationException("CommandBuilder methods are not implemented in this SDK. They're currently only supported in the shell language."); + } + + protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElement, CodeTypeBase returnType) + { + ArgumentNullException.ThrowIfNull(returnType); + var returnTypeName = conventions.GetTypeString(returnType, currentElement, false); + var isStream = conventions.StreamTypeName.Equals(returnTypeName, StringComparison.OrdinalIgnoreCase); + var isEnum = returnType is CodeType codeType && codeType.TypeDefinition is CodeEnum; + if (isVoid) return "SendNoContentAsync"; + else if (isStream || conventions.IsPrimitiveType(returnTypeName) || isEnum) + if (returnType.IsCollection) + return $"SendPrimitiveCollectionAsync<{returnTypeName}>"; + else + return $"SendPrimitiveAsync<{returnTypeName}>"; + else if (returnType.IsCollection) return $"SendCollectionAsync<{returnTypeName}>"; + else return $"SendAsync<{returnTypeName}>"; + } + private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) + { + conventions.WriteLongDescription(code.Documentation, writer); + foreach (var paramWithDescription in code.Parameters + .Where(static x => x.Documentation.DescriptionAvailable) + .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) + writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Documentation.Description.CleanupXMLString()}"); + conventions.WriteDeprecationAttribute(code, writer); + } + private static readonly BaseCodeParameterOrderComparer parameterOrderComparer = new(); + private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass parentClass, CodeMethod currentMethod) + { + if (isConstructor && inherits) + { + if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && parentClass.Properties.FirstOrDefaultOfKind(CodePropertyKind.UrlTemplate) is CodeProperty urlTemplateProperty && + !string.IsNullOrEmpty(urlTemplateProperty.DefaultValue)) + { + var thirdParameterName = string.Empty; + if (currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParameter) + thirdParameterName = $", {pathParametersParameter.Name}"; + else if (currentMethod.Parameters.OfKind(CodeParameterKind.RawUrl) is CodeParameter rawUrlParameter) + thirdParameterName = $", {rawUrlParameter.Name}"; + else if (parentClass.Properties.FirstOrDefaultOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProperty && !string.IsNullOrEmpty(pathParametersProperty.DefaultValue)) + thirdParameterName = $", {pathParametersProperty.DefaultValue}"; + if (currentMethod.Parameters.OfKind(CodeParameterKind.RequestAdapter) is CodeParameter requestAdapterParameter) + { + return $" : base({requestAdapterParameter.Name.ToFirstCharacterLowerCase()}, {urlTemplateProperty.DefaultValue}{thirdParameterName})"; + } + else if (parentClass.StartBlock?.Inherits?.Name?.Contains("CliRequestBuilder", StringComparison.Ordinal) == true) + { + // CLI uses a different base class. + return $" : base({urlTemplateProperty.DefaultValue}{thirdParameterName})"; + } + } + return " : base()"; + } + + return string.Empty; + } + private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) + { + var staticModifier = code.IsStatic ? "static " : string.Empty; + var hideModifier = (inherits, code.Kind) switch + { + (true, CodeMethodKind.Serializer or CodeMethodKind.Deserializer) => "override ", + (false, CodeMethodKind.Serializer or CodeMethodKind.Deserializer) => "virtual ", + (true, CodeMethodKind.Factory) => "new ", + _ => string.Empty + }; + var genericTypePrefix = isVoid ? string.Empty : "<"; + var genericTypeSuffix = code.IsAsync && !isVoid ? ">" : string.Empty; + var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); + var asyncPrefix = code.IsAsync ? "async Task" + genericTypePrefix : string.Empty; + var voidCorrectedTaskReturnType = code.IsAsync && isVoid ? string.Empty : returnType; + if (code.ReturnType.IsArray && code.IsOfKind(CodeMethodKind.RequestExecutor)) + voidCorrectedTaskReturnType = $"IEnumerable<{voidCorrectedTaskReturnType.StripArraySuffix()}>"; + // TODO: Task type should be moved into the refiner + var completeReturnType = isConstructor ? + string.Empty : + $"{asyncPrefix}{voidCorrectedTaskReturnType}{genericTypeSuffix} "; + var baseSuffix = GetBaseSuffix(isConstructor, inherits, parentClass, code); + var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); + var methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterUpperCase(); + var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); + if (includeNullableReferenceType) + { + var completeReturnTypeWithNullable = isConstructor || string.IsNullOrEmpty(genericTypeSuffix) ? completeReturnType : $"{completeReturnType[..^2].TrimEnd('?')}?{genericTypeSuffix} "; + var nullableParameters = string.Join(", ", code.Parameters.Order(parameterOrderComparer) + .Select(p => p.IsOfKind(CodeParameterKind.RequestConfiguration) ? + GetParameterSignatureWithNullableRefType(p, code) : + conventions.GetParameterSignature(p, code)) + .ToList()); + DartConventionService.WriteNullableOpening(writer); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{"); + DartConventionService.WriteNullableMiddle(writer); + } + + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); + + if (includeNullableReferenceType) + DartConventionService.WriteNullableClosing(writer); + + } + + private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) + { + var signatureSegments = conventions.GetParameterSignature(parameter, targetElement).Split(" ", StringSplitOptions.RemoveEmptyEntries); + return $"{signatureSegments[0]}? {string.Join(" ", signatureSegments[1..])}"; + } + private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod method, bool includeNullableRef = false) + { + var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; + var propertyType = conventions.GetTypeString(propType, method, false); + if (propType is CodeType currentType) + { + if (isCollection) + if (currentType.TypeDefinition == null) + return $"WriteCollectionOfPrimitiveValues<{propertyType}>"; + else if (currentType.TypeDefinition is CodeEnum) + return $"WriteCollectionOfEnumValues<{propertyType.TrimEnd('?')}>"; + else + return $"WriteCollectionOfObjectValues<{propertyType}>"; + else if (currentType.TypeDefinition is CodeEnum enumType) + return $"WriteEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>"; + + } + return propertyType switch + { + "byte[]" => "WriteByteArrayValue", + _ when conventions.IsPrimitiveType(propertyType) => $"Write{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value", + _ => $"WriteObjectValue<{propertyType.ToFirstCharacterUpperCase()}{(includeNullableRef ? "?" : string.Empty)}>", + }; } } diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index b3e45ee161..ddc90633c5 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -10,12 +10,68 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w { ArgumentNullException.ThrowIfNull(codeElement); ArgumentNullException.ThrowIfNull(writer); + if (codeElement.ExistsInExternalBaseType) return; + var propertyType = conventions.GetTypeString(codeElement.Type, codeElement); + var isNullableReferenceType = !propertyType.EndsWith('?') + && codeElement.IsOfKind( + CodePropertyKind.Custom, + CodePropertyKind.QueryParameter);// Other property types are appropriately constructor initialized + conventions.WriteShortDescription(codeElement.Documentation.Description, writer); + conventions.WriteDeprecationAttribute(codeElement, writer); + if (isNullableReferenceType) + { + DartConventionService.WriteNullableOpening(writer); + WritePropertyInternal(codeElement, writer, $"{propertyType}?"); + DartConventionService.WriteNullableMiddle(writer); + } - var propertyName = codeElement.Name.ToFirstCharacterUpperCase(); - writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {conventions.TranslateType(codeElement.Type)} {propertyName} {{"); - writer.IncreaseIndent(); - writer.WriteLine("get; set;"); - writer.DecreaseIndent(); - writer.WriteLine("}"); + WritePropertyInternal(codeElement, writer, propertyType);// Always write the normal way + + if (isNullableReferenceType) + DartConventionService.WriteNullableClosing(writer); + } + + private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writer, string propertyType) + { + if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("The parent of a property should be a class"); + var backingStoreProperty = parentClass.GetBackingStoreProperty(); + var setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "private " : string.Empty; + var simpleBody = $"get; {setterAccessModifier}set;"; + var defaultValue = string.Empty; + switch (codeElement.Kind) + { + case CodePropertyKind.RequestBuilder: + writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get =>"); + writer.IncreaseIndent(); + conventions.AddRequestBuilderBody(parentClass, propertyType, writer); + writer.DecreaseIndent(); + writer.WriteLine("}"); + break; + case CodePropertyKind.AdditionalData when backingStoreProperty != null: + case CodePropertyKind.Custom when backingStoreProperty != null: + var backingStoreKey = codeElement.WireName; + writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{"); + writer.IncreaseIndent(); + writer.WriteLine($"get {{ return {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Get<{propertyType}>(\"{backingStoreKey}\"); }}"); + writer.WriteLine($"set {{ {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Set(\"{backingStoreKey}\", value); }}"); + writer.DecreaseIndent(); + writer.WriteLine("}"); + break; + case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition: + if (parentClass.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterUpperCase(), static x => x.Name.ToFirstCharacterUpperCase(), "?.") is string primaryMessageCodePath && !string.IsNullOrEmpty(primaryMessageCodePath)) + writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => {primaryMessageCodePath} ?? string.Empty; }}"); + else + writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => base.Message; }}"); + break; + case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped: + writer.WriteLine($"[QueryParameter(\"{codeElement.SerializationName}\")]"); + goto default; + case CodePropertyKind.QueryParameters: + defaultValue = $" = new {propertyType}();"; + goto default; + default: + writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ {simpleBody} }}{defaultValue}"); + break; + } } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index af175543a5..df92695a97 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -1,60 +1,287 @@ using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; -namespace Kiota.Builder.Writers.Dart; +using static Kiota.Builder.CodeDOM.CodeTypeBase; +namespace Kiota.Builder.Writers.Dart; public class DartConventionService : CommonLanguageConventionService { + public override string StreamTypeName => "stream"; + public override string VoidTypeName => "void"; + public override string DocCommentPrefix => "/// "; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "float", "double", "decimal", "long", "Guid", "DateTimeOffset", "TimeSpan", "Date", "Time", "sbyte", "byte" }; + public const char NullableMarker = '?'; + public static string NullableMarkerAsString => "?"; + public override string ParseNodeInterfaceName => "IParseNode"; + + public static void WriteNullableOpening(LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteLine($"#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER", false); + writer.WriteLine($"#nullable enable", false); + } + public static void WriteNullableMiddle(LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteLine($"#nullable restore", false); + writer.WriteLine("#else", false); + } + public static void WriteNullableClosing(LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteLine("#endif", false); + } + public override void WriteShortDescription(string description, LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + if (!string.IsNullOrEmpty(description)) + writer.WriteLine($"{DocCommentPrefix}{description.CleanupXMLString()}"); + } + public void WriteLongDescription(CodeDocumentation documentation, LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + if (documentation is null) return; + if (documentation.DescriptionAvailable || documentation.ExternalDocumentationAvailable) + { + writer.WriteLine($"{DocCommentPrefix}"); + if (documentation.DescriptionAvailable) + writer.WriteLine($"{DocCommentPrefix}{documentation.Description.CleanupXMLString()}"); + if (documentation.ExternalDocumentationAvailable) + writer.WriteLine($"{DocCommentPrefix}{documentation.DocumentationLabel} "); + writer.WriteLine($"{DocCommentPrefix}"); + } + } public override string GetAccessModifier(AccessModifier access) { return access switch { - AccessModifier.Private => "_", - AccessModifier.Protected => "", - AccessModifier.Public => "", - _ => throw new ArgumentOutOfRangeException(nameof(access), access, null), + AccessModifier.Public => "public", + AccessModifier.Protected => "protected", + _ => "private", }; } - - public override string TranslateType(CodeType type) +#pragma warning disable CA1822 // Method should be static + internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, string? prefix = default, IEnumerable? pathParameters = default) { - ArgumentNullException.ThrowIfNull(type); - - return type.Name; + if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && + parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProp) + { + var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : $", {string.Join(", ", pathParameters.Select(x => $"{x.Name.ToFirstCharacterLowerCase()}"))}"; + var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterUpperCase() : urlTemplateVarName; + writer.WriteLine($"{prefix}new {returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterUpperCase()}{pathParametersSuffix});"); + } } - - public override void WriteShortDescription(string description, LanguageWriter writer) + public override string TempDictionaryVarName => "urlTplParams"; + internal void AddParametersAssignment(LanguageWriter writer, CodeTypeBase pathParametersType, string pathParametersReference, string varName = "", params (CodeTypeBase, string, string)[] parameters) { - throw new System.NotImplementedException(); + if (pathParametersType == null) return; + if (string.IsNullOrEmpty(varName)) + { + varName = TempDictionaryVarName; + writer.WriteLine($"var {varName} = new {pathParametersType.Name}({pathParametersReference});"); + } + if (parameters.Length != 0) + { + writer.WriteLines(parameters.Select(p => + { + var (ct, name, identName) = p; + string nullCheck = string.Empty; + if (ct.CollectionKind == CodeTypeCollectionKind.None && ct.IsNullable) + { + if (nameof(String).Equals(ct.Name, StringComparison.OrdinalIgnoreCase)) + nullCheck = $"if (!string.IsNullOrWhiteSpace({identName})) "; + else + nullCheck = $"if ({identName} != null) "; + } + return $"{nullCheck}{varName}.Add(\"{name}\", {identName});"; + }).ToArray()); + } + } +#pragma warning restore CA1822 // Method should be static + private static bool ShouldTypeHaveNullableMarker(CodeTypeBase propType, string propTypeName) + { + return propType.IsNullable && (NullableTypes.Contains(propTypeName) || (propType is CodeType codeType && codeType.TypeDefinition is CodeEnum)); + } + private HashSet _namespaceSegmentsNames = new(StringComparer.OrdinalIgnoreCase); + private readonly object _namespaceSegmentsNamesLock = new(); + private HashSet GetNamesInUseByNamespaceSegments(CodeElement currentElement) + { + if (_namespaceSegmentsNames.Count == 0) + { + lock (_namespaceSegmentsNamesLock) + { + var rootNamespace = currentElement.GetImmediateParentOfType().GetRootNamespace(); + _namespaceSegmentsNames = GetAllNamespaces(rootNamespace) + .Where(static x => !string.IsNullOrEmpty(x.Name)) + .SelectMany(static ns => ns.Name.Split('.', StringSplitOptions.RemoveEmptyEntries)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + _namespaceSegmentsNames.Add("keyvaluepair"); //workaround as System.Collections.Generic imports keyvalue pair + } + } + return _namespaceSegmentsNames; } + private static IEnumerable GetAllNamespaces(CodeNamespace ns) + { + foreach (var childNs in ns.Namespaces) + { + yield return childNs; + foreach (var childNsSegment in GetAllNamespaces(childNs)) + yield return childNsSegment; + } + } + public override string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool includeCollectionInformation = true, LanguageWriter? writer = null) + { + return GetTypeString(code, targetElement, includeCollectionInformation, true); + } + public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool includeCollectionInformation, bool includeNullableInformation, bool includeActionInformation = true) + { + ArgumentNullException.ThrowIfNull(targetElement); + if (code is CodeComposedTypeBase) + throw new InvalidOperationException($"Dart does not support union types, the union type {code.Name} should have been filtered out by the refiner"); + if (code is CodeType currentType) + { + var typeName = TranslateTypeAndAvoidUsingNamespaceSegmentNames(currentType, targetElement); + var nullableSuffix = ShouldTypeHaveNullableMarker(code, typeName) && includeNullableInformation ? NullableMarkerAsString : string.Empty; + var collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation ? "List<" : string.Empty; + var collectionSuffix = currentType.CollectionKind switch + { + CodeTypeCollectionKind.Complex when includeCollectionInformation => ">", + CodeTypeCollectionKind.Array when includeCollectionInformation => "[]", + _ => string.Empty, + }; + var genericParameters = currentType.GenericTypeParameterValues.Count != 0 ? + $"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" : + string.Empty; + if (currentType.ActionOf && includeActionInformation) + return $"Action<{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}>"; + return $"{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}"; + } - public override string GetParameterSignature(CodeParameter parameter, CodeElement targetElement, LanguageWriter? writer = null) + throw new InvalidOperationException($"type of type {code?.GetType()} is unknown"); + } + private string TranslateTypeAndAvoidUsingNamespaceSegmentNames(CodeType currentType, CodeElement targetElement) { - throw new System.NotImplementedException(); + var parentElementsHash = targetElement.Parent is CodeClass parentClass ? + parentClass.Methods.Select(static x => x.Name) + .Union(parentClass.Properties.Select(static x => x.Name)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToHashSet(StringComparer.OrdinalIgnoreCase) : + new HashSet(0, StringComparer.OrdinalIgnoreCase); + + var typeName = TranslateType(currentType); + var areElementsInSameNamesSpace = DoesTypeExistsInSameNamesSpaceAsTarget(currentType, targetElement); + if (currentType.TypeDefinition != null && + ( + GetNamesInUseByNamespaceSegments(targetElement).Contains(typeName) && !areElementsInSameNamesSpace // match if elements are not in the same namespace and the type name is used in the namespace segments + || parentElementsHash.Contains(typeName) // match if type name is used in the parent elements segments + || !areElementsInSameNamesSpace && DoesTypeExistsInTargetAncestorNamespace(currentType, targetElement) // match if elements are not in the same namespace and the type exists in target ancestor namespace + || !areElementsInSameNamesSpace && DoesTypeExistsInOtherImportedNamespaces(currentType, targetElement) // match if elements is not imported already by another namespace. + ) + ) + return $"{currentType.TypeDefinition.GetImmediateParentOfType().Name}.{typeName}"; + return typeName; } - public override string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool includeCollectionInformation = true, - LanguageWriter? writer = null) + private static bool DoesTypeExistsInSameNamesSpaceAsTarget(CodeType currentType, CodeElement targetElement) { - throw new System.NotImplementedException(); + return currentType?.TypeDefinition?.GetImmediateParentOfType()?.Name.Equals(targetElement?.GetImmediateParentOfType()?.Name, StringComparison.OrdinalIgnoreCase) ?? false; } - public override string StreamTypeName + private static bool DoesTypeExistsInTargetAncestorNamespace(CodeType currentType, CodeElement targetElement) { - get => "Stream"; + // Avoid type ambiguity on similarly named classes. Currently, if we have namespaces A and A.B where both namespaces have type T, + // Trying to use type A.B.T in namespace A without using a qualified name will break the build. + // Similarly, if we have type A.B.C.D.T1 that needs to be used within type A.B.C.T2, but there's also a type + // A.B.T1, using T1 in T2 will resolve A.B.T1 even if you have a using statement with A.B.C.D. + var hasChildWithName = false; + if (currentType != null && currentType.TypeDefinition != null && !currentType.IsExternal && targetElement != null) + { + var typeName = currentType.TypeDefinition.Name; + var ns = targetElement.GetImmediateParentOfType(); + var rootNs = ns?.GetRootNamespace(); + while (ns is not null && ns != rootNs && !hasChildWithName) + { + hasChildWithName = ns.GetChildElements(true).OfType().Any(c => c.Name?.Equals(typeName, StringComparison.OrdinalIgnoreCase) == true); + ns = ns.Parent is CodeNamespace n ? n : (ns.GetImmediateParentOfType()); + } + } + return hasChildWithName; } - public override string VoidTypeName => "void"; + private static bool DoesTypeExistsInOtherImportedNamespaces(CodeType currentType, CodeElement targetElement) + { + if (currentType.TypeDefinition is CodeClass { Parent: CodeNamespace currentTypeNamespace } codeClass) + { + var targetClass = targetElement.GetImmediateParentOfType(); + var importedNamespaces = targetClass.StartBlock.Usings + .Where(codeUsing => !codeUsing.IsExternal // 1. Are defined during generation(not external) + && codeUsing.Declaration?.TypeDefinition != null + && !codeUsing.Name.Equals(currentTypeNamespace.Name, StringComparison.OrdinalIgnoreCase)) // 2. Do not match the namespace of the current type + .Select(static codeUsing => codeUsing.Declaration!.TypeDefinition!.GetImmediateParentOfType()) + .DistinctBy(static declaredNamespace => declaredNamespace.Name); - public override string DocCommentPrefix => "///"; + return importedNamespaces.Any(importedNamespace => (importedNamespace.FindChildByName(codeClass.Name, false) != null) + || (importedNamespace.FindChildByName(codeClass.Name, false) != null)); + } + return false; + } - public override string ParseNodeInterfaceName + public override string TranslateType(CodeType type) + { + ArgumentNullException.ThrowIfNull(type); + return type.Name switch + { + "integer" => "int", + "boolean" => "bool", + "int64" => "long", + "string" or "float" or "double" or "object" or "void" or "decimal" or "sbyte" or "byte" => type.Name.ToLowerInvariant(),// little casing hack + "binary" or "base64" or "base64url" => "byte[]", + _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "object", + }; + } + public bool IsPrimitiveType(string typeName) { - get => "IParseNode"; + if (string.IsNullOrEmpty(typeName)) return false; + typeName = typeName.StripArraySuffix().TrimEnd('?').ToLowerInvariant(); + return typeName switch + { + "string" => true, + _ when NullableTypes.Contains(typeName) => true, + _ => false, + }; } + public override string GetParameterSignature(CodeParameter parameter, CodeElement targetElement, LanguageWriter? writer = null) + { + ArgumentNullException.ThrowIfNull(parameter); + var parameterType = GetTypeString(parameter.Type, targetElement); + var defaultValue = parameter switch + { + _ when !string.IsNullOrEmpty(parameter.DefaultValue) => $" = {parameter.DefaultValue}", + _ when nameof(String).Equals(parameterType, StringComparison.OrdinalIgnoreCase) && parameter.Optional => " = \"\"", + _ when parameter.Optional => " = default", + _ => string.Empty, + }; + return $"{GetDeprecationInformation(parameter)}{parameterType} {parameter.Name.ToFirstCharacterLowerCase()}{defaultValue}"; + } + private static string GetDeprecationInformation(IDeprecableElement element) + { + if (element.Deprecation is null || !element.Deprecation.IsDeprecated) return string.Empty; - public override string TempDictionaryVarName + var versionComment = string.IsNullOrEmpty(element.Deprecation.Version) ? string.Empty : $" as of {element.Deprecation.Version}"; + var dateComment = element.Deprecation.Date is null ? string.Empty : $" on {element.Deprecation.Date.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; + var removalComment = element.Deprecation.RemovalDate is null ? string.Empty : $" and will be removed {element.Deprecation.RemovalDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; + return $"[Obsolete(\"{element.Deprecation.Description}{versionComment}{dateComment}{removalComment}\")]"; + } + internal void WriteDeprecationAttribute(IDeprecableElement element, LanguageWriter writer) { - get => "tempDictionary"; + var deprecationMessage = GetDeprecationInformation(element); + if (!string.IsNullOrEmpty(deprecationMessage)) + writer.WriteLine(deprecationMessage); } } diff --git a/src/Kiota.Builder/Writers/Dart/DartWriter.cs b/src/Kiota.Builder/Writers/Dart/DartWriter.cs index ff43a5986e..0efe218785 100644 --- a/src/Kiota.Builder/Writers/Dart/DartWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/DartWriter.cs @@ -1,12 +1,11 @@ using Kiota.Builder.PathSegmenters; namespace Kiota.Builder.Writers.Dart; - public class DartWriter : LanguageWriter { - public DartWriter(string outputPath, string clientNamespaceName) + public DartWriter(string rootPath, string clientNamespaceName) { - PathSegmenter = new DartPathSegmenter(outputPath, clientNamespaceName); + PathSegmenter = new DartPathSegmenter(rootPath, clientNamespaceName); var conventionService = new DartConventionService(); AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeBlockEndWriter(conventionService)); @@ -15,5 +14,6 @@ public DartWriter(string outputPath, string clientNamespaceName) AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodePropertyWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeTypeWriter(conventionService)); + } } From 1570b5c45568fdc03135b3588aff92818538555f Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 30 Jan 2024 00:02:18 +0100 Subject: [PATCH 004/194] Fix getter generation --- .../Writers/Dart/CodeMethodWriter.cs | 6 -- .../Writers/Dart/CodePropertyWriter.cs | 18 +++--- .../Writers/Dart/DartConventionService.cs | 63 +++++++++---------- 3 files changed, 40 insertions(+), 47 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index d7d235b8c4..30c03c303a 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -611,16 +611,10 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua GetParameterSignatureWithNullableRefType(p, code) : conventions.GetParameterSignature(p, code)) .ToList()); - DartConventionService.WriteNullableOpening(writer); writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{"); - DartConventionService.WriteNullableMiddle(writer); } writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); - - if (includeNullableReferenceType) - DartConventionService.WriteNullableClosing(writer); - } private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index ddc90633c5..0d9e4ad54b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -20,30 +20,32 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w conventions.WriteDeprecationAttribute(codeElement, writer); if (isNullableReferenceType) { - DartConventionService.WriteNullableOpening(writer); WritePropertyInternal(codeElement, writer, $"{propertyType}?"); - DartConventionService.WriteNullableMiddle(writer); } WritePropertyInternal(codeElement, writer, propertyType);// Always write the normal way - - if (isNullableReferenceType) - DartConventionService.WriteNullableClosing(writer); } private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writer, string propertyType) { - if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("The parent of a property should be a class"); + if (codeElement.Parent is not CodeClass parentClass) + throw new InvalidOperationException("The parent of a property should be a class"); + var backingStoreProperty = parentClass.GetBackingStoreProperty(); var setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "private " : string.Empty; var simpleBody = $"get; {setterAccessModifier}set;"; var defaultValue = string.Empty; + + var attributes = conventions.GetAccessModifierAttribute(codeElement.Access); + if (!string.IsNullOrEmpty(attributes)) + writer.WriteLine(attributes); + switch (codeElement.Kind) { case CodePropertyKind.RequestBuilder: - writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get =>"); + writer.WriteLine($"get {propertyType} {conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterUpperCase()} {{"); writer.IncreaseIndent(); - conventions.AddRequestBuilderBody(parentClass, propertyType, writer); + conventions.AddRequestBuilderBody(parentClass, propertyType, writer, prefix: "return "); writer.DecreaseIndent(); writer.WriteLine("}"); break; diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index df92695a97..7df39c36b5 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -14,58 +14,55 @@ public class DartConventionService : CommonLanguageConventionService public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; - private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "float", "double", "decimal", "long", "Guid", "DateTimeOffset", "TimeSpan", "Date", "Time", "sbyte", "byte" }; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "float", "double", "decimal", "long", "byte" }; public const char NullableMarker = '?'; public static string NullableMarkerAsString => "?"; public override string ParseNodeInterfaceName => "IParseNode"; - public static void WriteNullableOpening(LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER", false); - writer.WriteLine($"#nullable enable", false); - } - public static void WriteNullableMiddle(LanguageWriter writer) + public override void WriteShortDescription(string description, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"#nullable restore", false); - writer.WriteLine("#else", false); + if (!string.IsNullOrEmpty(description)) + writer.WriteLine($"{DocCommentPrefix}{description.CleanupXMLString()}"); } - public static void WriteNullableClosing(LanguageWriter writer) + public void WriteLongDescription(CodeDocumentation documentation, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine("#endif", false); + ArgumentNullException.ThrowIfNull(documentation); + + if (documentation is { DescriptionAvailable: false, ExternalDocumentationAvailable: false }) + return; + + if (documentation.DescriptionAvailable) + writer.WriteLine($"{DocCommentPrefix}{documentation.Description.CleanupXMLString()}"); + if (documentation.ExternalDocumentationAvailable) + writer.WriteLine($"{DocCommentPrefix}[{documentation.DocumentationLabel}]({documentation.DocumentationLink})"); } - public override void WriteShortDescription(string description, LanguageWriter writer) + public override string GetAccessModifier(AccessModifier access) { - ArgumentNullException.ThrowIfNull(writer); - if (!string.IsNullOrEmpty(description)) - writer.WriteLine($"{DocCommentPrefix}{description.CleanupXMLString()}"); + // Dart does not support access modifiers + return ""; } - public void WriteLongDescription(CodeDocumentation documentation, LanguageWriter writer) + +#pragma warning disable CA1822 // Method should be static + public string GetAccessModifierPrefix(AccessModifier access) { - ArgumentNullException.ThrowIfNull(writer); - if (documentation is null) return; - if (documentation.DescriptionAvailable || documentation.ExternalDocumentationAvailable) + return access switch { - writer.WriteLine($"{DocCommentPrefix}"); - if (documentation.DescriptionAvailable) - writer.WriteLine($"{DocCommentPrefix}{documentation.Description.CleanupXMLString()}"); - if (documentation.ExternalDocumentationAvailable) - writer.WriteLine($"{DocCommentPrefix}{documentation.DocumentationLabel} "); - writer.WriteLine($"{DocCommentPrefix}"); - } + AccessModifier.Private => "_", + _ => string.Empty, + }; } - public override string GetAccessModifier(AccessModifier access) + + public string GetAccessModifierAttribute(AccessModifier access) { return access switch { - AccessModifier.Public => "public", - AccessModifier.Protected => "protected", - _ => "private", + AccessModifier.Protected => "@protected", + _ => string.Empty, }; } -#pragma warning disable CA1822 // Method should be static + internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, string? prefix = default, IEnumerable? pathParameters = default) { if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && @@ -73,7 +70,7 @@ internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, La { var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : $", {string.Join(", ", pathParameters.Select(x => $"{x.Name.ToFirstCharacterLowerCase()}"))}"; var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterUpperCase() : urlTemplateVarName; - writer.WriteLine($"{prefix}new {returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterUpperCase()}{pathParametersSuffix});"); + writer.WriteLine($"{prefix}{returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterUpperCase()}{pathParametersSuffix});"); } } public override string TempDictionaryVarName => "urlTplParams"; From 451ebdecad1ac60850b196040a16a0606e0d95da Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 30 Jan 2024 00:03:50 +0100 Subject: [PATCH 005/194] Remove public access modifier from class declarations --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index c4da764b40..77ac96d079 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -34,9 +34,9 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit .OfType() .Select(static x => x.ToFirstCharacterUpperCase()) .ToArray(); - var derivation = derivedTypes.Length != 0 ? ": " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") + " " : string.Empty; + var derivation = derivedTypes.Length != 0 ? "extends " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") + " " : string.Empty; conventions.WriteLongDescription(parentClass.Documentation, writer); conventions.WriteDeprecationAttribute(parentClass, writer); - writer.StartBlock($"public class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{"); + writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{"); } } From 9fe17cfb8cb4a75ee47925b07ea182268e844782 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 30 Jan 2024 00:05:27 +0100 Subject: [PATCH 006/194] Generate namespace as library part of --- .../Writers/Dart/CodeClassDeclarationWriter.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 77ac96d079..42491a452f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -12,7 +12,9 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit { ArgumentNullException.ThrowIfNull(codeElement); ArgumentNullException.ThrowIfNull(writer); - if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); + + if (codeElement.Parent is not CodeClass parentClass) + throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); if (codeElement.Parent?.Parent is CodeNamespace) { @@ -26,7 +28,8 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit .OrderBy(static x => x, StringComparer.Ordinal) .ToList() .ForEach(x => writer.WriteLine(x)); - writer.StartBlock($"namespace {codeElement.Parent.Parent.Name} {{"); + writer.WriteLine($"part of {codeElement.Parent.Parent.Name};"); + writer.WriteLine(); } var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : new string?[] { conventions.GetTypeString(codeElement.Inherits, parentClass) }) From 37fb3f2608324edd9edb9fef23974b0ed500a790 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 30 Jan 2024 00:34:51 +0100 Subject: [PATCH 007/194] Adjusted properties and type translations --- .../Writers/Dart/CodePropertyWriter.cs | 43 ++++++++++++------- .../Writers/Dart/DartConventionService.cs | 14 +++--- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 0d9e4ad54b..832e00c613 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -32,18 +32,18 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ throw new InvalidOperationException("The parent of a property should be a class"); var backingStoreProperty = parentClass.GetBackingStoreProperty(); - var setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "private " : string.Empty; - var simpleBody = $"get; {setterAccessModifier}set;"; + var setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "_" : string.Empty; var defaultValue = string.Empty; + var getterModifier = string.Empty; - var attributes = conventions.GetAccessModifierAttribute(codeElement.Access); - if (!string.IsNullOrEmpty(attributes)) - writer.WriteLine(attributes); + var accessModifierAttribute = conventions.GetAccessModifierAttribute(codeElement.Access); + if (!string.IsNullOrEmpty(accessModifierAttribute)) + writer.WriteLine(accessModifierAttribute); switch (codeElement.Kind) { case CodePropertyKind.RequestBuilder: - writer.WriteLine($"get {propertyType} {conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterUpperCase()} {{"); + writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToCamelCase()} {{"); writer.IncreaseIndent(); conventions.AddRequestBuilderBody(parentClass, propertyType, writer, prefix: "return "); writer.DecreaseIndent(); @@ -52,27 +52,38 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ case CodePropertyKind.AdditionalData when backingStoreProperty != null: case CodePropertyKind.Custom when backingStoreProperty != null: var backingStoreKey = codeElement.WireName; - writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{"); + writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToCamelCase()} {{"); writer.IncreaseIndent(); - writer.WriteLine($"get {{ return {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Get<{propertyType}>(\"{backingStoreKey}\"); }}"); - writer.WriteLine($"set {{ {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Set(\"{backingStoreKey}\", value); }}"); + writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Get<{propertyType}>(\"{backingStoreKey}\");"); + writer.DecreaseIndent(); + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine($"set {setterAccessModifier}{codeElement.Name.ToCamelCase()}({propertyType} value) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Set(\"{backingStoreKey}\", value);"); writer.DecreaseIndent(); writer.WriteLine("}"); break; case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition: - if (parentClass.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterUpperCase(), static x => x.Name.ToFirstCharacterUpperCase(), "?.") is string primaryMessageCodePath && !string.IsNullOrEmpty(primaryMessageCodePath)) - writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => {primaryMessageCodePath} ?? string.Empty; }}"); + writer.WriteLine("@override"); + + if (parentClass.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterUpperCase(), + static x => x.Name.ToFirstCharacterUpperCase(), "?.") is { } primaryMessageCodePath && + !string.IsNullOrEmpty(primaryMessageCodePath)) + defaultValue = $"=> {primaryMessageCodePath} ?? \"\";"; else - writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => base.Message; }}"); - break; + defaultValue = "=> super.Message;"; + + getterModifier = "get "; + goto default; case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped: - writer.WriteLine($"[QueryParameter(\"{codeElement.SerializationName}\")]"); + writer.WriteLine($"/// @QueryParameter(\"{codeElement.SerializationName}\")"); goto default; case CodePropertyKind.QueryParameters: - defaultValue = $" = new {propertyType}();"; + defaultValue = $" = {propertyType}()"; goto default; default: - writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ {simpleBody} }}{defaultValue}"); + writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToCamelCase()}{defaultValue};"); break; } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 7df39c36b5..f3afd4ad78 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -156,7 +156,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i $"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" : string.Empty; if (currentType.ActionOf && includeActionInformation) - return $"Action<{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}>"; + return $"Func<{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}>"; return $"{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}"; } @@ -234,21 +234,23 @@ public override string TranslateType(CodeType type) ArgumentNullException.ThrowIfNull(type); return type.Name switch { - "integer" => "int", + "integer" or "sbyte" or "byte" => "int", "boolean" => "bool", - "int64" => "long", - "string" or "float" or "double" or "object" or "void" or "decimal" or "sbyte" or "byte" => type.Name.ToLowerInvariant(),// little casing hack + "string" => "String", + "double" or "float" or "decimal" or "int64" => "double", + "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "byte[]", _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "object", }; } + public bool IsPrimitiveType(string typeName) { if (string.IsNullOrEmpty(typeName)) return false; typeName = typeName.StripArraySuffix().TrimEnd('?').ToLowerInvariant(); return typeName switch { - "string" => true, + "String" => true, _ when NullableTypes.Contains(typeName) => true, _ => false, }; @@ -273,7 +275,7 @@ private static string GetDeprecationInformation(IDeprecableElement element) var versionComment = string.IsNullOrEmpty(element.Deprecation.Version) ? string.Empty : $" as of {element.Deprecation.Version}"; var dateComment = element.Deprecation.Date is null ? string.Empty : $" on {element.Deprecation.Date.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; var removalComment = element.Deprecation.RemovalDate is null ? string.Empty : $" and will be removed {element.Deprecation.RemovalDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; - return $"[Obsolete(\"{element.Deprecation.Description}{versionComment}{dateComment}{removalComment}\")]"; + return $"@obsolete(\"{element.Deprecation.Description}{versionComment}{dateComment}{removalComment}\")"; } internal void WriteDeprecationAttribute(IDeprecableElement element, LanguageWriter writer) { From 78cb806e8fdaaf8ba8cf4549fdc53dd8d6231f9d Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 3 Sep 2024 11:12:15 +0200 Subject: [PATCH 008/194] started working on code generation This code is not nearly finished, but was pushed to work simultaneously on this code base. Using a DartRefiner that is created from scratch. In the end this will be our actual refiner, and we will update ILanguage to reflect this. --- .../PathSegmenters/DartPathSegmenter.cs | 7 +- .../DartExceptionsReservedNamesProvider.cs | 12 + src/Kiota.Builder/Refiners/DartRefiner.cs | 303 ++++++++++++++++++ .../Refiners/DartRefinerFromScratch.cs | 148 +++++++++ .../Refiners/DartReservedNamesProvider.cs | 78 +++++ .../Refiners/ILanguageRefiner.cs | 3 + .../Dart/CodeClassDeclarationWriter.cs | 11 +- .../Writers/Dart/CodeEnumWriter.cs | 4 +- .../Writers/Dart/CodeIndexerWriter.cs | 5 +- .../Writers/Dart/CodeMethodWriter.cs | 8 +- .../Writers/Dart/CodePropertyWriter.cs | 2 +- .../Writers/Dart/DartConventionService.cs | 80 +++-- src/Kiota.Builder/Writers/Dart/DartWriter.cs | 2 +- 13 files changed, 622 insertions(+), 41 deletions(-) create mode 100644 src/Kiota.Builder/Refiners/DartExceptionsReservedNamesProvider.cs create mode 100644 src/Kiota.Builder/Refiners/DartRefiner.cs create mode 100644 src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs create mode 100644 src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs diff --git a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs index 92b5a0b94c..77f0490e3c 100644 --- a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs +++ b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs @@ -1,12 +1,11 @@ -using Kiota.Builder.CodeDOM; +using System; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; namespace Kiota.Builder.PathSegmenters; -public class DartPathSegmenter : CommonPathSegmenter +public class DartPathSegmenter(string rootPath, string clientNamespaceName) : CommonPathSegmenter(rootPath, clientNamespaceName) { - public DartPathSegmenter(string rootPath, string clientNamespaceName) : base(rootPath, clientNamespaceName) { } - public override string FileSuffix => ".dart"; public override string NormalizeNamespaceSegment(string segmentName) => segmentName.ToCamelCase(); diff --git a/src/Kiota.Builder/Refiners/DartExceptionsReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartExceptionsReservedNamesProvider.cs new file mode 100644 index 0000000000..892d157958 --- /dev/null +++ b/src/Kiota.Builder/Refiners/DartExceptionsReservedNamesProvider.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; + +namespace Kiota.Builder.Refiners; +public class DartExceptionsReservedNamesProvider : IReservedNamesProvider +{ + private readonly Lazy> _reservedNames = new(static () => new(StringComparer.OrdinalIgnoreCase) + { + "toString" + }); + public HashSet ReservedNames => _reservedNames.Value; +} diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs new file mode 100644 index 0000000000..7eff8d9761 --- /dev/null +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Configuration; +using Kiota.Builder.Extensions; + +namespace Kiota.Builder.Refiners; +public class DartRefiner : CommonLanguageRefiner, ILanguageRefiner +{ + public DartRefiner(GenerationConfiguration configuration) : base(configuration) { } + public override Task Refine(CodeNamespace generatedCode, CancellationToken cancellationToken) + { + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + AddPrimaryErrorMessage(generatedCode, + "Message", + () => new CodeType { Name = "string", IsNullable = false, IsExternal = true }, + true + ); + DeduplicateErrorMappings(generatedCode); + MoveRequestBuilderPropertiesToBaseType(generatedCode, + new CodeUsing + { + Name = "BaseRequestBuilder", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }); + + RemoveRequestConfigurationClasses(generatedCode, + new CodeUsing + { + Name = "RequestConfiguration", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }, + new CodeType + { + Name = "DefaultQueryParameters", + IsExternal = true, + }, + !_configuration.ExcludeBackwardCompatible,//TODO remove the condition for v2 + !_configuration.ExcludeBackwardCompatible); + AddDefaultImports(generatedCode, defaultUsingEvaluators); + MoveClassesWithNamespaceNamesUnderNamespace(generatedCode); + ConvertUnionTypesToWrapper(generatedCode, + _configuration.UsesBackingStore, + static s => s, + true, + AbstractionsNamespaceName, + "IComposedTypeWrapper" + ); + cancellationToken.ThrowIfCancellationRequested(); + AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); + AddAsyncSuffix(generatedCode); + cancellationToken.ThrowIfCancellationRequested(); + AddParsableImplementsForModelClasses(generatedCode, "IParsable"); + CapitalizeNamespacesFirstLetters(generatedCode); + ReplaceBinaryByNativeType(generatedCode, "Stream", "System.IO"); + MakeEnumPropertiesNullable(generatedCode); + /* Exclude the following as their names will be capitalized making the change unnecessary in this case sensitive language + * code classes, class declarations, property names, using declarations, namespace names + * Exclude CodeMethod as the return type will also be capitalized (excluding the CodeType is not enough since this is evaluated at the code method level) + */ + ReplaceReservedNames( + generatedCode, + new DartReservedNamesProvider(), x => $"@{x.ToFirstCharacterUpperCase()}", + new HashSet { typeof(CodeClass), typeof(ClassDeclaration), typeof(CodeProperty), typeof(CodeUsing), typeof(CodeNamespace), typeof(CodeMethod), typeof(CodeEnum), typeof(CodeEnumOption) } + ); + ReplaceReservedNames( + generatedCode, + new DartReservedNamesProvider(), + x => $"{x.ToFirstCharacterUpperCase()}Escaped" + ); + ReplaceReservedExceptionPropertyNames( + generatedCode, + new DartExceptionsReservedNamesProvider(), + static x => $"{x.ToFirstCharacterUpperCase()}Escaped" + ); + cancellationToken.ThrowIfCancellationRequested(); + ReplaceReservedModelTypes(generatedCode, new DartReservedNamesProvider(), x => $"{x}Object"); + ReplaceReservedNamespaceTypeNames(generatedCode, new DartReservedNamesProvider(), static x => $"{x}Namespace"); + ReplacePropertyNames(generatedCode, + new() { + CodePropertyKind.Custom, + CodePropertyKind.QueryParameter, + }, + static s => s.ToPascalCase(UnderscoreArray)); + LowerCaseNamespaceNames(generatedCode); + + var defaultConfiguration = new GenerationConfiguration(); + cancellationToken.ThrowIfCancellationRequested(); + ReplaceDefaultSerializationModules( + generatedCode, + defaultConfiguration.Serializers, + new(StringComparer.OrdinalIgnoreCase) { + $"{SerializationNamespaceName}.JsonSerializationWriterFactory", + $"{SerializationNamespaceName}.TextSerializationWriterFactory", + $"{SerializationNamespaceName}.FormSerializationWriterFactory", + $"{SerializationNamespaceName}.MultipartSerializationWriterFactory", + } + ); + ReplaceDefaultDeserializationModules( + generatedCode, + defaultConfiguration.Deserializers, + new(StringComparer.OrdinalIgnoreCase) { + $"{SerializationNamespaceName}.JsonParseNodeFactory", + $"{SerializationNamespaceName}.FormParseNodeFactory", + $"{SerializationNamespaceName}.TextParseNodeFactory" + } + ); + + DisambiguatePropertiesWithClassNames(generatedCode); + // Correct the core types after reserved names for types/properties are done to avoid collision of types e.g. renaming custom model called `DateOnly` to `Date` + CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, correctIndexer: CorrectIndexerType); + cancellationToken.ThrowIfCancellationRequested(); + + AddSerializationModulesImport(generatedCode, + [ $"{AbstractionsNamespaceName}.ApiClientBuilder", + $"{SerializationNamespaceName}.SerializationWriterFactoryRegistry" ], + [$"{SerializationNamespaceName}.ParseNodeFactoryRegistry"], '^'); + + + + AddParentClassToErrorClasses( + generatedCode, + "ApiException", + AbstractionsNamespaceName + ); + AddConstructorsForDefaultValues(generatedCode, false); + AddDiscriminatorMappingsUsingsToParentClasses( + generatedCode, + "IParseNode" + ); + }, cancellationToken); + } + protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass) + { + var sameNameProperty = currentClass.Properties + .FirstOrDefault(x => x.Name.Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase)); + if (sameNameProperty != null) + { + currentClass.RemoveChildElement(sameNameProperty); + if (string.IsNullOrEmpty(sameNameProperty.SerializationName)) + sameNameProperty.SerializationName = sameNameProperty.Name; + sameNameProperty.Name = $"{sameNameProperty.Name}Prop"; + currentClass.AddProperty(sameNameProperty); + } + } + CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); + } + protected static void MakeEnumPropertiesNullable(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.Model)) + currentClass.Properties + .Where(x => x.Type is CodeType propType && propType.TypeDefinition is CodeEnum) + .ToList() + .ForEach(x => x.Type.IsNullable = true); + CrawlTree(currentElement, MakeEnumPropertiesNullable); + } + private const string AbstractionsNamespaceName = "Microsoft.Kiota.Abstractions"; + private const string SerializationNamespaceName = $"{AbstractionsNamespaceName}.Serialization"; + private const string StoreNamespaceName = $"{AbstractionsNamespaceName}.Store"; + private const string ExtensionsNamespaceName = $"{AbstractionsNamespaceName}.Extensions"; + + protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), + AbstractionsNamespaceName, "RequestAdapter"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), + AbstractionsNamespaceName, "Method", "RequestInformation", "IRequestOption"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), + SerializationNamespaceName, "SerializationWriter"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), + SerializationNamespaceName, "ParseNode"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor), + ExtensionsNamespaceName, "Mao"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), + SerializationNamespaceName, "Parsable"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), + SerializationNamespaceName, "AdditionalDataHolder"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), + SerializationNamespaceName, "Parsable"), + new (static x => x is CodeClass || x is CodeEnum, + "System", "String"), + new (static x => x is CodeClass, + "System.Collections.Generic", "List", "Dictionary"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model, CodeClassKind.RequestBuilder), + "System.IO", "Stream"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), + "System.Threading", "CancellationToken"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.RequestBuilder), + "System.Threading.Tasks", "Task"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model, CodeClassKind.RequestBuilder), + ExtensionsNamespaceName, "Enumerable"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor) && + method.Parameters.Any(y => y.IsOfKind(CodeParameterKind.BackingStore)), + StoreNamespaceName, "IBackingStoreFactory", "IBackingStoreFactorySingleton"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.BackingStore), + StoreNamespaceName, "IBackingStore", "IBackedModel", "BackingStoreFactorySingleton" ), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(prop.SerializationName), + AbstractionsNamespaceName, "QueryParameterAttribute"), + new (static x => x is CodeClass @class && @class.OriginalComposedType is CodeIntersectionType intersectionType && intersectionType.Types.Any(static y => !y.IsExternal), + SerializationNamespaceName, "ParseNodeHelper"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), + AbstractionsNamespaceName, "RequestHeaders"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase), + SerializationNamespaceName, KiotaBuilder.UntypedNodeName), + new (static x => x is CodeEnum prop && prop.Options.Any(x => x.IsNameEscaped), + "System.Runtime.Serialization", "EnumMemberAttribute"), + new (static x => x is IDeprecableElement element && element.Deprecation is not null && element.Deprecation.IsDeprecated, + "System", "ObsoleteAttribute"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), + AbstractionsNamespaceName, MultipartBodyClassName), + }; + private const string MultipartBodyClassName = "MultipartBody"; + protected static void CapitalizeNamespacesFirstLetters(CodeElement current) + { + if (current is CodeNamespace currentNamespace) + currentNamespace.Name = currentNamespace.Name.Split('.').Select(static x => x.ToFirstCharacterUpperCase()).Aggregate(static (x, y) => $"{x}.{y}"); + CrawlTree(current, CapitalizeNamespacesFirstLetters); + } + protected static void AddAsyncSuffix(CodeElement currentElement) + { + if (currentElement is CodeMethod currentMethod && currentMethod.IsAsync) + currentMethod.Name += "Async"; + CrawlTree(currentElement, AddAsyncSuffix); + } + protected static void CorrectPropertyType(CodeProperty currentProperty) + { + ArgumentNullException.ThrowIfNull(currentProperty); + if (currentProperty.IsOfKind(CodePropertyKind.Options)) + currentProperty.DefaultValue = "new List()"; + else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) + currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); + } + protected static void CorrectMethodType(CodeMethod currentMethod) + { + ArgumentNullException.ThrowIfNull(currentMethod); + CorrectCoreTypes(currentMethod.Parent as CodeClass, DateTypesReplacements, currentMethod.Parameters + .Select(x => x.Type) + .Union(new[] { currentMethod.ReturnType }) + .ToArray()); + CorrectCoreTypes(currentMethod.Parent as CodeClass, DateTypesReplacements, currentMethod.PathQueryAndHeaderParameters + .Select(x => x.Type) + .Union(new[] { currentMethod.ReturnType }) + .ToArray()); + } + protected static void CorrectIndexerType(CodeIndexer currentIndexer) + { + ArgumentNullException.ThrowIfNull(currentIndexer); + CorrectCoreTypes(currentIndexer.Parent as CodeClass, DateTypesReplacements, currentIndexer.IndexParameter.Type); + } + + private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) + { + { + "DateOnly",("Date", new CodeUsing + { + Name = "Date", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true, + }, + }) + }, + { + "TimeOnly",("Time", new CodeUsing + { + Name = "Time", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true, + }, + }) + }, + }; + + private static void LowerCaseNamespaceNames(CodeElement currentElement) + { + if (currentElement is CodeNamespace codeNamespace) + { + if (!string.IsNullOrEmpty(codeNamespace.Name)) + codeNamespace.Name = codeNamespace.Name.ToLowerInvariant(); + + CrawlTree(currentElement, LowerCaseNamespaceNames); + } + } + +} diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs new file mode 100644 index 0000000000..edb0be6df8 --- /dev/null +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Configuration; +using Kiota.Builder.Extensions; + +namespace Kiota.Builder.Refiners; +public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner +{ + private const string MultipartBodyClassName = "MultipartBody"; + private const string AbstractionsNamespaceName = "kiota_abstractions/kiota_abstractions"; + private const string SerializationNamespaceName = "kiota_serialization"; + + protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), + AbstractionsNamespaceName, "RequestAdapter"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), + AbstractionsNamespaceName, "Method", "RequestInformation", "RequestOption"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), + SerializationNamespaceName, "SerializationWriter"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), + SerializationNamespaceName, "ParseNode"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), + SerializationNamespaceName, "Parsable"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), + SerializationNamespaceName, "AdditionalDataHolder"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), + SerializationNamespaceName, "Parsable"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(prop.SerializationName), + AbstractionsNamespaceName, "QueryParameterAttribute"), + new (static x => x is CodeClass @class && @class.OriginalComposedType is CodeIntersectionType intersectionType && intersectionType.Types.Any(static y => !y.IsExternal), + SerializationNamespaceName, "ParseNodeHelper"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), + AbstractionsNamespaceName, "RequestHeaders"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase), + SerializationNamespaceName, KiotaBuilder.UntypedNodeName), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), + AbstractionsNamespaceName, MultipartBodyClassName), + }; + + + public DartRefinerFromScratch(GenerationConfiguration configuration) : base(configuration) { } + public override Task Refine(CodeNamespace generatedCode, CancellationToken cancellationToken) + { + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + var defaultConfiguration = new GenerationConfiguration(); + CorrectCommonNames(generatedCode); + + // This adds the BaseRequestBuilder class as a superclass + MoveRequestBuilderPropertiesToBaseType(generatedCode, + new CodeUsing + { + Name = $"BaseRequestBuilder<{defaultConfiguration.ClientClassName}>", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }); + + AddDefaultImports(generatedCode, defaultUsingEvaluators); + cancellationToken.ThrowIfCancellationRequested(); + + ReplaceDefaultSerializationModules( + generatedCode, + defaultConfiguration.Serializers, + new(StringComparer.OrdinalIgnoreCase) { + $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonSerializationWriterFactory", + $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextSerializationWriterFactory", + $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormSerializationWriterFactory", + $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", + } + ); + ReplaceDefaultDeserializationModules( + generatedCode, + defaultConfiguration.Deserializers, + new(StringComparer.OrdinalIgnoreCase) { + $"{SerializationNamespaceName}/{SerializationNamespaceName}.JsonParseNodeFactory", + $"{SerializationNamespaceName}/{SerializationNamespaceName}.FormParseNodeFactory", + $"{SerializationNamespaceName}/{SerializationNamespaceName}.TextParseNodeFactory" + } + ); + AddSerializationModulesImport(generatedCode, + [$"{AbstractionsNamespaceName}.ApiClientBuilder", + $"{SerializationNamespaceName}/{SerializationNamespaceName}.SerializationWriterFactoryRegistry"], + [$"{SerializationNamespaceName}/{SerializationNamespaceName}.ParseNodeFactoryRegistry"]); + cancellationToken.ThrowIfCancellationRequested(); + + CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); + + + }, cancellationToken); + } + + /// + /// Corrects common names so they can be used with Dart. + /// This normally comes down to changing the first character to lower case. + /// GetFieldDeserializers is corrected to GetFieldDeserializers + /// + private static void CorrectCommonNames(CodeElement currentElement) + { + if (currentElement is CodeMethod m && + currentElement.Parent is CodeClass parentClass) + { + parentClass.RenameChildElement(m.Name, m.Name.ToFirstCharacterLowerCase()); + } + else if (currentElement is CodeIndexer i) + { + i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); + } + else if (currentElement is CodeEnum e) + { + foreach (var option in e.Options) + { + if (!string.IsNullOrEmpty(option.Name) && Char.IsLower(option.Name[0])) + { + if (string.IsNullOrEmpty(option.SerializationName)) + { + option.SerializationName = option.Name; + } + option.Name = option.Name.ToFirstCharacterUpperCase(); + } + } + } + + CrawlTree(currentElement, element => CorrectCommonNames(element)); + } + + private static void CorrectMethodType(CodeMethod currentMethod) { + + } + + private static void CorrectPropertyType(CodeProperty currentProperty) + { + } + + private static void CorrectImplements(ProprietableBlockDeclaration block) + { + block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I + } + + +} diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs new file mode 100644 index 0000000000..12f0bb5011 --- /dev/null +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; + +namespace Kiota.Builder.Refiners; +public class DartReservedNamesProvider : IReservedNamesProvider +{ + private readonly Lazy> _reservedNames = new(() => new(StringComparer.OrdinalIgnoreCase) { + "abstract", + "as", + "assert", + "async", + "await", + "base", + "break", + "case", + "catch", + "class", + "const", + "continue", + "covariant", + "default", + "deferred", + "do", + "dynamic", + "else", + "enum", + "export", + "extends", + "extension", + "external", + "factory", + "false", + "final", + "finally", + "for", + "Function", + "get", + "hide", + "if", + "implements", + "import", + "in", + "interface", + "is", + "late", + "library", + "mixin", + "new", + "null", + "of", + "on", + "operator", + "part", + "required", + "rethrow", + "return", + "sealed", + "set", + "show", + "static", + "super", + "switch", + "sync", + "this", + "throw", + "true", + "try", + "type", + "typedef", + "var", + "void", + "when", + "with", + "while", + "yield" + }); + public HashSet ReservedNames => _reservedNames.Value; +} diff --git a/src/Kiota.Builder/Refiners/ILanguageRefiner.cs b/src/Kiota.Builder/Refiners/ILanguageRefiner.cs index 5e6999144e..ed8efaf48f 100644 --- a/src/Kiota.Builder/Refiners/ILanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/ILanguageRefiner.cs @@ -40,6 +40,9 @@ public static async Task Refine(GenerationConfiguration config, CodeNamespace ge case GenerationLanguage.Python: await new PythonRefiner(config).Refine(generatedCode, cancellationToken).ConfigureAwait(false); break; + case GenerationLanguage.Dart: + await new DartRefinerFromScratch(config).Refine(generatedCode, cancellationToken).ConfigureAwait(false); + break; } } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 42491a452f..1b918686a4 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -6,7 +6,6 @@ namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter { - public static string AutoGenerationHeader => "// "; public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { @@ -18,27 +17,25 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent?.Parent is CodeNamespace) { - writer.WriteLine(AutoGenerationHeader); codeElement.Usings .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder .Select(static x => x.Declaration?.IsExternal ?? false ? - $"using {x.Declaration.Name.NormalizeNameSpaceName(".")};" : - $"using {x.Name.NormalizeNameSpaceName(".")};") + $"import 'package:{x.Declaration.Name}.dart';" : + $"import 'package:{x.Name}.dart';") .Distinct(StringComparer.Ordinal) .OrderBy(static x => x, StringComparer.Ordinal) .ToList() .ForEach(x => writer.WriteLine(x)); - writer.WriteLine($"part of {codeElement.Parent.Parent.Name};"); writer.WriteLine(); } - var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : new string?[] { conventions.GetTypeString(codeElement.Inherits, parentClass) }) + var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : [conventions.GetTypeString(codeElement.Inherits, parentClass)]) .Union(codeElement.Implements.Select(static x => x.Name)) .OfType() .Select(static x => x.ToFirstCharacterUpperCase()) .ToArray(); var derivation = derivedTypes.Length != 0 ? "extends " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") + " " : string.Empty; - conventions.WriteLongDescription(parentClass.Documentation, writer); + conventions.WriteLongDescription(parentClass, writer); conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{"); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 3ddebab23c..6edeecb60e 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -29,7 +29,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine(x); writer.StartBlock($"namespace {codeNamespace.Name} {{"); } - conventions.WriteShortDescription(codeElement.Documentation.Description, writer); + conventions.WriteShortDescription(codeElement, writer); if (codeElement.Flags) writer.WriteLine("[Flags]"); conventions.WriteDeprecationAttribute(codeElement, writer); @@ -37,7 +37,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write var idx = 0; foreach (var option in codeElement.Options) { - conventions.WriteShortDescription(option.Documentation.Description, writer); + conventions.WriteShortDescription(option, writer); if (option.IsNameEscaped) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs index 6eccacb32e..c83963d755 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs @@ -12,8 +12,9 @@ public override void WriteCodeElement(CodeIndexer codeElement, LanguageWriter wr ArgumentNullException.ThrowIfNull(writer); if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("The parent of a property should be a class"); var returnType = conventions.GetTypeString(codeElement.ReturnType, codeElement); - conventions.WriteShortDescription(codeElement.Documentation.Description, writer); - writer.WriteLine($"{conventions.DocCommentPrefix}{codeElement.IndexParameter.Documentation.Description.CleanupXMLString()}"); + conventions.WriteShortDescription(codeElement, writer); + // TODO Kees, make it work: + // writer.WriteLine($"{conventions.DocCommentPrefix}{codeElement.IndexParameter.Documentation.Description.CleanupXMLString()}"); conventions.WriteDeprecationAttribute(codeElement, writer); writer.StartBlock($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexParameter.Type, codeElement)} position] {{ get {{"); if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 30c03c303a..60004e4bd6 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -219,8 +219,8 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me var pathParametersProperty = parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters); var backingStoreParameter = method.Parameters.OfKind(CodeParameterKind.BackingStore); var requestAdapterPropertyName = requestAdapterProperty.Name.ToFirstCharacterUpperCase(); - WriteSerializationRegistration(method.SerializerModules, writer, "RegisterDefaultSerializer"); - WriteSerializationRegistration(method.DeserializerModules, writer, "RegisterDefaultDeserializer"); + WriteSerializationRegistration(method.SerializerModules, writer, "registerDefaultSerializer"); + WriteSerializationRegistration(method.DeserializerModules, writer, "registerDefaultDeserializer"); if (!string.IsNullOrEmpty(method.BaseUrl)) { writer.StartBlock($"if (string.IsNullOrEmpty({requestAdapterPropertyName}.BaseUrl)) {{"); @@ -541,11 +541,11 @@ protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElemen } private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) { - conventions.WriteLongDescription(code.Documentation, writer); + conventions.WriteLongDescription(code, writer); foreach (var paramWithDescription in code.Parameters .Where(static x => x.Documentation.DescriptionAvailable) .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) - writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Documentation.Description.CleanupXMLString()}"); + writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}"); conventions.WriteDeprecationAttribute(code, writer); } private static readonly BaseCodeParameterOrderComparer parameterOrderComparer = new(); diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 832e00c613..6d6b9e56fc 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -16,7 +16,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w && codeElement.IsOfKind( CodePropertyKind.Custom, CodePropertyKind.QueryParameter);// Other property types are appropriately constructor initialized - conventions.WriteShortDescription(codeElement.Documentation.Description, writer); + conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); if (isNullableReferenceType) { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index f3afd4ad78..dc18ff5e18 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -11,40 +11,83 @@ namespace Kiota.Builder.Writers.Dart; public class DartConventionService : CommonLanguageConventionService { + internal static string AutoGenerationHeader => "// auto generated"; public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; - private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "float", "double", "decimal", "long", "byte" }; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double" }; public const char NullableMarker = '?'; public static string NullableMarkerAsString => "?"; - public override string ParseNodeInterfaceName => "IParseNode"; + public override string ParseNodeInterfaceName => "ParseNode"; - public override void WriteShortDescription(string description, LanguageWriter writer) + private const string ReferenceTypePrefix = "["; + private const string ReferenceTypeSuffix = "]"; + + public override bool WriteShortDescription(IDocumentedElement element, LanguageWriter writer, string prefix = "", string suffix = "") { ArgumentNullException.ThrowIfNull(writer); - if (!string.IsNullOrEmpty(description)) - writer.WriteLine($"{DocCommentPrefix}{description.CleanupXMLString()}"); + ArgumentNullException.ThrowIfNull(element); + if (!element.Documentation.DescriptionAvailable) return false; + if (element is not CodeElement codeElement) return false; + + writer.WriteLine($"{DocCommentPrefix} {element.Documentation.GetDescription}"); + + return true; } - public void WriteLongDescription(CodeDocumentation documentation, LanguageWriter writer) + + public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEnumerable? additionalRemarks = default) { ArgumentNullException.ThrowIfNull(writer); - ArgumentNullException.ThrowIfNull(documentation); + if (element is not IDocumentedElement documentedElement || documentedElement.Documentation is not CodeDocumentation documentation) return; + if (additionalRemarks == default) + additionalRemarks = []; + var remarks = additionalRemarks.Where(static x => !string.IsNullOrEmpty(x)).ToArray(); + if (documentation.DescriptionAvailable || documentation.ExternalDocumentationAvailable || remarks.Length != 0) + { + writer.WriteLine(DocCommentPrefix); + if (documentation.DescriptionAvailable) + { + var description = documentedElement.Documentation.GetDescription(x => GetTypeReferenceForDocComment(x, element), ReferenceTypePrefix, ReferenceTypeSuffix); + writer.WriteLine($"{DocCommentPrefix}{description}"); + } + foreach (var additionalRemark in remarks) + writer.WriteLine($"{DocCommentPrefix}{additionalRemark}"); + if (element is IDeprecableElement deprecableElement && deprecableElement.Deprecation is not null && deprecableElement.Deprecation.IsDeprecated) + foreach (var additionalComment in GetDeprecationInformationForDocumentationComment(deprecableElement)) + writer.WriteLine($"{DocCommentPrefix}{additionalComment}"); - if (documentation is { DescriptionAvailable: false, ExternalDocumentationAvailable: false }) - return; + if (documentation.ExternalDocumentationAvailable) + writer.WriteLine($"{DocCommentPrefix}@see {documentation.DocumentationLabel}"); + } + } - if (documentation.DescriptionAvailable) - writer.WriteLine($"{DocCommentPrefix}{documentation.Description.CleanupXMLString()}"); - if (documentation.ExternalDocumentationAvailable) - writer.WriteLine($"{DocCommentPrefix}[{documentation.DocumentationLabel}]({documentation.DocumentationLink})"); + internal string GetTypeReferenceForDocComment(CodeTypeBase code, CodeElement targetElement) + { + if (code is CodeType codeType && codeType.TypeDefinition is CodeMethod method) + return $"{GetTypeString(new CodeType { TypeDefinition = method.Parent, IsExternal = false }, targetElement)}#{GetTypeString(code, targetElement)}"; + return $"{GetTypeString(code, targetElement)}"; } + + private string[] GetDeprecationInformationForDocumentationComment(IDeprecableElement element) + { + if (element.Deprecation is null || !element.Deprecation.IsDeprecated) return Array.Empty(); + + var versionComment = string.IsNullOrEmpty(element.Deprecation.Version) ? string.Empty : $" as of {element.Deprecation.Version}"; + var dateComment = element.Deprecation.Date is null ? string.Empty : $" on {element.Deprecation.Date.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; + var removalComment = element.Deprecation.RemovalDate is null ? string.Empty : $" and will be removed {element.Deprecation.RemovalDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; + return [ + $"@deprecated", + $"{element.Deprecation.GetDescription(type => GetTypeString(type, (element as CodeElement)!))}{versionComment}{dateComment}{removalComment}" + ]; + } + public override string GetAccessModifier(AccessModifier access) { // Dart does not support access modifiers return ""; } -#pragma warning disable CA1822 // Method should be static + #pragma warning disable CA1822 // Method should be static public string GetAccessModifierPrefix(AccessModifier access) { return access switch @@ -56,11 +99,7 @@ public string GetAccessModifierPrefix(AccessModifier access) public string GetAccessModifierAttribute(AccessModifier access) { - return access switch - { - AccessModifier.Protected => "@protected", - _ => string.Empty, - }; + return string.Empty; } internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, string? prefix = default, IEnumerable? pathParameters = default) @@ -275,7 +314,7 @@ private static string GetDeprecationInformation(IDeprecableElement element) var versionComment = string.IsNullOrEmpty(element.Deprecation.Version) ? string.Empty : $" as of {element.Deprecation.Version}"; var dateComment = element.Deprecation.Date is null ? string.Empty : $" on {element.Deprecation.Date.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; var removalComment = element.Deprecation.RemovalDate is null ? string.Empty : $" and will be removed {element.Deprecation.RemovalDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; - return $"@obsolete(\"{element.Deprecation.Description}{versionComment}{dateComment}{removalComment}\")"; + return $"@obsolete(\"{element.Deprecation.GetDescription}{versionComment}{dateComment}{removalComment}\")"; } internal void WriteDeprecationAttribute(IDeprecableElement element, LanguageWriter writer) { @@ -283,4 +322,5 @@ internal void WriteDeprecationAttribute(IDeprecableElement element, LanguageWrit if (!string.IsNullOrEmpty(deprecationMessage)) writer.WriteLine(deprecationMessage); } + } diff --git a/src/Kiota.Builder/Writers/Dart/DartWriter.cs b/src/Kiota.Builder/Writers/Dart/DartWriter.cs index 0efe218785..a660c665d9 100644 --- a/src/Kiota.Builder/Writers/Dart/DartWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/DartWriter.cs @@ -14,6 +14,6 @@ public DartWriter(string rootPath, string clientNamespaceName) AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodePropertyWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeTypeWriter(conventionService)); - + } } From 50c59c6cb5a993ec9fadc4efb9c49c6bf2db7b6f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 4 Sep 2024 07:35:55 +0200 Subject: [PATCH 009/194] Don't add nullable properties twice --- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 6d6b9e56fc..04070b0fd2 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -22,8 +22,10 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w { WritePropertyInternal(codeElement, writer, $"{propertyType}?"); } - - WritePropertyInternal(codeElement, writer, propertyType);// Always write the normal way + else + { + WritePropertyInternal(codeElement, writer, propertyType); + } } private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writer, string propertyType) From 31c42ca1ce69b1412537c9140826454b36766b82 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 4 Sep 2024 10:27:46 +0200 Subject: [PATCH 010/194] Write opening line of method only once, avoid to many closing parentheses --- src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs | 4 ---- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 6 ++++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index 905b859000..1e78c86192 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -9,9 +9,5 @@ public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter write { ArgumentNullException.ThrowIfNull(writer); writer.CloseBlock(); - if (codeElement?.Parent is CodeClass codeClass && codeClass.Parent is CodeNamespace) - { - writer.CloseBlock(); - } } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 60004e4bd6..abe0653391 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -613,8 +613,10 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua .ToList()); writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{"); } - - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); + else + { + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); + } } private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) From 6fd1b18ce38697997774b0cecc098b421ae06ded Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 4 Sep 2024 15:39:26 +0200 Subject: [PATCH 011/194] Added generics to BaseRequestBuilder Also added imprts for properties and methods. Tjose imports are not correct yet. --- .../Refiners/DartRefinerFromScratch.cs | 18 ++++++++++-------- .../Writers/Dart/CodeClassDeclarationWriter.cs | 3 ++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index edb0be6df8..66d18c5b5c 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -55,15 +55,17 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance MoveRequestBuilderPropertiesToBaseType(generatedCode, new CodeUsing { - Name = $"BaseRequestBuilder<{defaultConfiguration.ClientClassName}>", + Name = "BaseRequestBuilder", Declaration = new CodeType { Name = AbstractionsNamespaceName, - IsExternal = true + IsExternal = true, } - }); + }, addCurrentTypeAsGenericTypeParameter: true); AddDefaultImports(generatedCode, defaultUsingEvaluators); + AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); + cancellationToken.ThrowIfCancellationRequested(); ReplaceDefaultSerializationModules( @@ -80,15 +82,15 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance generatedCode, defaultConfiguration.Deserializers, new(StringComparer.OrdinalIgnoreCase) { - $"{SerializationNamespaceName}/{SerializationNamespaceName}.JsonParseNodeFactory", - $"{SerializationNamespaceName}/{SerializationNamespaceName}.FormParseNodeFactory", - $"{SerializationNamespaceName}/{SerializationNamespaceName}.TextParseNodeFactory" + $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonParseNodeFactory", + $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormParseNodeFactory", + $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextParseNodeFactory" } ); AddSerializationModulesImport(generatedCode, [$"{AbstractionsNamespaceName}.ApiClientBuilder", - $"{SerializationNamespaceName}/{SerializationNamespaceName}.SerializationWriterFactoryRegistry"], - [$"{SerializationNamespaceName}/{SerializationNamespaceName}.ParseNodeFactoryRegistry"]); + $"{AbstractionsNamespaceName}.SerializationWriterFactoryRegistry"], + [$"{AbstractionsNamespaceName}.ParseNodeFactoryRegistry"]); cancellationToken.ThrowIfCancellationRequested(); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 1b918686a4..3f6861b07b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -2,6 +2,7 @@ using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.Writers.Go; namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter @@ -21,7 +22,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder .Select(static x => x.Declaration?.IsExternal ?? false ? $"import 'package:{x.Declaration.Name}.dart';" : - $"import 'package:{x.Name}.dart';") + $"import {x.Declaration!.Name}.dart") .Distinct(StringComparer.Ordinal) .OrderBy(static x => x, StringComparer.Ordinal) .ToList() From 6fbff09cdd0c34d9f027dba6119a37f259368b85 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 4 Sep 2024 15:54:00 +0200 Subject: [PATCH 012/194] simple form of enum generation --- .../Writers/Dart/CodeEnumWriter.cs | 32 ++++++++----------- .../Writers/Dart/DartConventionService.cs | 3 +- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 6edeecb60e..0acfb5d8ca 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -17,38 +17,32 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write if (!codeElement.Options.Any()) return; - var codeNamespace = codeElement.Parent as CodeNamespace; - if (codeNamespace != null) - { - writer.WriteLine(AutoGenerationHeader); - foreach (var x in codeElement.Usings - .Where(static x => x.Declaration?.IsExternal ?? true) - .Select(static x => $"using {(x.Declaration?.Name ?? x.Name).NormalizeNameSpaceName(".")};") - .Distinct(StringComparer.Ordinal) - .OrderBy(static x => x, StringComparer.Ordinal)) - writer.WriteLine(x); - writer.StartBlock($"namespace {codeNamespace.Name} {{"); - } conventions.WriteShortDescription(codeElement, writer); if (codeElement.Flags) writer.WriteLine("[Flags]"); conventions.WriteDeprecationAttribute(codeElement, writer); - writer.StartBlock($"public enum {codeElement.Name.ToFirstCharacterUpperCase()} {{"); + writer.StartBlock($"enum {codeElement.Name.ToFirstCharacterUpperCase()} {{"); var idx = 0; foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); - - if (option.IsNameEscaped) + if (IsAllCapital(option.Name)) + { + writer.WriteLine($"{option.Name}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); + } + else { - writer.WriteLine($"[EnumMember(Value = \"{option.SerializationName}\")]"); + writer.WriteLine($"{option.Name.ToFirstCharacterLowerCase()}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); } - writer.WriteLine($"{option.Name.ToFirstCharacterUpperCase()}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); idx++; } - if (codeNamespace != null) - writer.CloseBlock(); } + + private bool IsAllCapital(String text) + { + return text.All(c => char.IsUpper(c)); + } + private static readonly Func GetEnumFlag = static idx => (idx == 0 ? 1 : Math.Pow(2, idx)).ToString(CultureInfo.InvariantCulture); } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index dc18ff5e18..c4c532b3d6 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -30,7 +30,8 @@ public override bool WriteShortDescription(IDocumentedElement element, LanguageW if (!element.Documentation.DescriptionAvailable) return false; if (element is not CodeElement codeElement) return false; - writer.WriteLine($"{DocCommentPrefix} {element.Documentation.GetDescription}"); + var description = element.Documentation.GetDescription(x => GetTypeReferenceForDocComment(x, codeElement), ReferenceTypePrefix, ReferenceTypeSuffix, RemoveInvalidDescriptionCharacters); + writer.WriteLine($"{DocCommentPrefix} {description}"); return true; } From ae55584ea367a5e4ed72059cf4e80c360a0cb03e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 4 Sep 2024 16:01:21 +0200 Subject: [PATCH 013/194] Remove function --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index c4c532b3d6..6f37493c99 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -30,7 +30,7 @@ public override bool WriteShortDescription(IDocumentedElement element, LanguageW if (!element.Documentation.DescriptionAvailable) return false; if (element is not CodeElement codeElement) return false; - var description = element.Documentation.GetDescription(x => GetTypeReferenceForDocComment(x, codeElement), ReferenceTypePrefix, ReferenceTypeSuffix, RemoveInvalidDescriptionCharacters); + var description = element.Documentation.GetDescription(x => GetTypeReferenceForDocComment(x, codeElement), ReferenceTypePrefix, ReferenceTypeSuffix); writer.WriteLine($"{DocCommentPrefix} {description}"); return true; From efd5094275b1d847662db714809cdc96eec5c7fd Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Thu, 5 Sep 2024 11:16:43 +0200 Subject: [PATCH 014/194] Imports in ApiClient are now correct Imports in other files are still incorrect. --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 2 +- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 66d18c5b5c..60f842d2bc 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -102,7 +102,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance /// /// Corrects common names so they can be used with Dart. /// This normally comes down to changing the first character to lower case. - /// GetFieldDeserializers is corrected to GetFieldDeserializers + /// GetFieldDeserializers is corrected to getFieldDeserializers /// private static void CorrectCommonNames(CodeElement currentElement) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 3f6861b07b..c64696464f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -22,7 +22,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder .Select(static x => x.Declaration?.IsExternal ?? false ? $"import 'package:{x.Declaration.Name}.dart';" : - $"import {x.Declaration!.Name}.dart") + $"import './{x.Name.Split('.')[1]}/{x.Declaration!.Name.ToSnakeCase()}.dart';") .Distinct(StringComparer.Ordinal) .OrderBy(static x => x, StringComparer.Ordinal) .ToList() From 20152e3c1afe389d463acb01d28bd6dc39acc9d1 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 5 Sep 2024 11:37:54 +0200 Subject: [PATCH 015/194] Workaround for clone method that should be implemented --- .../Writers/Dart/CodeBlockEndWriter.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index 1e78c86192..f23fa76f93 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeBlockEndWriter : BaseElementWriter @@ -8,6 +10,22 @@ public CodeBlockEndWriter(DartConventionService conventionService) : base(conven public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); + overrideCloneMethod(codeElement, writer); writer.CloseBlock(); } + + private void overrideCloneMethod(BlockEnd codeElement, LanguageWriter writer) + { + if (codeElement?.Parent is CodeClass classElement && classElement.Kind is CodeClassKind.RequestBuilder) + { + writer.WriteLine("@override"); + writer.WriteLine($"{classElement.Name.ToFirstCharacterUpperCase()} clone() {{"); + writer.IncreaseIndent(); + var constructor = classElement.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); + String? argumentList = constructor?.Parameters.Select(static x => x.Name).Aggregate(static (x, y) => $"{x}, {y}"); + writer.WriteLine($"return {classElement.Name.ToFirstCharacterUpperCase()}({argumentList});"); + writer.DecreaseIndent(); + writer.WriteLine("}"); + } + } } From 01633cb2e8638e6f0982fb29c03af2fa6d0ef31d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 6 Sep 2024 07:07:08 +0200 Subject: [PATCH 016/194] Remove nested configuration classes, replace base with super, no new --- .../Refiners/DartRefinerFromScratch.cs | 15 +++++++++++ .../Writers/Dart/CodeMethodWriter.cs | 25 ++++++++++--------- .../Writers/Dart/DartConventionService.cs | 6 ++--- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 60f842d2bc..3a38212358 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -50,6 +50,21 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance cancellationToken.ThrowIfCancellationRequested(); var defaultConfiguration = new GenerationConfiguration(); CorrectCommonNames(generatedCode); + RemoveRequestConfigurationClasses(generatedCode, + new CodeUsing + { + Name = "RequestConfiguration", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }, + new CodeType + { + Name = "DefaultQueryParameters", + IsExternal = true, + }); // This adds the BaseRequestBuilder class as a superclass MoveRequestBuilderPropertiesToBaseType(generatedCode, diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index abe0653391..a721364b10 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -105,7 +105,7 @@ private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElemen { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property"); - writer.WriteLine($"return new {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterUpperCase()});"); + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterUpperCase()});"); } private static readonly CodePropertyTypeComparer CodePropertyTypeForwardComparer = new(); private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true); @@ -114,15 +114,15 @@ private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, Cod writer.StartBlock($"return {DiscriminatorMappingVarName} switch {{"); foreach (var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings) { - writer.WriteLine($"\"{mappedType.Key}\" => new {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); + writer.WriteLine($"\"{mappedType.Key}\" => {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); } - writer.WriteLine($"_ => new {parentClass.Name.ToFirstCharacterUpperCase()}(),"); + writer.WriteLine($"_ => {parentClass.Name.ToFirstCharacterUpperCase()}(),"); writer.CloseBlock("};"); } private const string ResultVarName = "result"; private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) { - writer.WriteLine($"var {ResultVarName} = new {parentClass.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); var includeElse = false; foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .OrderBy(static x => x, CodePropertyTypeForwardComparer) @@ -134,7 +134,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if(\"{mappedType.Key}\".Equals({DiscriminatorMappingVarName}, StringComparison.OrdinalIgnoreCase)) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = new {conventions.GetTypeString(propertyType, codeElement)}();"); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); writer.CloseBlock(); } else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) @@ -153,7 +153,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla } private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) { - writer.WriteLine($"var {ResultVarName} = new {parentClass.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); var includeElse = false; foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => x.Type is not CodeType propertyType || propertyType.IsCollection || propertyType.TypeDefinition is not CodeClass) @@ -183,7 +183,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, writer.IncreaseIndent(); } foreach (var property in complexProperties) - writer.WriteLine($"{ResultVarName}.{property.Item1.Name.ToFirstCharacterUpperCase()} = new {conventions.GetTypeString(property.Item2, codeElement)}();"); + writer.WriteLine($"{ResultVarName}.{property.Item1.Name.ToFirstCharacterUpperCase()} = {conventions.GetTypeString(property.Item2, codeElement)}();"); if (includeElse) { writer.CloseBlock(); @@ -206,7 +206,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); else - writer.WriteLine($"return new {parentClass.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}();"); } private void WriteRequestBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) { @@ -273,6 +273,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } } private string DefaultDeserializerValue => $"new Dictionary>"; + private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -545,7 +546,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) foreach (var paramWithDescription in code.Parameters .Where(static x => x.Documentation.DescriptionAvailable) .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) - writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}"); + writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}"); conventions.WriteDeprecationAttribute(code, writer); } private static readonly BaseCodeParameterOrderComparer parameterOrderComparer = new(); @@ -565,15 +566,15 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass thirdParameterName = $", {pathParametersProperty.DefaultValue}"; if (currentMethod.Parameters.OfKind(CodeParameterKind.RequestAdapter) is CodeParameter requestAdapterParameter) { - return $" : base({requestAdapterParameter.Name.ToFirstCharacterLowerCase()}, {urlTemplateProperty.DefaultValue}{thirdParameterName})"; + return $" : super({requestAdapterParameter.Name.ToFirstCharacterLowerCase()}, {urlTemplateProperty.DefaultValue}{thirdParameterName})"; } else if (parentClass.StartBlock?.Inherits?.Name?.Contains("CliRequestBuilder", StringComparison.Ordinal) == true) { // CLI uses a different base class. - return $" : base({urlTemplateProperty.DefaultValue}{thirdParameterName})"; + return $" : super({urlTemplateProperty.DefaultValue}{thirdParameterName})"; } } - return " : base()"; + return " : super()"; } return string.Empty; diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 6f37493c99..2b2c351a82 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -87,8 +87,8 @@ public override string GetAccessModifier(AccessModifier access) // Dart does not support access modifiers return ""; } - - #pragma warning disable CA1822 // Method should be static + +#pragma warning disable CA1822 // Method should be static public string GetAccessModifierPrefix(AccessModifier access) { return access switch @@ -120,7 +120,7 @@ internal void AddParametersAssignment(LanguageWriter writer, CodeTypeBase pathPa if (string.IsNullOrEmpty(varName)) { varName = TempDictionaryVarName; - writer.WriteLine($"var {varName} = new {pathParametersType.Name}({pathParametersReference});"); + writer.WriteLine($"var {varName} = {pathParametersType.Name}({pathParametersReference});"); } if (parameters.Length != 0) { From b9a74538042bb68eeecfacdb570e02d6d83a35f2 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 6 Sep 2024 07:22:03 +0200 Subject: [PATCH 017/194] Solved merge conflict --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index a721364b10..f80eecb263 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -272,8 +272,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho .ToArray()); } } - private string DefaultDeserializerValue => $"new Dictionary>"; - + private string DefaultDeserializerValue => $"Map>()"; private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -454,7 +453,7 @@ private void WriteSerializerBody(bool shouldHide, CodeMethod method, CodeClass p private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) { if (shouldHide) - writer.WriteLine("base.Serialize(writer);"); + writer.WriteLine("super.serialize(writer);"); foreach (var otherProp in parentClass .GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => !x.ExistsInBaseType && !x.ReadOnly) From 837cada4aed6b8899b15c910c5bdb68dfef8604d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 6 Sep 2024 10:35:33 +0200 Subject: [PATCH 018/194] Use correct namespaces in defaultUsingEvaluators --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 3a38212358..96e9fb4787 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -20,19 +20,19 @@ public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), AbstractionsNamespaceName, "Method", "RequestInformation", "RequestOption"), new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), - SerializationNamespaceName, "SerializationWriter"), + AbstractionsNamespaceName, "SerializationWriter"), new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), - SerializationNamespaceName, "ParseNode"), + AbstractionsNamespaceName, "ParseNode"), new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), - SerializationNamespaceName, "Parsable"), + AbstractionsNamespaceName, "Parsable"), new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), - SerializationNamespaceName, "AdditionalDataHolder"), + AbstractionsNamespaceName, "AdditionalDataHolder"), new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), - SerializationNamespaceName, "Parsable"), + AbstractionsNamespaceName, "Parsable"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(prop.SerializationName), AbstractionsNamespaceName, "QueryParameterAttribute"), new (static x => x is CodeClass @class && @class.OriginalComposedType is CodeIntersectionType intersectionType && intersectionType.Types.Any(static y => !y.IsExternal), - SerializationNamespaceName, "ParseNodeHelper"), + AbstractionsNamespaceName, "ParseNodeHelper"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), AbstractionsNamespaceName, "RequestHeaders"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase), From 36074a19de273c7f8a64f789a2db1c8eaa47ccea Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 6 Sep 2024 11:47:19 +0200 Subject: [PATCH 019/194] api_client.dart compiles after generation No idea if it actually works, but at least it compiles. --- .../Refiners/DartRefinerFromScratch.cs | 39 +++++++++++++++++++ .../Writers/Dart/CodeMethodWriter.cs | 10 ++--- .../Writers/Dart/DartConventionService.cs | 6 ++- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 96e9fb4787..3906bd1214 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -154,6 +154,45 @@ private static void CorrectMethodType(CodeMethod currentMethod) { private static void CorrectPropertyType(CodeProperty currentProperty) { + ArgumentNullException.ThrowIfNull(currentProperty); + + if (currentProperty.IsOfKind(CodePropertyKind.Options)) + currentProperty.DefaultValue = "List()"; + else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) + currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + else if (currentProperty.IsOfKind(CodePropertyKind.RequestAdapter)) + { + currentProperty.Type.Name = "RequestAdapter"; + currentProperty.Type.IsNullable = true; + } + else if (currentProperty.IsOfKind(CodePropertyKind.BackingStore)) + { + currentProperty.Type.Name = currentProperty.Type.Name[1..]; // removing the "I" + currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); + } + else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameter)) + { + currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + } + else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) + { + currentProperty.Type.Name = "Map"; + currentProperty.DefaultValue = "Map()"; + } + else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) + { + currentProperty.Type.IsNullable = true; + } + else if (currentProperty.IsOfKind(CodePropertyKind.PathParameters)) + { + currentProperty.Type.IsNullable = true; + currentProperty.Type.Name = "Map"; + if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) + currentProperty.DefaultValue = "Map()"; + } + currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); + // TODO KEES + // CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); } private static void CorrectImplements(ProprietableBlockDeclaration block) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index f80eecb263..23f3fe5fe1 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -218,16 +218,16 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me if (parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is not CodeProperty requestAdapterProperty) return; var pathParametersProperty = parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters); var backingStoreParameter = method.Parameters.OfKind(CodeParameterKind.BackingStore); - var requestAdapterPropertyName = requestAdapterProperty.Name.ToFirstCharacterUpperCase(); + var requestAdapterPropertyName = requestAdapterProperty.Name.ToFirstCharacterLowerCase(); WriteSerializationRegistration(method.SerializerModules, writer, "registerDefaultSerializer"); WriteSerializationRegistration(method.DeserializerModules, writer, "registerDefaultDeserializer"); if (!string.IsNullOrEmpty(method.BaseUrl)) { - writer.StartBlock($"if (string.IsNullOrEmpty({requestAdapterPropertyName}.BaseUrl)) {{"); - writer.WriteLine($"{requestAdapterPropertyName}.BaseUrl = \"{method.BaseUrl}\";"); + writer.StartBlock($"if ({requestAdapterPropertyName}.baseUrl != null || {requestAdapterPropertyName}.baseUrl!.isEmpty) {{"); + writer.WriteLine($"{requestAdapterPropertyName}.baseUrl = \"{method.BaseUrl}\";"); writer.CloseBlock(); if (pathParametersProperty != null) - writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterUpperCase()}.TryAdd(\"baseurl\", {requestAdapterPropertyName}.BaseUrl);"); + writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterLowerCase()}[\"baseurl\"] = {requestAdapterPropertyName}.baseUrl;"); } if (backingStoreParameter != null) writer.WriteLine($"{requestAdapterPropertyName}.EnableBackingStore({backingStoreParameter.Name});"); @@ -236,7 +236,7 @@ private static void WriteSerializationRegistration(HashSet serialization { if (serializationClassNames != null) foreach (var serializationClassName in serializationClassNames) - writer.WriteLine($"ApiClientBuilder.{methodName}<{serializationClassName}>();"); + writer.WriteLine($"ApiClientBuilder.{methodName}(() => {serializationClassName}());"); } private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 2b2c351a82..91c5127ed4 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -109,8 +109,10 @@ internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, La parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProp) { var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : $", {string.Join(", ", pathParameters.Select(x => $"{x.Name.ToFirstCharacterLowerCase()}"))}"; - var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterUpperCase() : urlTemplateVarName; - writer.WriteLine($"{prefix}{returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterUpperCase()}{pathParametersSuffix});"); + var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterLowerCase() : urlTemplateVarName; + // TODO Kees this can't be the final output but curently it creates a correct ApiClient + writer.WriteLine($"{prefix}{returnType}({requestAdapterProp.Name.ToFirstCharacterLowerCase()}, \"\", {urlTplRef});"); + } } public override string TempDictionaryVarName => "urlTplParams"; From 18bfceaf64acb9656989a682f2b6692115db6896 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 6 Sep 2024 11:51:11 +0200 Subject: [PATCH 020/194] Improved generation of import statements --- .../Refiners/DartRefinerFromScratch.cs | 19 +++++++++++++++++++ .../Dart/CodeClassDeclarationWriter.cs | 11 +++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 3906bd1214..d4566bf5b1 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -79,6 +79,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance }, addCurrentTypeAsGenericTypeParameter: true); AddDefaultImports(generatedCode, defaultUsingEvaluators); + AddInheritedTypeImport(generatedCode); AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); cancellationToken.ThrowIfCancellationRequested(); @@ -199,6 +200,24 @@ private static void CorrectImplements(ProprietableBlockDeclaration block) { block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I } + private static void AddInheritedTypeImport(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass && + currentClass.StartBlock is ClassDeclaration currentClassDeclaration && + currentClass.GetImmediateParentOfType() is CodeNamespace currentClassNamespace) + { + var inheritTypes = currentClassDeclaration.Inherits?.AllTypes ?? Enumerable.Empty(); + var usingsToAdd = inheritTypes + .SelectMany(static x => x.AllTypes.Select(static y => (type: y, ns: y.TypeDefinition?.GetImmediateParentOfType()))) + .Where(static x => x.ns != null) + .Select(static x => new CodeUsing { Name = x.ns!.Name, Declaration = x.type }) + .Where(x => x.Declaration?.TypeDefinition != currentElement) + .ToArray(); + if (usingsToAdd.Length != 0) + (currentClass.Parent is CodeClass parentClass ? parentClass : currentClass).AddUsing(usingsToAdd); + } + CrawlTree(currentElement, AddInheritedTypeImport); + } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index c64696464f..baf8f57e44 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -20,9 +20,9 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit { codeElement.Usings .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder - .Select(static x => x.Declaration?.IsExternal ?? false ? + .Select(x => x.Declaration?.IsExternal ?? false ? $"import 'package:{x.Declaration.Name}.dart';" : - $"import './{x.Name.Split('.')[1]}/{x.Declaration!.Name.ToSnakeCase()}.dart';") + getImportStatement(x, codeElement)) .Distinct(StringComparer.Ordinal) .OrderBy(static x => x, StringComparer.Ordinal) .ToList() @@ -40,4 +40,11 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{"); } + + private static string getImportStatement(CodeUsing x, ClassDeclaration codeElement) + { + return codeElement.GetNamespaceDepth() == 1 ? + $"import './{x.Name.Split('.')[1]}/{x.Declaration!.Name.ToSnakeCase()}.dart';" + : $"import '../{x.Name.Split('.')[1]}/{x.Declaration!.Name.ToSnakeCase()}.dart';"; + } } From 178e3024cf637adb949e0577d7a1da47a1157836 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 6 Sep 2024 15:21:46 +0200 Subject: [PATCH 021/194] Lists of integers now use the proper type. Added more Dart syntax to creating methods. --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 14 +++++++------- .../Writers/Dart/DartConventionService.cs | 7 +++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 23f3fe5fe1..efb2e37190 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -29,9 +29,9 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri { var parameterName = parameter.Name.ToFirstCharacterLowerCase(); if (nameof(String).Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase) && parameter.Type.CollectionKind == CodeTypeBase.CodeTypeCollectionKind.None) - writer.WriteLine($"if(string.IsNullOrEmpty({parameterName})) throw new ArgumentNullException(nameof({parameterName}));"); + writer.WriteLine($"if({parameterName} != null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); else - writer.WriteLine($"_ = {parameterName} ?? throw new ArgumentNullException(nameof({parameterName}));"); + writer.WriteLine($"_ = {parameterName} ?? throw ArgumentError.notNull({parameterName});"); } HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); writer.CloseBlock(); @@ -105,7 +105,7 @@ private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElemen { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property"); - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterUpperCase()});"); + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterLowerCase()});"); } private static readonly CodePropertyTypeComparer CodePropertyTypeForwardComparer = new(); private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true); @@ -132,9 +132,9 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) { var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if(\"{mappedType.Key}\".Equals({DiscriminatorMappingVarName}, StringComparison.OrdinalIgnoreCase)) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if(\"{mappedType.Key}.toUpperCase()\".equals({DiscriminatorMappingVarName}.toUpperCase())) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); writer.CloseBlock(); } else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) @@ -253,7 +253,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho { defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; } - writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterUpperCase()} = {defaultValue};"); + writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue};"); } if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && @@ -332,7 +332,7 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod .Where(static x => !x.ExistsInBaseType) .OrderBy(static x => x.Name, StringComparer.Ordinal)) { - writer.WriteLine($"{{\"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},"); + writer.WriteLine($"{{\"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterLowerCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},"); } writer.CloseBlock("};"); } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 91c5127ed4..478c375195 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -45,7 +45,6 @@ public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEn var remarks = additionalRemarks.Where(static x => !string.IsNullOrEmpty(x)).ToArray(); if (documentation.DescriptionAvailable || documentation.ExternalDocumentationAvailable || remarks.Length != 0) { - writer.WriteLine(DocCommentPrefix); if (documentation.DescriptionAvailable) { var description = documentedElement.Documentation.GetDescription(x => GetTypeReferenceForDocComment(x, element), ReferenceTypePrefix, ReferenceTypeSuffix); @@ -274,15 +273,15 @@ private static bool DoesTypeExistsInOtherImportedNamespaces(CodeType currentType public override string TranslateType(CodeType type) { ArgumentNullException.ThrowIfNull(type); - return type.Name switch + return type.Name.ToLowerInvariant() switch { - "integer" or "sbyte" or "byte" => "int", + "integer" or "sbyte" or "byte" => "int", "boolean" => "bool", "string" => "String", "double" or "float" or "decimal" or "int64" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "byte[]", - _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "object", + _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "Object", }; } From 973c92638c21af20cfd1ca1580cf7f37a4977d72 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 9 Sep 2024 13:11:43 +0200 Subject: [PATCH 022/194] extends and implements are properly generated createFromDiscriminatorValue also looks correct. --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 1 + .../Writers/Dart/CodeClassDeclarationWriter.cs | 11 ++++------- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 8 ++------ .../Writers/Dart/DartConventionService.cs | 1 + 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index d4566bf5b1..7d78cfaa92 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -81,6 +81,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddDefaultImports(generatedCode, defaultUsingEvaluators); AddInheritedTypeImport(generatedCode); AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); + AddParsableImplementsForModelClasses(generatedCode, "Parsable"); cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index baf8f57e44..bf89835d47 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -30,15 +30,12 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit writer.WriteLine(); } - var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : [conventions.GetTypeString(codeElement.Inherits, parentClass)]) - .Union(codeElement.Implements.Select(static x => x.Name)) - .OfType() - .Select(static x => x.ToFirstCharacterUpperCase()) - .ToArray(); - var derivation = derivedTypes.Length != 0 ? "extends " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") + " " : string.Empty; + var derivation = codeElement.Inherits == null ? string.Empty : $" extends {codeElement.Inherits.Name}"; + var implements = !codeElement.Implements.Any() ? string.Empty : $" implements {codeElement.Implements.Select(x => x.Name).Aggregate((x, y) => x + ", " + y)}"; + conventions.WriteLongDescription(parentClass, writer); conventions.WriteDeprecationAttribute(parentClass, writer); - writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{"); + writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()}{derivation}{implements} {{"); } private static string getImportStatement(CodeUsing x, ClassDeclaration codeElement) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index efb2e37190..39d0239983 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -30,8 +30,6 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri var parameterName = parameter.Name.ToFirstCharacterLowerCase(); if (nameof(String).Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase) && parameter.Type.CollectionKind == CodeTypeBase.CodeTypeCollectionKind.None) writer.WriteLine($"if({parameterName} != null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); - else - writer.WriteLine($"_ = {parameterName} ?? throw ArgumentError.notNull({parameterName});"); } HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); writer.CloseBlock(); @@ -584,14 +582,12 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var hideModifier = (inherits, code.Kind) switch { (true, CodeMethodKind.Serializer or CodeMethodKind.Deserializer) => "override ", - (false, CodeMethodKind.Serializer or CodeMethodKind.Deserializer) => "virtual ", - (true, CodeMethodKind.Factory) => "new ", _ => string.Empty }; var genericTypePrefix = isVoid ? string.Empty : "<"; var genericTypeSuffix = code.IsAsync && !isVoid ? ">" : string.Empty; var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - var asyncPrefix = code.IsAsync ? "async Task" + genericTypePrefix : string.Empty; + var asyncPrefix = code.IsAsync ? "async " + genericTypePrefix : string.Empty; var voidCorrectedTaskReturnType = code.IsAsync && isVoid ? string.Empty : returnType; if (code.ReturnType.IsArray && code.IsOfKind(CodeMethodKind.RequestExecutor)) voidCorrectedTaskReturnType = $"IEnumerable<{voidCorrectedTaskReturnType.StripArraySuffix()}>"; @@ -601,7 +597,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua $"{asyncPrefix}{voidCorrectedTaskReturnType}{genericTypeSuffix} "; var baseSuffix = GetBaseSuffix(isConstructor, inherits, parentClass, code); var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); - var methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterUpperCase(); + var methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterLowerCase(); var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); if (includeNullableReferenceType) { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 478c375195..e92d3db630 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -281,6 +281,7 @@ public override string TranslateType(CodeType type) "double" or "float" or "decimal" or "int64" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "byte[]", + "iparsenode" => "ParseNode", _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "Object", }; } From 02e96766bc6559846d8e37e19241cffa72ee8f7e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Mon, 9 Sep 2024 14:31:36 +0200 Subject: [PATCH 023/194] Start with morer dynamic generation of import statements --- .../Dart/CodeClassDeclarationWriter.cs | 43 +++++++++++++++++-- .../Writers/Dart/DartConventionService.cs | 10 ----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index bf89835d47..d6891218da 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -40,8 +40,45 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit private static string getImportStatement(CodeUsing x, ClassDeclaration codeElement) { - return codeElement.GetNamespaceDepth() == 1 ? - $"import './{x.Name.Split('.')[1]}/{x.Declaration!.Name.ToSnakeCase()}.dart';" - : $"import '../{x.Name.Split('.')[1]}/{x.Declaration!.Name.ToSnakeCase()}.dart';"; + var classParent = codeElement.Parent?.Parent?.Name; + var import = x.Name; + if (classParent != null) + { + var importstatement = x.Name.Replace(classParent, "", StringComparison.Ordinal).Replace(".", "/", StringComparison.Ordinal); + int equalSegments = 0; + bool allSegmentsEqual = true; + var classArray = classParent.Split('.'); + var importArray = import.Split('.'); + for (int i = 0; i < importArray.Length && i < classArray.Length; i++) + { + if (!classArray[i].Equals(importArray[i], StringComparison.Ordinal)) + { + equalSegments = i; + allSegmentsEqual = false; + break; + } + } + + //import falls within class directory + if (allSegmentsEqual) + { + for (int i = 0; i < classArray.Length; i++) + { + importstatement = importstatement.Replace(classArray[i] + "/", "", StringComparison.Ordinal); + importstatement = importstatement.Replace(classArray[i], "", StringComparison.Ordinal); + } + if (string.IsNullOrEmpty(importstatement)) + { + return classArray.Length == importArray.Length ? $"import './{x.Declaration!.Name.ToSnakeCase()}.dart';" : $"import '../{x.Declaration!.Name.ToSnakeCase()}.dart';"; + } + } + + for (int i = 0; i < (classArray.Length - equalSegments); i++) + { + importstatement = importstatement.Replace(classArray[i], "..", StringComparison.Ordinal); + } + return equalSegments == 0 ? $"import '.{importstatement}/{x.Declaration!.Name.ToSnakeCase()}.dart';" : $"import '{importstatement}/{x.Declaration!.Name.ToSnakeCase()}.dart';"; + } + return $"import './{x.Name.Split('.').Last()}/{x.Declaration!.Name.ToSnakeCase()}.dart';"; } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index e92d3db630..b23888acd4 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -213,16 +213,6 @@ private string TranslateTypeAndAvoidUsingNamespaceSegmentNames(CodeType currentT new HashSet(0, StringComparer.OrdinalIgnoreCase); var typeName = TranslateType(currentType); - var areElementsInSameNamesSpace = DoesTypeExistsInSameNamesSpaceAsTarget(currentType, targetElement); - if (currentType.TypeDefinition != null && - ( - GetNamesInUseByNamespaceSegments(targetElement).Contains(typeName) && !areElementsInSameNamesSpace // match if elements are not in the same namespace and the type name is used in the namespace segments - || parentElementsHash.Contains(typeName) // match if type name is used in the parent elements segments - || !areElementsInSameNamesSpace && DoesTypeExistsInTargetAncestorNamespace(currentType, targetElement) // match if elements are not in the same namespace and the type exists in target ancestor namespace - || !areElementsInSameNamesSpace && DoesTypeExistsInOtherImportedNamespaces(currentType, targetElement) // match if elements is not imported already by another namespace. - ) - ) - return $"{currentType.TypeDefinition.GetImmediateParentOfType().Name}.{typeName}"; return typeName; } From bcfb91b09d46bb72d518e8e14492fc155f234c4c Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 9 Sep 2024 14:49:59 +0200 Subject: [PATCH 024/194] Fix generating generics in inheritance --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index bf89835d47..264b9c3e21 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -2,7 +2,6 @@ using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; -using Kiota.Builder.Writers.Go; namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter @@ -30,7 +29,8 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit writer.WriteLine(); } - var derivation = codeElement.Inherits == null ? string.Empty : $" extends {codeElement.Inherits.Name}"; + var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : [conventions.GetTypeString(codeElement.Inherits, parentClass)]).ToArray(); + var derivation = derivedTypes.Length != 0 ? " extends " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") : string.Empty; var implements = !codeElement.Implements.Any() ? string.Empty : $" implements {codeElement.Implements.Select(x => x.Name).Aggregate((x, y) => x + ", " + y)}"; conventions.WriteLongDescription(parentClass, writer); From 7e50b4162b6ab2117dd29f96eea2d55bce8e9ebb Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 10 Sep 2024 08:40:34 +0200 Subject: [PATCH 025/194] Property names should start with lowercase, import all types from methods and properties --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 2 +- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 7d78cfaa92..e860e81bee 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -80,7 +80,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddDefaultImports(generatedCode, defaultUsingEvaluators); AddInheritedTypeImport(generatedCode); - AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); + AddPropertiesAndMethodTypesImports(generatedCode, true, true, false); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 04070b0fd2..3dc01e8f53 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -85,7 +85,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ defaultValue = $" = {propertyType}()"; goto default; default: - writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToCamelCase()}{defaultValue};"); + writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterLowerCase()}{defaultValue};"); break; } } From 9a32802461d318def137baa22f83d6cf9a02f4be Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 10 Sep 2024 09:42:54 +0200 Subject: [PATCH 026/194] Property for additional data is overriden from abstract class --- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 3dc01e8f53..f6830b1dad 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -84,6 +84,9 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ case CodePropertyKind.QueryParameters: defaultValue = $" = {propertyType}()"; goto default; + case CodePropertyKind.AdditionalData: + writer.WriteLine("@override"); + goto default; default: writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterLowerCase()}{defaultValue};"); break; From dd28ad1acf283dcf16450f5303afb867ddfeb90d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 10 Sep 2024 10:01:59 +0200 Subject: [PATCH 027/194] move override one line up for methods --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 39d0239983..1903f81732 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -579,11 +579,10 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; - var hideModifier = (inherits, code.Kind) switch + if (inherits && (code.Kind == CodeMethodKind.Serializer || code.Kind == CodeMethodKind.Deserializer)) { - (true, CodeMethodKind.Serializer or CodeMethodKind.Deserializer) => "override ", - _ => string.Empty - }; + writer.WriteLine("@override"); + } var genericTypePrefix = isVoid ? string.Empty : "<"; var genericTypeSuffix = code.IsAsync && !isVoid ? ">" : string.Empty; var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); @@ -607,11 +606,11 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua GetParameterSignatureWithNullableRefType(p, code) : conventions.GetParameterSignature(p, code)) .ToList()); - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{"); } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); } } From 0c4ebfd8389ea77c6a77e429d8eb96164517d47a Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 10 Sep 2024 12:35:32 +0200 Subject: [PATCH 028/194] Now generates an api client that compiles --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index e860e81bee..fe31217cf4 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -82,7 +82,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddInheritedTypeImport(generatedCode); AddPropertiesAndMethodTypesImports(generatedCode, true, true, false); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); - + AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); ReplaceDefaultSerializationModules( @@ -92,7 +92,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonSerializationWriterFactory", $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextSerializationWriterFactory", $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormSerializationWriterFactory", - $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", + // $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", } ); ReplaceDefaultDeserializationModules( From 5654a956866c41b7dc1caf9be5527f6ceb028540 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 11 Sep 2024 08:45:23 +0200 Subject: [PATCH 029/194] Relative imports now work But the code needs some TLC. I will ask Ricardo to have a look at it. --- .../PathSegmenters/DartPathSegmenter.cs | 6 ++ .../Dart/CodeClassDeclarationWriter.cs | 81 +++++++------------ 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs index 77f0490e3c..4869be49e6 100644 --- a/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs +++ b/src/Kiota.Builder/PathSegmenters/DartPathSegmenter.cs @@ -1,6 +1,7 @@ using System; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.Writers.Go; namespace Kiota.Builder.PathSegmenters; @@ -11,4 +12,9 @@ public class DartPathSegmenter(string rootPath, string clientNamespaceName) : Co public override string NormalizeNamespaceSegment(string segmentName) => segmentName.ToCamelCase(); public override string NormalizeFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToSnakeCase(); + + internal string GetRelativeFileName(CodeNamespace @namespace, CodeElement element) + { + return NormalizeFileName(element); + } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index cdf34b6941..5574cd772c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -2,11 +2,13 @@ using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.PathSegmenters; namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter { - public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) { } + public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) {} + public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(codeElement); @@ -15,18 +17,35 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); + var currentNamespace = codeElement.GetImmediateParentOfType(); + + var relativeImportManager = new RelativeImportManager( + "keyhub", '.', (writer.PathSegmenter as DartPathSegmenter)!.GetRelativeFileName); + if (codeElement.Parent?.Parent is CodeNamespace) { codeElement.Usings - .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder - .Select(x => x.Declaration?.IsExternal ?? false ? - $"import 'package:{x.Declaration.Name}.dart';" : - getImportStatement(x, codeElement)) - .Distinct(StringComparer.Ordinal) - .OrderBy(static x => x, StringComparer.Ordinal) - .ToList() - .ForEach(x => writer.WriteLine(x)); + .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder + .Where(static x => x.IsExternal) + .Select(x => $"import 'package:{x.Declaration!.Name}.dart';") + .Distinct(StringComparer.Ordinal) + .OrderBy(static x => x, StringComparer.Ordinal) + .ToList() + .ForEach(x => writer.WriteLine(x)); + + foreach (var relativePath in codeElement.Usings + .Where(static x => !x.IsExternal) + .DistinctBy(static x => $"{x.Name}{x.Declaration?.Name}", StringComparer.OrdinalIgnoreCase) + .Select(x => x.Declaration?.Name?.StartsWith('.') ?? false ? + (string.Empty, string.Empty, x.Declaration.Name) : + relativeImportManager.GetRelativeImportPathForUsing(x, currentNamespace)) + .Select(static x => x.Item3) + .Distinct() + .Order(StringComparer.OrdinalIgnoreCase)) + writer.WriteLine($"import '{relativePath.ToSnakeCase()}.dart';"); + writer.WriteLine(); + } var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : [conventions.GetTypeString(codeElement.Inherits, parentClass)]).ToArray(); @@ -37,48 +56,4 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()}{derivation}{implements} {{"); } - - private static string getImportStatement(CodeUsing x, ClassDeclaration codeElement) - { - var classParent = codeElement.Parent?.Parent?.Name; - var import = x.Name; - if (classParent != null) - { - var importstatement = x.Name.Replace(classParent, "", StringComparison.Ordinal).Replace(".", "/", StringComparison.Ordinal); - int equalSegments = 0; - bool allSegmentsEqual = true; - var classArray = classParent.Split('.'); - var importArray = import.Split('.'); - for (int i = 0; i < importArray.Length && i < classArray.Length; i++) - { - if (!classArray[i].Equals(importArray[i], StringComparison.Ordinal)) - { - equalSegments = i; - allSegmentsEqual = false; - break; - } - } - - //import falls within class directory - if (allSegmentsEqual) - { - for (int i = 0; i < classArray.Length; i++) - { - importstatement = importstatement.Replace(classArray[i] + "/", "", StringComparison.Ordinal); - importstatement = importstatement.Replace(classArray[i], "", StringComparison.Ordinal); - } - if (string.IsNullOrEmpty(importstatement)) - { - return classArray.Length == importArray.Length ? $"import './{x.Declaration!.Name.ToSnakeCase()}.dart';" : $"import '../{x.Declaration!.Name.ToSnakeCase()}.dart';"; - } - } - - for (int i = 0; i < (classArray.Length - equalSegments); i++) - { - importstatement = importstatement.Replace(classArray[i], "..", StringComparison.Ordinal); - } - return equalSegments == 0 ? $"import '.{importstatement}/{x.Declaration!.Name.ToSnakeCase()}.dart';" : $"import '{importstatement}/{x.Declaration!.Name.ToSnakeCase()}.dart';"; - } - return $"import './{x.Name.Split('.').Last()}/{x.Declaration!.Name.ToSnakeCase()}.dart';"; - } } From 5fe2fa7bc6a70417aaca406e71d91e6cdc8ecb44 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 11 Sep 2024 10:34:08 +0200 Subject: [PATCH 030/194] use different syntax for constructors of model classes that need to initialize non nullable additionalData field --- .../Refiners/DartRefinerFromScratch.cs | 9 +++++---- .../Writers/Dart/CodeMethodWriter.cs | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index fe31217cf4..5c9eee5010 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -112,7 +112,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); - + }, cancellationToken); } @@ -150,7 +150,8 @@ private static void CorrectCommonNames(CodeElement currentElement) CrawlTree(currentElement, element => CorrectCommonNames(element)); } - private static void CorrectMethodType(CodeMethod currentMethod) { + private static void CorrectMethodType(CodeMethod currentMethod) + { } @@ -178,8 +179,8 @@ private static void CorrectPropertyType(CodeProperty currentProperty) } else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) { - currentProperty.Type.Name = "Map"; - currentProperty.DefaultValue = "Map()"; + currentProperty.Type.Name = "Map"; + currentProperty.DefaultValue = "Map()"; } else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 1903f81732..ad574c7444 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -32,7 +32,16 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri writer.WriteLine($"if({parameterName} != null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); } HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); - writer.CloseBlock(); + + var isConstructor = codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); + if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) + { + writer.DecreaseIndent(); + } + else + { + writer.CloseBlock(); + } } protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter writer, bool doesInherit, CodeClass parentClass, bool isVoid) @@ -573,6 +582,10 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass } return " : super()"; } + else if (isConstructor && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) + { + return " : "; + } return string.Empty; } @@ -598,6 +611,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); var methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterLowerCase(); var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); + var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; if (includeNullableReferenceType) { var completeReturnTypeWithNullable = isConstructor || string.IsNullOrEmpty(genericTypeSuffix) ? completeReturnType : $"{completeReturnType[..^2].TrimEnd('?')}?{genericTypeSuffix} "; @@ -610,7 +624,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {openingBracket}"); } } From fe848f4be81acc7fb2d42800c422fb40d9bbd9bd Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 11 Sep 2024 16:03:48 +0200 Subject: [PATCH 031/194] changes to creation of requestgenerator method, simple form of method now compiles --- .../Refiners/DartRefinerFromScratch.cs | 5 ---- .../Writers/Dart/CodeMethodWriter.cs | 24 ++++++++++++------- .../Writers/Dart/DartConventionService.cs | 11 +++++---- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 5c9eee5010..839fc17760 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -59,11 +59,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance Name = AbstractionsNamespaceName, IsExternal = true } - }, - new CodeType - { - Name = "DefaultQueryParameters", - IsExternal = true, }); // This adds the BaseRequestBuilder class as a superclass diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index ad574c7444..c71e699db2 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -4,6 +4,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.OrderComparers; +using Microsoft.OpenApi.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeMethodWriter : BaseElementWriter @@ -418,33 +419,33 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req if (currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate) is not CodeProperty urlTemplateProperty) throw new InvalidOperationException("url template property cannot be null"); var operationName = codeElement.HttpMethod.ToString(); - writer.WriteLine($"var {RequestInfoVarName} = new RequestInformation(Method.{operationName?.ToUpperInvariant()}, {GetPropertyCall(urlTemplateProperty, "string.Empty")}, {GetPropertyCall(urlTemplateParamsProperty, "string.Empty")});"); + writer.WriteLine($"var {RequestInfoVarName} = RequestInformation(httpMethod : HttpMethod.{operationName?.ToLowerInvariant()}, {currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate)?.Name} : {GetPropertyCall(urlTemplateProperty, "string.Empty")}, {currentClass.GetPropertyOfKind(CodePropertyKind.PathParameters)?.Name} : {GetPropertyCall(urlTemplateParamsProperty, "string.Empty")});"); if (requestParams.requestConfiguration != null) - writer.WriteLine($"{RequestInfoVarName}.Configure({requestParams.requestConfiguration.Name});"); + writer.WriteLine($"{RequestInfoVarName}.configure({requestParams.requestConfiguration.Name});"); if (codeElement.ShouldAddAcceptHeader) - writer.WriteLine($"{RequestInfoVarName}.Headers.TryAdd(\"Accept\", \"{codeElement.AcceptHeaderValue}\");"); + writer.WriteLine($"{RequestInfoVarName}.headers.put(\"Accept\", \"{codeElement.AcceptHeaderValue}\");"); if (requestParams.requestBody != null) { var suffix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty; if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase)) { if (requestParams.requestContentType is not null) - writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name});"); else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType)) - writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");"); + writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");"); } else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty) if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase))) - writer.WriteLine($"{RequestInfoVarName}.SetContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); else - writer.WriteLine($"{RequestInfoVarName}.SetContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); } writer.WriteLine($"return {RequestInfoVarName};"); } - private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"{property.Name.ToFirstCharacterUpperCase()}"; + private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"{property.Name.ToFirstCharacterLowerCase()}"; private void WriteSerializerBody(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -631,7 +632,12 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) { var signatureSegments = conventions.GetParameterSignature(parameter, targetElement).Split(" ", StringSplitOptions.RemoveEmptyEntries); - return $"{signatureSegments[0]}? {string.Join(" ", signatureSegments[1..])}"; + var nullablesegment = signatureSegments[0]; + if (!"void".Equals(nullablesegment, StringComparison.Ordinal)) + { + nullablesegment = nullablesegment + "?"; + } + return $"{nullablesegment} {string.Join(" ", signatureSegments[1..])}"; } private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod method, bool includeNullableRef = false) { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index b23888acd4..a96c5d48a5 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -197,7 +197,10 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i $"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" : string.Empty; if (currentType.ActionOf && includeActionInformation) - return $"Func<{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}>"; + { + return $"void Function({collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix})"; + } + return $"{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}"; } @@ -271,6 +274,7 @@ public override string TranslateType(CodeType type) "double" or "float" or "decimal" or "int64" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "byte[]", + string s when s.Contains("RequestConfiguration", StringComparison.OrdinalIgnoreCase) => "RequestConfiguration", "iparsenode" => "ParseNode", _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "Object", }; @@ -293,9 +297,8 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen var parameterType = GetTypeString(parameter.Type, targetElement); var defaultValue = parameter switch { - _ when !string.IsNullOrEmpty(parameter.DefaultValue) => $" = {parameter.DefaultValue}", - _ when nameof(String).Equals(parameterType, StringComparison.OrdinalIgnoreCase) && parameter.Optional => " = \"\"", - _ when parameter.Optional => " = default", + _ when !string.IsNullOrEmpty(parameter.DefaultValue) => $" : {parameter.DefaultValue}", + _ when nameof(String).Equals(parameterType, StringComparison.OrdinalIgnoreCase) && parameter.Optional => " : \"\"", _ => string.Empty, }; return $"{GetDeprecationInformation(parameter)}{parameterType} {parameter.Name.ToFirstCharacterLowerCase()}{defaultValue}"; From 44f724852f7c3dcd98f7fce71047139e8e449fc1 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Thu, 12 Sep 2024 07:11:08 +0200 Subject: [PATCH 032/194] getFieldDeserializers works for simple case --- .../Refiners/DartRefinerFromScratch.cs | 6 ++- .../Writers/Dart/CodeMethodWriter.cs | 42 +++++++++++-------- .../Writers/Dart/DartConventionService.cs | 2 +- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 5c9eee5010..bc075c0ad9 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -152,7 +152,11 @@ private static void CorrectCommonNames(CodeElement currentElement) private static void CorrectMethodType(CodeMethod currentMethod) { - + if (currentMethod.IsOfKind(CodeMethodKind.Deserializer)) + { + currentMethod.ReturnType.Name = "Map"; + currentMethod.Name = "getFieldDeserializers"; + } } private static void CorrectPropertyType(CodeProperty currentProperty) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index ad574c7444..6b65e99a1f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -279,7 +279,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho .ToArray()); } } - private string DefaultDeserializerValue => $"Map>()"; + private string DefaultDeserializerValue => $"Map"; private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -308,6 +308,7 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par } writer.WriteLine($"return {DefaultDeserializerValue}();"); } + private const string DeserializerReturnType = "Map"; private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) { var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) @@ -330,18 +331,24 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La } writer.WriteLine($"return {DefaultDeserializerValue}();"); } + private const string DeserializerVarName = "deserializerMap"; private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { - var parentSerializationInfo = shouldHide ? $"(base.{codeElement.Name.ToFirstCharacterUpperCase()}())" : string.Empty; - writer.StartBlock($"return {DefaultDeserializerValue}{parentSerializationInfo} {{"); - foreach (var otherProp in parentClass - .GetPropertiesOfKind(CodePropertyKind.Custom) - .Where(static x => !x.ExistsInBaseType) - .OrderBy(static x => x.Name, StringComparer.Ordinal)) + + var fieldToSerialize = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom).ToArray(); + writer.WriteLine($"{DeserializerReturnType} {DeserializerVarName} = " + (shouldHide ? "{};" : "super.getFieldDeserializers();")); + + if (fieldToSerialize.Length != 0) { - writer.WriteLine($"{{\"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterLowerCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},"); + fieldToSerialize + .Where(static x => !x.ExistsInBaseType) + .OrderBy(static x => x.Name) + .Select(x => + $"{DeserializerVarName}['{x.WireName}'] = (node) => {x.WireName} = node.{GetDeserializationMethodName(x.Type, codeElement)};") + .ToList() + .ForEach(x => writer.WriteLine(x)); } - writer.CloseBlock("};"); + writer.WriteLine($"return {DeserializerVarName};"); } private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod method) { @@ -351,22 +358,23 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me { if (isCollection) { - var collectionMethod = propType.IsArray ? "?.ToArray()" : "?.ToList()"; + var collectionMethod = ""; if (currentType.TypeDefinition == null) - return $"GetCollectionOfPrimitiveValues<{propertyType}>(){collectionMethod}"; + return $"getCollectionOfPrimitiveValues<{propertyType}>(){collectionMethod}"; else if (currentType.TypeDefinition is CodeEnum) - return $"GetCollectionOfEnumValues<{propertyType.TrimEnd('?')}>(){collectionMethod}"; + return $"getCollectionOfEnumValues<{propertyType.TrimEnd('?')}>(){collectionMethod}"; else - return $"GetCollectionOfObjectValues<{propertyType}>({propertyType}.CreateFromDiscriminatorValue){collectionMethod}"; + return $"getCollectionOfObjectValues<{propertyType}>({propertyType}.CreateFromDiscriminatorValue){collectionMethod}"; } else if (currentType.TypeDefinition is CodeEnum enumType) - return $"GetEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>()"; + return $"getEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>()"; } return propertyType switch { - "byte[]" => "GetByteArrayValue()", - _ when conventions.IsPrimitiveType(propertyType) => $"Get{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value()", - _ => $"GetObjectValue<{propertyType.ToFirstCharacterUpperCase()}>({propertyType}.CreateFromDiscriminatorValue)", + "byte[]" => "getByteArrayValue()", + String => "getStringValue()", + _ when conventions.IsPrimitiveType(propertyType) => $"get{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value()", + _ => $"getObjectValue<{propertyType.ToFirstCharacterUpperCase()}>({propertyType}.createFromDiscriminatorValue)", }; } protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams requestParams, CodeClass parentClass, bool isVoid, string returnTypeWithoutCollectionInformation, LanguageWriter writer) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index b23888acd4..4187af89f9 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -186,7 +186,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i { var typeName = TranslateTypeAndAvoidUsingNamespaceSegmentNames(currentType, targetElement); var nullableSuffix = ShouldTypeHaveNullableMarker(code, typeName) && includeNullableInformation ? NullableMarkerAsString : string.Empty; - var collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation ? "List<" : string.Empty; + var collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation ? "Iterable<" : string.Empty; var collectionSuffix = currentType.CollectionKind switch { CodeTypeCollectionKind.Complex when includeCollectionInformation => ">", From c7524b6fc198255b269b19362517475a78ccb93c Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 12 Sep 2024 08:26:07 +0200 Subject: [PATCH 033/194] Changes to make requestexecutor method compile --- .../Refiners/DartRefinerFromScratch.cs | 1 + .../Writers/Dart/CodeMethodWriter.cs | 31 ++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index d1a0018f3d..6d4c85f8ac 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -105,6 +105,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance [$"{AbstractionsNamespaceName}.ParseNodeFactoryRegistry"]); cancellationToken.ThrowIfCancellationRequested(); + RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 99f04b64b6..162e152def 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -393,21 +393,21 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re var parametersList = new CodeParameter?[] { requestParams.requestBody, requestParams.requestContentType, requestParams.requestConfiguration } .Select(static x => x?.Name).Where(static x => x != null).Aggregate(static (x, y) => $"{x}, {y}"); writer.WriteLine($"var requestInfo = {generatorMethodName}({parametersList});"); - var errorMappingVarName = "default"; + var errorMappingVarName = "{}"; if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.WriteLine($"var {errorMappingVarName} = new Dictionary> {{"); + writer.WriteLine($"var {errorMappingVarName} = {{"); writer.IncreaseIndent(); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { - writer.WriteLine($"{{\"{errorMapping.Key.ToUpperInvariant()}\", {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.CreateFromDiscriminatorValue}},"); + writer.WriteLine($"\"{errorMapping.Key.ToUpperInvariant()}\" : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); } writer.CloseBlock("};"); } var returnTypeCodeType = codeElement.ReturnType as CodeType; var returnTypeFactory = returnTypeCodeType?.TypeDefinition is CodeClass - ? $", {returnTypeWithoutCollectionInformation}.CreateFromDiscriminatorValue" + ? $", {returnTypeWithoutCollectionInformation}.createFromDiscriminatorValue" : null; var prefix = (isVoid, codeElement.ReturnType.IsCollection) switch { @@ -415,7 +415,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re (_, true) => "var collectionResult = ", (_, _) => "return ", }; - writer.WriteLine($"{prefix}await RequestAdapter.{GetSendRequestMethodName(isVoid, codeElement, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, {errorMappingVarName}, cancellationToken).ConfigureAwait(false);"); + writer.WriteLine($"{prefix}await requestAdapter.{GetSendRequestMethodName(isVoid, codeElement, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, {errorMappingVarName});"); if (codeElement.ReturnType.IsCollection) writer.WriteLine("return collectionResult?.ToList();"); } @@ -546,14 +546,14 @@ protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElemen var returnTypeName = conventions.GetTypeString(returnType, currentElement, false); var isStream = conventions.StreamTypeName.Equals(returnTypeName, StringComparison.OrdinalIgnoreCase); var isEnum = returnType is CodeType codeType && codeType.TypeDefinition is CodeEnum; - if (isVoid) return "SendNoContentAsync"; + if (isVoid) return "sendNoContent"; else if (isStream || conventions.IsPrimitiveType(returnTypeName) || isEnum) if (returnType.IsCollection) - return $"SendPrimitiveCollectionAsync<{returnTypeName}>"; + return $"sendPrimitiveCollectionAsync<{returnTypeName}>"; else - return $"SendPrimitiveAsync<{returnTypeName}>"; - else if (returnType.IsCollection) return $"SendCollectionAsync<{returnTypeName}>"; - else return $"SendAsync<{returnTypeName}>"; + return $"sendPrimitive<{returnTypeName}>"; + else if (returnType.IsCollection) return $"sendCollection<{returnTypeName}>"; + else return $"send<{returnTypeName}>"; } private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) { @@ -608,14 +608,15 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var genericTypePrefix = isVoid ? string.Empty : "<"; var genericTypeSuffix = code.IsAsync && !isVoid ? ">" : string.Empty; var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - var asyncPrefix = code.IsAsync ? "async " + genericTypePrefix : string.Empty; var voidCorrectedTaskReturnType = code.IsAsync && isVoid ? string.Empty : returnType; + var async = code.IsAsync ? " async" : string.Empty; if (code.ReturnType.IsArray && code.IsOfKind(CodeMethodKind.RequestExecutor)) voidCorrectedTaskReturnType = $"IEnumerable<{voidCorrectedTaskReturnType.StripArraySuffix()}>"; + else if (code.IsOfKind(CodeMethodKind.RequestExecutor) && code.IsAsync) + voidCorrectedTaskReturnType = $"Future<{voidCorrectedTaskReturnType.StripArraySuffix()}>"; // TODO: Task type should be moved into the refiner var completeReturnType = isConstructor ? - string.Empty : - $"{asyncPrefix}{voidCorrectedTaskReturnType}{genericTypeSuffix} "; + string.Empty : voidCorrectedTaskReturnType + " "; var baseSuffix = GetBaseSuffix(isConstructor, inherits, parentClass, code); var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); var methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterLowerCase(); @@ -629,11 +630,11 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua GetParameterSignatureWithNullableRefType(p, code) : conventions.GetParameterSignature(p, code)) .ToList()); - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}{async} {{"); } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {openingBracket}"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}{async} {openingBracket}"); } } From 8b0f41ede180cf9688c84c017a80d907dbfdd299 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 12 Sep 2024 08:34:22 +0200 Subject: [PATCH 034/194] Use dynamic instead of object for pathparameter --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 6d4c85f8ac..b358155245 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -189,9 +189,9 @@ private static void CorrectPropertyType(CodeProperty currentProperty) else if (currentProperty.IsOfKind(CodePropertyKind.PathParameters)) { currentProperty.Type.IsNullable = true; - currentProperty.Type.Name = "Map"; + currentProperty.Type.Name = "Map"; if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) - currentProperty.DefaultValue = "Map()"; + currentProperty.DefaultValue = "Map()"; } currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); // TODO KEES From 1599e98257f4da1d06f98b91c9b67ec8edc49cdc Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 12 Sep 2024 09:15:42 +0200 Subject: [PATCH 035/194] Corrected requestbuilder arguments --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index ae84958a86..9b9e36b552 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -109,8 +109,7 @@ internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, La { var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : $", {string.Join(", ", pathParameters.Select(x => $"{x.Name.ToFirstCharacterLowerCase()}"))}"; var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterLowerCase() : urlTemplateVarName; - // TODO Kees this can't be the final output but curently it creates a correct ApiClient - writer.WriteLine($"{prefix}{returnType}({requestAdapterProp.Name.ToFirstCharacterLowerCase()}, \"\", {urlTplRef});"); + writer.WriteLine($"{prefix}{returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterLowerCase()}{pathParametersSuffix});"); } } From debbc43e4dff086862171f01dfaeb3e88ffc715d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 12 Sep 2024 11:04:29 +0200 Subject: [PATCH 036/194] Use named constructor for requestbuilders with raw url parameter --- .../Refiners/DartRefinerFromScratch.cs | 7 +++++++ .../Writers/Dart/CodeMethodWriter.cs | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index b358155245..b5f106a7c6 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -153,6 +153,13 @@ private static void CorrectMethodType(CodeMethod currentMethod) currentMethod.ReturnType.Name = "Map"; currentMethod.Name = "getFieldDeserializers"; } + else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlConstructor)) + { + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.RequestAdapter)) + .Where(x => x.Type.Name.StartsWith('I')) + .ToList() + .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" + } } private static void CorrectPropertyType(CodeProperty currentProperty) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 162e152def..da31cac56a 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -113,7 +113,7 @@ private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElemen { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property"); - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}.withUrl({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterLowerCase()});"); } private static readonly CodePropertyTypeComparer CodePropertyTypeForwardComparer = new(); private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true); @@ -576,7 +576,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass if (currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParameter) thirdParameterName = $", {pathParametersParameter.Name}"; else if (currentMethod.Parameters.OfKind(CodeParameterKind.RawUrl) is CodeParameter rawUrlParameter) - thirdParameterName = $", {rawUrlParameter.Name}"; + thirdParameterName = $", {{RequestInformation.rawUrlKey : {rawUrlParameter.Name}}}"; else if (parentClass.Properties.FirstOrDefaultOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProperty && !string.IsNullOrEmpty(pathParametersProperty.DefaultValue)) thirdParameterName = $", {pathParametersProperty.DefaultValue}"; if (currentMethod.Parameters.OfKind(CodeParameterKind.RequestAdapter) is CodeParameter requestAdapterParameter) @@ -619,7 +619,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua string.Empty : voidCorrectedTaskReturnType + " "; var baseSuffix = GetBaseSuffix(isConstructor, inherits, parentClass, code); var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); - var methodName = isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterLowerCase(); + var methodName = GetMethodName(code, parentClass, isConstructor); var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; if (includeNullableReferenceType) @@ -638,6 +638,15 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua } } + private static string GetMethodName(CodeMethod code, CodeClass parentClass, bool isConstructor) + { + if (code.IsOfKind(CodeMethodKind.RawUrlConstructor)) + { + return parentClass.Name.ToFirstCharacterUpperCase() + ".withUrl"; + } + return isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterLowerCase(); + } + private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) { var signatureSegments = conventions.GetParameterSignature(parameter, targetElement).Split(" ", StringSplitOptions.RemoveEmptyEntries); From ee10fabfe915a3d8858c1e138d0942e834532bce Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 12 Sep 2024 13:44:52 +0200 Subject: [PATCH 037/194] Remove unneccesary void --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 9b9e36b552..df67abb767 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -197,7 +197,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i string.Empty; if (currentType.ActionOf && includeActionInformation) { - return $"void Function({collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix})"; + return $"Function({collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix})"; } return $"{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}"; From 409b7e26aa0f740f41ed0a3b014f11c9a380ec31 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Thu, 12 Sep 2024 15:10:08 +0200 Subject: [PATCH 038/194] For simple cases (de)serializers work --- .../Writers/Dart/CodeMethodWriter.cs | 23 ++++++++++--------- .../Writers/Dart/DartConventionService.cs | 1 + 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 99f04b64b6..45239323b9 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -337,7 +337,7 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod { var fieldToSerialize = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom).ToArray(); - writer.WriteLine($"{DeserializerReturnType} {DeserializerVarName} = " + (shouldHide ? "{};" : "super.getFieldDeserializers();")); + writer.WriteLine($"{DeserializerReturnType} {DeserializerVarName} = " + (shouldHide ? "super.getFieldDeserializers();" : "{};")); if (fieldToSerialize.Length != 0) { @@ -464,7 +464,7 @@ private void WriteSerializerBody(bool shouldHide, CodeMethod method, CodeClass p WriteSerializerBodyForInheritedModel(shouldHide, method, parentClass, writer); if (parentClass.GetPropertyOfKind(CodePropertyKind.AdditionalData) is CodeProperty additionalDataProperty) - writer.WriteLine($"writer.WriteAdditionalData({additionalDataProperty.Name});"); + writer.WriteLine($"writer.writeAdditionalData({additionalDataProperty.Name.ToFirstCharacterLowerCase()});"); } private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) { @@ -476,7 +476,7 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me .OrderBy(static x => x.Name)) { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); - writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterUpperCase()});"); + writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterLowerCase()});"); } } private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) @@ -601,7 +601,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; - if (inherits && (code.Kind == CodeMethodKind.Serializer || code.Kind == CodeMethodKind.Deserializer)) + if (code.Kind == CodeMethodKind.Serializer || code.Kind == CodeMethodKind.Deserializer) { writer.WriteLine("@override"); } @@ -655,20 +655,21 @@ private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod meth { if (isCollection) if (currentType.TypeDefinition == null) - return $"WriteCollectionOfPrimitiveValues<{propertyType}>"; + return $"writeCollectionOfPrimitiveValues<{propertyType}>"; else if (currentType.TypeDefinition is CodeEnum) - return $"WriteCollectionOfEnumValues<{propertyType.TrimEnd('?')}>"; + return $"writeCollectionOfEnumValues<{propertyType.TrimEnd('?')}>"; else - return $"WriteCollectionOfObjectValues<{propertyType}>"; + return $"writeCollectionOfObjectValues<{propertyType}>"; else if (currentType.TypeDefinition is CodeEnum enumType) - return $"WriteEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>"; + return $"writeEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>"; } return propertyType switch { - "byte[]" => "WriteByteArrayValue", - _ when conventions.IsPrimitiveType(propertyType) => $"Write{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value", - _ => $"WriteObjectValue<{propertyType.ToFirstCharacterUpperCase()}{(includeNullableRef ? "?" : string.Empty)}>", + "byte[]" => "writeByteArrayValue", + "String" => "writeStringValue", + _ when conventions.IsPrimitiveType(propertyType) => $"write{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value", + _ => $"writeObjectValue<{propertyType.ToFirstCharacterUpperCase()}{(includeNullableRef ? "?" : "")}>", }; } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index ae84958a86..b5306e691c 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -276,6 +276,7 @@ public override string TranslateType(CodeType type) "binary" or "base64" or "base64url" => "byte[]", string s when s.Contains("RequestConfiguration", StringComparison.OrdinalIgnoreCase) => "RequestConfiguration", "iparsenode" => "ParseNode", + "iserializationwriter" => "SerializationWriter", _ => type.Name.ToFirstCharacterUpperCase() is string typeName && !string.IsNullOrEmpty(typeName) ? typeName : "Object", }; } From bdf2ea721b32c0980ea615b559f6ad2497a07bb5 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 12 Sep 2024 15:23:12 +0200 Subject: [PATCH 039/194] Filter imports --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index b5f106a7c6..e1567d1a0b 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -75,7 +75,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddDefaultImports(generatedCode, defaultUsingEvaluators); AddInheritedTypeImport(generatedCode); - AddPropertiesAndMethodTypesImports(generatedCode, true, true, false); + AddPropertiesAndMethodTypesImports(generatedCode, true, true, false, codeTypeFilter); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); @@ -229,4 +229,13 @@ currentClass.StartBlock is ClassDeclaration currentClassDeclaration && } CrawlTree(currentElement, AddInheritedTypeImport); } + + public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) + { + var nestedTypes = usingsToAdd.OfType().Where( + static codeType => codeType.TypeDefinition is CodeClass codeClass + && codeClass.IsOfKind(CodeClassKind.RequestConfiguration)); + + return usingsToAdd.Except(nestedTypes); + } } From 1d8ecd37ce286a4e7c9624c74c3c159c292dc7e6 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 13 Sep 2024 07:54:12 +0200 Subject: [PATCH 040/194] Remove redundant method --- .../Refiners/DartRefinerFromScratch.cs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index e1567d1a0b..4ff39b41fd 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -74,7 +74,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance }, addCurrentTypeAsGenericTypeParameter: true); AddDefaultImports(generatedCode, defaultUsingEvaluators); - AddInheritedTypeImport(generatedCode); AddPropertiesAndMethodTypesImports(generatedCode, true, true, false, codeTypeFilter); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); @@ -209,27 +208,6 @@ private static void CorrectImplements(ProprietableBlockDeclaration block) { block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I } - private static void AddInheritedTypeImport(CodeElement currentElement) - { - if (currentElement is CodeClass currentClass && - currentClass.StartBlock is ClassDeclaration currentClassDeclaration && - currentClass.GetImmediateParentOfType() is CodeNamespace currentClassNamespace) - { - var inheritTypes = currentClassDeclaration.Inherits?.AllTypes ?? Enumerable.Empty(); - var usingsToAdd = inheritTypes - .SelectMany(static x => x.AllTypes.Select(static y => (type: y, ns: y.TypeDefinition?.GetImmediateParentOfType()))) - .Where(static x => x.ns != null) - .Select(static x => new CodeUsing { Name = x.ns!.Name, Declaration = x.type }) - .Where(x => x.Declaration?.TypeDefinition != currentElement) - .ToArray(); - - - if (usingsToAdd.Length != 0) - (currentClass.Parent is CodeClass parentClass ? parentClass : currentClass).AddUsing(usingsToAdd); - } - CrawlTree(currentElement, AddInheritedTypeImport); - } - public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) { var nestedTypes = usingsToAdd.OfType().Where( From b28e0b2a8773c7c5e187a1dd8c4c4b46026e96df Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 13 Sep 2024 11:46:54 +0200 Subject: [PATCH 041/194] void should be void instead of empty --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 8501532534..f35f2809ff 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -608,7 +608,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var genericTypePrefix = isVoid ? string.Empty : "<"; var genericTypeSuffix = code.IsAsync && !isVoid ? ">" : string.Empty; var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - var voidCorrectedTaskReturnType = code.IsAsync && isVoid ? string.Empty : returnType; + var voidCorrectedTaskReturnType = code.IsAsync && isVoid ? "void" : returnType; var async = code.IsAsync ? " async" : string.Empty; if (code.ReturnType.IsArray && code.IsOfKind(CodeMethodKind.RequestExecutor)) voidCorrectedTaskReturnType = $"IEnumerable<{voidCorrectedTaskReturnType.StripArraySuffix()}>"; From 4e3fa89a54f2da4afa2d25ab1ea46b10ff6f2733 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 13 Sep 2024 15:32:33 +0200 Subject: [PATCH 042/194] Replace indexer methods --- .../Refiners/DartRefinerFromScratch.cs | 5 ++++ .../Writers/Dart/CodeIndexerWriter.cs | 25 ------------------- .../Writers/Dart/CodeMethodWriter.cs | 3 ++- .../Writers/Dart/DartConventionService.cs | 10 ++++++-- src/Kiota.Builder/Writers/Dart/DartWriter.cs | 3 +-- 5 files changed, 16 insertions(+), 30 deletions(-) delete mode 100644 src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 4ff39b41fd..a615129d0a 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -50,6 +50,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance cancellationToken.ThrowIfCancellationRequested(); var defaultConfiguration = new GenerationConfiguration(); CorrectCommonNames(generatedCode); + ReplaceIndexersByMethodsWithParameter(generatedCode, + false, + static x => $"by{x.ToFirstCharacterUpperCase()}", + static x => x.ToFirstCharacterLowerCase(), + GenerationLanguage.Dart); RemoveRequestConfigurationClasses(generatedCode, new CodeUsing { diff --git a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs deleted file mode 100644 index c83963d755..0000000000 --- a/src/Kiota.Builder/Writers/Dart/CodeIndexerWriter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Kiota.Builder.CodeDOM; -using Kiota.Builder.Extensions; - -namespace Kiota.Builder.Writers.Dart; -public class CodeIndexerWriter : BaseElementWriter -{ - public CodeIndexerWriter(DartConventionService conventionService) : base(conventionService) { } - public override void WriteCodeElement(CodeIndexer codeElement, LanguageWriter writer) - { - ArgumentNullException.ThrowIfNull(codeElement); - ArgumentNullException.ThrowIfNull(writer); - if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("The parent of a property should be a class"); - var returnType = conventions.GetTypeString(codeElement.ReturnType, codeElement); - conventions.WriteShortDescription(codeElement, writer); - // TODO Kees, make it work: - // writer.WriteLine($"{conventions.DocCommentPrefix}{codeElement.IndexParameter.Documentation.Description.CleanupXMLString()}"); - conventions.WriteDeprecationAttribute(codeElement, writer); - writer.StartBlock($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexParameter.Type, codeElement)} position] {{ get {{"); - if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp) - conventions.AddParametersAssignment(writer, pathParametersProp.Type, pathParametersProp.Name.ToFirstCharacterUpperCase(), string.Empty, (codeElement.IndexParameter.Type, codeElement.IndexParameter.SerializationName, "position")); - conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName, "return "); - writer.CloseBlock("} }"); - } -} diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index f35f2809ff..90756bba21 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -81,6 +81,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w case CodeMethodKind.RawUrlConstructor: WriteConstructorBody(parentClass, codeElement, writer); break; + case CodeMethodKind.IndexerBackwardCompatibility: case CodeMethodKind.RequestBuilderWithParameters: WriteRequestBuilderBody(parentClass, codeElement, writer); break; @@ -219,7 +220,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas private void WriteRequestBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) { var importSymbol = conventions.GetTypeString(codeElement.ReturnType, parentClass); - conventions.AddRequestBuilderBody(parentClass, importSymbol, writer, prefix: "return ", pathParameters: codeElement.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Path))); + conventions.AddRequestBuilderBody(parentClass, importSymbol, writer, prefix: "return ", pathParameters: codeElement.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Path)), customParameters: codeElement.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Custom))); } private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index bd6b10801c..f99438007c 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -102,15 +102,21 @@ public string GetAccessModifierAttribute(AccessModifier access) return string.Empty; } - internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, string? prefix = default, IEnumerable? pathParameters = default) + internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, string? prefix = default, IEnumerable? pathParameters = default, IEnumerable? customParameters = default) { if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProp) { var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : $", {string.Join(", ", pathParameters.Select(x => $"{x.Name.ToFirstCharacterLowerCase()}"))}"; var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterLowerCase() : urlTemplateVarName; + if (customParameters?.Any() ?? false) + { + urlTplRef = TempDictionaryVarName; + writer.WriteLine($"var {urlTplRef} = Map.of({pathParametersProp.Name.ToFirstCharacterLowerCase()});"); + foreach (var param in customParameters) + writer.WriteLine($"{urlTplRef}.putIfAbsent(\"{param.Name.ToFirstCharacterLowerCase()}\", ()=> {param.Name.ToFirstCharacterLowerCase()});"); + } writer.WriteLine($"{prefix}{returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterLowerCase()}{pathParametersSuffix});"); - } } public override string TempDictionaryVarName => "urlTplParams"; diff --git a/src/Kiota.Builder/Writers/Dart/DartWriter.cs b/src/Kiota.Builder/Writers/Dart/DartWriter.cs index a660c665d9..26afd9f0d3 100644 --- a/src/Kiota.Builder/Writers/Dart/DartWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/DartWriter.cs @@ -10,10 +10,9 @@ public DartWriter(string rootPath, string clientNamespaceName) AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeBlockEndWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeEnumWriter(conventionService)); - AddOrReplaceCodeElementWriter(new CodeIndexerWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodePropertyWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeTypeWriter(conventionService)); - + } } From 07328762596ca470cb25fb8540a1f02f70a87b2c Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 16 Sep 2024 07:30:04 +0200 Subject: [PATCH 043/194] Added imports for discriminator types Currently works for the simple case we are processing. --- .../Dart/CodeClassDeclarationWriter.cs | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 5574cd772c..bc9d98b45c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -1,13 +1,15 @@ using System; +using System.Collections.Generic; using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.PathSegmenters; +using Microsoft.Kiota.Abstractions.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter { - public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) {} + public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { @@ -17,8 +19,10 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); + addImportsForDiscriminatorTypes(codeElement); + var currentNamespace = codeElement.GetImmediateParentOfType(); - + var relativeImportManager = new RelativeImportManager( "keyhub", '.', (writer.PathSegmenter as DartPathSegmenter)!.GetRelativeFileName); @@ -56,4 +60,35 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()}{derivation}{implements} {{"); } + /// + /// Dart needs import statements for classes that are in the same folder. + /// Date: Tue, 17 Sep 2024 08:37:45 +0200 Subject: [PATCH 044/194] Pretty close to having a working generator Two things go wrong: 1 The content type must be application/json As vendor specific content types are not yet supported. 2 The URL passed is incorrect. With these minor changes the client runs for a very simple request. --- .../Writers/Dart/CodeBlockEndWriter.cs | 3 ++- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index f23fa76f93..831464d9d1 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -2,6 +2,7 @@ using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.OrderComparers; namespace Kiota.Builder.Writers.Dart; public class CodeBlockEndWriter : BaseElementWriter @@ -22,7 +23,7 @@ private void overrideCloneMethod(BlockEnd codeElement, LanguageWriter writer) writer.WriteLine($"{classElement.Name.ToFirstCharacterUpperCase()} clone() {{"); writer.IncreaseIndent(); var constructor = classElement.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); - String? argumentList = constructor?.Parameters.Select(static x => x.Name).Aggregate(static (x, y) => $"{x}, {y}"); + String? argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()).Select(static x => x.Name).Aggregate(static (x, y) => $"{x}, {y}"); writer.WriteLine($"return {classElement.Name.ToFirstCharacterUpperCase()}({argumentList});"); writer.DecreaseIndent(); writer.WriteLine("}"); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 90756bba21..9863d1cbca 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -30,7 +30,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri { var parameterName = parameter.Name.ToFirstCharacterLowerCase(); if (nameof(String).Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase) && parameter.Type.CollectionKind == CodeTypeBase.CodeTypeCollectionKind.None) - writer.WriteLine($"if({parameterName} != null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); + writer.WriteLine($"if({parameterName} == null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); } HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); @@ -120,7 +120,7 @@ private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElemen private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true); private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { - writer.StartBlock($"return {DiscriminatorMappingVarName} switch {{"); + writer.StartBlock($"return switch({DiscriminatorMappingVarName}) {{"); foreach (var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings) { writer.WriteLine($"\"{mappedType.Key}\" => {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); @@ -206,7 +206,11 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas var parseNodeParameter = codeElement.Parameters.OfKind(CodeParameterKind.ParseNode) ?? throw new InvalidOperationException("Factory method should have a ParseNode parameter"); if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) - writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.GetChildNode(\"{parentClass.DiscriminatorInformation.DiscriminatorPropertyName}\")?.GetStringValue();"); + { + var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; + discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; + writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode(\"{discriminatorPropertyName}\")?.getStringValue();"); + } if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) WriteFactoryMethodBodyForInheritedModel(codeElement, parentClass, writer); @@ -232,7 +236,7 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me WriteSerializationRegistration(method.DeserializerModules, writer, "registerDefaultDeserializer"); if (!string.IsNullOrEmpty(method.BaseUrl)) { - writer.StartBlock($"if ({requestAdapterPropertyName}.baseUrl != null || {requestAdapterPropertyName}.baseUrl!.isEmpty) {{"); + writer.StartBlock($"if ({requestAdapterPropertyName}.baseUrl == null || {requestAdapterPropertyName}.baseUrl!.isEmpty) {{"); writer.WriteLine($"{requestAdapterPropertyName}.baseUrl = \"{method.BaseUrl}\";"); writer.CloseBlock(); if (pathParametersProperty != null) @@ -346,7 +350,7 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod .Where(static x => !x.ExistsInBaseType) .OrderBy(static x => x.Name) .Select(x => - $"{DeserializerVarName}['{x.WireName}'] = (node) => {x.WireName} = node.{GetDeserializationMethodName(x.Type, codeElement)};") + $"{DeserializerVarName}['{x.WireName}'] = (node) => {x.Name.ToFirstCharacterLowerCase()} = node.{GetDeserializationMethodName(x.Type, codeElement)};") .ToList() .ForEach(x => writer.WriteLine(x)); } From 2324933f9d882d36389c30feb93822e8770c249f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 17 Sep 2024 08:42:52 +0200 Subject: [PATCH 045/194] Correct type for datetime, fix missing enum importsg --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 3 +-- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index a615129d0a..6da7b3b838 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -79,7 +79,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance }, addCurrentTypeAsGenericTypeParameter: true); AddDefaultImports(generatedCode, defaultUsingEvaluators); - AddPropertiesAndMethodTypesImports(generatedCode, true, true, false, codeTypeFilter); + AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); @@ -112,7 +112,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); - }, cancellationToken); } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index f99438007c..c2e37cda35 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -279,6 +279,7 @@ public override string TranslateType(CodeType type) "double" or "float" or "decimal" or "int64" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "byte[]", + "datetimeoffset" => "DateTime", string s when s.Contains("RequestConfiguration", StringComparison.OrdinalIgnoreCase) => "RequestConfiguration", "iparsenode" => "ParseNode", "iserializationwriter" => "SerializationWriter", From a7e2d32f9566e8143273419bc0ab7502cded64bf Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 17 Sep 2024 10:50:49 +0200 Subject: [PATCH 046/194] Arrays should be lists in dart --- .../Writers/Dart/DartConventionService.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index c2e37cda35..4aee5706ab 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.Tracing; using System.Globalization; using System.Linq; @@ -192,12 +193,11 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i var typeName = TranslateTypeAndAvoidUsingNamespaceSegmentNames(currentType, targetElement); var nullableSuffix = ShouldTypeHaveNullableMarker(code, typeName) && includeNullableInformation ? NullableMarkerAsString : string.Empty; var collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation ? "Iterable<" : string.Empty; - var collectionSuffix = currentType.CollectionKind switch + if (currentType.CollectionKind == CodeTypeCollectionKind.Array && includeCollectionInformation) { - CodeTypeCollectionKind.Complex when includeCollectionInformation => ">", - CodeTypeCollectionKind.Array when includeCollectionInformation => "[]", - _ => string.Empty, - }; + collectionPrefix = "List<"; + } + var collectionSuffix = currentType.CollectionKind == CodeTypeCollectionKind.None ? string.Empty : ">"; var genericParameters = currentType.GenericTypeParameterValues.Count != 0 ? $"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" : string.Empty; From c12e490590485222b157cd8bca2d3ecf76a7d9b5 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 17 Sep 2024 11:30:23 +0200 Subject: [PATCH 047/194] Fix double >> --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 4aee5706ab..a688722914 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -197,7 +197,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i { collectionPrefix = "List<"; } - var collectionSuffix = currentType.CollectionKind == CodeTypeCollectionKind.None ? string.Empty : ">"; + var collectionSuffix = currentType.CollectionKind == CodeTypeCollectionKind.None || !includeCollectionInformation ? string.Empty : ">"; var genericParameters = currentType.GenericTypeParameterValues.Count != 0 ? $"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" : string.Empty; From 0899156e9334a2962f1510ab69526404d2a4910c Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 17 Sep 2024 15:46:59 +0200 Subject: [PATCH 048/194] Fix imports of subclasses in different directories --- .../Writers/Dart/CodeClassDeclarationWriter.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index bc9d98b45c..11d501d491 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -75,18 +75,13 @@ void addImportsForDiscriminatorTypes(ClassDeclaration classDeclaration) { var discriminatorInformation = (method.Parent as IDiscriminatorInformationHolder)!.DiscriminatorInformation; var discriminatorMappings = discriminatorInformation.DiscriminatorMappings; - foreach(var discriminatorMapping in discriminatorMappings) { + foreach (var discriminatorMapping in discriminatorMappings) + { var className = discriminatorMapping.Value.Name; - // ToSnakeCase does not process strings starting with a capital letter correctly - // so we change the first lettter to lower case - className = $"./{string.Concat(className[..1].ToLowerInvariant(), className.AsSpan(1))}"; - classDeclaration.AddUsings(new CodeUsing { + classDeclaration.AddUsings(new CodeUsing + { Name = className, - Declaration = new() - { - Name = className, - IsExternal = false, - } + Declaration = discriminatorMapping.Value }); } } From 7f5f4d5443e4c8115af0e37f0c8433e89f104def Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 18 Sep 2024 09:33:15 +0200 Subject: [PATCH 049/194] Small fixes to field deserializer method --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 +-- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 9863d1cbca..9546959521 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -370,7 +370,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me else if (currentType.TypeDefinition is CodeEnum) return $"getCollectionOfEnumValues<{propertyType.TrimEnd('?')}>(){collectionMethod}"; else - return $"getCollectionOfObjectValues<{propertyType}>({propertyType}.CreateFromDiscriminatorValue){collectionMethod}"; + return $"getCollectionOfObjectValues<{propertyType}>({propertyType}.createFromDiscriminatorValue){collectionMethod}"; } else if (currentType.TypeDefinition is CodeEnum enumType) return $"getEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>()"; @@ -378,7 +378,6 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me return propertyType switch { "byte[]" => "getByteArrayValue()", - String => "getStringValue()", _ when conventions.IsPrimitiveType(propertyType) => $"get{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value()", _ => $"getObjectValue<{propertyType.ToFirstCharacterUpperCase()}>({propertyType}.createFromDiscriminatorValue)", }; diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index a688722914..79c608f86d 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -293,7 +293,7 @@ public bool IsPrimitiveType(string typeName) typeName = typeName.StripArraySuffix().TrimEnd('?').ToLowerInvariant(); return typeName switch { - "String" => true, + "string" or "dateonly" or "datetime" => true, _ when NullableTypes.Contains(typeName) => true, _ => false, }; From accc199dbf2d4c734487500cc600987979ae4fd6 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 18 Sep 2024 11:14:08 +0200 Subject: [PATCH 050/194] Enum values named according to conventions --- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 0acfb5d8ca..9b3a12ac3f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -4,6 +4,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.Refiners; namespace Kiota.Builder.Writers.Dart; public class CodeEnumWriter : BaseElementWriter @@ -16,7 +17,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write ArgumentNullException.ThrowIfNull(writer); if (!codeElement.Options.Any()) return; - + DartReservedNamesProvider reservedNamesProvider = new DartReservedNamesProvider(); conventions.WriteShortDescription(codeElement, writer); if (codeElement.Flags) writer.WriteLine("[Flags]"); @@ -26,14 +27,13 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); - if (IsAllCapital(option.Name)) - { - writer.WriteLine($"{option.Name}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); - } - else + var value = option.Name.ToLowerInvariant().ToCamelCase('_'); + if (reservedNamesProvider.ReservedNames.Contains(value)) { - writer.WriteLine($"{option.Name.ToFirstCharacterLowerCase()}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); + value = value.ToUpperInvariant(); } + writer.WriteLine($"{value}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); + idx++; } } From 9bde37f9f7bbf7b1f82d0ea6f48df9ea232387b0 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 18 Sep 2024 13:19:27 +0200 Subject: [PATCH 051/194] Might be Uint8List in the future But since Dart does not supports byte[] List is for now the better choice. Note: Uint8List requires a separate import. --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index a688722914..7582ef726e 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -278,7 +278,7 @@ public override string TranslateType(CodeType type) "string" => "String", "double" or "float" or "decimal" or "int64" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack - "binary" or "base64" or "base64url" => "byte[]", + "binary" or "base64" or "base64url" => "List", "datetimeoffset" => "DateTime", string s when s.Contains("RequestConfiguration", StringComparison.OrdinalIgnoreCase) => "RequestConfiguration", "iparsenode" => "ParseNode", From 8faad2ceff837487915fc5b31610afbaeb6c8793 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 19 Sep 2024 10:19:20 +0200 Subject: [PATCH 052/194] added type to requestconfiguration --- .../Refiners/DartRefinerFromScratch.cs | 55 +++++++++++++++---- .../Writers/Dart/CodeEnumWriter.cs | 5 -- .../Writers/Dart/CodeMethodWriter.cs | 8 ++- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 6da7b3b838..bb2dca5861 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -55,17 +55,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance static x => $"by{x.ToFirstCharacterUpperCase()}", static x => x.ToFirstCharacterLowerCase(), GenerationLanguage.Dart); - RemoveRequestConfigurationClasses(generatedCode, - new CodeUsing - { - Name = "RequestConfiguration", - Declaration = new CodeType - { - Name = AbstractionsNamespaceName, - IsExternal = true - } - }); + AddQueryParameterExtractorMethod(generatedCode); // This adds the BaseRequestBuilder class as a superclass MoveRequestBuilderPropertiesToBaseType(generatedCode, new CodeUsing @@ -77,6 +68,20 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance IsExternal = true, } }, addCurrentTypeAsGenericTypeParameter: true); + RemoveRequestConfigurationClasses(generatedCode, + new CodeUsing + { + Name = "RequestConfiguration", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }, new CodeType + { + Name = "DefaultQueryParameters", + IsExternal = true, + }); AddDefaultImports(generatedCode, defaultUsingEvaluators); AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); @@ -220,4 +225,34 @@ public static IEnumerable codeTypeFilter(IEnumerable return usingsToAdd.Except(nestedTypes); } + private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "getQueryParameters") + { + if (currentElement is CodeClass currentClass && + currentClass.IsOfKind(CodeClassKind.QueryParameters)) + { + currentClass.StartBlock.AddImplements(new CodeType + { + IsExternal = true, + Name = "AbstractQueryParameters" + }); + currentClass.AddMethod(new CodeMethod + { + Name = methodName, + Access = AccessModifier.Public, + ReturnType = new CodeType + { + Name = "Map", + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + Kind = CodeMethodKind.QueryParametersMapper, + Documentation = new() + { + DescriptionTemplate = "Extracts the query parameters into a map for the URI template parsing.", + }, + }); + } + CrawlTree(currentElement, x => AddQueryParameterExtractorMethod(x, methodName)); + } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 9b3a12ac3f..e51f8ab17b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -38,11 +38,6 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write } } - private bool IsAllCapital(String text) - { - return text.All(c => char.IsUpper(c)); - } - private static readonly Func GetEnumFlag = static idx => (idx == 0 ? 1 : Math.Pow(2, idx)).ToString(CultureInfo.InvariantCulture); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 9546959521..64701ff635 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -4,6 +4,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.OrderComparers; +using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Extensions; namespace Kiota.Builder.Writers.Dart; @@ -433,8 +434,11 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req var operationName = codeElement.HttpMethod.ToString(); writer.WriteLine($"var {RequestInfoVarName} = RequestInformation(httpMethod : HttpMethod.{operationName?.ToLowerInvariant()}, {currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate)?.Name} : {GetPropertyCall(urlTemplateProperty, "string.Empty")}, {currentClass.GetPropertyOfKind(CodePropertyKind.PathParameters)?.Name} : {GetPropertyCall(urlTemplateParamsProperty, "string.Empty")});"); - if (requestParams.requestConfiguration != null) - writer.WriteLine($"{RequestInfoVarName}.configure({requestParams.requestConfiguration.Name});"); + if (requestParams.requestConfiguration != null && requestParams.requestConfiguration.Type is CodeType paramType) + { + var parameterClassName = paramType.GenericTypeParameterValues.First().Name.ToFirstCharacterUpperCase(); + writer.WriteLine($"{RequestInfoVarName}.configure<{parameterClassName}>({requestParams.requestConfiguration.Name}, () => {parameterClassName}());"); + } if (codeElement.ShouldAddAcceptHeader) writer.WriteLine($"{RequestInfoVarName}.headers.put(\"Accept\", \"{codeElement.AcceptHeaderValue}\");"); From e689de90b8d2b024a057e625621c0a84e722f54e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 19 Sep 2024 11:47:24 +0200 Subject: [PATCH 053/194] Move queryparameterclasses --- .../Refiners/DartRefinerFromScratch.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index bb2dca5861..124cb9ae5f 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -55,7 +55,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance static x => $"by{x.ToFirstCharacterUpperCase()}", static x => x.ToFirstCharacterLowerCase(), GenerationLanguage.Dart); - AddQueryParameterExtractorMethod(generatedCode); // This adds the BaseRequestBuilder class as a superclass MoveRequestBuilderPropertiesToBaseType(generatedCode, @@ -82,9 +81,9 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance Name = "DefaultQueryParameters", IsExternal = true, }); - + MoveQueryParameterClass(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); - AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); + AddPropertiesAndMethodTypesImports(generatedCode, true, true, true); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); @@ -252,7 +251,29 @@ private void AddQueryParameterExtractorMethod(CodeElement currentElement, string DescriptionTemplate = "Extracts the query parameters into a map for the URI template parsing.", }, }); + currentClass.AddUsing(new CodeUsing + { + Name = "AbstractQueryParameters", + Declaration = new CodeType { Name = AbstractionsNamespaceName, IsExternal = true }, + }); } CrawlTree(currentElement, x => AddQueryParameterExtractorMethod(x, methodName)); } + + private void MoveQueryParameterClass(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass && + currentClass.IsOfKind(CodeClassKind.RequestBuilder)) + { + var parentNamespace = currentClass.GetImmediateParentOfType(); + var nestedClasses = currentClass.InnerClasses.Where(x => x.IsOfKind(CodeClassKind.QueryParameters)); + foreach (CodeClass nestedClass in nestedClasses) + { + + parentNamespace.AddClass(nestedClass); + currentClass.RemoveChildElementByName(nestedClass.Name); + } + } + CrawlTree(currentElement, x => MoveQueryParameterClass(x)); + } } From 51a45104de6750589a22640ecc855ed3636fcc51 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 19 Sep 2024 13:36:38 +0200 Subject: [PATCH 054/194] Write implementation of getQueryParameters method --- .../Refiners/DartRefinerFromScratch.cs | 1 - .../Writers/Dart/CodeMethodWriter.cs | 20 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 124cb9ae5f..ff34c2bbb2 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -269,7 +269,6 @@ private void MoveQueryParameterClass(CodeElement currentElement) var nestedClasses = currentClass.InnerClasses.Where(x => x.IsOfKind(CodeClassKind.QueryParameters)); foreach (CodeClass nestedClass in nestedClasses) { - parentNamespace.AddClass(nestedClass); currentClass.RemoveChildElementByName(nestedClass.Name); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 64701ff635..8a4ea53030 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -86,6 +86,9 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w case CodeMethodKind.RequestBuilderWithParameters: WriteRequestBuilderBody(parentClass, codeElement, writer); break; + case CodeMethodKind.QueryParametersMapper: + WriteQueryparametersBody(parentClass, codeElement, writer); + break; case CodeMethodKind.Getter: case CodeMethodKind.Setter: throw new InvalidOperationException("getters and setters are automatically added on fields in dotnet"); @@ -111,6 +114,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w break; } } + private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); @@ -609,7 +613,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; - if (code.Kind == CodeMethodKind.Serializer || code.Kind == CodeMethodKind.Deserializer) + if (code.Kind == CodeMethodKind.Serializer || code.Kind == CodeMethodKind.Deserializer || code.Kind == CodeMethodKind.QueryParametersMapper) { writer.WriteLine("@override"); } @@ -665,6 +669,20 @@ private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, } return $"{nullablesegment} {string.Join(" ", signatureSegments[1..])}"; } + + + private void WriteQueryparametersBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) + { + writer.WriteLine("return {"); + writer.IncreaseIndent(); + foreach (CodeProperty property in parentClass.Properties) + { + writer.WriteLine($"\"{property.Name}\" : {property.Name},"); + } + writer.DecreaseIndent(); + writer.WriteLine("};"); + } + private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod method, bool includeNullableRef = false) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; From dabf69e7a75c47a787465ad18cf01e8c8260b733 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 19 Sep 2024 15:14:51 +0200 Subject: [PATCH 055/194] Types for RequestConfiguration generics should also be imported --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index ff34c2bbb2..cf6084d4c2 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -83,7 +83,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance }); MoveQueryParameterClass(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); - AddPropertiesAndMethodTypesImports(generatedCode, true, true, true); + AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); @@ -218,11 +218,11 @@ private static void CorrectImplements(ProprietableBlockDeclaration block) } public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) { - var nestedTypes = usingsToAdd.OfType().Where( - static codeType => codeType.TypeDefinition is CodeClass codeClass - && codeClass.IsOfKind(CodeClassKind.RequestConfiguration)); + var genericParameterTypes = usingsToAdd.OfType().Where( + static codeType => codeType.Parent is CodeParameter parameter + && parameter.IsOfKind(CodeParameterKind.RequestConfiguration)).Select(x => x.GenericTypeParameterValues.First()); - return usingsToAdd.Except(nestedTypes); + return usingsToAdd.Union(genericParameterTypes); } private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "getQueryParameters") { From 2ffeedb88d69b3a4a6c2a6f5fef9f00d1b732729 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 20 Sep 2024 09:08:43 +0200 Subject: [PATCH 056/194] Use Uuids, escape propertynames --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 4 ++++ src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index cf6084d4c2..ed5ae88170 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -39,6 +39,8 @@ public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner SerializationNamespaceName, KiotaBuilder.UntypedNodeName), new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), AbstractionsNamespaceName, MultipartBodyClassName), + new (static x => x is CodeProperty prop && prop.Type.Name.EqualsIgnoreCase("Guid"), + "uuid/uuid", "Uuid"), }; @@ -190,6 +192,8 @@ private static void CorrectPropertyType(CodeProperty currentProperty) else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameter)) { currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + if (currentProperty.Type.Name.Equals("Guid", StringComparison.OrdinalIgnoreCase)) + currentProperty.Type.Name = "Uuid"; } else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) { diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index f6830b1dad..030e735585 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -1,10 +1,12 @@ using System; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; +using Kiota.Builder.Refiners; namespace Kiota.Builder.Writers.Dart; public class CodePropertyWriter : BaseElementWriter { + private DartReservedNamesProvider reservedNamesProvider = new DartReservedNamesProvider(); public CodePropertyWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter writer) { @@ -42,10 +44,15 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ if (!string.IsNullOrEmpty(accessModifierAttribute)) writer.WriteLine(accessModifierAttribute); + var propertyName = codeElement.Name.ToCamelCase(); + if (reservedNamesProvider.ReservedNames.Contains(propertyName)) + { + propertyName += "Escaped"; + } switch (codeElement.Kind) { case CodePropertyKind.RequestBuilder: - writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToCamelCase()} {{"); + writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); conventions.AddRequestBuilderBody(parentClass, propertyType, writer, prefix: "return "); writer.DecreaseIndent(); @@ -54,7 +61,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ case CodePropertyKind.AdditionalData when backingStoreProperty != null: case CodePropertyKind.Custom when backingStoreProperty != null: var backingStoreKey = codeElement.WireName; - writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToCamelCase()} {{"); + writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Get<{propertyType}>(\"{backingStoreKey}\");"); writer.DecreaseIndent(); From e8fdb476fdb271e04e622266144096f238c5628c Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 20 Sep 2024 09:26:06 +0200 Subject: [PATCH 057/194] Compiling requestexecutor for binary data --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 ++- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 8a4ea53030..e2ec7b6fda 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -561,10 +561,11 @@ protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElemen if (isVoid) return "sendNoContent"; else if (isStream || conventions.IsPrimitiveType(returnTypeName) || isEnum) if (returnType.IsCollection) - return $"sendPrimitiveCollectionAsync<{returnTypeName}>"; + return $"sendPrimitiveCollection<{returnTypeName}>"; else return $"sendPrimitive<{returnTypeName}>"; else if (returnType.IsCollection) return $"sendCollection<{returnTypeName}>"; + else if (returnType.Name.EqualsIgnoreCase("binary")) return "sendPrimitiveCollection"; else return $"send<{returnTypeName}>"; } private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index a024688fe7..24a2287f68 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -278,7 +278,7 @@ public override string TranslateType(CodeType type) "string" => "String", "double" or "float" or "decimal" or "int64" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack - "binary" or "base64" or "base64url" => "List", + "binary" or "base64" or "base64url" => "Iterable", "datetimeoffset" => "DateTime", string s when s.Contains("RequestConfiguration", StringComparison.OrdinalIgnoreCase) => "RequestConfiguration", "iparsenode" => "ParseNode", From e45c144cfef81967333c76070566a101f7882f25 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 20 Sep 2024 11:35:21 +0200 Subject: [PATCH 058/194] Added value to generated enums and corrected method call for enum serialization --- .../Refiners/DartRefinerFromScratch.cs | 15 ---------- .../Writers/Dart/CodeEnumWriter.cs | 28 +++++++++++-------- .../Writers/Dart/CodeMethodWriter.cs | 7 ++++- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index ed5ae88170..dbc3e82872 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -137,21 +137,6 @@ private static void CorrectCommonNames(CodeElement currentElement) { i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); } - else if (currentElement is CodeEnum e) - { - foreach (var option in e.Options) - { - if (!string.IsNullOrEmpty(option.Name) && Char.IsLower(option.Name[0])) - { - if (string.IsNullOrEmpty(option.SerializationName)) - { - option.SerializationName = option.Name; - } - option.Name = option.Name.ToFirstCharacterUpperCase(); - } - } - } - CrawlTree(currentElement, element => CorrectCommonNames(element)); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index e51f8ab17b..00c9968a47 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -18,26 +18,30 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write if (!codeElement.Options.Any()) return; DartReservedNamesProvider reservedNamesProvider = new DartReservedNamesProvider(); + var enumName = codeElement.Name.ToFirstCharacterUpperCase(); conventions.WriteShortDescription(codeElement, writer); - if (codeElement.Flags) - writer.WriteLine("[Flags]"); conventions.WriteDeprecationAttribute(codeElement, writer); - writer.StartBlock($"enum {codeElement.Name.ToFirstCharacterUpperCase()} {{"); - var idx = 0; + writer.StartBlock($"enum {enumName} {{"); + var lastOption = codeElement.Options.Last(); + foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); - var value = option.Name.ToLowerInvariant().ToCamelCase('_'); - if (reservedNamesProvider.ReservedNames.Contains(value)) + var correctedName = getCorrectedName(option.Name); + if (reservedNamesProvider.ReservedNames.Contains(correctedName)) { - value = value.ToUpperInvariant(); + correctedName = correctedName.ToUpperInvariant(); } - writer.WriteLine($"{value}{(codeElement.Flags ? " = " + GetEnumFlag(idx) : string.Empty)},"); - - idx++; + writer.WriteLine($"{correctedName}(\"{option.Name}\"){(option == lastOption ? ";" : ",")}"); } + writer.WriteLine($"const {enumName}(this.value);"); + writer.WriteLine("final String value;"); } - private static readonly Func GetEnumFlag = static idx => - (idx == 0 ? 1 : Math.Pow(2, idx)).ToString(CultureInfo.InvariantCulture); + private string getCorrectedName(string name) + { + if (name.Contains('_', StringComparison.Ordinal)) + return name.ToLowerInvariant().ToCamelCase('_'); + return name.All(c => char.IsUpper(c)) ? name.ToLowerInvariant() : name; + } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index e2ec7b6fda..fb6c05cb84 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -488,7 +488,12 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me .OrderBy(static x => x.Name)) { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); - writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterLowerCase()});"); + var secondArgument = ""; + if (otherProp.Type is CodeType currentType && currentType.TypeDefinition is CodeEnum enumType) + { + secondArgument = $", (e) => e?.value"; + } + writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterLowerCase()}{secondArgument});"); } } private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) From 2c9e85ed1435394e20d2e4f6aa50cdd0e6e04de5 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 20 Sep 2024 11:38:44 +0200 Subject: [PATCH 059/194] Booleans are written correctly --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index e2ec7b6fda..45206a0379 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -488,7 +488,8 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me .OrderBy(static x => x.Name)) { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); - writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterLowerCase()});"); + var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; + writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()});"); } } private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) From 0d05268125a7156e4fbe2d3c7e27e2f9f38bc207 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 20 Sep 2024 13:26:22 +0200 Subject: [PATCH 060/194] Imports for discrimiator types work better We do have a spurious unused import but this is way better than missing an import. --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 11d501d491..47ee0dc95f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -65,10 +65,8 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit /// Date: Fri, 20 Sep 2024 13:29:33 +0200 Subject: [PATCH 061/194] deserialization of enum values --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index a012874bd5..8e18e2bcaf 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -378,7 +378,10 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me return $"getCollectionOfObjectValues<{propertyType}>({propertyType}.createFromDiscriminatorValue){collectionMethod}"; } else if (currentType.TypeDefinition is CodeEnum enumType) - return $"getEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>()"; + { + var typeName = enumType.Name.ToFirstCharacterUpperCase(); + return $"getEnumValue<{typeName}>((stringValue) => {typeName}.values.where((enumVal) => enumVal.value == stringValue).firstOrNull)"; + } } return propertyType switch { From c75c2e736ad5676552d86426e157128b97b19899 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 20 Sep 2024 14:39:15 +0200 Subject: [PATCH 062/194] Deserialize collections of enums --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 9 ++++++--- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 8e18e2bcaf..775f4f395c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -371,9 +371,12 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me { var collectionMethod = ""; if (currentType.TypeDefinition == null) - return $"getCollectionOfPrimitiveValues<{propertyType}>(){collectionMethod}"; - else if (currentType.TypeDefinition is CodeEnum) - return $"getCollectionOfEnumValues<{propertyType.TrimEnd('?')}>(){collectionMethod}"; + return $"getCollectionOfPrimitiveValues<{propertyType.TrimEnd(DartConventionService.NullableMarker)}>(){collectionMethod}"; + else if (currentType.TypeDefinition is CodeEnum enumType) + { + var typeName = enumType.Name.ToFirstCharacterUpperCase(); + return $"getCollectionOfEnumValues<{typeName}>((stringValue) => {typeName}.values.where((enumVal) => enumVal.value == stringValue).firstOrNull)"; + } else return $"getCollectionOfObjectValues<{propertyType}>({propertyType}.createFromDiscriminatorValue){collectionMethod}"; } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 24a2287f68..280f86632c 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -206,7 +206,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i return $"Function({collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix})"; } - return $"{collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix}"; + return $"{collectionPrefix}{typeName}{genericParameters}{collectionSuffix}{nullableSuffix}"; } throw new InvalidOperationException($"type of type {code?.GetType()} is unknown"); From 5a2ba18edc4cfa06774648b928400e1c67b7c3f4 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 20 Sep 2024 14:59:44 +0200 Subject: [PATCH 063/194] raw url constructors don't have a body --- .../Writers/Dart/CodeMethodWriter.cs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 8e18e2bcaf..849b17565e 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -34,16 +34,20 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri writer.WriteLine($"if({parameterName} == null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); } HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); - var isConstructor = codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) - { - writer.DecreaseIndent(); - } - else - { - writer.CloseBlock(); + + if (codeElement.IsOfKind(CodeMethodKind.RawUrlConstructor)) { + writer.DecreaseIndent(); + } else { + if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) + { + writer.DecreaseIndent(); + } else { + writer.CloseBlock(); + } + } + } protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter writer, bool doesInherit, CodeClass parentClass, bool isVoid) @@ -644,6 +648,11 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var methodName = GetMethodName(code, parentClass, isConstructor); var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; + + if (code.IsOfKind(CodeMethodKind.RawUrlConstructor)) { + openingBracket = ";"; + } + if (includeNullableReferenceType) { var completeReturnTypeWithNullable = isConstructor || string.IsNullOrEmpty(genericTypeSuffix) ? completeReturnType : $"{completeReturnType[..^2].TrimEnd('?')}?{genericTypeSuffix} "; From f843ad6d21bf7492085d67f7e13e96d8678b425b Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 20 Sep 2024 15:12:34 +0200 Subject: [PATCH 064/194] Change all Guid properties to UuidValues --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 8 +++++--- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index dbc3e82872..f1097992eb 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -6,6 +6,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; +using Kiota.Builder.Writers.Dart; namespace Kiota.Builder.Refiners; public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner @@ -40,7 +41,7 @@ public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), AbstractionsNamespaceName, MultipartBodyClassName), new (static x => x is CodeProperty prop && prop.Type.Name.EqualsIgnoreCase("Guid"), - "uuid/uuid", "Uuid"), + "uuid/uuid", "Uuid", "UuidValue"), }; @@ -177,8 +178,6 @@ private static void CorrectPropertyType(CodeProperty currentProperty) else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameter)) { currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; - if (currentProperty.Type.Name.Equals("Guid", StringComparison.OrdinalIgnoreCase)) - currentProperty.Type.Name = "Uuid"; } else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) { @@ -196,6 +195,9 @@ private static void CorrectPropertyType(CodeProperty currentProperty) if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) currentProperty.DefaultValue = "Map()"; } + if (currentProperty.Type.Name.Equals("Guid", StringComparison.OrdinalIgnoreCase)) + currentProperty.Type.Name = "UuidValue"; + currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); // TODO KEES // CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 6c84e4a592..235540e8e7 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -392,6 +392,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me } return propertyType switch { + "UuidValue" => "getGuidValue()", "byte[]" => "getByteArrayValue()", _ when conventions.IsPrimitiveType(propertyType) => $"get{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value()", _ => $"getObjectValue<{propertyType.ToFirstCharacterUpperCase()}>({propertyType}.createFromDiscriminatorValue)", From f35c8b28321d8cd647f0c7861825f2485aa2137e Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 23 Sep 2024 07:21:41 +0200 Subject: [PATCH 065/194] Bringing down compiler warnings to 218 These are the number of warnings in the generated code. --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 2 +- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index dbc3e82872..dfd2bf2441 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -183,7 +183,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) { currentProperty.Type.Name = "Map"; - currentProperty.DefaultValue = "Map()"; + currentProperty.DefaultValue = "{}"; } else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 6c84e4a592..62a4aca04c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -36,6 +36,9 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); var isConstructor = codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); + if (isConstructor) { + Console.WriteLine(codeElement.Name + ":" + codeElement.Kind + ":" + codeElement.Parent.Name); + } if (codeElement.IsOfKind(CodeMethodKind.RawUrlConstructor)) { writer.DecreaseIndent(); } else { From c200a877010c750c92cb274e36d48edec9354612 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 23 Sep 2024 07:52:11 +0200 Subject: [PATCH 066/194] Corrected names containing an underscore. This corrects the class names for additional objects. Number of compiler warnings: 165 --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 4b2cea5093..42e5e657f8 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -84,6 +84,18 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance Name = "DefaultQueryParameters", IsExternal = true, }); + var reservedNamesProvider = new DartReservedNamesProvider(); + CorrectNames(generatedCode, s => + { + if (s.Contains('_', StringComparison.OrdinalIgnoreCase) && + s.ToPascalCase(UnderscoreArray) is string refinedName && + !reservedNamesProvider.ReservedNames.Contains(s) && + !reservedNamesProvider.ReservedNames.Contains(refinedName)) + return refinedName; + else + return s; + }); + MoveQueryParameterClass(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); From 2bce885a0d7a7f35007c7cff41b0ccd57f0148cd Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 23 Sep 2024 09:26:16 +0200 Subject: [PATCH 067/194] Almost all consructors are generated properly Only 18 compiler warnings left in our example. --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 4f366368a6..c739aff15f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -4,8 +4,6 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.OrderComparers; -using Microsoft.OpenApi.Expressions; -using Microsoft.OpenApi.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeMethodWriter : BaseElementWriter @@ -36,10 +34,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); var isConstructor = codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - if (isConstructor) { - Console.WriteLine(codeElement.Name + ":" + codeElement.Kind + ":" + codeElement.Parent.Name); - } - if (codeElement.IsOfKind(CodeMethodKind.RawUrlConstructor)) { + if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !codeElement.IsOfKind(CodeMethodKind.ClientConstructor)) { + // Constuctors (except for ClientConstructor) don't need a body. writer.DecreaseIndent(); } else { if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) @@ -48,7 +44,6 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri } else { writer.CloseBlock(); } - } } @@ -98,7 +93,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w break; case CodeMethodKind.Getter: case CodeMethodKind.Setter: - throw new InvalidOperationException("getters and setters are automatically added on fields in dotnet"); + throw new InvalidOperationException("getters and setters are automatically added on fields in Dart"); case CodeMethodKind.RequestBuilderBackwardCompatibility: throw new InvalidOperationException("RequestBuilderBackwardCompatibility is not supported as the request builders are implemented by properties."); case CodeMethodKind.ErrorMessageOverride: @@ -656,7 +651,8 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; - if (code.IsOfKind(CodeMethodKind.RawUrlConstructor)) { + // Constuctors (except for ClientConstructor) don't need a body but a closing statement + if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !code.IsOfKind(CodeMethodKind.ClientConstructor)) { openingBracket = ";"; } From 792e1c81ccb62e2fa477eb609f5a536b1cdbd183 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 23 Sep 2024 12:56:58 +0200 Subject: [PATCH 068/194] Still bringing down the number of compiler warnings Currently we are stuck at 8 compiler warnings. --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 2 +- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 42e5e657f8..b55fd0848d 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -205,7 +205,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) currentProperty.Type.IsNullable = true; currentProperty.Type.Name = "Map"; if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) - currentProperty.DefaultValue = "Map()"; + currentProperty.DefaultValue = "{}"; } if (currentProperty.Type.Name.Equals("Guid", StringComparison.OrdinalIgnoreCase)) currentProperty.Type.Name = "UuidValue"; diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 00c9968a47..db53e15c4a 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.Linq; using Kiota.Builder.CodeDOM; @@ -30,7 +29,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write var correctedName = getCorrectedName(option.Name); if (reservedNamesProvider.ReservedNames.Contains(correctedName)) { - correctedName = correctedName.ToUpperInvariant(); + correctedName += "Escaped"; } writer.WriteLine($"{correctedName}(\"{option.Name}\"){(option == lastOption ? ";" : ",")}"); } @@ -42,6 +41,6 @@ private string getCorrectedName(string name) { if (name.Contains('_', StringComparison.Ordinal)) return name.ToLowerInvariant().ToCamelCase('_'); - return name.All(c => char.IsUpper(c)) ? name.ToLowerInvariant() : name; + return name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name; } } From 2d15035fe1227003b20baf3bd537e293c144f16b Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 23 Sep 2024 13:04:26 +0200 Subject: [PATCH 069/194] Adding ASync to async getters. --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index b55fd0848d..4b9c45b284 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -102,6 +102,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); + AddAsyncSuffix(generatedCode); + ReplaceDefaultSerializationModules( generatedCode, @@ -227,6 +229,12 @@ public static IEnumerable codeTypeFilter(IEnumerable return usingsToAdd.Union(genericParameterTypes); } + protected static void AddAsyncSuffix(CodeElement currentElement) + { + if (currentElement is CodeMethod currentMethod && currentMethod.IsAsync) + currentMethod.Name += "Async"; + CrawlTree(currentElement, AddAsyncSuffix); + } private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "getQueryParameters") { if (currentElement is CodeClass currentClass && From aa96c8cb2702262652cb358271377316987be184 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 24 Sep 2024 06:38:16 +0200 Subject: [PATCH 070/194] Adding code from original DartRefiner --- .../Refiners/DartRefinerFromScratch.cs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 4b9c45b284..ed867c35ff 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -132,6 +132,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); + DisambiguatePropertiesWithClassNames(generatedCode); }, cancellationToken); } @@ -178,7 +179,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) if (currentProperty.IsOfKind(CodePropertyKind.Options)) currentProperty.DefaultValue = "List()"; else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) - currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; else if (currentProperty.IsOfKind(CodePropertyKind.RequestAdapter)) { currentProperty.Type.Name = "RequestAdapter"; @@ -191,7 +192,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) } else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameter)) { - currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; } else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) { @@ -213,8 +214,6 @@ private static void CorrectPropertyType(CodeProperty currentProperty) currentProperty.Type.Name = "UuidValue"; currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); - // TODO KEES - // CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); } private static void CorrectImplements(ProprietableBlockDeclaration block) @@ -286,4 +285,23 @@ private void MoveQueryParameterClass(CodeElement currentElement) } CrawlTree(currentElement, x => MoveQueryParameterClass(x)); } + + protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass) + { + var sameNameProperty = currentClass.Properties + .FirstOrDefault(x => x.Name.Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase)); + if (sameNameProperty != null) + { + currentClass.RemoveChildElement(sameNameProperty); + if (string.IsNullOrEmpty(sameNameProperty.SerializationName)) + sameNameProperty.SerializationName = sameNameProperty.Name; + sameNameProperty.Name = $"{sameNameProperty.Name}Prop"; + currentClass.AddProperty(sameNameProperty); + } + } + CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); + } + } From fa9c2b0686452542b28c7dc7c06cc83491d4613e Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 24 Sep 2024 09:56:29 +0200 Subject: [PATCH 071/194] getAsync now has on optional positional parameter This allows you to write cleaner client code. --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index c739aff15f..8bf986ee6f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -656,6 +656,8 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua openingBracket = ";"; } + var optionalParamOpen = methodName.EqualsIgnoreCase("getAsync") ? "[" : ""; + var optionalParamClose = methodName.EqualsIgnoreCase("getAsync") ? "]" : ""; if (includeNullableReferenceType) { var completeReturnTypeWithNullable = isConstructor || string.IsNullOrEmpty(genericTypeSuffix) ? completeReturnType : $"{completeReturnType[..^2].TrimEnd('?')}?{genericTypeSuffix} "; @@ -664,11 +666,11 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua GetParameterSignatureWithNullableRefType(p, code) : conventions.GetParameterSignature(p, code)) .ToList()); - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}{async} {{"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({optionalParamOpen}{nullableParameters}{optionalParamClose}){baseSuffix}{async} {{"); } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}{async} {openingBracket}"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({optionalParamOpen}{parameters}{optionalParamClose}){baseSuffix}{async} {openingBracket}"); } } From 74a74be86d11f6026ab22ecb691b601be168518e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 24 Sep 2024 11:31:02 +0200 Subject: [PATCH 072/194] Integers should not become doubles --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 280f86632c..16e7f2d7be 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -273,10 +273,10 @@ public override string TranslateType(CodeType type) ArgumentNullException.ThrowIfNull(type); return type.Name.ToLowerInvariant() switch { - "integer" or "sbyte" or "byte" => "int", + "integer" or "sbyte" or "byte" or "int64" => "int", "boolean" => "bool", "string" => "String", - "double" or "float" or "decimal" or "int64" => "double", + "double" or "float" or "decimal" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "Iterable", "datetimeoffset" => "DateTime", From e40ad0b3c973bafb96ea7df4cb46eb7bb7ea0f0d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 24 Sep 2024 15:49:54 +0200 Subject: [PATCH 073/194] Error classes should extend ApiException --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index ed867c35ff..4e3f2334f3 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -130,6 +130,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance [$"{AbstractionsNamespaceName}.ParseNodeFactoryRegistry"]); cancellationToken.ThrowIfCancellationRequested(); + AddParentClassToErrorClasses( + generatedCode, + "ApiException", + AbstractionsNamespaceName + ); RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); DisambiguatePropertiesWithClassNames(generatedCode); From 82bd98c110c873fd295708dd624dd3da1764236b Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 08:49:37 +0200 Subject: [PATCH 074/194] add error message --- .../Refiners/DartRefinerFromScratch.cs | 5 ++++ .../Writers/Dart/CodeMethodWriter.cs | 23 +++++++++++-------- .../Writers/Dart/CodePropertyWriter.cs | 11 +-------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 4e3f2334f3..01c6dd2a6c 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -135,6 +135,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "ApiException", AbstractionsNamespaceName ); + AddPrimaryErrorMessage(generatedCode, + "message", + () => new CodeType { Name = "string", IsNullable = true, IsExternal = false }, + true + ); RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); DisambiguatePropertiesWithClassNames(generatedCode); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 8bf986ee6f..e83b9ceebf 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -34,14 +34,19 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); var isConstructor = codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !codeElement.IsOfKind(CodeMethodKind.ClientConstructor)) { + if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !codeElement.IsOfKind(CodeMethodKind.ClientConstructor)) + { // Constuctors (except for ClientConstructor) don't need a body. - writer.DecreaseIndent(); - } else { + writer.DecreaseIndent(); + } + else + { if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) { writer.DecreaseIndent(); - } else { + } + else + { writer.CloseBlock(); } } @@ -347,8 +352,7 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La private const string DeserializerVarName = "deserializerMap"; private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { - - var fieldToSerialize = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom).ToArray(); + var fieldToSerialize = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.ErrorMessageOverride).ToArray(); writer.WriteLine($"{DeserializerReturnType} {DeserializerVarName} = " + (shouldHide ? "super.getFieldDeserializers();" : "{};")); if (fieldToSerialize.Length != 0) @@ -492,7 +496,7 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me if (shouldHide) writer.WriteLine("super.serialize(writer);"); foreach (var otherProp in parentClass - .GetPropertiesOfKind(CodePropertyKind.Custom) + .GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.ErrorMessageOverride) .Where(static x => !x.ExistsInBaseType && !x.ReadOnly) .OrderBy(static x => x.Name)) { @@ -652,9 +656,10 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; // Constuctors (except for ClientConstructor) don't need a body but a closing statement - if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !code.IsOfKind(CodeMethodKind.ClientConstructor)) { + if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !code.IsOfKind(CodeMethodKind.ClientConstructor)) + { openingBracket = ";"; - } + } var optionalParamOpen = methodName.EqualsIgnoreCase("getAsync") ? "[" : ""; var optionalParamClose = methodName.EqualsIgnoreCase("getAsync") ? "]" : ""; diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 030e735585..1287415750 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -17,7 +17,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w var isNullableReferenceType = !propertyType.EndsWith('?') && codeElement.IsOfKind( CodePropertyKind.Custom, - CodePropertyKind.QueryParameter);// Other property types are appropriately constructor initialized + CodePropertyKind.QueryParameter, CodePropertyKind.ErrorMessageOverride); conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); if (isNullableReferenceType) @@ -75,15 +75,6 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ break; case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition: writer.WriteLine("@override"); - - if (parentClass.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterUpperCase(), - static x => x.Name.ToFirstCharacterUpperCase(), "?.") is { } primaryMessageCodePath && - !string.IsNullOrEmpty(primaryMessageCodePath)) - defaultValue = $"=> {primaryMessageCodePath} ?? \"\";"; - else - defaultValue = "=> super.Message;"; - - getterModifier = "get "; goto default; case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped: writer.WriteLine($"/// @QueryParameter(\"{codeElement.SerializationName}\")"); From f5fad2fe20b35766fcc4f95539708365c0b93085 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 09:49:08 +0200 Subject: [PATCH 075/194] deduplicate error mappings --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 01c6dd2a6c..ff60f948f2 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -140,6 +140,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance () => new CodeType { Name = "string", IsNullable = true, IsExternal = false }, true ); + DeduplicateErrorMappings(generatedCode); RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); DisambiguatePropertiesWithClassNames(generatedCode); From c59695ad3a73222ba3cc13be20fd5e59d6e284c8 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 09:58:21 +0200 Subject: [PATCH 076/194] Remove unnecessary methods --- src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index ff60f948f2..7e9e184fee 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -144,7 +144,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance RemoveCancellationParameter(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); DisambiguatePropertiesWithClassNames(generatedCode); - + RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); }, cancellationToken); } From 13d05dee7355f08eacd7e7c2084b32e5d8b188cd Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 10:49:43 +0200 Subject: [PATCH 077/194] Add the clone method to the refiner --- .../Refiners/DartRefinerFromScratch.cs | 26 +++++++++++++++++++ .../Writers/Dart/CodeBlockEndWriter.cs | 16 ------------ .../Writers/Dart/CodeMethodWriter.cs | 15 +++++++++-- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 7e9e184fee..5803317f90 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -145,6 +145,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); DisambiguatePropertiesWithClassNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); + AddCloneMethodToRequestBuilders(generatedCode); }, cancellationToken); } @@ -314,5 +315,30 @@ protected static void DisambiguatePropertiesWithClassNames(CodeElement currentEl } CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); } + private void AddCloneMethodToRequestBuilders(CodeElement currentElement, string methodName = "clone") + { + if (currentElement is CodeClass currentClass && + currentClass.IsOfKind(CodeClassKind.RequestBuilder)) + { + currentClass.AddMethod(new CodeMethod + { + Name = methodName, + Access = AccessModifier.Public, + ReturnType = new CodeType + { + Name = currentClass.Name, + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + Kind = CodeMethodKind.Custom, + Documentation = new() + { + DescriptionTemplate = "Clones the requestbuilder.", + }, + }); + } + CrawlTree(currentElement, x => AddCloneMethodToRequestBuilders(x, methodName)); + } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index 831464d9d1..2acb33404d 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -11,22 +11,6 @@ public CodeBlockEndWriter(DartConventionService conventionService) : base(conven public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); - overrideCloneMethod(codeElement, writer); writer.CloseBlock(); } - - private void overrideCloneMethod(BlockEnd codeElement, LanguageWriter writer) - { - if (codeElement?.Parent is CodeClass classElement && classElement.Kind is CodeClassKind.RequestBuilder) - { - writer.WriteLine("@override"); - writer.WriteLine($"{classElement.Name.ToFirstCharacterUpperCase()} clone() {{"); - writer.IncreaseIndent(); - var constructor = classElement.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); - String? argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()).Select(static x => x.Name).Aggregate(static (x, y) => $"{x}, {y}"); - writer.WriteLine($"return {classElement.Name.ToFirstCharacterUpperCase()}({argumentList});"); - writer.DecreaseIndent(); - writer.WriteLine("}"); - } - } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index e83b9ceebf..cef4cd0579 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -114,6 +114,9 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w case CodeMethodKind.Factory: WriteFactoryMethodBody(codeElement, parentClass, writer); break; + case CodeMethodKind.Custom: + WriteCustomMethodBody(codeElement, parentClass, writer); + break; case CodeMethodKind.ComposedTypeMarker: throw new InvalidOperationException("ComposedTypeMarker is not required as interface is explicitly implemented."); default: @@ -121,7 +124,6 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w break; } } - private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); @@ -633,7 +635,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; - if (code.Kind == CodeMethodKind.Serializer || code.Kind == CodeMethodKind.Deserializer || code.Kind == CodeMethodKind.QueryParametersMapper) + if (code.IsOfKind(CodeMethodKind.Serializer, CodeMethodKind.Deserializer, CodeMethodKind.QueryParametersMapper) || (code.IsOfKind(CodeMethodKind.Custom) && code.Name.Equals("clone", StringComparison.OrdinalIgnoreCase))) { writer.WriteLine("@override"); } @@ -737,4 +739,13 @@ _ when conventions.IsPrimitiveType(propertyType) => $"write{propertyType.TrimEnd _ => $"writeObjectValue<{propertyType.ToFirstCharacterUpperCase()}{(includeNullableRef ? "?" : "")}>", }; } + private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) + { + if (codeElement.Name.Equals("clone", StringComparison.OrdinalIgnoreCase)) + { + var constructor = parentClass.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); + String? argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()).Select(static x => x.Name).Aggregate(static (x, y) => $"{x}, {y}"); + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({argumentList});"); + } + } } From 05a843aeb546dfaa6076fdbddadca4542fb7a902 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 11:18:10 +0200 Subject: [PATCH 078/194] Don't snakecase whole path, filename is already snakecased --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 47ee0dc95f..fcfc08eb7b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -46,7 +46,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit .Select(static x => x.Item3) .Distinct() .Order(StringComparer.OrdinalIgnoreCase)) - writer.WriteLine($"import '{relativePath.ToSnakeCase()}.dart';"); + writer.WriteLine($"import '{relativePath}.dart';"); writer.WriteLine(); @@ -66,7 +66,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit void addImportsForDiscriminatorTypes(ClassDeclaration classDeclaration) { - var parent = classDeclaration.Parent as CodeClass; + var parent = classDeclaration.Parent as CodeClass; var methods = parent!.GetMethodsOffKind(CodeMethodKind.Factory); var method = methods?.FirstOrDefault(); if (method != null && method.Parent is CodeElement codeElement && method.Parent is IDiscriminatorInformationHolder) From fbe5927f490c1d672d417e9034e592841e2c94ae Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 13:31:38 +0200 Subject: [PATCH 079/194] Escape dollar sign in default value urltemplate --- .../Refiners/DartRefinerFromScratch.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 5803317f90..f52ae52075 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -146,6 +146,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance DisambiguatePropertiesWithClassNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); AddCloneMethodToRequestBuilders(generatedCode); + escapeUrlTemplates(generatedCode); }, cancellationToken); } @@ -341,4 +342,17 @@ private void AddCloneMethodToRequestBuilders(CodeElement currentElement, string } CrawlTree(currentElement, x => AddCloneMethodToRequestBuilders(x, methodName)); } + + private void escapeUrlTemplates(CodeElement currentElement) + { + if (currentElement is CodeProperty property && + property.IsOfKind(CodePropertyKind.UrlTemplate)) + { + if (property.DefaultValue.Contains('$', StringComparison.Ordinal)) + { + property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); + } + } + CrawlTree(currentElement, escapeUrlTemplates); + } } From 76a51bdb123510782e3447b26b912e69c97b3531 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 25 Sep 2024 15:40:29 +0200 Subject: [PATCH 080/194] Correct (de)serialization of iterable int --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index cef4cd0579..95530ce55a 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -396,6 +396,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me } return propertyType switch { + "Iterable" => "getCollectionOfPrimitiveValues()", "UuidValue" => "getGuidValue()", "byte[]" => "getByteArrayValue()", _ when conventions.IsPrimitiveType(propertyType) => $"get{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value()", @@ -735,6 +736,7 @@ private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod meth { "byte[]" => "writeByteArrayValue", "String" => "writeStringValue", + "Iterable" => "writeCollectionOfPrimitiveValues", _ when conventions.IsPrimitiveType(propertyType) => $"write{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value", _ => $"writeObjectValue<{propertyType.ToFirstCharacterUpperCase()}{(includeNullableRef ? "?" : "")}>", }; From 4eb7e5400d91422a1fefec7ee97ea2418184a428 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 26 Sep 2024 10:35:15 +0200 Subject: [PATCH 081/194] Use existing method for adding imports --- .../Refiners/DartRefinerFromScratch.cs | 2 +- .../Dart/CodeClassDeclarationWriter.cs | 26 ------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index f52ae52075..9407ec73a6 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -103,7 +103,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); AddAsyncSuffix(generatedCode); - + AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); ReplaceDefaultSerializationModules( generatedCode, diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index fcfc08eb7b..353c585a7d 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -19,8 +19,6 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); - addImportsForDiscriminatorTypes(codeElement); - var currentNamespace = codeElement.GetImmediateParentOfType(); var relativeImportManager = new RelativeImportManager( @@ -60,28 +58,4 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()}{derivation}{implements} {{"); } - /// - /// Dart needs import statements for classes that are in the same folder. - /// Date: Mon, 30 Sep 2024 15:36:17 +0200 Subject: [PATCH 082/194] Escape dollar sign in more string values --- .../Refiners/DartRefinerFromScratch.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 9407ec73a6..7064a03884 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -146,7 +146,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance DisambiguatePropertiesWithClassNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); AddCloneMethodToRequestBuilders(generatedCode); - escapeUrlTemplates(generatedCode); + escapeStringValues(generatedCode); }, cancellationToken); } @@ -343,7 +343,7 @@ private void AddCloneMethodToRequestBuilders(CodeElement currentElement, string CrawlTree(currentElement, x => AddCloneMethodToRequestBuilders(x, methodName)); } - private void escapeUrlTemplates(CodeElement currentElement) + private void escapeStringValues(CodeElement currentElement) { if (currentElement is CodeProperty property && property.IsOfKind(CodePropertyKind.UrlTemplate)) @@ -353,6 +353,13 @@ private void escapeUrlTemplates(CodeElement currentElement) property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); } } - CrawlTree(currentElement, escapeUrlTemplates); + else if (currentElement is CodeProperty prop) + { + if (!String.IsNullOrEmpty(prop.SerializationName) && prop.SerializationName.Contains('$', StringComparison.Ordinal)) + { + prop.SerializationName = prop.SerializationName.Replace("$", "\\$", StringComparison.Ordinal); + } + } + CrawlTree(currentElement, escapeStringValues); } } From 6d1441c811e788b8621181981fb07b90acd6281c Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 3 Oct 2024 15:17:33 +0200 Subject: [PATCH 083/194] improved method generation, better handling of nullable/optional parameters --- .../Refiners/DartRefinerFromScratch.cs | 10 ++++-- .../Writers/Dart/CodeMethodWriter.cs | 31 ++++++++++++------- .../Writers/Dart/DartConventionService.cs | 19 +++++++----- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 7064a03884..32aeabbe9e 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -146,7 +146,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance DisambiguatePropertiesWithClassNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); AddCloneMethodToRequestBuilders(generatedCode); - escapeStringValues(generatedCode); + EscapeStringValues(generatedCode); }, cancellationToken); } @@ -166,6 +166,10 @@ private static void CorrectCommonNames(CodeElement currentElement) { i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); } + else if (currentElement.Name.Equals("clone", StringComparison.Ordinal) && currentElement is not CodeMethod && currentElement.Parent is CodeClass parentClass2) + { + parentClass2.RenameChildElement(currentElement.Name, "cloneEscaped"); + } CrawlTree(currentElement, element => CorrectCommonNames(element)); } @@ -343,7 +347,7 @@ private void AddCloneMethodToRequestBuilders(CodeElement currentElement, string CrawlTree(currentElement, x => AddCloneMethodToRequestBuilders(x, methodName)); } - private void escapeStringValues(CodeElement currentElement) + private void EscapeStringValues(CodeElement currentElement) { if (currentElement is CodeProperty property && property.IsOfKind(CodePropertyKind.UrlTemplate)) @@ -360,6 +364,6 @@ private void escapeStringValues(CodeElement currentElement) prop.SerializationName = prop.SerializationName.Replace("$", "\\$", StringComparison.Ordinal); } } - CrawlTree(currentElement, escapeStringValues); + CrawlTree(currentElement, EscapeStringValues); } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 95530ce55a..c2e2b3f0e0 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -25,18 +25,12 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri WriteMethodDocumentation(codeElement, writer); WriteMethodPrototype(codeElement, parentClass, writer, returnType, inherits, isVoid); writer.IncreaseIndent(); - foreach (var parameter in codeElement.Parameters.Where(static x => !x.Optional && !x.IsOfKind(CodeParameterKind.RequestAdapter, CodeParameterKind.PathParameters, CodeParameterKind.RawUrl)).OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) - { - var parameterName = parameter.Name.ToFirstCharacterLowerCase(); - if (nameof(String).Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase) && parameter.Type.CollectionKind == CodeTypeBase.CodeTypeCollectionKind.None) - writer.WriteLine($"if({parameterName} == null || {parameterName}.isEmpty) throw ArgumentError.notNull({parameterName});"); - } + HandleMethodKind(codeElement, writer, inherits, parentClass, isVoid); var isConstructor = codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); - if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !codeElement.IsOfKind(CodeMethodKind.ClientConstructor)) + if (HasEmptyConstructorBody(codeElement, parentClass, isConstructor)) { - // Constuctors (except for ClientConstructor) don't need a body. writer.DecreaseIndent(); } else @@ -53,6 +47,16 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri } + private static bool HasEmptyConstructorBody(CodeMethod codeElement, CodeClass parentClass, bool isConstructor) + { + if (parentClass.IsOfKind(CodeClassKind.Model) && codeElement.IsOfKind(CodeMethodKind.Constructor)) + { + return !parentClass.Properties.Where(prop => !string.IsNullOrEmpty(prop.DefaultValue)).Any(); + } + var hasBody = codeElement.Parameters.Where(p => !p.IsOfKind(CodeParameterKind.RequestAdapter) && !p.IsOfKind(CodeParameterKind.PathParameters)).Any(); + return isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !codeElement.IsOfKind(CodeMethodKind.ClientConstructor) && (!hasBody || codeElement.IsOfKind(CodeMethodKind.RawUrlConstructor)); + } + protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter writer, bool doesInherit, CodeClass parentClass, bool isVoid) { ArgumentNullException.ThrowIfNull(codeElement); @@ -64,6 +68,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w var requestConfig = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration); var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType); var requestParams = new RequestParams(requestBodyParam, requestConfig, requestContentType); + switch (codeElement.Kind) { case CodeMethodKind.Serializer: @@ -292,7 +297,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho conventions.AddParametersAssignment(writer, pathParametersParam.Type, pathParametersParam.Name.ToFirstCharacterLowerCase(), - pathParametersProp.Name.ToFirstCharacterUpperCase(), + pathParametersProp.Name.ToFirstCharacterLowerCase(), currentMethod.Parameters .Where(static x => x.IsOfKind(CodeParameterKind.Path)) .Select(static x => (x.Type, string.IsNullOrEmpty(x.SerializationName) ? x.Name : x.SerializationName, x.Name.ToFirstCharacterLowerCase())) @@ -659,7 +664,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; // Constuctors (except for ClientConstructor) don't need a body but a closing statement - if (isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !code.IsOfKind(CodeMethodKind.ClientConstructor)) + if (HasEmptyConstructorBody(code, parentClass, isConstructor)) { openingBracket = ";"; } @@ -746,7 +751,11 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass if (codeElement.Name.Equals("clone", StringComparison.OrdinalIgnoreCase)) { var constructor = parentClass.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); - String? argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()).Select(static x => x.Name).Aggregate(static (x, y) => $"{x}, {y}"); + String? argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()) + .Select(static x => x.Type.Parent is CodeParameter param && param.IsOfKind(CodeParameterKind.RequestAdapter, CodeParameterKind.PathParameters) + ? x.Name : + x.Optional ? "null" : x.DefaultValue) + .Aggregate(static (x, y) => $"{x}, {y}"); writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({argumentList});"); } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 16e7f2d7be..d1ef782443 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -16,7 +16,7 @@ public class DartConventionService : CommonLanguageConventionService public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; - private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double" }; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string" }; public const char NullableMarker = '?'; public static string NullableMarkerAsString => "?"; public override string ParseNodeInterfaceName => "ParseNode"; @@ -108,7 +108,8 @@ internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, La if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProp) { - var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : $", {string.Join(", ", pathParameters.Select(x => $"{x.Name.ToFirstCharacterLowerCase()}"))}"; + var pathParametersSuffix = !(pathParameters?.Any() ?? false) ? string.Empty : + $", {string.Join(", ", pathParameters.Select(x => x.Optional ? $"{x.Name.ToFirstCharacterLowerCase()} : {x.Name.ToFirstCharacterLowerCase()}" : $"{x.Name.ToFirstCharacterLowerCase()}"))}"; var urlTplRef = string.IsNullOrEmpty(urlTemplateVarName) ? pathParametersProp.Name.ToFirstCharacterLowerCase() : urlTemplateVarName; if (customParameters?.Any() ?? false) { @@ -138,11 +139,11 @@ internal void AddParametersAssignment(LanguageWriter writer, CodeTypeBase pathPa if (ct.CollectionKind == CodeTypeCollectionKind.None && ct.IsNullable) { if (nameof(String).Equals(ct.Name, StringComparison.OrdinalIgnoreCase)) - nullCheck = $"if (!string.IsNullOrWhiteSpace({identName})) "; + nullCheck = $"if ({identName}!= null && {identName}.isNotEmpty) "; else nullCheck = $"if ({identName} != null) "; } - return $"{nullCheck}{varName}.Add(\"{name}\", {identName});"; + return $"{nullCheck}{varName}[\"{name}\"]={identName};"; }).ToArray()); } } @@ -301,14 +302,16 @@ _ when NullableTypes.Contains(typeName) => true, public override string GetParameterSignature(CodeParameter parameter, CodeElement targetElement, LanguageWriter? writer = null) { ArgumentNullException.ThrowIfNull(parameter); - var parameterType = GetTypeString(parameter.Type, targetElement); + var parameterType = GetTypeString(parameter.Type, targetElement, true, parameter.Optional); var defaultValue = parameter switch { - _ when !string.IsNullOrEmpty(parameter.DefaultValue) => $" : {parameter.DefaultValue}", - _ when nameof(String).Equals(parameterType, StringComparison.OrdinalIgnoreCase) && parameter.Optional => " : \"\"", + _ when !string.IsNullOrEmpty(parameter.DefaultValue) => $" = {parameter.DefaultValue}", + _ when nameof(String).Equals(parameterType, StringComparison.OrdinalIgnoreCase) && parameter.Optional => " = \"\"", _ => string.Empty, }; - return $"{GetDeprecationInformation(parameter)}{parameterType} {parameter.Name.ToFirstCharacterLowerCase()}{defaultValue}"; + var open = !string.IsNullOrEmpty(defaultValue) ? "{" : ""; + var close = !string.IsNullOrEmpty(defaultValue) ? "}" : ""; + return $"{GetDeprecationInformation(parameter)}{open}{parameterType} {parameter.Name.ToFirstCharacterLowerCase()}{defaultValue}{close}"; } private static string GetDeprecationInformation(IDeprecableElement element) { From 82459687821f66449f472346bd8bcd384f281948 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 4 Oct 2024 09:22:32 +0200 Subject: [PATCH 084/194] Corrected some types --- .../Refiners/DartRefinerFromScratch.cs | 28 +++++++++++-------- .../Refiners/DartReservedNamesProvider.cs | 4 ++- .../Writers/Dart/CodeMethodWriter.cs | 2 ++ .../Writers/Dart/DartConventionService.cs | 4 +-- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 32aeabbe9e..889cf5e7d1 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -36,12 +36,8 @@ public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner AbstractionsNamespaceName, "ParseNodeHelper"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), AbstractionsNamespaceName, "RequestHeaders"), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase), - SerializationNamespaceName, KiotaBuilder.UntypedNodeName), new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), AbstractionsNamespaceName, MultipartBodyClassName), - new (static x => x is CodeProperty prop && prop.Type.Name.EqualsIgnoreCase("Guid"), - "uuid/uuid", "Uuid", "UuidValue"), }; @@ -53,6 +49,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance cancellationToken.ThrowIfCancellationRequested(); var defaultConfiguration = new GenerationConfiguration(); CorrectCommonNames(generatedCode); + CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); ReplaceIndexersByMethodsWithParameter(generatedCode, false, static x => $"by{x.ToFirstCharacterUpperCase()}", @@ -105,6 +102,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance AddAsyncSuffix(generatedCode); AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); + ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped", new HashSet { typeof(CodeEnumOption) }); ReplaceDefaultSerializationModules( generatedCode, defaultConfiguration.Serializers, @@ -142,7 +140,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance ); DeduplicateErrorMappings(generatedCode); RemoveCancellationParameter(generatedCode); - CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); DisambiguatePropertiesWithClassNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); AddCloneMethodToRequestBuilders(generatedCode); @@ -166,10 +163,6 @@ private static void CorrectCommonNames(CodeElement currentElement) { i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); } - else if (currentElement.Name.Equals("clone", StringComparison.Ordinal) && currentElement is not CodeMethod && currentElement.Parent is CodeClass parentClass2) - { - parentClass2.RenameChildElement(currentElement.Name, "cloneEscaped"); - } CrawlTree(currentElement, element => CorrectCommonNames(element)); } @@ -227,10 +220,8 @@ private static void CorrectPropertyType(CodeProperty currentProperty) if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) currentProperty.DefaultValue = "{}"; } - if (currentProperty.Type.Name.Equals("Guid", StringComparison.OrdinalIgnoreCase)) - currentProperty.Type.Name = "UuidValue"; - currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); + CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); } private static void CorrectImplements(ProprietableBlockDeclaration block) @@ -366,4 +357,17 @@ private void EscapeStringValues(CodeElement currentElement) } CrawlTree(currentElement, EscapeStringValues); } + + private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) { + + {"TimeSpan", ("Duration", null)}, + {"Guid", ("UuidValue", new CodeUsing { + Name = "UuidValue", + Declaration = new CodeType { + Name = "uuid/uuid", + IsExternal = true, + }, + })}, + }; + } diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs index 12f0bb5011..342fe23375 100644 --- a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -72,7 +72,9 @@ public class DartReservedNamesProvider : IReservedNamesProvider "when", "with", "while", - "yield" + "yield", + "BaseRequestBuilder", + "clone" }); public HashSet ReservedNames => _reservedNames.Value; } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index c2e2b3f0e0..eb307587f1 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -737,11 +737,13 @@ private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod meth return $"writeEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>"; } + return propertyType switch { "byte[]" => "writeByteArrayValue", "String" => "writeStringValue", "Iterable" => "writeCollectionOfPrimitiveValues", + "UuidValue" => "writeUuidValue", _ when conventions.IsPrimitiveType(propertyType) => $"write{propertyType.TrimEnd(DartConventionService.NullableMarker).ToFirstCharacterUpperCase()}Value", _ => $"writeObjectValue<{propertyType.ToFirstCharacterUpperCase()}{(includeNullableRef ? "?" : "")}>", }; diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index d1ef782443..774959776d 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -16,7 +16,7 @@ public class DartConventionService : CommonLanguageConventionService public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; - private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string" }; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string", "datetime" }; public const char NullableMarker = '?'; public static string NullableMarkerAsString => "?"; public override string ParseNodeInterfaceName => "ParseNode"; @@ -294,7 +294,7 @@ public bool IsPrimitiveType(string typeName) typeName = typeName.StripArraySuffix().TrimEnd('?').ToLowerInvariant(); return typeName switch { - "string" or "dateonly" or "datetime" => true, + "string" or "dateonly" or "timeonly" or "datetime" or "duration" => true, _ when NullableTypes.Contains(typeName) => true, _ => false, }; From 2e4a471e3c197a4d7036c9c9915dbece0943bd8e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 4 Oct 2024 11:51:06 +0200 Subject: [PATCH 085/194] Fixes some wrong method names, invalid enum values and correct deprecation annotation --- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 15 ++++++++++++++- .../Writers/Dart/CodeMethodWriter.cs | 4 ++-- .../Writers/Dart/DartConventionService.cs | 6 +++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index db53e15c4a..9031cea3bc 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -1,9 +1,11 @@ using System; +using System.Collections.Generic; using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.Refiners; +using Microsoft.OpenApi.Any; namespace Kiota.Builder.Writers.Dart; public class CodeEnumWriter : BaseElementWriter @@ -23,20 +25,31 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.StartBlock($"enum {enumName} {{"); var lastOption = codeElement.Options.Last(); + HashSet usedNames = new HashSet(); foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); var correctedName = getCorrectedName(option.Name); - if (reservedNamesProvider.ReservedNames.Contains(correctedName)) + if (reservedNamesProvider.ReservedNames.Contains(correctedName) || IllegalEnumValue(correctedName)) { correctedName += "Escaped"; } + if (!usedNames.Add(correctedName)) + { + correctedName = option.Name; + usedNames.Add(correctedName); + } writer.WriteLine($"{correctedName}(\"{option.Name}\"){(option == lastOption ? ";" : ",")}"); } writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); } + private bool IllegalEnumValue(string correctedName) + { + return correctedName.EqualsIgnoreCase("string") || correctedName.EqualsIgnoreCase("index"); + } + private string getCorrectedName(string name) { if (name.Contains('_', StringComparison.Ordinal)) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index eb307587f1..c698064572 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -447,7 +447,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re }; writer.WriteLine($"{prefix}await requestAdapter.{GetSendRequestMethodName(isVoid, codeElement, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, {errorMappingVarName});"); if (codeElement.ReturnType.IsCollection) - writer.WriteLine("return collectionResult?.ToList();"); + writer.WriteLine("return collectionResult?.toList();"); } private const string RequestInfoVarName = "requestInfo"; private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams requestParams, CodeClass currentClass, LanguageWriter writer) @@ -479,7 +479,7 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req } else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty) if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase))) - writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); else writer.WriteLine($"{RequestInfoVarName}.setContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 774959776d..7365c1fb1e 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -16,7 +16,7 @@ public class DartConventionService : CommonLanguageConventionService public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; - private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string", "datetime" }; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string", "datetime", "dateonly", "timeonly" }; public const char NullableMarker = '?'; public static string NullableMarkerAsString => "?"; public override string ParseNodeInterfaceName => "ParseNode"; @@ -313,14 +313,14 @@ _ when nameof(String).Equals(parameterType, StringComparison.OrdinalIgnoreCase) var close = !string.IsNullOrEmpty(defaultValue) ? "}" : ""; return $"{GetDeprecationInformation(parameter)}{open}{parameterType} {parameter.Name.ToFirstCharacterLowerCase()}{defaultValue}{close}"; } - private static string GetDeprecationInformation(IDeprecableElement element) + private string GetDeprecationInformation(IDeprecableElement element) { if (element.Deprecation is null || !element.Deprecation.IsDeprecated) return string.Empty; var versionComment = string.IsNullOrEmpty(element.Deprecation.Version) ? string.Empty : $" as of {element.Deprecation.Version}"; var dateComment = element.Deprecation.Date is null ? string.Empty : $" on {element.Deprecation.Date.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; var removalComment = element.Deprecation.RemovalDate is null ? string.Empty : $" and will be removed {element.Deprecation.RemovalDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; - return $"@obsolete(\"{element.Deprecation.GetDescription}{versionComment}{dateComment}{removalComment}\")"; + return $"@Deprecated(\"{element.Deprecation.GetDescription(type => GetTypeString(type, (element as CodeElement)!))}{versionComment}{dateComment}{removalComment}\")"; } internal void WriteDeprecationAttribute(IDeprecableElement element, LanguageWriter writer) { From 5227b3df0c89f82d06513a2062f36c5b81c954f5 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 8 Oct 2024 09:05:16 +0200 Subject: [PATCH 086/194] Use named imports when necessary --- .../Refiners/DartRefinerFromScratch.cs | 30 ++++++++++++++++++- .../Dart/CodeClassDeclarationWriter.cs | 24 +++++++++------ .../Writers/Dart/DartConventionService.cs | 17 +++++++++++ src/Kiota.Builder/Writers/Dart/DartWriter.cs | 2 +- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 889cf5e7d1..2f8a3f8d4b 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -14,6 +14,7 @@ public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner private const string MultipartBodyClassName = "MultipartBody"; private const string AbstractionsNamespaceName = "kiota_abstractions/kiota_abstractions"; private const string SerializationNamespaceName = "kiota_serialization"; + private static readonly CodeUsingDeclarationNameComparer usingComparer = new(); protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), @@ -144,6 +145,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); AddCloneMethodToRequestBuilders(generatedCode); EscapeStringValues(generatedCode); + AliasUsingWithSameSymbol(generatedCode); }, cancellationToken); } @@ -369,5 +371,31 @@ private void EscapeStringValues(CodeElement currentElement) }, })}, }; - + private static void AliasUsingWithSameSymbol(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass && currentClass.StartBlock != null && currentClass.StartBlock.Usings.Any(x => !x.IsExternal)) + { + var duplicatedSymbolsUsings = currentClass.StartBlock.Usings + .Distinct(usingComparer) + .Where(static x => !string.IsNullOrEmpty(x.Declaration?.Name) && x.Declaration.TypeDefinition != null) + .GroupBy(static x => x.Declaration!.Name, StringComparer.OrdinalIgnoreCase) + .Where(x => x.Count() > 1) + .SelectMany(x => x) + .Union(currentClass.StartBlock + .Usings + .Where(x => !x.IsExternal) + .Where(x => x.Declaration! + .Name + .Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase))); + foreach (var usingElement in duplicatedSymbolsUsings) + { + var replacement = string.Join("_", usingElement.Declaration!.TypeDefinition!.GetImmediateParentOfType().Name + .Split(".", StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.ToLowerInvariant()) + .ToArray()); + usingElement.Alias = $"{(string.IsNullOrEmpty(replacement) ? string.Empty : $"{replacement}")}_{usingElement.Declaration!.TypeDefinition!.Name.ToLowerInvariant()}"; + } + } + CrawlTree(currentElement, AliasUsingWithSameSymbol); + } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 353c585a7d..f502cd4520 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -9,7 +9,13 @@ namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter { - public CodeClassDeclarationWriter(DartConventionService conventionService) : base(conventionService) { } + private readonly RelativeImportManager relativeImportManager; + + public CodeClassDeclarationWriter(DartConventionService conventionService, string clientNamespaceName, DartPathSegmenter pathSegmenter) : base(conventionService) + { + ArgumentNullException.ThrowIfNull(pathSegmenter); + relativeImportManager = new RelativeImportManager(clientNamespaceName, '.', pathSegmenter.GetRelativeFileName); + } public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer) { @@ -21,9 +27,6 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit var currentNamespace = codeElement.GetImmediateParentOfType(); - var relativeImportManager = new RelativeImportManager( - "keyhub", '.', (writer.PathSegmenter as DartPathSegmenter)!.GetRelativeFileName); - if (codeElement.Parent?.Parent is CodeNamespace) { codeElement.Usings @@ -39,12 +42,10 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit .Where(static x => !x.IsExternal) .DistinctBy(static x => $"{x.Name}{x.Declaration?.Name}", StringComparer.OrdinalIgnoreCase) .Select(x => x.Declaration?.Name?.StartsWith('.') ?? false ? - (string.Empty, string.Empty, x.Declaration.Name) : + (string.Empty, x.Alias, x.Declaration.Name) : relativeImportManager.GetRelativeImportPathForUsing(x, currentNamespace)) - .Select(static x => x.Item3) - .Distinct() - .Order(StringComparer.OrdinalIgnoreCase)) - writer.WriteLine($"import '{relativePath}.dart';"); + .OrderBy(static x => x.Item3, StringComparer.Ordinal)) + writer.WriteLine($"import '{relativePath.Item3}.dart'{getAlias(relativePath.Item2)};"); writer.WriteLine(); @@ -58,4 +59,9 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()}{derivation}{implements} {{"); } + + private String getAlias(string alias) + { + return string.IsNullOrEmpty(alias) ? string.Empty : $" as {alias}"; + } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 7365c1fb1e..22afd194d0 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -192,6 +192,11 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i if (code is CodeType currentType) { var typeName = TranslateTypeAndAvoidUsingNamespaceSegmentNames(currentType, targetElement); + var alias = GetTypeAlias(currentType, targetElement); + if (!string.IsNullOrEmpty(alias)) + { + typeName = alias + "." + typeName; + } var nullableSuffix = ShouldTypeHaveNullableMarker(code, typeName) && includeNullableInformation ? NullableMarkerAsString : string.Empty; var collectionPrefix = currentType.CollectionKind == CodeTypeCollectionKind.Complex && includeCollectionInformation ? "Iterable<" : string.Empty; if (currentType.CollectionKind == CodeTypeCollectionKind.Array && includeCollectionInformation) @@ -212,6 +217,18 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i throw new InvalidOperationException($"type of type {code?.GetType()} is unknown"); } + + private static string GetTypeAlias(CodeType targetType, CodeElement targetElement) + { + if (targetElement.GetImmediateParentOfType() is IBlock parentBlock && + parentBlock.Usings + .FirstOrDefault(x => !x.IsExternal && + x.Declaration?.TypeDefinition != null && + x.Declaration.TypeDefinition == targetType.TypeDefinition && + !string.IsNullOrEmpty(x.Alias)) is CodeUsing aliasedUsing) + return aliasedUsing.Alias; + return string.Empty; + } private string TranslateTypeAndAvoidUsingNamespaceSegmentNames(CodeType currentType, CodeElement targetElement) { var parentElementsHash = targetElement.Parent is CodeClass parentClass ? diff --git a/src/Kiota.Builder/Writers/Dart/DartWriter.cs b/src/Kiota.Builder/Writers/Dart/DartWriter.cs index 26afd9f0d3..cf5b2ba539 100644 --- a/src/Kiota.Builder/Writers/Dart/DartWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/DartWriter.cs @@ -7,7 +7,7 @@ public DartWriter(string rootPath, string clientNamespaceName) { PathSegmenter = new DartPathSegmenter(rootPath, clientNamespaceName); var conventionService = new DartConventionService(); - AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService, clientNamespaceName, (DartPathSegmenter)PathSegmenter)); AddOrReplaceCodeElementWriter(new CodeBlockEndWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeEnumWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService)); From fafe3b9fc12f52106e6a61420e6cec10c924e92e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 9 Oct 2024 14:39:21 +0200 Subject: [PATCH 087/194] changed generation of error classes to work with copyWith method --- .../Refiners/DartRefinerFromScratch.cs | 66 +++++---- .../Writers/Dart/CodeMethodWriter.cs | 136 +++++++++++++----- .../Writers/Dart/CodePropertyWriter.cs | 2 +- .../Writers/Dart/DartConventionService.cs | 6 + 4 files changed, 152 insertions(+), 58 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 2f8a3f8d4b..53b354f7cb 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -134,16 +134,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance "ApiException", AbstractionsNamespaceName ); - AddPrimaryErrorMessage(generatedCode, - "message", - () => new CodeType { Name = "string", IsNullable = true, IsExternal = false }, - true - ); DeduplicateErrorMappings(generatedCode); RemoveCancellationParameter(generatedCode); DisambiguatePropertiesWithClassNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); - AddCloneMethodToRequestBuilders(generatedCode); + AddCustomMethods(generatedCode); EscapeStringValues(generatedCode); AliasUsingWithSameSymbol(generatedCode); }, cancellationToken); @@ -313,31 +308,54 @@ protected static void DisambiguatePropertiesWithClassNames(CodeElement currentEl } CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); } - private void AddCloneMethodToRequestBuilders(CodeElement currentElement, string methodName = "clone") + private void AddCustomMethods(CodeElement currentElement) { - if (currentElement is CodeClass currentClass && - currentClass.IsOfKind(CodeClassKind.RequestBuilder)) + if (currentElement is CodeClass currentClass) { - currentClass.AddMethod(new CodeMethod + if (currentClass.IsOfKind(CodeClassKind.RequestBuilder)) { - Name = methodName, - Access = AccessModifier.Public, - ReturnType = new CodeType + currentClass.AddMethod(new CodeMethod { - Name = currentClass.Name, - IsNullable = false, - }, - IsAsync = false, - IsStatic = false, + Name = "clone", + Access = AccessModifier.Public, + ReturnType = new CodeType + { + Name = currentClass.Name, + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, - Kind = CodeMethodKind.Custom, - Documentation = new() + Kind = CodeMethodKind.Custom, + Documentation = new() + { + DescriptionTemplate = "Clones the requestbuilder.", + }, + }); + } + if (currentClass.IsOfKind(CodeClassKind.Model) && currentClass.IsErrorDefinition) + { + currentClass.AddMethod(new CodeMethod { - DescriptionTemplate = "Clones the requestbuilder.", - }, - }); + Name = "copyWith", + Access = AccessModifier.Public, + ReturnType = new CodeType + { + Name = currentClass.Name, + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + + Kind = CodeMethodKind.Custom, + Documentation = new() + { + DescriptionTemplate = "Creates a copy of the object.", + }, + }); + } } - CrawlTree(currentElement, x => AddCloneMethodToRequestBuilders(x, methodName)); + CrawlTree(currentElement, x => AddCustomMethods(x)); } private void EscapeStringValues(CodeElement currentElement) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index c698064572..714a66ddaa 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -4,6 +4,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.OrderComparers; +using static Kiota.Builder.CodeDOM.CodeTypeBase; namespace Kiota.Builder.Writers.Dart; public class CodeMethodWriter : BaseElementWriter @@ -35,16 +36,19 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri } else { - if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) + if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition) { writer.DecreaseIndent(); } + else if (isConstructor && parentClass.IsErrorDefinition) + { + writer.CloseBlock("});"); + } else { writer.CloseBlock(); } } - } private static bool HasEmptyConstructorBody(CodeMethod codeElement, CodeClass parentClass, bool isConstructor) @@ -219,6 +223,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, } writer.WriteLine($"return {ResultVarName};"); } + private const string DiscriminatorMappingVarName = "mappingValue"; private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { @@ -237,9 +242,14 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); + else if (parentClass.IsErrorDefinition) + { + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}(additionalData: {{}});"); + } else writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}();"); } + private void WriteRequestBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) { var importSymbol = conventions.GetTypeString(codeElement.ReturnType, parentClass); @@ -272,38 +282,63 @@ private static void WriteSerializationRegistration(HashSet serialization } private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer) { - foreach (var propWithDefault in parentClass - .Properties - .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters)) - // do not apply the default value if the type is composed as the default value may not necessarily which type to use - .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) - .OrderByDescending(static x => x.Kind) - .ThenBy(static x => x.Name)) + if (parentClass.IsErrorDefinition) + { + WriteErrorClassConstructor(parentClass, currentMethod, writer); + } + else { - var defaultValue = propWithDefault.DefaultValue; - if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) + foreach (var propWithDefault in parentClass + .Properties + .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters)) + // do not apply the default value if the type is composed as the default value may not necessarily which type to use + .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) + .OrderByDescending(static x => x.Kind) + .ThenBy(static x => x.Name)) { - defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; + var defaultValue = propWithDefault.DefaultValue; + if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) + { + defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; + } + writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue};"); + } + if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && + parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && + currentMethod.IsOfKind(CodeMethodKind.Constructor) && + currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParam) + { + var pathParameters = currentMethod.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Path)); + if (pathParameters.Any()) + conventions.AddParametersAssignment(writer, + pathParametersParam.Type, + pathParametersParam.Name.ToFirstCharacterLowerCase(), + pathParametersProp.Name.ToFirstCharacterLowerCase(), + currentMethod.Parameters + .Where(static x => x.IsOfKind(CodeParameterKind.Path)) + .Select(static x => (x.Type, string.IsNullOrEmpty(x.SerializationName) ? x.Name : x.SerializationName, x.Name.ToFirstCharacterLowerCase())) + .ToArray()); } - writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue};"); } - if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && - parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && - currentMethod.IsOfKind(CodeMethodKind.Constructor) && - currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParam) + } + + private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer) + { + foreach (string prop in DartConventionService.ErrorClassProperties) { - var pathParameters = currentMethod.Parameters.Where(static x => x.IsOfKind(CodeParameterKind.Path)); - if (pathParameters.Any()) - conventions.AddParametersAssignment(writer, - pathParametersParam.Type, - pathParametersParam.Name.ToFirstCharacterLowerCase(), - pathParametersProp.Name.ToFirstCharacterLowerCase(), - currentMethod.Parameters - .Where(static x => x.IsOfKind(CodeParameterKind.Path)) - .Select(static x => (x.Type, string.IsNullOrEmpty(x.SerializationName) ? x.Name : x.SerializationName, x.Name.ToFirstCharacterLowerCase())) - .ToArray()); + writer.WriteLine($"super.{prop},"); + } + foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) + { + var required = prop.Type.IsNullable ? "" : "required "; + + if (!conventions.ErrorClassPropertyExistsInSuperClass(prop)) + { + writer.WriteLine($"{required}this.{prop.Name.ToFirstCharacterLowerCase()},"); + } } } + private string DefaultDeserializerValue => $"Map"; private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { @@ -365,7 +400,7 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod if (fieldToSerialize.Length != 0) { fieldToSerialize - .Where(static x => !x.ExistsInBaseType) + .Where(x => !x.ExistsInBaseType && !conventions.ErrorClassPropertyExistsInSuperClass(x)) .OrderBy(static x => x.Name) .Select(x => $"{DeserializerVarName}['{x.WireName}'] = (node) => {x.Name.ToFirstCharacterLowerCase()} = node.{GetDeserializationMethodName(x.Type, codeElement)};") @@ -505,7 +540,7 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me writer.WriteLine("super.serialize(writer);"); foreach (var otherProp in parentClass .GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.ErrorMessageOverride) - .Where(static x => !x.ExistsInBaseType && !x.ReadOnly) + .Where(x => !x.ExistsInBaseType && !x.ReadOnly && !conventions.ErrorClassPropertyExistsInSuperClass(x)) .OrderBy(static x => x.Name)) { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); @@ -631,7 +666,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass } return " : super()"; } - else if (isConstructor && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) + else if (isConstructor && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition) { return " : "; } @@ -641,7 +676,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; - if (code.IsOfKind(CodeMethodKind.Serializer, CodeMethodKind.Deserializer, CodeMethodKind.QueryParametersMapper) || (code.IsOfKind(CodeMethodKind.Custom) && code.Name.Equals("clone", StringComparison.OrdinalIgnoreCase))) + if (code.IsOfKind(CodeMethodKind.Serializer, CodeMethodKind.Deserializer, CodeMethodKind.QueryParametersMapper) || (code.IsOfKind(CodeMethodKind.Custom))) { writer.WriteLine("@override"); } @@ -662,7 +697,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var methodName = GetMethodName(code, parentClass, isConstructor); var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; - + var closingparenthesis = (isConstructor && parentClass.IsErrorDefinition) ? string.Empty : ")"; // Constuctors (except for ClientConstructor) don't need a body but a closing statement if (HasEmptyConstructorBody(code, parentClass, isConstructor)) { @@ -681,12 +716,30 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua .ToList()); writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({optionalParamOpen}{nullableParameters}{optionalParamClose}){baseSuffix}{async} {{"); } + else if (parentClass.IsOfKind(CodeClassKind.Model) && code.IsOfKind(CodeMethodKind.Custom) && code.Name.EqualsIgnoreCase("copyWith")) + { + var parentParameters = "int? statusCode, String? message, Map>? responseHeaders, Iterable? innerExceptions, "; + var ownParameters = string.Join(", ", parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData) + .Where(p => !conventions.ErrorClassPropertyExistsInSuperClass(p)) + .Select(p => $"{GetPrefix(p)}{conventions.TranslateType(p.Type)}{getSuffix(p)}? {p.Name.ToFirstCharacterLowerCase()}")); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({openingBracket}{parentParameters}{ownParameters} }}){{"); + } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({optionalParamOpen}{parameters}{optionalParamClose}){baseSuffix}{async} {openingBracket}"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({optionalParamOpen}{parameters}{optionalParamClose}{closingparenthesis}{baseSuffix}{async} {openingBracket}"); } } + private string getSuffix(CodeProperty property) + { + return property.Type.CollectionKind == CodeTypeCollectionKind.Complex ? ">" : string.Empty; + } + + private string GetPrefix(CodeProperty property) + { + return property.Type.CollectionKind == CodeTypeCollectionKind.Complex ? "Iterable<" : string.Empty; + } + private static string GetMethodName(CodeMethod code, CodeClass parentClass, bool isConstructor) { if (code.IsOfKind(CodeMethodKind.RawUrlConstructor)) @@ -760,5 +813,22 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass .Aggregate(static (x, y) => $"{x}, {y}"); writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({argumentList});"); } + if (codeElement.Name.Equals("copyWith", StringComparison.Ordinal)) + { + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}("); + foreach (string prop in DartConventionService.ErrorClassProperties) + { + writer.WriteLine($"{prop} : {prop} ?? this.{prop}, "); + } + foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) + { + var propertyname = prop.Name.ToFirstCharacterLowerCase(); + if (!conventions.ErrorClassPropertyExistsInSuperClass(prop)) + { + writer.WriteLine($"{propertyname} : {propertyname} ?? this.{propertyname}, "); + } + } + writer.WriteLine($");"); + } } } diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 1287415750..708799b350 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -12,7 +12,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w { ArgumentNullException.ThrowIfNull(codeElement); ArgumentNullException.ThrowIfNull(writer); - if (codeElement.ExistsInExternalBaseType) return; + if (codeElement.ExistsInExternalBaseType || conventions.ErrorClassPropertyExistsInSuperClass(codeElement)) return; var propertyType = conventions.GetTypeString(codeElement.Type, codeElement); var isNullableReferenceType = !propertyType.EndsWith('?') && codeElement.IsOfKind( diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 22afd194d0..b1f1491ff3 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -13,6 +13,8 @@ namespace Kiota.Builder.Writers.Dart; public class DartConventionService : CommonLanguageConventionService { internal static string AutoGenerationHeader => "// auto generated"; + internal static readonly HashSet ErrorClassProperties = new(StringComparer.OrdinalIgnoreCase) { "message", "statusCode", "responseHeaders", "innerExceptions" }; + public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; @@ -346,4 +348,8 @@ internal void WriteDeprecationAttribute(IDeprecableElement element, LanguageWrit writer.WriteLine(deprecationMessage); } + public bool ErrorClassPropertyExistsInSuperClass(CodeProperty codeElement) + { + return codeElement?.Parent is CodeClass parentClass && parentClass.IsErrorDefinition && ErrorClassProperties.Contains(codeElement.Name); + } } From 58d1fce87c6fbafd222cde3af2fae84c5fae35ae Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 10 Oct 2024 15:41:50 +0200 Subject: [PATCH 088/194] some fixes to intersection and union models --- .../Refiners/DartRefinerFromScratch.cs | 5 +++++ .../Writers/Dart/CodeMethodWriter.cs | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 53b354f7cb..05de1375ea 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -49,6 +49,11 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance { cancellationToken.ThrowIfCancellationRequested(); var defaultConfiguration = new GenerationConfiguration(); + ConvertUnionTypesToWrapper(generatedCode, + _configuration.UsesBackingStore, + static s => s, + false, + AbstractionsNamespaceName); CorrectCommonNames(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); ReplaceIndexersByMethodsWithParameter(generatedCode, diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 714a66ddaa..940a785cec 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -164,7 +164,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) { var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if(\"{mappedType.Key}.toUpperCase()\".equals({DiscriminatorMappingVarName}.toUpperCase())) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({mappedType.Key}.toUpperCase().equals({DiscriminatorMappingVarName}.toUpperCase())) {{"); writer.IncreaseIndent(); writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); writer.CloseBlock(); @@ -175,7 +175,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName}) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};"); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {valueVarName};"); writer.CloseBlock(); } if (!includeElse) @@ -197,7 +197,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName}) {{"); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};"); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {valueVarName};"); writer.CloseBlock(); } if (!includeElse) @@ -215,7 +215,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, writer.IncreaseIndent(); } foreach (var property in complexProperties) - writer.WriteLine($"{ResultVarName}.{property.Item1.Name.ToFirstCharacterUpperCase()} = {conventions.GetTypeString(property.Item2, codeElement)}();"); + writer.WriteLine($"{ResultVarName}.{property.Item1.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(property.Item2, codeElement)}();"); if (includeElse) { writer.CloseBlock(); @@ -358,10 +358,10 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par .Where(static x => x.Type is CodeType propertyType && !propertyType.IsCollection && propertyType.TypeDefinition is CodeClass) .OrderBy(static x => x, CodePropertyTypeForwardComparer) .ThenBy(static x => x.Name) - .Select(static x => x.Name.ToFirstCharacterUpperCase())) + .Select(static x => x.Name.ToFirstCharacterLowerCase())) { writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({otherPropName} != null) {{"); - writer.WriteLine($"return {otherPropName}.{method.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"return {otherPropName}!.{method.Name.ToFirstCharacterLowerCase()}();"); writer.CloseBlock(); if (!includeElse) includeElse = true; @@ -562,9 +562,9 @@ private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass paren .OrderBy(static x => x, CodePropertyTypeForwardComparer) .ThenBy(static x => x.Name)) { - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterLowerCase()} != null) {{"); writer.IncreaseIndent(); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterLowerCase()});"); writer.CloseBlock(); if (!includeElse) includeElse = true; @@ -598,7 +598,7 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas writer.IncreaseIndent(); } var propertiesNames = complexProperties - .Select(static x => x.Name.ToFirstCharacterUpperCase()) + .Select(static x => x.Name.ToFirstCharacterLowerCase()) .OrderBy(static x => x) .Aggregate(static (x, y) => $"{x}, {y}"); writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {propertiesNames});"); From f0b7b75b20544f70b4778c2176abc0c4f7f84170 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 15 Oct 2024 13:09:41 +0200 Subject: [PATCH 089/194] More fixes to generated model classes for intersection and union models --- .../Refiners/DartRefinerFromScratch.cs | 3 +- .../Writers/Dart/CodeMethodWriter.cs | 80 +++++++++---------- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs index 05de1375ea..26a5dbcc0e 100644 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs @@ -52,8 +52,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance ConvertUnionTypesToWrapper(generatedCode, _configuration.UsesBackingStore, static s => s, - false, - AbstractionsNamespaceName); + false); CorrectCommonNames(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); ReplaceIndexersByMethodsWithParameter(generatedCode, diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 940a785cec..ee21c69740 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -156,30 +156,32 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla { writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); var includeElse = false; - foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) - .OrderBy(static x => x, CodePropertyTypeForwardComparer) - .ThenBy(static x => x.Name, StringComparer.Ordinal)) + if (parentClass.DiscriminatorInformation.HasBasicDiscriminatorInformation) { - if (property.Type is CodeType propertyType) - if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) - { - var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({mappedType.Key}.toUpperCase().equals({DiscriminatorMappingVarName}.toUpperCase())) {{"); - writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); - writer.CloseBlock(); - } - else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) - { - var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); - var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName}) {{"); - writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {valueVarName};"); - writer.CloseBlock(); - } - if (!includeElse) - includeElse = true; + foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .OrderBy(static x => x, CodePropertyTypeForwardComparer) + .ThenBy(static x => x.Name, StringComparer.Ordinal)) + { + if (property.Type is CodeType propertyType) + if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) + { + var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({mappedType.Key}.toUpperCase().equals({DiscriminatorMappingVarName}.toUpperCase())) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); + writer.CloseBlock(); + } + else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) + { + var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName}) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); + writer.CloseBlock(); + } + if (!includeElse) + includeElse = true; + } } writer.WriteLine($"return {ResultVarName};"); } @@ -195,9 +197,8 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, if (property.Type is CodeType propertyType) { var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); - var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; - writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName}) {{"); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {valueVarName};"); + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName}) {{"); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); writer.CloseBlock(); } if (!includeElse) @@ -229,7 +230,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas { var parseNodeParameter = codeElement.Parameters.OfKind(CodeParameterKind.ParseNode) ?? throw new InvalidOperationException("Factory method should have a ParseNode parameter"); - if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) + if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType && parentClass.DiscriminatorInformation.HasBasicDiscriminatorInformation) { var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; @@ -369,27 +370,20 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par writer.WriteLine($"return {DefaultDeserializerValue}();"); } private const string DeserializerReturnType = "Map"; + private const string DeserializerName = "deserializers"; + private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) { + + writer.WriteLine($"{DefaultDeserializerValue} {DeserializerName} = {{}};"); var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => x.Type is CodeType propType && propType.TypeDefinition is CodeClass && !x.Type.IsCollection) .ToArray(); - if (complexProperties.Length != 0) + foreach (CodeProperty prop in complexProperties) { - var propertiesNames = complexProperties - .Select(static x => x.Name.ToFirstCharacterUpperCase()) - .OrderBy(static x => x) - .ToArray(); - var propertiesNamesAsConditions = propertiesNames - .Select(static x => $"{x} != null") - .Aggregate(static (x, y) => $"{x} || {y}"); - writer.StartBlock($"if({propertiesNamesAsConditions}) {{"); - var propertiesNamesAsArgument = propertiesNames - .Aggregate(static (x, y) => $"{x}, {y}"); - writer.WriteLine($"return ParseNodeHelper.MergeDeserializersForIntersectionWrapper({propertiesNamesAsArgument});"); - writer.CloseBlock(); + writer.WriteLine($"if({prop.Name.ToFirstCharacterLowerCase()} != null){{{DeserializerName}.addAll({prop.Name.ToFirstCharacterLowerCase()}!.getFieldDeserializers());}}"); } - writer.WriteLine($"return {DefaultDeserializerValue}();"); + writer.WriteLine($"return {DeserializerName};"); } private const string DeserializerVarName = "deserializerMap"; private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) @@ -580,9 +574,9 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas .OrderBy(static x => x, CodePropertyTypeBackwardComparer) .ThenBy(static x => x.Name)) { - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterLowerCase()} != null) {{"); writer.IncreaseIndent(); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterLowerCase()});"); writer.CloseBlock(); if (!includeElse) includeElse = true; From 2eab53967fd41cbfcccefd42ee6712bb358a3f60 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 16 Oct 2024 11:36:50 +0200 Subject: [PATCH 090/194] Added Dart language to GenerateSample Fixed a bug in the process. Propertynames in Json can start with uppercase letter, but in Dart we store them using camelCase. QueryParameters incorrectly used the upeercase propertyname to get the value. The fix is in line with how Java handles query parameters. --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- .../Kiota.Builder.IntegrationTests/GenerateSample.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index ee21c69740..42c79d5059 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -761,7 +761,7 @@ private void WriteQueryparametersBody(CodeClass parentClass, CodeMethod codeElem writer.IncreaseIndent(); foreach (CodeProperty property in parentClass.Properties) { - writer.WriteLine($"\"{property.Name}\" : {property.Name},"); + writer.WriteLine($"\"{property.Name}\" : {property.Name.ToFirstCharacterLowerCase()},"); } writer.DecreaseIndent(); writer.WriteLine("};"); diff --git a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs index e501197158..cecc8891b6 100644 --- a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs +++ b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs @@ -20,11 +20,13 @@ public void Dispose() [InlineData(GenerationLanguage.Java, false)] [InlineData(GenerationLanguage.TypeScript, false)] [InlineData(GenerationLanguage.Go, false)] + [InlineData(GenerationLanguage.Dart, false)] [InlineData(GenerationLanguage.Ruby, false)] [InlineData(GenerationLanguage.CSharp, true)] [InlineData(GenerationLanguage.Java, true)] [InlineData(GenerationLanguage.PHP, false)] [InlineData(GenerationLanguage.TypeScript, true)] + [InlineData(GenerationLanguage.Dart, true)] [Theory] public async Task GeneratesTodo(GenerationLanguage language, bool backingStore) { @@ -46,11 +48,13 @@ public async Task GeneratesTodo(GenerationLanguage language, bool backingStore) [InlineData(GenerationLanguage.Java, false)] [InlineData(GenerationLanguage.TypeScript, false)] [InlineData(GenerationLanguage.Go, false)] + [InlineData(GenerationLanguage.Dart, false)] [InlineData(GenerationLanguage.Ruby, false)] [InlineData(GenerationLanguage.CSharp, true)] [InlineData(GenerationLanguage.Java, true)] [InlineData(GenerationLanguage.PHP, false)] [InlineData(GenerationLanguage.TypeScript, true)] + [InlineData(GenerationLanguage.Dart, true)] [Theory] public async Task GeneratesModelWithDictionary(GenerationLanguage language, bool backingStore) { @@ -72,11 +76,13 @@ public async Task GeneratesModelWithDictionary(GenerationLanguage language, bool [InlineData(GenerationLanguage.Java, false)] [InlineData(GenerationLanguage.TypeScript, false)] [InlineData(GenerationLanguage.Go, false)] + [InlineData(GenerationLanguage.Dart, false)] [InlineData(GenerationLanguage.Ruby, false)] [InlineData(GenerationLanguage.CSharp, true)] [InlineData(GenerationLanguage.Java, true)] [InlineData(GenerationLanguage.PHP, false)] [InlineData(GenerationLanguage.TypeScript, true)] + [InlineData(GenerationLanguage.Dart, true)] [Theory] public async Task GeneratesResponseWithMultipleReturnFormats(GenerationLanguage language, bool backingStore) { @@ -97,6 +103,7 @@ public async Task GeneratesResponseWithMultipleReturnFormats(GenerationLanguage [InlineData(GenerationLanguage.CSharp)] [InlineData(GenerationLanguage.Java)] [InlineData(GenerationLanguage.Go)] + [InlineData(GenerationLanguage.Dart)] [InlineData(GenerationLanguage.Ruby)] [InlineData(GenerationLanguage.Python)] [InlineData(GenerationLanguage.TypeScript)] @@ -119,6 +126,7 @@ public async Task GeneratesErrorsInliningParents(GenerationLanguage language) [InlineData(GenerationLanguage.CSharp)] [InlineData(GenerationLanguage.Java)] [InlineData(GenerationLanguage.Go)] + [InlineData(GenerationLanguage.Dart)] [InlineData(GenerationLanguage.Ruby)] [InlineData(GenerationLanguage.Python)] [InlineData(GenerationLanguage.TypeScript)] @@ -167,6 +175,7 @@ public async Task GeneratesIdiomaticChildrenNames(GenerationLanguage language) } [InlineData(GenerationLanguage.CSharp)] [InlineData(GenerationLanguage.Go)] + [InlineData(GenerationLanguage.Dart)] [InlineData(GenerationLanguage.Java)] [InlineData(GenerationLanguage.PHP)] [InlineData(GenerationLanguage.Python)] @@ -201,6 +210,9 @@ public async Task GeneratesUritemplateHints(GenerationLanguage language) case GenerationLanguage.CSharp: Assert.Contains("[QueryParameter(\"startDateTime\")]", fullText); break; + case GenerationLanguage.Dart: + Assert.Contains("\"EndDateTime\" : endDateTime", fullText); + break; case GenerationLanguage.Go: Assert.Contains("`uriparametername:\"startDateTime\"`", fullText); break; From bf56f412ee621aed311e6247ed19fe893f6fb30a Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Thu, 17 Oct 2024 07:59:30 +0200 Subject: [PATCH 091/194] Copied Dart refiner code over original refiner Previously we used a dart refiner we created from scratch. Just to be sure it only contains the code we actually need. Currently the differences between the existing refiner and the newly created refiner are small. At this point we decided to copy our refiner code over the existing refiner. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 555 +++++++++++------- .../Refiners/DartRefinerFromScratch.cs | 423 ------------- .../Refiners/ILanguageRefiner.cs | 2 +- 3 files changed, 342 insertions(+), 638 deletions(-) delete mode 100644 src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 7eff8d9761..b19d8016ad 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -6,22 +6,62 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; +using Kiota.Builder.Writers.Dart; namespace Kiota.Builder.Refiners; public class DartRefiner : CommonLanguageRefiner, ILanguageRefiner { + private const string MultipartBodyClassName = "MultipartBody"; + private const string AbstractionsNamespaceName = "kiota_abstractions/kiota_abstractions"; + private const string SerializationNamespaceName = "kiota_serialization"; + private static readonly CodeUsingDeclarationNameComparer usingComparer = new(); + + protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), + AbstractionsNamespaceName, "RequestAdapter"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), + AbstractionsNamespaceName, "Method", "RequestInformation", "RequestOption"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), + AbstractionsNamespaceName, "SerializationWriter"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), + AbstractionsNamespaceName, "ParseNode"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), + AbstractionsNamespaceName, "Parsable"), + new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), + AbstractionsNamespaceName, "AdditionalDataHolder"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), + AbstractionsNamespaceName, "Parsable"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(prop.SerializationName), + AbstractionsNamespaceName, "QueryParameterAttribute"), + new (static x => x is CodeClass @class && @class.OriginalComposedType is CodeIntersectionType intersectionType && intersectionType.Types.Any(static y => !y.IsExternal), + AbstractionsNamespaceName, "ParseNodeHelper"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), + AbstractionsNamespaceName, "RequestHeaders"), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), + AbstractionsNamespaceName, MultipartBodyClassName), + }; + + public DartRefiner(GenerationConfiguration configuration) : base(configuration) { } public override Task Refine(CodeNamespace generatedCode, CancellationToken cancellationToken) { return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - AddPrimaryErrorMessage(generatedCode, - "Message", - () => new CodeType { Name = "string", IsNullable = false, IsExternal = true }, - true - ); - DeduplicateErrorMappings(generatedCode); + var defaultConfiguration = new GenerationConfiguration(); + ConvertUnionTypesToWrapper(generatedCode, + _configuration.UsesBackingStore, + static s => s, + false); + CorrectCommonNames(generatedCode); + CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); + ReplaceIndexersByMethodsWithParameter(generatedCode, + false, + static x => $"by{x.ToFirstCharacterUpperCase()}", + static x => x.ToFirstCharacterLowerCase(), + GenerationLanguage.Dart); + AddQueryParameterExtractorMethod(generatedCode); + // This adds the BaseRequestBuilder class as a superclass MoveRequestBuilderPropertiesToBaseType(generatedCode, new CodeUsing { @@ -29,206 +69,180 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance Declaration = new CodeType { Name = AbstractionsNamespaceName, - IsExternal = true + IsExternal = true, } - }); - + }, addCurrentTypeAsGenericTypeParameter: true); RemoveRequestConfigurationClasses(generatedCode, - new CodeUsing - { - Name = "RequestConfiguration", - Declaration = new CodeType - { - Name = AbstractionsNamespaceName, - IsExternal = true - } - }, - new CodeType - { - Name = "DefaultQueryParameters", - IsExternal = true, - }, - !_configuration.ExcludeBackwardCompatible,//TODO remove the condition for v2 - !_configuration.ExcludeBackwardCompatible); + new CodeUsing + { + Name = "RequestConfiguration", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }, new CodeType + { + Name = "DefaultQueryParameters", + IsExternal = true, + }); + var reservedNamesProvider = new DartReservedNamesProvider(); + CorrectNames(generatedCode, s => + { + if (s.Contains('_', StringComparison.OrdinalIgnoreCase) && + s.ToPascalCase(UnderscoreArray) is string refinedName && + !reservedNamesProvider.ReservedNames.Contains(s) && + !reservedNamesProvider.ReservedNames.Contains(refinedName)) + return refinedName; + else + return s; + }); + + MoveQueryParameterClass(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); - MoveClassesWithNamespaceNamesUnderNamespace(generatedCode); - ConvertUnionTypesToWrapper(generatedCode, - _configuration.UsesBackingStore, - static s => s, - true, - AbstractionsNamespaceName, - "IComposedTypeWrapper" - ); + AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); + AddParsableImplementsForModelClasses(generatedCode, "Parsable"); + AddConstructorsForDefaultValues(generatedCode, true); cancellationToken.ThrowIfCancellationRequested(); - AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); AddAsyncSuffix(generatedCode); - cancellationToken.ThrowIfCancellationRequested(); - AddParsableImplementsForModelClasses(generatedCode, "IParsable"); - CapitalizeNamespacesFirstLetters(generatedCode); - ReplaceBinaryByNativeType(generatedCode, "Stream", "System.IO"); - MakeEnumPropertiesNullable(generatedCode); - /* Exclude the following as their names will be capitalized making the change unnecessary in this case sensitive language - * code classes, class declarations, property names, using declarations, namespace names - * Exclude CodeMethod as the return type will also be capitalized (excluding the CodeType is not enough since this is evaluated at the code method level) - */ - ReplaceReservedNames( - generatedCode, - new DartReservedNamesProvider(), x => $"@{x.ToFirstCharacterUpperCase()}", - new HashSet { typeof(CodeClass), typeof(ClassDeclaration), typeof(CodeProperty), typeof(CodeUsing), typeof(CodeNamespace), typeof(CodeMethod), typeof(CodeEnum), typeof(CodeEnumOption) } - ); - ReplaceReservedNames( - generatedCode, - new DartReservedNamesProvider(), - x => $"{x.ToFirstCharacterUpperCase()}Escaped" - ); + AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); + + ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped", [typeof(CodeEnumOption)]); + ReplaceReservedModelTypes(generatedCode, reservedNamesProvider, x => $"{x}Object"); ReplaceReservedExceptionPropertyNames( generatedCode, new DartExceptionsReservedNamesProvider(), - static x => $"{x.ToFirstCharacterUpperCase()}Escaped" + static x => $"{x.ToFirstCharacterLowerCase()}Escaped" ); - cancellationToken.ThrowIfCancellationRequested(); - ReplaceReservedModelTypes(generatedCode, new DartReservedNamesProvider(), x => $"{x}Object"); - ReplaceReservedNamespaceTypeNames(generatedCode, new DartReservedNamesProvider(), static x => $"{x}Namespace"); - ReplacePropertyNames(generatedCode, - new() { - CodePropertyKind.Custom, - CodePropertyKind.QueryParameter, - }, - static s => s.ToPascalCase(UnderscoreArray)); - LowerCaseNamespaceNames(generatedCode); - var defaultConfiguration = new GenerationConfiguration(); - cancellationToken.ThrowIfCancellationRequested(); ReplaceDefaultSerializationModules( generatedCode, defaultConfiguration.Serializers, new(StringComparer.OrdinalIgnoreCase) { - $"{SerializationNamespaceName}.JsonSerializationWriterFactory", - $"{SerializationNamespaceName}.TextSerializationWriterFactory", - $"{SerializationNamespaceName}.FormSerializationWriterFactory", - $"{SerializationNamespaceName}.MultipartSerializationWriterFactory", + $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonSerializationWriterFactory", + $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextSerializationWriterFactory", + $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormSerializationWriterFactory", + // $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", } ); ReplaceDefaultDeserializationModules( generatedCode, defaultConfiguration.Deserializers, new(StringComparer.OrdinalIgnoreCase) { - $"{SerializationNamespaceName}.JsonParseNodeFactory", - $"{SerializationNamespaceName}.FormParseNodeFactory", - $"{SerializationNamespaceName}.TextParseNodeFactory" + $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonParseNodeFactory", + $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormParseNodeFactory", + $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextParseNodeFactory" } ); - - DisambiguatePropertiesWithClassNames(generatedCode); - // Correct the core types after reserved names for types/properties are done to avoid collision of types e.g. renaming custom model called `DateOnly` to `Date` - CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, correctIndexer: CorrectIndexerType); - cancellationToken.ThrowIfCancellationRequested(); - AddSerializationModulesImport(generatedCode, - [ $"{AbstractionsNamespaceName}.ApiClientBuilder", - $"{SerializationNamespaceName}.SerializationWriterFactoryRegistry" ], - [$"{SerializationNamespaceName}.ParseNodeFactoryRegistry"], '^'); - - + [$"{AbstractionsNamespaceName}.ApiClientBuilder", + $"{AbstractionsNamespaceName}.SerializationWriterFactoryRegistry"], + [$"{AbstractionsNamespaceName}.ParseNodeFactoryRegistry"]); + cancellationToken.ThrowIfCancellationRequested(); AddParentClassToErrorClasses( - generatedCode, - "ApiException", - AbstractionsNamespaceName - ); - AddConstructorsForDefaultValues(generatedCode, false); - AddDiscriminatorMappingsUsingsToParentClasses( - generatedCode, - "IParseNode" + generatedCode, + "ApiException", + AbstractionsNamespaceName ); + DeduplicateErrorMappings(generatedCode); + RemoveCancellationParameter(generatedCode); + DisambiguatePropertiesWithClassNames(generatedCode); + RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); + AddCustomMethods(generatedCode); + EscapeStringValues(generatedCode); + AliasUsingWithSameSymbol(generatedCode); }, cancellationToken); } - protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) + + /// + /// Corrects common names so they can be used with Dart. + /// This normally comes down to changing the first character to lower case. + /// GetFieldDeserializers is corrected to getFieldDeserializers + /// + private static void CorrectCommonNames(CodeElement currentElement) { - if (currentElement is CodeClass currentClass) + if (currentElement is CodeMethod m && + currentElement.Parent is CodeClass parentClass) { - var sameNameProperty = currentClass.Properties - .FirstOrDefault(x => x.Name.Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase)); - if (sameNameProperty != null) - { - currentClass.RemoveChildElement(sameNameProperty); - if (string.IsNullOrEmpty(sameNameProperty.SerializationName)) - sameNameProperty.SerializationName = sameNameProperty.Name; - sameNameProperty.Name = $"{sameNameProperty.Name}Prop"; - currentClass.AddProperty(sameNameProperty); - } + parentClass.RenameChildElement(m.Name, m.Name.ToFirstCharacterLowerCase()); } - CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); + else if (currentElement is CodeIndexer i) + { + i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); + } + CrawlTree(currentElement, element => CorrectCommonNames(element)); } - protected static void MakeEnumPropertiesNullable(CodeElement currentElement) + + private static void CorrectMethodType(CodeMethod currentMethod) { - if (currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.Model)) - currentClass.Properties - .Where(x => x.Type is CodeType propType && propType.TypeDefinition is CodeEnum) - .ToList() - .ForEach(x => x.Type.IsNullable = true); - CrawlTree(currentElement, MakeEnumPropertiesNullable); + if (currentMethod.IsOfKind(CodeMethodKind.Deserializer)) + { + currentMethod.ReturnType.Name = "Map"; + currentMethod.Name = "getFieldDeserializers"; + } + else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlConstructor)) + { + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.RequestAdapter)) + .Where(x => x.Type.Name.StartsWith('I')) + .ToList() + .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" + } } - private const string AbstractionsNamespaceName = "Microsoft.Kiota.Abstractions"; - private const string SerializationNamespaceName = $"{AbstractionsNamespaceName}.Serialization"; - private const string StoreNamespaceName = $"{AbstractionsNamespaceName}.Store"; - private const string ExtensionsNamespaceName = $"{AbstractionsNamespaceName}.Extensions"; - protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), - AbstractionsNamespaceName, "RequestAdapter"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), - AbstractionsNamespaceName, "Method", "RequestInformation", "IRequestOption"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), - SerializationNamespaceName, "SerializationWriter"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), - SerializationNamespaceName, "ParseNode"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor), - ExtensionsNamespaceName, "Mao"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), - SerializationNamespaceName, "Parsable"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), - SerializationNamespaceName, "AdditionalDataHolder"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), - SerializationNamespaceName, "Parsable"), - new (static x => x is CodeClass || x is CodeEnum, - "System", "String"), - new (static x => x is CodeClass, - "System.Collections.Generic", "List", "Dictionary"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model, CodeClassKind.RequestBuilder), - "System.IO", "Stream"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), - "System.Threading", "CancellationToken"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.RequestBuilder), - "System.Threading.Tasks", "Task"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model, CodeClassKind.RequestBuilder), - ExtensionsNamespaceName, "Enumerable"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ClientConstructor) && - method.Parameters.Any(y => y.IsOfKind(CodeParameterKind.BackingStore)), - StoreNamespaceName, "IBackingStoreFactory", "IBackingStoreFactorySingleton"), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.BackingStore), - StoreNamespaceName, "IBackingStore", "IBackedModel", "BackingStoreFactorySingleton" ), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(prop.SerializationName), - AbstractionsNamespaceName, "QueryParameterAttribute"), - new (static x => x is CodeClass @class && @class.OriginalComposedType is CodeIntersectionType intersectionType && intersectionType.Types.Any(static y => !y.IsExternal), - SerializationNamespaceName, "ParseNodeHelper"), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), - AbstractionsNamespaceName, "RequestHeaders"), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase), - SerializationNamespaceName, KiotaBuilder.UntypedNodeName), - new (static x => x is CodeEnum prop && prop.Options.Any(x => x.IsNameEscaped), - "System.Runtime.Serialization", "EnumMemberAttribute"), - new (static x => x is IDeprecableElement element && element.Deprecation is not null && element.Deprecation.IsDeprecated, - "System", "ObsoleteAttribute"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), - AbstractionsNamespaceName, MultipartBodyClassName), - }; - private const string MultipartBodyClassName = "MultipartBody"; - protected static void CapitalizeNamespacesFirstLetters(CodeElement current) + private static void CorrectPropertyType(CodeProperty currentProperty) + { + ArgumentNullException.ThrowIfNull(currentProperty); + + if (currentProperty.IsOfKind(CodePropertyKind.Options)) + currentProperty.DefaultValue = "List()"; + else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) + currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + else if (currentProperty.IsOfKind(CodePropertyKind.RequestAdapter)) + { + currentProperty.Type.Name = "RequestAdapter"; + currentProperty.Type.IsNullable = true; + } + else if (currentProperty.IsOfKind(CodePropertyKind.BackingStore)) + { + currentProperty.Type.Name = currentProperty.Type.Name[1..]; // removing the "I" + currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); + } + else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameter)) + { + currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + } + else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) + { + currentProperty.Type.Name = "Map"; + currentProperty.DefaultValue = "{}"; + } + else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) + { + currentProperty.Type.IsNullable = true; + } + else if (currentProperty.IsOfKind(CodePropertyKind.PathParameters)) + { + currentProperty.Type.IsNullable = true; + currentProperty.Type.Name = "Map"; + if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) + currentProperty.DefaultValue = "{}"; + } + currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); + CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); + } + + private static void CorrectImplements(ProprietableBlockDeclaration block) { - if (current is CodeNamespace currentNamespace) - currentNamespace.Name = currentNamespace.Name.Split('.').Select(static x => x.ToFirstCharacterUpperCase()).Aggregate(static (x, y) => $"{x}.{y}"); - CrawlTree(current, CapitalizeNamespacesFirstLetters); + block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I + } + public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) + { + var genericParameterTypes = usingsToAdd.OfType().Where( + static codeType => codeType.Parent is CodeParameter parameter + && parameter.IsOfKind(CodeParameterKind.RequestConfiguration)).Select(x => x.GenericTypeParameterValues.First()); + + return usingsToAdd.Union(genericParameterTypes); } protected static void AddAsyncSuffix(CodeElement currentElement) { @@ -236,68 +250,181 @@ protected static void AddAsyncSuffix(CodeElement currentElement) currentMethod.Name += "Async"; CrawlTree(currentElement, AddAsyncSuffix); } - protected static void CorrectPropertyType(CodeProperty currentProperty) + private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "getQueryParameters") { - ArgumentNullException.ThrowIfNull(currentProperty); - if (currentProperty.IsOfKind(CodePropertyKind.Options)) - currentProperty.DefaultValue = "new List()"; - else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) - currentProperty.DefaultValue = $"new {currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; - CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); + if (currentElement is CodeClass currentClass && + currentClass.IsOfKind(CodeClassKind.QueryParameters)) + { + currentClass.StartBlock.AddImplements(new CodeType + { + IsExternal = true, + Name = "AbstractQueryParameters" + }); + currentClass.AddMethod(new CodeMethod + { + Name = methodName, + Access = AccessModifier.Public, + ReturnType = new CodeType + { + Name = "Map", + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + Kind = CodeMethodKind.QueryParametersMapper, + Documentation = new() + { + DescriptionTemplate = "Extracts the query parameters into a map for the URI template parsing.", + }, + }); + currentClass.AddUsing(new CodeUsing + { + Name = "AbstractQueryParameters", + Declaration = new CodeType { Name = AbstractionsNamespaceName, IsExternal = true }, + }); + } + CrawlTree(currentElement, x => AddQueryParameterExtractorMethod(x, methodName)); } - protected static void CorrectMethodType(CodeMethod currentMethod) + + private void MoveQueryParameterClass(CodeElement currentElement) { - ArgumentNullException.ThrowIfNull(currentMethod); - CorrectCoreTypes(currentMethod.Parent as CodeClass, DateTypesReplacements, currentMethod.Parameters - .Select(x => x.Type) - .Union(new[] { currentMethod.ReturnType }) - .ToArray()); - CorrectCoreTypes(currentMethod.Parent as CodeClass, DateTypesReplacements, currentMethod.PathQueryAndHeaderParameters - .Select(x => x.Type) - .Union(new[] { currentMethod.ReturnType }) - .ToArray()); + if (currentElement is CodeClass currentClass && + currentClass.IsOfKind(CodeClassKind.RequestBuilder)) + { + var parentNamespace = currentClass.GetImmediateParentOfType(); + var nestedClasses = currentClass.InnerClasses.Where(x => x.IsOfKind(CodeClassKind.QueryParameters)); + foreach (CodeClass nestedClass in nestedClasses) + { + parentNamespace.AddClass(nestedClass); + currentClass.RemoveChildElementByName(nestedClass.Name); + } + } + CrawlTree(currentElement, x => MoveQueryParameterClass(x)); } - protected static void CorrectIndexerType(CodeIndexer currentIndexer) + + protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) { - ArgumentNullException.ThrowIfNull(currentIndexer); - CorrectCoreTypes(currentIndexer.Parent as CodeClass, DateTypesReplacements, currentIndexer.IndexParameter.Type); + if (currentElement is CodeClass currentClass) + { + var sameNameProperty = currentClass.Properties + .FirstOrDefault(x => x.Name.Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase)); + if (sameNameProperty != null) + { + currentClass.RemoveChildElement(sameNameProperty); + if (string.IsNullOrEmpty(sameNameProperty.SerializationName)) + sameNameProperty.SerializationName = sameNameProperty.Name; + sameNameProperty.Name = $"{sameNameProperty.Name}Prop"; + currentClass.AddProperty(sameNameProperty); + } + } + CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); } - - private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) + private void AddCustomMethods(CodeElement currentElement) { + if (currentElement is CodeClass currentClass) { - "DateOnly",("Date", new CodeUsing + if (currentClass.IsOfKind(CodeClassKind.RequestBuilder)) + { + currentClass.AddMethod(new CodeMethod { - Name = "Date", - Declaration = new CodeType + Name = "clone", + Access = AccessModifier.Public, + ReturnType = new CodeType { - Name = AbstractionsNamespaceName, - IsExternal = true, + Name = currentClass.Name, + IsNullable = false, }, - }) - }, - { - "TimeOnly",("Time", new CodeUsing + IsAsync = false, + IsStatic = false, + + Kind = CodeMethodKind.Custom, + Documentation = new() + { + DescriptionTemplate = "Clones the requestbuilder.", + }, + }); + } + if (currentClass.IsOfKind(CodeClassKind.Model) && currentClass.IsErrorDefinition) + { + currentClass.AddMethod(new CodeMethod { - Name = "Time", - Declaration = new CodeType + Name = "copyWith", + Access = AccessModifier.Public, + ReturnType = new CodeType { - Name = AbstractionsNamespaceName, - IsExternal = true, + Name = currentClass.Name, + IsNullable = false, }, - }) - }, - }; + IsAsync = false, + IsStatic = false, - private static void LowerCaseNamespaceNames(CodeElement currentElement) + Kind = CodeMethodKind.Custom, + Documentation = new() + { + DescriptionTemplate = "Creates a copy of the object.", + }, + }); + } + } + CrawlTree(currentElement, x => AddCustomMethods(x)); + } + + private void EscapeStringValues(CodeElement currentElement) { - if (currentElement is CodeNamespace codeNamespace) + if (currentElement is CodeProperty property && + property.IsOfKind(CodePropertyKind.UrlTemplate)) { - if (!string.IsNullOrEmpty(codeNamespace.Name)) - codeNamespace.Name = codeNamespace.Name.ToLowerInvariant(); - - CrawlTree(currentElement, LowerCaseNamespaceNames); + if (property.DefaultValue.Contains('$', StringComparison.Ordinal)) + { + property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); + } } + else if (currentElement is CodeProperty prop) + { + if (!String.IsNullOrEmpty(prop.SerializationName) && prop.SerializationName.Contains('$', StringComparison.Ordinal)) + { + prop.SerializationName = prop.SerializationName.Replace("$", "\\$", StringComparison.Ordinal); + } + } + CrawlTree(currentElement, EscapeStringValues); } + private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) { + + {"TimeSpan", ("Duration", null)}, + {"Guid", ("UuidValue", new CodeUsing { + Name = "UuidValue", + Declaration = new CodeType { + Name = "uuid/uuid", + IsExternal = true, + }, + })}, + }; + private static void AliasUsingWithSameSymbol(CodeElement currentElement) + { + if (currentElement is CodeClass currentClass && currentClass.StartBlock != null && currentClass.StartBlock.Usings.Any(x => !x.IsExternal)) + { + var duplicatedSymbolsUsings = currentClass.StartBlock.Usings + .Distinct(usingComparer) + .Where(static x => !string.IsNullOrEmpty(x.Declaration?.Name) && x.Declaration.TypeDefinition != null) + .GroupBy(static x => x.Declaration!.Name, StringComparer.OrdinalIgnoreCase) + .Where(x => x.Count() > 1) + .SelectMany(x => x) + .Union(currentClass.StartBlock + .Usings + .Where(x => !x.IsExternal) + .Where(x => x.Declaration! + .Name + .Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase))); + foreach (var usingElement in duplicatedSymbolsUsings) + { + var replacement = string.Join("_", usingElement.Declaration!.TypeDefinition!.GetImmediateParentOfType().Name + .Split(".", StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.ToLowerInvariant()) + .ToArray()); + usingElement.Alias = $"{(string.IsNullOrEmpty(replacement) ? string.Empty : $"{replacement}")}_{usingElement.Declaration!.TypeDefinition!.Name.ToLowerInvariant()}"; + } + } + CrawlTree(currentElement, AliasUsingWithSameSymbol); + } } diff --git a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs b/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs deleted file mode 100644 index 26a5dbcc0e..0000000000 --- a/src/Kiota.Builder/Refiners/DartRefinerFromScratch.cs +++ /dev/null @@ -1,423 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Kiota.Builder.CodeDOM; -using Kiota.Builder.Configuration; -using Kiota.Builder.Extensions; -using Kiota.Builder.Writers.Dart; - -namespace Kiota.Builder.Refiners; -public class DartRefinerFromScratch : CommonLanguageRefiner, ILanguageRefiner -{ - private const string MultipartBodyClassName = "MultipartBody"; - private const string AbstractionsNamespaceName = "kiota_abstractions/kiota_abstractions"; - private const string SerializationNamespaceName = "kiota_serialization"; - private static readonly CodeUsingDeclarationNameComparer usingComparer = new(); - - protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), - AbstractionsNamespaceName, "RequestAdapter"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestGenerator), - AbstractionsNamespaceName, "Method", "RequestInformation", "RequestOption"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Serializer), - AbstractionsNamespaceName, "SerializationWriter"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.Deserializer), - AbstractionsNamespaceName, "ParseNode"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model), - AbstractionsNamespaceName, "Parsable"), - new (static x => x is CodeClass @class && @class.IsOfKind(CodeClassKind.Model) && @class.Properties.Any(x => x.IsOfKind(CodePropertyKind.AdditionalData)), - AbstractionsNamespaceName, "AdditionalDataHolder"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor), - AbstractionsNamespaceName, "Parsable"), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.QueryParameter) && !string.IsNullOrEmpty(prop.SerializationName), - AbstractionsNamespaceName, "QueryParameterAttribute"), - new (static x => x is CodeClass @class && @class.OriginalComposedType is CodeIntersectionType intersectionType && intersectionType.Types.Any(static y => !y.IsExternal), - AbstractionsNamespaceName, "ParseNodeHelper"), - new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), - AbstractionsNamespaceName, "RequestHeaders"), - new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), - AbstractionsNamespaceName, MultipartBodyClassName), - }; - - - public DartRefinerFromScratch(GenerationConfiguration configuration) : base(configuration) { } - public override Task Refine(CodeNamespace generatedCode, CancellationToken cancellationToken) - { - return Task.Run(() => - { - cancellationToken.ThrowIfCancellationRequested(); - var defaultConfiguration = new GenerationConfiguration(); - ConvertUnionTypesToWrapper(generatedCode, - _configuration.UsesBackingStore, - static s => s, - false); - CorrectCommonNames(generatedCode); - CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); - ReplaceIndexersByMethodsWithParameter(generatedCode, - false, - static x => $"by{x.ToFirstCharacterUpperCase()}", - static x => x.ToFirstCharacterLowerCase(), - GenerationLanguage.Dart); - AddQueryParameterExtractorMethod(generatedCode); - // This adds the BaseRequestBuilder class as a superclass - MoveRequestBuilderPropertiesToBaseType(generatedCode, - new CodeUsing - { - Name = "BaseRequestBuilder", - Declaration = new CodeType - { - Name = AbstractionsNamespaceName, - IsExternal = true, - } - }, addCurrentTypeAsGenericTypeParameter: true); - RemoveRequestConfigurationClasses(generatedCode, - new CodeUsing - { - Name = "RequestConfiguration", - Declaration = new CodeType - { - Name = AbstractionsNamespaceName, - IsExternal = true - } - }, new CodeType - { - Name = "DefaultQueryParameters", - IsExternal = true, - }); - var reservedNamesProvider = new DartReservedNamesProvider(); - CorrectNames(generatedCode, s => - { - if (s.Contains('_', StringComparison.OrdinalIgnoreCase) && - s.ToPascalCase(UnderscoreArray) is string refinedName && - !reservedNamesProvider.ReservedNames.Contains(s) && - !reservedNamesProvider.ReservedNames.Contains(refinedName)) - return refinedName; - else - return s; - }); - - MoveQueryParameterClass(generatedCode); - AddDefaultImports(generatedCode, defaultUsingEvaluators); - AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); - AddParsableImplementsForModelClasses(generatedCode, "Parsable"); - AddConstructorsForDefaultValues(generatedCode, true); - cancellationToken.ThrowIfCancellationRequested(); - AddAsyncSuffix(generatedCode); - AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); - - ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped", new HashSet { typeof(CodeEnumOption) }); - ReplaceDefaultSerializationModules( - generatedCode, - defaultConfiguration.Serializers, - new(StringComparer.OrdinalIgnoreCase) { - $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonSerializationWriterFactory", - $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextSerializationWriterFactory", - $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormSerializationWriterFactory", - // $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", - } - ); - ReplaceDefaultDeserializationModules( - generatedCode, - defaultConfiguration.Deserializers, - new(StringComparer.OrdinalIgnoreCase) { - $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonParseNodeFactory", - $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormParseNodeFactory", - $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextParseNodeFactory" - } - ); - AddSerializationModulesImport(generatedCode, - [$"{AbstractionsNamespaceName}.ApiClientBuilder", - $"{AbstractionsNamespaceName}.SerializationWriterFactoryRegistry"], - [$"{AbstractionsNamespaceName}.ParseNodeFactoryRegistry"]); - cancellationToken.ThrowIfCancellationRequested(); - - AddParentClassToErrorClasses( - generatedCode, - "ApiException", - AbstractionsNamespaceName - ); - DeduplicateErrorMappings(generatedCode); - RemoveCancellationParameter(generatedCode); - DisambiguatePropertiesWithClassNames(generatedCode); - RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder); - AddCustomMethods(generatedCode); - EscapeStringValues(generatedCode); - AliasUsingWithSameSymbol(generatedCode); - }, cancellationToken); - } - - /// - /// Corrects common names so they can be used with Dart. - /// This normally comes down to changing the first character to lower case. - /// GetFieldDeserializers is corrected to getFieldDeserializers - /// - private static void CorrectCommonNames(CodeElement currentElement) - { - if (currentElement is CodeMethod m && - currentElement.Parent is CodeClass parentClass) - { - parentClass.RenameChildElement(m.Name, m.Name.ToFirstCharacterLowerCase()); - } - else if (currentElement is CodeIndexer i) - { - i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); - } - CrawlTree(currentElement, element => CorrectCommonNames(element)); - } - - private static void CorrectMethodType(CodeMethod currentMethod) - { - if (currentMethod.IsOfKind(CodeMethodKind.Deserializer)) - { - currentMethod.ReturnType.Name = "Map"; - currentMethod.Name = "getFieldDeserializers"; - } - else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlConstructor)) - { - currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.RequestAdapter)) - .Where(x => x.Type.Name.StartsWith('I')) - .ToList() - .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" - } - } - - private static void CorrectPropertyType(CodeProperty currentProperty) - { - ArgumentNullException.ThrowIfNull(currentProperty); - - if (currentProperty.IsOfKind(CodePropertyKind.Options)) - currentProperty.DefaultValue = "List()"; - else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) - currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; - else if (currentProperty.IsOfKind(CodePropertyKind.RequestAdapter)) - { - currentProperty.Type.Name = "RequestAdapter"; - currentProperty.Type.IsNullable = true; - } - else if (currentProperty.IsOfKind(CodePropertyKind.BackingStore)) - { - currentProperty.Type.Name = currentProperty.Type.Name[1..]; // removing the "I" - currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); - } - else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameter)) - { - currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; - } - else if (currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) - { - currentProperty.Type.Name = "Map"; - currentProperty.DefaultValue = "{}"; - } - else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) - { - currentProperty.Type.IsNullable = true; - } - else if (currentProperty.IsOfKind(CodePropertyKind.PathParameters)) - { - currentProperty.Type.IsNullable = true; - currentProperty.Type.Name = "Map"; - if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) - currentProperty.DefaultValue = "{}"; - } - currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); - CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); - } - - private static void CorrectImplements(ProprietableBlockDeclaration block) - { - block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I - } - public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) - { - var genericParameterTypes = usingsToAdd.OfType().Where( - static codeType => codeType.Parent is CodeParameter parameter - && parameter.IsOfKind(CodeParameterKind.RequestConfiguration)).Select(x => x.GenericTypeParameterValues.First()); - - return usingsToAdd.Union(genericParameterTypes); - } - protected static void AddAsyncSuffix(CodeElement currentElement) - { - if (currentElement is CodeMethod currentMethod && currentMethod.IsAsync) - currentMethod.Name += "Async"; - CrawlTree(currentElement, AddAsyncSuffix); - } - private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "getQueryParameters") - { - if (currentElement is CodeClass currentClass && - currentClass.IsOfKind(CodeClassKind.QueryParameters)) - { - currentClass.StartBlock.AddImplements(new CodeType - { - IsExternal = true, - Name = "AbstractQueryParameters" - }); - currentClass.AddMethod(new CodeMethod - { - Name = methodName, - Access = AccessModifier.Public, - ReturnType = new CodeType - { - Name = "Map", - IsNullable = false, - }, - IsAsync = false, - IsStatic = false, - Kind = CodeMethodKind.QueryParametersMapper, - Documentation = new() - { - DescriptionTemplate = "Extracts the query parameters into a map for the URI template parsing.", - }, - }); - currentClass.AddUsing(new CodeUsing - { - Name = "AbstractQueryParameters", - Declaration = new CodeType { Name = AbstractionsNamespaceName, IsExternal = true }, - }); - } - CrawlTree(currentElement, x => AddQueryParameterExtractorMethod(x, methodName)); - } - - private void MoveQueryParameterClass(CodeElement currentElement) - { - if (currentElement is CodeClass currentClass && - currentClass.IsOfKind(CodeClassKind.RequestBuilder)) - { - var parentNamespace = currentClass.GetImmediateParentOfType(); - var nestedClasses = currentClass.InnerClasses.Where(x => x.IsOfKind(CodeClassKind.QueryParameters)); - foreach (CodeClass nestedClass in nestedClasses) - { - parentNamespace.AddClass(nestedClass); - currentClass.RemoveChildElementByName(nestedClass.Name); - } - } - CrawlTree(currentElement, x => MoveQueryParameterClass(x)); - } - - protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) - { - if (currentElement is CodeClass currentClass) - { - var sameNameProperty = currentClass.Properties - .FirstOrDefault(x => x.Name.Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase)); - if (sameNameProperty != null) - { - currentClass.RemoveChildElement(sameNameProperty); - if (string.IsNullOrEmpty(sameNameProperty.SerializationName)) - sameNameProperty.SerializationName = sameNameProperty.Name; - sameNameProperty.Name = $"{sameNameProperty.Name}Prop"; - currentClass.AddProperty(sameNameProperty); - } - } - CrawlTree(currentElement, DisambiguatePropertiesWithClassNames); - } - private void AddCustomMethods(CodeElement currentElement) - { - if (currentElement is CodeClass currentClass) - { - if (currentClass.IsOfKind(CodeClassKind.RequestBuilder)) - { - currentClass.AddMethod(new CodeMethod - { - Name = "clone", - Access = AccessModifier.Public, - ReturnType = new CodeType - { - Name = currentClass.Name, - IsNullable = false, - }, - IsAsync = false, - IsStatic = false, - - Kind = CodeMethodKind.Custom, - Documentation = new() - { - DescriptionTemplate = "Clones the requestbuilder.", - }, - }); - } - if (currentClass.IsOfKind(CodeClassKind.Model) && currentClass.IsErrorDefinition) - { - currentClass.AddMethod(new CodeMethod - { - Name = "copyWith", - Access = AccessModifier.Public, - ReturnType = new CodeType - { - Name = currentClass.Name, - IsNullable = false, - }, - IsAsync = false, - IsStatic = false, - - Kind = CodeMethodKind.Custom, - Documentation = new() - { - DescriptionTemplate = "Creates a copy of the object.", - }, - }); - } - } - CrawlTree(currentElement, x => AddCustomMethods(x)); - } - - private void EscapeStringValues(CodeElement currentElement) - { - if (currentElement is CodeProperty property && - property.IsOfKind(CodePropertyKind.UrlTemplate)) - { - if (property.DefaultValue.Contains('$', StringComparison.Ordinal)) - { - property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); - } - } - else if (currentElement is CodeProperty prop) - { - if (!String.IsNullOrEmpty(prop.SerializationName) && prop.SerializationName.Contains('$', StringComparison.Ordinal)) - { - prop.SerializationName = prop.SerializationName.Replace("$", "\\$", StringComparison.Ordinal); - } - } - CrawlTree(currentElement, EscapeStringValues); - } - - private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) { - - {"TimeSpan", ("Duration", null)}, - {"Guid", ("UuidValue", new CodeUsing { - Name = "UuidValue", - Declaration = new CodeType { - Name = "uuid/uuid", - IsExternal = true, - }, - })}, - }; - private static void AliasUsingWithSameSymbol(CodeElement currentElement) - { - if (currentElement is CodeClass currentClass && currentClass.StartBlock != null && currentClass.StartBlock.Usings.Any(x => !x.IsExternal)) - { - var duplicatedSymbolsUsings = currentClass.StartBlock.Usings - .Distinct(usingComparer) - .Where(static x => !string.IsNullOrEmpty(x.Declaration?.Name) && x.Declaration.TypeDefinition != null) - .GroupBy(static x => x.Declaration!.Name, StringComparer.OrdinalIgnoreCase) - .Where(x => x.Count() > 1) - .SelectMany(x => x) - .Union(currentClass.StartBlock - .Usings - .Where(x => !x.IsExternal) - .Where(x => x.Declaration! - .Name - .Equals(currentClass.Name, StringComparison.OrdinalIgnoreCase))); - foreach (var usingElement in duplicatedSymbolsUsings) - { - var replacement = string.Join("_", usingElement.Declaration!.TypeDefinition!.GetImmediateParentOfType().Name - .Split(".", StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.ToLowerInvariant()) - .ToArray()); - usingElement.Alias = $"{(string.IsNullOrEmpty(replacement) ? string.Empty : $"{replacement}")}_{usingElement.Declaration!.TypeDefinition!.Name.ToLowerInvariant()}"; - } - } - CrawlTree(currentElement, AliasUsingWithSameSymbol); - } -} diff --git a/src/Kiota.Builder/Refiners/ILanguageRefiner.cs b/src/Kiota.Builder/Refiners/ILanguageRefiner.cs index ed8efaf48f..5a1c23cd49 100644 --- a/src/Kiota.Builder/Refiners/ILanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/ILanguageRefiner.cs @@ -41,7 +41,7 @@ public static async Task Refine(GenerationConfiguration config, CodeNamespace ge await new PythonRefiner(config).Refine(generatedCode, cancellationToken).ConfigureAwait(false); break; case GenerationLanguage.Dart: - await new DartRefinerFromScratch(config).Refine(generatedCode, cancellationToken).ConfigureAwait(false); + await new DartRefiner(config).Refine(generatedCode, cancellationToken).ConfigureAwait(false); break; } } From 6b2cb3baabf3d6582a36f4595d4f748e2d5989a6 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 17 Oct 2024 12:59:33 +0200 Subject: [PATCH 092/194] Some fixes to intersection and union model and corrected an issue with constructors with default values --- .../Writers/Dart/CodeEnumWriter.cs | 9 +- .../Writers/Dart/CodeMethodWriter.cs | 88 +++++++++++-------- .../Writers/Dart/DartConventionService.cs | 8 ++ 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 9031cea3bc..a57ae33754 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -29,7 +29,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); - var correctedName = getCorrectedName(option.Name); + var correctedName = conventions.getCorrectedEnumName(option.Name); if (reservedNamesProvider.ReservedNames.Contains(correctedName) || IllegalEnumValue(correctedName)) { correctedName += "Escaped"; @@ -49,11 +49,4 @@ private bool IllegalEnumValue(string correctedName) { return correctedName.EqualsIgnoreCase("string") || correctedName.EqualsIgnoreCase("index"); } - - private string getCorrectedName(string name) - { - if (name.Contains('_', StringComparison.Ordinal)) - return name.ToLowerInvariant().ToCamelCase('_'); - return name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name; - } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 42c79d5059..d1032e8d5f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -156,32 +156,29 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla { writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); var includeElse = false; - if (parentClass.DiscriminatorInformation.HasBasicDiscriminatorInformation) + foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) + .OrderBy(static x => x, CodePropertyTypeForwardComparer) + .ThenBy(static x => x.Name, StringComparer.Ordinal)) { - foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) - .OrderBy(static x => x, CodePropertyTypeForwardComparer) - .ThenBy(static x => x.Name, StringComparer.Ordinal)) - { - if (property.Type is CodeType propertyType) - if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) - { - var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({mappedType.Key}.toUpperCase().equals({DiscriminatorMappingVarName}.toUpperCase())) {{"); - writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); - writer.CloseBlock(); - } - else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) - { - var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName}) {{"); - writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); - writer.CloseBlock(); - } - if (!includeElse) - includeElse = true; - } + if (property.Type is CodeType propertyType) + if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) + { + var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if('{mappedType.Key}' == {DiscriminatorMappingVarName}) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); + writer.CloseBlock(); + } + else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) + { + var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName}) {{"); + writer.IncreaseIndent(); + writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); + writer.CloseBlock(); + } + if (!includeElse) + includeElse = true; } writer.WriteLine($"return {ResultVarName};"); } @@ -230,7 +227,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas { var parseNodeParameter = codeElement.Parameters.OfKind(CodeParameterKind.ParseNode) ?? throw new InvalidOperationException("Factory method should have a ParseNode parameter"); - if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType && parentClass.DiscriminatorInformation.HasBasicDiscriminatorInformation) + if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) { var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; @@ -289,20 +286,33 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } else { - foreach (var propWithDefault in parentClass - .Properties - .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters)) - // do not apply the default value if the type is composed as the default value may not necessarily which type to use - .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) - .OrderByDescending(static x => x.Kind) - .ThenBy(static x => x.Name)) + var separator = ','; + var propWithDefaults = parentClass.Properties + .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters)) + // do not apply the default value if the type is composed as the default value may not necessarily which type to use + .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) + .OrderByDescending(static x => x.Kind) + .ThenBy(static x => x.Name).ToArray(); + var lastOption = propWithDefaults.LastOrDefault(); + + foreach (var propWithDefault in propWithDefaults) { var defaultValue = propWithDefault.DefaultValue; + if (propWithDefault == lastOption) + { + separator = ';'; + } if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) { - defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; + defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')); + defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; + } + else if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) + { + defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')); + defaultValue = $"'{defaultValue}'"; } - writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue};"); + writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue}{separator}"); } if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && @@ -381,7 +391,7 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La .ToArray(); foreach (CodeProperty prop in complexProperties) { - writer.WriteLine($"if({prop.Name.ToFirstCharacterLowerCase()} != null){{{DeserializerName}.addAll({prop.Name.ToFirstCharacterLowerCase()}!.getFieldDeserializers());}}"); + writer.WriteLine($"if({prop.Name.ToFirstCharacterLowerCase()} != null){{{prop.Name.ToFirstCharacterLowerCase()}!.getFieldDeserializers().forEach((k,v) => {DeserializerName}.putIfAbsent(k, ()=>v));}}"); } writer.WriteLine($"return {DeserializerName};"); } @@ -591,11 +601,13 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas writer.WriteLine("else {"); writer.IncreaseIndent(); } - var propertiesNames = complexProperties + var firstPropertyName = complexProperties.First().Name.ToFirstCharacterLowerCase(); + var propertiesNames = complexProperties.Skip(0) .Select(static x => x.Name.ToFirstCharacterLowerCase()) .OrderBy(static x => x) .Aggregate(static (x, y) => $"{x}, {y}"); - writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {propertiesNames});"); + var propertiesList = string.IsNullOrEmpty(propertiesNames) ? "" : $", [{propertiesNames}]"; + writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {firstPropertyName}{propertiesList});"); if (includeElse) { writer.CloseBlock(); diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index b1f1491ff3..b63475a5ff 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -352,4 +352,12 @@ public bool ErrorClassPropertyExistsInSuperClass(CodeProperty codeElement) { return codeElement?.Parent is CodeClass parentClass && parentClass.IsErrorDefinition && ErrorClassProperties.Contains(codeElement.Name); } + + public string getCorrectedEnumName(string name) + { + ArgumentNullException.ThrowIfNull(name); + if (name.Contains('_', StringComparison.Ordinal)) + return name.ToLowerInvariant().ToCamelCase('_'); + return name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name; + } } From d9d056f261f3d4cc41aa7a2c570b1f66f7cdabc9 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 17 Oct 2024 15:45:17 +0200 Subject: [PATCH 093/194] Type for errormapping to avoid compile errors for custom error classes --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index d1032e8d5f..d156dd509f 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -466,7 +466,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.WriteLine($"var {errorMappingVarName} = {{"); + writer.WriteLine($"Map> {errorMappingVarName} = {{"); writer.IncreaseIndent(); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { From 86abc1c8bcfbba65cbfa7c7a199ce3a803af5013 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 18 Oct 2024 07:41:53 +0200 Subject: [PATCH 094/194] Method was renamed --- src/Kiota.Builder/Refiners/DartRefiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index b19d8016ad..e91ecb7d01 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -250,7 +250,7 @@ protected static void AddAsyncSuffix(CodeElement currentElement) currentMethod.Name += "Async"; CrawlTree(currentElement, AddAsyncSuffix); } - private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "getQueryParameters") + private void AddQueryParameterExtractorMethod(CodeElement currentElement, string methodName = "toMap") { if (currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.QueryParameters)) From 31bc7dd0c23a37c2d3e5a18f915a2db957dd0288 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 18 Oct 2024 09:24:42 +0200 Subject: [PATCH 095/194] Use serialization name for enums, untypednodes should also have factory argument --- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 2 +- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index a57ae33754..fe637a9a76 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -39,7 +39,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write correctedName = option.Name; usedNames.Add(correctedName); } - writer.WriteLine($"{correctedName}(\"{option.Name}\"){(option == lastOption ? ";" : ",")}"); + writer.WriteLine($"{correctedName}(\"{option.SerializationName}\"){(option == lastOption ? ";" : ",")}"); } writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index d156dd509f..65eea7247e 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -304,7 +304,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) { - defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')); + defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')).CleanupSymbolName(); defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; } else if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) @@ -475,7 +475,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re writer.CloseBlock("};"); } var returnTypeCodeType = codeElement.ReturnType as CodeType; - var returnTypeFactory = returnTypeCodeType?.TypeDefinition is CodeClass + var returnTypeFactory = returnTypeCodeType?.TypeDefinition is CodeClass || (returnTypeCodeType != null && returnTypeCodeType.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)) ? $", {returnTypeWithoutCollectionInformation}.createFromDiscriminatorValue" : null; var prefix = (isVoid, codeElement.ReturnType.IsCollection) switch From b6cf3654239318bf305e11a2d97944fb3474def6 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 18 Oct 2024 10:22:49 +0200 Subject: [PATCH 096/194] Requestexecutur should always return await --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 65eea7247e..c941bdfd4c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -478,15 +478,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re var returnTypeFactory = returnTypeCodeType?.TypeDefinition is CodeClass || (returnTypeCodeType != null && returnTypeCodeType.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)) ? $", {returnTypeWithoutCollectionInformation}.createFromDiscriminatorValue" : null; - var prefix = (isVoid, codeElement.ReturnType.IsCollection) switch - { - (true, _) => string.Empty, - (_, true) => "var collectionResult = ", - (_, _) => "return ", - }; - writer.WriteLine($"{prefix}await requestAdapter.{GetSendRequestMethodName(isVoid, codeElement, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, {errorMappingVarName});"); - if (codeElement.ReturnType.IsCollection) - writer.WriteLine("return collectionResult?.toList();"); + writer.WriteLine($"return await requestAdapter.{GetSendRequestMethodName(isVoid, codeElement, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, {errorMappingVarName});"); } private const string RequestInfoVarName = "requestInfo"; private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams requestParams, CodeClass currentClass, LanguageWriter writer) @@ -629,7 +621,7 @@ protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElemen if (isVoid) return "sendNoContent"; else if (isStream || conventions.IsPrimitiveType(returnTypeName) || isEnum) if (returnType.IsCollection) - return $"sendPrimitiveCollection<{returnTypeName}>"; + return $"sendPrimitiveCollection<{returnTypeName.TrimEnd('?')}>"; else return $"sendPrimitive<{returnTypeName}>"; else if (returnType.IsCollection) return $"sendCollection<{returnTypeName}>"; From 11721b82a3c7c0d1fae2d85ad3d802e80ad7f854 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 18 Oct 2024 11:08:30 +0200 Subject: [PATCH 097/194] Use single quotes instead of double, simplified escaping dollar sign in property --- src/Kiota.Builder/Refiners/DartRefiner.cs | 14 +++++------- .../Writers/Dart/CodeMethodWriter.cs | 22 +++++++++---------- .../Writers/Dart/CodePropertyWriter.cs | 2 +- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index e91ecb7d01..25e4425a2a 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -371,19 +371,15 @@ private void AddCustomMethods(CodeElement currentElement) private void EscapeStringValues(CodeElement currentElement) { - if (currentElement is CodeProperty property && - property.IsOfKind(CodePropertyKind.UrlTemplate)) + if (currentElement is CodeProperty property) { - if (property.DefaultValue.Contains('$', StringComparison.Ordinal)) + if (!String.IsNullOrEmpty(property.SerializationName) && property.SerializationName.Contains('$', StringComparison.Ordinal)) { - property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); + property.SerializationName = property.SerializationName.Replace("$", "\\$", StringComparison.Ordinal); } - } - else if (currentElement is CodeProperty prop) - { - if (!String.IsNullOrEmpty(prop.SerializationName) && prop.SerializationName.Contains('$', StringComparison.Ordinal)) + if (property.DefaultValue.Contains('$', StringComparison.Ordinal)) { - prop.SerializationName = prop.SerializationName.Replace("$", "\\$", StringComparison.Ordinal); + property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); } } CrawlTree(currentElement, EscapeStringValues); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index c941bdfd4c..2c6e033c6c 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -146,7 +146,7 @@ private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, Cod writer.StartBlock($"return switch({DiscriminatorMappingVarName}) {{"); foreach (var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings) { - writer.WriteLine($"\"{mappedType.Key}\" => {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); + writer.WriteLine($"'{mappedType.Key}' => {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); } writer.WriteLine($"_ => {parentClass.Name.ToFirstCharacterUpperCase()}(),"); writer.CloseBlock("};"); @@ -231,7 +231,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas { var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; - writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode(\"{discriminatorPropertyName}\")?.getStringValue();"); + writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); } if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) @@ -264,10 +264,10 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me if (!string.IsNullOrEmpty(method.BaseUrl)) { writer.StartBlock($"if ({requestAdapterPropertyName}.baseUrl == null || {requestAdapterPropertyName}.baseUrl!.isEmpty) {{"); - writer.WriteLine($"{requestAdapterPropertyName}.baseUrl = \"{method.BaseUrl}\";"); + writer.WriteLine($"{requestAdapterPropertyName}.baseUrl = '{method.BaseUrl}';"); writer.CloseBlock(); if (pathParametersProperty != null) - writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterLowerCase()}[\"baseurl\"] = {requestAdapterPropertyName}.baseUrl;"); + writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterLowerCase()}['baseurl'] = {requestAdapterPropertyName}.baseUrl;"); } if (backingStoreParameter != null) writer.WriteLine($"{requestAdapterPropertyName}.EnableBackingStore({backingStoreParameter.Name});"); @@ -470,7 +470,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re writer.IncreaseIndent(); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { - writer.WriteLine($"\"{errorMapping.Key.ToUpperInvariant()}\" : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); + writer.WriteLine($"'{errorMapping.Key.ToUpperInvariant()}' : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); } writer.CloseBlock("};"); } @@ -497,7 +497,7 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req } if (codeElement.ShouldAddAcceptHeader) - writer.WriteLine($"{RequestInfoVarName}.headers.put(\"Accept\", \"{codeElement.AcceptHeaderValue}\");"); + writer.WriteLine($"{RequestInfoVarName}.headers.put('Accept', '{codeElement.AcceptHeaderValue}');"); if (requestParams.requestBody != null) { var suffix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty; @@ -506,13 +506,13 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req if (requestParams.requestContentType is not null) writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name});"); else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType)) - writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");"); + writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, '{codeElement.RequestBodyContentType}');"); } else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty) if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase))) - writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, '{codeElement.RequestBodyContentType}', {requestParams.requestBody.Name});"); else - writer.WriteLine($"{RequestInfoVarName}.setContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, '{codeElement.RequestBodyContentType}', {requestParams.requestBody.Name});"); } writer.WriteLine($"return {RequestInfoVarName};"); @@ -546,7 +546,7 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me { secondArgument = $", (e) => e?.value"; } - writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()}{secondArgument});"); + writer.WriteLine($"writer.{serializationMethodName}('{otherProp.WireName}', {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()}{secondArgument});"); } } private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) @@ -765,7 +765,7 @@ private void WriteQueryparametersBody(CodeClass parentClass, CodeMethod codeElem writer.IncreaseIndent(); foreach (CodeProperty property in parentClass.Properties) { - writer.WriteLine($"\"{property.Name}\" : {property.Name.ToFirstCharacterLowerCase()},"); + writer.WriteLine($"'{property.Name}' : {property.Name.ToFirstCharacterLowerCase()},"); } writer.DecreaseIndent(); writer.WriteLine("};"); diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 708799b350..2bc6258e25 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -77,7 +77,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ writer.WriteLine("@override"); goto default; case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped: - writer.WriteLine($"/// @QueryParameter(\"{codeElement.SerializationName}\")"); + writer.WriteLine($"/// @QueryParameter('{codeElement.SerializationName}')"); goto default; case CodePropertyKind.QueryParameters: defaultValue = $" = {propertyType}()"; From 5a121a236ede88891240c4b3c487dcc8593f65ab Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 22 Oct 2024 11:19:58 +0200 Subject: [PATCH 098/194] Added refiner test for dart --- src/Kiota.Builder/Refiners/DartRefiner.cs | 17 +- .../Writers/Dart/DartConventionService.cs | 1 - .../GenerateSample.cs | 2 +- .../Refiners/DartLanguageRefinerTests.cs | 435 ++++++++++++++++++ 4 files changed, 452 insertions(+), 3 deletions(-) create mode 100644 tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 25e4425a2a..ef0ef342a9 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -37,6 +37,8 @@ public class DartRefiner : CommonLanguageRefiner, ILanguageRefiner AbstractionsNamespaceName, "ParseNodeHelper"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Headers), AbstractionsNamespaceName, "RequestHeaders"), + new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase), + AbstractionsNamespaceName, KiotaBuilder.UntypedNodeName), new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator) && method.Parameters.Any(static y => y.IsOfKind(CodeParameterKind.RequestBody) && y.Type.Name.Equals(MultipartBodyClassName, StringComparison.OrdinalIgnoreCase)), AbstractionsNamespaceName, MultipartBodyClassName), }; @@ -176,7 +178,15 @@ private static void CorrectCommonNames(CodeElement currentElement) private static void CorrectMethodType(CodeMethod currentMethod) { - if (currentMethod.IsOfKind(CodeMethodKind.Deserializer)) + if (currentMethod.IsOfKind(CodeMethodKind.Serializer)) + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Serializer)).ToList().ForEach(x => + { + x.Optional = false; + x.Type.IsNullable = true; + if (x.Type.Name.StartsWith('I')) + x.Type.Name = x.Type.Name[1..]; + }); + else if (currentMethod.IsOfKind(CodeMethodKind.Deserializer)) { currentMethod.ReturnType.Name = "Map"; currentMethod.Name = "getFieldDeserializers"; @@ -188,6 +198,10 @@ private static void CorrectMethodType(CodeMethod currentMethod) .ToList() .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" } + CorrectCoreTypes(currentMethod.Parent as CodeClass, DateTypesReplacements, currentMethod.Parameters + .Select(static x => x.Type) + .Union(new[] { currentMethod.ReturnType }) + .ToArray()); } private static void CorrectPropertyType(CodeProperty currentProperty) @@ -388,6 +402,7 @@ private void EscapeStringValues(CodeElement currentElement) private static readonly Dictionary DateTypesReplacements = new(StringComparer.OrdinalIgnoreCase) { {"TimeSpan", ("Duration", null)}, + {"DateTimeOffset", ("DateTime", null)}, {"Guid", ("UuidValue", new CodeUsing { Name = "UuidValue", Declaration = new CodeType { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index b63475a5ff..7e349cd60e 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -299,7 +299,6 @@ public override string TranslateType(CodeType type) "double" or "float" or "decimal" => "double", "object" or "void" => type.Name.ToLowerInvariant(),// little casing hack "binary" or "base64" or "base64url" => "Iterable", - "datetimeoffset" => "DateTime", string s when s.Contains("RequestConfiguration", StringComparison.OrdinalIgnoreCase) => "RequestConfiguration", "iparsenode" => "ParseNode", "iserializationwriter" => "SerializationWriter", diff --git a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs index cecc8891b6..dfe04fa287 100644 --- a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs +++ b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs @@ -211,7 +211,7 @@ public async Task GeneratesUritemplateHints(GenerationLanguage language) Assert.Contains("[QueryParameter(\"startDateTime\")]", fullText); break; case GenerationLanguage.Dart: - Assert.Contains("\"EndDateTime\" : endDateTime", fullText); + Assert.Contains("'EndDateTime' : endDateTime", fullText); break; case GenerationLanguage.Go: Assert.Contains("`uriparametername:\"startDateTime\"`", fullText); diff --git a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs new file mode 100644 index 0000000000..d18b965d0b --- /dev/null +++ b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs @@ -0,0 +1,435 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Configuration; +using Kiota.Builder.Extensions; +using Kiota.Builder.Refiners; + +using Xunit; + +namespace Kiota.Builder.Tests.Refiners; +public class DartLanguageRefinerTests +{ + private readonly CodeNamespace root = CodeNamespace.InitRootNamespace(); + #region CommonLanguageRefinerTests + [Fact] + public async Task AddsExceptionInheritanceOnErrorClasses() + { + var model = root.AddClass(new CodeClass + { + Name = "somemodel", + Kind = CodeClassKind.Model, + IsErrorDefinition = true, + }).First(); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + + var declaration = model.StartBlock; + + Assert.Contains("ApiException", declaration.Usings.Select(x => x.Name)); + Assert.Equal("ApiException", declaration.Inherits.Name); + } + [Fact] + public async Task AddsUsingsForErrorTypesForRequestExecutor() + { + var requestBuilder = root.AddClass(new CodeClass + { + Name = "somerequestbuilder", + Kind = CodeClassKind.RequestBuilder, + }).First(); + var subNS = root.AddNamespace($"{root.Name}.subns"); // otherwise the import gets trimmed + var errorClass = subNS.AddClass(new CodeClass + { + Name = "Error4XX", + Kind = CodeClassKind.Model, + IsErrorDefinition = true, + }).First(); + var requestExecutor = requestBuilder.AddMethod(new CodeMethod + { + Name = "get", + Kind = CodeMethodKind.RequestExecutor, + ReturnType = new CodeType + { + Name = "string" + }, + }).First(); + requestExecutor.AddErrorMapping("4XX", new CodeType + { + Name = "Error4XX", + TypeDefinition = errorClass, + }); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + + var declaration = requestBuilder.StartBlock; + + Assert.Contains("Error4XX", declaration.Usings.Select(x => x.Declaration?.Name)); + } + [Fact] + public async Task EscapesReservedKeywordsInInternalDeclaration() + { + var model = root.AddClass(new CodeClass + { + Name = "break", + Kind = CodeClassKind.Model + }).First(); + var nUsing = new CodeUsing + { + Name = "some.ns", + }; + nUsing.Declaration = new CodeType + { + IsExternal = false, + TypeDefinition = model + }; + model.AddUsing(nUsing); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.NotEqual("break", nUsing.Declaration.Name, StringComparer.OrdinalIgnoreCase); + Assert.Contains("Escaped", nUsing.Declaration.Name); + } + [Fact] + public async Task EscapesReservedKeywords() + { + var model = root.AddClass(new CodeClass + { + Name = "break", + Kind = CodeClassKind.Model + }).First(); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.NotEqual("break", model.Name, StringComparer.OrdinalIgnoreCase); + Assert.Contains("Escaped", model.Name); + } + [Fact] + public async Task AddsDefaultImports() + { + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model + }).First(); + var requestBuilder = root.AddClass(new CodeClass + { + Name = "rb", + Kind = CodeClassKind.RequestBuilder, + }).First(); + requestBuilder.AddMethod(new CodeMethod + { + Name = "get", + Kind = CodeMethodKind.RequestExecutor, + ReturnType = new CodeType + { + Name = "string", + }, + }); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.NotEmpty(model.StartBlock.Usings); + Assert.NotEmpty(requestBuilder.StartBlock.Usings); + } + [Fact] + public async Task ReplacesDateTimeOffsetByNativeType() + { + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model + }).First(); + var method = model.AddMethod(new CodeMethod + { + Name = "method", + ReturnType = new CodeType + { + Name = "DateTimeOffset" + }, + }).First(); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.NotEmpty(model.StartBlock.Usings); + Assert.Equal("DateTime", method.ReturnType.Name); + } + [Fact] + public async Task ReplacesTimeSpanByNativeType() + { + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model + }).First(); + var method = model.AddMethod(new CodeMethod + { + Name = "method", + ReturnType = new CodeType + { + Name = "TimeSpan" + }, + }).First(); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.NotEmpty(model.StartBlock.Usings); + Assert.Equal("Duration", method.ReturnType.Name); + } + [Fact] + public async Task ReplacesIndexersByMethodsWithParameter() + { + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model + }).First(); + var collectionNS = root.AddNamespace("collection"); + var itemsNs = collectionNS.AddNamespace($"{collectionNS.Name}.items"); + var requestBuilder = itemsNs.AddClass(new CodeClass + { + Name = "requestBuilder", + Kind = CodeClassKind.RequestBuilder + }).First(); + requestBuilder.AddProperty(new CodeProperty + { + Name = "urlTemplate", + DefaultValue = "path", + Kind = CodePropertyKind.UrlTemplate, + Type = new CodeType + { + Name = "string", + } + }); + requestBuilder.AddIndexer(new CodeIndexer + { + Name = "idx", + ReturnType = new CodeType + { + Name = requestBuilder.Name, + TypeDefinition = requestBuilder, + }, + IndexParameter = new() + { + Name = "id", + Type = new CodeType + { + Name = "string", + }, + } + }); + var collectionRequestBuilder = collectionNS.AddClass(new CodeClass + { + Name = "CollectionRequestBuilder", + Kind = CodeClassKind.RequestBuilder, + }).First(); + collectionRequestBuilder.AddProperty(new CodeProperty + { + Name = "collection", + Kind = CodePropertyKind.RequestBuilder, + Type = new CodeType + { + Name = requestBuilder.Name, + TypeDefinition = requestBuilder, + }, + }); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.Single(requestBuilder.Properties); + Assert.Empty(requestBuilder.GetChildElements(true).OfType()); + Assert.Single(requestBuilder.Methods.Where(static x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility))); + Assert.Single(collectionRequestBuilder.Properties); + } + [Fact] + public async Task DoesNotKeepCancellationParametersInRequestExecutors() + { + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.RequestBuilder + }).First(); + var method = model.AddMethod(new CodeMethod + { + Name = "getMethod", + Kind = CodeMethodKind.RequestExecutor, + ReturnType = new CodeType + { + Name = "string" + } + }).First(); + var cancellationParam = new CodeParameter + { + Name = "cancellationToken", + Optional = true, + Kind = CodeParameterKind.Cancellation, + Documentation = new() + { + DescriptionTemplate = "Cancellation token to use when cancelling requests", + }, + Type = new CodeType { Name = "CancellationToken", IsExternal = true }, + }; + method.AddParameter(cancellationParam); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.False(method.Parameters.Any()); + Assert.DoesNotContain(cancellationParam, method.Parameters); + } + [Fact] + public async Task NormalizeInheritedClassesNames() + { + var parentModel = root.AddClass(new CodeClass + { + Name = "parent_Model", + Kind = CodeClassKind.Model, + }).First(); + var implementsModel = root.AddClass(new CodeClass + { + Name = "implements_Model", + Kind = CodeClassKind.Model, + }).First(); + var childModel = root.AddClass(new CodeClass + { + Name = "childModel", + Kind = CodeClassKind.Model, + }).First(); + childModel.StartBlock.Inherits = new CodeType + { + Name = "parent_Model", + TypeDefinition = parentModel, + }; + childModel.StartBlock.AddImplements(new CodeType + { + Name = "implements_Model", + TypeDefinition = implementsModel, + }); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.Equal("ParentModel", childModel.StartBlock.Inherits.Name); + Assert.Equal("ImplementsModel", childModel.StartBlock.Implements.First().Name); + } + #endregion + #region DartLanguageRefinerTests + [Fact] + public async Task CorrectsCoreType() + { + const string requestAdapterDefaultName = "IRequestAdapter"; + const string factoryDefaultName = "ISerializationWriterFactory"; + const string deserializeDefaultName = "IDictionary>"; + const string dateTimeOffsetDefaultName = "DateTimeOffset"; + const string additionalDataDefaultName = "new Dictionary()"; + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model + }).First(); + model.AddProperty(new() + { + Name = "core", + Kind = CodePropertyKind.RequestAdapter, + Type = new CodeType + { + Name = requestAdapterDefaultName + } + }, new() + { + Name = "someDate", + Kind = CodePropertyKind.Custom, + Type = new CodeType + { + Name = dateTimeOffsetDefaultName, + } + }, new() + { + Name = "additionalData", + Kind = CodePropertyKind.AdditionalData, + Type = new CodeType + { + Name = additionalDataDefaultName + } + }); + const string additionalDataHolderDefaultName = "IAdditionalDataHolder"; + model.StartBlock.AddImplements(new CodeType + { + Name = additionalDataHolderDefaultName, + IsExternal = true, + }); + var executorMethod = model.AddMethod(new CodeMethod + { + Name = "executor", + Kind = CodeMethodKind.RequestExecutor, + ReturnType = new CodeType + { + Name = "string" + } + }, new() + { + Name = "deserializeFields", + ReturnType = new CodeType + { + Name = deserializeDefaultName, + }, + Kind = CodeMethodKind.Deserializer + }).First(); + const string serializerDefaultName = "ISerializationWriter"; + var serializationMethod = model.AddMethod(new CodeMethod + { + Name = "serialization", + Kind = CodeMethodKind.Serializer, + ReturnType = new CodeType + { + Name = "string" + } + }).First(); + serializationMethod.AddParameter(new CodeParameter + { + Name = "handler", + Kind = CodeParameterKind.Serializer, + Type = new CodeType + { + Name = serializerDefaultName, + } + }); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + Assert.DoesNotContain(model.Properties, static x => requestAdapterDefaultName.Equals(x.Type.Name)); + Assert.DoesNotContain(model.Properties, static x => factoryDefaultName.Equals(x.Type.Name)); + Assert.DoesNotContain(model.Properties, static x => dateTimeOffsetDefaultName.Equals(x.Type.Name)); + Assert.DoesNotContain(model.Properties, static x => additionalDataDefaultName.Equals(x.Type.Name)); + Assert.DoesNotContain(model.Methods, static x => deserializeDefaultName.Equals(x.ReturnType.Name)); + Assert.DoesNotContain(model.Methods.SelectMany(static x => x.Parameters), static x => serializerDefaultName.Equals(x.Type.Name)); + Assert.DoesNotContain(model.StartBlock.Implements, static x => additionalDataHolderDefaultName.Equals(x.Name, StringComparison.OrdinalIgnoreCase)); + Assert.Contains(additionalDataHolderDefaultName[1..], model.StartBlock.Implements.Select(static x => x.Name).ToList()); + } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task AddsUsingForUntypedNode(bool usesBackingStore) + { + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model + }).First(); + var property = model.AddProperty(new CodeProperty + { + Name = "property", + Type = new CodeType + { + Name = KiotaBuilder.UntypedNodeName, + IsExternal = true + }, + }).First(); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart, UsesBackingStore = usesBackingStore }, root); + Assert.Equal(KiotaBuilder.UntypedNodeName, property.Type.Name); + Assert.NotEmpty(model.StartBlock.Usings); + var nodeUsing = model.StartBlock.Usings.Where(static declaredUsing => declaredUsing.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)).ToArray(); + Assert.Single(nodeUsing); + Assert.Equal("kiota_abstractions/kiota_abstractions", nodeUsing[0].Declaration.Name); + } + [Fact] + public async Task AddsCustomMethods() + { + var builder = root.AddClass(new CodeClass + { + Name = "builder", + Kind = CodeClassKind.RequestBuilder + }).First(); + var model = root.AddClass(new CodeClass + { + Name = "model", + Kind = CodeClassKind.Model, + IsErrorDefinition = true, + }).First(); + + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + var buildermethods = builder.Methods; + var modelmethods = model.Methods; + Assert.Contains(buildermethods, x => x.IsOfKind(CodeMethodKind.Custom) && x.Name.Equals("clone", StringComparison.Ordinal)); + Assert.Contains(modelmethods, x => x.IsOfKind(CodeMethodKind.Custom) && x.Name.Equals("copyWith", StringComparison.Ordinal)); + } + #endregion +} From 134b76240ba01956c5f25cb228a0f0ab8efcb14a Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 22 Oct 2024 13:26:50 +0200 Subject: [PATCH 099/194] Fix compile errors after update with main --- src/Kiota.Builder/Refiners/DartRefiner.cs | 2 +- .../Refiners/ILanguageRefiner.cs | 2 +- .../Writers/Dart/DartConventionService.cs | 2 +- .../Refiners/DartLanguageRefinerTests.cs | 28 +++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index ef0ef342a9..c7480d73e0 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -45,7 +45,7 @@ public class DartRefiner : CommonLanguageRefiner, ILanguageRefiner public DartRefiner(GenerationConfiguration configuration) : base(configuration) { } - public override Task Refine(CodeNamespace generatedCode, CancellationToken cancellationToken) + public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken cancellationToken) { return Task.Run(() => { diff --git a/src/Kiota.Builder/Refiners/ILanguageRefiner.cs b/src/Kiota.Builder/Refiners/ILanguageRefiner.cs index af47362820..37b42e51cb 100644 --- a/src/Kiota.Builder/Refiners/ILanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/ILanguageRefiner.cs @@ -41,7 +41,7 @@ public static async Task RefineAsync(GenerationConfiguration config, CodeNamespa await new PythonRefiner(config).RefineAsync(generatedCode, cancellationToken).ConfigureAwait(false); break; case GenerationLanguage.Dart: - await new DartRefiner(config).Refine(generatedCode, cancellationToken).ConfigureAwait(false); + await new DartRefiner(config).RefineAsync(generatedCode, cancellationToken).ConfigureAwait(false); break; } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 7e349cd60e..72fbf1f807 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -206,7 +206,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i collectionPrefix = "List<"; } var collectionSuffix = currentType.CollectionKind == CodeTypeCollectionKind.None || !includeCollectionInformation ? string.Empty : ">"; - var genericParameters = currentType.GenericTypeParameterValues.Count != 0 ? + var genericParameters = currentType.GenericTypeParameterValues.Any() ? $"<{string.Join(", ", currentType.GenericTypeParameterValues.Select(x => GetTypeString(x, targetElement, includeCollectionInformation)))}>" : string.Empty; if (currentType.ActionOf && includeActionInformation) diff --git a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs index d18b965d0b..08d1288441 100644 --- a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs @@ -22,7 +22,7 @@ public async Task AddsExceptionInheritanceOnErrorClasses() Kind = CodeClassKind.Model, IsErrorDefinition = true, }).First(); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); var declaration = model.StartBlock; @@ -58,7 +58,7 @@ public async Task AddsUsingsForErrorTypesForRequestExecutor() Name = "Error4XX", TypeDefinition = errorClass, }); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); var declaration = requestBuilder.StartBlock; @@ -82,7 +82,7 @@ public async Task EscapesReservedKeywordsInInternalDeclaration() TypeDefinition = model }; model.AddUsing(nUsing); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEqual("break", nUsing.Declaration.Name, StringComparer.OrdinalIgnoreCase); Assert.Contains("Escaped", nUsing.Declaration.Name); } @@ -94,7 +94,7 @@ public async Task EscapesReservedKeywords() Name = "break", Kind = CodeClassKind.Model }).First(); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEqual("break", model.Name, StringComparer.OrdinalIgnoreCase); Assert.Contains("Escaped", model.Name); } @@ -120,7 +120,7 @@ public async Task AddsDefaultImports() Name = "string", }, }); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEmpty(model.StartBlock.Usings); Assert.NotEmpty(requestBuilder.StartBlock.Usings); } @@ -140,7 +140,7 @@ public async Task ReplacesDateTimeOffsetByNativeType() Name = "DateTimeOffset" }, }).First(); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEmpty(model.StartBlock.Usings); Assert.Equal("DateTime", method.ReturnType.Name); } @@ -160,7 +160,7 @@ public async Task ReplacesTimeSpanByNativeType() Name = "TimeSpan" }, }).First(); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEmpty(model.StartBlock.Usings); Assert.Equal("Duration", method.ReturnType.Name); } @@ -221,10 +221,10 @@ public async Task ReplacesIndexersByMethodsWithParameter() TypeDefinition = requestBuilder, }, }); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.Single(requestBuilder.Properties); Assert.Empty(requestBuilder.GetChildElements(true).OfType()); - Assert.Single(requestBuilder.Methods.Where(static x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility))); + Assert.Single(requestBuilder.Methods, static x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility)); Assert.Single(collectionRequestBuilder.Properties); } [Fact] @@ -256,7 +256,7 @@ public async Task DoesNotKeepCancellationParametersInRequestExecutors() Type = new CodeType { Name = "CancellationToken", IsExternal = true }, }; method.AddParameter(cancellationParam); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.False(method.Parameters.Any()); Assert.DoesNotContain(cancellationParam, method.Parameters); } @@ -288,7 +288,7 @@ public async Task NormalizeInheritedClassesNames() Name = "implements_Model", TypeDefinition = implementsModel, }); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.Equal("ParentModel", childModel.StartBlock.Inherits.Name); Assert.Equal("ImplementsModel", childModel.StartBlock.Implements.First().Name); } @@ -374,7 +374,7 @@ public async Task CorrectsCoreType() Name = serializerDefaultName, } }); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.DoesNotContain(model.Properties, static x => requestAdapterDefaultName.Equals(x.Type.Name)); Assert.DoesNotContain(model.Properties, static x => factoryDefaultName.Equals(x.Type.Name)); Assert.DoesNotContain(model.Properties, static x => dateTimeOffsetDefaultName.Equals(x.Type.Name)); @@ -403,7 +403,7 @@ public async Task AddsUsingForUntypedNode(bool usesBackingStore) IsExternal = true }, }).First(); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart, UsesBackingStore = usesBackingStore }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart, UsesBackingStore = usesBackingStore }, root); Assert.Equal(KiotaBuilder.UntypedNodeName, property.Type.Name); Assert.NotEmpty(model.StartBlock.Usings); var nodeUsing = model.StartBlock.Usings.Where(static declaredUsing => declaredUsing.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)).ToArray(); @@ -425,7 +425,7 @@ public async Task AddsCustomMethods() IsErrorDefinition = true, }).First(); - await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); var buildermethods = builder.Methods; var modelmethods = model.Methods; Assert.Contains(buildermethods, x => x.IsOfKind(CodeMethodKind.Custom) && x.Name.Equals("clone", StringComparison.Ordinal)); From 48e729897c6b00b8785739d49610e5f954a29c2f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 22 Oct 2024 15:06:10 +0200 Subject: [PATCH 100/194] Add dart to code generation it --- it/dart/.gitignore | 3 +++ it/dart/pubspec.yaml | 40 +++++++++++++++++++++++++++++++++ it/get-additional-arguments.ps1 | 3 +++ 3 files changed, 46 insertions(+) create mode 100644 it/dart/.gitignore create mode 100644 it/dart/pubspec.yaml diff --git a/it/dart/.gitignore b/it/dart/.gitignore new file mode 100644 index 0000000000..4f66d2275a --- /dev/null +++ b/it/dart/.gitignore @@ -0,0 +1,3 @@ +pubspec.lock +.dart_tool/ +src/ \ No newline at end of file diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml new file mode 100644 index 0000000000..ad6ce900da --- /dev/null +++ b/it/dart/pubspec.yaml @@ -0,0 +1,40 @@ +name: kiota_dart_generate +description: api generation +version: 0.0.1 +publish_to: none + +environment: + sdk: ^3.4.4 + +# Add regular dependencies here. +dependencies: + kiota_abstractions: + git: + url: https://github.com/kiota-community/dart_kiota.git + ref: json + path: packages/kiota_abstractions + kiota_http: + git: + url: https://github.com/kiota-community/dart_kiota.git + ref: json + path: packages/kiota_http + kiota_serialization_form: + git: + url: https://github.com/kiota-community/dart_kiota.git + ref: json + path: packages/kiota_serialization_form + kiota_serialization_text: + git: + url: https://github.com/kiota-community/dart_kiota.git + ref: json + path: packages/kiota_serialization_text + kiota_serialization_json: + git: + url: https://github.com/kiota-community/dart_kiota.git + ref: json + path: packages/kiota_serialization_json + http: ^1.2.2 + uuid: ^4.5.1 + +dev_dependencies: + lints: ^3.0.0 diff --git a/it/get-additional-arguments.ps1 b/it/get-additional-arguments.ps1 index 6f68879e2d..1727ea1960 100755 --- a/it/get-additional-arguments.ps1 +++ b/it/get-additional-arguments.ps1 @@ -23,6 +23,9 @@ if ($language -eq "csharp") { elseif ($language -eq "java") { $command = " --output `"./it/$language/src`"" } +elseif ($language -eq "dart") { + $command = " --output `"./it/$language/src`"" +} elseif ($language -eq "go") { $command = " --output `"./it/$language/client`" --namespace-name `"integrationtest/client`"" } From f9edf028586d52b154c1b352b3b5c767270530f4 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 07:53:46 +0200 Subject: [PATCH 101/194] Run dart analyze or test --- it/dart/api_client_test.dart | 21 +++++++++++++++++++++ it/dart/pubspec.yaml | 1 + it/exec-cmd.ps1 | 23 +++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 it/dart/api_client_test.dart diff --git a/it/dart/api_client_test.dart b/it/dart/api_client_test.dart new file mode 100644 index 0000000000..1d7f421bdf --- /dev/null +++ b/it/dart/api_client_test.dart @@ -0,0 +1,21 @@ +import 'package:kiota_abstractions/kiota_abstractions.dart'; +import 'package:kiota_http/kiota_http.dart'; +import 'package:test/test.dart'; +import 'src/api_client.dart'; + +void main() { + group('apiclient', () { + test('basic endpoint test', () { + final requestAdapter = HttpClientRequestAdapter( + client: KiotaClientFactory.createClient(), + authProvider: AnonymousAuthenticationProvider(), + pNodeFactory: ParseNodeFactoryRegistry.defaultInstance, + sWriterFactory: SerializationWriterFactoryRegistry.defaultInstance, + ); + requestAdapter.baseUrl = "http://localhost:1080"; + var client = ApiClient(requestAdapter); + + expect(() => client.api.v1.topics.getAsync(), throwsException); + }); + }); +} diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml index ad6ce900da..e234819775 100644 --- a/it/dart/pubspec.yaml +++ b/it/dart/pubspec.yaml @@ -38,3 +38,4 @@ dependencies: dev_dependencies: lints: ^3.0.0 + test: ^1.25.2 diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index af5993caa3..d25a96360d 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -202,6 +202,29 @@ elseif ($language -eq "python") { Pop-Location } } +if ($language -eq "dart") { + if ($mockServerTest) { + Push-Location $itTestPath + + $itTestPathSources = Join-Path -Path $testPath -ChildPath "src" + $itTestPathDest = Join-Path -Path $itTestPath -ChildPath "src" + if (Test-Path $itTestPathDest) { + Remove-Item $itTestPathDest -Force -Recurse + } + Copy-Item -Path $itTestPathSources -Destination $itTestPathDest -Recurse + + Invoke-Call -ScriptBlock { + dart test + } -ErrorAction Stop + + Pop-Location + } + else { + Invoke-Call -ScriptBlock { + dart analyze + } -ErrorAction Stop + } +} Pop-Location if (!([string]::IsNullOrEmpty($mockSeverITFolder))) { From 0cc8d4b11110773cf9468cab3130a8496a32ce33 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 09:20:50 +0200 Subject: [PATCH 102/194] Remove unused import and incorrect override --- src/Kiota.Builder/Refiners/DartRefiner.cs | 3 ++- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index c7480d73e0..abc4081f54 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -252,11 +252,12 @@ private static void CorrectImplements(ProprietableBlockDeclaration block) } public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) { + var result = usingsToAdd.OfType().Except(usingsToAdd.Where(static codeType => codeType.Parent is ClassDeclaration declaration && declaration.Parent is CodeClass codeClass && codeClass.IsErrorDefinition)); var genericParameterTypes = usingsToAdd.OfType().Where( static codeType => codeType.Parent is CodeParameter parameter && parameter.IsOfKind(CodeParameterKind.RequestConfiguration)).Select(x => x.GenericTypeParameterValues.First()); - return usingsToAdd.Union(genericParameterTypes); + return result.Union(genericParameterTypes); } protected static void AddAsyncSuffix(CodeElement currentElement) { diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 2bc6258e25..0c90b2e964 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.Refiners; @@ -83,7 +84,8 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ defaultValue = $" = {propertyType}()"; goto default; case CodePropertyKind.AdditionalData: - writer.WriteLine("@override"); + if (parentClass.StartBlock.Implements.Where(static x => x.Name.Equals("AdditionalDataHolder", StringComparison.Ordinal)).Any()) + writer.WriteLine("@override"); goto default; default: writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterLowerCase()}{defaultValue};"); From f7e1050a69bdeb65aa1b5cb5dc61eb526a1f565a Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 10:14:34 +0200 Subject: [PATCH 103/194] only analyze code in src dir --- it/exec-cmd.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index d25a96360d..8a02fe455e 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -221,7 +221,7 @@ if ($language -eq "dart") { } else { Invoke-Call -ScriptBlock { - dart analyze + dart analyze src/ } -ErrorAction Stop } } From 61580d28b46be9368d8e00807369bd7339ed9b55 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 10:40:40 +0200 Subject: [PATCH 104/194] Only requestconfiguration parameter should be optional --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 2c6e033c6c..cf5002417b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -702,17 +702,15 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua openingBracket = ";"; } - var optionalParamOpen = methodName.EqualsIgnoreCase("getAsync") ? "[" : ""; - var optionalParamClose = methodName.EqualsIgnoreCase("getAsync") ? "]" : ""; if (includeNullableReferenceType) { var completeReturnTypeWithNullable = isConstructor || string.IsNullOrEmpty(genericTypeSuffix) ? completeReturnType : $"{completeReturnType[..^2].TrimEnd('?')}?{genericTypeSuffix} "; var nullableParameters = string.Join(", ", code.Parameters.Order(parameterOrderComparer) .Select(p => p.IsOfKind(CodeParameterKind.RequestConfiguration) ? - GetParameterSignatureWithNullableRefType(p, code) : + $"[{GetParameterSignatureWithNullableRefType(p, code)}]" : conventions.GetParameterSignature(p, code)) .ToList()); - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({optionalParamOpen}{nullableParameters}{optionalParamClose}){baseSuffix}{async} {{"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}{async} {{"); } else if (parentClass.IsOfKind(CodeClassKind.Model) && code.IsOfKind(CodeMethodKind.Custom) && code.Name.EqualsIgnoreCase("copyWith")) { @@ -724,7 +722,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({optionalParamOpen}{parameters}{optionalParamClose}{closingparenthesis}{baseSuffix}{async} {openingBracket}"); + writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}{closingparenthesis}{baseSuffix}{async} {openingBracket}"); } } From 5ccb0da34b71936915921bafaed150cde58b040b Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 11:00:00 +0200 Subject: [PATCH 105/194] Fix writing boolean values in serializer methods, added data types to reserved names --- src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs | 4 ++++ src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs index 342fe23375..ae7da6792b 100644 --- a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -11,6 +11,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "async", "await", "base", + "bool", "break", "case", "catch", @@ -21,6 +22,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "default", "deferred", "do", + "double", "dynamic", "else", "enum", @@ -40,6 +42,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "implements", "import", "in", + "int", "interface", "is", "late", @@ -58,6 +61,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "set", "show", "static", + "string", "super", "switch", "sync", diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index cf5002417b..e64cc67ca8 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -558,9 +558,11 @@ private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass paren .OrderBy(static x => x, CodePropertyTypeForwardComparer) .ThenBy(static x => x.Name)) { + var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); + var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterLowerCase()} != null) {{"); writer.IncreaseIndent(); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()});"); writer.CloseBlock(); if (!includeElse) includeElse = true; @@ -576,9 +578,11 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas .OrderBy(static x => x, CodePropertyTypeBackwardComparer) .ThenBy(static x => x.Name)) { + var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); + var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterLowerCase()} != null) {{"); writer.IncreaseIndent(); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()});"); writer.CloseBlock(); if (!includeElse) includeElse = true; From 7b6f1ceb254af54b0e5f1ec3e75be2eb0ea31c17 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 13:29:11 +0200 Subject: [PATCH 106/194] Replace methods before type correction, different check in factory method --- src/Kiota.Builder/Refiners/DartRefiner.cs | 5 +++-- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index abc4081f54..2792b4a848 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -55,13 +55,14 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken _configuration.UsesBackingStore, static s => s, false); - CorrectCommonNames(generatedCode); - CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); ReplaceIndexersByMethodsWithParameter(generatedCode, false, static x => $"by{x.ToFirstCharacterUpperCase()}", static x => x.ToFirstCharacterLowerCase(), GenerationLanguage.Dart); + CorrectCommonNames(generatedCode); + CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); + AddQueryParameterExtractorMethod(generatedCode); // This adds the BaseRequestBuilder class as a superclass MoveRequestBuilderPropertiesToBaseType(generatedCode, diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index e64cc67ca8..0956094194 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -194,7 +194,8 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, if (property.Type is CodeType propertyType) { var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); - writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName}) {{"); + var check = propertyType.IsCollection ? ".isNotEmpty" : " != null"; + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); writer.CloseBlock(); } From c6c6345f5161dd4e4f8f6f55edff221c18533ee4 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 15:06:44 +0200 Subject: [PATCH 107/194] Stream should be escaped, some fixes to writing of default values --- src/Kiota.Builder/Refiners/DartRefiner.cs | 2 +- .../Refiners/DartReservedNamesProvider.cs | 1 + src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 5 ----- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 12 +++++++++++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 2792b4a848..671f6f5d98 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -110,7 +110,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken AddAsyncSuffix(generatedCode); AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); - ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped", [typeof(CodeEnumOption)]); + ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped"); ReplaceReservedModelTypes(generatedCode, reservedNamesProvider, x => $"{x}Object"); ReplaceReservedExceptionPropertyNames( generatedCode, diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs index ae7da6792b..77bdea5133 100644 --- a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -61,6 +61,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "set", "show", "static", + "stream", "string", "super", "switch", diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index fe637a9a76..a24381d5c1 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -18,7 +18,6 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write ArgumentNullException.ThrowIfNull(writer); if (!codeElement.Options.Any()) return; - DartReservedNamesProvider reservedNamesProvider = new DartReservedNamesProvider(); var enumName = codeElement.Name.ToFirstCharacterUpperCase(); conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); @@ -30,10 +29,6 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write { conventions.WriteShortDescription(option, writer); var correctedName = conventions.getCorrectedEnumName(option.Name); - if (reservedNamesProvider.ReservedNames.Contains(correctedName) || IllegalEnumValue(correctedName)) - { - correctedName += "Escaped"; - } if (!usedNames.Add(correctedName)) { correctedName = option.Name; diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 0956094194..859e928201 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -4,6 +4,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.OrderComparers; +using Kiota.Builder.Refiners; using static Kiota.Builder.CodeDOM.CodeTypeBase; namespace Kiota.Builder.Writers.Dart; @@ -306,13 +307,22 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) { defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')).CleanupSymbolName(); + if (new DartReservedNamesProvider().ReservedNames.Contains(defaultValue)) + { + defaultValue = defaultValue + "Escaped"; + } defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; } else if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) { - defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')); + defaultValue = defaultValue.Trim('"'); defaultValue = $"'{defaultValue}'"; } + else if (propWithDefault.Type is CodeType propertyType3 && propertyType3.Name.Equals("Boolean", StringComparison.Ordinal)) + { + defaultValue = defaultValue.Trim('"'); + defaultValue = $"{defaultValue}"; + } writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue}{separator}"); } if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && From 39213638c3a4fd03af91644492f0353bd914f6f5 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 23 Oct 2024 15:48:40 +0200 Subject: [PATCH 108/194] Error classes should have a constructor --- src/Kiota.Builder/Refiners/DartRefiner.cs | 30 +++++++++++++++++++ .../Writers/Dart/CodeMethodWriter.cs | 4 +-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 671f6f5d98..1788557a0b 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -106,6 +106,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddConstructorsForDefaultValues(generatedCode, true); + AddConstructorForErrorClass(generatedCode); cancellationToken.ThrowIfCancellationRequested(); AddAsyncSuffix(generatedCode); AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); @@ -158,6 +159,35 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken }, cancellationToken); } + ///error classes should always have a constructor for the copyWith method + private void AddConstructorForErrorClass(CodeElement currentElement) + { + if (currentElement is CodeClass codeClass && codeClass.IsErrorDefinition && !codeClass.Methods.Where(static x => x.IsOfKind(CodeMethodKind.Constructor)).Any()) + { + codeClass.AddMethod(new CodeMethod + { + Name = "constructor", + Kind = CodeMethodKind.Constructor, + IsAsync = false, + IsStatic = false, + Documentation = new(new() { + {"TypeName", new CodeType { + IsExternal = false, + TypeDefinition = codeClass, + } + } + }) + { + DescriptionTemplate = "Instantiates a new {TypeName} and sets the default values.", + }, + Access = AccessModifier.Public, + ReturnType = new CodeType { Name = "void", IsExternal = true }, + Parent = codeClass, + }); + } + CrawlTree(currentElement, element => AddConstructorForErrorClass(element)); + } + /// /// Corrects common names so they can be used with Dart. /// This normally comes down to changing the first character to lower case. diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 859e928201..bb463c74cd 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -54,7 +54,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri private static bool HasEmptyConstructorBody(CodeMethod codeElement, CodeClass parentClass, bool isConstructor) { - if (parentClass.IsOfKind(CodeClassKind.Model) && codeElement.IsOfKind(CodeMethodKind.Constructor)) + if (parentClass.IsOfKind(CodeClassKind.Model) && codeElement.IsOfKind(CodeMethodKind.Constructor) && !parentClass.IsErrorDefinition) { return !parentClass.Properties.Where(prop => !string.IsNullOrEmpty(prop.DefaultValue)).Any(); } @@ -242,7 +242,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); - else if (parentClass.IsErrorDefinition) + else if (parentClass.IsErrorDefinition && parentClass.StartBlock.Implements.Where(static x => x.Name.Equals("AdditionalDataHolder", StringComparison.Ordinal)).Any()) { writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}(additionalData: {{}});"); } From 0a97948f3e3fd4c4c4a745a713c4b69c862aa5e6 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 24 Oct 2024 09:47:00 +0200 Subject: [PATCH 109/194] mappingvalue was being written without being used, index in enums should be escaped --- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 5 ----- .../Writers/Dart/CodeMethodWriter.cs | 16 +++++++++++----- .../Writers/Dart/DartConventionService.cs | 11 +++++++++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index a24381d5c1..969c631926 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -39,9 +39,4 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); } - - private bool IllegalEnumValue(string correctedName) - { - return correctedName.EqualsIgnoreCase("string") || correctedName.EqualsIgnoreCase("index"); - } } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index bb463c74cd..8ffe99387e 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -156,6 +156,13 @@ private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, Cod private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) { writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); + + if (parentClass.GetPropertiesOfKind(CodePropertyKind.Custom).Where(static x => x.Type is CodeType cType && cType.TypeDefinition is CodeClass && !cType.IsCollection).Any()) + { + var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; + discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; + writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); + } var includeElse = false; foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .OrderBy(static x => x, CodePropertyTypeForwardComparer) @@ -173,7 +180,8 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) { var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName}) {{"); + var check = propertyType.IsCollection ? ".isNotEmpty" : $" is {typeName}"; + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); writer.IncreaseIndent(); writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); writer.CloseBlock(); @@ -229,15 +237,13 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas { var parseNodeParameter = codeElement.Parameters.OfKind(CodeParameterKind.ParseNode) ?? throw new InvalidOperationException("Factory method should have a ParseNode parameter"); - if (parentClass.DiscriminatorInformation.ShouldWriteParseNodeCheck && !parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) + if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) { var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); - } - - if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) WriteFactoryMethodBodyForInheritedModel(codeElement, parentClass, writer); + } else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 72fbf1f807..ca444ba8e6 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -355,8 +355,15 @@ public bool ErrorClassPropertyExistsInSuperClass(CodeProperty codeElement) public string getCorrectedEnumName(string name) { ArgumentNullException.ThrowIfNull(name); + var correctedName = ""; if (name.Contains('_', StringComparison.Ordinal)) - return name.ToLowerInvariant().ToCamelCase('_'); - return name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name; + { + correctedName = name.ToLowerInvariant().ToCamelCase('_'); + } + else + { + correctedName = name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name; + } + return correctedName.Equals("index", StringComparison.Ordinal) ? correctedName + "Escaped" : correctedName; } } From d6363133e826eb9879ae21d189896e147666186e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 24 Oct 2024 10:21:35 +0200 Subject: [PATCH 110/194] Better check for writing additionaldata --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 8ffe99387e..07273b1e46 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -248,7 +248,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); - else if (parentClass.IsErrorDefinition && parentClass.StartBlock.Implements.Where(static x => x.Name.Equals("AdditionalDataHolder", StringComparison.Ordinal)).Any()) + else if (parentClass.IsErrorDefinition && parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) { writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}(additionalData: {{}});"); } From 5d113cce18d04a3d04974a7888ebd80587393c2f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 24 Oct 2024 11:27:41 +0200 Subject: [PATCH 111/194] Moved and fixed the apiclienttest --- it/dart/{ => basic/test}/api_client_test.dart | 9 ++++++--- it/exec-cmd.ps1 | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) rename it/dart/{ => basic/test}/api_client_test.dart (73%) diff --git a/it/dart/api_client_test.dart b/it/dart/basic/test/api_client_test.dart similarity index 73% rename from it/dart/api_client_test.dart rename to it/dart/basic/test/api_client_test.dart index 1d7f421bdf..e49a039f44 100644 --- a/it/dart/api_client_test.dart +++ b/it/dart/basic/test/api_client_test.dart @@ -1,7 +1,8 @@ import 'package:kiota_abstractions/kiota_abstractions.dart'; import 'package:kiota_http/kiota_http.dart'; import 'package:test/test.dart'; -import 'src/api_client.dart'; +import '../src/api_client.dart'; +import '../src/models/error.dart'; void main() { group('apiclient', () { @@ -14,8 +15,10 @@ void main() { ); requestAdapter.baseUrl = "http://localhost:1080"; var client = ApiClient(requestAdapter); - - expect(() => client.api.v1.topics.getAsync(), throwsException); + expect( + () => client.api.v1.topics.getAsync(), + throwsA(predicate( + (e) => e is Error && e.id == 'my-sample-id' && e.code == 123))); }); }); } diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index 8a02fe455e..bc9ef9d87e 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -202,7 +202,7 @@ elseif ($language -eq "python") { Pop-Location } } -if ($language -eq "dart") { +elseif ($language -eq "dart") { if ($mockServerTest) { Push-Location $itTestPath From 4eab0b0bc4624ae9d55849d545e850ada8817b62 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 25 Oct 2024 14:53:01 +0200 Subject: [PATCH 112/194] Changes to generate compiling code with backingstore --- src/Kiota.Builder/Refiners/DartRefiner.cs | 6 +- .../Writers/Dart/CodeMethodWriter.cs | 68 +++++++++++++++---- .../Writers/Dart/CodePropertyWriter.cs | 10 +-- .../Writers/Dart/DartConventionService.cs | 2 +- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 1788557a0b..902b76a381 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -222,9 +222,9 @@ private static void CorrectMethodType(CodeMethod currentMethod) currentMethod.ReturnType.Name = "Map"; currentMethod.Name = "getFieldDeserializers"; } - else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlConstructor)) + else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlConstructor, CodeMethodKind.ClientConstructor)) { - currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.RequestAdapter)) + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.RequestAdapter, CodeParameterKind.BackingStore)) .Where(x => x.Type.Name.StartsWith('I')) .ToList() .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" @@ -279,7 +279,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) private static void CorrectImplements(ProprietableBlockDeclaration block) { - block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I + block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase) || "IBackedModel".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I } public static IEnumerable codeTypeFilter(IEnumerable usingsToAdd) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 07273b1e46..c08d3ee872 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -37,13 +37,20 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri } else { - if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition) + if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition && !parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { writer.DecreaseIndent(); } else if (isConstructor && parentClass.IsErrorDefinition) { - writer.CloseBlock("});"); + if (parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) + { + writer.CloseBlock("}) {additionalData = {};}"); + } + else + { + writer.CloseBlock("});"); + } } else { @@ -248,7 +255,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); - else if (parentClass.IsErrorDefinition && parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any()) + else if (parentClass.IsErrorDefinition && parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}(additionalData: {{}});"); } @@ -278,7 +285,11 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterLowerCase()}['baseurl'] = {requestAdapterPropertyName}.baseUrl;"); } if (backingStoreParameter != null) - writer.WriteLine($"{requestAdapterPropertyName}.EnableBackingStore({backingStoreParameter.Name});"); + { + writer.StartBlock($"if ({backingStoreParameter.Name} != null) {{"); + writer.WriteLine($"{requestAdapterPropertyName}.enableBackingStore({backingStoreParameter.Name});"); + writer.CloseBlock(); + } } private static void WriteSerializationRegistration(HashSet serializationClassNames, LanguageWriter writer, string methodName) { @@ -296,7 +307,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho { var separator = ','; var propWithDefaults = parentClass.Properties - .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters)) + .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !x.IsOfKind(CodePropertyKind.UrlTemplate, CodePropertyKind.PathParameters, CodePropertyKind.BackingStore)) // do not apply the default value if the type is composed as the default value may not necessarily which type to use .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) .OrderByDescending(static x => x.Kind) @@ -356,13 +367,16 @@ private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod curren { writer.WriteLine($"super.{prop},"); } - foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) + if (!parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { - var required = prop.Type.IsNullable ? "" : "required "; - - if (!conventions.ErrorClassPropertyExistsInSuperClass(prop)) + foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) { - writer.WriteLine($"{required}this.{prop.Name.ToFirstCharacterLowerCase()},"); + var required = prop.Type.IsNullable ? "" : "required "; + + if (!conventions.ErrorClassPropertyExistsInSuperClass(prop)) + { + writer.WriteLine($"{required}this.{prop.Name.ToFirstCharacterLowerCase()},"); + } } } } @@ -685,7 +699,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass } return " : super()"; } - else if (isConstructor && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition) + else if (isConstructor && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition && !parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { return " : "; } @@ -823,7 +837,7 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass if (codeElement.Name.Equals("clone", StringComparison.OrdinalIgnoreCase)) { var constructor = parentClass.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); - String? argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()) + var argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()) .Select(static x => x.Type.Parent is CodeParameter param && param.IsOfKind(CodeParameterKind.RequestAdapter, CodeParameterKind.PathParameters) ? x.Name : x.Optional ? "null" : x.DefaultValue) @@ -832,20 +846,44 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass } if (codeElement.Name.Equals("copyWith", StringComparison.Ordinal)) { - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}("); + var hasBackingStore = parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.BackingStore)).Any(); + var resultName = hasBackingStore ? "result" : string.Empty; + + if (hasBackingStore) + { + writer.WriteLine($"var {resultName} = {parentClass.Name.ToFirstCharacterUpperCase()}("); + } + else + { + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}("); + } foreach (string prop in DartConventionService.ErrorClassProperties) { writer.WriteLine($"{prop} : {prop} ?? this.{prop}, "); } + if (hasBackingStore) + { + writer.WriteLine(");"); + } foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) { var propertyname = prop.Name.ToFirstCharacterLowerCase(); + var separator = hasBackingStore ? "=" : ":"; + var ending = hasBackingStore ? ";" : ","; + var resultPropertyName = string.IsNullOrEmpty(resultName) ? propertyname : $"{resultName}.{propertyname}"; if (!conventions.ErrorClassPropertyExistsInSuperClass(prop)) { - writer.WriteLine($"{propertyname} : {propertyname} ?? this.{propertyname}, "); + writer.WriteLine($"{resultPropertyName} {separator} {propertyname} ?? this.{propertyname}{ending} "); } } - writer.WriteLine($");"); + if (hasBackingStore) + { + writer.WriteLine($"return {resultName}; "); + } + else + { + writer.WriteLine($");"); + } } } } diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 0c90b2e964..474b6385ae 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -37,7 +37,6 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ throw new InvalidOperationException("The parent of a property should be a class"); var backingStoreProperty = parentClass.GetBackingStoreProperty(); - var setterAccessModifier = codeElement.ReadOnly && codeElement.Access > AccessModifier.Private ? "_" : string.Empty; var defaultValue = string.Empty; var getterModifier = string.Empty; @@ -64,13 +63,13 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ var backingStoreKey = codeElement.WireName; writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); - writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Get<{propertyType}>(\"{backingStoreKey}\");"); + writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterLowerCase()}.get<{propertyType}>('{backingStoreKey}')!;"); writer.DecreaseIndent(); writer.WriteLine("}"); writer.WriteLine(); - writer.WriteLine($"set {setterAccessModifier}{codeElement.Name.ToCamelCase()}({propertyType} value) {{"); + writer.WriteLine($"set {codeElement.Name.ToCamelCase()}({propertyType} value) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{backingStoreProperty.Name.ToFirstCharacterUpperCase()}?.Set(\"{backingStoreKey}\", value);"); + writer.WriteLine($"{backingStoreProperty.Name.ToFirstCharacterLowerCase()}.set('{backingStoreKey}', value);"); writer.DecreaseIndent(); writer.WriteLine("}"); break; @@ -87,6 +86,9 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ if (parentClass.StartBlock.Implements.Where(static x => x.Name.Equals("AdditionalDataHolder", StringComparison.Ordinal)).Any()) writer.WriteLine("@override"); goto default; + case CodePropertyKind.BackingStore: + defaultValue = " = BackingStoreFactorySingleton.instance.createBackingStore()"; + goto default; default: writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterLowerCase()}{defaultValue};"); break; diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index ca444ba8e6..17e069924d 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -18,7 +18,7 @@ public class DartConventionService : CommonLanguageConventionService public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; - private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string", "datetime", "dateonly", "timeonly" }; + private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string", "datetime", "dateonly", "timeonly", "backingstorefactory" }; public const char NullableMarker = '?'; public static string NullableMarkerAsString => "?"; public override string ParseNodeInterfaceName => "ParseNode"; From f1cbb0fb98222c52989608714c7318122544618f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 29 Oct 2024 13:17:21 +0100 Subject: [PATCH 113/194] Use defaultvalue if property cannot be null --- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 474b6385ae..8eba203edd 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -61,9 +61,10 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ case CodePropertyKind.AdditionalData when backingStoreProperty != null: case CodePropertyKind.Custom when backingStoreProperty != null: var backingStoreKey = codeElement.WireName; + var defaultIfNotNullable = propertyType.EndsWith('?') ? string.Empty : $" ?? {codeElement.DefaultValue}"; writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); - writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterLowerCase()}.get<{propertyType}>('{backingStoreKey}')!;"); + writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterLowerCase()}.get<{propertyType}>('{backingStoreKey}'){defaultIfNotNullable};"); writer.DecreaseIndent(); writer.WriteLine("}"); writer.WriteLine(); From 8d8a8feaf226d8f2f5c8e4f19b37d9ec409cae4f Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 30 Oct 2024 09:31:12 +0100 Subject: [PATCH 114/194] First attempt to solve name mangling In Dart, like java, properties use camel case and classes use Pascal case. We want to move using these different cases out of the writers and into the refiner. With the current changes the output remains exactly the same. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 10 +- .../Dart/CodeClassDeclarationWriter.cs | 2 +- .../Writers/Dart/CodeMethodWriter.cs | 100 +++++++++--------- 3 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 902b76a381..df359e55ab 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -53,7 +53,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken var defaultConfiguration = new GenerationConfiguration(); ConvertUnionTypesToWrapper(generatedCode, _configuration.UsesBackingStore, - static s => s, + static s => s.ToFirstCharacterLowerCase(), false); ReplaceIndexersByMethodsWithParameter(generatedCode, false, @@ -242,7 +242,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) if (currentProperty.IsOfKind(CodePropertyKind.Options)) currentProperty.DefaultValue = "List()"; else if (currentProperty.IsOfKind(CodePropertyKind.Headers)) - currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterUpperCase()}()"; + currentProperty.DefaultValue = $"{currentProperty.Type.Name.ToFirstCharacterLowerCase()}()"; else if (currentProperty.IsOfKind(CodePropertyKind.RequestAdapter)) { currentProperty.Type.Name = "RequestAdapter"; @@ -261,6 +261,8 @@ private static void CorrectPropertyType(CodeProperty currentProperty) { currentProperty.Type.Name = "Map"; currentProperty.DefaultValue = "{}"; + currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); + } else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) { @@ -273,6 +275,10 @@ private static void CorrectPropertyType(CodeProperty currentProperty) if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) currentProperty.DefaultValue = "{}"; } + else if (currentProperty.IsOfKind(CodePropertyKind.Custom)) + { + currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); + } currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index f502cd4520..8c440beebb 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -57,7 +57,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteLongDescription(parentClass, writer); conventions.WriteDeprecationAttribute(parentClass, writer); - writer.StartBlock($"class {codeElement.Name.ToFirstCharacterUpperCase()}{derivation}{implements} {{"); + writer.StartBlock($"class {codeElement.Name}{derivation}{implements} {{"); } private String getAlias(string alias) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index c08d3ee872..880cda1b65 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -145,7 +145,7 @@ private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElemen { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property"); - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}.withUrl({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"return {parentClass.Name}.withUrl({rawUrlParameter.Name}, {requestAdapterProperty.Name});"); } private static readonly CodePropertyTypeComparer CodePropertyTypeForwardComparer = new(); private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true); @@ -156,19 +156,19 @@ private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, Cod { writer.WriteLine($"'{mappedType.Key}' => {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),"); } - writer.WriteLine($"_ => {parentClass.Name.ToFirstCharacterUpperCase()}(),"); + writer.WriteLine($"_ => {parentClass.Name}(),"); writer.CloseBlock("};"); } private const string ResultVarName = "result"; private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) { - writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"var {ResultVarName} = {parentClass.Name}();"); if (parentClass.GetPropertiesOfKind(CodePropertyKind.Custom).Where(static x => x.Type is CodeType cType && cType.TypeDefinition is CodeClass && !cType.IsCollection).Any()) { var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; - writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); + writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); } var includeElse = false; foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) @@ -181,16 +181,16 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if('{mappedType.Key}' == {DiscriminatorMappingVarName}) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(propertyType, codeElement)}();"); + writer.WriteLine($"{ResultVarName}.{property.Name} = {conventions.GetTypeString(propertyType, codeElement)}();"); writer.CloseBlock(); } else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) { var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); var check = propertyType.IsCollection ? ".isNotEmpty" : $" is {typeName}"; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); + writer.WriteLine($"{ResultVarName}.{property.Name} = {parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)};"); writer.CloseBlock(); } if (!includeElse) @@ -200,7 +200,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla } private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) { - writer.WriteLine($"var {ResultVarName} = {parentClass.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"var {ResultVarName} = {parentClass.Name}();"); var includeElse = false; foreach (var property in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => x.Type is not CodeType propertyType || propertyType.IsCollection || propertyType.TypeDefinition is not CodeClass) @@ -211,8 +211,8 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, { var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); var check = propertyType.IsCollection ? ".isNotEmpty" : " != null"; - writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); - writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterLowerCase()} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)};"); + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); + writer.WriteLine($"{ResultVarName}.{property.Name} = {parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)};"); writer.CloseBlock(); } if (!includeElse) @@ -230,7 +230,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, writer.IncreaseIndent(); } foreach (var property in complexProperties) - writer.WriteLine($"{ResultVarName}.{property.Item1.Name.ToFirstCharacterLowerCase()} = {conventions.GetTypeString(property.Item2, codeElement)}();"); + writer.WriteLine($"{ResultVarName}.{property.Item1.Name} = {conventions.GetTypeString(property.Item2, codeElement)}();"); if (includeElse) { writer.CloseBlock(); @@ -248,7 +248,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas { var discriminatorPropertyName = parentClass.DiscriminatorInformation.DiscriminatorPropertyName; discriminatorPropertyName = discriminatorPropertyName.StartsWith('$') ? "\\" + discriminatorPropertyName : discriminatorPropertyName; - writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name.ToFirstCharacterLowerCase()}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); + writer.WriteLine($"var {DiscriminatorMappingVarName} = {parseNodeParameter.Name}.getChildNode('{discriminatorPropertyName}')?.getStringValue();"); WriteFactoryMethodBodyForInheritedModel(codeElement, parentClass, writer); } else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -257,10 +257,10 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); else if (parentClass.IsErrorDefinition && parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}(additionalData: {{}});"); + writer.WriteLine($"return {parentClass.Name}(additionalData: {{}});"); } else - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}();"); + writer.WriteLine($"return {parentClass.Name}();"); } private void WriteRequestBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) @@ -273,7 +273,7 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me if (parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is not CodeProperty requestAdapterProperty) return; var pathParametersProperty = parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters); var backingStoreParameter = method.Parameters.OfKind(CodeParameterKind.BackingStore); - var requestAdapterPropertyName = requestAdapterProperty.Name.ToFirstCharacterLowerCase(); + var requestAdapterPropertyName = requestAdapterProperty.Name; WriteSerializationRegistration(method.SerializerModules, writer, "registerDefaultSerializer"); WriteSerializationRegistration(method.DeserializerModules, writer, "registerDefaultDeserializer"); if (!string.IsNullOrEmpty(method.BaseUrl)) @@ -282,7 +282,7 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me writer.WriteLine($"{requestAdapterPropertyName}.baseUrl = '{method.BaseUrl}';"); writer.CloseBlock(); if (pathParametersProperty != null) - writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterLowerCase()}['baseurl'] = {requestAdapterPropertyName}.baseUrl;"); + writer.WriteLine($"{pathParametersProperty.Name}['baseurl'] = {requestAdapterPropertyName}.baseUrl;"); } if (backingStoreParameter != null) { @@ -326,7 +326,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')).CleanupSymbolName(); if (new DartReservedNamesProvider().ReservedNames.Contains(defaultValue)) { - defaultValue = defaultValue + "Escaped"; + defaultValue += "Escaped"; } defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; } @@ -351,11 +351,11 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho if (pathParameters.Any()) conventions.AddParametersAssignment(writer, pathParametersParam.Type, - pathParametersParam.Name.ToFirstCharacterLowerCase(), - pathParametersProp.Name.ToFirstCharacterLowerCase(), + pathParametersParam.Name, + pathParametersProp.Name, currentMethod.Parameters .Where(static x => x.IsOfKind(CodeParameterKind.Path)) - .Select(static x => (x.Type, string.IsNullOrEmpty(x.SerializationName) ? x.Name : x.SerializationName, x.Name.ToFirstCharacterLowerCase())) + .Select(static x => (x.Type, string.IsNullOrEmpty(x.SerializationName) ? x.Name : x.SerializationName, x.Name)) .ToArray()); } } @@ -375,7 +375,7 @@ private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod curren if (!conventions.ErrorClassPropertyExistsInSuperClass(prop)) { - writer.WriteLine($"{required}this.{prop.Name.ToFirstCharacterLowerCase()},"); + writer.WriteLine($"{required}this.{prop.Name},"); } } } @@ -400,10 +400,10 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par .Where(static x => x.Type is CodeType propertyType && !propertyType.IsCollection && propertyType.TypeDefinition is CodeClass) .OrderBy(static x => x, CodePropertyTypeForwardComparer) .ThenBy(static x => x.Name) - .Select(static x => x.Name.ToFirstCharacterLowerCase())) + .Select(static x => x.Name)) { writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({otherPropName} != null) {{"); - writer.WriteLine($"return {otherPropName}!.{method.Name.ToFirstCharacterLowerCase()}();"); + writer.WriteLine($"return {otherPropName}!.{method.Name}();"); writer.CloseBlock(); if (!includeElse) includeElse = true; @@ -422,7 +422,7 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La .ToArray(); foreach (CodeProperty prop in complexProperties) { - writer.WriteLine($"if({prop.Name.ToFirstCharacterLowerCase()} != null){{{prop.Name.ToFirstCharacterLowerCase()}!.getFieldDeserializers().forEach((k,v) => {DeserializerName}.putIfAbsent(k, ()=>v));}}"); + writer.WriteLine($"if({prop.Name} != null){{{prop.Name}!.getFieldDeserializers().forEach((k,v) => {DeserializerName}.putIfAbsent(k, ()=>v));}}"); } writer.WriteLine($"return {DeserializerName};"); } @@ -438,7 +438,7 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod .Where(x => !x.ExistsInBaseType && !conventions.ErrorClassPropertyExistsInSuperClass(x)) .OrderBy(static x => x.Name) .Select(x => - $"{DeserializerVarName}['{x.WireName}'] = (node) => {x.Name.ToFirstCharacterLowerCase()} = node.{GetDeserializationMethodName(x.Type, codeElement)};") + $"{DeserializerVarName}['{x.WireName}'] = (node) => {x.Name} = node.{GetDeserializationMethodName(x.Type, codeElement)};") .ToList() .ForEach(x => writer.WriteLine(x)); } @@ -457,7 +457,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me return $"getCollectionOfPrimitiveValues<{propertyType.TrimEnd(DartConventionService.NullableMarker)}>(){collectionMethod}"; else if (currentType.TypeDefinition is CodeEnum enumType) { - var typeName = enumType.Name.ToFirstCharacterUpperCase(); + var typeName = enumType.Name; return $"getCollectionOfEnumValues<{typeName}>((stringValue) => {typeName}.values.where((enumVal) => enumVal.value == stringValue).firstOrNull)"; } else @@ -465,7 +465,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me } else if (currentType.TypeDefinition is CodeEnum enumType) { - var typeName = enumType.Name.ToFirstCharacterUpperCase(); + var typeName = enumType.Name; return $"getEnumValue<{typeName}>((stringValue) => {typeName}.values.where((enumVal) => enumVal.value == stringValue).firstOrNull)"; } } @@ -523,7 +523,7 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req if (requestParams.requestConfiguration != null && requestParams.requestConfiguration.Type is CodeType paramType) { - var parameterClassName = paramType.GenericTypeParameterValues.First().Name.ToFirstCharacterUpperCase(); + var parameterClassName = paramType.GenericTypeParameterValues.First().Name; writer.WriteLine($"{RequestInfoVarName}.configure<{parameterClassName}>({requestParams.requestConfiguration.Name}, () => {parameterClassName}());"); } @@ -541,14 +541,14 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req } else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty) if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase))) - writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, '{codeElement.RequestBodyContentType}', {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable{suffix}({requestAdapterProperty.Name}, '{codeElement.RequestBodyContentType}', {requestParams.requestBody.Name});"); else - writer.WriteLine($"{RequestInfoVarName}.setContentFromScalar{suffix}({requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, '{codeElement.RequestBodyContentType}', {requestParams.requestBody.Name});"); + writer.WriteLine($"{RequestInfoVarName}.setContentFromScalar{suffix}({requestAdapterProperty.Name}, '{codeElement.RequestBodyContentType}', {requestParams.requestBody.Name});"); } writer.WriteLine($"return {RequestInfoVarName};"); } - private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"{property.Name.ToFirstCharacterLowerCase()}"; + private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"{property.Name}"; private void WriteSerializerBody(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -559,7 +559,7 @@ private void WriteSerializerBody(bool shouldHide, CodeMethod method, CodeClass p WriteSerializerBodyForInheritedModel(shouldHide, method, parentClass, writer); if (parentClass.GetPropertyOfKind(CodePropertyKind.AdditionalData) is CodeProperty additionalDataProperty) - writer.WriteLine($"writer.writeAdditionalData({additionalDataProperty.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"writer.writeAdditionalData({additionalDataProperty.Name});"); } private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod method, CodeClass parentClass, LanguageWriter writer) { @@ -577,7 +577,7 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me { secondArgument = $", (e) => e?.value"; } - writer.WriteLine($"writer.{serializationMethodName}('{otherProp.WireName}', {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()}{secondArgument});"); + writer.WriteLine($"writer.{serializationMethodName}('{otherProp.WireName}', {booleanValue}{otherProp.Name}{secondArgument});"); } } private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer) @@ -591,9 +591,9 @@ private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass paren { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterLowerCase()} != null) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name} != null) {{"); writer.IncreaseIndent(); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name});"); writer.CloseBlock(); if (!includeElse) includeElse = true; @@ -611,9 +611,9 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterLowerCase()} != null) {{"); + writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name} != null) {{"); writer.IncreaseIndent(); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name});"); writer.CloseBlock(); if (!includeElse) includeElse = true; @@ -628,9 +628,9 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas writer.WriteLine("else {"); writer.IncreaseIndent(); } - var firstPropertyName = complexProperties.First().Name.ToFirstCharacterLowerCase(); + var firstPropertyName = complexProperties.First().Name; var propertiesNames = complexProperties.Skip(0) - .Select(static x => x.Name.ToFirstCharacterLowerCase()) + .Select(static x => x.Name) .OrderBy(static x => x) .Aggregate(static (x, y) => $"{x}, {y}"); var propertiesList = string.IsNullOrEmpty(propertiesNames) ? "" : $", [{propertiesNames}]"; @@ -669,7 +669,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) foreach (var paramWithDescription in code.Parameters .Where(static x => x.Documentation.DescriptionAvailable) .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) - writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}"); + writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}"); conventions.WriteDeprecationAttribute(code, writer); } private static readonly BaseCodeParameterOrderComparer parameterOrderComparer = new(); @@ -689,7 +689,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass thirdParameterName = $", {pathParametersProperty.DefaultValue}"; if (currentMethod.Parameters.OfKind(CodeParameterKind.RequestAdapter) is CodeParameter requestAdapterParameter) { - return $" : super({requestAdapterParameter.Name.ToFirstCharacterLowerCase()}, {urlTemplateProperty.DefaultValue}{thirdParameterName})"; + return $" : super({requestAdapterParameter.Name}, {urlTemplateProperty.DefaultValue}{thirdParameterName})"; } else if (parentClass.StartBlock?.Inherits?.Name?.Contains("CliRequestBuilder", StringComparison.Ordinal) == true) { @@ -752,7 +752,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var parentParameters = "int? statusCode, String? message, Map>? responseHeaders, Iterable? innerExceptions, "; var ownParameters = string.Join(", ", parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData) .Where(p => !conventions.ErrorClassPropertyExistsInSuperClass(p)) - .Select(p => $"{GetPrefix(p)}{conventions.TranslateType(p.Type)}{getSuffix(p)}? {p.Name.ToFirstCharacterLowerCase()}")); + .Select(p => $"{GetPrefix(p)}{conventions.TranslateType(p.Type)}{getSuffix(p)}? {p.Name}")); writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({openingBracket}{parentParameters}{ownParameters} }}){{"); } else @@ -775,9 +775,9 @@ private static string GetMethodName(CodeMethod code, CodeClass parentClass, bool { if (code.IsOfKind(CodeMethodKind.RawUrlConstructor)) { - return parentClass.Name.ToFirstCharacterUpperCase() + ".withUrl"; + return parentClass.Name + ".withUrl"; } - return isConstructor ? parentClass.Name.ToFirstCharacterUpperCase() : code.Name.ToFirstCharacterLowerCase(); + return isConstructor ? parentClass.Name : code.Name; } private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) @@ -798,7 +798,7 @@ private void WriteQueryparametersBody(CodeClass parentClass, CodeMethod codeElem writer.IncreaseIndent(); foreach (CodeProperty property in parentClass.Properties) { - writer.WriteLine($"'{property.Name}' : {property.Name.ToFirstCharacterLowerCase()},"); + writer.WriteLine($"'{property.Name}' : {property.Name},"); } writer.DecreaseIndent(); writer.WriteLine("};"); @@ -818,7 +818,7 @@ private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod meth else return $"writeCollectionOfObjectValues<{propertyType}>"; else if (currentType.TypeDefinition is CodeEnum enumType) - return $"writeEnumValue<{enumType.Name.ToFirstCharacterUpperCase()}>"; + return $"writeEnumValue<{enumType.Name}>"; } @@ -842,7 +842,7 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass ? x.Name : x.Optional ? "null" : x.DefaultValue) .Aggregate(static (x, y) => $"{x}, {y}"); - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({argumentList});"); + writer.WriteLine($"return {parentClass.Name}({argumentList});"); } if (codeElement.Name.Equals("copyWith", StringComparison.Ordinal)) { @@ -851,11 +851,11 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass if (hasBackingStore) { - writer.WriteLine($"var {resultName} = {parentClass.Name.ToFirstCharacterUpperCase()}("); + writer.WriteLine($"var {resultName} = {parentClass.Name}("); } else { - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}("); + writer.WriteLine($"return {parentClass.Name}("); } foreach (string prop in DartConventionService.ErrorClassProperties) { @@ -867,7 +867,7 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass } foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) { - var propertyname = prop.Name.ToFirstCharacterLowerCase(); + var propertyname = prop.Name; var separator = hasBackingStore ? "=" : ":"; var ending = hasBackingStore ? ";" : ","; var resultPropertyName = string.IsNullOrEmpty(resultName) ? propertyname : $"{resultName}.{propertyname}"; From d4a4300176aa27a3e5287dc723fe52abc29919ac Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 30 Oct 2024 09:52:50 +0100 Subject: [PATCH 115/194] Removed changing the case of enums/properties Casing is determined by the DartRefiner. --- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 2 +- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 969c631926..b08c6a641b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -18,7 +18,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write ArgumentNullException.ThrowIfNull(writer); if (!codeElement.Options.Any()) return; - var enumName = codeElement.Name.ToFirstCharacterUpperCase(); + var enumName = codeElement.Name; conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); writer.StartBlock($"enum {enumName} {{"); diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 474b6385ae..1f3f23f738 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -63,13 +63,13 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ var backingStoreKey = codeElement.WireName; writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); - writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterLowerCase()}.get<{propertyType}>('{backingStoreKey}')!;"); + writer.WriteLine($"return {backingStoreProperty.Name}.get<{propertyType}>('{backingStoreKey}')!;"); writer.DecreaseIndent(); writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine($"set {codeElement.Name.ToCamelCase()}({propertyType} value) {{"); writer.IncreaseIndent(); - writer.WriteLine($"{backingStoreProperty.Name.ToFirstCharacterLowerCase()}.set('{backingStoreKey}', value);"); + writer.WriteLine($"{backingStoreProperty.Name}.set('{backingStoreKey}', value);"); writer.DecreaseIndent(); writer.WriteLine("}"); break; @@ -90,7 +90,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ defaultValue = " = BackingStoreFactorySingleton.instance.createBackingStore()"; goto default; default: - writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name.ToFirstCharacterLowerCase()}{defaultValue};"); + writer.WriteLine($"{propertyType} {getterModifier}{conventions.GetAccessModifierPrefix(codeElement.Access)}{codeElement.Name}{defaultValue};"); break; } } From 29c9dab5cecb7109c74592301b45c9db3461e8c2 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 30 Oct 2024 09:58:05 +0100 Subject: [PATCH 116/194] Added writer tests for dart --- .../Writers/Dart/CodeBlockEndWriter.cs | 5 +- src/Kiota.Builder/Writers/Dart/DartWriter.cs | 2 +- .../Dart/CodeClassDeclarationWriterTests.cs | 94 +++++++++++++++++++ .../Writers/Dart/CodeClassEndWriterTests.cs | 45 +++++++++ .../Writers/Dart/DartWriterTests.cs | 19 ++++ 5 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 tests/Kiota.Builder.Tests/Writers/Dart/CodeClassDeclarationWriterTests.cs create mode 100644 tests/Kiota.Builder.Tests/Writers/Dart/CodeClassEndWriterTests.cs create mode 100644 tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index 2acb33404d..00697d91e8 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -5,10 +5,9 @@ using Kiota.Builder.OrderComparers; namespace Kiota.Builder.Writers.Dart; -public class CodeBlockEndWriter : BaseElementWriter +public class CodeBlockEndWriter : ICodeElementWriter { - public CodeBlockEndWriter(DartConventionService conventionService) : base(conventionService) { } - public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) + public void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); writer.CloseBlock(); diff --git a/src/Kiota.Builder/Writers/Dart/DartWriter.cs b/src/Kiota.Builder/Writers/Dart/DartWriter.cs index cf5b2ba539..f368db63a8 100644 --- a/src/Kiota.Builder/Writers/Dart/DartWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/DartWriter.cs @@ -8,7 +8,7 @@ public DartWriter(string rootPath, string clientNamespaceName) PathSegmenter = new DartPathSegmenter(rootPath, clientNamespaceName); var conventionService = new DartConventionService(); AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService, clientNamespaceName, (DartPathSegmenter)PathSegmenter)); - AddOrReplaceCodeElementWriter(new CodeBlockEndWriter(conventionService)); + AddOrReplaceCodeElementWriter(new CodeBlockEndWriter()); AddOrReplaceCodeElementWriter(new CodeEnumWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodePropertyWriter(conventionService)); diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeClassDeclarationWriterTests.cs new file mode 100644 index 0000000000..316990a799 --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeClassDeclarationWriterTests.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; + +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Writers; +using Kiota.Builder.Writers.Dart; + +using Xunit; + +namespace Kiota.Builder.Tests.Writers.Dart; +public sealed class CodeClassDeclarationWriterTests : IDisposable +{ + private const string DefaultPath = "./"; + private const string DefaultName = "name"; + private const string DefaultNameSpace = "ns"; + private readonly StringWriter tw; + private readonly LanguageWriter writer; + private readonly CodeClassDeclarationWriter codeElementWriter; + private readonly CodeClass parentClass; + private readonly CodeNamespace root; + + public CodeClassDeclarationWriterTests() + { + writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.Dart, DefaultPath, DefaultName); + codeElementWriter = new CodeClassDeclarationWriter(new DartConventionService(), DefaultNameSpace, (Builder.PathSegmenters.DartPathSegmenter)writer.PathSegmenter); + tw = new StringWriter(); + writer.SetTextWriter(tw); + root = CodeNamespace.InitRootNamespace(); + parentClass = new() + { + Name = "parentClass" + }; + root.AddClass(parentClass); + } + public void Dispose() + { + tw?.Dispose(); + GC.SuppressFinalize(this); + } + [Fact] + public void WritesSimpleDeclaration() + { + codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); + var result = tw.ToString(); + Assert.Contains("class", result); + } + [Fact] + public void WritesImplementation() + { + var declaration = parentClass.StartBlock; + declaration.AddImplements(new CodeType + { + Name = "someInterface" + }); + codeElementWriter.WriteCodeElement(declaration, writer); + var result = tw.ToString(); + Assert.Contains("implements someInterface", result); + } + [Fact] + public void WritesInheritance() + { + var declaration = parentClass.StartBlock; + declaration.Inherits = new() + { + Name = "someParent" + }; + codeElementWriter.WriteCodeElement(declaration, writer); + var result = tw.ToString(); + Assert.Contains("extends", result); + Assert.Contains("SomeParent", result); + } + [Fact] + public void WritesImports() + { + var declaration = parentClass.StartBlock; + CodeClass messageClass = new() + { + Name = "Message" + }; + root.AddClass(messageClass); + declaration.AddUsings(new CodeUsing() + { + Name = "project.graph", + Declaration = new() + { + Name = "Message", + TypeDefinition = messageClass + } + }); + codeElementWriter.WriteCodeElement(declaration, writer); + var result = tw.ToString(); + Assert.Contains("import './message.dart';", result); + } +} diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeClassEndWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeClassEndWriterTests.cs new file mode 100644 index 0000000000..c590b2bc7f --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeClassEndWriterTests.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using System.Linq; + +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Writers; +using Kiota.Builder.Writers.Dart; + +using Xunit; + +namespace Kiota.Builder.Tests.Writers.Dart; +public sealed class CodeClassEndWriterTests : IDisposable +{ + private const string DefaultPath = "./"; + private const string DefaultName = "name"; + private readonly StringWriter tw; + private readonly LanguageWriter writer; + private readonly CodeBlockEndWriter codeElementWriter; + private readonly CodeClass parentClass; + public CodeClassEndWriterTests() + { + codeElementWriter = new CodeBlockEndWriter(); + writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.Dart, DefaultPath, DefaultName); + tw = new StringWriter(); + writer.SetTextWriter(tw); + var root = CodeNamespace.InitRootNamespace(); + parentClass = new CodeClass + { + Name = "parentClass" + }; + root.AddClass(parentClass); + } + public void Dispose() + { + tw?.Dispose(); + GC.SuppressFinalize(this); + } + [Fact] + public void ClosesNonNestedClasses() + { + codeElementWriter.WriteCodeElement(parentClass.EndBlock, writer); + var result = tw.ToString(); + Assert.Equal(1, result.Count(x => x == '}')); + } +} diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs new file mode 100644 index 0000000000..11c3086f0d --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs @@ -0,0 +1,19 @@ +using System; + +using Kiota.Builder.Writers.Dart; + +using Xunit; + +namespace Kiota.Builder.Tests.Writers.Dart; +public class DartWriterTests +{ + [Fact] + public void Instantiates() + { + var writer = new DartWriter("./", "graph"); + Assert.NotNull(writer); + Assert.NotNull(writer.PathSegmenter); + Assert.Throws(() => new DartWriter(null, "graph")); + Assert.Throws(() => new DartWriter("./", null)); + } +} From 2ffaee33705e174603e6262247b9fc1d58afb920 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 30 Oct 2024 14:01:50 +0100 Subject: [PATCH 117/194] Added enumwriter test --- .../Writers/Dart/CodeEnumWriterTests.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs new file mode 100644 index 0000000000..878f8958dc --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using System.Linq; + +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; +using Kiota.Builder.Writers; + +using Xunit; + +namespace Kiota.Builder.Tests.Writers.Dart; +public sealed class CodeEnumWriterTests : IDisposable +{ + private const string DefaultPath = "./"; + private const string DefaultName = "name"; + private readonly StringWriter tw; + private readonly LanguageWriter writer; + private readonly CodeEnum currentEnum; + private const string EnumName = "SomeEnum"; + public CodeEnumWriterTests() + { + writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.Dart, DefaultPath, DefaultName); + tw = new StringWriter(); + writer.SetTextWriter(tw); + var root = CodeNamespace.InitRootNamespace(); + currentEnum = root.AddEnum(new CodeEnum + { + Name = EnumName, + }).First(); + } + public void Dispose() + { + tw?.Dispose(); + GC.SuppressFinalize(this); + } + [Fact] + public void WritesEnum() + { + const string optionName = "option1"; + currentEnum.AddOption(new CodeEnumOption { Name = optionName, SerializationName = optionName }); + writer.Write(currentEnum); + var result = tw.ToString(); + Assert.Contains("enum", result); + Assert.Contains(EnumName, result); + Assert.Contains($"{optionName}(\"{optionName}\")", result); + Assert.Contains($"const {EnumName}(this.value);", result); + Assert.Contains("final String value;", result); + } + [Fact] + public void DoesntWriteAnythingOnNoOption() + { + writer.Write(currentEnum); + var result = tw.ToString(); + Assert.Empty(result); + } + [Fact] + public void WritesEnumOptionDescription() + { + var option = new CodeEnumOption + { + Documentation = new() + { + DescriptionTemplate = "Some option description", + }, + Name = "option1", + }; + currentEnum.AddOption(option); + writer.Write(currentEnum); + var result = tw.ToString(); + Console.WriteLine(result); + Assert.Contains($"/// {option.Documentation.DescriptionTemplate}", result); + } + [Fact] + public void WritesEnumSerializationValue() + { + var OptionName = "plus1"; + var SerializationValue = "+1"; + var option = new CodeEnumOption + { + Name = OptionName, + SerializationName = SerializationValue + }; + currentEnum.AddOption(option); + writer.Write(currentEnum); + var result = tw.ToString(); + Assert.Contains($"{OptionName}(\"{SerializationValue}\")", result); + } +} From 11cdb6c53e59dec28c4aa0dbdf7fb95bbf959b7c Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Thu, 31 Oct 2024 11:58:47 +0100 Subject: [PATCH 118/194] More and more naming moved into DartRefiner And from the different writers. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index df359e55ab..5156e3e0e0 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -199,6 +199,7 @@ private static void CorrectCommonNames(CodeElement currentElement) currentElement.Parent is CodeClass parentClass) { parentClass.RenameChildElement(m.Name, m.Name.ToFirstCharacterLowerCase()); + parentClass.Name = parentClass.Name.ToFirstCharacterUpperCase(); } else if (currentElement is CodeIndexer i) { @@ -233,6 +234,7 @@ private static void CorrectMethodType(CodeMethod currentMethod) .Select(static x => x.Type) .Union(new[] { currentMethod.ReturnType }) .ToArray()); + currentMethod.Parameters.ToList().ForEach(static x => x.Name = x.Name.ToFirstCharacterLowerCase()); } private static void CorrectPropertyType(CodeProperty currentProperty) @@ -274,9 +276,7 @@ private static void CorrectPropertyType(CodeProperty currentProperty) currentProperty.Type.Name = "Map"; if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) currentProperty.DefaultValue = "{}"; - } - else if (currentProperty.IsOfKind(CodePropertyKind.Custom)) - { + } else { currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); } currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); From 4b82519aba3bff8335cd3f71105fa8a21031480e Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 31 Oct 2024 15:11:09 +0100 Subject: [PATCH 119/194] Added tests for codemethodwriter and misc fixes --- src/Kiota.Builder/Refiners/DartRefiner.cs | 4 + .../Writers/Dart/CodeMethodWriter.cs | 25 +- .../Writers/Dart/DartConventionService.cs | 4 +- .../Writers/Dart/CodeMethodWriterTests.cs | 1555 +++++++++++++++++ 4 files changed, 1573 insertions(+), 15 deletions(-) create mode 100644 tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 902b76a381..3c2dadcbcb 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -428,6 +428,10 @@ private void EscapeStringValues(CodeElement currentElement) property.DefaultValue = property.DefaultValue.Replace("$", "\\$", StringComparison.Ordinal); } } + else if (currentElement is CodeMethod method && method.HasUrlTemplateOverride) + { + method.UrlTemplateOverride = method.UrlTemplateOverride.Replace("$", "\\$", StringComparison.Ordinal); + } CrawlTree(currentElement, EscapeStringValues); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index c08d3ee872..8192845edb 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -330,15 +330,13 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; } - else if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) + else if (propWithDefault.Type is CodeType propertyType2) { defaultValue = defaultValue.Trim('"'); - defaultValue = $"'{defaultValue}'"; - } - else if (propWithDefault.Type is CodeType propertyType3 && propertyType3.Name.Equals("Boolean", StringComparison.Ordinal)) - { - defaultValue = defaultValue.Trim('"'); - defaultValue = $"{defaultValue}"; + if (propertyType2.Name.Equals("String", StringComparison.Ordinal)) + { + defaultValue = $"'{defaultValue}'"; + } } writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue}{separator}"); } @@ -519,7 +517,8 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req if (currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate) is not CodeProperty urlTemplateProperty) throw new InvalidOperationException("url template property cannot be null"); var operationName = codeElement.HttpMethod.ToString(); - writer.WriteLine($"var {RequestInfoVarName} = RequestInformation(httpMethod : HttpMethod.{operationName?.ToLowerInvariant()}, {currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate)?.Name} : {GetPropertyCall(urlTemplateProperty, "string.Empty")}, {currentClass.GetPropertyOfKind(CodePropertyKind.PathParameters)?.Name} : {GetPropertyCall(urlTemplateParamsProperty, "string.Empty")});"); + var urlTemplateValue = codeElement.HasUrlTemplateOverride ? $"'{codeElement.UrlTemplateOverride}'" : GetPropertyCall(urlTemplateProperty, "''"); + writer.WriteLine($"var {RequestInfoVarName} = RequestInformation(httpMethod : HttpMethod.{operationName?.ToLowerInvariant()}, {urlTemplateProperty.Name} : {urlTemplateValue}, {urlTemplateParamsProperty.Name} : {GetPropertyCall(urlTemplateParamsProperty, "string.Empty")});"); if (requestParams.requestConfiguration != null && requestParams.requestConfiguration.Type is CodeType paramType) { @@ -629,10 +628,10 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas writer.IncreaseIndent(); } var firstPropertyName = complexProperties.First().Name.ToFirstCharacterLowerCase(); - var propertiesNames = complexProperties.Skip(0) + var propertiesNames = complexProperties.Skip(1).Any() ? complexProperties.Skip(1) .Select(static x => x.Name.ToFirstCharacterLowerCase()) .OrderBy(static x => x) - .Aggregate(static (x, y) => $"{x}, {y}"); + .Aggregate(static (x, y) => $"{x}, {y}") : string.Empty; var propertiesList = string.IsNullOrEmpty(propertiesNames) ? "" : $", [{propertiesNames}]"; writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {firstPropertyName}{propertiesList});"); if (includeElse) @@ -745,7 +744,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua $"[{GetParameterSignatureWithNullableRefType(p, code)}]" : conventions.GetParameterSignature(p, code)) .ToList()); - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}{async} {{"); + writer.WriteLine($"{staticModifier}{completeReturnTypeWithNullable}{conventions.GetAccessModifier(code.Access)}{methodName}({nullableParameters}){baseSuffix}{async} {{"); } else if (parentClass.IsOfKind(CodeClassKind.Model) && code.IsOfKind(CodeMethodKind.Custom) && code.Name.EqualsIgnoreCase("copyWith")) { @@ -753,11 +752,11 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var ownParameters = string.Join(", ", parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData) .Where(p => !conventions.ErrorClassPropertyExistsInSuperClass(p)) .Select(p => $"{GetPrefix(p)}{conventions.TranslateType(p.Type)}{getSuffix(p)}? {p.Name.ToFirstCharacterLowerCase()}")); - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({openingBracket}{parentParameters}{ownParameters} }}){{"); + writer.WriteLine($"{staticModifier}{completeReturnType}{conventions.GetAccessModifier(code.Access)}{methodName}({openingBracket}{parentParameters}{ownParameters} }}){{"); } else { - writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{completeReturnType}{methodName}({parameters}{closingparenthesis}{baseSuffix}{async} {openingBracket}"); + writer.WriteLine($"{staticModifier}{completeReturnType}{conventions.GetAccessModifier(code.Access)}{methodName}({parameters}{closingparenthesis}{baseSuffix}{async} {openingBracket}"); } } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 17e069924d..4cf1d2ab8b 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -60,7 +60,7 @@ public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEn writer.WriteLine($"{DocCommentPrefix}{additionalComment}"); if (documentation.ExternalDocumentationAvailable) - writer.WriteLine($"{DocCommentPrefix}@see {documentation.DocumentationLabel}"); + writer.WriteLine($"{DocCommentPrefix} [{documentation.DocumentationLabel}]({documentation.DocumentationLink})"); } } @@ -87,7 +87,7 @@ private string[] GetDeprecationInformationForDocumentationComment(IDeprecableEle public override string GetAccessModifier(AccessModifier access) { // Dart does not support access modifiers - return ""; + return access == AccessModifier.Private ? "_" : string.Empty; } #pragma warning disable CA1822 // Method should be static diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs new file mode 100644 index 0000000000..b35d12a1c7 --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs @@ -0,0 +1,1555 @@ +using System; +using System.IO; +using System.Linq; +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Extensions; +using Kiota.Builder.Writers; +using Kiota.Builder.Writers.Dart; + +using Xunit; + +namespace Kiota.Builder.Tests.Writers.Dart; +public sealed class CodeMethodWriterTests : IDisposable +{ + private const string DefaultPath = "./"; + private const string DefaultName = "name"; + private readonly StringWriter tw; + private readonly LanguageWriter writer; + private CodeMethod method; + private CodeClass parentClass; + private readonly CodeNamespace root; + private const string ExecuterExceptionVar = "executionException"; + private const string MethodName = "methodName"; + private const string ReturnTypeName = "Somecustomtype"; + private const string MethodDescription = "some description"; + private const string ParamDescription = "some parameter description"; + private const string ParamName = "paramName"; + public CodeMethodWriterTests() + { + writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.Dart, DefaultPath, DefaultName); + tw = new StringWriter(); + writer.SetTextWriter(tw); + root = CodeNamespace.InitRootNamespace(); + } + private void setup(bool withInheritance = false) + { + if (parentClass != null) + throw new InvalidOperationException("setup() must only be called once"); + CodeClass baseClass = default; + if (withInheritance) + { + baseClass = root.AddClass(new CodeClass + { + Name = "SomeParentClass", + }).First(); + baseClass.AddProperty(new CodeProperty + { + Name = "definedInParent", + Type = new CodeType + { + Name = "String" + }, + Kind = CodePropertyKind.Custom, + }); + } + parentClass = new CodeClass + { + Name = "ParentClass" + }; + if (withInheritance) + { + parentClass.StartBlock.Inherits = new CodeType + { + Name = "SomeParentClass", + TypeDefinition = baseClass + }; + } + root.AddClass(parentClass); + method = new CodeMethod + { + Name = MethodName, + ReturnType = new CodeType + { + Name = ReturnTypeName + } + }; + parentClass.AddMethod(method); + } + public void Dispose() + { + tw?.Dispose(); + GC.SuppressFinalize(this); + } + private void AddRequestProperties() + { + parentClass.StartBlock.Inherits = new CodeType + { + Name = "BaseRequestBuilder", + IsExternal = true, + }; + parentClass.AddProperty(new CodeProperty + { + Name = "requestAdapter", + Kind = CodePropertyKind.RequestAdapter, + Type = new CodeType + { + Name = "RequestAdapter", + } + }); + parentClass.AddProperty(new CodeProperty + { + Name = "pathParameters", + Kind = CodePropertyKind.PathParameters, + Type = new CodeType + { + Name = "String", + } + }); + parentClass.AddProperty(new CodeProperty + { + Name = "urlTemplate", + Kind = CodePropertyKind.UrlTemplate, + Type = new CodeType + { + Name = "String", + } + }); + } + private void AddSerializationProperties() + { + parentClass.AddProperty(new CodeProperty + { + Name = "additionalData", + Kind = CodePropertyKind.AdditionalData, + Type = new CodeType + { + Name = "String" + }, + Getter = new CodeMethod + { + Name = "getAdditionalData", + ReturnType = new CodeType + { + Name = "String" + } + }, + Setter = new CodeMethod + { + Name = "setAdditionalData", + ReturnType = new CodeType + { + Name = "String" + } + } + }); + parentClass.AddProperty(new CodeProperty + { + Name = "dummyProp", + Type = new CodeType + { + Name = "String" + }, + Getter = new CodeMethod + { + Name = "getDummyProp", + ReturnType = new CodeType + { + Name = "String" + }, + }, + Setter = new CodeMethod + { + Name = "setDummyProp", + ReturnType = new CodeType + { + Name = "void" + } + }, + }); + parentClass.AddProperty(new CodeProperty + { + Name = "noAccessors", + Kind = CodePropertyKind.Custom, + Type = new CodeType + { + Name = "String" + } + }); + parentClass.AddProperty(new CodeProperty + { + Name = "dummyColl", + Type = new CodeType + { + Name = "String", + CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Array, + }, + Getter = new CodeMethod + { + Name = "getDummyColl", + ReturnType = new CodeType + { + Name = "String", + CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Array, + }, + }, + Setter = new CodeMethod + { + Name = "setDummyColl", + ReturnType = new CodeType + { + Name = "void", + } + }, + }); + parentClass.AddProperty(new CodeProperty + { + Name = "dummyComplexColl", + Type = new CodeType + { + Name = "Complex", + CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Array, + TypeDefinition = new CodeClass + { + Name = "SomeComplexType" + } + }, + Getter = new CodeMethod + { + Name = "getDummyComplexColl", + ReturnType = new CodeType + { + Name = "String", + CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Array, + }, + }, + Setter = new CodeMethod + { + Name = "setDummyComplexColl", + ReturnType = new CodeType + { + Name = "void" + } + } + }); + parentClass.AddProperty(new CodeProperty + { + Name = "dummyEnumCollection", + Type = new CodeType + { + Name = "SomeEnum", + TypeDefinition = new CodeEnum + { + Name = "EnumType" + } + }, + Getter = new CodeMethod + { + Name = "getDummyEnumCollection", + ReturnType = new CodeType + { + Name = "String" + }, + }, + Setter = new CodeMethod + { + Name = "setDummyEnumCollection", + ReturnType = new CodeType + { + Name = "void" + } + } + }); + } + private CodeClass AddUnionType() + { + var complexType1 = root.AddClass(new CodeClass + { + Name = "ComplexType1", + Kind = CodeClassKind.Model, + }).First(); + var complexType2 = root.AddClass(new CodeClass + { + Name = "ComplexType2", + Kind = CodeClassKind.Model, + }).First(); + var unionType = root.AddClass(new CodeClass + { + Name = "UnionType", + Kind = CodeClassKind.Model, + OriginalComposedType = new CodeUnionType + { + Name = "UnionType", + }, + DiscriminatorInformation = new() + { + DiscriminatorPropertyName = "@odata.type", + }, + }).First(); + var cType1 = new CodeType + { + Name = "ComplexType1", + TypeDefinition = complexType1 + }; + var cType2 = new CodeType + { + Name = "ComplexType2", + TypeDefinition = complexType2, + CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Complex, + }; + var sType = new CodeType + { + Name = "String", + }; + unionType.DiscriminatorInformation.AddDiscriminatorMapping("#kiota.complexType1", new CodeType + { + Name = "ComplexType1", + TypeDefinition = cType1 + }); + unionType.DiscriminatorInformation.AddDiscriminatorMapping("#kiota.complexType2", new CodeType + { + Name = "ComplexType2", + TypeDefinition = cType2 + }); + unionType.OriginalComposedType.AddType(cType1); + unionType.OriginalComposedType.AddType(cType2); + unionType.OriginalComposedType.AddType(sType); + unionType.AddProperty(new CodeProperty + { + Name = "ComplexType1Value", + Type = cType1, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setComplexType1Value", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getComplexType1Value", + ReturnType = cType1, + Kind = CodeMethodKind.Getter, + } + }); + unionType.AddProperty(new CodeProperty + { + Name = "ComplexType2Value", + Type = cType2, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setComplexType2Value", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getComplexType2Value", + ReturnType = cType2, + Kind = CodeMethodKind.Getter, + } + }); + unionType.AddProperty(new CodeProperty + { + Name = "StringValue", + Type = sType, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setStringValue", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getStringValue", + ReturnType = sType, + Kind = CodeMethodKind.Getter, + } + }); + return unionType; + } + private CodeClass AddIntersectionType() + { + var complexType1 = root.AddClass(new CodeClass + { + Name = "ComplexType1", + Kind = CodeClassKind.Model, + }).First(); + var complexType2 = root.AddClass(new CodeClass + { + Name = "ComplexType2", + Kind = CodeClassKind.Model, + }).First(); + var complexType3 = root.AddClass(new CodeClass + { + Name = "ComplexType3", + Kind = CodeClassKind.Model, + }).First(); + var intersectionType = root.AddClass(new CodeClass + { + Name = "IntersectionType", + Kind = CodeClassKind.Model, + OriginalComposedType = new CodeIntersectionType + { + Name = "IntersectionType", + }, + DiscriminatorInformation = new() + { + DiscriminatorPropertyName = "@odata.type", + }, + }).First(); + var cType1 = new CodeType + { + Name = "ComplexType1", + TypeDefinition = complexType1 + }; + var cType2 = new CodeType + { + Name = "ComplexType2", + TypeDefinition = complexType2, + CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Complex, + }; + var cType3 = new CodeType + { + Name = "ComplexType3", + TypeDefinition = complexType3 + }; + intersectionType.DiscriminatorInformation.AddDiscriminatorMapping("#kiota.complexType1", new CodeType + { + Name = "ComplexType1", + TypeDefinition = cType1 + }); + intersectionType.DiscriminatorInformation.AddDiscriminatorMapping("#kiota.complexType2", new CodeType + { + Name = "ComplexType2", + TypeDefinition = cType2 + }); + intersectionType.DiscriminatorInformation.AddDiscriminatorMapping("#kiota.complexType3", new CodeType + { + Name = "ComplexType3", + TypeDefinition = cType3 + }); + var sType = new CodeType + { + Name = "String", + }; + intersectionType.OriginalComposedType.AddType(cType1); + intersectionType.OriginalComposedType.AddType(cType2); + intersectionType.OriginalComposedType.AddType(cType3); + intersectionType.OriginalComposedType.AddType(sType); + intersectionType.AddProperty(new CodeProperty + { + Name = "ComplexType1Value", + Type = cType1, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setComplexType1Value", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getComplexType1Value", + ReturnType = cType1, + Kind = CodeMethodKind.Getter, + } + }); + intersectionType.AddProperty(new CodeProperty + { + Name = "ComplexType2Value", + Type = cType2, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setComplexType2Value", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getComplexType2Value", + ReturnType = cType2, + Kind = CodeMethodKind.Getter, + } + }); + intersectionType.AddProperty(new CodeProperty + { + Name = "ComplexType3Value", + Type = cType3, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setComplexType3Value", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getComplexType3Value", + ReturnType = cType3, + Kind = CodeMethodKind.Getter, + } + }); + intersectionType.AddProperty(new CodeProperty + { + Name = "StringValue", + Type = sType, + Kind = CodePropertyKind.Custom, + Setter = new CodeMethod + { + Name = "setStringValue", + ReturnType = new CodeType + { + Name = "void" + }, + Kind = CodeMethodKind.Setter, + }, + Getter = new CodeMethod + { + Name = "getStringValue", + ReturnType = sType, + Kind = CodeMethodKind.Getter, + } + }); + return intersectionType; + } + private void AddRequestBodyParameters(bool useComplexTypeForBody = false) + { + var stringType = new CodeType + { + Name = "String", + }; + var requestConfigClass = parentClass.AddInnerClass(new CodeClass + { + Name = "RequestConfig", + Kind = CodeClassKind.RequestConfiguration, + }).First(); + requestConfigClass.AddProperty(new() + { + Name = "h", + Kind = CodePropertyKind.Headers, + Type = stringType, + }, + new() + { + Name = "q", + Kind = CodePropertyKind.QueryParameters, + Type = stringType, + }, + new() + { + Name = "o", + Kind = CodePropertyKind.Options, + Type = stringType, + }); + method.AddParameter(new CodeParameter + { + Name = "b", + Kind = CodeParameterKind.RequestBody, + Type = useComplexTypeForBody ? new CodeType + { + Name = "SomeComplexTypeForRequestBody", + TypeDefinition = root.AddClass(new CodeClass + { + Name = "SomeComplexTypeForRequestBody", + Kind = CodeClassKind.Model, + }).First(), + } : stringType, + }); + var configType = new CodeType + { + Name = "RequestConfig", + TypeDefinition = requestConfigClass, + ActionOf = true, + }; + configType.AddGenericTypeParameterValue(new CodeType { Name = "DefaultQueryParameters" }); + method.AddParameter(new CodeParameter + { + Name = "c", + Kind = CodeParameterKind.RequestConfiguration, + Type = configType, + Optional = true, + }); + } + [Fact] + public void WritesVoidTypeForExecutor() + { + setup(); + method.Kind = CodeMethodKind.RequestExecutor; + method.HttpMethod = HttpMethod.Get; + method.AddParameter(new CodeParameter() + { + Type = new CodeType(), + Kind = CodeParameterKind.RequestConfiguration + }); + method.ReturnType = new CodeType + { + Name = "void", + }; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("Future", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesRequestBuilder() + { + setup(); + method.Kind = CodeMethodKind.RequestBuilderBackwardCompatibility; + Assert.Throws(() => writer.Write(method)); + } + [Fact] + public void WritesRequestBodiesThrowOnNullHttpMethod() + { + setup(); + method.Kind = CodeMethodKind.RequestExecutor; + Assert.Throws(() => writer.Write(method)); + method.Kind = CodeMethodKind.RequestGenerator; + Assert.Throws(() => writer.Write(method)); + } + [Fact] + public void WritesRequestExecutorBody() + { + setup(); + method.Kind = CodeMethodKind.RequestExecutor; + method.HttpMethod = HttpMethod.Get; + var error4XX = root.AddClass(new CodeClass + { + Name = "Error4XX", + }).First(); + var error5XX = root.AddClass(new CodeClass + { + Name = "Error5XX", + }).First(); + var error401 = root.AddClass(new CodeClass + { + Name = "Error401", + }).First(); + method.AddErrorMapping("4XX", new CodeType { Name = "Error4XX", TypeDefinition = error4XX }); + method.AddErrorMapping("5XX", new CodeType { Name = "Error5XX", TypeDefinition = error5XX }); + method.AddErrorMapping("401", new CodeType { Name = "Error401", TypeDefinition = error401 }); + AddRequestBodyParameters(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("var requestInfo", result); + Assert.Contains("Map> errorMapping = {", result); + Assert.Contains("'401' : Error401.createFromDiscriminatorValue,", result); + Assert.Contains("'4XX' : Error4XX.createFromDiscriminatorValue,", result); + Assert.Contains("'5XX' : Error5XX.createFromDiscriminatorValue,", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void DoesntCreateDictionaryOnEmptyErrorMapping() + { + setup(); + method.Kind = CodeMethodKind.RequestExecutor; + method.HttpMethod = HttpMethod.Get; + AddRequestBodyParameters(); + writer.Write(method); + var result = tw.ToString(); + Assert.DoesNotContain("Map> errorMapping = {", result); + Assert.Contains("{}", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesModelFactoryBody() + { + setup(); + var parentModel = root.AddClass(new CodeClass + { + Name = "ParentModel", + Kind = CodeClassKind.Model, + }).First(); + var childModel = root.AddClass(new CodeClass + { + Name = "ChildModel", + Kind = CodeClassKind.Model, + }).First(); + childModel.StartBlock.Inherits = new CodeType + { + Name = "ParentModel", + TypeDefinition = parentModel, + }; + var factoryMethod = parentModel.AddMethod(new CodeMethod + { + Name = "factory", + Kind = CodeMethodKind.Factory, + ReturnType = new CodeType + { + Name = "ParentModel", + TypeDefinition = parentModel, + }, + IsStatic = true, + }).First(); + parentModel.DiscriminatorInformation.AddDiscriminatorMapping("ns.childmodel", new CodeType + { + Name = "childModel", + TypeDefinition = childModel, + }); + parentModel.DiscriminatorInformation.DiscriminatorPropertyName = "@odata.type"; + factoryMethod.AddParameter(new CodeParameter + { + Name = "parseNode", + Kind = CodeParameterKind.ParseNode, + Type = new CodeType + { + Name = "ParseNode", + TypeDefinition = new CodeClass + { + Name = "ParseNode", + }, + IsExternal = true, + }, + Optional = false, + }); + writer.Write(factoryMethod); + var result = tw.ToString(); + Assert.Contains("var mappingValue = parseNode.getChildNode('@odata.type')", result); + Assert.Contains("return switch(mappingValue) {", result); + Assert.Contains("'ns.childmodel' => ChildModel(),", result); + Assert.Contains("_ => ParentModel()", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void DoesntWriteFactorySwitchOnMissingParameter() + { + setup(); + var parentModel = root.AddClass(new CodeClass + { + Name = "parentModel", + Kind = CodeClassKind.Model, + }).First(); + var childModel = root.AddClass(new CodeClass + { + Name = "childModel", + Kind = CodeClassKind.Model, + }).First(); + childModel.StartBlock.Inherits = new CodeType + { + Name = "parentModel", + TypeDefinition = parentModel, + }; + var factoryMethod = parentModel.AddMethod(new CodeMethod + { + Name = "factory", + Kind = CodeMethodKind.Factory, + ReturnType = new CodeType + { + Name = "parentModel", + TypeDefinition = parentModel, + }, + IsStatic = true, + }).First(); + parentModel.DiscriminatorInformation.AddDiscriminatorMapping("ns.childmodel", new CodeType + { + Name = "childModel", + TypeDefinition = childModel, + }); + parentModel.DiscriminatorInformation.DiscriminatorPropertyName = "@odata.type"; + Assert.Throws(() => writer.Write(factoryMethod)); + } + [Fact] + public void DoesntWriteFactorySwitchOnEmptyPropertyName() + { + setup(); + var parentModel = root.AddClass(new CodeClass + { + Name = "ParentModel", + Kind = CodeClassKind.Model, + }).First(); + var childModel = root.AddClass(new CodeClass + { + Name = "ChildModel", + Kind = CodeClassKind.Model, + }).First(); + childModel.StartBlock.Inherits = new CodeType + { + Name = "parentModel", + TypeDefinition = parentModel, + }; + var factoryMethod = parentModel.AddMethod(new CodeMethod + { + Name = "factory", + Kind = CodeMethodKind.Factory, + ReturnType = new CodeType + { + Name = "ParentModel", + TypeDefinition = parentModel, + }, + IsStatic = true, + }).First(); + parentModel.DiscriminatorInformation.AddDiscriminatorMapping("ns.childmodel", new CodeType + { + Name = "ChildModel", + TypeDefinition = childModel, + }); + parentModel.DiscriminatorInformation.DiscriminatorPropertyName = string.Empty; + factoryMethod.AddParameter(new CodeParameter + { + Name = "parseNode", + Kind = CodeParameterKind.ParseNode, + Type = new CodeType + { + Name = "ParseNode", + TypeDefinition = new CodeClass + { + Name = "ParseNode", + }, + IsExternal = true, + }, + Optional = false, + }); + writer.Write(factoryMethod); + var result = tw.ToString(); + Assert.DoesNotContain("var mappingValue = parseNode.getChildNode('@odata.type')", result); + Assert.DoesNotContain("return switch(mappingValue) {", result); + Assert.DoesNotContain("'ns.childmodel' => ChildModel(),", result); + Assert.Contains("return ParentModel()", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void DoesntWriteFactorySwitchOnEmptyMappings() + { + setup(); + var parentModel = root.AddClass(new CodeClass + { + Name = "ParentModel", + Kind = CodeClassKind.Model, + }).First(); + var factoryMethod = parentModel.AddMethod(new CodeMethod + { + Name = "factory", + Kind = CodeMethodKind.Factory, + ReturnType = new CodeType + { + Name = "ParentModel", + TypeDefinition = parentModel, + }, + IsStatic = true, + }).First(); + parentModel.DiscriminatorInformation.DiscriminatorPropertyName = "@odata.type"; + factoryMethod.AddParameter(new CodeParameter + { + Name = "parseNode", + Kind = CodeParameterKind.ParseNode, + Type = new CodeType + { + Name = "ParseNode", + TypeDefinition = new CodeClass + { + Name = "ParseNode", + }, + IsExternal = true, + }, + Optional = false, + }); + writer.Write(factoryMethod); + var result = tw.ToString(); + Assert.DoesNotContain("final ParseNode mappingValueNode = parseNode.getChildNode(\"@odata.type\")", result); + Assert.DoesNotContain("if (mappingValueNode != null) {", result); + Assert.DoesNotContain("final String mappingValue = mappingValueNode.getStringValue()", result); + Assert.DoesNotContain("switch (mappingValue) {", result); + Assert.DoesNotContain("case \"ns.childmodel\": return new ChildModel();", result); + Assert.Contains("return ParentModel()", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesRequestGeneratorBodyForMultipart() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Post; + AddRequestProperties(); + AddRequestBodyParameters(); + method.Parameters.First(static x => x.IsOfKind(CodeParameterKind.RequestBody)).Type = new CodeType { Name = "MultipartBody", IsExternal = true }; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("setContentFromParsable", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesRequestExecutorBodyForCollections() + { + setup(); + method.Kind = CodeMethodKind.RequestExecutor; + method.HttpMethod = HttpMethod.Get; + method.ReturnType.CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Array; + AddRequestBodyParameters(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("sendCollection", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + + //vanaf hier, heeft ook configure nodig, dus wel generics + [Fact] + public void WritesRequestGeneratorBodyForScalar() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Get; + AddRequestProperties(); + AddRequestBodyParameters(); + method.AcceptedResponseTypes.Add("application/json"); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("var requestInfo = RequestInformation(httpMethod : HttpMethod.get, urlTemplate : urlTemplate, pathParameters : pathParameters);", result); + Assert.Contains("requestInfo.configure(c, () => DefaultQueryParameters());", result); + Assert.Contains("requestInfo.headers.put('Accept', 'application/json');", result); + Assert.Contains("requestInfo.setContentFromScalar(requestAdapter, '', b)", result); + Assert.Contains("return requestInfo;", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesRequestGeneratorBodyForScalarCollection() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Get; + AddRequestProperties(); + AddRequestBodyParameters(); + method.AcceptedResponseTypes.Add("application/json"); + var bodyParameter = method.Parameters.OfKind(CodeParameterKind.RequestBody); + bodyParameter.Type.CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Complex; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("var requestInfo = RequestInformation(httpMethod : HttpMethod.get, urlTemplate : urlTemplate, pathParameters : pathParameters)", result); + Assert.Contains("requestInfo.configure(c, () => DefaultQueryParameters());", result); + Assert.Contains("requestInfo.headers.put('Accept', 'application/json');", result); + Assert.Contains("setContentFromScalarCollection", result); + Assert.Contains("return requestInfo;", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesRequestGeneratorBodyForParsable() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Get; + AddRequestProperties(); + AddRequestBodyParameters(true); + method.AcceptedResponseTypes.Add("application/json"); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("var requestInfo = RequestInformation(httpMethod : HttpMethod.get, urlTemplate : urlTemplate, pathParameters : pathParameters)", result); + Assert.Contains("requestInfo.configure(c, () => DefaultQueryParameters());", result); + Assert.Contains("requestInfo.headers.put('Accept', 'application/json')", result); + Assert.Contains("setContentFromParsable", result); + Assert.Contains("return requestInfo;", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesRequestGeneratorBodyWhenUrlTemplateIsOverrode() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Get; + AddRequestProperties(); + AddRequestBodyParameters(true); + method.AcceptedResponseTypes.Add("application/json"); + method.UrlTemplateOverride = "{baseurl+}/foo/bar"; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("var requestInfo = RequestInformation(httpMethod : HttpMethod.get, urlTemplate : '{baseurl+}/foo/bar', pathParameters : pathParameters)", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesUnionDeSerializerBody() + { + setup(); + var wrapper = AddUnionType(); + var deserializationMethod = wrapper.AddMethod(new CodeMethod + { + Name = "getFieldDeserializers", + Kind = CodeMethodKind.Deserializer, + IsAsync = false, + ReturnType = new CodeType + { + Name = "Map", + }, + }).First(); + writer.Write(deserializationMethod); + var result = tw.ToString(); + Assert.Contains("complexType1Value != null", result); + Assert.Contains("return complexType1Value!.getFieldDeserializers()", result); + Assert.Contains("Map()", result); + AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "Map()", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesIntersectionDeSerializerBody() + { + setup(); + var wrapper = AddIntersectionType(); + var deserializationMethod = wrapper.AddMethod(new CodeMethod + { + Name = "getFieldDeserializers", + Kind = CodeMethodKind.Deserializer, + IsAsync = false, + ReturnType = new CodeType + { + Name = "Map", + }, + }).First(); + writer.Write(deserializationMethod); + var result = tw.ToString(); + Assert.Contains("Map deserializers = {};", result); + Assert.Contains("if(complexType1Value != null){complexType1Value!.getFieldDeserializers().forEach((k,v) => deserializers.putIfAbsent(k, ()=>v));}", result); + Assert.Contains("if(complexType3Value != null){complexType3Value!.getFieldDeserializers().forEach((k,v) => deserializers.putIfAbsent(k, ()=>v));}", result); + Assert.Contains("return deserializers", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesInheritedDeSerializerBody() + { + setup(true); + method.Kind = CodeMethodKind.Deserializer; + method.IsAsync = false; + AddSerializationProperties(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("super.getFieldDeserializers()", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesDeSerializerBody() + { + setup(); + method.Kind = CodeMethodKind.Deserializer; + method.IsAsync = false; + AddSerializationProperties(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("getStringValue", result); + Assert.Contains("getCollectionOfPrimitiveValues", result); + Assert.Contains("getCollectionOfObjectValues", result); + Assert.Contains("getEnumValue", result); + Assert.DoesNotContain("definedInParent", result, StringComparison.OrdinalIgnoreCase); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesInheritedSerializerBody() + { + setup(true); + method.Kind = CodeMethodKind.Serializer; + method.IsAsync = false; + AddSerializationProperties(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("super.serialize", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesUnionSerializerBody() + { + setup(); + var wrapper = AddUnionType(); + var serializationMethod = wrapper.AddMethod(new CodeMethod + { + Name = "factory", + Kind = CodeMethodKind.Serializer, + IsAsync = false, + ReturnType = new CodeType + { + Name = "void", + }, + }).First(); + serializationMethod.AddParameter(new CodeParameter + { + Name = "writer", + Kind = CodeParameterKind.Serializer, + Type = new CodeType + { + Name = "SerializationWriter" + } + }); + writer.Write(serializationMethod); + var result = tw.ToString(); + Assert.DoesNotContain("super.serialize(writer)", result); + Assert.Contains("if(complexType1Value != null) {", result); + Assert.Contains("writer.writeObjectValue(null, complexType1Value)", result); + Assert.Contains("stringValue != null", result); + Assert.Contains("writer.writeStringValue(null, stringValue)", result); + Assert.Contains("complexType2Value != null", result); + Assert.Contains("writer.writeCollectionOfObjectValues(null, complexType2Value)", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesIntersectionSerializerBody() + { + setup(); + var wrapper = AddIntersectionType(); + var serializationMethod = wrapper.AddMethod(new CodeMethod + { + Name = "factory", + Kind = CodeMethodKind.Serializer, + IsAsync = false, + ReturnType = new CodeType + { + Name = "void", + }, + }).First(); + serializationMethod.AddParameter(new CodeParameter + { + Name = "writer", + Kind = CodeParameterKind.Serializer, + Type = new CodeType + { + Name = "SerializationWriter" + } + }); + writer.Write(serializationMethod); + var result = tw.ToString(); + Assert.DoesNotContain("super.serialize(writer)", result); + Assert.DoesNotContain("complexType1Value != null) {", result); + Assert.Contains("writer.writeObjectValue(null, complexType1Value, [complexType3Value])", result); + Assert.Contains("stringValue != null", result); + Assert.Contains("writer.writeStringValue(null, stringValue)", result); + Assert.Contains("complexType2Value != null", result); + Assert.Contains("writer.writeCollectionOfObjectValues(null, complexType2Value)", result); + AssertExtensions.Before("writer.writeStringValue(null, stringValue)", "writer.writeObjectValue(null, complexType1Value, [complexType3Value])", result); + AssertExtensions.Before("writer.writeCollectionOfObjectValues(null, complexType2Value)", "writer.writeObjectValue(null, complexType1Value, [complexType3Value])", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesSerializerBody() + { + setup(); + method.Kind = CodeMethodKind.Serializer; + method.IsAsync = false; + AddSerializationProperties(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("writeStringValue", result); + Assert.Contains("writeCollectionOfPrimitiveValues", result); + Assert.Contains("writeCollectionOfObjectValues", result); + Assert.Contains("writeEnumValue", result); + Assert.Contains("writeAdditionalData(additionalData);", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesMethodDescriptionLink() + { + setup(); + method.Documentation.DescriptionTemplate = MethodDescription; + method.Documentation.DocumentationLabel = "see more"; + method.Documentation.DocumentationLink = new("https://foo.org/docs"); + method.IsAsync = false; + var parameter = new CodeParameter + { + Documentation = new() + { + DescriptionTemplate = ParamDescription, + }, + Name = ParamName, + Type = new CodeType + { + Name = "String" + } + }; + method.AddParameter(parameter); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("[see more](https://foo.org/docs)", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void Defensive() + { + setup(); + var codeMethodWriter = new CodeMethodWriter(new DartConventionService()); + Assert.Throws(() => codeMethodWriter.WriteCodeElement(null, writer)); + Assert.Throws(() => codeMethodWriter.WriteCodeElement(method, null)); + var originalParent = method.Parent; + method.Parent = CodeNamespace.InitRootNamespace(); + Assert.Throws(() => codeMethodWriter.WriteCodeElement(method, writer)); + method.Parent = originalParent; + } + [Fact] + public void ThrowsIfParentIsNotClass() + { + setup(); + method.Parent = CodeNamespace.InitRootNamespace(); + Assert.Throws(() => writer.Write(method)); + } + [Fact] + public void WritesReturnType() + { + setup(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains($"{ReturnTypeName} {MethodName}", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesPublicMethodByDefault() + { + setup(); + writer.Write(method); + var result = tw.ToString(); + Assert.DoesNotContain("_", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesPrivateMethod() + { + setup(); + method.Access = AccessModifier.Private; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("_", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesPathParameterRequestBuilder() + { + setup(); + AddRequestProperties(); + method.Kind = CodeMethodKind.RequestBuilderWithParameters; + method.AddParameter(new CodeParameter + { + Name = "pathParam", + Kind = CodeParameterKind.Path, + Type = new CodeType + { + Name = "String" + } + }); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("requestAdapter", result); + Assert.Contains("pathParameters", result); + Assert.Contains("pathParam", result); + Assert.Contains("return", result); + } + [Fact] + public void WritesConstructor() + { + setup(); + method.Kind = CodeMethodKind.Constructor; + var defaultValue = "\"someVal\""; + var propName = "propWithDefaultValue"; + parentClass.Kind = CodeClassKind.RequestBuilder; + parentClass.AddProperty(new CodeProperty + { + Name = propName, + DefaultValue = defaultValue, + Kind = CodePropertyKind.Custom, + Type = new CodeType + { + Name = "String" + } + }); + var defaultValueNull = "\"null\""; + var nullPropName = "propWithDefaultNullValue"; + parentClass.AddProperty(new CodeProperty + { + Name = nullPropName, + DefaultValue = defaultValueNull, + Kind = CodePropertyKind.Custom, + Type = new CodeType + { + Name = "int", + IsNullable = true + } + }); + var defaultValueBool = "true"; + var boolPropName = "propWithDefaultBoolValue"; + parentClass.AddProperty(new CodeProperty + { + Name = boolPropName, + DefaultValue = defaultValueBool, + Kind = CodePropertyKind.Custom, + Type = new CodeType + { + Name = "Boolean", + IsNullable = true + } + }); + AddRequestProperties(); + method.AddParameter(new CodeParameter + { + Name = "pathParameters", + Kind = CodeParameterKind.PathParameters, + Type = new CodeType + { + Name = "Map" + } + }); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains(parentClass.Name, result); + Assert.Contains($"{propName} = '{defaultValue.TrimQuotes()}'", result); + Assert.Contains($"{nullPropName} = {defaultValueNull.TrimQuotes()}", result); + Assert.Contains($"{boolPropName} = {defaultValueBool.TrimQuotes()}", result); + Assert.Contains("super", result); + } + [Fact] + public void WritesWithUrl() + { + setup(); + method.Kind = CodeMethodKind.RawUrlBuilder; + Assert.Throws(() => writer.Write(method)); + method.AddParameter(new CodeParameter + { + Name = "rawUrl", + Kind = CodeParameterKind.RawUrl, + Type = new CodeType + { + Name = "String" + }, + }); + Assert.Throws(() => writer.Write(method)); + AddRequestProperties(); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains($"return {parentClass.Name}", result); + } + [Fact] + public void DoesNotWriteConstructorWithDefaultFromComposedType() + { + setup(); + method.Kind = CodeMethodKind.Constructor; + var defaultValue = "Test Value"; + var propName = "size"; + var unionType = root.AddClass(new CodeClass + { + Name = "UnionType", + Kind = CodeClassKind.Model, + OriginalComposedType = new CodeUnionType + { + Name = "UnionType", + }, + DiscriminatorInformation = new() + { + DiscriminatorPropertyName = "@odata.type", + }, + }).First(); + parentClass.AddProperty(new CodeProperty + { + Name = propName, + DefaultValue = defaultValue, + Kind = CodePropertyKind.Custom, + Type = new CodeType { TypeDefinition = unionType } + }); + var sType = new CodeType + { + Name = "String", + }; + var arrayType = new CodeType + { + Name = "array", + }; + unionType.OriginalComposedType.AddType(sType); + unionType.OriginalComposedType.AddType(arrayType); + + writer.Write(method); + var result = tw.ToString(); + Assert.Contains(parentClass.Name, result); + Assert.DoesNotContain(defaultValue, result);//ensure the composed type is not referenced + } + [Fact] + public void WritesRawUrlConstructor() + { + setup(); + method.Kind = CodeMethodKind.RawUrlConstructor; + var defaultValue = "\"someVal\""; + var propName = "propWithDefaultValue"; + parentClass.Kind = CodeClassKind.RequestBuilder; + parentClass.AddProperty(new CodeProperty + { + Name = propName, + DefaultValue = defaultValue, + Kind = CodePropertyKind.Custom, + Type = new CodeType + { + Name = "String" + } + }); + AddRequestProperties(); + method.AddParameter(new CodeParameter + { + Name = "rawUrl", + Kind = CodeParameterKind.RawUrl, + Type = new CodeType + { + Name = "String" + } + }); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains(parentClass.Name, result); + Assert.Contains($"{propName} = '{defaultValue.TrimQuotes()}'", result); + Assert.Contains("super", result); + } + [Fact] + public void WritesApiConstructor() + { + setup(); + method.Kind = CodeMethodKind.ClientConstructor; + method.BaseUrl = "https://graph.microsoft.com/v1.0"; + parentClass.AddProperty(new CodeProperty + { + Name = "pathParameters", + Kind = CodePropertyKind.PathParameters, + Type = new CodeType + { + Name = "Dictionary", + IsExternal = true, + } + }); + var coreProp = parentClass.AddProperty(new CodeProperty + { + Name = "core", + Kind = CodePropertyKind.RequestAdapter, + Type = new CodeType + { + Name = "HttpCore", + IsExternal = true, + } + }).First(); + method.AddParameter(new CodeParameter + { + Name = "core", + Kind = CodeParameterKind.RequestAdapter, + Type = coreProp.Type, + }); + method.DeserializerModules = new() { "com.microsoft.kiota.serialization.Deserializer" }; + method.SerializerModules = new() { "com.microsoft.kiota.serialization.Serializer" }; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains(parentClass.Name, result); + Assert.Contains("registerDefaultSerializer", result); + Assert.Contains("registerDefaultDeserializer", result); + Assert.Contains($"pathParameters['baseurl'] = core.baseUrl", result); + Assert.Contains($"core.baseUrl = '{method.BaseUrl}'", result); + } + [Fact] + public void WritesApiConstructorWithBackingStore() + { + setup(); + method.Kind = CodeMethodKind.ClientConstructor; + var coreProp = parentClass.AddProperty(new CodeProperty + { + Name = "core", + Kind = CodePropertyKind.RequestAdapter, + Type = new CodeType + { + Name = "HttpCore", + IsExternal = true, + } + }).First(); + method.AddParameter(new CodeParameter + { + Name = "core", + Kind = CodeParameterKind.RequestAdapter, + Type = coreProp.Type, + }); + var backingStoreParam = new CodeParameter + { + Name = "backingStore", + Kind = CodeParameterKind.BackingStore, + Type = new CodeType + { + Name = "BackingStore", + IsExternal = true, + } + }; + method.AddParameter(backingStoreParam); + var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.Dart, DefaultPath, DefaultName); + tempWriter.SetTextWriter(tw); + tempWriter.Write(method); + var result = tw.ToString(); + Assert.Contains("enableBackingStore", result); + } + [Fact] + public void DoesntWriteReadOnlyPropertiesInSerializerBody() + { + setup(true); + method.Kind = CodeMethodKind.Serializer; + AddSerializationProperties(); + parentClass.AddProperty(new CodeProperty + { + Name = "readOnlyProperty", + ReadOnly = true, + Type = new CodeType + { + Name = "String", + }, + }); + writer.Write(method); + var result = tw.ToString(); + Assert.DoesNotContain("readOnlyProperty", result); + AssertExtensions.CurlyBracesAreClosed(result); + } + [Fact] + public void WritesDeprecationInformation() + { + setup(); + method.Deprecation = new("This method is deprecated", DateTimeOffset.Parse("2020-01-01T00:00:00Z"), DateTimeOffset.Parse("2021-01-01T00:00:00Z"), "v2.0"); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("This method is deprecated", result); + Assert.Contains("2020-01-01", result); + Assert.Contains("2021-01-01", result); + Assert.Contains("v2.0", result); + Assert.Contains("@Deprecated", result); + } + [Fact] + public void WritesDeprecationInformationFromBuilder() + { + setup(); + var newMethod = method.Clone() as CodeMethod; + newMethod.Name = "NewAwesomeMethod";// new method replacement + method.Deprecation = new("This method is obsolete. Use NewAwesomeMethod instead.", IsDeprecated: true, TypeReferences: new() { { "TypeName", new CodeType { TypeDefinition = newMethod, IsExternal = false } } }); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("This method is obsolete. Use NewAwesomeMethod instead.", result); + } + [Fact] + public void WritesRequestGeneratorAcceptHeaderQuotes() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Get; + AddRequestProperties(); + method.AcceptedResponseTypes.Add("application/json; profile=\"CamelCase\""); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("requestInfo.headers.put('Accept', 'application/json; profile=\"CamelCase\"')", result); + } + + [Fact] + public void WritesRequestGeneratorContentTypeQuotes() + { + setup(); + method.Kind = CodeMethodKind.RequestGenerator; + method.HttpMethod = HttpMethod.Post; + AddRequestProperties(); + AddRequestBodyParameters(); + method.RequestBodyContentType = "application/json; profile=\"CamelCase\""; + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("'application/json; profile=\"CamelCase\"'", result); + } +} From 1ead0a99e859e74737326e841cf01ce70628c0de Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Thu, 31 Oct 2024 15:21:05 +0100 Subject: [PATCH 120/194] All properties use camel case now. This solves the problem of having underscores in some properties. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 5156e3e0e0..1fc5a395ba 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -100,7 +100,14 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken else return s; }); - + ReplacePropertyNames(generatedCode, + [ + CodePropertyKind.Custom, + CodePropertyKind.AdditionalData, + CodePropertyKind.QueryParameter, + CodePropertyKind.RequestBuilder, + ], + static s => s.ToCamelCase(UnderscoreArray)); MoveQueryParameterClass(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); From 3764ec02049536f9f4165393ede139cc262c5f02 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 1 Nov 2024 08:17:31 +0100 Subject: [PATCH 121/194] Added tests for codepropertywriter --- .../Writers/Dart/CodePropertyWriter.cs | 2 +- .../Writers/Dart/CodePropertyWriterTests.cs | 134 ++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 8eba203edd..afb8b43905 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -61,7 +61,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ case CodePropertyKind.AdditionalData when backingStoreProperty != null: case CodePropertyKind.Custom when backingStoreProperty != null: var backingStoreKey = codeElement.WireName; - var defaultIfNotNullable = propertyType.EndsWith('?') ? string.Empty : $" ?? {codeElement.DefaultValue}"; + var defaultIfNotNullable = propertyType.EndsWith('?') ? string.Empty : codeElement.IsOfKind(CodePropertyKind.AdditionalData) ? " ?? {}" : $" ?? {codeElement.DefaultValue}"; writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); writer.WriteLine($"return {backingStoreProperty.Name.ToFirstCharacterLowerCase()}.get<{propertyType}>('{backingStoreKey}'){defaultIfNotNullable};"); diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs new file mode 100644 index 0000000000..a8c7e6223c --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs @@ -0,0 +1,134 @@ +using System; +using System.IO; +using System.Linq; +using Kiota.Builder.CodeDOM; +using Kiota.Builder.Writers; + +using Xunit; + +namespace Kiota.Builder.Tests.Writers.Dart; +public sealed class CodePropertyWriterTests : IDisposable +{ + private const string DefaultPath = "./"; + private const string DefaultName = "name"; + private readonly StringWriter tw; + private readonly LanguageWriter writer; + private readonly CodeProperty property; + private readonly CodeClass parentClass; + private const string PropertyName = "propertyName"; + private const string TypeName = "Somecustomtype"; + public CodePropertyWriterTests() + { + writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.Dart, DefaultPath, DefaultName); + tw = new StringWriter(); + writer.SetTextWriter(tw); + var root = CodeNamespace.InitRootNamespace(); + parentClass = new CodeClass + { + Name = "parentClass" + }; + root.AddClass(parentClass); + property = new CodeProperty + { + Name = PropertyName, + Type = new CodeType + { + Name = TypeName + } + }; + parentClass.AddProperty(property, new() + { + Name = "pathParameters", + Kind = CodePropertyKind.PathParameters, + Type = new CodeType + { + Name = "PathParameters", + }, + }, new() + { + Name = "requestAdapter", + Kind = CodePropertyKind.RequestAdapter, + Type = new CodeType + { + Name = "RequestAdapter", + }, + }); + } + public void Dispose() + { + tw?.Dispose(); + GC.SuppressFinalize(this); + } + [Fact] + public void WritesRequestBuilder() + { + property.Kind = CodePropertyKind.RequestBuilder; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains($"return {TypeName}", result); + Assert.Contains("requestAdapter", result); + Assert.Contains("pathParameters", result); + } + [Fact] + public void WritesCustomProperty() + { + property.Kind = CodePropertyKind.Custom; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains($"{TypeName}? {PropertyName}", result); + } + [Fact] + public void MapsCustomPropertiesToBackingStore() + { + parentClass.AddBackingStoreProperty(); + property.Kind = CodePropertyKind.Custom; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains("return backingStore.get('propertyName');", result); + Assert.Contains("backingStore.set('propertyName', value);", result); + } + [Fact] + public void MapsAdditionalDataPropertiesToBackingStore() + { + parentClass.AddBackingStoreProperty(); + property.Kind = CodePropertyKind.AdditionalData; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains("return backingStore.get('propertyName') ?? {};", result); + Assert.Contains("backingStore.set('propertyName', value);", result); + } + [Fact] + public void DoesntWritePropertiesExistingInParentType() + { + parentClass.AddProperty(new CodeProperty + { + Name = "definedInParent", + Type = new CodeType + { + Name = "string" + }, + Kind = CodePropertyKind.Custom, + }); + var subClass = (parentClass.Parent as CodeNamespace).AddClass(new CodeClass + { + Name = "BaseClass", + }).First(); + subClass.StartBlock.Inherits = new CodeType + { + Name = "BaseClass", + TypeDefinition = parentClass + }; + var propertyToWrite = subClass.AddProperty(new CodeProperty + { + Name = "definedInParent", + Type = new CodeType + { + Name = "string" + }, + Kind = CodePropertyKind.Custom, + }).First(); + writer.Write(propertyToWrite); + var result = tw.ToString(); + Assert.Empty(result); + } +} From 04e182c050c4dbd6b798d8c88526b849c9d65ec1 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 1 Nov 2024 11:36:20 +0100 Subject: [PATCH 122/194] Enum options are now translated in DartRefiner --- src/Kiota.Builder/Refiners/DartRefiner.cs | 27 +++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 1fc5a395ba..55e48aa512 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -51,6 +51,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken { cancellationToken.ThrowIfCancellationRequested(); var defaultConfiguration = new GenerationConfiguration(); + CorrectCommonNames(generatedCode); ConvertUnionTypesToWrapper(generatedCode, _configuration.UsesBackingStore, static s => s.ToFirstCharacterLowerCase(), @@ -60,7 +61,6 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken static x => $"by{x.ToFirstCharacterUpperCase()}", static x => x.ToFirstCharacterLowerCase(), GenerationLanguage.Dart); - CorrectCommonNames(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); AddQueryParameterExtractorMethod(generatedCode); @@ -212,6 +212,27 @@ private static void CorrectCommonNames(CodeElement currentElement) { i.IndexParameter.Name = i.IndexParameter.Name.ToFirstCharacterLowerCase(); } + else if (currentElement is CodeEnum e) + { + foreach (var option in e.Options) + { + if (!string.IsNullOrEmpty(option.Name)) + { + if (option.Name.Contains('_', StringComparison.Ordinal)) + { + option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); + } + else if (option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c))) + { + option.Name = option.Name.ToLowerInvariant(); + } + Console.Write(e.Name + ':'); + option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); + Console.WriteLine(option.Name); + } + } + } + CrawlTree(currentElement, element => CorrectCommonNames(element)); } @@ -283,7 +304,9 @@ private static void CorrectPropertyType(CodeProperty currentProperty) currentProperty.Type.Name = "Map"; if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) currentProperty.DefaultValue = "{}"; - } else { + } + else + { currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); } currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); From 1fe9ff8575a83daedb68986721ff9e9ba942d1c9 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 1 Nov 2024 11:36:50 +0100 Subject: [PATCH 123/194] Enum writer assumes options are already correct --- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index b08c6a641b..d809a72cb8 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -24,17 +24,11 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.StartBlock($"enum {enumName} {{"); var lastOption = codeElement.Options.Last(); - HashSet usedNames = new HashSet(); + HashSet usedNames = []; foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); - var correctedName = conventions.getCorrectedEnumName(option.Name); - if (!usedNames.Add(correctedName)) - { - correctedName = option.Name; - usedNames.Add(correctedName); - } - writer.WriteLine($"{correctedName}(\"{option.SerializationName}\"){(option == lastOption ? ";" : ",")}"); + writer.WriteLine($"{option.Name}('{option.SerializationName}'){(option == lastOption ? ";" : ",")}"); } writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); From e061f74f68b2ce359de5670a44ba0bf340d90f58 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 1 Nov 2024 11:38:20 +0100 Subject: [PATCH 124/194] Cosmetic change --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 880cda1b65..a3b74bf0a5 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -786,7 +786,7 @@ private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, var nullablesegment = signatureSegments[0]; if (!"void".Equals(nullablesegment, StringComparison.Ordinal)) { - nullablesegment = nullablesegment + "?"; + nullablesegment += "?"; } return $"{nullablesegment} {string.Join(" ", signatureSegments[1..])}"; } From 011603225e0b43167460b0d9d319d8672b88b8dc Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 1 Nov 2024 11:51:29 +0100 Subject: [PATCH 125/194] Removed debug output --- src/Kiota.Builder/Refiners/DartRefiner.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 55e48aa512..c5ca07ec36 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -226,9 +226,7 @@ private static void CorrectCommonNames(CodeElement currentElement) { option.Name = option.Name.ToLowerInvariant(); } - Console.Write(e.Name + ':'); option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); - Console.WriteLine(option.Name); } } } From 4c4a30b53633f827015209653411a073d5d0f0df Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 1 Nov 2024 12:19:13 +0100 Subject: [PATCH 126/194] Enum naming is now part of DartRefiner --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index a3b74bf0a5..aebb9a2aa9 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -321,16 +321,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho { separator = ';'; } - if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) - { - defaultValue = conventions.getCorrectedEnumName(defaultValue.Trim('"')).CleanupSymbolName(); - if (new DartReservedNamesProvider().ReservedNames.Contains(defaultValue)) - { - defaultValue += "Escaped"; - } - defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; - } - else if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) + if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) { defaultValue = defaultValue.Trim('"'); defaultValue = $"'{defaultValue}'"; From b13fad7748f23e2fae4e9ff36f4bc404bca23547 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 5 Nov 2024 11:00:32 +0100 Subject: [PATCH 127/194] Fixed enum option names --- src/Kiota.Builder/Refiners/DartRefiner.cs | 10 ++++------ src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 1 - 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index d7e43a5a57..20b685381b 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -218,19 +218,17 @@ private static void CorrectCommonNames(CodeElement currentElement) { if (!string.IsNullOrEmpty(option.Name)) { - if (option.Name.Contains('_', StringComparison.Ordinal)) + if (option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c))) { - option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); + option.Name = option.Name.ToLowerInvariant(); } - else if (option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c))) + else { - option.Name = option.Name.ToLowerInvariant(); + option.Name = option.Name.ToCamelCase('_'); } - option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); } } } - CrawlTree(currentElement, element => CorrectCommonNames(element)); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index d809a72cb8..b705267fed 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -24,7 +24,6 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.StartBlock($"enum {enumName} {{"); var lastOption = codeElement.Options.Last(); - HashSet usedNames = []; foreach (var option in codeElement.Options) { conventions.WriteShortDescription(option, writer); From 6edbeddc81ec1940853e9f900181f2be84643471 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 5 Nov 2024 11:58:22 +0100 Subject: [PATCH 128/194] Added index as a reserved name Dart uses the property index in enums. --- src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs index 77bdea5133..18d1abeecf 100644 --- a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -42,6 +42,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "implements", "import", "in", + "index", "int", "interface", "is", From 5b4547200d97abc358ba8d3f3d2d38c1b8707b4e Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 5 Nov 2024 11:59:28 +0100 Subject: [PATCH 129/194] Avoiding duplicate options in enums --- .../Writers/Dart/CodeEnumWriter.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index b705267fed..cffbe72af2 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -22,9 +22,11 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); writer.StartBlock($"enum {enumName} {{"); - var lastOption = codeElement.Options.Last(); - foreach (var option in codeElement.Options) + var options = deduplicateOptions(codeElement.Options); + var lastOption = options.Last(); + + foreach (var option in options) { conventions.WriteShortDescription(option, writer); writer.WriteLine($"{option.Name}('{option.SerializationName}'){(option == lastOption ? ";" : ",")}"); @@ -32,4 +34,26 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); } + + /// + /// Prevents duplicate options by making sure the option names are unique + /// + /// All options for a single enum + /// A unique set of options + private static HashSet deduplicateOptions(IEnumerable options) + { + HashSet uniqueOptionNames = []; + HashSet uniqueOptions = []; + foreach (var option in options) + { + if (uniqueOptionNames.Add(option.Name)) + { + uniqueOptions.Add(option); + } + } + + return uniqueOptions; + } } + + From b2418f8bf66718fa89f76815834715564eab58d1 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 5 Nov 2024 13:57:48 +0100 Subject: [PATCH 130/194] Fixed unit tests Most problems were caused by change from double to single quotes. --- .../Writers/Dart/CodeEnumWriterTests.cs | 4 ++-- .../Writers/Dart/CodeMethodWriterTests.cs | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs index 878f8958dc..eed82fcd4d 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs @@ -42,7 +42,7 @@ public void WritesEnum() var result = tw.ToString(); Assert.Contains("enum", result); Assert.Contains(EnumName, result); - Assert.Contains($"{optionName}(\"{optionName}\")", result); + Assert.Contains($"{optionName}('{optionName}')", result); Assert.Contains($"const {EnumName}(this.value);", result); Assert.Contains("final String value;", result); } @@ -83,6 +83,6 @@ public void WritesEnumSerializationValue() currentEnum.AddOption(option); writer.Write(currentEnum); var result = tw.ToString(); - Assert.Contains($"{OptionName}(\"{SerializationValue}\")", result); + Assert.Contains($"{OptionName}('{SerializationValue}')", result); } } diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs index b35d12a1c7..b510a95073 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs @@ -315,7 +315,7 @@ private CodeClass AddUnionType() unionType.OriginalComposedType.AddType(sType); unionType.AddProperty(new CodeProperty { - Name = "ComplexType1Value", + Name = "complexType1Value", Type = cType1, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -336,7 +336,7 @@ private CodeClass AddUnionType() }); unionType.AddProperty(new CodeProperty { - Name = "ComplexType2Value", + Name = "complexType2Value", Type = cType2, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -357,7 +357,7 @@ private CodeClass AddUnionType() }); unionType.AddProperty(new CodeProperty { - Name = "StringValue", + Name = "stringValue", Type = sType, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -449,7 +449,7 @@ private CodeClass AddIntersectionType() intersectionType.OriginalComposedType.AddType(sType); intersectionType.AddProperty(new CodeProperty { - Name = "ComplexType1Value", + Name = "complexType1Value", Type = cType1, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -470,7 +470,7 @@ private CodeClass AddIntersectionType() }); intersectionType.AddProperty(new CodeProperty { - Name = "ComplexType2Value", + Name = "complexType2Value", Type = cType2, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -491,7 +491,7 @@ private CodeClass AddIntersectionType() }); intersectionType.AddProperty(new CodeProperty { - Name = "ComplexType3Value", + Name = "complexType3Value", Type = cType3, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -512,7 +512,7 @@ private CodeClass AddIntersectionType() }); intersectionType.AddProperty(new CodeProperty { - Name = "StringValue", + Name = "stringValue", Type = sType, Kind = CodePropertyKind.Custom, Setter = new CodeMethod @@ -1247,7 +1247,7 @@ public void WritesConstructor() { setup(); method.Kind = CodeMethodKind.Constructor; - var defaultValue = "\"someVal\""; + var defaultValue = "'someVal'"; var propName = "propWithDefaultValue"; parentClass.Kind = CodeClassKind.RequestBuilder; parentClass.AddProperty(new CodeProperty @@ -1260,7 +1260,7 @@ public void WritesConstructor() Name = "String" } }); - var defaultValueNull = "\"null\""; + var defaultValueNull = "'null'"; var nullPropName = "propWithDefaultNullValue"; parentClass.AddProperty(new CodeProperty { @@ -1299,9 +1299,9 @@ public void WritesConstructor() writer.Write(method); var result = tw.ToString(); Assert.Contains(parentClass.Name, result); - Assert.Contains($"{propName} = '{defaultValue.TrimQuotes()}'", result); - Assert.Contains($"{nullPropName} = {defaultValueNull.TrimQuotes()}", result); - Assert.Contains($"{boolPropName} = {defaultValueBool.TrimQuotes()}", result); + Assert.Contains($"{propName} = '{defaultValue}'", result); + Assert.Contains($"{nullPropName} = {defaultValueNull}", result); + Assert.Contains($"{boolPropName} = {defaultValueBool}", result); Assert.Contains("super", result); } [Fact] From 47cfdda19b1a719393531c99c9415bc0c811d11a Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 6 Nov 2024 08:08:19 +0100 Subject: [PATCH 131/194] Fixed case of enum option This fixes a problem at least with one open api spec but we have to test it with other specs as well. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 20b685381b..69089f2a62 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -224,7 +224,7 @@ private static void CorrectCommonNames(CodeElement currentElement) } else { - option.Name = option.Name.ToCamelCase('_'); + option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); } } } From 205bc0998755f76e7014efd4157ec5fa377f8701 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 6 Nov 2024 10:21:03 +0100 Subject: [PATCH 132/194] Corrected enum names Enum names were still incorrect in places where an enum value was assigned. To address this problem, enum names are now (again) corrected in the DartConventionService. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 12 +----------- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 13 +++++++++++-- .../Writers/Dart/DartConventionService.cs | 6 +++--- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 69089f2a62..1575ccd927 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -216,17 +216,7 @@ private static void CorrectCommonNames(CodeElement currentElement) { foreach (var option in e.Options) { - if (!string.IsNullOrEmpty(option.Name)) - { - if (option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c))) - { - option.Name = option.Name.ToLowerInvariant(); - } - else - { - option.Name = option.Name.ToLowerInvariant().ToCamelCase('_'); - } - } + option.Name = DartConventionService.getCorrectedEnumName(option.Name); } } CrawlTree(currentElement, element => CorrectCommonNames(element)); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 1fd78fdd73..9bde79ef23 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -321,7 +321,16 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho { separator = ';'; } - if (propWithDefault.Type is CodeType propertyType2 && propertyType2.Name.Equals("String", StringComparison.Ordinal)) + if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) + { + defaultValue = DartConventionService.getCorrectedEnumName(defaultValue.Trim('"')).CleanupSymbolName(); + if (new DartReservedNamesProvider().ReservedNames.Contains(defaultValue)) + { + defaultValue += "Escaped"; + } + defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; + } + else if (propWithDefault.Type is CodeType propertyType2) { defaultValue = defaultValue.Trim('"'); if (propertyType2.Name.Equals("String", StringComparison.Ordinal)) @@ -329,7 +338,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho defaultValue = $"'{defaultValue}'"; } } - writer.WriteLine($"{propWithDefault.Name.ToFirstCharacterLowerCase()} = {defaultValue}{separator}"); + writer.WriteLine($"{propWithDefault.Name} = {defaultValue}{separator}"); } if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) && parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 4cf1d2ab8b..539043f8f3 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -352,7 +352,7 @@ public bool ErrorClassPropertyExistsInSuperClass(CodeProperty codeElement) return codeElement?.Parent is CodeClass parentClass && parentClass.IsErrorDefinition && ErrorClassProperties.Contains(codeElement.Name); } - public string getCorrectedEnumName(string name) + public static string getCorrectedEnumName(string name) { ArgumentNullException.ThrowIfNull(name); var correctedName = ""; @@ -362,8 +362,8 @@ public string getCorrectedEnumName(string name) } else { - correctedName = name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name; + correctedName = name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? name.ToLowerInvariant() : name.ToFirstCharacterLowerCase(); } - return correctedName.Equals("index", StringComparison.Ordinal) ? correctedName + "Escaped" : correctedName; + return correctedName; } } From 6028016341ece73522fb49cdf6477fa201143fd0 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 8 Nov 2024 07:42:55 +0100 Subject: [PATCH 133/194] Removed unused imports --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 8c440beebb..f22a1868ff 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; using System.Linq; using Kiota.Builder.CodeDOM; -using Kiota.Builder.Extensions; using Kiota.Builder.PathSegmenters; -using Microsoft.Kiota.Abstractions.Extensions; namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter From ca26c4e85d43f0d014d4bb66bf0fc43ecdfcff86 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 8 Nov 2024 07:49:14 +0100 Subject: [PATCH 134/194] Moved call to CorrectCommonNames The method ConvertUnionTypesToWrapper may introduce new classes where the first char is lower case. This solves multiple problems in different writers. Additionally enum options names are corrected. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 27 ++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 1575ccd927..80c0406f3d 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -6,7 +6,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; -using Kiota.Builder.Writers.Dart; + namespace Kiota.Builder.Refiners; public class DartRefiner : CommonLanguageRefiner, ILanguageRefiner @@ -51,11 +51,12 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken { cancellationToken.ThrowIfCancellationRequested(); var defaultConfiguration = new GenerationConfiguration(); - CorrectCommonNames(generatedCode); + ConvertUnionTypesToWrapper(generatedCode, _configuration.UsesBackingStore, static s => s.ToFirstCharacterLowerCase(), false); + CorrectCommonNames(generatedCode); ReplaceIndexersByMethodsWithParameter(generatedCode, false, static x => $"by{x.ToFirstCharacterUpperCase()}", @@ -216,7 +217,7 @@ private static void CorrectCommonNames(CodeElement currentElement) { foreach (var option in e.Options) { - option.Name = DartConventionService.getCorrectedEnumName(option.Name); + option.Name = getCorrectedEnumOptionName(option); } } CrawlTree(currentElement, element => CorrectCommonNames(element)); @@ -496,4 +497,24 @@ private static void AliasUsingWithSameSymbol(CodeElement currentElement) } CrawlTree(currentElement, AliasUsingWithSameSymbol); } + + private static string getCorrectedEnumOptionName(CodeEnumOption option) + { + ArgumentNullException.ThrowIfNull(option); + var correctedName = ""; + if (option.Name.Contains('_', StringComparison.Ordinal)) + { + correctedName = option.Name.ToUpperInvariant().ToCamelCase('_'); + } + else + { + correctedName = option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? option.Name.ToUpperInvariant() : option.Name.ToFirstCharacterUpperCase(); + } + if (option.SerializationName.Contains('\'', StringComparison.OrdinalIgnoreCase)) + { + option.SerializationName = option.SerializationName.Replace("'", "\\'", StringComparison.OrdinalIgnoreCase); + } + return correctedName; + } + } From 038d64fac573ffb8efc2abb2688e38b5f82d8f91 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 8 Nov 2024 12:21:14 +0100 Subject: [PATCH 135/194] Fixed enums with symbols only One enum option for example only contained a /. This is translated into "Slash". By passing the cleand up symbol name to getCorrectedEnumName, we now get the correct enum name. --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 9bde79ef23..d1e45dab6b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -323,7 +323,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) { - defaultValue = DartConventionService.getCorrectedEnumName(defaultValue.Trim('"')).CleanupSymbolName(); + defaultValue = DartConventionService.getCorrectedEnumName(defaultValue.Trim('"').CleanupSymbolName()); if (new DartReservedNamesProvider().ReservedNames.Contains(defaultValue)) { defaultValue += "Escaped"; @@ -379,7 +379,8 @@ private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod curren } } - private string DefaultDeserializerValue => $"Map"; + private string DefaultDeserializerReturnType => $"Map"; + private string DefaultDeserializerReturnInstance => $""; private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -406,7 +407,7 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par if (!includeElse) includeElse = true; } - writer.WriteLine($"return {DefaultDeserializerValue}();"); + writer.WriteLine($"return {DefaultDeserializerReturnInstance}{{}};"); } private const string DeserializerReturnType = "Map"; private const string DeserializerName = "deserializers"; @@ -414,7 +415,7 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) { - writer.WriteLine($"{DefaultDeserializerValue} {DeserializerName} = {{}};"); + writer.WriteLine($"{DefaultDeserializerReturnType} {DeserializerName} = {{}};"); var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => x.Type is CodeType propType && propType.TypeDefinition is CodeClass && !x.Type.IsCollection) .ToArray(); From 59d42cd898107c0dac134db730fb6834b06e25c6 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 8 Nov 2024 12:23:08 +0100 Subject: [PATCH 136/194] Small changes in order . Plus a change in ReplaceIndexersByMethodsWithParameter, which now creates the correct names. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 74 ++++++++++++----------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 80c0406f3d..4d49ff9e81 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -6,6 +6,7 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; +using Kiota.Builder.Writers.Dart; namespace Kiota.Builder.Refiners; @@ -57,40 +58,8 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken static s => s.ToFirstCharacterLowerCase(), false); CorrectCommonNames(generatedCode); - ReplaceIndexersByMethodsWithParameter(generatedCode, - false, - static x => $"by{x.ToFirstCharacterUpperCase()}", - static x => x.ToFirstCharacterLowerCase(), - GenerationLanguage.Dart); - CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); - - AddQueryParameterExtractorMethod(generatedCode); - // This adds the BaseRequestBuilder class as a superclass - MoveRequestBuilderPropertiesToBaseType(generatedCode, - new CodeUsing - { - Name = "BaseRequestBuilder", - Declaration = new CodeType - { - Name = AbstractionsNamespaceName, - IsExternal = true, - } - }, addCurrentTypeAsGenericTypeParameter: true); - RemoveRequestConfigurationClasses(generatedCode, - new CodeUsing - { - Name = "RequestConfiguration", - Declaration = new CodeType - { - Name = AbstractionsNamespaceName, - IsExternal = true - } - }, new CodeType - { - Name = "DefaultQueryParameters", - IsExternal = true, - }); var reservedNamesProvider = new DartReservedNamesProvider(); + cancellationToken.ThrowIfCancellationRequested(); CorrectNames(generatedCode, s => { if (s.Contains('_', StringComparison.OrdinalIgnoreCase) && @@ -101,6 +70,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken else return s; }); + CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); ReplacePropertyNames(generatedCode, [ CodePropertyKind.Custom, @@ -109,6 +79,39 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken CodePropertyKind.RequestBuilder, ], static s => s.ToCamelCase(UnderscoreArray)); + + ReplaceIndexersByMethodsWithParameter(generatedCode, + false, + static x => $"by{x.ToPascalCase('_')}", + static x => x.ToCamelCase('_'), + GenerationLanguage.Dart); + + AddQueryParameterExtractorMethod(generatedCode); + // This adds the BaseRequestBuilder class as a superclass + MoveRequestBuilderPropertiesToBaseType(generatedCode, + new CodeUsing + { + Name = "BaseRequestBuilder", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true, + } + }, addCurrentTypeAsGenericTypeParameter: true); + RemoveRequestConfigurationClasses(generatedCode, + new CodeUsing + { + Name = "RequestConfiguration", + Declaration = new CodeType + { + Name = AbstractionsNamespaceName, + IsExternal = true + } + }, new CodeType + { + Name = "DefaultQueryParameters", + IsExternal = true, + }); MoveQueryParameterClass(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); AddPropertiesAndMethodTypesImports(generatedCode, true, true, true, codeTypeFilter); @@ -215,6 +218,7 @@ private static void CorrectCommonNames(CodeElement currentElement) } else if (currentElement is CodeEnum e) { + e.Name = DartConventionService.getCorrectedEnumName(e.Name); foreach (var option in e.Options) { option.Name = getCorrectedEnumOptionName(option); @@ -504,11 +508,11 @@ private static string getCorrectedEnumOptionName(CodeEnumOption option) var correctedName = ""; if (option.Name.Contains('_', StringComparison.Ordinal)) { - correctedName = option.Name.ToUpperInvariant().ToCamelCase('_'); + correctedName = option.Name.ToLowerInvariant().ToCamelCase('_'); } else { - correctedName = option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? option.Name.ToUpperInvariant() : option.Name.ToFirstCharacterUpperCase(); + correctedName = option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? option.Name.ToLowerInvariant() : option.Name.ToFirstCharacterLowerCase(); } if (option.SerializationName.Contains('\'', StringComparison.OrdinalIgnoreCase)) { From e807b21dce6761c0c9c7da5fdb6d0d02458b33d4 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 8 Nov 2024 15:29:20 +0100 Subject: [PATCH 137/194] Moved updating serialization names to writer Discussed this with Emond. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 4 ---- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 8 +++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 4d49ff9e81..d48a4ba7d7 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -514,10 +514,6 @@ private static string getCorrectedEnumOptionName(CodeEnumOption option) { correctedName = option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? option.Name.ToLowerInvariant() : option.Name.ToFirstCharacterLowerCase(); } - if (option.SerializationName.Contains('\'', StringComparison.OrdinalIgnoreCase)) - { - option.SerializationName = option.SerializationName.Replace("'", "\\'", StringComparison.OrdinalIgnoreCase); - } return correctedName; } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index cffbe72af2..476966bfd4 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -29,7 +29,13 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write foreach (var option in options) { conventions.WriteShortDescription(option, writer); - writer.WriteLine($"{option.Name}('{option.SerializationName}'){(option == lastOption ? ";" : ",")}"); + + var serializationName = option.SerializationName; + if (serializationName.Contains('\'', StringComparison.OrdinalIgnoreCase)) + { + serializationName = serializationName.Replace("'", "\\'", StringComparison.OrdinalIgnoreCase); + } + writer.WriteLine($"{option.Name}('{serializationName}'){(option == lastOption ? ";" : ",")}"); } writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); From e3fff8e463d6952ca4ba32827f2e9c0fdc90d397 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 07:20:10 +0100 Subject: [PATCH 138/194] Added dart to the language matrix --- .github/workflows/integration-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index af6046f4b4..95189e7e2d 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -43,6 +43,7 @@ jobs: - ruby - php - python + - dart description: - "./tests/Kiota.Builder.IntegrationTests/InheritingErrors.yaml" - "./tests/Kiota.Builder.IntegrationTests/EnumHandling.yaml" From 880026d10ceb5150c214092cc630bbf5970f6002 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 07:32:15 +0100 Subject: [PATCH 139/194] Add setup for Dart --- .github/workflows/integration-tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 95189e7e2d..6801e662f4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -109,6 +109,11 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.11" + - name: Setup Dart + if: matrix.language == 'dart' + uses: dart-lang/setup-dart@v1.6.5 + with: + sdk: "3.5" - name: Check if test is suppressed id: check-suppressed From a0201e04b95c6958049cefa84ccbe0c23ab96604 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 07:35:08 +0100 Subject: [PATCH 140/194] Ran dotnet format --- src/Kiota.Builder/Refiners/DartRefiner.cs | 4 ++-- .../Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 3c2dadcbcb..fd3b41fc9c 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -140,7 +140,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken ); AddSerializationModulesImport(generatedCode, [$"{AbstractionsNamespaceName}.ApiClientBuilder", - $"{AbstractionsNamespaceName}.SerializationWriterFactoryRegistry"], + $"{AbstractionsNamespaceName}.SerializationWriterFactoryRegistry"], [$"{AbstractionsNamespaceName}.ParseNodeFactoryRegistry"]); cancellationToken.ThrowIfCancellationRequested(); diff --git a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs index 08d1288441..c71de8f288 100644 --- a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Threading.Tasks; using Kiota.Builder.CodeDOM; From 375bfcdd14b78e4bdfba372572b933e0075119fc Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 08:07:06 +0100 Subject: [PATCH 141/194] dart pub get needs to be run every time before analyze --- it/exec-cmd.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index b871cfc816..f7d9b759d0 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -221,6 +221,7 @@ elseif ($language -eq "dart") { } else { Invoke-Call -ScriptBlock { + dart pub get dart analyze src/ } -ErrorAction Stop } From 1f4cc01a8f82e463b1aa9ed14fdad1991138e9df Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 08:30:45 +0100 Subject: [PATCH 142/194] Added dart to language matrix for idempotency tests --- .github/workflows/idempotency-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/idempotency-tests.yml b/.github/workflows/idempotency-tests.yml index cf479de6d4..074325f488 100644 --- a/.github/workflows/idempotency-tests.yml +++ b/.github/workflows/idempotency-tests.yml @@ -63,6 +63,7 @@ jobs: - ruby - php - python + - dart description: - "./tests/Kiota.Builder.IntegrationTests/InheritingErrors.yaml" - "./tests/Kiota.Builder.IntegrationTests/NoUnderscoresInModel.yaml" From d2a3850b819ef05940fb6a96176c1699140f3c3b Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 10:20:42 +0100 Subject: [PATCH 143/194] Replace methods before correcting types, don't normalize enum names with normalization for enum options --- src/Kiota.Builder/Refiners/DartRefiner.cs | 30 ++++--------------- .../Writers/Dart/CodeEnumWriter.cs | 2 +- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index eb401cdaf1..e21c7499a8 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -57,6 +57,11 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken _configuration.UsesBackingStore, static s => s.ToFirstCharacterLowerCase(), false); + ReplaceIndexersByMethodsWithParameter(generatedCode, + false, + static x => $"by{x.ToPascalCase('_')}", + static x => x.ToCamelCase('_'), + GenerationLanguage.Dart); CorrectCommonNames(generatedCode); var reservedNamesProvider = new DartReservedNamesProvider(); cancellationToken.ThrowIfCancellationRequested(); @@ -80,12 +85,6 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken ], static s => s.ToCamelCase(UnderscoreArray)); - ReplaceIndexersByMethodsWithParameter(generatedCode, - false, - static x => $"by{x.ToPascalCase('_')}", - static x => x.ToCamelCase('_'), - GenerationLanguage.Dart); - AddQueryParameterExtractorMethod(generatedCode); // This adds the BaseRequestBuilder class as a superclass MoveRequestBuilderPropertiesToBaseType(generatedCode, @@ -218,10 +217,9 @@ private static void CorrectCommonNames(CodeElement currentElement) } else if (currentElement is CodeEnum e) { - e.Name = DartConventionService.getCorrectedEnumName(e.Name); foreach (var option in e.Options) { - option.Name = getCorrectedEnumOptionName(option); + option.Name = DartConventionService.getCorrectedEnumName(option.Name); } } CrawlTree(currentElement, element => CorrectCommonNames(element)); @@ -501,20 +499,4 @@ private static void AliasUsingWithSameSymbol(CodeElement currentElement) } CrawlTree(currentElement, AliasUsingWithSameSymbol); } - - private static string getCorrectedEnumOptionName(CodeEnumOption option) - { - ArgumentNullException.ThrowIfNull(option); - var correctedName = ""; - if (option.Name.Contains('_', StringComparison.Ordinal)) - { - correctedName = option.Name.ToLowerInvariant().ToCamelCase('_'); - } - else - { - correctedName = option.Name.All(c => char.IsUpper(c) || char.IsAsciiDigit(c)) ? option.Name.ToLowerInvariant() : option.Name.ToFirstCharacterLowerCase(); - } - return correctedName; - } - } diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 476966bfd4..c3bf521cf3 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -29,7 +29,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write foreach (var option in options) { conventions.WriteShortDescription(option, writer); - + var serializationName = option.SerializationName; if (serializationName.Contains('\'', StringComparison.OrdinalIgnoreCase)) { From ad6d032e74abf87135e572ed8b5c40b1fd6e7b9c Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 10:40:11 +0100 Subject: [PATCH 144/194] Remove toCamelCase from CodePropertyWriter --- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index e174ee83f5..c0331fdd8b 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -44,7 +44,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ if (!string.IsNullOrEmpty(accessModifierAttribute)) writer.WriteLine(accessModifierAttribute); - var propertyName = codeElement.Name.ToCamelCase(); + var propertyName = codeElement.Name; if (reservedNamesProvider.ReservedNames.Contains(propertyName)) { propertyName += "Escaped"; @@ -68,7 +68,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ writer.DecreaseIndent(); writer.WriteLine("}"); writer.WriteLine(); - writer.WriteLine($"set {codeElement.Name.ToCamelCase()}({propertyType} value) {{"); + writer.WriteLine($"set {codeElement.Name}({propertyType} value) {{"); writer.IncreaseIndent(); writer.WriteLine($"{backingStoreProperty.Name}.set('{backingStoreKey}', value);"); writer.DecreaseIndent(); From 0568dc38a31abdfea6e26a1fe4c00d221d1bac7f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 10:53:51 +0100 Subject: [PATCH 145/194] Fix broken unit test --- tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs | 1 - .../Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs index eed82fcd4d..37ce1e96f9 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeEnumWriterTests.cs @@ -3,7 +3,6 @@ using System.Linq; using Kiota.Builder.CodeDOM; -using Kiota.Builder.Extensions; using Kiota.Builder.Writers; using Xunit; diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs index b510a95073..f26d021d31 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs @@ -992,8 +992,8 @@ public void WritesUnionDeSerializerBody() var result = tw.ToString(); Assert.Contains("complexType1Value != null", result); Assert.Contains("return complexType1Value!.getFieldDeserializers()", result); - Assert.Contains("Map()", result); - AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "Map()", result); + Assert.Contains("()", result); + AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "()", result); AssertExtensions.CurlyBracesAreClosed(result); } [Fact] From 5baa691c5abc98c0892c484ec055db57d1c09c52 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 11:02:26 +0100 Subject: [PATCH 146/194] Remove some unused methods --- .../Writers/Dart/DartConventionService.cs | 63 ------------------- 1 file changed, 63 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 4cf1d2ab8b..0d2265a887 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -154,25 +154,6 @@ private static bool ShouldTypeHaveNullableMarker(CodeTypeBase propType, string p { return propType.IsNullable && (NullableTypes.Contains(propTypeName) || (propType is CodeType codeType && codeType.TypeDefinition is CodeEnum)); } - private HashSet _namespaceSegmentsNames = new(StringComparer.OrdinalIgnoreCase); - private readonly object _namespaceSegmentsNamesLock = new(); - private HashSet GetNamesInUseByNamespaceSegments(CodeElement currentElement) - { - if (_namespaceSegmentsNames.Count == 0) - { - lock (_namespaceSegmentsNamesLock) - { - var rootNamespace = currentElement.GetImmediateParentOfType().GetRootNamespace(); - _namespaceSegmentsNames = GetAllNamespaces(rootNamespace) - .Where(static x => !string.IsNullOrEmpty(x.Name)) - .SelectMany(static ns => ns.Name.Split('.', StringSplitOptions.RemoveEmptyEntries)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToHashSet(StringComparer.OrdinalIgnoreCase); - _namespaceSegmentsNames.Add("keyvaluepair"); //workaround as System.Collections.Generic imports keyvalue pair - } - } - return _namespaceSegmentsNames; - } private static IEnumerable GetAllNamespaces(CodeNamespace ns) { foreach (var childNs in ns.Namespaces) @@ -244,50 +225,6 @@ private string TranslateTypeAndAvoidUsingNamespaceSegmentNames(CodeType currentT return typeName; } - private static bool DoesTypeExistsInSameNamesSpaceAsTarget(CodeType currentType, CodeElement targetElement) - { - return currentType?.TypeDefinition?.GetImmediateParentOfType()?.Name.Equals(targetElement?.GetImmediateParentOfType()?.Name, StringComparison.OrdinalIgnoreCase) ?? false; - } - - private static bool DoesTypeExistsInTargetAncestorNamespace(CodeType currentType, CodeElement targetElement) - { - // Avoid type ambiguity on similarly named classes. Currently, if we have namespaces A and A.B where both namespaces have type T, - // Trying to use type A.B.T in namespace A without using a qualified name will break the build. - // Similarly, if we have type A.B.C.D.T1 that needs to be used within type A.B.C.T2, but there's also a type - // A.B.T1, using T1 in T2 will resolve A.B.T1 even if you have a using statement with A.B.C.D. - var hasChildWithName = false; - if (currentType != null && currentType.TypeDefinition != null && !currentType.IsExternal && targetElement != null) - { - var typeName = currentType.TypeDefinition.Name; - var ns = targetElement.GetImmediateParentOfType(); - var rootNs = ns?.GetRootNamespace(); - while (ns is not null && ns != rootNs && !hasChildWithName) - { - hasChildWithName = ns.GetChildElements(true).OfType().Any(c => c.Name?.Equals(typeName, StringComparison.OrdinalIgnoreCase) == true); - ns = ns.Parent is CodeNamespace n ? n : (ns.GetImmediateParentOfType()); - } - } - return hasChildWithName; - } - - private static bool DoesTypeExistsInOtherImportedNamespaces(CodeType currentType, CodeElement targetElement) - { - if (currentType.TypeDefinition is CodeClass { Parent: CodeNamespace currentTypeNamespace } codeClass) - { - var targetClass = targetElement.GetImmediateParentOfType(); - var importedNamespaces = targetClass.StartBlock.Usings - .Where(codeUsing => !codeUsing.IsExternal // 1. Are defined during generation(not external) - && codeUsing.Declaration?.TypeDefinition != null - && !codeUsing.Name.Equals(currentTypeNamespace.Name, StringComparison.OrdinalIgnoreCase)) // 2. Do not match the namespace of the current type - .Select(static codeUsing => codeUsing.Declaration!.TypeDefinition!.GetImmediateParentOfType()) - .DistinctBy(static declaredNamespace => declaredNamespace.Name); - - return importedNamespaces.Any(importedNamespace => (importedNamespace.FindChildByName(codeClass.Name, false) != null) - || (importedNamespace.FindChildByName(codeClass.Name, false) != null)); - } - return false; - } - public override string TranslateType(CodeType type) { ArgumentNullException.ThrowIfNull(type); From 0051887fe636ff1c96dde5459fd9b20af06a6b9d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 12 Nov 2024 13:16:17 +0100 Subject: [PATCH 147/194] Added dart to appsettings and launch --- .vscode/launch.json | 23 ++++++++++++++++++++++- src/kiota/appsettings.json | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f4bcd561b3..5e7ab25887 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -170,6 +170,27 @@ "console": "internalConsole", "stopAtEntry": false }, + { + "name": "Launch Dart", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/src/kiota/bin/Debug/net8.0/kiota.dll", + "args": [ + "generate", + "--openapi", + "https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-powershell/dev/openApiDocs/v1.0/Mail.yml", + "--language", + "dart", + "-o", + "${workspaceFolder}/samples/msgraph-mail/java/utilities/src/main/java/graphjavav4/utilities", + "-n", + "graphjavav4.utilities" + ], + "cwd": "${workspaceFolder}/src/kiota", + "console": "internalConsole", + "stopAtEntry": false + }, { "name": "Launch CLI (CSharp)", "type": "coreclr", @@ -385,4 +406,4 @@ "processId": "${command:pickProcess}" } ] -} \ No newline at end of file +} diff --git a/src/kiota/appsettings.json b/src/kiota/appsettings.json index 3e76f73085..61af6ad684 100644 --- a/src/kiota/appsettings.json +++ b/src/kiota/appsettings.json @@ -376,6 +376,42 @@ } ], "DependencyInstallCommand": "dotnet add package {0} --version {1}" + }, + "Dart": { + "MaturityLevel": "Experimental", + "Dependencies": [ + { + "Name": "kiota_abstractions", + "Version": "0.0.1", + "Type": "Abstractions" + }, + { + "Name": "kiota_http", + "Version": "0.0.1", + "Type": "Http" + }, + { + "Name": "kiota_serialization_form", + "Version": "0.0.1", + "Type": "Serialization" + }, + { + "Name": "kiota_serialization_text", + "Version": "0.0.1", + "Type": "Serialization" + }, + { + "Name": "kiota_serialization_json", + "Version": "0.0.1", + "Type": "Serialization" + }, + { + "Name": "kiota_serialization_multipart", + "Version": "0.0.1", + "Type": "Serialization" + } + ], + "DependencyInstallCommand": "" } } } From 4183cd1a8264a99af0c611cc9d3de87d8ac9d7b8 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 13 Nov 2024 07:43:19 +0100 Subject: [PATCH 148/194] Fix unit test --- src/Kiota.Builder/Refiners/DartRefiner.cs | 1 - src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 2 -- .../Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs | 4 ++-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index e21c7499a8..d7bae81e2d 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -281,7 +281,6 @@ private static void CorrectPropertyType(CodeProperty currentProperty) currentProperty.Type.Name = "Map"; currentProperty.DefaultValue = "{}"; currentProperty.Name = currentProperty.Name.ToFirstCharacterLowerCase(); - } else if (currentProperty.IsOfKind(CodePropertyKind.UrlTemplate)) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index c3bf521cf3..43146c7b00 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -61,5 +61,3 @@ private static HashSet deduplicateOptions(IEnumerable()", result); - AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "()", result); + Assert.Contains("{}", result); + AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "{}", result); AssertExtensions.CurlyBracesAreClosed(result); } [Fact] From bd73dd6c9594e16aefd408200b6267bd5d628996 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 13 Nov 2024 08:06:48 +0100 Subject: [PATCH 149/194] Fix issue found with unit test --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index d1e45dab6b..ced00afa08 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -798,7 +798,8 @@ private void WriteQueryparametersBody(CodeClass parentClass, CodeMethod codeElem writer.IncreaseIndent(); foreach (CodeProperty property in parentClass.Properties) { - writer.WriteLine($"'{property.Name}' : {property.Name},"); + var key = property.IsNameEscaped ? property.SerializationName : property.Name; + writer.WriteLine($"'{key}' : {property.Name},"); } writer.DecreaseIndent(); writer.WriteLine("};"); From 4e0f7ca745eff8a7a06f8bc42974395ee67ceaeb Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 13 Nov 2024 13:52:39 +0100 Subject: [PATCH 150/194] Activated multipart serialization SInce multipart branch of serialization was merged into json branch. --- src/Kiota.Builder/Refiners/DartRefiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 3c2dadcbcb..c6dde04795 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -126,7 +126,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonSerializationWriterFactory", $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextSerializationWriterFactory", $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormSerializationWriterFactory", - // $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", + $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", } ); ReplaceDefaultDeserializationModules( From 2c2457ef064680721354a279fe84e400dd52a496 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 14 Nov 2024 11:10:06 +0100 Subject: [PATCH 151/194] Fix typo in multipart and add multipart for integration tests --- it/dart/pubspec.yaml | 5 +++++ src/Kiota.Builder/Refiners/DartRefiner.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml index e234819775..37bae43f1b 100644 --- a/it/dart/pubspec.yaml +++ b/it/dart/pubspec.yaml @@ -33,6 +33,11 @@ dependencies: url: https://github.com/kiota-community/dart_kiota.git ref: json path: packages/kiota_serialization_json + kiota_serialization_multipart: + git: + url: https://github.com/kiota-community/dart_kiota.git + ref: json + path: packages/kiota_serialization_multipart http: ^1.2.2 uuid: ^4.5.1 diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index fa57a585bc..9f0394af98 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -136,7 +136,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken $"{SerializationNamespaceName}_json/{SerializationNamespaceName}_json.JsonSerializationWriterFactory", $"{SerializationNamespaceName}_text/{SerializationNamespaceName}_text.TextSerializationWriterFactory", $"{SerializationNamespaceName}_form/{SerializationNamespaceName}_form.FormSerializationWriterFactory", - $"{SerializationNamespaceName}_multi/{SerializationNamespaceName}_multi.MultipartSerializationWriterFactory", + $"{SerializationNamespaceName}_multipart/{SerializationNamespaceName}_multipart.MultipartSerializationWriterFactory", } ); ReplaceDefaultDeserializationModules( From 8af7f25ad9461764e7253770505477ef88d83243 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 15 Nov 2024 08:31:32 +0100 Subject: [PATCH 152/194] Moved some naming logic to refiner --- src/Kiota.Builder/Refiners/DartRefiner.cs | 9 +++++++++ src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 4 ---- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 5 ----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 9f0394af98..d2123daf5f 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -220,6 +220,15 @@ private static void CorrectCommonNames(CodeElement currentElement) foreach (var option in e.Options) { option.Name = DartConventionService.getCorrectedEnumName(option.Name); + option.SerializationName = option.SerializationName.Replace("'", "\\'", StringComparison.OrdinalIgnoreCase); + } + } + else if (currentElement is CodeProperty p && p.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum && !string.IsNullOrEmpty(p.DefaultValue)) + { + p.DefaultValue = DartConventionService.getCorrectedEnumName(p.DefaultValue.Trim('"').CleanupSymbolName()); + if (new DartReservedNamesProvider().ReservedNames.Contains(p.DefaultValue)) + { + p.DefaultValue += "Escaped"; } } CrawlTree(currentElement, element => CorrectCommonNames(element)); diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 43146c7b00..2229956e6d 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -31,10 +31,6 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write conventions.WriteShortDescription(option, writer); var serializationName = option.SerializationName; - if (serializationName.Contains('\'', StringComparison.OrdinalIgnoreCase)) - { - serializationName = serializationName.Replace("'", "\\'", StringComparison.OrdinalIgnoreCase); - } writer.WriteLine($"{option.Name}('{serializationName}'){(option == lastOption ? ";" : ",")}"); } writer.WriteLine($"const {enumName}(this.value);"); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index ced00afa08..f44fb46f23 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -323,11 +323,6 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum) { - defaultValue = DartConventionService.getCorrectedEnumName(defaultValue.Trim('"').CleanupSymbolName()); - if (new DartReservedNamesProvider().ReservedNames.Contains(defaultValue)) - { - defaultValue += "Escaped"; - } defaultValue = $"{conventions.GetTypeString(propWithDefault.Type, currentMethod).TrimEnd('?')}.{defaultValue}"; } else if (propWithDefault.Type is CodeType propertyType2) From 453ff8b52bcab4362836d0ec6b6d18fdcb37623b Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 15 Nov 2024 09:30:07 +0100 Subject: [PATCH 153/194] Stream is not a reserved word --- src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs index 18d1abeecf..3817f70b82 100644 --- a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -62,7 +62,6 @@ public class DartReservedNamesProvider : IReservedNamesProvider "set", "show", "static", - "stream", "string", "super", "switch", From 9865ca9efdbb62abc65f7080c1727a4e4871541d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 15 Nov 2024 10:10:46 +0100 Subject: [PATCH 154/194] Revert "Stream is not a reserved word" This reverts commit 453ff8b52bcab4362836d0ec6b6d18fdcb37623b. --- src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs index 3817f70b82..18d1abeecf 100644 --- a/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs +++ b/src/Kiota.Builder/Refiners/DartReservedNamesProvider.cs @@ -62,6 +62,7 @@ public class DartReservedNamesProvider : IReservedNamesProvider "set", "show", "static", + "stream", "string", "super", "switch", From 9d435635be6556eb783825fb174b60599f7bdb99 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 15 Nov 2024 11:42:36 +0100 Subject: [PATCH 155/194] Remove deduplication logic for enum options from enum writer --- src/Kiota.Builder/Refiners/DartRefiner.cs | 12 +++++++++- .../Writers/Dart/CodeEnumWriter.cs | 22 +------------------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index d2123daf5f..20c18ebfa5 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -217,11 +217,21 @@ private static void CorrectCommonNames(CodeElement currentElement) } else if (currentElement is CodeEnum e) { - foreach (var option in e.Options) + var options = e.Options.ToList(); + foreach (var option in options) { option.Name = DartConventionService.getCorrectedEnumName(option.Name); option.SerializationName = option.SerializationName.Replace("'", "\\'", StringComparison.OrdinalIgnoreCase); } + ///ensure enum options with the same corrected name get a unique name + var nameGroups = options.Select((Option, index) => new { Option, index }).GroupBy(s => s.Option.Name).ToList(); + foreach (var group in nameGroups.Where(g => g.Count() > 1)) + { + foreach (var entry in group.Skip(1).Select((g, i) => new { g, i })) + { + options[entry.g.index].Name = options[entry.g.index].Name + entry.i; + } + } } else if (currentElement is CodeProperty p && p.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum && !string.IsNullOrEmpty(p.DefaultValue)) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 2229956e6d..beaf3fecd9 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -23,7 +23,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write conventions.WriteDeprecationAttribute(codeElement, writer); writer.StartBlock($"enum {enumName} {{"); - var options = deduplicateOptions(codeElement.Options); + var options = codeElement.Options; var lastOption = options.Last(); foreach (var option in options) @@ -36,24 +36,4 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"const {enumName}(this.value);"); writer.WriteLine("final String value;"); } - - /// - /// Prevents duplicate options by making sure the option names are unique - /// - /// All options for a single enum - /// A unique set of options - private static HashSet deduplicateOptions(IEnumerable options) - { - HashSet uniqueOptionNames = []; - HashSet uniqueOptions = []; - foreach (var option in options) - { - if (uniqueOptionNames.Add(option.Name)) - { - uniqueOptions.Add(option); - } - } - - return uniqueOptions; - } } From 385953d6b3ca0cc044676bfb9e5f561acccc056b Mon Sep 17 00:00:00 2001 From: Kees-Schotanus <42993280+Kees-Schotanus@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:50:45 +0100 Subject: [PATCH 156/194] Update .github/workflows/integration-tests.yml Co-authored-by: Vincent Biret --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 8219928527..8576c5848f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -112,7 +112,7 @@ jobs: python-version: "3.11" - name: Setup Dart if: matrix.language == 'dart' - uses: dart-lang/setup-dart@v1.6.5 + uses: dart-lang/setup-dart@v1 with: sdk: "3.5" From 16988369e3fa099899487671f8963e1161c368e3 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus <42993280+Kees-Schotanus@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:51:06 +0100 Subject: [PATCH 157/194] Update .vscode/launch.json Co-authored-by: Vincent Biret --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 5e7ab25887..2638c90765 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -185,7 +185,7 @@ "-o", "${workspaceFolder}/samples/msgraph-mail/java/utilities/src/main/java/graphjavav4/utilities", "-n", - "graphjavav4.utilities" + "graphdart4.utilities" ], "cwd": "${workspaceFolder}/src/kiota", "console": "internalConsole", From 412000643bc4d8cd79323af1dba3b7076494e764 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus <42993280+Kees-Schotanus@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:18:23 +0100 Subject: [PATCH 158/194] Update src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs Co-authored-by: Vincent Biret --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index f44fb46f23..a16d8217a4 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -37,7 +37,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri } else { - if (isConstructor && !inherits && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition && !parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) + if (isConstructor && !inherits && parentClass.Properties.Where(static x => x.Kind is CodePropertyKind.AdditionalData).Any() && !parentClass.IsErrorDefinition && !parentClass.Properties.Where(static x => x.Kind is CodePropertyKind.BackingStore).Any()) { writer.DecreaseIndent(); } From 3010434c8314e052b8e7e3f6360090e2ae67939b Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Mon, 18 Nov 2024 14:22:45 +0100 Subject: [PATCH 159/194] Processed review comments. --- .../Writers/Dart/CodeClassDeclarationWriter.cs | 14 +++++++------- .../Writers/Dart/CodePropertyWriter.cs | 14 +++----------- .../Writers/Dart/DartWriterTests.cs | 1 - 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index f22a1868ff..61d3704404 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -27,13 +27,13 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent?.Parent is CodeNamespace) { codeElement.Usings - .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder - .Where(static x => x.IsExternal) - .Select(x => $"import 'package:{x.Declaration!.Name}.dart';") - .Distinct(StringComparer.Ordinal) - .OrderBy(static x => x, StringComparer.Ordinal) - .ToList() - .ForEach(x => writer.WriteLine(x)); + .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder + .Where(static x => x.IsExternal) + .Select(x => $"import 'package:{x.Declaration!.Name}.dart';") + .Distinct(StringComparer.Ordinal) + .OrderBy(static x => x, StringComparer.Ordinal) + .ToList() + .ForEach(x => writer.WriteLine(x)); foreach (var relativePath in codeElement.Usings .Where(static x => !x.IsExternal) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index c0331fdd8b..8c9e040e16 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -7,7 +7,6 @@ namespace Kiota.Builder.Writers.Dart; public class CodePropertyWriter : BaseElementWriter { - private DartReservedNamesProvider reservedNamesProvider = new DartReservedNamesProvider(); public CodePropertyWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter writer) { @@ -45,18 +44,13 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ writer.WriteLine(accessModifierAttribute); var propertyName = codeElement.Name; - if (reservedNamesProvider.ReservedNames.Contains(propertyName)) - { - propertyName += "Escaped"; - } switch (codeElement.Kind) { case CodePropertyKind.RequestBuilder: writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); conventions.AddRequestBuilderBody(parentClass, propertyType, writer, prefix: "return "); - writer.DecreaseIndent(); - writer.WriteLine("}"); + writer.CloseBlock(); break; case CodePropertyKind.AdditionalData when backingStoreProperty != null: case CodePropertyKind.Custom when backingStoreProperty != null: @@ -65,14 +59,12 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.IncreaseIndent(); writer.WriteLine($"return {backingStoreProperty.Name}.get<{propertyType}>('{backingStoreKey}'){defaultIfNotNullable};"); - writer.DecreaseIndent(); - writer.WriteLine("}"); + writer.CloseBlock(); writer.WriteLine(); writer.WriteLine($"set {codeElement.Name}({propertyType} value) {{"); writer.IncreaseIndent(); writer.WriteLine($"{backingStoreProperty.Name}.set('{backingStoreKey}', value);"); - writer.DecreaseIndent(); - writer.WriteLine("}"); + writer.CloseBlock(); break; case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition: writer.WriteLine("@override"); diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs index 11c3086f0d..7eef46c8a7 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/DartWriterTests.cs @@ -11,7 +11,6 @@ public class DartWriterTests public void Instantiates() { var writer = new DartWriter("./", "graph"); - Assert.NotNull(writer); Assert.NotNull(writer.PathSegmenter); Assert.Throws(() => new DartWriter(null, "graph")); Assert.Throws(() => new DartWriter("./", null)); From a13aa4ea25d89fc0a03ee61786aceb0cc497c080 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Mon, 18 Nov 2024 15:56:18 +0100 Subject: [PATCH 160/194] Use main branch --- it/dart/pubspec.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml index 37bae43f1b..4e7c399e90 100644 --- a/it/dart/pubspec.yaml +++ b/it/dart/pubspec.yaml @@ -11,32 +11,32 @@ dependencies: kiota_abstractions: git: url: https://github.com/kiota-community/dart_kiota.git - ref: json + ref: main path: packages/kiota_abstractions kiota_http: git: url: https://github.com/kiota-community/dart_kiota.git - ref: json + ref: main path: packages/kiota_http kiota_serialization_form: git: url: https://github.com/kiota-community/dart_kiota.git - ref: json + ref: main path: packages/kiota_serialization_form kiota_serialization_text: git: url: https://github.com/kiota-community/dart_kiota.git - ref: json + ref: main path: packages/kiota_serialization_text kiota_serialization_json: git: url: https://github.com/kiota-community/dart_kiota.git - ref: json + ref: main path: packages/kiota_serialization_json kiota_serialization_multipart: git: url: https://github.com/kiota-community/dart_kiota.git - ref: json + ref: main path: packages/kiota_serialization_multipart http: ^1.2.2 uuid: ^4.5.1 From 62ff9f95b77f8d1bda3744b201519cf165f47d30 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 19 Nov 2024 08:14:07 +0100 Subject: [PATCH 161/194] Replace double quotes with single --- src/Kiota.Builder/Refiners/DartRefiner.cs | 4 ++++ src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 20c18ebfa5..4e3d55881c 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -241,6 +241,10 @@ private static void CorrectCommonNames(CodeElement currentElement) p.DefaultValue += "Escaped"; } } + else if (currentElement is CodeProperty property && property.IsOfKind(CodePropertyKind.UrlTemplate) && !string.IsNullOrEmpty(property.DefaultValue)) + { + property.DefaultValue = $"'{property.DefaultValue.Trim('"')}'"; + } CrawlTree(currentElement, element => CorrectCommonNames(element)); } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 6a27a0d9a3..60ef2382da 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -118,7 +118,7 @@ internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, La urlTplRef = TempDictionaryVarName; writer.WriteLine($"var {urlTplRef} = Map.of({pathParametersProp.Name.ToFirstCharacterLowerCase()});"); foreach (var param in customParameters) - writer.WriteLine($"{urlTplRef}.putIfAbsent(\"{param.Name.ToFirstCharacterLowerCase()}\", ()=> {param.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"{urlTplRef}.putIfAbsent('{param.Name.ToFirstCharacterLowerCase()}', ()=> {param.Name.ToFirstCharacterLowerCase()});"); } writer.WriteLine($"{prefix}{returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterLowerCase()}{pathParametersSuffix});"); } From 68e41c80d97f0d878d00b1bc679fe3477fb4f5bc Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Tue, 19 Nov 2024 08:19:01 +0100 Subject: [PATCH 162/194] Updated forEach as part of review comments --- .../Writers/Dart/CodeClassDeclarationWriter.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 61d3704404..23ef230c60 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -26,14 +26,12 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent?.Parent is CodeNamespace) { - codeElement.Usings + foreach (var externalPath in codeElement.Usings .Where(x => (x.Declaration?.IsExternal ?? true) || !x.Declaration.Name.Equals(codeElement.Name, StringComparison.OrdinalIgnoreCase)) // needed for circular requests patterns like message folder .Where(static x => x.IsExternal) - .Select(x => $"import 'package:{x.Declaration!.Name}.dart';") - .Distinct(StringComparer.Ordinal) - .OrderBy(static x => x, StringComparer.Ordinal) - .ToList() - .ForEach(x => writer.WriteLine(x)); + .DistinctBy(static x => x.Declaration!.Name, StringComparer.Ordinal) + .OrderBy(static x => x.Declaration!.Name, StringComparer.Ordinal)) + writer.WriteLine($"import 'package:{externalPath.Declaration!.Name}.dart';"); foreach (var relativePath in codeElement.Usings .Where(static x => !x.IsExternal) From ee8bb0b29a1ebe2869c891d8cb17b12190402e6d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 19 Nov 2024 09:21:26 +0100 Subject: [PATCH 163/194] Urltemplates back to double quotes, map type to righthand side --- src/Kiota.Builder/Refiners/DartRefiner.cs | 4 ---- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 10 ++++++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 4e3d55881c..20c18ebfa5 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -241,10 +241,6 @@ private static void CorrectCommonNames(CodeElement currentElement) p.DefaultValue += "Escaped"; } } - else if (currentElement is CodeProperty property && property.IsOfKind(CodePropertyKind.UrlTemplate) && !string.IsNullOrEmpty(property.DefaultValue)) - { - property.DefaultValue = $"'{property.DefaultValue.Trim('"')}'"; - } CrawlTree(currentElement, element => CorrectCommonNames(element)); } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index a16d8217a4..bb0d8903a3 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -404,7 +404,6 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par } writer.WriteLine($"return {DefaultDeserializerReturnInstance}{{}};"); } - private const string DeserializerReturnType = "Map"; private const string DeserializerName = "deserializers"; private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) @@ -424,7 +423,14 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { var fieldToSerialize = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.ErrorMessageOverride).ToArray(); - writer.WriteLine($"{DeserializerReturnType} {DeserializerVarName} = " + (shouldHide ? "super.getFieldDeserializers();" : "{};")); + if (shouldHide) + { + writer.WriteLine($"var {DeserializerVarName} = " + "super.getFieldDeserializers();"); + } + else + { + writer.WriteLine($"var {DeserializerVarName} = {DefaultDeserializerReturnInstance}{{}};"); + } if (fieldToSerialize.Length != 0) { From 33fd7553f29f278d90592de227adc7509ad83e46 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 19 Nov 2024 10:28:00 +0100 Subject: [PATCH 164/194] Put back void before requestconfiguration functions --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 8 ++------ src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index bb0d8903a3..de2d5fe676 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -784,12 +784,8 @@ private static string GetMethodName(CodeMethod code, CodeClass parentClass, bool private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) { var signatureSegments = conventions.GetParameterSignature(parameter, targetElement).Split(" ", StringSplitOptions.RemoveEmptyEntries); - var nullablesegment = signatureSegments[0]; - if (!"void".Equals(nullablesegment, StringComparison.Ordinal)) - { - nullablesegment += "?"; - } - return $"{nullablesegment} {string.Join(" ", signatureSegments[1..])}"; + signatureSegments[1] += "?"; + return $"{string.Join(" ", signatureSegments)}"; } diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 60ef2382da..6d6275ea7c 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -192,7 +192,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i string.Empty; if (currentType.ActionOf && includeActionInformation) { - return $"Function({collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix})"; + return $"void Function({collectionPrefix}{typeName}{genericParameters}{nullableSuffix}{collectionSuffix})"; } return $"{collectionPrefix}{typeName}{genericParameters}{collectionSuffix}{nullableSuffix}"; From 23141806f3f8485d7db71a7dddbf79bbd526d8d1 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 19 Nov 2024 11:03:32 +0100 Subject: [PATCH 165/194] Changes to comments for method parameters --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index de2d5fe676..0c07def1e3 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -670,7 +670,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) foreach (var paramWithDescription in code.Parameters .Where(static x => x.Documentation.DescriptionAvailable) .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) - writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}"); + conventions.WriteParameterDescription(paramWithDescription, writer); conventions.WriteDeprecationAttribute(code, writer); } private static readonly BaseCodeParameterOrderComparer parameterOrderComparer = new(); diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 6d6275ea7c..431b72ba54 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -38,6 +38,13 @@ public override bool WriteShortDescription(IDocumentedElement element, LanguageW return true; } + public void WriteParameterDescription(CodeParameter element, LanguageWriter writer, string prefix = "", string suffix = "") + { + ArgumentNullException.ThrowIfNull(writer); + ArgumentNullException.ThrowIfNull(element); + var description = element.Documentation.GetDescription(x => GetTypeReferenceForDocComment(x, element), ReferenceTypePrefix, ReferenceTypeSuffix); + writer.WriteLine($"{DocCommentPrefix} {ReferenceTypePrefix}{element.Name}{ReferenceTypeSuffix} {description}"); + } public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEnumerable? additionalRemarks = default) { From 7b74c1d23c87e7f97146a2803dc45c8e4a074a94 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 19 Nov 2024 11:38:16 +0100 Subject: [PATCH 166/194] Check if segment at index 1 exists --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 0c07def1e3..d832dcd019 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -784,7 +784,8 @@ private static string GetMethodName(CodeMethod code, CodeClass parentClass, bool private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, CodeElement targetElement) { var signatureSegments = conventions.GetParameterSignature(parameter, targetElement).Split(" ", StringSplitOptions.RemoveEmptyEntries); - signatureSegments[1] += "?"; + if (signatureSegments.Length > 1 && signatureSegments[1].StartsWith("Function", StringComparison.Ordinal)) + signatureSegments[1] += "?"; return $"{string.Join(" ", signatureSegments)}"; } From 4b28b998d984d5a6a90348898f9f611b5fbbb360 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Tue, 19 Nov 2024 15:53:28 +0100 Subject: [PATCH 167/194] Added void as Function returntype in some more places --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 6 +++--- .../Writers/Dart/CodeMethodWriterTests.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index d832dcd019..0af717bfbb 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -374,8 +374,8 @@ private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod curren } } - private string DefaultDeserializerReturnType => $"Map"; - private string DefaultDeserializerReturnInstance => $""; + private string DefaultDeserializerReturnType => $"Map"; + private string DefaultDeserializerReturnInstance => $""; private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForUnionType) @@ -409,7 +409,7 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) { - writer.WriteLine($"{DefaultDeserializerReturnType} {DeserializerName} = {{}};"); + writer.WriteLine($"var {DeserializerName} = {DefaultDeserializerReturnInstance}{{}};"); var complexProperties = parentClass.GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => x.Type is CodeType propType && propType.TypeDefinition is CodeClass && !x.Type.IsCollection) .ToArray(); diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs index 44465e263b..41701466c8 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs @@ -992,8 +992,8 @@ public void WritesUnionDeSerializerBody() var result = tw.ToString(); Assert.Contains("complexType1Value != null", result); Assert.Contains("return complexType1Value!.getFieldDeserializers()", result); - Assert.Contains("{}", result); - AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "{}", result); + Assert.Contains("{}", result); + AssertExtensions.Before("return complexType1Value!.getFieldDeserializers()", "{}", result); AssertExtensions.CurlyBracesAreClosed(result); } [Fact] @@ -1013,7 +1013,7 @@ public void WritesIntersectionDeSerializerBody() }).First(); writer.Write(deserializationMethod); var result = tw.ToString(); - Assert.Contains("Map deserializers = {};", result); + Assert.Contains("var deserializers = {};", result); Assert.Contains("if(complexType1Value != null){complexType1Value!.getFieldDeserializers().forEach((k,v) => deserializers.putIfAbsent(k, ()=>v));}", result); Assert.Contains("if(complexType3Value != null){complexType3Value!.getFieldDeserializers().forEach((k,v) => deserializers.putIfAbsent(k, ()=>v));}", result); Assert.Contains("return deserializers", result); From 50dea25adecfc8847bfd933fd115ee90f937d108 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 20 Nov 2024 07:48:57 +0100 Subject: [PATCH 168/194] use _ instead of escaped --- src/Kiota.Builder/Refiners/DartRefiner.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 20c18ebfa5..4397651d87 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -121,12 +121,12 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken AddAsyncSuffix(generatedCode); AddDiscriminatorMappingsUsingsToParentClasses(generatedCode, "ParseNode", addUsings: true, includeParentNamespace: true); - ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}Escaped"); + ReplaceReservedNames(generatedCode, reservedNamesProvider, x => $"{x}_"); ReplaceReservedModelTypes(generatedCode, reservedNamesProvider, x => $"{x}Object"); ReplaceReservedExceptionPropertyNames( generatedCode, new DartExceptionsReservedNamesProvider(), - static x => $"{x.ToFirstCharacterLowerCase()}Escaped" + static x => $"{x.ToFirstCharacterLowerCase()}_" ); ReplaceDefaultSerializationModules( @@ -238,7 +238,7 @@ private static void CorrectCommonNames(CodeElement currentElement) p.DefaultValue = DartConventionService.getCorrectedEnumName(p.DefaultValue.Trim('"').CleanupSymbolName()); if (new DartReservedNamesProvider().ReservedNames.Contains(p.DefaultValue)) { - p.DefaultValue += "Escaped"; + p.DefaultValue += "_"; } } CrawlTree(currentElement, element => CorrectCommonNames(element)); From c1e813ede6ead54113916b128573b43f3ca7b912 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 20 Nov 2024 08:20:08 +0100 Subject: [PATCH 169/194] Corrected unit test for checking for _ instead of escaped, added comment about generated code --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 3 +++ src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 -- .../Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 23ef230c60..c421d95e3d 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -7,6 +7,7 @@ namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter { private readonly RelativeImportManager relativeImportManager; + private static string AutoGenerationHeader => "/// auto generated"; public CodeClassDeclarationWriter(DartConventionService conventionService, string clientNamespaceName, DartPathSegmenter pathSegmenter) : base(conventionService) { @@ -21,6 +22,8 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); + writer.WriteLine("// ignore_for_file: type=lint"); + writer.WriteLine(AutoGenerationHeader); var currentNamespace = codeElement.GetImmediateParentOfType(); diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 431b72ba54..65213907f7 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -12,9 +12,7 @@ namespace Kiota.Builder.Writers.Dart; public class DartConventionService : CommonLanguageConventionService { - internal static string AutoGenerationHeader => "// auto generated"; internal static readonly HashSet ErrorClassProperties = new(StringComparer.OrdinalIgnoreCase) { "message", "statusCode", "responseHeaders", "innerExceptions" }; - public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; diff --git a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs index c71de8f288..da52efde87 100644 --- a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs @@ -84,7 +84,7 @@ public async Task EscapesReservedKeywordsInInternalDeclaration() model.AddUsing(nUsing); await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEqual("break", nUsing.Declaration.Name, StringComparer.OrdinalIgnoreCase); - Assert.Contains("Escaped", nUsing.Declaration.Name); + Assert.Contains("_", nUsing.Declaration.Name); } [Fact] public async Task EscapesReservedKeywords() @@ -96,7 +96,7 @@ public async Task EscapesReservedKeywords() }).First(); await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Dart }, root); Assert.NotEqual("break", model.Name, StringComparer.OrdinalIgnoreCase); - Assert.Contains("Escaped", model.Name); + Assert.Contains("_", model.Name); } [Fact] public async Task AddsDefaultImports() From 95a753a4aae61cb8aaa67cd58c905be5930daa20 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Wed, 20 Nov 2024 09:15:06 +0100 Subject: [PATCH 170/194] also add autogenerated and linting messages to enums --- .../Writers/Dart/CodeClassDeclarationWriter.cs | 6 ++---- src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs | 2 ++ src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- .../Writers/Dart/DartConventionService.cs | 14 ++++++++++++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index c421d95e3d..75542f11d0 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -7,7 +7,6 @@ namespace Kiota.Builder.Writers.Dart; public class CodeClassDeclarationWriter : BaseElementWriter { private readonly RelativeImportManager relativeImportManager; - private static string AutoGenerationHeader => "/// auto generated"; public CodeClassDeclarationWriter(DartConventionService conventionService, string clientNamespaceName, DartPathSegmenter pathSegmenter) : base(conventionService) { @@ -22,9 +21,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException($"The provided code element {codeElement.Name} doesn't have a parent of type {nameof(CodeClass)}"); - writer.WriteLine("// ignore_for_file: type=lint"); - writer.WriteLine(AutoGenerationHeader); - + conventions.WriteLintingMessage(writer); var currentNamespace = codeElement.GetImmediateParentOfType(); if (codeElement.Parent?.Parent is CodeNamespace) @@ -53,6 +50,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit var derivation = derivedTypes.Length != 0 ? " extends " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") : string.Empty; var implements = !codeElement.Implements.Any() ? string.Empty : $" implements {codeElement.Implements.Select(x => x.Name).Aggregate((x, y) => x + ", " + y)}"; + conventions.WriteAutogeneratedMessage(writer); conventions.WriteLongDescription(parentClass, writer); conventions.WriteDeprecationAttribute(parentClass, writer); writer.StartBlock($"class {codeElement.Name}{derivation}{implements} {{"); diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index beaf3fecd9..8ea3f0fffb 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -19,6 +19,8 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write if (!codeElement.Options.Any()) return; var enumName = codeElement.Name; + conventions.WriteLintingMessage(writer); + conventions.WriteAutogeneratedMessage(writer); conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecationAttribute(codeElement, writer); writer.StartBlock($"enum {enumName} {{"); diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 0af717bfbb..63260801c2 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -295,7 +295,7 @@ private static void WriteSerializationRegistration(HashSet serialization { if (serializationClassNames != null) foreach (var serializationClassName in serializationClassNames) - writer.WriteLine($"ApiClientBuilder.{methodName}(() => {serializationClassName}());"); + writer.WriteLine($"ApiClientBuilder.{methodName}({serializationClassName}.new);"); } private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 65213907f7..85753ff583 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -12,6 +12,7 @@ namespace Kiota.Builder.Writers.Dart; public class DartConventionService : CommonLanguageConventionService { + private static string AutoGenerationHeader => "/// auto generated"; internal static readonly HashSet ErrorClassProperties = new(StringComparer.OrdinalIgnoreCase) { "message", "statusCode", "responseHeaders", "innerExceptions" }; public override string StreamTypeName => "stream"; public override string VoidTypeName => "void"; @@ -44,6 +45,19 @@ public void WriteParameterDescription(CodeParameter element, LanguageWriter writ writer.WriteLine($"{DocCommentPrefix} {ReferenceTypePrefix}{element.Name}{ReferenceTypeSuffix} {description}"); } + public void WriteAutogeneratedMessage(LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteLine(AutoGenerationHeader); + } + + + public void WriteLintingMessage(LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteLine("// ignore_for_file: type=lint"); + } + public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEnumerable? additionalRemarks = default) { ArgumentNullException.ThrowIfNull(writer); From 7aeb5f641bd986c3cc0385093e9c6cebc5a5fff8 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 21 Nov 2024 17:05:36 +0100 Subject: [PATCH 171/194] Changed package names --- it/dart/basic/test/api_client_test.dart | 4 ++-- it/dart/pubspec.yaml | 24 +++++++++++------------ src/Kiota.Builder/Refiners/DartRefiner.cs | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/it/dart/basic/test/api_client_test.dart b/it/dart/basic/test/api_client_test.dart index e49a039f44..03b737137b 100644 --- a/it/dart/basic/test/api_client_test.dart +++ b/it/dart/basic/test/api_client_test.dart @@ -1,5 +1,5 @@ -import 'package:kiota_abstractions/kiota_abstractions.dart'; -import 'package:kiota_http/kiota_http.dart'; +import 'package:microsoft_kiota_abstractions/microsoft_kiota_abstractions.dart'; +import 'package:microsoft_kiota_http/microsoft_kiota_http.dart'; import 'package:test/test.dart'; import '../src/api_client.dart'; import '../src/models/error.dart'; diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml index 4e7c399e90..8f07ca3e69 100644 --- a/it/dart/pubspec.yaml +++ b/it/dart/pubspec.yaml @@ -8,36 +8,36 @@ environment: # Add regular dependencies here. dependencies: - kiota_abstractions: + microsoft_kiota_abstractions: git: url: https://github.com/kiota-community/dart_kiota.git ref: main - path: packages/kiota_abstractions - kiota_http: + path: packages/microsoft_kiota_abstractions + microsoft_kiota_http: git: url: https://github.com/kiota-community/dart_kiota.git ref: main - path: packages/kiota_http - kiota_serialization_form: + path: packages/microsoft_kiota_http + microsoft_kiota_serialization_form: git: url: https://github.com/kiota-community/dart_kiota.git ref: main - path: packages/kiota_serialization_form - kiota_serialization_text: + path: packages/microsoft_kiota_serialization_form + microsoft_kiota_serialization_text: git: url: https://github.com/kiota-community/dart_kiota.git ref: main - path: packages/kiota_serialization_text - kiota_serialization_json: + path: packages/microsoft_kiota_serialization_text + microsoft_kiota_serialization_json: git: url: https://github.com/kiota-community/dart_kiota.git ref: main - path: packages/kiota_serialization_json - kiota_serialization_multipart: + path: packages/microsoft_kiota_serialization_json + microsoft_kiota_serialization_multipart: git: url: https://github.com/kiota-community/dart_kiota.git ref: main - path: packages/kiota_serialization_multipart + path: packages/microsoft_kiota_serialization_multipart http: ^1.2.2 uuid: ^4.5.1 diff --git a/src/Kiota.Builder/Refiners/DartRefiner.cs b/src/Kiota.Builder/Refiners/DartRefiner.cs index 4397651d87..054415c1ad 100644 --- a/src/Kiota.Builder/Refiners/DartRefiner.cs +++ b/src/Kiota.Builder/Refiners/DartRefiner.cs @@ -13,8 +13,8 @@ namespace Kiota.Builder.Refiners; public class DartRefiner : CommonLanguageRefiner, ILanguageRefiner { private const string MultipartBodyClassName = "MultipartBody"; - private const string AbstractionsNamespaceName = "kiota_abstractions/kiota_abstractions"; - private const string SerializationNamespaceName = "kiota_serialization"; + private const string AbstractionsNamespaceName = "microsoft_kiota_abstractions/microsoft_kiota_abstractions"; + private const string SerializationNamespaceName = "microsoft_kiota_serialization"; private static readonly CodeUsingDeclarationNameComparer usingComparer = new(); protected static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { From 5fef7e4ed535bf7adc8a3b52aeba1d6096654ec3 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Thu, 21 Nov 2024 17:14:30 +0100 Subject: [PATCH 172/194] Change package name in unit test --- tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs index da52efde87..7310b4b2ba 100644 --- a/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/DartLanguageRefinerTests.cs @@ -408,7 +408,7 @@ public async Task AddsUsingForUntypedNode(bool usesBackingStore) Assert.NotEmpty(model.StartBlock.Usings); var nodeUsing = model.StartBlock.Usings.Where(static declaredUsing => declaredUsing.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)).ToArray(); Assert.Single(nodeUsing); - Assert.Equal("kiota_abstractions/kiota_abstractions", nodeUsing[0].Declaration.Name); + Assert.Equal("microsoft_kiota_abstractions/microsoft_kiota_abstractions", nodeUsing[0].Declaration.Name); } [Fact] public async Task AddsCustomMethods() From c5600c1bcbfe37e776d5255ea59a61ab997acdc7 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 22 Nov 2024 07:47:34 +0100 Subject: [PATCH 173/194] Added bundle to appsettings --- src/kiota/appsettings.json | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/kiota/appsettings.json b/src/kiota/appsettings.json index 61af6ad684..d26c4be32d 100644 --- a/src/kiota/appsettings.json +++ b/src/kiota/appsettings.json @@ -381,34 +381,39 @@ "MaturityLevel": "Experimental", "Dependencies": [ { - "Name": "kiota_abstractions", + "Name": "microsoft_kiota_abstractions", "Version": "0.0.1", "Type": "Abstractions" }, { - "Name": "kiota_http", + "Name": "microsoft_kiota_http", "Version": "0.0.1", "Type": "Http" }, { - "Name": "kiota_serialization_form", + "Name": "microsoft_kiota_serialization_form", "Version": "0.0.1", "Type": "Serialization" }, { - "Name": "kiota_serialization_text", + "Name": "microsoft_kiota_serialization_text", "Version": "0.0.1", "Type": "Serialization" }, { - "Name": "kiota_serialization_json", + "Name": "microsoft_kiota_serialization_json", "Version": "0.0.1", "Type": "Serialization" }, { - "Name": "kiota_serialization_multipart", + "Name": "microsoft_kiota_serialization_multipart", "Version": "0.0.1", "Type": "Serialization" + }, + { + "Name": "microsoft_kiota_bundle", + "Version": "0.0.1", + "Type": "Bundle" } ], "DependencyInstallCommand": "" From 79ddf75709ab1a3900697901c4b468722c40a502 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 22 Nov 2024 08:00:38 +0100 Subject: [PATCH 174/194] Fix casing for stream, use static in lambda's where possible --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 10 +++++----- .../Writers/Dart/DartConventionService.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 63260801c2..50630bc7a6 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -43,7 +43,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri } else if (isConstructor && parentClass.IsErrorDefinition) { - if (parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) + if (parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { writer.CloseBlock("}) {additionalData = {};}"); } @@ -360,7 +360,7 @@ private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod curren { writer.WriteLine($"super.{prop},"); } - if (!parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) + if (!parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { foreach (CodeProperty prop in parentClass.GetPropertiesOfKind(CodePropertyKind.Custom, CodePropertyKind.AdditionalData)) { @@ -700,7 +700,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass } return " : super()"; } - else if (isConstructor && parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition && !parentClass.Properties.Where(x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) + else if (isConstructor && parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.AdditionalData)).Any() && !parentClass.IsErrorDefinition && !parentClass.Properties.Where(static x => x.IsOfKind(CodePropertyKind.BackingStore)).Any()) { return " : "; } @@ -727,7 +727,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua var completeReturnType = isConstructor ? string.Empty : voidCorrectedTaskReturnType + " "; var baseSuffix = GetBaseSuffix(isConstructor, inherits, parentClass, code); - var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); + var parameters = string.Join(", ", code.Parameters.OrderBy(static x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, code)).ToList()); var methodName = GetMethodName(code, parentClass, isConstructor); var includeNullableReferenceType = code.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator); var openingBracket = baseSuffix.Equals(" : ", StringComparison.Ordinal) ? "" : "{"; @@ -836,7 +836,7 @@ private void WriteCustomMethodBody(CodeMethod codeElement, CodeClass parentClass if (codeElement.Name.Equals("clone", StringComparison.OrdinalIgnoreCase)) { var constructor = parentClass.GetMethodsOffKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor).Where(static x => x.Parameters.Any()).FirstOrDefault(); - var argumentList = constructor?.Parameters.OrderBy(x => x, new BaseCodeParameterOrderComparer()) + var argumentList = constructor?.Parameters.OrderBy(static x => x, new BaseCodeParameterOrderComparer()) .Select(static x => x.Type.Parent is CodeParameter param && param.IsOfKind(CodeParameterKind.RequestAdapter, CodeParameterKind.PathParameters) ? x.Name : x.Optional ? "null" : x.DefaultValue) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 85753ff583..057bbfcf77 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -14,7 +14,7 @@ public class DartConventionService : CommonLanguageConventionService { private static string AutoGenerationHeader => "/// auto generated"; internal static readonly HashSet ErrorClassProperties = new(StringComparer.OrdinalIgnoreCase) { "message", "statusCode", "responseHeaders", "innerExceptions" }; - public override string StreamTypeName => "stream"; + public override string StreamTypeName => "Stream"; public override string VoidTypeName => "void"; public override string DocCommentPrefix => "/// "; private static readonly HashSet NullableTypes = new(StringComparer.OrdinalIgnoreCase) { "int", "bool", "double", "string", "datetime", "dateonly", "timeonly", "backingstorefactory" }; From ad8cb485d18f0584807f6bd5814b7673e5682580 Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 22 Nov 2024 08:19:04 +0100 Subject: [PATCH 175/194] Update src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs Co-authored-by: Vincent Biret --- src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 8c9e040e16..006db6b2b1 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -61,8 +61,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ writer.WriteLine($"return {backingStoreProperty.Name}.get<{propertyType}>('{backingStoreKey}'){defaultIfNotNullable};"); writer.CloseBlock(); writer.WriteLine(); - writer.WriteLine($"set {codeElement.Name}({propertyType} value) {{"); - writer.IncreaseIndent(); + writer.StartBlock($"set {codeElement.Name}({propertyType} value) {{"); writer.WriteLine($"{backingStoreProperty.Name}.set('{backingStoreKey}', value);"); writer.CloseBlock(); break; From 4a912176a45173b049f6af70110b1461d3847a7f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 22 Nov 2024 08:28:17 +0100 Subject: [PATCH 176/194] Update src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs Co-authored-by: Vincent Biret --- src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index 75542f11d0..e7c6ffc911 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -48,7 +48,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit var derivedTypes = (codeElement.Inherits is null ? Enumerable.Empty() : [conventions.GetTypeString(codeElement.Inherits, parentClass)]).ToArray(); var derivation = derivedTypes.Length != 0 ? " extends " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") : string.Empty; - var implements = !codeElement.Implements.Any() ? string.Empty : $" implements {codeElement.Implements.Select(x => x.Name).Aggregate((x, y) => x + ", " + y)}"; + var implements = !codeElement.Implements.Any() ? string.Empty : $" implements {codeElement.Implements.Select(static x => x.Name).Aggregate(static (x, y) => x + ", " + y)}"; conventions.WriteAutogeneratedMessage(writer); conventions.WriteLongDescription(parentClass, writer); From 8fde406ea880660f994e5a5af18ba44597bd5b2c Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 22 Nov 2024 08:37:05 +0100 Subject: [PATCH 177/194] Update src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs Co-authored-by: Vincent Biret --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 50630bc7a6..7becabf23d 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -179,8 +179,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla if (propertyType.TypeDefinition is CodeClass && !propertyType.IsCollection) { var mappedType = parentClass.DiscriminatorInformation.DiscriminatorMappings.FirstOrDefault(x => x.Value.Name.Equals(propertyType.Name, StringComparison.OrdinalIgnoreCase)); - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if('{mappedType.Key}' == {DiscriminatorMappingVarName}) {{"); - writer.IncreaseIndent(); + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if('{mappedType.Key}' == {DiscriminatorMappingVarName}) {{"); writer.WriteLine($"{ResultVarName}.{property.Name} = {conventions.GetTypeString(propertyType, codeElement)}();"); writer.CloseBlock(); } From a054ae198170bb9f24693f20271b2b9ac482594d Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Fri, 22 Nov 2024 09:04:08 +0100 Subject: [PATCH 178/194] Use startblock where possible in codemethodwriter, some cleanup of unused stuff --- .../Writers/Dart/CodeBlockEndWriter.cs | 3 -- .../Writers/Dart/CodeEnumWriter.cs | 5 --- .../Writers/Dart/CodeMethodWriter.cs | 35 +++++++------------ .../Writers/Dart/CodePropertyWriter.cs | 12 ++----- .../Writers/Dart/DartConventionService.cs | 8 +---- 5 files changed, 16 insertions(+), 47 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs index 00697d91e8..caf0f81346 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeBlockEndWriter.cs @@ -1,8 +1,5 @@ using System; -using System.Linq; using Kiota.Builder.CodeDOM; -using Kiota.Builder.Extensions; -using Kiota.Builder.OrderComparers; namespace Kiota.Builder.Writers.Dart; public class CodeBlockEndWriter : ICodeElementWriter diff --git a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs index 8ea3f0fffb..d736fb80c5 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeEnumWriter.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Generic; using System.Linq; using Kiota.Builder.CodeDOM; -using Kiota.Builder.Extensions; -using Kiota.Builder.Refiners; -using Microsoft.OpenApi.Any; namespace Kiota.Builder.Writers.Dart; public class CodeEnumWriter : BaseElementWriter { - public static string AutoGenerationHeader => "// "; public CodeEnumWriter(DartConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 7becabf23d..f76f8bc3c8 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -4,7 +4,6 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.OrderComparers; -using Kiota.Builder.Refiners; using static Kiota.Builder.CodeDOM.CodeTypeBase; namespace Kiota.Builder.Writers.Dart; @@ -111,7 +110,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w WriteRequestBuilderBody(parentClass, codeElement, writer); break; case CodeMethodKind.QueryParametersMapper: - WriteQueryparametersBody(parentClass, codeElement, writer); + WriteQueryparametersBody(parentClass, writer); break; case CodeMethodKind.Getter: case CodeMethodKind.Setter: @@ -187,8 +186,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla { var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); var check = propertyType.IsCollection ? ".isNotEmpty" : $" is {typeName}"; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); - writer.IncreaseIndent(); + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); writer.WriteLine($"{ResultVarName}.{property.Name} = {parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)};"); writer.CloseBlock(); } @@ -225,8 +223,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, { if (includeElse) { - writer.WriteLine("else {"); - writer.IncreaseIndent(); + writer.StartBlock("else {"); } foreach (var property in complexProperties) writer.WriteLine($"{ResultVarName}.{property.Item1.Name} = {conventions.GetTypeString(property.Item2, codeElement)}();"); @@ -300,7 +297,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho { if (parentClass.IsErrorDefinition) { - WriteErrorClassConstructor(parentClass, currentMethod, writer); + WriteErrorClassConstructor(parentClass, writer); } else { @@ -353,7 +350,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho } } - private void WriteErrorClassConstructor(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer) + private void WriteErrorClassConstructor(CodeClass parentClass, LanguageWriter writer) { foreach (string prop in DartConventionService.ErrorClassProperties) { @@ -496,8 +493,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.WriteLine($"Map> {errorMappingVarName} = {{"); - writer.IncreaseIndent(); + writer.StartBlock($"Map> {errorMappingVarName} = {{"); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { writer.WriteLine($"'{errorMapping.Key.ToUpperInvariant()}' : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); @@ -591,8 +587,7 @@ private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass paren { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name} != null) {{"); - writer.IncreaseIndent(); + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name} != null) {{"); writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name});"); writer.CloseBlock(); if (!includeElse) @@ -611,8 +606,7 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas { var serializationMethodName = GetSerializationMethodName(otherProp.Type, method); var booleanValue = serializationMethodName == "writeBoolValue" ? "value:" : ""; - writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name} != null) {{"); - writer.IncreaseIndent(); + writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name} != null) {{"); writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {booleanValue}{otherProp.Name});"); writer.CloseBlock(); if (!includeElse) @@ -625,8 +619,7 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas { if (includeElse) { - writer.WriteLine("else {"); - writer.IncreaseIndent(); + writer.StartBlock("else {"); } var firstPropertyName = complexProperties.First().Name; var propertiesNames = complexProperties.Skip(1).Any() ? complexProperties.Skip(1) @@ -709,7 +702,7 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; - if (code.IsOfKind(CodeMethodKind.Serializer, CodeMethodKind.Deserializer, CodeMethodKind.QueryParametersMapper) || (code.IsOfKind(CodeMethodKind.Custom))) + if (code.IsOfKind(CodeMethodKind.Serializer, CodeMethodKind.Deserializer, CodeMethodKind.QueryParametersMapper) || code.IsOfKind(CodeMethodKind.Custom)) { writer.WriteLine("@override"); } @@ -789,17 +782,15 @@ private string GetParameterSignatureWithNullableRefType(CodeParameter parameter, } - private void WriteQueryparametersBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) + private void WriteQueryparametersBody(CodeClass parentClass, LanguageWriter writer) { - writer.WriteLine("return {"); - writer.IncreaseIndent(); + writer.StartBlock("return {"); foreach (CodeProperty property in parentClass.Properties) { var key = property.IsNameEscaped ? property.SerializationName : property.Name; writer.WriteLine($"'{key}' : {property.Name},"); } - writer.DecreaseIndent(); - writer.WriteLine("};"); + writer.CloseBlock("};"); } private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod method, bool includeNullableRef = false) diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index 006db6b2b1..16ceee96eb 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -1,8 +1,6 @@ using System; using System.Linq; using Kiota.Builder.CodeDOM; -using Kiota.Builder.Extensions; -using Kiota.Builder.Refiners; namespace Kiota.Builder.Writers.Dart; public class CodePropertyWriter : BaseElementWriter @@ -39,16 +37,11 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ var defaultValue = string.Empty; var getterModifier = string.Empty; - var accessModifierAttribute = conventions.GetAccessModifierAttribute(codeElement.Access); - if (!string.IsNullOrEmpty(accessModifierAttribute)) - writer.WriteLine(accessModifierAttribute); - var propertyName = codeElement.Name; switch (codeElement.Kind) { case CodePropertyKind.RequestBuilder: - writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); - writer.IncreaseIndent(); + writer.StartBlock($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); conventions.AddRequestBuilderBody(parentClass, propertyType, writer, prefix: "return "); writer.CloseBlock(); break; @@ -56,8 +49,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ case CodePropertyKind.Custom when backingStoreProperty != null: var backingStoreKey = codeElement.WireName; var defaultIfNotNullable = propertyType.EndsWith('?') ? string.Empty : codeElement.IsOfKind(CodePropertyKind.AdditionalData) ? " ?? {}" : $" ?? {codeElement.DefaultValue}"; - writer.WriteLine($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); - writer.IncreaseIndent(); + writer.StartBlock($"{propertyType} get {conventions.GetAccessModifierPrefix(codeElement.Access)}{propertyName} {{"); writer.WriteLine($"return {backingStoreProperty.Name}.get<{propertyType}>('{backingStoreKey}'){defaultIfNotNullable};"); writer.CloseBlock(); writer.WriteLine(); diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 057bbfcf77..678dd4e1f0 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.Tracing; using System.Globalization; using System.Linq; @@ -37,7 +36,7 @@ public override bool WriteShortDescription(IDocumentedElement element, LanguageW return true; } - public void WriteParameterDescription(CodeParameter element, LanguageWriter writer, string prefix = "", string suffix = "") + public void WriteParameterDescription(CodeParameter element, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); ArgumentNullException.ThrowIfNull(element); @@ -119,11 +118,6 @@ public string GetAccessModifierPrefix(AccessModifier access) }; } - public string GetAccessModifierAttribute(AccessModifier access) - { - return string.Empty; - } - internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, string? prefix = default, IEnumerable? pathParameters = default, IEnumerable? customParameters = default) { if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp && From 727f17a794263b6275a7660b5853d37f1b72a80d Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Fri, 22 Nov 2024 10:14:54 +0100 Subject: [PATCH 179/194] Updated to version 0.0.2 of the abstractions --- src/kiota/appsettings.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/kiota/appsettings.json b/src/kiota/appsettings.json index d26c4be32d..4d15112889 100644 --- a/src/kiota/appsettings.json +++ b/src/kiota/appsettings.json @@ -382,37 +382,37 @@ "Dependencies": [ { "Name": "microsoft_kiota_abstractions", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Abstractions" }, { "Name": "microsoft_kiota_http", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Http" }, { "Name": "microsoft_kiota_serialization_form", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Serialization" }, { "Name": "microsoft_kiota_serialization_text", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Serialization" }, { "Name": "microsoft_kiota_serialization_json", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Serialization" }, { "Name": "microsoft_kiota_serialization_multipart", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Serialization" }, { "Name": "microsoft_kiota_bundle", - "Version": "0.0.1", + "Version": "0.0.2", "Type": "Bundle" } ], From 92be3f8119270e63a70026ab8d4de8bb641cdf1f Mon Sep 17 00:00:00 2001 From: Joanne ter Maat Date: Mon, 25 Nov 2024 10:48:08 +0100 Subject: [PATCH 180/194] Update src/kiota/appsettings.json Co-authored-by: Vincent Biret --- src/kiota/appsettings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kiota/appsettings.json b/src/kiota/appsettings.json index 4d15112889..c785f4befb 100644 --- a/src/kiota/appsettings.json +++ b/src/kiota/appsettings.json @@ -379,6 +379,7 @@ }, "Dart": { "MaturityLevel": "Experimental", + "SupportExperience": "Community", "Dependencies": [ { "Name": "microsoft_kiota_abstractions", From 1a2e0c1a18056790fa8b91063eed5142d3b3fe2d Mon Sep 17 00:00:00 2001 From: Kees-Schotanus <42993280+Kees-Schotanus@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:49:06 +0100 Subject: [PATCH 181/194] Update src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs Co-authored-by: Ricardo Boss --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index f76f8bc3c8..92fea9e12a 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -493,7 +493,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.StartBlock($"Map> {errorMappingVarName} = {{"); + writer.StartBlock($"final {errorMappingVarName} = >{{"); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { writer.WriteLine($"'{errorMapping.Key.ToUpperInvariant()}' : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); From cf2f21de468e8ee2a578e416fe84428429882245 Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 27 Nov 2024 08:58:11 +0100 Subject: [PATCH 182/194] Undo last commit as it fails the tests --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 92fea9e12a..f76f8bc3c8 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -493,7 +493,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.StartBlock($"final {errorMappingVarName} = >{{"); + writer.StartBlock($"Map> {errorMappingVarName} = {{"); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { writer.WriteLine($"'{errorMapping.Key.ToUpperInvariant()}' : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); From 48c83e4f68312c5b4e52e8f99784f2cd9f54406c Mon Sep 17 00:00:00 2001 From: Kees-Schotanus Date: Wed, 27 Nov 2024 12:48:11 +0100 Subject: [PATCH 183/194] Changes after review comment Ricardo's suggestion has been applied and the test has been updated. --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 2 +- tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index f76f8bc3c8..92fea9e12a 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -493,7 +493,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.StartBlock($"Map> {errorMappingVarName} = {{"); + writer.StartBlock($"final {errorMappingVarName} = >{{"); foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) { writer.WriteLine($"'{errorMapping.Key.ToUpperInvariant()}' : {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.createFromDiscriminatorValue,"); diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs index 41701466c8..7426330ec5 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodeMethodWriterTests.cs @@ -652,7 +652,7 @@ public void WritesRequestExecutorBody() writer.Write(method); var result = tw.ToString(); Assert.Contains("var requestInfo", result); - Assert.Contains("Map> errorMapping = {", result); + Assert.Contains("final errorMapping = >{", result); Assert.Contains("'401' : Error401.createFromDiscriminatorValue,", result); Assert.Contains("'4XX' : Error4XX.createFromDiscriminatorValue,", result); Assert.Contains("'5XX' : Error5XX.createFromDiscriminatorValue,", result); From 1d9b26815aa406712f1f81c3f4d87c3f0004d886 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 22:28:03 +0100 Subject: [PATCH 184/194] Use minimum Dart SDK 3.6 --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 978bc0b184..7435d74ca7 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -114,7 +114,7 @@ jobs: if: matrix.language == 'dart' uses: dart-lang/setup-dart@v1 with: - sdk: "3.5" + sdk: "3.6" - name: Check if test is suppressed id: check-suppressed From 80e06a59a27add65ead502dccbef5653fcf924ac Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 22:37:34 +0100 Subject: [PATCH 185/194] Changed dependencies to use new repository location also updated the min environment version and dependencies --- it/dart/pubspec.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml index 8f07ca3e69..ba6e51a350 100644 --- a/it/dart/pubspec.yaml +++ b/it/dart/pubspec.yaml @@ -4,43 +4,43 @@ version: 0.0.1 publish_to: none environment: - sdk: ^3.4.4 + sdk: ^3.6.0 # Add regular dependencies here. dependencies: microsoft_kiota_abstractions: git: - url: https://github.com/kiota-community/dart_kiota.git + url: https://github.com/microsoft/kiota-dart.git ref: main path: packages/microsoft_kiota_abstractions microsoft_kiota_http: git: - url: https://github.com/kiota-community/dart_kiota.git + url: https://github.com/microsoft/kiota-dart.git ref: main path: packages/microsoft_kiota_http microsoft_kiota_serialization_form: git: - url: https://github.com/kiota-community/dart_kiota.git + url: https://github.com/microsoft/kiota-dart.git ref: main path: packages/microsoft_kiota_serialization_form microsoft_kiota_serialization_text: git: - url: https://github.com/kiota-community/dart_kiota.git + url: https://github.com/microsoft/kiota-dart.git ref: main path: packages/microsoft_kiota_serialization_text microsoft_kiota_serialization_json: git: - url: https://github.com/kiota-community/dart_kiota.git + url: https://github.com/microsoft/kiota-dart.git ref: main path: packages/microsoft_kiota_serialization_json microsoft_kiota_serialization_multipart: git: - url: https://github.com/kiota-community/dart_kiota.git + url: https://github.com/microsoft/kiota-dart.git ref: main path: packages/microsoft_kiota_serialization_multipart http: ^1.2.2 uuid: ^4.5.1 dev_dependencies: - lints: ^3.0.0 - test: ^1.25.2 + lints: ^5.1.1 + test: ^1.25.14 From 90d40ce6ce71d04bb7b22a9ba6defb1bb9eaa190 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 22:46:27 +0100 Subject: [PATCH 186/194] Updated documentation; descriptionUrl is now also required --- it/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/it/Readme.md b/it/Readme.md index aac690c34d..262e5b88c0 100644 --- a/it/Readme.md +++ b/it/Readme.md @@ -17,5 +17,5 @@ Generate the code: And finally run the test: ```bash -./it/exec-cmd.ps1 -language ${LANG} +./it/exec-cmd.ps1 -descriptionUrl ${FILE/URL} -language ${LANG} ``` From 1862d62a7b2ac4fddd17da64c16e76fbf56e4d01 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 22:47:23 +0100 Subject: [PATCH 187/194] Need to use hosted versions as their transitive dependencies would prevent version resolution --- it/dart/pubspec.yaml | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/it/dart/pubspec.yaml b/it/dart/pubspec.yaml index ba6e51a350..8becd341e7 100644 --- a/it/dart/pubspec.yaml +++ b/it/dart/pubspec.yaml @@ -8,36 +8,12 @@ environment: # Add regular dependencies here. dependencies: - microsoft_kiota_abstractions: - git: - url: https://github.com/microsoft/kiota-dart.git - ref: main - path: packages/microsoft_kiota_abstractions - microsoft_kiota_http: - git: - url: https://github.com/microsoft/kiota-dart.git - ref: main - path: packages/microsoft_kiota_http - microsoft_kiota_serialization_form: - git: - url: https://github.com/microsoft/kiota-dart.git - ref: main - path: packages/microsoft_kiota_serialization_form - microsoft_kiota_serialization_text: - git: - url: https://github.com/microsoft/kiota-dart.git - ref: main - path: packages/microsoft_kiota_serialization_text - microsoft_kiota_serialization_json: - git: - url: https://github.com/microsoft/kiota-dart.git - ref: main - path: packages/microsoft_kiota_serialization_json - microsoft_kiota_serialization_multipart: - git: - url: https://github.com/microsoft/kiota-dart.git - ref: main - path: packages/microsoft_kiota_serialization_multipart + microsoft_kiota_abstractions: ^0.0.1 + microsoft_kiota_http: ^0.0.1 + microsoft_kiota_serialization_form: ^0.0.1 + microsoft_kiota_serialization_text: ^0.0.1 + microsoft_kiota_serialization_json: ^0.0.1 + microsoft_kiota_serialization_multipart: ^0.0.1 http: ^1.2.2 uuid: ^4.5.1 From 17e9922cb49c6ccc8d92ca06b2c762a35f013e3e Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 22:47:38 +0100 Subject: [PATCH 188/194] Use `lib` instead of `src` as is custom for Dart --- it/dart/{basic => }/test/api_client_test.dart | 4 ++-- it/exec-cmd.ps1 | 6 +++--- it/get-additional-arguments.ps1 | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename it/dart/{basic => }/test/api_client_test.dart (92%) diff --git a/it/dart/basic/test/api_client_test.dart b/it/dart/test/api_client_test.dart similarity index 92% rename from it/dart/basic/test/api_client_test.dart rename to it/dart/test/api_client_test.dart index 03b737137b..6bc18fd191 100644 --- a/it/dart/basic/test/api_client_test.dart +++ b/it/dart/test/api_client_test.dart @@ -1,8 +1,8 @@ import 'package:microsoft_kiota_abstractions/microsoft_kiota_abstractions.dart'; import 'package:microsoft_kiota_http/microsoft_kiota_http.dart'; import 'package:test/test.dart'; -import '../src/api_client.dart'; -import '../src/models/error.dart'; +import '../lib/api_client.dart'; +import '../lib/models/error.dart'; void main() { group('apiclient', () { diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index f7d9b759d0..be9e149da7 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -206,8 +206,8 @@ elseif ($language -eq "dart") { if ($mockServerTest) { Push-Location $itTestPath - $itTestPathSources = Join-Path -Path $testPath -ChildPath "src" - $itTestPathDest = Join-Path -Path $itTestPath -ChildPath "src" + $itTestPathSources = Join-Path -Path $testPath -ChildPath "lib" + $itTestPathDest = Join-Path -Path $itTestPath -ChildPath "lib" if (Test-Path $itTestPathDest) { Remove-Item $itTestPathDest -Force -Recurse } @@ -222,7 +222,7 @@ elseif ($language -eq "dart") { else { Invoke-Call -ScriptBlock { dart pub get - dart analyze src/ + dart analyze lib/ } -ErrorAction Stop } } diff --git a/it/get-additional-arguments.ps1 b/it/get-additional-arguments.ps1 index 7e6e843444..e96e3c4a0c 100755 --- a/it/get-additional-arguments.ps1 +++ b/it/get-additional-arguments.ps1 @@ -24,7 +24,7 @@ elseif ($language -eq "java") { $command = " --output `"./it/$language/src/apisdk`"" } elseif ($language -eq "dart") { - $command = " --output `"./it/$language/src`"" + $command = " --output `"./it/$language/lib`"" } elseif ($language -eq "go") { $command = " --output `"./it/$language/client`" --namespace-name `"integrationtest/client`"" From 39406cd09d253c43b4fe101a8f6db40ac3e491f4 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 22:59:31 +0100 Subject: [PATCH 189/194] Restore test structure for basic tests --- it/dart/{ => basic}/test/api_client_test.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename it/dart/{ => basic}/test/api_client_test.dart (100%) diff --git a/it/dart/test/api_client_test.dart b/it/dart/basic/test/api_client_test.dart similarity index 100% rename from it/dart/test/api_client_test.dart rename to it/dart/basic/test/api_client_test.dart From 5bdf99eabdbcae4078c018c1f5b3151b41718df6 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Wed, 8 Jan 2025 13:40:19 +0100 Subject: [PATCH 190/194] Always use the latest stable version of Dart SDK --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 7435d74ca7..7e0ef9ffff 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -114,7 +114,7 @@ jobs: if: matrix.language == 'dart' uses: dart-lang/setup-dart@v1 with: - sdk: "3.6" + sdk: "stable" - name: Check if test is suppressed id: check-suppressed From 4f6468916ac31213f012b9394eb219385af4f022 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Wed, 8 Jan 2025 13:42:18 +0100 Subject: [PATCH 191/194] Always run analyze for Dart --- it/exec-cmd.ps1 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index be9e149da7..0bd7595493 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -203,6 +203,11 @@ elseif ($language -eq "python") { } } elseif ($language -eq "dart") { + Invoke-Call -ScriptBlock { + dart pub get + dart analyze lib/ + } -ErrorAction Stop + if ($mockServerTest) { Push-Location $itTestPath @@ -219,12 +224,6 @@ elseif ($language -eq "dart") { Pop-Location } - else { - Invoke-Call -ScriptBlock { - dart pub get - dart analyze lib/ - } -ErrorAction Stop - } } Pop-Location From 8e8102021bbd145b5582b5624d7fd0c41cd50d1e Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Tue, 7 Jan 2025 16:26:09 +0100 Subject: [PATCH 192/194] Fix request build using wrong path parameter name The name used for the URL template needs to match the serialized name of the custom parameter. --- src/Kiota.Builder/Writers/Dart/DartConventionService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 678dd4e1f0..552c9cc5fd 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -131,7 +131,7 @@ internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, La urlTplRef = TempDictionaryVarName; writer.WriteLine($"var {urlTplRef} = Map.of({pathParametersProp.Name.ToFirstCharacterLowerCase()});"); foreach (var param in customParameters) - writer.WriteLine($"{urlTplRef}.putIfAbsent('{param.Name.ToFirstCharacterLowerCase()}', ()=> {param.Name.ToFirstCharacterLowerCase()});"); + writer.WriteLine($"{urlTplRef}.putIfAbsent('{param.SerializationName}', () => {param.Name.ToFirstCharacterLowerCase()});"); } writer.WriteLine($"{prefix}{returnType}({urlTplRef}, {requestAdapterProp.Name.ToFirstCharacterLowerCase()}{pathParametersSuffix});"); } From 98e79193ccc99f95004ee674b091cc88f195b4d4 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Wed, 8 Jan 2025 13:50:24 +0100 Subject: [PATCH 193/194] Apply suggestions from code review --- .../Dart/CodeClassDeclarationWriter.cs | 4 ++-- .../Writers/Dart/CodeMethodWriter.cs | 22 ++++------------- .../Writers/Dart/DartConventionService.cs | 24 +++---------------- 3 files changed, 10 insertions(+), 40 deletions(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs index e7c6ffc911..0499688ac6 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeClassDeclarationWriter.cs @@ -40,7 +40,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit (string.Empty, x.Alias, x.Declaration.Name) : relativeImportManager.GetRelativeImportPathForUsing(x, currentNamespace)) .OrderBy(static x => x.Item3, StringComparer.Ordinal)) - writer.WriteLine($"import '{relativePath.Item3}.dart'{getAlias(relativePath.Item2)};"); + writer.WriteLine($"import '{relativePath.Item3}.dart'{GetAlias(relativePath.Item2)};"); writer.WriteLine(); @@ -56,7 +56,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit writer.StartBlock($"class {codeElement.Name}{derivation}{implements} {{"); } - private String getAlias(string alias) + private static String GetAlias(string alias) { return string.IsNullOrEmpty(alias) ? string.Empty : $" as {alias}"; } diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 92fea9e12a..3731f4b1ca 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -62,9 +62,9 @@ private static bool HasEmptyConstructorBody(CodeMethod codeElement, CodeClass pa { if (parentClass.IsOfKind(CodeClassKind.Model) && codeElement.IsOfKind(CodeMethodKind.Constructor) && !parentClass.IsErrorDefinition) { - return !parentClass.Properties.Where(prop => !string.IsNullOrEmpty(prop.DefaultValue)).Any(); + return parentClass.Properties.All(prop => string.IsNullOrEmpty(prop.DefaultValue)); } - var hasBody = codeElement.Parameters.Where(p => !p.IsOfKind(CodeParameterKind.RequestAdapter) && !p.IsOfKind(CodeParameterKind.PathParameters)).Any(); + var hasBody = codeElement.Parameters.Any(p => !p.IsOfKind(CodeParameterKind.RequestAdapter) && !p.IsOfKind(CodeParameterKind.PathParameters)); return isConstructor && parentClass.IsOfKind(CodeClassKind.RequestBuilder) && !codeElement.IsOfKind(CodeMethodKind.ClientConstructor) && (!hasBody || codeElement.IsOfKind(CodeMethodKind.RawUrlConstructor)); } @@ -120,13 +120,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w case CodeMethodKind.ErrorMessageOverride: throw new InvalidOperationException("ErrorMessageOverride is not supported as the error message is implemented by a property."); case CodeMethodKind.CommandBuilder: - var origParams = codeElement.OriginalMethod?.Parameters ?? codeElement.Parameters; - requestBodyParam = origParams.OfKind(CodeParameterKind.RequestBody); - requestConfig = origParams.OfKind(CodeParameterKind.RequestConfiguration); - requestContentType = origParams.OfKind(CodeParameterKind.RequestBodyContentType); - requestParams = new RequestParams(requestBodyParam, requestConfig, requestContentType); - WriteCommandBuilderBody(codeElement, parentClass, requestParams, isVoid, returnType, writer); - break; + throw new InvalidOperationException("CommandBuilder methods are not implemented in this SDK. They're currently only supported in the shell language."); case CodeMethodKind.Factory: WriteFactoryMethodBody(codeElement, parentClass, writer); break; @@ -206,7 +200,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, { if (property.Type is CodeType propertyType) { - var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + conventions.GetTypeString(propertyType, codeElement, true, false); var check = propertyType.IsCollection ? ".isNotEmpty" : " != null"; writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); writer.WriteLine($"{ResultVarName}.{property.Name} = {parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)};"); @@ -370,7 +364,6 @@ private void WriteErrorClassConstructor(CodeClass parentClass, LanguageWriter wr } } - private string DefaultDeserializerReturnType => $"Map"; private string DefaultDeserializerReturnInstance => $""; private void WriteDeserializerBody(bool shouldHide, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { @@ -635,11 +628,6 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas } } - protected virtual void WriteCommandBuilderBody(CodeMethod codeElement, CodeClass parentClass, RequestParams requestParams, bool isVoid, string returnType, LanguageWriter writer) - { - throw new InvalidOperationException("CommandBuilder methods are not implemented in this SDK. They're currently only supported in the shell language."); - } - protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElement, CodeTypeBase returnType) { ArgumentNullException.ThrowIfNull(returnType); @@ -706,7 +694,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua { writer.WriteLine("@override"); } - var genericTypePrefix = isVoid ? string.Empty : "<"; + var genericTypeSuffix = code.IsAsync && !isVoid ? ">" : string.Empty; var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); var voidCorrectedTaskReturnType = code.IsAsync && isVoid ? "void" : returnType; diff --git a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs index 552c9cc5fd..13434eb98b 100644 --- a/src/Kiota.Builder/Writers/Dart/DartConventionService.cs +++ b/src/Kiota.Builder/Writers/Dart/DartConventionService.cs @@ -167,15 +167,7 @@ private static bool ShouldTypeHaveNullableMarker(CodeTypeBase propType, string p { return propType.IsNullable && (NullableTypes.Contains(propTypeName) || (propType is CodeType codeType && codeType.TypeDefinition is CodeEnum)); } - private static IEnumerable GetAllNamespaces(CodeNamespace ns) - { - foreach (var childNs in ns.Namespaces) - { - yield return childNs; - foreach (var childNsSegment in GetAllNamespaces(childNs)) - yield return childNsSegment; - } - } + public override string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool includeCollectionInformation = true, LanguageWriter? writer = null) { return GetTypeString(code, targetElement, includeCollectionInformation, true); @@ -187,7 +179,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool i throw new InvalidOperationException($"Dart does not support union types, the union type {code.Name} should have been filtered out by the refiner"); if (code is CodeType currentType) { - var typeName = TranslateTypeAndAvoidUsingNamespaceSegmentNames(currentType, targetElement); + var typeName = TranslateTypeAndAvoidUsingNamespaceSegmentNames(currentType); var alias = GetTypeAlias(currentType, targetElement); if (!string.IsNullOrEmpty(alias)) { @@ -225,18 +217,8 @@ private static string GetTypeAlias(CodeType targetType, CodeElement targetElemen return aliasedUsing.Alias; return string.Empty; } - private string TranslateTypeAndAvoidUsingNamespaceSegmentNames(CodeType currentType, CodeElement targetElement) - { - var parentElementsHash = targetElement.Parent is CodeClass parentClass ? - parentClass.Methods.Select(static x => x.Name) - .Union(parentClass.Properties.Select(static x => x.Name)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToHashSet(StringComparer.OrdinalIgnoreCase) : - new HashSet(0, StringComparer.OrdinalIgnoreCase); - var typeName = TranslateType(currentType); - return typeName; - } + private string TranslateTypeAndAvoidUsingNamespaceSegmentNames(CodeType currentType) => TranslateType(currentType); public override string TranslateType(CodeType type) { From fc6cb763e825c82655c971cf7212b17c79075c21 Mon Sep 17 00:00:00 2001 From: Ricardo Boss Date: Wed, 8 Jan 2025 14:29:10 +0100 Subject: [PATCH 194/194] Removed method call with no side-effects --- src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs index 3731f4b1ca..83ff8ccbb3 100644 --- a/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodeMethodWriter.cs @@ -200,7 +200,6 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, { if (property.Type is CodeType propertyType) { - conventions.GetTypeString(propertyType, codeElement, true, false); var check = propertyType.IsCollection ? ".isNotEmpty" : " != null"; writer.StartBlock($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)}{check}) {{"); writer.WriteLine($"{ResultVarName}.{property.Name} = {parseNodeParameter.Name}.{GetDeserializationMethodName(propertyType, codeElement)};");