Git Product home page Git Product logo

falanx's Introduction

Build Status NuGet

Falanx code generation

This repository contains the code generator to generate F# source (.fs files) from Protobuf v3 schema.

The general concepts are as follows:

  • Code generation, to generate F# source code, rather than types being injected as a type provider.
  • Idiomatic F# code is generated rather than simple .NET 1.1 era code. This means records, discriminated unions, etc., are generated where appropriate.

How to use

In a .NET Sdk library project, add the following packages

<PackageReference Include="Falanx.Proto.Codec.Binary" Version="0.5.*" />
<PackageReference Include="Falanx.Proto.Codec.Json" Version="0.5.*" />
<PackageReference Include="Falanx.Sdk" Version="0.5.*" PrivateAssets="All" />

It's possibile to use only one of Falanx.Proto.Codec.Binary and Falanx.Proto.Codec.Json or both, the generated code will depends on the packages referenced

Now specify the .proto file path like

  <ItemGroup>
    <ProtoFile Include="..\proto\bundle.proto" />
  </ItemGroup>

and an auto generated file will be created on build

More info in example-sdk/README.md

Template

Install the .NET template for an example library sample

dotnet new -i Falanx.Templates
dotnet new falanx

use --codec argument to specify the codecs (values json,binary,all)

Tool

It's possibile to use falanx as command line .NET global tool

dotnet tool install -g Falanx.Tool
falanx --help

To generate a .fs file for a specified .proto file:

falanx --inputfile test\examples\schemas\bundle.proto --defaultnamespace test --outputfile bundle.fs

More info in example\README.md

How to build Falanx

More info in docs/developer_guide.md

Use the src/Falanx.sln solution for development, or directly the projects with .NET Core Sdk (dotnet).

Projects:

  • src/Falanx.Tool the falanx console app, run with dotnet run
  • test/Falanx.Tests the unit test, run with dotnet run
  • test/Falanx.IntegrationTests the integration tests, run with dotnet run

As shortcuts, from root:

  • dotnet build to build the falanx executable Falanx.Tool.
  • dotnet pack to generate packages in bin/nupks
  • dotnet test -v n to run tests

To build packages

From root

dotnet pack

The nupkgs will be in bin/nupkg

To specify a version pass the Version property like /p:Version=0.1.0-alpha7

Info

Falanx uses:

  • Type Provider SDK common type for quotation and AST support
  • FsAst untyped F# AST to code via the code formatter Fantomas
  • Froto protobuf parser and binary serializer
  • Fantomas code formatter and linter

Security

This repository is actively monitored by Jet Engineers and the Jet Security team. Please monitor this repo for security updates and advisories. For more information and contacts, please see SECURITY

falanx's People

Contributors

7sharp9 avatar azure-pipelines[bot] avatar enricosada avatar erichgoldman avatar gusty avatar haf avatar jorgef avatar kevmal avatar mshulman avatar natelkins avatar realvictorprm avatar troykershaw avatar vasily-kirichenko avatar vbfox avatar vchekan avatar wuzzeb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

falanx's Issues

A proto file with a normal field follows by a oneOf results in incorrect generated code

Given:

message TestAllTypes {
  // Singular
  int32 single_int32 = 1;

  // For oneof test
   oneof oneof_field {
     uint32 oneof_uint32 = 111;
     //NestedMessage oneof_nested_message = 112;
     string oneof_string = 113;
     //bytes oneof_bytes = 114;
   }
}

This code is generated:

type TestAllTypes =
    { mutable oneofField : TestAllTypes.oneof_field option
      mutable singleInt32 : int option }

    static member JsonObjCodec =
        fun singleInt32 oneofField ->
            { oneofField = singleInt32
              singleInt32 = oneofField } : TestAllTypes
        |> fun f ->
            Fleece.Newtonsoft.withFields<option<Int32> -> option<TestAllTypes.oneof_field> -> TestAllTypes, IReadOnlyDictionary<String, JToken>, Fleece.Newtonsoft.DecodeError, TestAllTypes, String, JToken>
                (f)
        |> fun codec ->
            let decode =
                let _bind_0, _ = codec
                _bind_0

            let encode =
                let _, _bind_1 = codec
                _bind_1

            Fleece.Newtonsoft.jfieldOpt<TestAllTypes, Int32, TestAllTypes> ("singleInt32") (fun x -> x.singleInt32)
                (decode, encode)

Notice the oneofField = singleInt32 in the record creation.

If the oneOf field is first then this does not happen.

Enum in class is not working: lead.proto.fs(251, 13): [FS0001] No overloads match for method 'OfJson'.

Snippet like the below

enum SourceEnum {
  FACEBOOK = 0;
  OTHER = 1;
}
message Source {
/* Only used if the source_type = OTHER */
  string other = 1;
  SourceEnum source = 2;
}

generates code

[<CLIMutable>]
type Source =
    { mutable other : string option
      mutable source : SourceEnum option }

    static member JsonObjCodec =
        (fun other source ->
        { other = other
          source = source }) <!> Operators.jopt<Source, String> ("other") (fun x -> x.other)
        <*> Operators.jopt<Source, SourceEnum> ("source") (fun x -> x.source)

which generates error

lead.proto.fs(251, 13): [FS0001] No overloads match for method 'OfJson'. The available overloads are shown below.

Which seems to be referring to this line

<*> Operators.jopt<Source, SourceEnum> ("source") (fun x -> x.source)

as the problem

Default namespace option must not be mandatory

Is your feature request related to a problem? Please describe.
When integrating with msbuild, it is impractial to demand to pass namespace as command line tool because it requires hacking project files.

Describe the solution you'd like
Implement namspace option support in.proto file and remove mandatory command line option --defaultnamespace

Code that uses Coerce needs a a special case for detecting interfaces on a provided type

This section of code:

| Coerce(e, t) ->
//dependencies.Append t
let synExpr = exprToAst e
let synType = sysTypeToSynType range t knownNamespaces ommitEnclosingType
let synCoerce =
// Need to manually check for interface. <interface>.IsAssignableFrom(<provided_type :> interface>) does not properly return true
if (t.IsInterface && (Array.contains t (e.Type.GetInterfaces()))) || t.IsAssignableFrom e.Type then
SynExpr.Upcast(synExpr, synType, range)
else
SynExpr.Downcast(synExpr, synType, range)

See #62 for more details.

Dependent proto messages should not need to be in dependency order

Is your feature request related to a problem? Please describe.
Dependent types need to be in dependency order in order for the generator to work.

Describe the solution you'd like
A topological sort of the proto types should be done by the generator.

Describe alternatives you've considered
Manual ordering in the proto file.

Additional context
None.

Recursively nested types fail

