From 68ae5543ec66b6b499dac48226f7f6287c9811b0 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 11 Jan 2024 17:14:20 +0100 Subject: [PATCH] Update long secondary constructor parameters. --- .../BaseConstructorTests.fs | 66 ------- src/Fantomas.Core.Tests/ConstructorTests.fs | 168 ++++++++++++++++++ .../Fantomas.Core.Tests.fsproj | 2 +- src/Fantomas.Core/CodePrinter.fs | 84 ++++++--- src/Fantomas.Core/SyntaxOak.fs | 2 + 5 files changed, 226 insertions(+), 96 deletions(-) delete mode 100644 src/Fantomas.Core.Tests/BaseConstructorTests.fs create mode 100644 src/Fantomas.Core.Tests/ConstructorTests.fs diff --git a/src/Fantomas.Core.Tests/BaseConstructorTests.fs b/src/Fantomas.Core.Tests/BaseConstructorTests.fs deleted file mode 100644 index bc65d29013..0000000000 --- a/src/Fantomas.Core.Tests/BaseConstructorTests.fs +++ /dev/null @@ -1,66 +0,0 @@ -module Fantomas.Core.Tests.BaseConstructorTests - -open NUnit.Framework -open FsUnit -open Fantomas.Core.Tests.TestHelpers - -[] -let ``multiple base constructors in record, 2111`` () = - formatSourceString - """ -type UnhandledWebException = - inherit Exception - - new(status: WebExceptionStatus, innerException: Exception) = - { inherit Exception(SPrintF1 - "Backend not prepared for this WebException with Status[%i]" - (int status), - innerException) } - - new(info: SerializationInfo, context: StreamingContext) = - { inherit Exception(info, context) } -""" - { config with MaxLineLength = 100 } - |> prepend newline - |> should - equal - """ -type UnhandledWebException = - inherit Exception - - new(status: WebExceptionStatus, innerException: Exception) = - { inherit - Exception( - SPrintF1 "Backend not prepared for this WebException with Status[%i]" (int status), - innerException - ) } - - new(info: SerializationInfo, context: StreamingContext) = { inherit Exception(info, context) } -""" - -[] -let ``single multiline base constructor, 2335`` () = - formatSourceString - """ -type FieldNotFoundException<'T>(obj:'T, field:string, specLink:string) = - inherit SwaggerSchemaParseException( - sprintf "Object MUST contain field `%s` (See %s for more details).\nObject:%A" - field specLink obj) -""" - { config with - SpaceBeforeClassConstructor = true - MaxLineLength = 90 } - |> prepend newline - |> should - equal - """ -type FieldNotFoundException<'T> (obj: 'T, field: string, specLink: string) = - inherit - SwaggerSchemaParseException ( - sprintf - "Object MUST contain field `%s` (See %s for more details).\nObject:%A" - field - specLink - obj - ) -""" diff --git a/src/Fantomas.Core.Tests/ConstructorTests.fs b/src/Fantomas.Core.Tests/ConstructorTests.fs new file mode 100644 index 0000000000..893f785fd5 --- /dev/null +++ b/src/Fantomas.Core.Tests/ConstructorTests.fs @@ -0,0 +1,168 @@ +module Fantomas.Core.Tests.ConstructorTests + +open NUnit.Framework +open FsUnit +open Fantomas.Core.Tests.TestHelpers + +[] +let ``multiple base constructors in record, 2111`` () = + formatSourceString + """ +type UnhandledWebException = + inherit Exception + + new(status: WebExceptionStatus, innerException: Exception) = + { inherit Exception(SPrintF1 + "Backend not prepared for this WebException with Status[%i]" + (int status), + innerException) } + + new(info: SerializationInfo, context: StreamingContext) = + { inherit Exception(info, context) } +""" + { config with MaxLineLength = 100 } + |> prepend newline + |> should + equal + """ +type UnhandledWebException = + inherit Exception + + new(status: WebExceptionStatus, innerException: Exception) = + { inherit + Exception( + SPrintF1 "Backend not prepared for this WebException with Status[%i]" (int status), + innerException + ) } + + new(info: SerializationInfo, context: StreamingContext) = { inherit Exception(info, context) } +""" + +[] +let ``single multiline base constructor, 2335`` () = + formatSourceString + """ +type FieldNotFoundException<'T>(obj:'T, field:string, specLink:string) = + inherit SwaggerSchemaParseException( + sprintf "Object MUST contain field `%s` (See %s for more details).\nObject:%A" + field specLink obj) +""" + { config with + SpaceBeforeClassConstructor = true + MaxLineLength = 90 } + |> prepend newline + |> should + equal + """ +type FieldNotFoundException<'T> (obj: 'T, field: string, specLink: string) = + inherit + SwaggerSchemaParseException ( + sprintf + "Object MUST contain field `%s` (See %s for more details).\nObject:%A" + field + specLink + obj + ) +""" + +[] +let ``multiline secondary constructor, 3037`` () = + formatSourceString + """ +type IntersectionOptions + private + ( + primary: bool, + ?root: Element, + ?rootMargin: string, + ?threshold: ResizeArray, + ?triggerOnce: bool + ) + = + + new(?root: Element, + ?rootMargin: string, + ?threshold: ResizeArray, + ?triggerOnce: bool) = + + IntersectionOptions(true) +""" + { config with MaxLineLength = 80 } + |> prepend newline + |> should + equal + """ +type IntersectionOptions + private + ( + primary: bool, + ?root: Element, + ?rootMargin: string, + ?threshold: ResizeArray, + ?triggerOnce: bool + ) = + + new + ( + ?root: Element, + ?rootMargin: string, + ?threshold: ResizeArray, + ?triggerOnce: bool + ) = + + IntersectionOptions(true) +""" + +[] +let ``secondary constructor with xml doc`` () = + formatSourceString + """ +type IntersectionOptions + ( + primary: bool + ) = + + /// Good stuff + new (secondary: int) = IntersectionOptions(secondary = 0) +""" + config + |> prepend newline + |> should + equal + """ +type IntersectionOptions(primary: bool) = + + /// Good stuff + new(secondary: int) = IntersectionOptions(secondary = 0) +""" + +[] +let ``setting AlternativeLongMemberDefinitions should be respected in long secondary constructor`` () = + formatSourceString + """ +type StateMachine( + // meh +) = + new( + // also meh but with an int + x:int) as secondCtor = StateMachine() +""" + { config with + AlternativeLongMemberDefinitions = true } + |> prepend newline + |> should + equal + """ +type StateMachine + ( + // meh + ) + = + new + ( + // also meh but with an int + x: int + ) as secondCtor + = + StateMachine() +""" diff --git a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj index fc1f54d822..dcaf08cfa3 100644 --- a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj +++ b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj @@ -121,7 +121,7 @@ - + diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index 3deeb25dde..66aaa7e932 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -3260,6 +3260,17 @@ let sepNlnBetweenTypeAndMembers (node: ITypeDefn) (ctx: Context) : Context = else ctx +let genLongPatternInConstructor (pat: Pattern) = + match pat with + | Pattern.Paren patParen -> + genSingleTextNode patParen.OpeningParen + +> expressionFitsOnRestOfLine + (genPat patParen.Pattern) + (indentSepNlnUnindent (genPat patParen.Pattern) +> sepNln) + +> genSingleTextNode patParen.ClosingParen + |> genNode patParen + | _ -> genPat pat + let genImplicitConstructor (node: ImplicitConstructorNode) = let short = genXml node.XmlDoc @@ -3270,26 +3281,15 @@ let genImplicitConstructor (node: ImplicitConstructorNode) = +> genPat node.Pattern let long = - let genPats = - match node.Pattern with - | Pattern.Paren patParen -> - genSingleTextNode patParen.OpeningParen - +> expressionFitsOnRestOfLine - (genPat patParen.Pattern) - (indentSepNlnUnindent (genPat patParen.Pattern) +> sepNln) - +> genSingleTextNode patParen.ClosingParen - |> genNode patParen - | _ -> genPat node.Pattern - indentSepNlnUnindent ( genXml node.XmlDoc +> genOnelinerAttributes node.Attributes +> onlyIf node.Attributes.IsSome sepNln +> expressionFitsOnRestOfLine - (genAccessOpt node.Accessibility +> genPats) + (genAccessOpt node.Accessibility +> genLongPatternInConstructor node.Pattern) (genAccessOpt node.Accessibility +> optSingle (fun _ -> sepNln) node.Accessibility - +> genPats) + +> genLongPatternInConstructor node.Pattern) +> (fun ctx -> onlyIf ctx.Config.AlternativeLongMemberDefinitions sepNln ctx) ) @@ -3709,24 +3709,50 @@ let genMemberDefn (md: MemberDefn) = | MemberDefn.ExternBinding node -> genExternBinding node | MemberDefn.DoExpr node -> genExpr (Expr.Single node) | MemberDefn.ExplicitCtor node -> + let short = + genAccessOpt node.Accessibility + +> genSingleTextNode node.New + +> sepSpaceBeforeClassConstructor + +> genPat node.Pattern + +> optSingle (fun alias -> sepSpace +> !- "as" +> sepSpace +> genSingleTextNode alias) node.Alias + +> sepSpace + +> genSingleTextNode node.Equals + +> sepSpace + +> genExpr node.Expr + + let long = + leadingExpressionIsMultiline + (genAccessOpt node.Accessibility + +> genSingleTextNode node.New + +> sepSpaceBeforeClassConstructor + +> autoIndentAndNlnIfExpressionExceedsPageWidth (genLongPatternInConstructor node.Pattern) + +> optSingle (fun alias -> sepSpace +> !- "as" +> sepSpace +> genSingleTextNode alias) node.Alias) + (fun isMultiline ctx -> + let genExpr = + genExpr node.Expr + +> optSingle + (fun thenExpr -> + sepNln + +> !- "then" + +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr thenExpr)) + node.ThenExpr + + let short = genSingleTextNode node.Equals +> sepSpace +> genExpr + + let long ctx = + if ctx.Config.AlternativeLongMemberDefinitions then + indentSepNlnUnindent (genSingleTextNode node.Equals +> sepNln +> genExpr) ctx + else + (sepSpace +> genSingleTextNode node.Equals +> indentSepNlnUnindent genExpr) ctx + + if isMultiline then + long ctx + else + expressionFitsOnRestOfLine short long ctx) + genXml node.XmlDoc +> genAttributes node.Attributes - +> genAccessOpt node.Accessibility - +> genSingleTextNode node.New - +> sepSpaceBeforeClassConstructor - +> genPat node.Pattern - +> optSingle (fun alias -> sepSpace +> !- "as" +> sepSpace +> genSingleTextNode alias) node.Alias - +> sepSpace - +> genSingleTextNode node.Equals - +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth ( - genExpr node.Expr - +> optSingle - (fun thenExpr -> - sepNln - +> !- "then" - +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr thenExpr)) - node.ThenExpr - ) + +> ifElse node.ThenExpr.IsSome long (expressionFitsOnRestOfLine short long) |> genNode (MemberDefn.Node md) | MemberDefn.LetBinding node -> genBindings true node.Bindings |> genNode (MemberDefn.Node md) | MemberDefn.Interface node -> diff --git a/src/Fantomas.Core/SyntaxOak.fs b/src/Fantomas.Core/SyntaxOak.fs index 387535c2b6..1cbc77d52e 100644 --- a/src/Fantomas.Core/SyntaxOak.fs +++ b/src/Fantomas.Core/SyntaxOak.fs @@ -2389,6 +2389,8 @@ type MemberDefnInheritNode(inheritKeyword: SingleTextNode, baseType: Type, range member val Inherit = inheritKeyword member val BaseType = baseType +/// Secondary constructor +/// new (pat: type) = expr type MemberDefnExplicitCtorNode ( xmlDoc: XmlDocNode option,