Skip to content

Commit

Permalink
refactor: F# 8 lambda syntax and other simplifications
Browse files Browse the repository at this point in the history
  • Loading branch information
Tarmil committed Dec 16, 2023
1 parent b9be1fe commit 2ef6c25
Show file tree
Hide file tree
Showing 17 changed files with 71 additions and 76 deletions.
2 changes: 1 addition & 1 deletion src/Bolero.Html/Builders.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type ChildContentAttr = delegate of receiver: obj * builder: RenderTreeBuilder *
/// <param name="receiver">The containing component.</param>
/// <param name="builder">The rendering builder.</param>
/// <param name="sequence">The rendering sequence number.</param>
type ChildAndRefContent = delegate of receiver: obj * builder: Rendering.RenderTreeBuilder * sequence: int -> int
type ChildAndRefContent = delegate of receiver: obj * builder: RenderTreeBuilder * sequence: int -> int

type [<Struct; NoComparison; NoEquality>] AttrBuilder =
member inline _.Yield([<InlineIfLambda>] attr: Attr) = attr
Expand Down
1 change: 0 additions & 1 deletion src/Bolero.Server/Components.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ open System.Threading.Tasks
open Microsoft.AspNetCore.Components
#if NET8_0
open Microsoft.AspNetCore.Components.Endpoints
open Microsoft.AspNetCore.Components.Web
#endif
open Microsoft.AspNetCore.Components.RenderTree
open Microsoft.AspNetCore.Components.Rendering
Expand Down
2 changes: 1 addition & 1 deletion src/Bolero.Server/Extensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type ServerComponentsExtensions =
/// <param name="page">The page to return.</param>
[<Extension>]
static member BoleroPage(_this: Controller, page: Node) =
new BoleroPageResult(page)
BoleroPageResult(page)

/// <summary>Render the JavaScript tag needed by Bolero in a Razor page.</summary>
/// <param name="config">The injected Bolero hosting configuration.</param>
Expand Down
4 changes: 2 additions & 2 deletions src/Bolero.Server/Remoting/Endpoints.fs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ type internal RemotingEndpointDataSource() =

override _.Endpoints =
endpointBuilders
|> Seq.collect (fun b -> b.ApplyFinally())
|> Seq.map (fun b -> b.Build())
|> Seq.collect _.ApplyFinally()
|> Seq.map _.Build()
|> Array.ofSeq
:> IReadOnlyList<Endpoint>

Expand Down
70 changes: 35 additions & 35 deletions src/Bolero.Templating.Provider/CodeGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,97 +31,97 @@ open Bolero.TemplatingInternals
open Bolero.Templating.ConvertExpr

let getThis (args: list<Expr>) : Expr<TemplateNode> =
TExpr.Coerce<TemplateNode>(args.[0])
TExpr.Coerce<TemplateNode>(args[0])