// This proto includes a recusively nested message.
message NestedTestAllTypes {
  NestedTestAllTypes child = 1;
  TestAllTypes payload = 2;
  repeated NestedTestAllTypes repeated_child = 3;
}

This results in:

falanx_test.fs(835, 13): [FS0001] This expression was expected to have type� 
ConcreteCodec<KeyValuePair<string,JToken> list,KeyValuePair<string,JToken> list,NestedTestAllTypes,NestedTestAllTypes>

but here has type�:
 
(IReadOnlyDictionary<string,JsonValue> -> Result<NestedTestAllTypes,DecodeError>) * (NestedTestAllTypes -> IReadOnlyDictionary<string,JsonValue>)

I think this is something that @gusty was expecting with Fleece?

Uneeded dependencies

Describe the bug
example-sdk/example2 dependencies include things like Froto.Parser which are most definitely not needed at runtime.

Expected behavior
Only dependencies needed at runtime should be included into projects which use Falanx to generate code.

Environement (please complete the following information):

  • OS: windows
  • Framework netcode-2.1

OneOf fields are not contained in the record definition

Take the example in the repo:

module SampleMessage =
    type test_oneof =
        | First_name of First_name : string
        | Age of Age : int
        | Last_name of Last_name : string

[<CLIMutable>]
type SampleMessage =
    { mutable martId : int option }
    member x.testOneof = x.testOneof

member x.testOneof = x.testOneof should actually be defined as part of the record

Immutable types

Is your feature request related to a problem? Please describe.
Would be nice if the types generated were immutable (even if they remain CLIMutable). I understand that minimizing copying might have been the goal, but there gotta be a relatively inexpensive way to implement x.ReadFrom that doesn't involve mutation (at least I think that's where the mutability comes in).

Describe the solution you'd like
I'll take any.

Describe alternatives you've considered
Live with the mutable types.

Additional context
n/a.

Mutual recursion is not supported

Given the following proto definition:

// Test that mutual recursion works.
message TestMutualRecursionA {
  TestMutualRecursionB bb = 1;
}

message TestMutualRecursionB {
  TestMutualRecursionA a = 1;
  int32 optional_int32 = 2;
}

The following error results as neither type can be processed by the other, not sure how to fix this due to the way types are processed by providedtypes.

