This guide explains the main reasoning of how Fantomas formats "Elmish" inspired code.
To keep things focused, the scope is currently limited to the Fable.React and Feliz 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
- https://github.com/Zaid-Ajaj/Feliz/blob/master/Feliz/Html.fs
- https://github.com/Zaid-Ajaj/Feliz/blob/master/Feliz/Properties.fs
Fabulous might be covered in the future as well.
There are two active patterns for SynExpr that capture the shapes in the Elmish DSL.
See SourceParser:
let (|ElmishReactWithoutChildren|_|) e = ...
let (|ElmishReactWithChildren|_|) e = ...
Captures unary tags like <input />
or <br />
.
Translated in the F# DSL, they match a function that takes a single list as arguments.
let i = input [ Type "hidden" ]
The props or attributes parameter is formatted like a normal list or array would be in default Fantomas.
// short
myTag [ a1; a2 ]
// long
myTag [ a1
a2
a3 ]
The tag and attributes will always align.
Translated in the Feliz DSL, tags with children also take a single list as arguments.
When fsharp_single_argument_web_mode is true
, props and children have one extra indent starting from the parent tag column.
The opening bracket starts right after the tag, and the closing bracket matches the start column of the tag.
let myContainer =
Html.div [
prop.className "container"
prop.children [
Html.h1 "my title"
]
]
Captures the non-unary tags like <p>...</p>
or <div>...</div>
.
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.
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.
Like with fsharp_single_argument_web_mode
, children have one extra indent starting from the parent tag column.
// short
let myParagraph = p [] [ str "short" ]
// long
let myContainer =
div [ ClassName "container" ] [
h1 [] [ str "my title" ]
]
When the children argument is empty, it is placed right after the attributes.
let x =
div [ OnClick(fun _ -> printfn "meh")
ClassName "container" ] []