@@ -2034,6 +2034,111 @@ module Util =
20342034 None
20352035 )
20362036
2037+ module Jsx =
2038+
2039+ (** *
2040+
2041+ For JSX, we want to rewrite the default output in order to remove all the code coming from list CEs
2042+
2043+ By default, this code
2044+
2045+ ```fs
2046+ Html.div
2047+ [
2048+ yield! [
2049+ Html.div "Test 1"
2050+ Html.div "Test 2"
2051+ ]
2052+ ]
2053+ ```
2054+
2055+ generates something like
2056+
2057+ ```jsx
2058+ <div>
2059+ {toList(delay(() => [<div>
2060+ Test 1
2061+ </div>, <div>
2062+ Test 2
2063+ </div>]))}
2064+ </div>;
2065+ ```
2066+
2067+ but thanks to the optimisation done below we get
2068+
2069+ ```jsx
2070+ <div>
2071+ <div>
2072+ Test 1
2073+ </div>
2074+ <div>
2075+ Test 2
2076+ </div>
2077+ </div>
2078+ ```
2079+
2080+ Initial implementation of this optimiser comes from https://github.com/shayanhabibi/Partas.Solid/blob/master/Partas.Solid.FablePlugin/Plugin.fs
2081+
2082+ ***)
2083+
2084+ // Check if the provided expression is equal to the expected identiferText (as a string)
2085+ let rec (| IdentifierIs | _ |) ( identifierText : string ) expression =
2086+ match expression with
2087+ | Expression.Identifier( Identifier( currentCallerText, _)) when identifierText = currentCallerText -> Some()
2088+ | _ -> None
2089+
2090+ // Make it easy to check if we are calling the expected function
2091+ and (| CalledExpression | _ |) ( callerText : string ) value =
2092+ match value with
2093+ | CallExpression( IdentifierIs callerText, UnrollerFromArray exprs, _, _) -> Some exprs
2094+ | _ -> None
2095+
2096+ and (| UnrollerFromSingleton |) ( expr : Expression ) : Expression list =
2097+ [ expr ]
2098+ |> function
2099+ | Unroller exprs -> exprs
2100+
2101+ and (| UnrollerFromArray |) ( arrayExpr : Expression array ) : Expression list =
2102+ arrayExpr
2103+ |> Array.toList
2104+ |> function
2105+ | Unroller exprs -> exprs
2106+
2107+ and (| Unroller |): Expression list -> Expression list =
2108+ function
2109+ | [] -> []
2110+ | expr :: Unroller rest ->
2111+ match expr with
2112+ | CalledExpression " toList" exprs -> exprs @ rest
2113+ | CalledExpression " delay" exprs -> exprs @ rest
2114+ | ArrowFunctionExpression([||],
2115+ BlockStatement [| ReturnStatement( ArrayExpression( UnrollerFromArray exprs, _),
2116+ _) |],
2117+ _,
2118+ _,
2119+ _) -> exprs @ rest
2120+ | ArrowFunctionExpression([||],
2121+ BlockStatement [| ReturnStatement( UnrollerFromSingleton exprs, _) |],
2122+ _,
2123+ _,
2124+ _) -> exprs @ rest
2125+ | CalledExpression " append" exprs -> exprs @ rest
2126+ | CalledExpression " singleton" exprs -> exprs @ rest
2127+ // Note: Should we guard this unwrapper by checking that all the elements in the array are JsxElements?
2128+ | ArrayExpression( UnrollerFromArray exprs, _) -> exprs @ rest
2129+ | ConditionalExpression( testExpr, UnrollerFromSingleton thenExprs, UnrollerFromSingleton elseExprs, loc) ->
2130+ ConditionalExpression(
2131+ testExpr,
2132+ SequenceExpression( thenExprs |> List.toArray, None),
2133+ SequenceExpression( elseExprs |> List.toArray, None),
2134+ loc
2135+ )
2136+ :: rest
2137+ | expr ->
2138+ // Tips 💡
2139+ // If a pattern is not optimized, you can put a debug point here to capture it
2140+ expr :: rest
2141+
20372142 let transformJsxEl ( com : IBabelCompiler ) ctx componentOrTag props =
20382143 match transformJsxProps com props with
20392144 | None -> Expression.nullLiteral ()
@@ -2047,6 +2152,12 @@ module Util =
20472152 // Because of call optimizations, it may happen a list has been transformed to an array in JS
20482153 | [ ArrayExpression( children, _) ] -> Array.toList children
20492154 | children -> children
2155+ // Optimize AST, removing F# CEs from the output (see documentation in the JSX module)
2156+ |> List.map ( fun child ->
2157+ match child with
2158+ | Jsx.UnrollerFromSingleton expr -> expr
2159+ )
2160+ |> List.concat
20502161
20512162 let props =
20522163 props |> List.rev |> List.map ( fun ( k , v ) -> k, transformAsExpr com ctx v)
0 commit comments