let MakeCtor (holes: Parsing.Vars) =
ProvidedConstructor([], fun args ->
let holes = TExpr.Array<obj> [
for KeyValue(_, type') in holes ->
match type' with
| Parsing.HoleType.String -> <@ box "" @>
| Parsing.HoleType.Html -> <@ box (Node.Empty()) @>
| Parsing.HoleType.Event _ -> <@ box (Events.NoOp<EventArgs>()) @>
| Parsing.HoleType.DataBinding _ -> <@ box (null, Events.NoOp<ChangeEventArgs>()) @>
| Parsing.HoleType.Attribute -> <@ box (Attr.Empty()) @>
| Parsing.HoleType.AttributeValue -> <@ null @>
| Parsing.HoleType.Ref -> <@ null @>
| HoleType.String -> <@ box "" @>
| HoleType.Html -> <@ box (Node.Empty()) @>
| HoleType.Event _ -> <@ box (Events.NoOp<EventArgs>()) @>
| HoleType.DataBinding _ -> <@ box (null, Events.NoOp<ChangeEventArgs>()) @>
| HoleType.Attribute -> <@ box (Attr.Empty()) @>
| HoleType.AttributeValue -> <@ null @>
| HoleType.Ref -> <@ null @>
]
<@@ (%getThis args).Holes <- %holes @@>)

/// Get the argument lists and bodies for methods that fill a hole of the given type.
let HoleMethodBodies (holeType: Parsing.HoleType) : (ProvidedParameter list * (Expr list -> Expr)) list =
let HoleMethodBodies (holeType: HoleType) : (ProvidedParameter list * (Expr list -> Expr)) list =
let (=>) name ty = ProvidedParameter(name, ty)
match holeType with
| Parsing.HoleType.String ->
| HoleType.String ->
[
["value" => typeof<string>], fun args ->
<@@ box (%%args.[1]: string) @@>
<@@ box (%%args[1]: string) @@>
]
| Parsing.HoleType.Html ->
| HoleType.Html ->
[
["value" => typeof<string>], fun args ->
<@@ box (Node.Text (%%args.[1]: string)) @@>
<@@ box (Node.Text (%%args[1]: string)) @@>
["value" => typeof<Node>], fun args ->
<@@ box (%%args.[1]: Node) @@>
<@@ box (%%args[1]: Node) @@>
]
| Parsing.HoleType.Event argTy ->
| HoleType.Event argTy ->
[
["value" => EventHandlerOf argTy], fun args ->
Expr.Coerce(args.[1], typeof<obj>)
Expr.Coerce(args[1], typeof<obj>)
]
| Parsing.HoleType.DataBinding Parsing.BindingType.BindString ->
| HoleType.DataBinding BindingType.BindString ->
[
["value" => typeof<string>; "set" => typeof<Action<string>>], fun args ->
<@@ box (box (%%args.[1]: string), Events.OnChange(%%args.[2])) @@>
<@@ box (box (%%args[1]: string), Events.OnChange(%%args[2])) @@>
]
| Parsing.HoleType.DataBinding Parsing.BindingType.BindNumber ->
| HoleType.DataBinding BindingType.BindNumber ->
[
["value" => typeof<int>; "set" => typeof<Action<int>>], fun args ->
<@@ box (box (%%args.[1]: int), Events.OnChangeInt(%%args.[2])) @@>
<@@ box (box (%%args[1]: int), Events.OnChangeInt(%%args[2])) @@>
["value" => typeof<float>; "set" => typeof<Action<float>>], fun args ->
<@@ box (box (%%args.[1]: float), Events.OnChangeFloat(%%args.[2])) @@>
<@@ box (box (%%args[1]: float), Events.OnChangeFloat(%%args[2])) @@>
]
| Parsing.HoleType.DataBinding Parsing.BindingType.BindBool ->
| HoleType.DataBinding BindingType.BindBool ->
[
["value" => typeof<bool>; "set" => typeof<Action<bool>>], fun args ->
<@@ box (box (%%args.[1]: bool), Events.OnChangeBool(%%args.[2])) @@>
<@@ box (box (%%args[1]: bool), Events.OnChangeBool(%%args[2])) @@>
]
| Parsing.HoleType.Attribute ->
| HoleType.Attribute ->
[
["value" => typeof<Attr>], fun args ->
<@@ box (%%args.[1]: Attr) @@>
<@@ box (%%args[1]: Attr) @@>
["value" => typeof<list<Attr>>], fun args ->
<@@ box (Attr.Attrs(%%args.[1]: list<Attr>)) @@>
<@@ box (Attr.Attrs(%%args[1]: list<Attr>)) @@>
]
| Parsing.HoleType.AttributeValue ->
| HoleType.AttributeValue ->
[
["value" => typeof<obj>], fun args ->
<@@ %%args.[1] @@>
<@@ %%args[1] @@>
]
| Parsing.HoleType.Ref ->
| HoleType.Ref ->
[
["value" => typeof<HtmlRef>], fun args ->
<@@ box (%%args.[1]: HtmlRef) @@>
<@@ box (%%args[1]: HtmlRef) @@>
]

let MakeHoleMethods (holeName: string) (holeType: Parsing.HoleType) (index: int) (containerTy: ProvidedTypeDefinition) =
let MakeHoleMethods (holeName: string) (holeType: HoleType) (index: int) (containerTy: ProvidedTypeDefinition) =
[
for args, value in HoleMethodBodies holeType do
yield ProvidedMethod(holeName, args, containerTy, fun args ->
let this = getThis args
<@@ (%this).Holes.[index] <- %%(value args)
<@@ (%this).Holes[index] <- %%(value args)
%this @@>) :> MemberInfo
]

let MakeFinalMethod (filename: option<string>) (subTemplateName: option<string>) (content: Parsing.Parsed) =
let MakeFinalMethod (filename: option<string>) (subTemplateName: option<string>) (content: Parsed) =
ProvidedMethod("Elt", [], typeof<Node>, fun args ->
let this = getThis args
let directExpr =
let vars = content.Vars |> Map.map (fun k v -> Var(k, TypeOf v))
let varExprs = vars |> Map.map (fun _ v -> Expr.Var v)
((0, ConvertNode varExprs (Parsing.Concat content.Expr) :> Expr), vars)
((0, ConvertNode varExprs (Concat content.Expr) :> Expr), vars)
||> Seq.fold (fun (i, e) (KeyValue(_, var)) ->
let value = <@@ (%this).Holes.[i] @@>
let value = <@@ (%this).Holes[i] @@>
let value = Expr.Coerce(value, var.Type)
i + 1, Expr.Let(var, value, e)
)
Expand Down
16 changes: 8 additions & 8 deletions src/Bolero.Templating.Provider/ConvertExpr.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ let WrapExpr (innerType: Parsing.HoleType) (outerType: Parsing.HoleType) (expr:
/// Map an expression's vars from its parent, wrapping the expression in let declarations.
let WrapAndConvert (vars: Map<string, Expr>) (subst: list<Parsing.VarSubstitution>) convert expr =
let vars, addLets = ((vars, id), subst) ||> List.fold (fun (vars, addLets) wrap ->
let unwrapped = vars.[wrap.name]
let unwrapped = vars[wrap.name]
let wrapped = WrapExpr wrap.innerType wrap.outerType unwrapped
let var = Var(wrap.name, TypeOf wrap.innerType)
let addLets e = Expr.Let(var, defaultArg wrapped unwrapped, addLets e) |> Expr.Cast
Expand All @@ -84,7 +84,7 @@ let rec ConvertAttrTextPart (vars: Map<string, Expr>) (text: Parsing.Expr) : Exp
| Parsing.PlainHtml text ->
<@ text @>
| Parsing.VarContent varName ->
let e : Expr<obj> = Expr.Coerce(vars.[varName], typeof<obj>) |> Expr.Cast
let e : Expr<obj> = Expr.Coerce(vars[varName], typeof<obj>) |> Expr.Cast
<@ (%e).ToString() @>
| Parsing.WrapVars (subst, text) ->
WrapAndConvert vars subst ConvertAttrTextPart text
Expand All @@ -100,11 +100,11 @@ let rec ConvertAttrValue (vars: Map<string, Expr>) (text: Parsing.Expr) : Expr<o
| Parsing.PlainHtml text ->
box <@ text @>
| Parsing.VarContent varName ->
box vars.[varName]
box vars[varName]
| Parsing.Fst varName ->
box (Expr.TupleGet(vars.[varName], 0))
box (Expr.TupleGet(vars[varName], 0))
| Parsing.Snd varName ->
box (Expr.TupleGet(vars.[varName], 1))
box (Expr.TupleGet(vars[varName], 1))
| Parsing.WrapVars (subst, text) ->
WrapAndConvert vars subst ConvertAttrValue text
| Parsing.Attr _ | Parsing.Elt _ | Parsing.HtmlRef _ ->
Expand All @@ -119,11 +119,11 @@ let rec ConvertAttr (vars: Map<string, Expr>) (attr: Parsing.Expr) : Expr<Attr>
let value = ConvertAttrValue vars value
<@ Attr.Make name %value @>
| Parsing.VarContent varName ->
vars.[varName] |> Expr.Cast
vars[varName] |> Expr.Cast
| Parsing.WrapVars (subst, attr) ->
WrapAndConvert vars subst ConvertAttr attr
| Parsing.HtmlRef varName ->
let ref = vars.[varName] |> Expr.Cast
let ref = vars[varName] |> Expr.Cast
<@ Ref.MakeAttr(%ref) @>
| Parsing.Fst _ | Parsing.Snd _ | Parsing.PlainHtml _ | Parsing.Elt _ ->
failwith $"Invalid attribute: {attr}"
Expand All @@ -144,7 +144,7 @@ let rec ConvertNode (vars: Map<string, Expr>) (node: Parsing.Expr) : Expr<Node>
let children = TExpr.Array<Node> (Seq.map (ConvertNode vars) children)
<@ Node.Elt name %attrs %children @>
| Parsing.VarContent varName ->
vars.[varName] |> Expr.Cast
vars[varName] |> Expr.Cast
| Parsing.WrapVars (subst, node) ->
WrapAndConvert vars subst ConvertNode node
| Parsing.Fst _ | Parsing.Snd _ | Parsing.Attr _ | Parsing.HtmlRef _ ->
Expand Down
6 changes: 3 additions & 3 deletions src/Bolero.Templating.Provider/Parsing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,14 @@ let ParseText (t: string) (varType: HoleType) : Parsed =
let mutable vars = Map.empty
for p in parse do
if p.Index > lastHoleEnd then
parts.Add(PlainHtml t.[lastHoleEnd..p.Index - 1])
let varName = p.Groups.[1].Value
parts.Add(PlainHtml t[lastHoleEnd..p.Index - 1])
let varName = p.Groups[1].Value
if not (Map.containsKey varName vars) then
vars <- Map.add varName varType vars
parts.Add(VarContent varName)
lastHoleEnd <- p.Index + p.Length
if lastHoleEnd < t.Length then
parts.Add(PlainHtml t.[lastHoleEnd..t.Length - 1])
parts.Add(PlainHtml t[lastHoleEnd..t.Length - 1])
WithVars vars (parts.ToArray() |> List.ofSeq)

/// None if this is not a data binding.
Expand Down
2 changes: 1 addition & 1 deletion src/Bolero.Templating.Provider/Path.fs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let Canonicalize (path: string) =
let GetRelativePath (baseDir: string) (fullPath: string) =
let rec go (thisDir: string) =
if thisDir = baseDir then
fullPath.[thisDir.Length + 1..]
fullPath[thisDir.Length + 1..]
elif thisDir.Length <= baseDir.Length then
invalidArg "fullPath" $"'{fullPath}' is not a subdirectory of '{baseDir}'"
else
Expand Down
4 changes: 2 additions & 2 deletions src/Bolero/Router.fs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ type PageModel<'T> =
prop.SetValue(this, value)
#else
member internal this.SetModel(value) =
(Unsafe.AsRef<'T>(&this.Model)) <- value
Unsafe.AsRef<'T>(&this.Model) <- value
#endif

[<AutoOpen>]
Expand Down Expand Up @@ -299,7 +299,7 @@ module private RouterImpl =
if getTag x = 0 then
None
else
s.write (someDector x).[0]
s.write <| (someDector x)[0]
}, ValueSome none
| false, _ -> fail (InvalidRouterKind.UnsupportedType ty)
else
Expand Down
2 changes: 1 addition & 1 deletion tests/Client/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ let view js model dispatch =
cond model.page <| function
| Form -> viewForm js model dispatch
| Collection -> viewCollection model dispatch
| Item (k, m) -> ecomp<ViewItemPage,_,_> (k, model.items.[k], m.Model) dispatch { attr.empty() }
| Item (k, m) -> ecomp<ViewItemPage,_,_> (k, model.items[k], m.Model) dispatch { attr.empty() }
| Lazy (x, y) -> viewLazy (x, y) model dispatch
| Virtual -> viewVirtual model dispatch
| NotFound -> p { text "Not found" }
Expand Down
4 changes: 2 additions & 2 deletions tests/Remoting.Client/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ let Update (myApi: MyApi) msg model =

let router : Router<Page, Model, Message> =
{
getEndPoint = fun m -> m.page
getEndPoint = _.page
getRoute = function
| Home -> "/"
| Custom i -> $"/custom/{i}"
Expand All @@ -157,7 +157,7 @@ type Form = Template<"subdir/form.html">
type Item() =
inherit ElmishComponent<KeyValuePair<int, string>, Message>()

override __.View (KeyValue (k, v)) dispatch =
override _.View (KeyValue (k, v)) dispatch =
Tpl.item().key(string k).value(v)
.remove(fun _ -> dispatch (RemoveItem k))
.Elt()
Expand Down
8 changes: 3 additions & 5 deletions tests/Remoting.Server/Startup.fs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ open Microsoft.AspNetCore
open Microsoft.AspNetCore.Authentication.Cookies
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Mvc
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.Logging
Expand All @@ -47,14 +45,14 @@ module Page =
``base`` { attr.href "/" }
}
body {
div { attr.id "main"; comp<Client.MyApp> }
div { attr.id "main"; comp<MyApp> }
script { attr.src "_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js" }
boleroScript
}
}

type MyApiHandler(log: ILogger<MyApiHandler>, ctx: IRemoteContext) =
inherit RemoteHandler<Client.MyApi>()
inherit RemoteHandler<MyApi>()

let mutable items = Map.empty

Expand Down Expand Up @@ -105,7 +103,7 @@ type Startup() =
services.AddSwaggerForSystemTextJson(JsonFSharpOptions()) |> ignore
services.AddEndpointsApiExplorer() |> ignore

member this.Configure(app: IApplicationBuilder, env: IHostEnvironment, log: ILogger<Startup>) =
member this.Configure(app: IApplicationBuilder, env: IHostEnvironment) =
app.UseAuthentication()
.UseStaticFiles()
.UseSwagger()
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit.Client/Html.fs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ type BoleroComponent() =
condUnionState <-
match s.Length with
| 0 -> Empty
| 1 -> OneChar s.[0]
| 1 -> OneChar s[0]
| _ -> ManyChars s)
}
cond condUnionState <| function
Expand Down
1 change: 0 additions & 1 deletion tests/Unit/Fixture.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ open OpenQA.Selenium.Chrome
// open OpenQA.Selenium.Firefox
open OpenQA.Selenium.Support.UI
open Swensen.Unquote
open Bolero.Tests

/// Defines the setup/teardown for all tests that use the web server and Selenium.
/// These web tests must be located in the namespace Bolero.Tests.Web
Expand Down
15 changes: 7 additions & 8 deletions tests/Unit/Tests/Routing.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace Bolero.Tests.Web

open System.Text.RegularExpressions
open System.Threading
open FSharp.Reflection
open NUnit.Framework
open OpenQA.Selenium
Expand Down Expand Up @@ -88,19 +87,19 @@ module Routing =

let failingRouters = [
failingRouter<``Invalid parameter syntax``> <| fun c ->
InvalidRouterKind.ParameterSyntax(c.[0], "{x")
InvalidRouterKind.ParameterSyntax(c[0], "{x")
failingRouter<``Unknown parameter name``> <| fun c ->
InvalidRouterKind.UnknownField(c.[0], "y")
InvalidRouterKind.UnknownField(c[0], "y")
failingRouter<``Duplicate field``> <| fun c ->
InvalidRouterKind.DuplicateField(c.[0], "x")
InvalidRouterKind.DuplicateField(c[0], "x")
failingRouter<``Incomplete parameter list``> <| fun c ->
InvalidRouterKind.MissingField(c.[0], "y")
InvalidRouterKind.MissingField(c[0], "y")
failingRouter<``Identical paths with different parameter names``> <| fun c ->
InvalidRouterKind.IdenticalPath(c.[1], c.[0])
InvalidRouterKind.IdenticalPath(c[1], c[0])
failingRouter<``Mismatched type parameters in same position``> <| fun c ->
InvalidRouterKind.ParameterTypeMismatch(c.[1], "y", c.[0], "x")
InvalidRouterKind.ParameterTypeMismatch(c[1], "y", c[0], "x")
failingRouter<``Rest parameter in non-final position``> <| fun c ->
InvalidRouterKind.RestNotLast(c.[0])
InvalidRouterKind.RestNotLast(c[0])
failingRouter<Dictionary<int, int>> <| fun _ ->
InvalidRouterKind.UnsupportedType typeof<Dictionary<int, int>>
]
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Tests/Templating.fs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ module Templating =
Double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, ref 0.)
let isValidPosition (pos: string) =
let a = pos.Split(',')
isNumber a.[0] && isNumber a.[1]
isNumber a[0] && isNumber a[1]

elt.ByClass("btn1").Click()
elt.Eventually <@ state.Text = "clicked 1" @>
Expand Down
Loading

0 comments on commit 2ef6c25

Please sign in to comment.