type 'TestMutualRecursionA' was not yet added as a member to a declaring type, stacktrace =    at System.Environment.get_StackTrace()
   at ProviderImplementation.ProvidedTypes.ProvidedTypeDefinition.get_Assembly() in /Users/dave.thomas/Documents/GitHub/falanx/paket-files/7sharp9/FSharp.TypeProviders.SDK/src/ProvidedTypes.fs:line 1508
   at Falanx.Machinery.Reflection.Impl.tryFindCompilationMappingAttributeFromType(Type typ) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Reflection.fs:line 52
   at Falanx.Machinery.Reflection.Impl.tryFindSourceConstructFlagsOfType(Type typ) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Reflection.fs:line 60
   at Falanx.Machinery.Reflection.Impl.isExceptionRepr(Type typ, BindingFlags bindingFlags) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Reflection.fs:line 67
   at Falanx.Machinery.Reflection.Impl.getTypeOfReprType(Type typ, BindingFlags bindingFlags) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Reflection.fs:line 118
   at Falanx.Machinery.Reflection.FSharpTypeSafe.IsFunction(Type typ) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Reflection.fs:line 256
   at Falanx.Machinery.Utils.sysTypeToSynType(range range, Type t, FSharpSet`1 knownNamespaces, FSharpOption`1 ommitEnclosingType) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Utils.fs:line 206
   at [email protected](Type arg) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Utils.fs:line 213
   at Microsoft.FSharp.Collections.Internal.IEnumerator.map@74.DoMoveNext(b& curr)
   at Microsoft.FSharp.Collections.Internal.IEnumerator.MapEnumerator`1.System-Collections-IEnumerator-MoveNext()
   at Microsoft.FSharp.Collections.SeqModule.ToList[T](IEnumerable`1 source)
   at Falanx.Machinery.Utils.sysTypeToSynType(range range, Type t, FSharpSet`1 knownNamespaces, FSharpOption`1 ommitEnclosingType) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/Utils.fs:line 213
   at <StartupCode$Falanx-Machinery>[email protected](FSharpExpr expr) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/QuotationToAst.fs:line 64
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x)
   at <StartupCode$Falanx-Machinery>[email protected](FSharpExpr expr) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/QuotationToAst.fs:line 273
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x)
   at <StartupCode$Falanx-Machinery>[email protected](FSharpExpr expr) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/QuotationToAst.fs:line 273
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x)
   at <StartupCode$Falanx-Machinery>[email protected](FSharpExpr expr) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/QuotationToAst.fs:line 273
   at Falanx.Machinery.Quotations.ToAst(FSharpExpr expr, FSharpOption`1 ommitEnclosingType, FSharpOption`1 knownNamespaces) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Machinery/QuotationToAst.fs:line 497
   at Falanx.Proto.Core.JsonCodec.createJsonObjCodec(TypeDescriptor typeDescriptor) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Proto.Core/JsonCodec/Codec.fs:line 429
   at [email protected](Codec codec) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Proto.Generator/TypeGeneration.fs:line 262
   at Microsoft.FSharp.Collections.SetTreeModule.iter[a](FSharpFunc`2 f, SetTree`1 t)
   at Falanx.Proto.Generator.TypeGeneration.createType(ProvidedTypeDefinition container, String scope, FSharpMap`2 lookup, FSharpSet`1 codecs, ProtoMessage message) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Proto.Generator/TypeGeneration.fs:line 235
   at [email protected](ProtoMessage message) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Proto.Generator/CreateProto.fs:line 88
   at Microsoft.FSharp.Collections.Internal.IEnumerator.map@74.DoMoveNext(b& curr)
   at Microsoft.FSharp.Collections.Internal.IEnumerator.MapEnumerator`1.System-Collections-IEnumerator-MoveNext()
   at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
   at Falanx.Proto.Generator.Proto.createProvidedTypes(String protoDef, String defaultnamespace, FSharpSet`1 codecs) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Proto.Generator/CreateProto.fs:line 86
   at Falanx.Proto.Generator.Proto.createFSharpDefinitions(String protoDef, String outputFile, String defaultnamespace, FSharpSet`1 codecs) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Proto.Generator/CreateProto.fs:line 117
   at Falanx.Generator.main.main(String[] argv) in /Users/dave.thomas/Documents/GitHub/falanx/src/Falanx.Tool/Program.fs:line 43

Project does not compile under linux

Describe the bug
Project does not compile under linux

To Reproduce
First, global.json pin sdk version to 2.1.403, which is outdated and makes it impossible(or difficult) to compile project out of the box. After removing global.json dotnet build starts but paket fails:

$ dotnet build Falanx.sln 
Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  shasum: /home/vadim/projects/falanx/.paket/../paket-files/paket.restore.cached: 
  shasum: /home/vadim/projects/falanx/.paket/../paket-files/paket.restore.cached: 
  shasum: /home/vadim/projects/falanx/.paket/../paket-files/paket.restore.cached: 
  shasum: /home/vadim/projects/falanx/.paket/../paket-files/paket.restore.cached: 
  Paket version 5.189.1
  Starting full restore process.
  Stacktrace:
  
    at <unknown> <0xffffffff>
  
  Unhandled Exception:
  System.NullReferenceException: Object reference not set to an instance of an object
  [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
/home/vadim/projects/falanx/.paket/Paket.Restore.targets(91,5): error MSB3073: The command "mono --runtime=v4.0.30319 "/home/vadim/projects/falanx/.paket/paket.exe" restore" exited with code 1. [/home/vadim/projects/falanx/Falanx.Proto.Generator/Falanx.Proto.Generator.fsproj]
  Paket version 5.189.1
  Paket version 5.189.1
  Stacktrace:
  Stacktrace:
  
  
    at <unknown> <0xffffffff>
    at <unknown> <0xffffffff>
  
  
  Unhandled Exception:
  Unhandled Exception:
  System.NullReferenceException: Object reference not set to an instance of an object
  System.NullReferenceException: Object reference not set to an instance of an object
  [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
  [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
/home/vadim/projects/falanx/.paket/Paket.Restore.targets(91,5): error MSB3073: The command "mono --runtime=v4.0.30319 "/home/vadim/projects/falanx/.paket/paket.exe" restore" exited with code 1. [/home/vadim/projects/falanx/Falanx.Proto.Codec.Binary/Falanx.Proto.Codec.Binary.fsproj]
/home/vadim/projects/falanx/.paket/Paket.Restore.targets(91,5): error MSB3073: The command "mono --runtime=v4.0.30319 "/home/vadim/projects/falanx/.paket/paket.exe" restore" exited with code 1. [/home/vadim/projects/falanx/Falanx.Proto.Codec.Json/Falanx.Proto.Codec.Json.fsproj]
  Paket version 5.189.1

Environement (please complete the following information):

  • OS: linux:
$ lsb_release -irc
Distributor ID:	LinuxMint
Release:	18.3
Codename:	sylvia
  • Framework [e.g. netstandard2.0, net461]
$ dotnet --list-sdks
2.0.2 [/usr/share/dotnet/sdk]
2.1.500 [/usr/share/dotnet/sdk]

In a proto message a map followed by a primitive causes an exception

syntax = "proto3";

message SomeMessage {
    int64 id = 1;
}

message SomeMessageWithMap {
    int64 aField = 1;
    map<string, SomeMessage> some_map = 2;
    string anotherField = 3;
    
}
An error occurred while generating type for message SomeMessageWithMap: System.ArgumentException: Type mismatch when building 'recd': incorrect argument type for an F# record. Expected 'Microsoft.FSharp.Core.FSharpOption`1[System.String]', but received type 'System.Collections.Generic.Dictionary`2[System.String,test.TypeContainer+SomeMessage]'.
Parameter name: receivedType
   at Microsoft.FSharp.Quotations.PatternsModule.checkTypesSR[a](Type expectedType, Type receivedType, a name, String threeHoleSR)
   at Microsoft.FSharp.Quotations.PatternsModule.mkNewRecord@771.Invoke(PropertyInfo minfo, FSharpExpr a)
   at Microsoft.FSharp.Collections.ListModule.loop@192-27[T1,T2](FSharpFunc`3 f, FSharpList`1 list1, FSharpList`1 list2)
   at Microsoft.FSharp.Collections.ListModule.Iterate2[T1,T2](FSharpFunc`2 action, FSharpList`1 list1, FSharpList`1 list2)
   at Microsoft.FSharp.Quotations.PatternsModule.mkNewRecord(Type ty, FSharpList`1 args)
   at Falanx.Proto.Core.JsonCodec.createLambdaRecord(TypeDescriptor typeDescriptor) in falanx/src/Falanx.Proto.Core/JsonCodec/Codec.fs:line 53
   at Falanx.Proto.Core.JsonCodec.createJsonObjCodec(TypeDescriptor typeDescriptor) in falanx/src/Falanx.Proto.Core/JsonCodec/Codec.fs:line 432
   at [email protected](Codec codec) in falanx/src/Falanx.Proto.Generator/TypeGeneration.fs:line 289
   at Microsoft.FSharp.Collections.SetTreeModule.iter[a](FSharpFunc`2 f, SetTree`1 t)
   at Falanx.Proto.Generator.TypeGeneration.createType(ProvidedTypeDefinition container, String scope, FSharpMap`2 lookup, FSharpSet`1 codecs, ProtoMessage message) in falanx/src/Falanx.Proto.Generator/TypeGeneration.fs:line 261

generated file use random id for bindings name

The bindings names used like _bind_754d7b7c1ddf4d16a99f99034f7fee2e can change, also if .proto file content is the same.

That's annoying when the generated files are added to source control

To Reproduce

Regenerate the files, when .proto content is the same

Expected behavior

no diff

Actual

the bindings names, like _bind_754d7b7c1ddf4d16a99f99034f7fee2e, are changed

        |> fun f -> 
            Fleece.Newtonsoft.withFields<Option<String> -> Option<String> -> Option<Double> -> Option<String> -> Option<String> -> Option<Int32> -> ItemLevelOrderHistory, IReadOnlyDictionary<String, JToken>, Fleece.Newtonsoft.DecodeError, ItemLevelOrderHistory, String, JToken> 
                (f)
        |> fun codec -> 
            let decode =
                let _bind_754d7b7c1ddf4d16a99f99034f7fee2e, _ = codec
                _bind_754d7b7c1ddf4d16a99f99034f7fee2e
            
            let encode =
                let _, _bind_ed4f1b694ded4aa08c6d71c7fac6845a = codec
                _bind_ed4f1b694ded4aa08c6d71c7fac6845a

Fantomas 2.9.1 breaks code generation

Describe the bug
cc @7sharp9 I am quite sure Fantomas is the culprit, but would like a confirmation from you to make sure there is no stalled package caching issue on my end.

Fantomas has no version constraint and has been locked in my branch to 2.9.1 instead of 2.9 as in master branch. It seems, such change breaks binary code generation. All alignments are off.

