diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 70eb569548..eb4c0b9680 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -41,14 +41,15 @@ "kosunix.guid", "wix.vscode-import-cost", "ms-vsliveshare.vsliveshare", - "eg2.vscode-npm-script", "fknop.vscode-npm", "ms-vscode.powershell", - "rebornix.ruby", + "Shopify.ruby-lsp", "visualstudioexptteam.vscodeintellicode", "streetsidesoftware.code-spell-checker", - "sswg.swift-lang", - "ms-dotnettools.blazorwasm-companion" + "swiftlang.swift-vscode", + "ms-dotnettools.blazorwasm-companion", + "ms-dotnettools.csdevkit", + "github.vscode-github-actions" ] } }, diff --git a/CHANGELOG.md b/CHANGELOG.md index fe3d0ebe85..1f296e00a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added support for OpenAPI 3.2.0 +- golang: indent with tabs instead of spaces +- golang: if there is only one return argument, omit the parentheses +- golang: remove trailing spaces on comments +- golang: fix import ordering +- golang: correctly indent case statements inside a switch ### Changed @@ -59,7 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue where migration from lock to workspace would fail because of stream management. [#6515](https://github.com/microsoft/kiota/issues/6515) - Fixed a bug where media types from error responses would be missing from the accept header. [#6572](https://github.com/microsoft/kiota/issues/6572) - Fixed a bug where serialization names for Dart were not correct [#6624](https://github.com/microsoft/kiota/issues/6624) -- Fixed a bug where imports from __future__ would appear below other imports in python generated code. [#4600](https://github.com/microsoft/kiota/issues/4600) +- Fixed a bug where imports from **future** would appear below other imports in python generated code. [#4600](https://github.com/microsoft/kiota/issues/4600) ## [1.26.1] - 2025-05-15 @@ -201,7 +206,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed Python error when a class inherits from a base class and implements an interface. [#5637](https://github.com/microsoft/kiota/issues/5637) - Fixed a bug where one/any schemas with single schema entries would be missing properties. [#5808](https://github.com/microsoft/kiota/issues/5808) - Fixed anyOf/oneOf generation in TypeScript. [5353](https://github.com/microsoft/kiota/issues/5353) -- Fixed invalid code in Php caused by "*/*/" in property description. [5635](https://github.com/microsoft/kiota/issues/5635) +- Fixed invalid code in Php caused by `"*/*/"` in property description. [5635](https://github.com/microsoft/kiota/issues/5635) - Fixed a bug where discriminator property name lookup could end up in an infinite loop. [#5771](https://github.com/microsoft/kiota/issues/5771) - Fixed TypeScript generation error when generating usings from shaken serializers. [#5634](https://github.com/microsoft/kiota/issues/5634) - Multiple fixed and improvements in OpenAPI description generation for plugins. [#5806](https://github.com/microsoft/kiota/issues/5806) @@ -342,7 +347,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added uri-form encoded serialization for PHP. [#2074](https://github.com/microsoft/kiota/issues/2074) - Added information message with base URL in the CLI experience. [#4635](https://github.com/microsoft/kiota/issues/4635) - Added optional parameter --disable-ssl-validation for generate, show, and download commands. [#4176](https://github.com/microsoft/kiota/issues/4176) -- For *Debug* builds of kiota, the `--log-level` / `--ll` option is now observed if specified explicitly on the command line. It still defaults to `Debug` for *Debug* builds and `Warning` for *Release* builds. [#4739](https://github.com/microsoft/kiota/pull/4739) +- For _Debug_ builds of kiota, the `--log-level` / `--ll` option is now observed if specified explicitly on the command line. It still defaults to `Debug` for _Debug_ builds and `Warning` for _Release_ builds. [#4739](https://github.com/microsoft/kiota/pull/4739) ### Changed @@ -944,7 +949,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed unused generated import for PHP Generation. - Fixed a bug where long namespaces would make Ruby packaging fail. - Fixed a bug where classes with namespace names are generated outside namespace in Python. [#2188](https://github.com/microsoft/kiota/issues/2188) -- Changed signature of escaped reserved names from {x}*escaped to {x}* in line with Python style guides. +- Changed signature of escaped reserved names from `{x}*escaped` to `{x}*` in line with Python style guides. - Add null checks in generated Shell language code. - Fixed a bug where Go indexers would fail to pass the index parameter. - Fixed a bug where path segments with parameters could be missing words. [#2209](https://github.com/microsoft/kiota/issues/2209) diff --git a/it/exec-cmd.ps1 b/it/exec-cmd.ps1 index 0bd7595493..40dd1ea388 100755 --- a/it/exec-cmd.ps1 +++ b/it/exec-cmd.ps1 @@ -146,6 +146,14 @@ elseif ($language -eq "go") { go test } -ErrorAction Stop + Invoke-Call -ScriptBlock { + $fmtStdOut = go fmt ./... 2>&1 + if ($fmtStdOut) { + Write-Host "go fmt produced output, so the generated code is not correctly formatted by kiota:`n$fmtStdOut" + exit 1 + } + } -ErrorAction Stop + Pop-Location } else { diff --git a/it/go/app.go b/it/go/app.go index 2f6a363bd3..9df30ce9e7 100644 --- a/it/go/app.go +++ b/it/go/app.go @@ -1,12 +1,12 @@ package integrationtest import ( - c "integrationtest/client" + "context" + "fmt" azidentity "github.com/Azure/azure-sdk-for-go/sdk/azidentity" a "github.com/microsoft/kiota-authentication-azure-go" r "github.com/microsoft/kiota-http-go" - "fmt" - "context" + c "integrationtest/client" ) func main() { @@ -33,4 +33,4 @@ func main() { } client := c.NewApiClient(adapter) fmt.Printf("Message: %v\n", client) -} \ No newline at end of file +} diff --git a/src/Kiota.Builder/Refiners/GoRefiner.cs b/src/Kiota.Builder/Refiners/GoRefiner.cs index b7c2e93589..83f9e34d11 100644 --- a/src/Kiota.Builder/Refiners/GoRefiner.cs +++ b/src/Kiota.Builder/Refiners/GoRefiner.cs @@ -847,7 +847,7 @@ private static void CorrectMethodType(CodeMethod currentMethod) currentMethod.Parameters.Where(static x => x.Type.Name.Equals("ISerializationWriter", StringComparison.Ordinal)).ToList().ForEach(x => x.Type.Name = "SerializationWriter"); else if (currentMethod.IsOfKind(CodeMethodKind.Deserializer)) { - currentMethod.ReturnType.Name = $"map[string]func({conventions.SerializationHash}.ParseNode)(error)"; + currentMethod.ReturnType.Name = $"map[string]func({conventions.SerializationHash}.ParseNode) error"; currentMethod.Name = "getFieldDeserializers"; } else if (currentMethod.IsOfKind(CodeMethodKind.ClientConstructor, CodeMethodKind.Constructor, CodeMethodKind.RawUrlConstructor)) diff --git a/src/Kiota.Builder/Writers/Go/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Go/CodeClassDeclarationWriter.cs index 6e7c26b7f9..1721613252 100644 --- a/src/Kiota.Builder/Writers/Go/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeClassDeclarationWriter.cs @@ -22,7 +22,7 @@ protected override void WriteTypeDeclaration(ClassDeclaration codeElement, Langu if (codeElement.Inherits?.AllTypes?.Any() ?? false) { var parentTypeName = conventions.GetTypeString(codeElement.Inherits.AllTypes.First(), currentClass, true, false); - writer.WriteLine($"{parentTypeName}"); + writer.WriteLine(parentTypeName); } } } diff --git a/src/Kiota.Builder/Writers/Go/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Go/CodeEnumWriter.cs index c678b7e450..ddf375c423 100644 --- a/src/Kiota.Builder/Writers/Go/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeEnumWriter.cs @@ -21,12 +21,11 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"package {ns.Name.GetLastNamespaceSegment().Replace("-", string.Empty, StringComparison.OrdinalIgnoreCase)}"); } - var usings = codeElement.Usings.OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase).ToArray(); - if (usings.Length > 0) + var usings = codeElement.Usings.Select(static x => x.Name).Order(StringComparer.OrdinalIgnoreCase).ToList(); + if (usings.Count > 0) { writer.StartBlock("import ("); - foreach (var cUsing in usings) - writer.WriteLine($"\"{cUsing.Name}\""); + usings.ForEach(x => writer.WriteLine($"\"{x}\"")); writer.CloseBlock(")"); } @@ -44,7 +43,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write foreach (var item in enumOptions) { if (item.Documentation.DescriptionAvailable) - writer.WriteLine($"// {item.Documentation.DescriptionTemplate}"); + conventions.WriteDescriptionItem(item.Documentation.DescriptionTemplate, writer); if (isMultiValue) writer.WriteLine($"{item.Name.ToUpperInvariant()}_{typeName.ToUpperInvariant()} = {(int)Math.Pow(2, power)}"); @@ -78,7 +77,7 @@ private static void WriteStringFunction(CodeEnum codeElement, LanguageWriter wri writer.StartBlock($"for p := 0; p < {enumOptions.Count}; p++ {{"); writer.WriteLine($"mantis := {typeName}(int(math.Pow(2, float64(p))))"); writer.StartBlock($"if i&mantis == mantis {{"); - writer.WriteLine($"values = append(values, options[p])"); + writer.WriteLine("values = append(values, options[p])"); writer.CloseBlock(); writer.CloseBlock(); writer.WriteLine("return strings.Join(values, \",\")"); @@ -107,31 +106,37 @@ private static void WriteParsableEnum(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"var result {typeName}"); writer.WriteLine("values := strings.Split(v, \",\")"); writer.StartBlock("for _, str := range values {"); - writer.StartBlock("switch str {"); + writer.WriteLine("switch str {"); foreach (var item in enumOptions) { - writer.StartBlock($"case \"{item.WireName}\":"); + writer.WriteLine($"case \"{item.WireName}\":"); + writer.IncreaseIndent(); writer.WriteLine($"result |= {item.Name.ToUpperInvariant()}_{typeName.ToUpperInvariant()}"); writer.DecreaseIndent(); } + writer.WriteLine("default:"); + writer.IncreaseIndent(); + writer.WriteLine("return nil, nil"); + writer.DecreaseIndent(); + writer.WriteLine("}"); // close the switch statement + writer.CloseBlock(); // close the for loop } else { writer.WriteLine($"result := {enumOptions[0].Name.ToUpperInvariant()}_{typeName.ToUpperInvariant()}"); - writer.StartBlock("switch v {"); + writer.WriteLine("switch v {"); foreach (var item in enumOptions) { - writer.StartBlock($"case \"{item.WireName}\":"); + writer.WriteLine($"case \"{item.WireName}\":"); + writer.IncreaseIndent(); writer.WriteLine($"result = {item.Name.ToUpperInvariant()}_{typeName.ToUpperInvariant()}"); writer.DecreaseIndent(); } + writer.StartBlock("default:"); + writer.WriteLine("return nil, nil"); + writer.DecreaseIndent(); + writer.WriteLine("}"); } - - writer.StartBlock("default:"); - writer.WriteLine($"return nil, nil"); - writer.DecreaseIndent(); - writer.CloseBlock(); - if (isMultiValue) writer.CloseBlock(); writer.WriteLine("return &result, nil"); writer.CloseBlock(); } diff --git a/src/Kiota.Builder/Writers/Go/CodeFileDeclarationWriter.cs b/src/Kiota.Builder/Writers/Go/CodeFileDeclarationWriter.cs index dadac0950e..dc55e0e83d 100644 --- a/src/Kiota.Builder/Writers/Go/CodeFileDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeFileDeclarationWriter.cs @@ -32,14 +32,13 @@ public override void WriteCodeElement(CodeFileDeclaration codeElement, LanguageW .Where(static x => x.Declaration != null && x.Declaration.IsExternal) .Select(static x => new Tuple(x.Name.StartsWith('*') ? x.Name[1..] : x.Declaration!.Name.GetNamespaceImportSymbol(), x.Declaration!.Name)) .Distinct()) - .OrderBy(static x => x.Item2.Count(static y => y == '/')) - .ThenBy(static x => x) + .OrderBy(static x => x.Item2) // Item1: import alias, Item2: import path .ToList(); if (importSegments.Count != 0) { writer.WriteLines(string.Empty, "import ("); writer.IncreaseIndent(); - importSegments.ForEach(x => writer.WriteLine(x.Item1.Equals(x.Item2, StringComparison.Ordinal) ? $"\"{x.Item2}\"" : $"{x.Item1} \"{x.Item2}\"")); + importSegments.ForEach(x => writer.WriteLine(string.IsNullOrEmpty(x.Item1) ? $"\"{x.Item2}\"" : $"{x.Item1} \"{x.Item2}\"")); writer.DecreaseIndent(); writer.WriteLines(")", string.Empty); } diff --git a/src/Kiota.Builder/Writers/Go/CodeInterfaceDeclarationWriter.cs b/src/Kiota.Builder/Writers/Go/CodeInterfaceDeclarationWriter.cs index 7bb0f7b09f..cbdc83190c 100644 --- a/src/Kiota.Builder/Writers/Go/CodeInterfaceDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeInterfaceDeclarationWriter.cs @@ -22,7 +22,7 @@ protected override void WriteTypeDeclaration(InterfaceDeclaration codeElement, L foreach (var implement in codeElement.Implements) { var parentTypeName = conventions.GetTypeString(implement, inter, true, false); - writer.WriteLine($"{parentTypeName}"); + writer.WriteLine(parentTypeName); } } } diff --git a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs index 479f7e01a3..e67b590a6d 100644 --- a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs @@ -93,6 +93,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri break; } writer.CloseBlock(); + writer.WriteLine(); // empty line after each func } private static void WriteErrorMethodOverride(CodeClass parentClass, LanguageWriter writer) { @@ -109,7 +110,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()}, m.BaseRequestBuilder.{requestAdapterProperty.Name.ToFirstCharacterUpperCase()});"); + writer.WriteLine($"return New{parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, m.BaseRequestBuilder.{requestAdapterProperty.Name.ToFirstCharacterUpperCase()})"); } private void WriteComposedTypeMarkerBody(LanguageWriter writer) { @@ -163,7 +164,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas } private void WriteFactoryMethodBodyForInheritedModel(CodeClass parentClass, LanguageWriter writer) { - writer.StartBlock($"switch *{DiscriminatorMappingVarName} {{"); + writer.WriteLine($"switch *{DiscriminatorMappingVarName} {{"); foreach (var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings) { writer.WriteLine($"case \"{mappedType.Key}\":"); @@ -171,7 +172,7 @@ private void WriteFactoryMethodBodyForInheritedModel(CodeClass parentClass, Lang writer.WriteLine($"return {conventions.GetImportedStaticMethodName(mappedType.Value, parentClass)}(), nil"); writer.DecreaseIndent(); } - writer.CloseBlock(); + writer.WriteLine("}"); } private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, CodeClass parentClass, CodeParameter parseNodeParameter, LanguageWriter writer) { @@ -438,9 +439,6 @@ private void WriteSerializerBodyForIntersectionModel(CodeClass parentClass, Lang private void WriteMethodPrototype(CodeMethod code, CodeElement parentBlock, LanguageWriter writer, string returnType, bool writePrototypeOnly) { - var returnTypeAsyncSuffix = code.IsAsync ? "error" : string.Empty; - if (!string.IsNullOrEmpty(returnType) && code.IsAsync) - returnTypeAsyncSuffix = $", {returnTypeAsyncSuffix}"; var isConstructor = code.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor, CodeMethodKind.RawUrlConstructor); var methodName = code.Kind switch { @@ -455,7 +453,7 @@ private void WriteMethodPrototype(CodeMethod code, CodeElement parentBlock, Lang var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, ParameterOrderComparer).Select(p => conventions.GetParameterSignature(p, parentBlock)).ToList()); var classType = conventions.GetTypeString(new CodeType { Name = parentBlock.Name, TypeDefinition = parentBlock }, parentBlock); var associatedTypePrefix = isConstructor || code.IsStatic || writePrototypeOnly ? string.Empty : $"(m {classType}) "; - var finalReturnType = isConstructor ? classType : $"{returnType}{returnTypeAsyncSuffix}"; + var finalReturnType = isConstructor ? classType : returnType; var errorDeclaration = code.IsOfKind(CodeMethodKind.ClientConstructor, CodeMethodKind.Constructor, CodeMethodKind.Getter, @@ -470,11 +468,28 @@ private void WriteMethodPrototype(CodeMethod code, CodeElement parentBlock, Lang CodeMethodKind.ErrorMessageOverride) || code.IsAsync ? string.Empty : "error"; - if (!string.IsNullOrEmpty(finalReturnType) && !string.IsNullOrEmpty(errorDeclaration)) - finalReturnType += ", "; - var openingBracket = writePrototypeOnly ? string.Empty : " {"; var funcPrefix = writePrototypeOnly ? string.Empty : "func "; - writer.WriteLine($"{funcPrefix}{associatedTypePrefix}{methodName}({parameters})({finalReturnType}{errorDeclaration}){openingBracket}"); + var returnTypeString = (code, finalReturnType, errorDeclaration) switch + { + _ when code.IsAsync && !string.IsNullOrEmpty(finalReturnType) => $"({finalReturnType}, error)", + _ when !string.IsNullOrEmpty(finalReturnType) && !string.IsNullOrEmpty(errorDeclaration) => $"({finalReturnType}, {errorDeclaration})", + _ when string.IsNullOrEmpty(finalReturnType) && !string.IsNullOrEmpty(errorDeclaration) => errorDeclaration, + _ when !string.IsNullOrEmpty(finalReturnType) && string.IsNullOrEmpty(errorDeclaration) => finalReturnType, + _ => string.Empty + }; + var openingBracket = (writePrototypeOnly, returnTypeString) switch + { + _ when writePrototypeOnly => string.Empty, + _ when string.IsNullOrEmpty(returnTypeString) => "{", // no leading space in this case + _ => " {", + }; + var firstPart = $"{funcPrefix}{associatedTypePrefix}{methodName}({parameters})"; + var finalString = (returnTypeString, openingBracket) switch + { + _ when string.IsNullOrEmpty(returnTypeString) && string.IsNullOrEmpty(openingBracket) => firstPart, + _ => $"{firstPart} {returnTypeString}{openingBracket}" + }; + writer.WriteLine(finalString); } private void WriteGetterBody(CodeMethod codeElement, LanguageWriter writer, CodeClass parentClass) { @@ -491,8 +506,8 @@ private void WriteGetterBody(CodeMethod codeElement, LanguageWriter writer, Code $"val , err := m.{backingStore.NamePrefix}{backingStore.Name.ToFirstCharacterLowerCase()}.Get(\"{codeElement.AccessedProperty.Name.ToFirstCharacterLowerCase()}\")"); writer.WriteBlock("if err != nil {", "}", "panic(err)"); writer.WriteBlock("if val == nil {", "}", - $"var value = {codeElement.AccessedProperty.DefaultValue};", - $"m.Set{codeElement.AccessedProperty.Name?.ToFirstCharacterUpperCase()}(value);"); + $"var value = {codeElement.AccessedProperty.DefaultValue}", + $"m.Set{codeElement.AccessedProperty.Name?.ToFirstCharacterUpperCase()}(value)"); writer.WriteLine($"return val.({conventions.GetTypeString(codeElement.AccessedProperty.Type, parentClass)})"); } @@ -524,7 +539,7 @@ private void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, L writer.WriteLine($"m.{BaseRequestBuilderVarName}.{pathParametersProperty.Name.ToFirstCharacterUpperCase()}[\"baseurl\"] = m.{requestAdapterPropertyName}.GetBaseUrl()"); } if (backingStoreParameter != null) - writer.WriteLine($"m.{requestAdapterPropertyName}.EnableBackingStore({backingStoreParameter.Name});"); + writer.WriteLine($"m.{requestAdapterPropertyName}.EnableBackingStore({backingStoreParameter.Name})"); } private void WriteSerializationRegistration(HashSet serializationModules, LanguageWriter writer, CodeClass parentClass, string methodName, string interfaceName) { @@ -535,14 +550,18 @@ private void WriteSerializationRegistration(HashSet serializationModules { var moduleImportSymbol = conventions.GetTypeString(new CodeType { Name = module, IsExternal = true }, parentClass, false, false); moduleImportSymbol = moduleImportSymbol.Split('.').First(); - writer.WriteLine($"{methodImportSymbol}(func() {interfaceImportSymbol} {{ return {moduleImportSymbol}.New{module}() }})"); + writer.WriteLine($"{methodImportSymbol}(func() {interfaceImportSymbol} {{"); + writer.IncreaseIndent(); + writer.WriteLine($"return {moduleImportSymbol}.New{module}()"); + writer.DecreaseIndent(); + writer.WriteLine("})"); } } private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer, bool inherits) { - writer.WriteLine($"m := &{parentClass.Name.ToFirstCharacterUpperCase()}{{"); if (inherits || parentClass.IsErrorDefinition) { + writer.WriteLine($"m := &{parentClass.Name.ToFirstCharacterUpperCase()}{{"); writer.IncreaseIndent(); var parentClassName = parentClass.StartBlock.Inherits!.Name.ToFirstCharacterUpperCase(); var newMethodName = conventions.GetImportedStaticMethodName(parentClass.StartBlock.Inherits, parentClass); @@ -558,14 +577,18 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho else writer.WriteLine($"{parentClassName}: *{newMethodName}(),"); writer.DecreaseIndent(); + writer.CloseBlock(decreaseIndent: false); + } + else + { + writer.WriteLine($"m := &{parentClass.Name.ToFirstCharacterUpperCase()}{{}}"); } - writer.CloseBlock(decreaseIndent: false); foreach (var propWithDefault in parentClass.GetPropertiesOfKind(CodePropertyKind.BackingStore, CodePropertyKind.RequestBuilder) .Where(static x => !string.IsNullOrEmpty(x.DefaultValue)) .OrderBy(static x => x.Name)) { - writer.WriteLine($"m.{propWithDefault.NamePrefix}{propWithDefault.Name.ToFirstCharacterLowerCase()} = {propWithDefault.DefaultValue};"); + writer.WriteLine($"m.{propWithDefault.NamePrefix}{propWithDefault.Name.ToFirstCharacterLowerCase()} = {propWithDefault.DefaultValue}"); } foreach (var propWithDefault in parentClass.GetPropertiesOfKind(CodePropertyKind.AdditionalData, CodePropertyKind.Custom) //additional data and custom rely on accessors .Where(static x => !string.IsNullOrEmpty(x.DefaultValue)) @@ -710,7 +733,7 @@ private void WriteDeserializerBodyForInheritedModel(CodeMethod codeElement, Code private void WriteFieldDeserializer(CodeProperty property, LanguageWriter writer, CodeClass parentClass, string parsableImportSymbol) { if (property.Setter is null) return; - writer.StartBlock($"res[\"{property.WireName}\"] = func (n {parsableImportSymbol}) error {{"); + writer.StartBlock($"res[\"{property.WireName}\"] = func(n {parsableImportSymbol}) error {{"); var propertyTypeImportName = conventions.GetTypeString(property.Type, parentClass, false, false); var deserializationMethodName = GetDeserializationMethodName(property.Type, parentClass); writer.WriteLine($"val, err := n.{deserializationMethodName}"); @@ -796,7 +819,7 @@ private void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams requ if (codeElement.ErrorMappings.Any()) { errorMappingVarName = "errorMapping"; - writer.WriteLine($"{errorMappingVarName} := {conventions.AbstractionsHash}.ErrorMappings {{"); + writer.WriteLine($"{errorMappingVarName} := {conventions.AbstractionsHash}.ErrorMappings{{"); writer.IncreaseIndent(); foreach (var errorMapping in codeElement.ErrorMappings) { @@ -860,7 +883,7 @@ private static void WriteMethodCall(CodeMethod codeElement, RequestParams reques private static void WriteGeneratorMethodCall(CodeMethod codeElement, RequestParams requestParams, CodeClass parentClass, LanguageWriter writer, string prefix) { WriteMethodCall(codeElement, requestParams, parentClass, writer, CodeMethodKind.RequestGenerator, (name, paramsCall) => - $"{prefix}m.{name}({paramsCall});" + $"{prefix}m.{name}({paramsCall})" ); } private const string RequestInfoVarName = "requestInfo"; diff --git a/src/Kiota.Builder/Writers/Go/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Go/CodePropertyWriter.cs index b61b49e8ae..f32969b0b8 100644 --- a/src/Kiota.Builder/Writers/Go/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodePropertyWriter.cs @@ -29,7 +29,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w var returnType = codeElement.Parent is CodeElement parent ? conventions.GetTypeString(codeElement.Type, parent) : string.Empty; conventions.WriteShortDescription(codeElement, writer); conventions.WriteDeprecation(codeElement, writer); - writer.WriteLine($"{propertyName} {returnType}{suffix}"); + writer.WriteLine(string.IsNullOrEmpty(returnType) && string.IsNullOrEmpty(suffix) ? propertyName : $"{propertyName} {returnType}{suffix}"); break; } } diff --git a/src/Kiota.Builder/Writers/Go/CodeProprietableBlockDeclarationWriter.cs b/src/Kiota.Builder/Writers/Go/CodeProprietableBlockDeclarationWriter.cs index e52461d3f7..4f8de0cafb 100644 --- a/src/Kiota.Builder/Writers/Go/CodeProprietableBlockDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeProprietableBlockDeclarationWriter.cs @@ -33,14 +33,13 @@ public override void WriteCodeElement(T codeElement, LanguageWriter writer) .Where(static x => x.Declaration != null && x.Declaration.IsExternal) .Select(static x => new Tuple(x.Name.StartsWith('*') ? x.Name[1..] : x.Declaration!.Name.GetNamespaceImportSymbol(), x.Declaration!.Name)) .Distinct()) - .OrderBy(static x => x.Item2.Count(static y => y == '/')) - .ThenBy(static x => x) + .OrderBy(static x => x.Item2) // Item1: import alias, Item2: import path .ToList(); if (importSegments.Count != 0) { writer.WriteLines(string.Empty, "import ("); writer.IncreaseIndent(); - importSegments.ForEach(x => writer.WriteLine(x.Item1.Equals(x.Item2, StringComparison.Ordinal) ? $"\"{x.Item2}\"" : $"{x.Item1} \"{x.Item2}\"")); + importSegments.ForEach(x => writer.WriteLine(string.IsNullOrEmpty(x.Item1) ? $"\"{x.Item2}\"" : $"{x.Item1} \"{x.Item2}\"")); writer.DecreaseIndent(); writer.WriteLines(")", string.Empty); } diff --git a/src/Kiota.Builder/Writers/Go/GoConventionService.cs b/src/Kiota.Builder/Writers/Go/GoConventionService.cs index 0e062ac7cd..37276cb0e9 100644 --- a/src/Kiota.Builder/Writers/Go/GoConventionService.cs +++ b/src/Kiota.Builder/Writers/Go/GoConventionService.cs @@ -15,7 +15,7 @@ public class GoConventionService : CommonLanguageConventionService public override string VoidTypeName => string.Empty; - public override string DocCommentPrefix => "// "; + public override string DocCommentPrefix => "//"; public override string ParseNodeInterfaceName => "ParseNode"; #pragma warning disable CA1822 // Method should be static public string AbstractionsHash => "i2ae4187f7daee263371cb1c977df639813ab50ffa529013b7437480d1ec0158f"; @@ -187,14 +187,20 @@ public override bool WriteShortDescription(IDocumentedElement element, LanguageW public void WriteGeneratorComment(LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"{DocCommentPrefix}Code generated by Microsoft Kiota - DO NOT EDIT."); - writer.WriteLine($"{DocCommentPrefix}Changes may cause incorrect behavior and will be lost if the code is regenerated."); + writer.WriteLine($"{DocCommentPrefix} Code generated by Microsoft Kiota - DO NOT EDIT."); + writer.WriteLine($"{DocCommentPrefix} Changes may cause incorrect behavior and will be lost if the code is regenerated."); writer.WriteLine(string.Empty); } public void WriteDescriptionItem(string description, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(writer); - writer.WriteLine($"{DocCommentPrefix}{description}"); + // account for a trailing whitespace on comments then the description is empty + var comment = description switch + { + _ when string.IsNullOrEmpty(description) => DocCommentPrefix, + _ => $"{DocCommentPrefix} {description}", + }; + writer.WriteLine(comment); } public void WriteLinkDescription(CodeDocumentation documentation, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Go/GoNamespaceExtensions.cs b/src/Kiota.Builder/Writers/Go/GoNamespaceExtensions.cs index aa779e3862..404ec853a6 100644 --- a/src/Kiota.Builder/Writers/Go/GoNamespaceExtensions.cs +++ b/src/Kiota.Builder/Writers/Go/GoNamespaceExtensions.cs @@ -20,7 +20,7 @@ public static string GetInternalNamespaceImport(this CodeElement ns) { if (ns == null) return string.Empty; var urlPrefixIndex = ns.Name.LastIndexOf('/') + 1; - return (ns.Name[..urlPrefixIndex] + string.Join("/", ns.Name[urlPrefixIndex..].Split('.', StringSplitOptions.RemoveEmptyEntries))); + return ns.Name[..urlPrefixIndex] + string.Join("/", ns.Name[urlPrefixIndex..].Split('.', StringSplitOptions.RemoveEmptyEntries)); } public static string GetNamespaceImportSymbol(this CodeElement ns) { diff --git a/src/Kiota.Builder/Writers/Go/GoWriter.cs b/src/Kiota.Builder/Writers/Go/GoWriter.cs index 1813a7920e..2a2d55a637 100644 --- a/src/Kiota.Builder/Writers/Go/GoWriter.cs +++ b/src/Kiota.Builder/Writers/Go/GoWriter.cs @@ -4,7 +4,7 @@ namespace Kiota.Builder.Writers.Go; public class GoWriter : LanguageWriter { - public GoWriter(string rootPath, string clientNamespaceName, bool excludeBackwardCompatible = false) + public GoWriter(string rootPath, string clientNamespaceName, bool excludeBackwardCompatible = false) : base("\t", 1) { PathSegmenter = new GoPathSegmenter(rootPath, clientNamespaceName); var conventionService = new GoConventionService(); diff --git a/src/Kiota.Builder/Writers/LanguageWriter.cs b/src/Kiota.Builder/Writers/LanguageWriter.cs index 22313267dd..bca10f478b 100644 --- a/src/Kiota.Builder/Writers/LanguageWriter.cs +++ b/src/Kiota.Builder/Writers/LanguageWriter.cs @@ -17,11 +17,11 @@ namespace Kiota.Builder.Writers; -public abstract class LanguageWriter +public abstract class LanguageWriter(string indentationChar = " ", int indentSize = 4) { private TextWriter? writer; - private const int IndentSize = 4; - private static readonly string indentString = Enumerable.Repeat(" ", 1000).Aggregate(static (x, y) => x + y); + private readonly int indentSize = indentSize; + private readonly string indentString = Enumerable.Repeat(indentationChar, 1000).Aggregate(static (x, y) => x + y); private int currentIndent; /// @@ -44,13 +44,13 @@ public IPathSegmenter? PathSegmenter public void IncreaseIndent(int factor = 1) { factorStack.Push(factor); - currentIndent += IndentSize * factor; + currentIndent += indentSize * factor; } public void DecreaseIndent() { var popped = factorStack.TryPop(out var factor); - currentIndent -= IndentSize * (popped ? factor : 1); + currentIndent -= indentSize * (popped ? factor : 1); } public string GetIndent() diff --git a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs index ca98e97656..f896cacc1f 100644 --- a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs @@ -635,7 +635,7 @@ public void WritesNullableVoidTypeForExecutor() }; writer.Write(method); var result = tw.ToString(); - Assert.Contains("(error)", result); + Assert.Contains("() {", result); AssertExtensions.CurlyBracesAreClosed(result); } [Fact] @@ -986,7 +986,7 @@ public void WritesIndexerWithUuidParam() writer.Write(methodForTest); var result = tw.ToString(); Assert.Contains("m.BaseRequestBuilder.RequestAdapter", result); - Assert.Contains("WithId(id i561e97a8befe7661a44c8f54600992b4207a3a0cf6770e5559949bc276de2e22.UUID)(Somecustomtype)", result); + Assert.Contains("WithId(id i561e97a8befe7661a44c8f54600992b4207a3a0cf6770e5559949bc276de2e22.UUID) Somecustomtype", result); Assert.Contains("m.BaseRequestBuilder.PathParameters", result); Assert.Contains("[\"id\"] = id.String()", result); Assert.Contains("return", result); @@ -1370,7 +1370,7 @@ public async Task WritesRequestExecutorForScalarTypesAsync() method.AcceptedResponseTypes.Add("application/json"); writer.Write(method); var result = tw.ToString(); - Assert.Contains($"func (m *ParentClass) MethodName(ctx context.Context, b []RequestOption, c *RequestConfig)([]i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.DateOnly, error)", result); + Assert.Contains($"func (m *ParentClass) MethodName(ctx context.Context, b []RequestOption, c *RequestConfig) ([]i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.DateOnly, error)", result); Assert.Contains("res, err := m.BaseRequestBuilder.RequestAdapter.SendPrimitiveCollection(ctx, requestInfo, \"dateonly\", nil)", result); Assert.Contains($"val := make([]i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.DateOnly, len(res))", result); Assert.Contains("return val, nil", result); @@ -1673,7 +1673,7 @@ public void WritesReturnType() setup(); writer.Write(method); var result = tw.ToString(); - Assert.Contains($"{MethodName.ToFirstCharacterUpperCase()}()(*{ReturnTypeName}, error)", result);// async default + Assert.Contains($"{MethodName.ToFirstCharacterUpperCase()}() (*{ReturnTypeName}, error)", result);// async default AssertExtensions.CurlyBracesAreClosed(result); } [Fact] @@ -2301,7 +2301,7 @@ public void WritesMessageOverrideOnPrimary() var result = tw.ToString(); // Then - Assert.Contains("Error()(string) {", result); + Assert.Contains("Error() string {", result); Assert.Contains("return *(m.GetProp1()", result); }