Skip to content

Commit 0e87429

Browse files
authored
feat: SolidComponent let bindings can be used as TagValues (#36)
add: tests for TagValues wrapping SolidComponent let bindings chore: Apply fantomas and cleanup remaining Partas.Solid.Tests dir fix: include test in plugin compilation project file for Fable to transpile
1 parent ee3e7da commit 0e87429

7 files changed

Lines changed: 102 additions & 8 deletions

File tree

Partas.Solid.FablePlugin/Plugin.fs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -901,15 +901,23 @@ module internal rec AST =
901901
| Call(
902902
Import({ Selector = "op_BangAt"; Kind = MemberImport(MemberRef({ FullName = "Partas.Solid.Builder" }, _)) }, _, _),
903903
{
904-
Args = Lambda(_, Call(callee, _, _, _), _) :: _
904+
Args = Lambda(_, Call(callee, callInfo, _, _), _) :: _
905905
},
906906
_,
907907
range
908908
) ->
909909
match callee with
910910
// Some ident
911911
| IdentExpr({ Type = Type.PartasName ctx typeName } as identee) ->
912-
IdentExpr({ identee with Name = typeName |> Utils.trimReservedIdentifiers }) |> Some
912+
match callInfo with
913+
// In the case where the referenced tag is a constructor, then it is a SolidTypeComponent, and we
914+
// actually intend to reference the name of the type.
915+
| CallInfo.Constructor ctx ->
916+
IdentExpr({ identee with Name = typeName |> Utils.trimReservedIdentifiers }) |> Some
917+
// Where the above is not true, the referenced tag is a let binding, and therefore a SolidComponent,
918+
// so we intent to reference the name of the binding.
919+
| _ ->
920+
callee |> Some
913921
// prevent import of native tags
914922
| Expr.NativeImportedConstructor ctx
915923
& Import(
@@ -923,9 +931,18 @@ module internal rec AST =
923931
| Import(
924932
importInfo,
925933
typ & Type.PartasName ctx typeName,
926-
range) ->
927-
Import({ importInfo with Selector = typeName }, typ, range)
928-
|> Some
934+
range) as expr->
935+
// We determine if the imported tag was a constructor. If it was, then it is a SolidTypeComponent,
936+
// and the name of the component will be the name of the type.
937+
match callInfo with
938+
| CallInfo.Constructor ctx ->
939+
Import({ importInfo with Selector = typeName }, typ, range)
940+
|> Some
941+
// If the above is not true, then the tag is a SolidComponent let binding, and the name of the
942+
// component will be the name of the binding.
943+
| _ ->
944+
expr
945+
|> Some
929946
| Import({ Kind = UserImport false }, _, _) ->
930947
Some callee
931948
| _ -> None

Partas.Solid.Tests.Plugin/Compiled/Partas.Solid.Tests.Plugin.Compiled.fsproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
<Content Include="AttributeCases\PartasImportAttr\PartasImportAttr.expected" />
8989
<Compile Include="AttributeCases\Pojo\Pojo.fs" />
9090
<Content Include="AttributeCases\Pojo\Pojo.expected" />
91+
<Compile Include="SolidCases\SolidComponentAsTagValues\SolidComponentAsTagValuesTypes.fs" />
92+
<Compile Include="SolidCases\SolidComponentAsTagValues\SolidComponentAsTagValues.fs" />
93+
<Content Include="SolidCases\SolidComponentAsTagValues\SolidComponentAsTagValues.expected" />
9194
<!-- <Content Include="Spec\Components.fs" />-->
9295
</ItemGroup>
9396

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { splitProps, mergeProps } from "solid-js";
2+
import { FakeImportedTag } from "fakeLibrary";
3+
import { ModuleTag } from "./SolidComponentAsTagValuesTypes.fs.jsx";
4+
5+
export function CustomTag(props) {
6+
props = mergeProps({
7+
icon: button,
8+
}, props);
9+
const [PARTAS_LOCAL, PARTAS_OTHERS] = splitProps(props, ["icon"]);
10+
return <div>
11+
<PARTAS_LOCAL.icon class="KeyVal" />
12+
<PARTAS_LOCAL.icon class="KeyVal2" />
13+
<PARTAS_LOCAL.icon class="constructor">
14+
<button>
15+
internal
16+
</button>
17+
</PARTAS_LOCAL.icon>
18+
</div>;
19+
}
20+
21+
export function Rock() {
22+
const Comp = FakeImportedTag;
23+
return <CustomTag icon={a}>
24+
<Comp other={ModuleTag} />
25+
</CustomTag>;
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module Partas.Solid.Tests.SolidCases.SolidComponentAsTagValues.SolidComponentAsTagValues
2+
3+
open Partas.Solid.Tests.SolidCases.SolidComponentAsTagValues.SolidComponentAsTagValuesTypes
4+
open Partas.Solid
5+
open Fable.Core
6+
open Fable.Core.JsInterop
7+
8+
[<Erase>]
9+
type CustomTag() =
10+
interface RegularNode
11+
12+
[<Erase>]
13+
member val icon: TagValue = unbox null with get, set
14+
15+
[<SolidTypeComponent>]
16+
member props.constructor =
17+
props.icon <- !@button
18+
19+
div () {
20+
props.icon % {| class' = "KeyVal" |}
21+
props.icon % {| class' = "KeyVal2" |}
22+
props.icon % div (class' = "constructor") { button () { "internal" } }
23+
24+
}
25+
26+
[<SolidComponent>]
27+
let Rock () =
28+
let Comp = !@Imported
29+
CustomTag (icon = unbox !@a) { Comp % Imported (other = !@ModuleTag) }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module Partas.Solid.Tests.SolidCases.SolidComponentAsTagValues.SolidComponentAsTagValuesTypes
2+
3+
open Partas.Solid
4+
open Fable.Core
5+
6+
#nowarn 64
7+
8+
[<SolidComponent>]
9+
let ModuleTag () = div ()
10+
11+
[<Import("FakeImportedTag", "fakeLibrary")>]
12+
type Imported() =
13+
interface RegularNode
14+
15+
[<Erase>]
16+
member val other: TagValue = jsNative with get, set

Partas.Solid.Tests.Plugin/Tests.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ let SolidCases =
9090
"CssStyles"
9191
|> runSolidCase "CssStyle definitions compiles correct output"
9292
"ChildLambdaProvider"
93-
|> runSolidCase "ChildLambdaProvider interfaces" ]
93+
|> runSolidCase "ChildLambdaProvider interfaces"
94+
"SolidComponentAsTagValues"
95+
|> runSolidCase "SolidComponent let bindings as TagValues" ]
9496

9597
[<Tests>]
9698
let AttributeCases =

Partas.Solid/Builder.fs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module Builder =
3838
type VoidNode =
3939
inherit HtmlTag
4040

41+
4142
[<System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>]
4243
type IChildLambdaProvider =
4344
inherit HtmlElement
@@ -142,7 +143,7 @@ module Builder =
142143
/// let tag = !@div
143144
/// </code></example>
144145
[<Erase>]
145-
type TagValue(tag: unit -> #HtmlElement) =
146+
type TagValue(tag: FSharpFunc<_, #HtmlElement>) =
146147
/// <summary>
147148
/// Directs the plugin to build the call site as a Tag
148149
/// in JSX.
@@ -200,7 +201,7 @@ module Builder =
200201
/// let tag = !@div
201202
/// </code></example>
202203
[<Erase>]
203-
let (!@) (this: unit -> 'T) =
204+
let (!@) (this: FSharpFunc<_, #HtmlElement>) =
204205
TagValue (unbox this)
205206

206207
/// Alias used in the provided builder

0 commit comments

Comments
 (0)