To Reproduce
Update paket.dependencies to nuget Fantomas == 2.9.1, do paket update and make sure that paked.lock has been updated fantomas.
Regenerate simplest schema with both json and binary serializers:

syntax = "proto3";

message ItemLevelOrderHistory {
  string client_id = 1;
  string retail_sku_id = 2;
  double category_id = 3;
  string brand = 4;
  string product = 5;
  float order_tss = 6;
}

Observe misaligned and non-compilable fs code (see at the end of the file):

namespace rec amnesiac

open System
open System.Collections.Generic
open Froto.Serialization
open Falanx.Proto.Codec.Binary
open Falanx.Proto.Codec.Binary.Primitives
open Newtonsoft.Json.Linq
open Fleece.Newtonsoft

[<CLIMutable>]
type ItemLevelOrderHistory =
    { mutable clientId : string option
      mutable retailSkuId : string option
      mutable categoryId : float option
      mutable brand : string option
      mutable product : string option
      mutable orderTss : float32 option }

    static member JsonObjCodec =
        fun clientId retailSkuId categoryId brand product orderTss ->
            { clientId = clientId
              retailSkuId = retailSkuId
              categoryId = categoryId
              brand = brand
              product = product
              orderTss = orderTss } : ItemLevelOrderHistory
        |> fun f ->
            Fleece.Newtonsoft.withFields<Option<String> -> Option<String> -> Option<Double> -> Option<String> -> Option<String> -> Option<Single> -> ItemLevelOrderHistory, IReadOnlyDictionary<String, JToken>, String, ItemLevelOrderHistory, String, JToken>
                (f)
        |> fun codec ->
            let decode =
                let _bind_f51abf1077e6456fb4a02f1268668e44, _ = codec in _bind_f51abf1077e6456fb4a02f1268668e44

            let encode =
                let _, _bind_f2bf7da83028415d8f61ab20ed413d52 = codec in _bind_f2bf7da83028415d8f61ab20ed413d52

            Fleece.Newtonsoft.jfieldOpt<ItemLevelOrderHistory, String, Option<String> -> Option<Double> -> Option<String> -> Option<String> -> Option<Single> -> ItemLevelOrderHistory>
                ("clientId") (fun x -> x.clientId) (decode, encode)
        |> fun codec ->
            let decode =
                let _bind_64c47fa0947d41c69a029cf384b7735d, _ = codec in _bind_64c47fa0947d41c69a029cf384b7735d

            let encode =
                let _, _bind_2e85977edcc6489d865d26ec19597bf5 = codec in _bind_2e85977edcc6489d865d26ec19597bf5

            Fleece.Newtonsoft.jfieldOpt<ItemLevelOrderHistory, String, Option<Double> -> Option<String> -> Option<String> -> Option<Single> -> ItemLevelOrderHistory>
                ("retailSkuId") (fun x -> x.retailSkuId) (decode, encode)
        |> fun codec ->
            let decode =
                let _bind_6894c9159daf4018a31a90c9833a8405, _ = codec in _bind_6894c9159daf4018a31a90c9833a8405

            let encode =
                let _, _bind_238da84697cd48cf86466368de0f4600 = codec in _bind_238da84697cd48cf86466368de0f4600

            Fleece.Newtonsoft.jfieldOpt<ItemLevelOrderHistory, Double, Option<String> -> Option<String> -> Option<Single> -> ItemLevelOrderHistory>
                ("categoryId") (fun x -> x.categoryId) (decode, encode)
        |> fun codec ->
            let decode =
                let _bind_74ddc87304bc4e8489d78066f700a51f, _ = codec in _bind_74ddc87304bc4e8489d78066f700a51f

            let encode =
                let _, _bind_ee3a6a24482d429cb3bf441b6ddc632a = codec in _bind_ee3a6a24482d429cb3bf441b6ddc632a

            Fleece.Newtonsoft.jfieldOpt<ItemLevelOrderHistory, String, Option<String> -> Option<Single> -> ItemLevelOrderHistory>
                ("brand") (fun x -> x.brand) (decode, encode)
        |> fun codec ->
            let decode =
                let _bind_77e6ee5133564ebb8e46ba8b43910660, _ = codec in _bind_77e6ee5133564ebb8e46ba8b43910660

            let encode =
                let _, _bind_dea5f0fa500a4123b7af3af31cf39176 = codec in _bind_dea5f0fa500a4123b7af3af31cf39176

            Fleece.Newtonsoft.jfieldOpt<ItemLevelOrderHistory, String, Option<Single> -> ItemLevelOrderHistory>
                ("product") (fun x -> x.product) (decode, encode)
        |> fun codec ->
            let decode =
                let _bind_4f0417a92ab14c8ca420979d5204e65a, _ = codec in _bind_4f0417a92ab14c8ca420979d5204e65a

            let encode =
                let _, _bind_b5af5897c4004ea780dcea10e1cf8438 = codec in _bind_b5af5897c4004ea780dcea10e1cf8438

            Fleece.Newtonsoft.jfieldOpt<ItemLevelOrderHistory, Single, ItemLevelOrderHistory> ("orderTss")
                (fun x -> x.orderTss) (decode, encode)

    static member Serialize(m : ItemLevelOrderHistory, buffer : ZeroCopyBuffer) =
        Primitives.writeOption<String> (Primitives.writeString) (1) (buffer) (m.clientId)
        Primitives.writeOption<String> (Primitives.writeString) (2) (buffer) (m.retailSkuId)
        Primitives.writeOption<Double> (Primitives.writeDouble) (3) (buffer) (m.categoryId)
        Primitives.writeOption<String> (Primitives.writeString) (4) (buffer) (m.brand)
        Primitives.writeOption<String> (Primitives.writeString) (5) (buffer) (m.product)
        Primitives.writeOption<Single> (Primitives.writeFloat) (6) (buffer) (m.orderTss)

    static member Deserialize(buffer : ZeroCopyBuffer) = Primitives.deserialize<ItemLevelOrderHistory> (buffer)
    interface IMessage with
        member x.Serialize(buffer : ZeroCopyBuffer) = ItemLevelOrderHistory.Serialize(x, buffer)

        member x.ReadFrom(buffer : ZeroCopyBuffer) =
            let enumerator : IEnumerator<Froto.Serialization.Encoding.RawField> =
                ZeroCopyBuffer.allFields(buffer).GetEnumerator() in while enumerator.MoveNext() do
                                                                        let current : Froto.Serialization.Encoding.RawField =
                                                                            enumerator.Current in if current.FieldNum = 6 then
                                                                                                      x.orderTss <- (Some
                                                                                                                         (Primitives.readFloat
                                                                                                                              current) : Option<Single>)
                                                                                                  else if current.FieldNum = 5 then
                                                                                                      x.product <- (Some
                                                                                                                        (Primitives.readString
                                                                                                                             current) : Option<String>)
                                                                                                  else if current.FieldNum = 4 then
                                                                                                      x.brand <- (Some
                                                                                                                      (Primitives.readString
                                                                                                                           current) : Option<String>)
                                                                                                  else if current.FieldNum = 3 then
                                                                                                      x.categoryId <- (Some
                                                                                                                           (Primitives.readDouble
                                                                                                                                current) : Option<Double>)
                                                                                                  else if current.FieldNum = 2 then
                                                                                                      x.retailSkuId <- (Some
                                                                                                                            (Primitives.readString
                                                                                                                                 current) : Option<String>)
                                                                                                  else if current.FieldNum = 1 then
                                                                                                      x.clientId <- (Some
                                                                                                                         (Primitives.readString
                                                                                                                              current) : Option<String>)
                                                                                                  else ()
                                                                    enumerator.Dispose()

        member x.SerializedLength() = Primitives.serializedLength<ItemLevelOrderHistory> (x)

