diff --git a/CHANGELOG.md b/CHANGELOG.md
index e783ce0b56..2224a66040 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- PREVIEW: Moved preview configuration files to the .kiota directory. [#4310](https://github.com/microsoft/kiota/issues/4310)
- PREVIEW: Moved the copy descriptions to dedicated folders. [#4310](https://github.com/microsoft/kiota/issues/4310)
- PREVIEW: Renamed the config to workspace file. [#4310](https://github.com/microsoft/kiota/issues/4310)
+- Changed Csharp code generation to put braces on new lines (where it makes sense). [#4347](https://github.com/microsoft/kiota/issues/4347)
## [1.12.0] - 2024-03-06
diff --git a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs
index fbd487b882..cca625a398 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs
@@ -37,6 +37,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit
var derivation = derivedTypes.Length != 0 ? ": " + derivedTypes.Aggregate(static (x, y) => $"{x}, {y}") + " " : string.Empty;
conventions.WriteLongDescription(parentClass, writer);
conventions.WriteDeprecationAttribute(parentClass, writer);
- writer.StartBlock($"public class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}{{");
+ writer.WriteLine($"public class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}");
+ writer.StartBlock();
}
}
diff --git a/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs
index 92d58d64fa..207468f20f 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs
@@ -33,7 +33,8 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write
if (codeElement.Flags)
writer.WriteLine("[Flags]");
conventions.WriteDeprecationAttribute(codeElement, writer);
- writer.StartBlock($"public enum {codeElement.Name.ToFirstCharacterUpperCase()} {{");
+ writer.WriteLine($"public enum {codeElement.Name.ToFirstCharacterUpperCase()}");
+ writer.StartBlock();
var idx = 0;
foreach (var option in codeElement.Options)
{
diff --git a/src/Kiota.Builder/Writers/CSharp/CodeIndexerWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeIndexerWriter.cs
index 89b3b292d6..d214ea34c4 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodeIndexerWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodeIndexerWriter.cs
@@ -16,10 +16,14 @@ public override void WriteCodeElement(CodeIndexer codeElement, LanguageWriter wr
conventions.WriteShortDescription(codeElement.IndexParameter, writer, $"", "");
conventions.WriteAdditionalDescriptionItem($"A {conventions.GetTypeStringForDocumentation(codeElement.ReturnType, codeElement)}", writer);
conventions.WriteDeprecationAttribute(codeElement, writer);
- writer.StartBlock($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexParameter.Type, codeElement)} position] {{ get {{");
+ writer.WriteLine($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexParameter.Type, codeElement)} position]");
+ writer.StartBlock();
+ writer.WriteLine("get");
+ writer.StartBlock();
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("} }");
+ writer.CloseBlock();
+ writer.CloseBlock();
}
}
diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
index 08a2e53183..852d8b7a12 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
@@ -111,7 +111,8 @@ 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.WriteLine($"return {DiscriminatorMappingVarName} switch");
+ writer.StartBlock();
foreach (var mappedType in parentClass.DiscriminatorInformation.DiscriminatorMappings)
{
writer.WriteLine($"\"{mappedType.Key}\" => new {conventions.GetTypeString(mappedType.Value.AllTypes.First(), codeElement)}(),");
@@ -132,19 +133,15 @@ 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.IncreaseIndent();
- writer.WriteLine($"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = new {conventions.GetTypeString(propertyType, codeElement)}();");
- writer.CloseBlock();
+ writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if(\"{mappedType.Key}\".Equals({DiscriminatorMappingVarName}, StringComparison.OrdinalIgnoreCase))");
+ writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = new {conventions.GetTypeString(propertyType, codeElement)}();");
}
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();
+ writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName})");
+ writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};");
}
if (!includeElse)
includeElse = true;
@@ -164,9 +161,8 @@ 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.CloseBlock();
+ writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName})");
+ writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};");
}
if (!includeElse)
includeElse = true;
@@ -223,9 +219,8 @@ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod me
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();
+ writer.WriteLine($"if (string.IsNullOrEmpty({requestAdapterPropertyName}.BaseUrl))");
+ writer.WriteBlock(lines: $"{requestAdapterPropertyName}.BaseUrl = \"{method.BaseUrl}\";");
if (pathParametersProperty != null)
writer.WriteLine($"{pathParametersProperty.Name.ToFirstCharacterUpperCase()}.TryAdd(\"baseurl\", {requestAdapterPropertyName}.BaseUrl);");
}
@@ -293,9 +288,8 @@ private void WriteDeserializerBodyForUnionModel(CodeMethod method, CodeClass par
.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();
+ writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherPropName} != null)");
+ writer.WriteBlock(lines: $"return {otherPropName}.{method.Name.ToFirstCharacterUpperCase()}();");
if (!includeElse)
includeElse = true;
}
@@ -315,7 +309,8 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La
var propertiesNamesAsConditions = propertiesNames
.Select(static x => $"{x} != null")
.Aggregate(static (x, y) => $"{x} || {y}");
- writer.StartBlock($"if({propertiesNamesAsConditions}) {{");
+ writer.WriteLine($"if({propertiesNamesAsConditions})");
+ writer.StartBlock();
var propertiesNamesAsArgument = propertiesNames
.Aggregate(static (x, y) => $"{x}, {y}");
writer.WriteLine($"return ParseNodeHelper.MergeDeserializersForIntersectionWrapper({propertiesNamesAsArgument});");
@@ -326,7 +321,8 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La
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} {{");
+ writer.WriteLine($"return {DefaultDeserializerValue}{parentSerializationInfo}");
+ writer.StartBlock();
foreach (var otherProp in parentClass
.GetPropertiesOfKind(CodePropertyKind.Custom)
.Where(static x => !x.ExistsInBaseType)
@@ -381,8 +377,8 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re
if (codeElement.ErrorMappings.Any())
{
errorMappingVarName = "errorMapping";
- writer.WriteLine($"var {errorMappingVarName} = new Dictionary> {{");
- writer.IncreaseIndent();
+ writer.WriteLine($"var {errorMappingVarName} = new Dictionary>");
+ writer.StartBlock();
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}},");
@@ -474,10 +470,8 @@ 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.IncreaseIndent();
- writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
- writer.CloseBlock();
+ writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null)");
+ writer.WriteBlock(lines: $"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
if (!includeElse)
includeElse = true;
}
@@ -492,10 +486,8 @@ 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.IncreaseIndent();
- writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
- writer.CloseBlock();
+ writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null)");
+ writer.WriteBlock(lines: $"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
if (!includeElse)
includeElse = true;
}
@@ -630,11 +622,13 @@ private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, Langua
conventions.GetParameterSignature(p, code))
.ToList());
CSharpConventionService.WriteNullableOpening(writer);
- writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix} {{");
+ writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnTypeWithNullable}{methodName}({nullableParameters}){baseSuffix}");
+ writer.WriteLine("{");
CSharpConventionService.WriteNullableMiddle(writer);
}
- writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{");
+ writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix}");
+ writer.WriteLine("{");
if (includeNullableReferenceType)
CSharpConventionService.WriteNullableClosing(writer);
diff --git a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs
index e4b9efffe7..d50c0bc1ff 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs
@@ -41,11 +41,11 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ
switch (codeElement.Kind)
{
case CodePropertyKind.RequestBuilder:
- writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get =>");
- writer.IncreaseIndent();
+ writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()}");
+ writer.StartBlock();
+ writer.Write("get => ");
conventions.AddRequestBuilderBody(parentClass, propertyType, writer);
- writer.DecreaseIndent();
- writer.WriteLine("}");
+ writer.CloseBlock();
break;
case CodePropertyKind.AdditionalData when backingStoreProperty != null:
case CodePropertyKind.Custom when backingStoreProperty != null:
diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
index 820e7d2a5d..f6ebf05944 100644
--- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
@@ -560,7 +560,7 @@ public void WritesModelFactoryBodyForUnionModels()
writer.Write(factoryMethod);
var result = tw.ToString();
Assert.Contains("var mappingValue = parseNode.GetChildNode(\"@odata.type\")?.GetStringValue()", result);
- Assert.DoesNotContain("return mappingValue switch {", result);
+ Assert.DoesNotContain("return mappingValue switch", result);
Assert.Contains("var result = new UnionTypeWrapper()", result);
Assert.Contains("if(\"#kiota.complexType1\".Equals(mappingValue, StringComparison.OrdinalIgnoreCase))", result);
Assert.Contains("ComplexType1Value = new ComplexType1()", result);
@@ -600,7 +600,7 @@ public void WritesModelFactoryBodyForIntersectionModels()
writer.Write(factoryMethod);
var result = tw.ToString();
Assert.DoesNotContain("var mappingValue = parseNode.GetChildNode(\"@odata.type\")?.GetStringValue()", result);
- Assert.DoesNotContain("return mappingValue switch {", result);
+ Assert.DoesNotContain("return mappingValue switch", result);
Assert.Contains("var result = new IntersectionTypeWrapper()", result);
Assert.DoesNotContain("if(\"#kiota.complexType1\".Equals(mappingValue, StringComparison.OrdinalIgnoreCase))", result);
Assert.Contains("if(parseNode.GetStringValue() is string stringValueValue)", result);
@@ -710,7 +710,7 @@ public void WritesModelFactoryBodyAndDisambiguateAmbiguousImportedTypes()
var result = tw.ToString();
Assert.Contains("var mappingValue = parseNode.GetChildNode(\"@odata.type\")?.GetStringValue()", result);
- Assert.Contains("return mappingValue switch {", result);
+ Assert.Contains("return mappingValue switch", result);
Assert.Contains("\"namespaceLevelOne.ConflictingModel\" => new namespaceLevelOne.ConflictingModel(),", result); //Assert the disambiguation happens due to the enum imported
Assert.Contains("_ => new ConflictingModelBaseClass()", result);
AssertExtensions.CurlyBracesAreClosed(result);
@@ -765,7 +765,7 @@ public void WritesModelFactoryBodyForInheritedModels()
writer.Write(factoryMethod);
var result = tw.ToString();
Assert.Contains("var mappingValue = parseNode.GetChildNode(\"@odata.type\")?.GetStringValue()", result);
- Assert.Contains("return mappingValue switch {", result);
+ Assert.Contains("return mappingValue switch", result);
Assert.Contains("\"ns.childmodel\" => new ChildModel()", result);
Assert.Contains("_ => new ParentModel()", result);
AssertExtensions.CurlyBracesAreClosed(result);
@@ -859,7 +859,7 @@ public void DoesntWriteFactorySwitchOnEmptyPropertyName()
var result = tw.ToString();
Assert.DoesNotContain("var mappingValue = parseNode.GetChildNode(\"@odata.type\")?.GetStringValue()", result);
Assert.DoesNotContain("var mappingValue = mappingValueNode?.GetStringValue()", result);
- Assert.DoesNotContain("return mappingValue switch {", result);
+ Assert.DoesNotContain("return mappingValue switch", result);
Assert.DoesNotContain("\"ns.childmodel\" => new ChildModel()", result);
Assert.Contains("return new ParentModel()", result);
AssertExtensions.CurlyBracesAreClosed(result);
@@ -900,7 +900,7 @@ public void DoesntWriteFactorySwitchOnEmptyMappings()
var result = tw.ToString();
Assert.DoesNotContain("var mappingValue = parseNode.GetChildNode(\"@odata.type\")?.GetStringValue()", result);
Assert.DoesNotContain("var mappingValue = mappingValueNode?.GetStringValue()", result);
- Assert.DoesNotContain("return mappingValue switch {", result);
+ Assert.DoesNotContain("return mappingValue switch", result);
Assert.DoesNotContain("\"ns.childmodel\" => new ChildModel()", result);
Assert.Contains("return new ParentModel()", result);
AssertExtensions.CurlyBracesAreClosed(result);