diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 6dbe40dcd8..3aebd4bf0e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,4 +1,4 @@ -### 4.0.0-alpha-009 - 06/2020 +### 4.0.0-alpha-010 - 06/2020 * WIP for [#705](https://github.com/fsprojects/fantomas/issues/705) * FCS 36 diff --git a/docs/Documentation.md b/docs/Documentation.md index 1eb12fab2b..4f0d004080 100644 --- a/docs/Documentation.md +++ b/docs/Documentation.md @@ -272,6 +272,7 @@ A default configuration file would look like "MaxFunctionBindingWidth":40, "MultilineBlockBracketsOnSameColumn":false, "NewlineBetweenTypeDefinitionAndMembers":false, + "MaxElmishWidth": 40, "StrictMode":false } ``` diff --git a/docs/Formatting-Elmish-code.md b/docs/Formatting-Elmish-code.md new file mode 100644 index 0000000000..31f5357758 --- /dev/null +++ b/docs/Formatting-Elmish-code.md @@ -0,0 +1,74 @@ +# Formatting Elmish style guide + +This guide explains the main reasoning of how Fantomas formats "Elmish" inspired code. + +## Scope + +To keep things focused, the scope is currently limited to the Fable.React bindings: +- https://github.com/fable-compiler/fable-react/blob/master/src/Fable.React.Standard.fs +- https://github.com/fable-compiler/fable-react/blob/master/src/Fable.React.Props.fs + +Variants like Feliz and Fabulous might be covered in the future as well. + +## Key concepts + +There are two active patterns for [SynExpr](https://fsharp.github.io/FSharp.Compiler.Service/reference/fsharp-compiler-syntaxtree-synexpr.html) that capture the shapes in the Elmish DSL. + +See [SourceParser.fs](../src/Fantomas/SourceParser.fs) + +```fsharp +let (|ElmishReactWithoutChildren|_|) e = ... + +let (|ElmishReactWithChildren|_|) e = +```` + +`ElmishReactWithoutChildren` captures unary tags like `` or `
`. +Translated in the F# DSL they match a function that takes a single list as arguments. + +```fsharp +let i = input [ Type "hidden" ] +``` + +The props or attributes parameter is formatted like a normal list or array would be in default Fantomas. + +```fsharp +// short +myTag [ a1; a2 ] + +// long +myTag [ a1 + a2 + a3 ] +``` + +The tag and attributes will always align. + +`ElmishReactWithChildren` captures the non-unary tags like `

...