Proto file is not re-generated

Describe the bug
Sometimes proto files are not re-generated.

To Reproduce
Steps to reproduce the behavior:
I've opened example-sdk/example2 solution and compiled it. Then added a field to bundle.proto and recompiled project. I've got an error about missing member as expected, because I have not corrected .cs code. Then I've removed the filed I've added to proto file (i.e. restored original .proto) and recompiled the project. Error remained and output suggested proto file was not recompiled.

Expected behavior
Proto file should be recompiled and error should be gone.

Environement (please complete the following information):

  • OS: windows
  • Framework dotnetcore-2.1

Enum with duplicate value produced code with duplicates

Given the following proto:

// Test an enum that has multiple values with the same number.
enum TestEnumWithDupValue {
  TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED = 0;
  option allow_alias = true;

  FOO1 = 1;
  BAR1 = 2;
  BAZ = 3;
  FOO2 = 1;
  BAR2 = 2;
}

This code is generated:

type TestEnumWithDupValue =
    | TestEnumWithDupValueUnspecified = 0
    | Foo1 = 1
    | Bar1 = 2
    | Baz = 3
    | Foo2 = 1
    | Bar2 = 2

We need to check what behaviour should happen on this error/failure etc.

Remove extra lambda call on Fleece generation

Currently on generating the following is created:

    fun url title -> 
        { url = url
          title = title } 
    |> fun f -> withFields (f)
    |> fun codec -> 
        let decode = fst codec
        let encode = snd codec
        jfieldOpt ("url") (fun x -> x.url) (decode, encode)
    |> fun codec -> 
        let decode = fst codec
        let encode = snd codec
        jfieldOpt ("url") (fun x -> x.title) (decode, encode)

Notice the extra lambda:

    |> fun f -> withFields (f)

Generated file doesnt appear in VS project explorer

Generated file doesnt appear in VS project explorer

How to reproduce

  1. launch Visual Studio
  2. open example-sdk\example2\Example2.sln
  3. run the build of the solution, it succeed
  4. intellisense work
  5. but l1.Contract project doesnt show the generated file

image

Expected behavior

The generated file is shown in the project explorer

Environment

Microsoft Visual Studio Enterprise 2017 
Version 15.7.5
VisualStudio.15.Release/15.7.5+27703.2042
Microsoft .NET Framework
Version 4.7.02556

Installed Version: Enterprise

NuGet Package Manager   4.6.0
NuGet Package Manager in Visual Studio. For more information about NuGet, visit http://docs.nuget.org/.

Visual F# Tools 10.1 for F# 4.1   15.7.0.0.  Commit Hash: 173513e369ffb7a1c4d5dccf83696d9aac2ab2d0.
Microsoft Visual F# Tools 10.1 for F# 4.1

support package directive

Is your feature request related to a problem? Please describe.
proto's package Sample.Messaging; directive currently stops the codegen output w/o any error.
No code is emitted beyond the namespace/open statements.

Describe the solution you'd like
Error out until the package directive can be supported. Once supported open a namespace using the name provided for the types following the directive.

Describe alternatives you've considered
Remove the directive.

Additional context
n/a.

Field ordering test produces out of ordered assignments in json

Given test:

// We list fields out of order, to ensure that we're using field number and not
// field index to determine serialization order.
message TestFieldOrderings {
  string my_string = 11;
  int64 my_int = 1;
  float my_float = 101;
  message NestedMessage {
    int64 oo = 2;
    // The field name "b" fails to compile in proto1 because it conflicts with
    // a local variable named "b" in one of the generated methods.  Doh.
    // This file needs to compile in proto1 to test backwards-compatibility.
    int32 bb = 1;
  }

  NestedMessage single_nested_message  = 200;
}

Produces this invalid json code:

module TestFieldOrderings =
    [<CLIMutable>]
    type NestedMessage =
        { mutable oo : int64 option
          mutable bb : int option }

        static member JsonObjCodec =
            fun (bb : option<Int32>) (oo : option<Int64>) ->
                { oo = bb
                  bb = oo } : TestFieldOrderings.NestedMessage
            |> fun (f : option<Int32> -> option<Int64> -> TestFieldOrderings.NestedMessage) ->
                Fleece.Newtonsoft.withFields<option<Int32> -> option<Int64> -> TestFieldOrderings.NestedMessage, IReadOnlyDictionary<String, JToken>, Fleece.Newtonsoft.DecodeError, TestFieldOrderings.NestedMessage, String, JToken>
                    (f)
            |> fun (codec : (IReadOnlyDictionary<String, JToken> -> Result<option<Int32> -> option<Int64> -> TestFieldOrderings.NestedMessage, Fleece.Newtonsoft.DecodeError>) * (TestFieldOrderings.NestedMessage -> IReadOnlyDictionary<String, JToken>)) ->
                let decode : IReadOnlyDictionary<String, JToken> -> Result<option<Int32> -> option<Int64> -> TestFieldOrderings.NestedMessage, Fleece.Newtonsoft.DecodeError> =
                    let _bind_72, _ = codec
                    _bind_72

                let encode : TestFieldOrderings.NestedMessage -> IReadOnlyDictionary<String, JToken> =
                    let _, _bind_73 = codec
                    _bind_73

                Fleece.Newtonsoft.jfieldOpt<TestFieldOrderings.NestedMessage, Int32, option<Int64> -> TestFieldOrderings.NestedMessage>
                    ("bb") (fun (x : TestFieldOrderings.NestedMessage) -> x.bb) (decode, encode)
            |> fun (codec : (IReadOnlyDictionary<String, JToken> -> Result<option<Int64> -> TestFieldOrderings.NestedMessage, Fleece.Newtonsoft.DecodeError>) * (TestFieldOrderings.NestedMessage -> IReadOnlyDictionary<String, JToken>)) ->
                let decode : IReadOnlyDictionary<String, JToken> -> Result<option<Int64> -> TestFieldOrderings.NestedMessage, Fleece.Newtonsoft.DecodeError> =
                    let _bind_74, _ = codec
                    _bind_74

                let encode : TestFieldOrderings.NestedMessage -> IReadOnlyDictionary<String, JToken> =
                    let _, _bind_75 = codec
                    _bind_75

                Fleece.Newtonsoft.jfieldOpt<TestFieldOrderings.NestedMessage, Int64, TestFieldOrderings.NestedMessage>
                    ("oo") (fun (x : TestFieldOrderings.NestedMessage) -> x.oo) (decode, encode)

