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.1falsefalse
- 4.0.0-alpha-009
+ 4.0.0-alpha-010FS0988
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.1fantomasTrue
- 4.0.0-alpha-009
+ 4.0.0-alpha-010fantomas-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-010FS0988netcoreapp3.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-010Source 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"
}