` or `
...
`. +Translated in the F# DSL they match a function that takes two lists as arguments. +The first argument matches the same rules as the unary tag. + +While the second argument starts its opening bracket right after the closing of the attributes. +The closing bracket of the children matches the start column of the tag. +Unless the entire expression is short. + +Children have one extra indent starting from the parent tag column. + + +```fsharp +// short +let myParagraph = p [] [ str "short" ] + +// long +let myContainer = + div [ ClassName "container" ] [ + h1 [] [ str "my title" ] + ] +``` + +When the children argument is empty, it is place right after the attributes. + +```fsharp +let x = + div [ OnClick (fun _ -> prinftn "meh" + ClassName "container" ] [] +``` diff --git a/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj b/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj index 1f9c050fcc..1e402e07c1 100644 --- a/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj +++ b/src/Fantomas.CoreGlobalTool.Tests/Fantomas.CoreGlobalTool.Tests.fsproj @@ -4,7 +4,7 @@ netcoreapp3.1 false false - 4.0.0-alpha-009 + 4.0.0-alpha-010 FS0988 diff --git a/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj b/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj index 84435fc6e5..59ba23a699 100644 --- a/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj +++ b/src/Fantomas.CoreGlobalTool/Fantomas.CoreGlobalTool.fsproj @@ -4,7 +4,7 @@ netcoreapp3.1 fantomas True - 4.0.0-alpha-009 + 4.0.0-alpha-010 fantomas-tool diff --git a/src/Fantomas.Tests/ElmishTests.fs b/src/Fantomas.Tests/ElmishTests.fs index c08d21817a..e3a7fa728e 100644 --- a/src/Fantomas.Tests/ElmishTests.fs +++ b/src/Fantomas.Tests/ElmishTests.fs @@ -119,4 +119,453 @@ let loginPage = (isRunning = true, heightRequest = 30.0, isVisible = model.IsSigningIn) ])) ]))) -""" \ No newline at end of file +""" + +[] +let ``input without attributes`` () = + formatSourceString false """let i = input [] +""" config + |> prepend newline + |> should equal """ +let i = input [] +""" + +[] +let ``short input with single attribute`` () = + formatSourceString false """let i = input [ Type "text" ] +""" config + |> prepend newline + |> should equal """ +let i = input [ Type "text" ] +""" + +[] +let ``multiline input with multiple attributes`` () = + formatSourceString false """let i = input [ Type "text"; Required "required" ] +""" config + |> prepend newline + |> should equal """ +let i = + input [ Type "text" + Required "required" ] +""" + +[] +let ``div without children or attributes`` () = + formatSourceString false """let d = div [] [] +""" config + |> prepend newline + |> should equal """ +let d = div [] [] +""" + +[] +let ``div with short attributes`` () = + formatSourceString false """let d = div [ ClassName "mt-4" ] [] +""" config + |> prepend newline + |> should equal """ +let d = div [ ClassName "mt-4" ] [] +""" + + +[] +let ``div with no attributes and short children`` () = + formatSourceString false """let d = div [] [ str "meh" ] +""" config + |> prepend newline + |> should equal """ +let d = div [] [ str "meh" ] +""" + +[] +let ``div with multiline attributes`` () = + formatSourceString false """let d = div [ ClassName "container"; OnClick (fun _ -> printfn "meh") ] [] +""" config + |> prepend newline + |> should equal """ +let d = + div [ ClassName "container" + OnClick(fun _ -> printfn "meh") ] [] +""" + +[] +let ``div with not attributes and multiple elmish children`` () = + formatSourceString false """let d = + div [] [ + span [] [ str "a" ] + span [] [ str "b" ] + ] +""" config + |> prepend newline + |> should equal """ +let d = + div [] [ + span [] [ str "a" ] + span [] [ str "b" ] + ] +""" + +[] +let ``div with single attribute and children`` () = + formatSourceString false """let view = + div [ ClassName "container" ] [ + h1 [] [ str "A heading 1" ] + p [] [ str "A paragraph" ] + ] +""" config + |> prepend newline + |> should equal """ +let view = + div [ ClassName "container" ] [ + h1 [] [ str "A heading 1" ] + p [] [ str "A paragraph" ] + ] +""" + +[] +let ``div with multiple attributes and children`` () = + formatSourceString false """let d = +div [ ClassName "container"; OnClick (fun _ -> printfn "meh") ] [ + span [] [str "foo"] + code [] [str "bar"] +] +""" config + |> prepend newline + |> should equal """ +let d = + div [ ClassName "container" + OnClick(fun _ -> printfn "meh") ] [ + span [] [ str "foo" ] + code [] [ str "bar" ] + ] +""" + + +[] +let ``short div with short p`` () = + formatSourceString false """let d = + div [] [ p [] [ str "meh" ] ] +""" config + |> prepend newline + |> should equal """ +let d = div [] [ p [] [ str "meh" ] ] +""" + + +[] +let ``short div with multiple short children`` () = + formatSourceString false """let d = + div [] [ + br [] ; br [] + ] +""" config + |> prepend newline + |> should equal """ +let d = div [] [ br []; br [] ] +""" + +[] +let ``div with long children but a long setting`` () = + formatSourceString false """let d = + div [] [ + p [] [ str "fooooooooo" ] + p [] [ str "baaaaaaaar" ] + ] +""" { config with MaxElmishWidth = 150 } + |> prepend newline + |> should equal """ +let d = + div [] [ p [] [ str "fooooooooo" ]; p [] [ str "baaaaaaaar" ] ] +""" + +// here the p is 38 characters +// this makes the div multiline but the p not. + +[] +let ``short div with slightly longer p`` () = + formatSourceString false """let d = + div [] [ p [] [ str "meeeeeeeeeeeeeeeeeeeeeh" ] ] +""" config + |> prepend newline + |> should equal """ +let d = + div [] [ + p [] [ str "meeeeeeeeeeeeeeeeeeeeeh" ] + ] +""" + +[] +let ``div with longer p`` () = + formatSourceString false """let d = + div [] [ p [] [ str "meeeeeeeeeeeeeeeeeeeeehhhh" ] ] +""" config + |> prepend newline + |> should equal """ +let d = + div [] [ + p [] [ + str "meeeeeeeeeeeeeeeeeeeeehhhh" + ] + ] +""" + +[] +let counter () = + formatSourceString false """ +let view model dispatch = + div [] [ + button [ OnClick (fun _ -> dispatch Decrement) ] [ + str "-" + ] + div [] [ + str (sprintf "%A" model) + ] + button [ OnClick (fun _ -> dispatch Increment) ] [ + str "+" + ] + ] +""" config + |> prepend newline + |> should equal """ +let view model dispatch = + div [] [ + button [ OnClick(fun _ -> dispatch Decrement) ] [ + str "-" + ] + div [] [ str (sprintf "%A" model) ] + button [ OnClick(fun _ -> dispatch Increment) ] [ + str "+" + ] + ] +""" + +[] +let ``view entry`` () = + formatSourceString false """ +let viewEntry todo dispatch = + li [ classList [ ("completed", todo.completed); ("editing", todo.editing) ] ] + [ div [ ClassName "view" ] + [ input [ ClassName "toggle" + Type "checkbox" + Checked todo.completed + OnChange (fun _ -> Check (todo.id,(not todo.completed)) |> dispatch) ] + label [ OnDoubleClick (fun _ -> EditingEntry (todo.id,true) |> dispatch) ] + [ str todo.description ] + button [ ClassName "destroy" + OnClick (fun _-> Delete todo.id |> dispatch) ] + [] + ] + input [ ClassName "edit" + valueOrDefault todo.description + Name "title" + Id ("todo-" + (string todo.id)) + OnInput (fun ev -> UpdateEntry (todo.id, !!ev.target?value) |> dispatch) + OnBlur (fun _ -> EditingEntry (todo.id,false) |> dispatch) + onEnter (EditingEntry (todo.id,false)) dispatch ] + ] +""" config + |> prepend newline + |> should equal """ +let viewEntry todo dispatch = + li [ classList [ ("completed", todo.completed) + ("editing", todo.editing) ] ] [ + div [ ClassName "view" ] [ + input [ ClassName "toggle" + Type "checkbox" + Checked todo.completed + OnChange(fun _ -> Check(todo.id, (not todo.completed)) |> dispatch) ] + label [ OnDoubleClick(fun _ -> EditingEntry(todo.id, true) |> dispatch) ] [ + str todo.description + ] + button [ ClassName "destroy" + OnClick(fun _ -> Delete todo.id |> dispatch) ] [] + ] + input [ ClassName "edit" + valueOrDefault todo.description + Name "title" + Id("todo-" + (string todo.id)) + OnInput(fun ev -> + UpdateEntry(todo.id, !!ev.target?value) + |> dispatch) + OnBlur(fun _ -> EditingEntry(todo.id, false) |> dispatch) + onEnter (EditingEntry(todo.id, false)) dispatch ] + ] +""" + +[] +let ``multiline attributes, no children`` () = + formatSourceString false """let a = + button [ ClassName "destroy" + OnClick(fun _-> Delete todo.id |> dispatch) ] + [] +""" config + |> prepend newline + |> should equal """ +let a = + button [ ClassName "destroy" + OnClick(fun _ -> Delete todo.id |> dispatch) ] [] +""" + +[] +let ``table and tbody`` () = + formatSourceString false """ +table [ ClassName "table table-striped table-hover mb-0" ] + [ tbody [] + [ tokenDetailRow "TokenName" (str tokenName) + tokenDetailRow "LeftColumn" (ofInt leftColumn) + tokenDetailRow "RightColumn" (ofInt rightColumn) + tokenDetailRow "Content" (pre [] [ code [] [ str token.Content ] ]) + tokenDetailRow "ColorClass" (str colorClass) + tokenDetailRow "CharClass" (str charClass) + tokenDetailRow "Tag" (ofInt tag) + tokenDetailRow "FullMatchedLength" + (span [ ClassName "has-text-weight-semibold" ] [ ofInt fullMatchedLength ]) ] ] +""" config + |> prepend newline + |> should equal """ +table [ ClassName "table table-striped table-hover mb-0" ] [ + tbody [] [ + tokenDetailRow "TokenName" (str tokenName) + tokenDetailRow "LeftColumn" (ofInt leftColumn) + tokenDetailRow "RightColumn" (ofInt rightColumn) + tokenDetailRow "Content" (pre [] [ code [] [ str token.Content ] ]) + tokenDetailRow "ColorClass" (str colorClass) + tokenDetailRow "CharClass" (str charClass) + tokenDetailRow "Tag" (ofInt tag) + tokenDetailRow "FullMatchedLength" + (span [ ClassName "has-text-weight-semibold" ] [ + ofInt fullMatchedLength + ]) + ] +] +""" + +[] +let ``child with empty children`` () = + formatSourceString false """ +let commands dispatch = + Button.button + [ Button.Color Primary + Button.Custom + [ ClassName "rounded-0" + OnClick(fun _ -> dispatch GetTrivia) ] ] + [ i [ ClassName "fas fa-code mr-1" ] [] + str "Get trivia" ] +""" config + |> prepend newline + |> should equal """ +let commands dispatch = + Button.button [ Button.Color Primary + Button.Custom [ ClassName "rounded-0" + OnClick(fun _ -> dispatch GetTrivia) ] ] [ + i [ ClassName "fas fa-code mr-1" ] [] + str "Get trivia" + ] +""" + +[] +let ``clock with two spaces`` () = + formatSourceString false """ +let view (CurrentTime time) dispatch = + svg + [ ViewBox "0 0 100 100" + SVG.Width "350px" ] + [ circle + [ Cx "50" + Cy "50" + R "45" + SVG.Fill "#0B79CE" ] [] + // Hours + clockHand (Hour time.Hour) "lightgreen" "2" 25.0 + handTop time.Hour "lightgreen" 25.0 12.0 + // Minutes + clockHand (Minute time.Minute) "white" "2" 35.0 + handTop time.Minute "white" 35.0 60.0 + // Seconds + clockHand (Second time.Second) "#023963" "1" 40.0 + handTop time.Second "#023963" 40.0 60.0 + // circle in the center + circle + [ Cx "50" + Cy "50" + R "3" + SVG.Fill "#0B79CE" + SVG.Stroke "#023963" + SVG.StrokeWidth 1.0 ] [] + ] +""" { config with IndentSpaceNum = 2 } + |> prepend newline + |> should equal """ +let view (CurrentTime time) dispatch = + svg [ ViewBox "0 0 100 100" + SVG.Width "350px" ] [ + circle [ Cx "50" + Cy "50" + R "45" + SVG.Fill "#0B79CE" ] [] + // Hours + clockHand (Hour time.Hour) "lightgreen" "2" 25.0 + handTop time.Hour "lightgreen" 25.0 12.0 + // Minutes + clockHand (Minute time.Minute) "white" "2" 35.0 + handTop time.Minute "white" 35.0 60.0 + // Seconds + clockHand (Second time.Second) "#023963" "1" 40.0 + handTop time.Second "#023963" 40.0 60.0 + // circle in the center + circle [ Cx "50" + Cy "50" + R "3" + SVG.Fill "#0B79CE" + SVG.Stroke "#023963" + SVG.StrokeWidth 1.0 ] [] + ] +""" + +[] +let ``input with attribute array`` () = + formatSourceString false """let ia = input [| Type "hidden"; Name "code"; Required "required" |] +""" config + |> prepend newline + |> should equal """ +let ia = + input [| Type "hidden" + Name "code" + Required "required" |] +""" + +[] +let ``div with children array`` () = + formatSourceString false """let d = + div [||] [| p [||] [| str "oh my foobar" |] |] +""" config + |> prepend newline + |> should equal """ +let d = + div [||] [| + p [||] [| str "oh my foobar" |] + |] +""" + +[] +let ``mix lists and array`` () = + formatSourceString false """let view dispatch model = + div [| Class "container" |] + [ + h1 [] [| str "my title" |] + button [| OnClick (fun _ -> dispatch Msg.Foo) |] [ + str "click me" + ] + ] +""" config + |> prepend newline + |> should equal """ +let view dispatch model = + div [| Class "container" |] [ + h1 [] [| str "my title" |] + button [| OnClick(fun _ -> dispatch Msg.Foo) |] [ + str "click me" + ] + ] +""" diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 1a9cb4a58a..b30444531c 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -1,7 +1,7 @@ - 4.0.0-alpha-009 + 4.0.0-alpha-010 FS0988 netcoreapp3.1 diff --git a/src/Fantomas.Tests/LambdaTests.fs b/src/Fantomas.Tests/LambdaTests.fs index 1c5c10cf87..a4f771a55f 100644 --- a/src/Fantomas.Tests/LambdaTests.fs +++ b/src/Fantomas.Tests/LambdaTests.fs @@ -65,11 +65,17 @@ open Reactstrap let private badgeSample = FunctionComponent.Of ((fun _ -> - fragment [] - [ h3 [] - [ str "Heading " - Badge.badge [ Badge.Color Secondary ] [ str "New" ] ] - Badge.badge [ Badge.Color Warning ] [ str "oh my" ] ]), + fragment [] [ + h3 [] [ + str "Heading " + Badge.badge [ Badge.Color Secondary ] [ + str "New" + ] + ] + Badge.badge [ Badge.Color Warning ] [ + str "oh my" + ] + ]), "BadgeSample") exportDefault badgeSample diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 0d8e2de768..476605ef84 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -825,6 +825,77 @@ and genExpr astContext synExpr = let sepCloseT = tokN synExpr.Range "RPAREN" sepCloseT match synExpr with + | ElmishReactWithoutChildren(identifier, attributes) -> + fun ctx -> + let maxRemainingArrayLength = ctx.Config.MaxElmishWidth - identifier.Length + let ctx' = + { ctx with Config = { ctx.Config with + MaxArrayOrListWidth = maxRemainingArrayLength + // override user setting to get original fantomas formatting + MultilineBlockBracketsOnSameColumn = false } } + (!- identifier + +> sepSpace + +> genExpr astContext attributes + +> fun cty -> + // reset the config with original values + { cty with Config = { cty.Config with + MaxArrayOrListWidth = ctx.Config.MaxArrayOrListWidth + MultilineBlockBracketsOnSameColumn = ctx.Config.MultilineBlockBracketsOnSameColumn } }) ctx' + + + | ElmishReactWithChildren((identifier,_,_), attributes, (isArray,children)) -> + let genChildren isShort = + match children with + | [] when (not isArray) -> sepOpenLFixed +> sepCloseLFixed + | [] when isArray -> sepOpenAFixed +> sepCloseAFixed + | [singleChild] -> + if isShort then + ifElse isArray sepOpenA sepOpenL + +> genExpr astContext singleChild + +> ifElse isArray sepCloseA sepCloseL + else + ifElse isArray sepOpenA sepOpenL + +> indent + +> sepNln + +> genExpr astContext singleChild + +> unindent + +> sepNln + +> ifElse isArray sepCloseAFixed sepCloseLFixed + + | children -> + if isShort then + ifElse isArray sepOpenA sepOpenL + +> col sepSemi children (genExpr astContext) + +> ifElse isArray sepCloseA sepCloseL + else + ifElse isArray sepOpenA sepOpenL + +> indent + +> sepNln + +> col sepNln children (genExpr astContext) + +> unindent + +> sepNln + +> ifElse isArray sepCloseAFixed sepCloseLFixed + + let shortExpression = + !- identifier + +> sepSpace + +> genExpr astContext attributes + +> sepSpace + +> genChildren true + + let longExpression = + atCurrentColumn(!- identifier + +> sepSpace + +> atCurrentColumn (genExpr astContext attributes) + +> sepSpace + +> genChildren false) + fun ctx -> + isShortExpression + ctx.Config.MaxElmishWidth + shortExpression + longExpression + ctx + | SingleExpr(Lazy, e) -> // Always add braces when dealing with lazy let hasParenthesis = hasParenthesis e diff --git a/src/Fantomas/Fantomas.fsproj b/src/Fantomas/Fantomas.fsproj index 0db9e911c2..dfb0da4a0c 100644 --- a/src/Fantomas/Fantomas.fsproj +++ b/src/Fantomas/Fantomas.fsproj @@ -3,7 +3,7 @@ netstandard2.0 - 4.0.0-alpha-009 + 4.0.0-alpha-010 Source code formatter for F# diff --git a/src/Fantomas/FormatConfig.fs b/src/Fantomas/FormatConfig.fs index bf84ca80d3..50147e1328 100644 --- a/src/Fantomas/FormatConfig.fs +++ b/src/Fantomas/FormatConfig.fs @@ -37,6 +37,7 @@ type FormatConfig = MultilineBlockBracketsOnSameColumn : bool NewlineBetweenTypeDefinitionAndMembers: bool KeepIfThenInSameLine : bool + MaxElmishWidth: Num /// Prettyprinting based on ASTs only StrictMode : bool } @@ -63,8 +64,9 @@ type FormatConfig = MaxFunctionBindingWidth = 40 MultilineBlockBracketsOnSameColumn = false KeepIfThenInSameLine = false - StrictMode = false - NewlineBetweenTypeDefinitionAndMembers = false } + MaxElmishWidth = 40 + NewlineBetweenTypeDefinitionAndMembers = false + StrictMode = false } static member ApplyOptions(currentConfig, options) = let currentValues = Reflection.getRecordFields currentConfig diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 66c30a3814..bd92409ed0 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -653,7 +653,6 @@ let (|Indexer|) = function | SynIndexerArg.Two(e1,e1FromEnd,e2,e2FromEnd,_,_) -> Pair((e1, e1FromEnd), (e2, e2FromEnd)) | SynIndexerArg.One(e,fromEnd,_) -> Single(e, fromEnd) -// hier ergens let (|OptVar|_|) = function | SynExpr.Ident(IdentOrKeyword(OpNameFull (s,r))) -> Some(s, false, r) @@ -1424,4 +1423,32 @@ let rec (|UppercaseSynExpr|LowercaseSynExpr|) (synExpr:SynExpr) = let isFunctionBinding (p: SynPat) = match p with | PatLongIdent(_, _, ps, _) when (List.isNotEmpty ps) -> true - | _ -> false \ No newline at end of file + | _ -> false + +let (|ElmishReactWithoutChildren|_|) e = + match e with + | App(OptVar(ident,_,_), [ArrayOrList(_) as attributes]) -> + Some(ident, attributes) + | App(OptVar(ident,_,_), [ArrayOrListOfSeqExpr(_, CompExpr(_, Sequentials _)) as attributes]) -> + Some(ident, attributes) + | _ -> + None + +let (|ElmishReactWithChildren|_|) e = + match e with + | App(OptVar(ident), [ArrayOrList(_) as attributes; ArrayOrList(isArray, children, _)]) -> + Some(ident, attributes, (isArray, children)) + | App(OptVar(ident), [ArrayOrListOfSeqExpr(_) as attributes + ArrayOrListOfSeqExpr(isArray, CompExpr(_, Sequentials children))]) -> + Some(ident, attributes, (isArray,children)) + | App(OptVar(ident), [ArrayOrListOfSeqExpr(_) as attributes + ArrayOrListOfSeqExpr(isArray, CompExpr(_, singleChild))]) + | App(OptVar(ident), [ArrayOrList(_) as attributes + ArrayOrListOfSeqExpr(isArray, CompExpr(_, singleChild))]) -> + Some(ident, attributes, (isArray,[singleChild])) + | App(OptVar(ident), [ArrayOrListOfSeqExpr(_) as attributes + ArrayOrList(isArray, [], _) ]) -> + Some(ident, attributes, (isArray, [])) + + | _ -> + None \ No newline at end of file diff --git a/src/Fantomas/schema.json b/src/Fantomas/schema.json index bb4fd5e0d2..26fdffdb19 100644 --- a/src/Fantomas/schema.json +++ b/src/Fantomas/schema.json @@ -71,6 +71,9 @@ "NewlineBetweenTypeDefinitionAndMembers": { "type": "boolean" }, + "MaxElmishWidth": { + "type": "integer" + }, "StrictMode": { "type": "boolean" }