Do not display "usage" when error in protobuf file

Describe the bug
Compile protobuf file which contains error (is invalid protobuf file). Along with protobuf syntax error there will be shown "usage" screen. This is confusing because makes user believe that something in command line was wrong.

Expected behavior
Only protobuf syntax error with line number should be shown. No exception stack trace or "usage" screen.

ProtoFile as collection

Is your feature request related to a problem? Please describe.
Having multiple ProtoFile entries (or multiple results from Include specifying a pattern) currently results in the error:

Could not find a part of the path 'file1.proto;file2.proto'.

Describe the solution you'd like
Handle the individual items in the collection instead of assuming it's a single file.

Describe alternatives you've considered
Project-per-proto might work, but I think it's too much overhead.

Additional context
n/a.

Poor error message

If the tool fails, the error message does not contain any tips what went wrong:

Falanx.Sdk.targets(70, 5): [MSB3073] The command "dotnet "..\packages\falanx.sdk\0.5.0\build../tools/netcoreapp2.1/any/falanx.dll" --inputfile "..1.proto" --outputfile "..\1.proto.fs" --defaultnamespace "Foo" --serializer binary" exited with code 1.

Tests do not run

Describe the bug
dotnet test Falanx.sln fail

To Reproduce
dotnet test Falanx.sln produce error (see also environment):

