Zaid-Ajaj / Snowflaqe

A dotnet CLI to generate type-safe GraphQL clients for F# and Fable with automatic deserialization, static query verification and type checking
MIT License
157 stars 26 forks source link

Generate props file with referenced fs files #34

Closed xperiandri closed 3 years ago

xperiandri commented 3 years ago

It would be nice to have a props file generated. This will allow scenario:

client.fsproj: <Import Project="output/generated.props" />

/output \<generated F# files> \<project name>.props

    <ItemGroup>
        <Compile Include="Query1.fs" />
        ...
    </ItemGroup>
Zaid-Ajaj commented 3 years ago

That looks like a doable improvement. Preferably via an option ["generateProps"]: <true | false> where false is default.

I am not sure how the props file will look like though, can you provide a full example?

xperiandri commented 3 years ago

The file extension can be any. Content matters. It will be something like:

<ItemGroup>
    <Compile Include="Types.fs" />
    <Compile Include="Query1.fs" />
    <Compile Include="Query2.fs" />
    ...
    <Compile Include="QueryN.fs" />
    <Compile Include="Client.fs" />
</ItemGroup>

That is all.

The main point is to include files in the right order and do not do that manually.

xperiandri commented 3 years ago

Just a piece of fsproj extracted to separate file and auto-generated

anthony-mi commented 3 years ago

I want to realize this opportunity. How to name the key that will switch generation between fsproj and props?

anthony-mi commented 3 years ago

I would like to use StringBuffer

type StringBuffer = StringBuilder -> unit

type StringBufferBuilder () =
    member inline __.Yield (txt: string) = fun (b: StringBuilder) -> Printf.bprintf b "%s" txt
    member inline __.Yield (c: char) = fun (b: StringBuilder) -> Printf.bprintf b "%c" c
    member inline __.Yield (b: byte) = fun (sb: StringBuilder) -> Printf.bprintf sb "%02x " b
    member inline __.YieldFrom (strings: #seq<string>) =
        fun (b: StringBuilder) ->
            for s in strings do Printf.bprintf b "%s" s

    member inline __.YieldFrom (f: StringBuffer) = f
    member __.Combine (f, g) = fun (b: StringBuilder) -> f b; g b
    member __.Delay f = fun (b: StringBuilder) -> (f()) b
    member __.Zero () = ignore

    member __.For (xs: 'a seq, f: 'a -> StringBuffer) =
        fun (b: StringBuilder) ->
            use e = xs.GetEnumerator ()
            while e.MoveNext() do
                (f e.Current) b

    member __.While (p: unit -> bool, f: StringBuffer) =
        fun (b: StringBuilder) -> while p () do f b

    member __.Run (f: StringBuffer) =
        let b = StringBuilder()
        do f b
        b.ToString()

let stringBuffer = new StringBufferBuilder ()

Can I add it to the project?

anthony-mi commented 3 years ago

I would like to generate fsproj using XDocument, XElement. Can I rewrite the generation on them?

Zaid-Ajaj commented 3 years ago

Hi @anthony-mi maybe I didn't understand the issue correctly, does this replace the fsproj entirely? if so, what about the external dependencies that the project uses in the generated GraphQL client, specifically Fable.Remoting.Client?

Zaid-Ajaj commented 3 years ago

I would like to generate fsproj using XDocument, XElement. Can I rewrite the generation on them?

That would be a nice improvement to the current API (which uses strings) to build the project file but that is a separate issue

xperiandri commented 3 years ago

It depends on your intent. If you want to go away from fsproj to props as I propose than we do that

xperiandri commented 3 years ago

But if you wan to keep the ability to have full project, then we need to introduce a switch

xperiandri commented 3 years ago

What is your opinion?

Zaid-Ajaj commented 3 years ago

There is already a switch called target which takes <fable | fsharp | shared> to which we can add propsFile or just props as another type of target but the question remains, what do you do with the external dependencies that are added and used in GraphqlClient.fs?

xperiandri commented 3 years ago

They can be added to props also

xperiandri commented 3 years ago

But it is better to add them manually

xperiandri commented 3 years ago

To the project file

xperiandri commented 3 years ago

There is already a switch called target which takes <fable | fsharp | shared> to which we can add propsFile

But props can be generated for any target

Zaid-Ajaj commented 3 years ago

They can be added to props also

So it is not just the files

<ItemGroup>
    <Compile Include="Types.fs" />
    <Compile Include="Query1.fs" />
    <Compile Include="Query2.fs" />
    ...
    <Compile Include="QueryN.fs" />
    <Compile Include="Client.fs" />
</ItemGroup>

but also with package references added

<ItemGroup>
    <Compile Include="Types.fs" />
    <Compile Include="Query1.fs" />
    <Compile Include="Query2.fs" />
    ...
    <Compile Include="QueryN.fs" />
    <Compile Include="Client.fs" />
</ItemGroup>
<ItemGroup>
    <PackageReference Update="FSharp.Core" Version="4.7.2" />
    <PackageReference Include="Fable.Remoting.Json" Version="2.14.0" />
</ItemGroup>

is that correct?

xperiandri commented 3 years ago

Yes, we can do that. But I think that these 2 dependencies any developer can add himself into his project as well as <Import Project="GraphQLClient.props" />

Zaid-Ajaj commented 3 years ago

I would rather have snowflaqe decide which dependencies are used because they are tied to the code generation. If a I fix something in the serializer and update snowflaqe to a new version, they would get the new version with the proper dependency versions etc.

xperiandri commented 3 years ago

That's fine, developer can override it in consuming project any way

xperiandri commented 3 years ago

Do you approve stringBuffer and XDocument?

Zaid-Ajaj commented 3 years ago

stringBuffer I don't mind, XDocument yes please! 🙏

anthony-mi commented 3 years ago

Changed fsproj generation to props - everything works. Screenshot_124 Screenshot_129

Zaid-Ajaj commented 3 years ago

Added option createProjectFile to implement this feature thanks to @anthony-mi where the value false makes snowflaqe output a props file instead of a project (see docs in readme)