System.IO.FileNotFoundException: Unable to find tests for C:\Users\vadym.chekan\source\repos\falanx_upstream\test\Falanx.IntegrationTests\bin\Debug\netcoreapp2.1\Falanx.IntegrationTests.dll. Make sure test project has a nuget reference of package "Microsoft.NET.Test.Sdk" and framework version settings are appropriate. Rerun with /diag option to diagnose further.
   at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager.GetTestHostProcessStartInfo(IEnumerable`1 sources, IDictionary`2 environmentVariables, TestRunnerConnectionInfo connectionInfo)
   at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyOperationManager.SetupChannel(IEnumerable`1 sources)
   at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyExecutionManager.StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsHandler eventHandler)

Test Run Aborted.

Environement (please complete the following information):

  • OS: windows; mingw64 bash
  • Framework dotnetcore-2.1

Rider intellisense doesnt work

affect v0.2.0

How to reproduce

  1. launch Jetbrains Rider
  2. open example-sdk\example2\Example2.sln
  3. run the build of the solution, it succeed
  4. intellisense doesnt work

reopening the solution doesnt affect the intellisense

image

Expected behavior

Intellisense works.
No items in the project explorer (it's a known bug in VS too #27 but doesnt affect the fsc args)

Environment

JetBrains Rider 2018.2.3
Build #RD-182.4231.496, built on September 13, 2018
JRE: 1.8.0_152-release-1248-b8 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

Do not publish every project as nuget package

Is your feature request related to a problem? Please describe.
We publish 7 nuget packages, which does not make sense because most projects are not standalone and make sense only as part of Falanx.Tool project. Instead we should publish 2 project: development dependecies, i.e. command line tool and runtime dependency (if any).

Describe the solution you'd like
Runtime dependency should not include dependencies which make sense for protobuf compiling stage.

Is there a way to import well known types?

If I have import "google/protobuf/timestamp.proto"; in my proto file to use the TimeStamp type, I'm getting an error in the converter that it cannot find the file. Is this supported? I just tried falanx as a global tool, not sure if that matters.

Single nested enum fails due to no support in fleece

  enum NestedEnum {
    NESTED_ENUM_UNSPECIFIED = 0;
    FOO = 1;
    BAR = 2;
    BAZ = 3;
    NEG = -1;  // Intentionally negative.
  }

Results in:

    type NestedEnum =
        | NestedEnumUnspecified = 0
        | Foo = 1
        | Bar = 2
        | Baz = 3
        | Neg = -1

...
type TestAllTypes =
    { mutable singleInt32 : int option
      mutable singleInt64 : int64 option
      mutable singleUint32 : UInt32 option
      mutable singleUint64 : UInt64 option
      mutable singleSint32 : int option
      mutable singleSint64 : int64 option
      mutable singleFixed32 : UInt32 option
      mutable singleFixed64 : UInt64 option
      mutable singleSfixed32 : int option
      mutable singleSfixed64 : int64 option
      mutable singleFloat : float32 option
      mutable singleDouble : float option
      mutable singleBool : bool option
      mutable singleString : string option
      mutable singleBytes : ArraySegment<Byte> option
      mutable singleNestedMessage : TestAllTypes.NestedMessage option
...
            Fleece.Newtonsoft.jfieldOpt<TestAllTypes, TestAllTypes.NestedEnum, option<List<Int32>> -> option<List<Int64>> -> option<List<UInt32>> -> option<List<UInt64>> -> option<List<Int32>> -> option<List<Int64>> -> option<List<UInt32>> -> option<List<UInt64>> -> option<List<Int32>> -> option<List<Int64>> -> option<List<Single>> -> option<List<Double>> -> option<List<Boolean>> -> option<List<String>> -> TestAllTypes>
                ("singleNestedEnum") (fun x -> x.singleNestedEnum) (decode, encode)
0>/Users/dave.thomas/Documents/GitHub/falanx/test/Falanx.Tests/schemas/falanx_test.proto.fs(319,13): Error FS0001 : No overloads match for method 'ToJson'. The available overloads are shown below.
0>Possible overload: 'static member ToJson.ToJson : x:bool * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'bool'    �.
0>Possible overload: 'static member ToJson.ToJson : x:string * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'string'    �.
0>Possible overload: 'static member ToJson.ToJson : x:DateTime * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'DateTime'    �.
0>Possible overload: 'static member ToJson.ToJson : x:DateTimeOffset * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'DateTimeOffset'    �.
0>Possible overload: 'static member ToJson.ToJson : x:decimal * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'decimal'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Double * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Double'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Single * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Single'    �.
0>Possible overload: 'static member ToJson.ToJson : x:int * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'int'    �.
0>Possible overload: 'static member ToJson.ToJson : x:uint32 * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'uint32'    �.
0>Possible overload: 'static member ToJson.ToJson : x:int64 * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'int64'    �.
0>Possible overload: 'static member ToJson.ToJson : x:uint64 * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'uint64'    �.
0>Possible overload: 'static member ToJson.ToJson : x:int16 * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'int16'    �.
0>Possible overload: 'static member ToJson.ToJson : x:uint16 * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'uint16'    �.
0>Possible overload: 'static member ToJson.ToJson : x:byte * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'byte'    �.
0>Possible overload: 'static member ToJson.ToJson : x:sbyte * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'sbyte'    �.
0>Possible overload: 'static member ToJson.ToJson : x:char * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'char'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Guid * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Guid'    �.
0>Possible overload: 'static member ToJson.ToJson : unit * ToJson -> JToken'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'unit'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Choice< ^a, ^b> * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue) and (ToJson or  ^b) : (static member ToJson :  ^b * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Choice<'a,'b>'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Choice< ^a, ^b, ^c> * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue) and (ToJson or  ^b) : (static member ToJson :  ^b * ToJson -> JsonValue) and (ToJson or  ^c) : (static member ToJson :  ^c * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Choice<'a,'b,'c>'    �.
0>Possible overload: 'static member ToJson.ToJson : x: ^a option * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a option'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Nullable< ^a> * ToJson -> JsonValue when  ^a : (new : unit ->  ^a) and  ^a : struct and  ^a :> ValueType and (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Nullable<'a>'    �.
0>Possible overload: 'static member ToJson.ToJson : x: ^a list * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a list'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Set< ^a> * ToJson -> JToken when  ^a : comparison and (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Set<'a>'    �.
0>Possible overload: 'static member ToJson.ToJson : x: ^a array * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a array'    �.
0>Possible overload: 'static member ToJson.ToJson : x:ArraySegment< ^a> * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'ArraySegment<'a>'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Map<string, ^a> * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Map<string,'a>'    �.
0>Possible overload: 'static member ToJson.ToJson : x:Dictionary<string, ^a> * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'Dictionary<string,'a>'    �.
0>Possible overload: 'static member ToJson.ToJson : x:ResizeArray< ^a> * ToJson -> JToken when (ToJson or  ^a) : (static member ToJson :  ^a * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    'ResizeArray<'a>'    �.
0>Possible overload: 'static member ToJson.ToJson : x:( ^a0 *  ^a1) * ToJson -> JToken when (ToJson or  ^a0) : (static member ToJson :  ^a0 * ToJson -> JsonValue) and (ToJson or  ^a1) : (static member ToJson :  ^a1 * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a * 'b'    �.
0>Possible overload: 'static member ToJson.ToJson : x:( ^a0 *  ^a1 *  ^a2) * ToJson -> JToken when (ToJson or  ^a0) : (static member ToJson :  ^a0 * ToJson -> JsonValue) and (ToJson or  ^a1) : (static member ToJson :  ^a1 * ToJson -> JsonValue) and (ToJson or  ^a2) : (static member ToJson :  ^a2 * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a * 'b * 'c'    �.
0>Possible overload: 'static member ToJson.ToJson : x:( ^a0 *  ^a1 *  ^a2 *  ^a3) * ToJson -> JToken when (ToJson or  ^a0) : (static member ToJson :  ^a0 * ToJson -> JsonValue) and (ToJson or  ^a1) : (static member ToJson :  ^a1 * ToJson -> JsonValue) and (ToJson or  ^a2) : (static member ToJson :  ^a2 * ToJson -> JsonValue) and (ToJson or  ^a3) : (static member ToJson :  ^a3 * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a * 'b * 'c * 'd'    �.
0>Possible overload: 'static member ToJson.ToJson : x:( ^a0 *  ^a1 *  ^a2 *  ^a3 *  ^a4) * ToJson -> JToken when (ToJson or  ^a0) : (static member ToJson :  ^a0 * ToJson -> JsonValue) and (ToJson or  ^a1) : (static member ToJson :  ^a1 * ToJson -> JsonValue) and (ToJson or  ^a2) : (static member ToJson :  ^a2 * ToJson -> JsonValue) and (ToJson or  ^a3) : (static member ToJson :  ^a3 * ToJson -> JsonValue) and (ToJson or  ^a4) : (static member ToJson :  ^a4 * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a * 'b * 'c * 'd * 'e'    �.
0>Possible overload: 'static member ToJson.ToJson : x:( ^a0 *  ^a1 *  ^a2 *  ^a3 *  ^a4 *  ^a5) * ToJson -> JToken when (ToJson or  ^a0) : (static member ToJson :  ^a0 * ToJson -> JsonValue) and (ToJson or  ^a1) : (static member ToJson :  ^a1 * ToJson -> JsonValue) and (ToJson or  ^a2) : (static member ToJson :  ^a2 * ToJson -> JsonValue) and (ToJson or  ^a3) : (static member ToJson :  ^a3 * ToJson -> JsonValue) and (ToJson or  ^a4) : (static member ToJson :  ^a4 * ToJson -> JsonValue) and (ToJson or  ^a5) : (static member ToJson :  ^a5 * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a * 'b * 'c * 'd * 'e * 'f'    �.
0>Possible overload: 'static member ToJson.ToJson : x:( ^a0 *  ^a1 *  ^a2 *  ^a3 *  ^a4 *  ^a5 *  ^a6) * ToJson -> JToken when (ToJson or  ^a0) : (static member ToJson :  ^a0 * ToJson -> JsonValue) and (ToJson or  ^a1) : (static member ToJson :  ^a1 * ToJson -> JsonValue) and (ToJson or  ^a2) : (static member ToJson :  ^a2 * ToJson -> JsonValue) and (ToJson or  ^a3) : (static member ToJson :  ^a3 * ToJson -> JsonValue) and (ToJson or  ^a4) : (static member ToJson :  ^a4 * ToJson -> JsonValue) and (ToJson or  ^a5) : (static member ToJson :  ^a5 * ToJson -> JsonValue) and (ToJson or  ^a6) : (static member ToJson :  ^a6 * ToJson -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a * 'b * 'c * 'd * 'e * 'f * 'g'    �.
0>Possible overload: 'static member ToJson.ToJson : t: ^T * Fleece.Default5 -> JToken when  ^T : (static member get_JsonObjCodec : -> Codec<IReadOnlyDictionary<string,JsonValue>, ^T>)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a'    �.
0>Possible overload: 'static member ToJson.ToJson : t: ^T * Fleece.Default4 -> JToken when  ^T : (static member get_JsonObjCodec : -> ConcreteCodec<KeyValuePair<string,JToken> list,KeyValuePair<string,JToken> list,'a1, ^T>)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a'    �.
0>Possible overload: 'static member ToJson.ToJson : t: ^T * Fleece.Default3 -> JsonValue when  ^T : (static member ToJSON :  ^T -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a'    �.
0>Possible overload: 'static member ToJson.ToJson : t: ^T * Fleece.Default2 -> JsonValue when  ^T : (static member ToJson :  ^T -> JsonValue)'. Type constraint mismatch. The type �    'TestAllTypes.NestedEnum'    �is not compatible with type�    ''a'    �.

Compiler Warnings with

Describe the bug
F# record type has compiler warnings with version Falanx.Sdk 0.4.0-alpha2.

warning FS0686: The method or function 'jfieldOpt' should not be given explicit type argument(s) because it does not declare its type parameters explicitly

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior

Environement (please complete the following information):

  • OS: osx
  • Framework: netstandard2.0, net462

Additional context
Add any other context about the problem here.

Running falanx on a proto file with a map in it fails with error

An error occurred while generating type for message SomeMessageWithMap: System.ArgumentException: Incompatible record length
Parameter name: args
   at Microsoft.FSharp.Quotations.PatternsModule.mkNewRecord(Type ty, FSharpList`1 args)
   at Falanx.Proto.Core.JsonCodec.createLambdaRecord(TypeDescriptor typeDescriptor) in falanx/src/Falanx.Proto.Core/JsonCodec/Codec.fs:line 53
   at Falanx.Proto.Core.JsonCodec.createJsonObjCodec(TypeDescriptor typeDescriptor) in falanx/src/Falanx.Proto.Core/JsonCodec/Codec.fs:line 433
   at [email protected](Codec codec) in falanx/src/Falanx.Proto.Generator/TypeGeneration.fs:line 281
   at Microsoft.FSharp.Collections.SetTreeModule.iter[a](FSharpFunc`2 f, SetTree`1 t)
   at Falanx.Proto.Generator.TypeGeneration.createType(ProvidedTypeDefinition container, String scope, FSharpMap`2 lookup, FSharpSet`1 codecs, ProtoMessage message) in falanx/src/Falanx.Proto.Generator/TypeGeneration.fs:line 253

The generator fail on maps where the value is a message

To Reproduce
Steps to reproduce the behavior:

  1. Run the tool on this proto file :
    syntax = "proto3";
    
    message SomeMessage {
        int64 id = 1;
    }
    
    message SomeMessageWithMap {
        map<string, SomeMessage> some_map = 1;
    }
  2. See the Unable to cast object of type 'Downcast' to type 'InferredUpcast'. error.

Additional context

Tested on master

Add .net <-> scala to test suite

add a test to check interop between .net (falanx) and scala, using same contract and default generator for scala.

both program will use same proto file, and will serialize and deserialize to a file.

like

  1. .net (falanx) serialize
  2. scala (scalapb) deserialize the message
  3. scala (scalapb) serialize the same message
  4. .net (falanx) deserialize the message

Schema compile error does not cause build to fail

Describe the bug
When there is an error in schema, msbuild by default does not check error code of Exec command and as result, compiler will fail with semi-random error, which makes it hard to troubleshoot.

To Reproduce
Delete .fs file.
Make intentional syntax error in .proto file.
Compile and observe error saying that .fs file is missing.

Expected behavior
Error should should indicate that failure happen in schema compilation and not in .fs file compilation.

template on unix fails tests

the template package generated on unix fails the integration tests

During template package install (dotnet new -i)

Error reading template from file: /ClassLibrary-FSharp/.template.config/template.json | Error = After parsing a value an unexpected character was encountered: a. Path 'symbols.FalanxJsonCodec.value', line 62, position 40.

To Reproduce

run the template integration tests on unix

Environement

  • OS: unix azure pipelines, on windows is ok

Additional context

on windows works

update froto

In the last froto version was fixed a couple of bugs. Would it be possible to release also a new version of falanx? One of this bugfixes would allow for our project to use falanx instead of a c# project.

`oneof` sub-messages

Is your feature request related to a problem? Please describe.
oneof messages defined like this currently fail to codegen:

message Poll {
}

message Discover {
}

message Command {
  oneof sub {
    Poll poll = 1;
    Discover discover = 2;
  }
}

Failed to serialize property Item: Poll. Error: System.Exception: Void writeEmbedded(Int32, Froto.Serialization.ZeroCopyBuffer, Falanx.BinaryCodec.IMessage) is not generic
at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1645.Invoke(String message)
at Falanx.BinaryGenerator.Serialization.serializeProperty(FSharpExpr buffer, FSharpExpr this, PropertyDescriptor prop)

Describe the solution you'd like
It's a perfectly valid construct and should be supported.

Describe alternatives you've considered
Can't think of any.

Additional context
n/a.

The F# record type produced by proto file has recursive namespace statement

Describe the bug

I am using the Falanx.Sdk 0.4.0-alpha2 and the produced F# record type module has recursive namespace statement.

This is not a bug per se, but for our projects, we use multiple files that share a common namespace. If we were to use recursive namespaces across all of our protobuff generated record types, that may remove the dependency order that is enforced on the namespace itself.

Actual behavior
This is what we see in the namespace definition of the produced F# record type

namespace rec ProfX.SearchApi

open System
open System.Collections.Generic
open Newtonsoft.Json.Linq
open Fleece.Newtonsoft

Environment (please complete the following information):

  • OS: osx
  • Framework: netstandard2.0, net462

Additional context

Usage of external project resources

Describe the bug
There are 2 resources used in paket.dependencies as github urls. This is not desirable as we do not have control over those and they can be removed any time and will break project.

github 7sharp9/FSharp.TypeProviders.SDK:generator src/ProvidedTypes.fs 
github 7sharp9/FSharp.TypeProviders.SDK:generator src/ProvidedTypesTesting.fs 
...
github enricosada/dotnet-proj-info test/dotnet-proj.Tests/FileUtils.fs

Expected behavior
If we use dependencies, it is better to relay on nuget packages which have much stricter removal rules.

Example README is incorrect due to missing a missing tools folder and/or steps

Describe the bug
The example describes cd tools, but no tools folder has been committed.

To Reproduce
Steps to reproduce the behavior:

  1. Clone repository
  2. cd example
  3. List files and folders
  4. See there is no tools folder
  5. dotnet restore fails as it cannot find a project or solution file

Expected behavior
The example README should describe a successful path to running the example.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.