Giter Site home page Giter Site logo

elm-ts-json's People

Contributors

dillonkearns avatar hansallis avatar jfmengels avatar pabra 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

Watchers

 avatar  avatar  avatar

elm-ts-json's Issues

ToElm type not generating

Hi here, the CLI does not generate the ToElm type for my code.

Heres my Definitions file:

module PortDefinition exposing (Flags, FromElm(..), ToElm(..), interop)

import TsJson.Decode as TsDecode exposing (Decoder)
import TsJson.Encode as TsEncode exposing (Encoder)


interop :
    { toElm : Decoder ToElm
    , fromElm : Encoder FromElm
    , flags : Decoder Flags
    }
interop =
    { toElm = toElm
    , fromElm = fromElm
    , flags = flags
    }


type FromElm
    = RegisterSounds (List Sound)
    | PlaySound { sound : Sound, looping : Bool }


type ToElm
    = SoundEnded Sound


type alias Flags =
    {}


fromElm : Encoder FromElm
fromElm =
    TsEncode.union
        (\playSound registerSounds value ->
            case value of
                RegisterSounds list ->
                    registerSounds list

                PlaySound args ->
                    playSound args
        )
        |> TsEncode.variantTagged "playSound"
            (TsEncode.object
                [ TsEncode.required "sound" (\obj -> obj.sound |> toString) TsEncode.string
                , TsEncode.required "looping" .looping TsEncode.bool
                ]
            )
        |> TsEncode.variantTagged "registerSounds"
            (TsEncode.list (TsEncode.string |> TsEncode.map toString))
        |> TsEncode.buildUnion


toElm : Decoder ToElm
toElm =
    TsDecode.discriminatedUnion "type"
        [ ( "soundEnded"
          , TsDecode.string
                |> TsDecode.andThen
                    (TsDecode.andThenInit
                        (\string ->
                            string
                                |> fromString
                                |> Maybe.map (\sound -> SoundEnded sound |> TsDecode.succeed)
                                |> Maybe.withDefault (TsDecode.fail ("Unkown sound ended: " ++ string))
                        )
                    )
          )
        ]


flags : Decoder Flags
flags =
    TsDecode.null {}



--------------------------------------
-- Sound.elm
--------------------------------------


{-| Reprentation of Sound
-}
type Sound
    = ClickButton


{-| List of all playable sounds
-}
asList : List Sound
asList =
    [ ClickButton ]


{-| returns the path to the sound
-}
toString : Sound -> String
toString sound =
    case sound of
        ClickButton ->
            "ClickButton.mp3"


fromString : String -> Maybe Sound
fromString string =
    case string of
        "ClickButton.mp3" ->
            Just ClickButton

        _ ->
            Nothing

Heres the result:

export type JsonObject = { [Key in string]?: JsonValue };
export type JsonArray = JsonValue[];

/**
Matches any valid JSON value.
Source: https://github.com/sindresorhus/type-fest/blob/master/source/basic.d.ts
*/
export type JsonValue =
  | string
  | number
  | boolean
  | null
  | JsonObject
  | JsonArray;

export interface ElmApp {
  ports: {
    interopFromElm: PortFromElm<FromElm>;
    interopToElm: PortToElm<ToElm>;
    [key: string]: UnknownPort;
  };
}

export type FromElm = { data : string[]; tag : "registerSounds" } | { data : { looping : boolean; sound : string }; tag : "playSound" };

export type ToElm = never;

export type Flags = null;

export namespace Main {
  function init(options: { node?: HTMLElement | null; flags: Flags }): ElmApp;
}

export as namespace Elm;

export { Elm };

export type UnknownPort = PortFromElm<unknown> | PortToElm<unknown> | undefined;

export type PortFromElm<Data> = {
  subscribe(callback: (fromElm: Data) => void): void;
  unsubscribe(callback: (fromElm: Data) => void): void;
};

export type PortToElm<Data> = { send(data: Data): void };

As you can see ToElm = never instead of generating my type.

Im using elm-ts-interop v0.0.8 and dillonkearns/elm-ts-json v2.1.1.

Add support for int unions

Currently I use

TsJson.Codec.stringUnion
        [ ( "0", Reliable )
        , ( "1", Lossy )
        , ( "-1", Unrecognized )
        ]

to encode data for a JS library. The resulting type is "0" | "1" | "-1" and I have to call parseInt on the JS side to prepare data for the library. It would be nice to simply write

TsJson.Codec.intUnion
        [ ( 0, Reliable )
        , ( 1, Lossy )
        , ( -1, Unrecognized )
        ]

to get 0 | 1 | -1 type and avoid extra conversion on the JS side.

Use opaque type for andThen, allow succeed and fail

@neurodynamic thanks again for the feedback on the API.

To follow up on the Discourse discussion, I think it would make sense to use an opaque type like the UnionEncodeValue type.

The benefit is that the library then guarantees that all possible decoders that may continue on from the andThen have been "registered". Otherwise, you could use any decoder within the andThen as it is in its current state, and that will cause the decoder to have inaccurate type information.

Here's an example with the current API:

                field "version" int
                    |> andThen
                        (andThenInit
                            (\version ->
                                case version of
                                    1 ->
                                        field "firstName" string

                                    _ ->
                                        at [ "name", "first" ] string
                            )
                        )
                    |> expectDecodes
                        { input = """{"version": 2, "name": {"first": "Jane"}}"""
                        , output = "Jane"
                        , typeDef = "{ version : number }"

Note that the type def doesn't have any information about the firstName or name.first fields. This is inaccurate.

If you "register" the continuation decoders, as is intended, then you get nice, accurate TypeScript type information:

field "version" int
    |> andThen
        (andThenInit
            (\v1Decoder v2Decoder version ->
                case version of
                    1 ->
                        v1Decoder

                    _ ->
                        v2Decoder
            )
            |> andThenDecoder (field "firstName" string)
            |> andThenDecoder (at [ "name", "first" ] string)
        )
    |> expectDecodes
        { input = """{"version": 2, "name": {"first": "Jane"}}"""
        , output = "Jane"
        , typeDef = "({ version : number } & { name : { first : string } } | { firstName : string })"
        }

I think this is quite nice! The improvement here would be for the API to enforce using the API in this intended way.

Guaranteeing correct usage with opaque types

That's where the opaque type comes in. Right now, the continuation takes a TsJson.Decode.Decoder. If we require it to use a simple wrapper type around that type (let's call it AndThenDecoder), then we can guarantee that the only way to get that wrapped type is by passing it through andThenDecoder ....

type AndThenDecoder a = AndThenDecoder (Decoder a)

succeed and fail

I think these two types may be special cases. You can't "register" either of these with andThenDecoder, because that would force you to have the success value or failure message when you register it. But that defeats the purpose of andThen.

I think adding these functions to the API will solve that problem:

andThenSucceed : a -> AndThenDecoder a
andThenSucceed a =
    AndThenDecoder (succeed a)

andThenFail : String -> AndThenDecoder a
andThenFail errorMessage =
    AndThenDecoder (fail errorMessage)

As far as the resulting TypeScript type defs from a Decoder, using succeed or fail within andThen doesn't change that. So I think this design will work nicely!

Possible to define elm type and encoder & decoder from typescript?

Currently this library allow one to define typescript type and elm type and encoder & decoder from combinator (source code) written in elm.

Is there another way. That allow one to define elm type and encoder & decoder from typescript type (parse from source code) or combinator functions / ast written in typescript ?

'Elm' refers to a UMD global typescript error in generated file

The generated typescript file contains the following lines:

export as namespace Elm;

export { Elm };

which raises the following error when I try to build:

gen/mainBack.d.ts:36:10 - error TS2686: 'Elm' refers to a UMD global, but the current file is a module. Consider adding an import instead.

36 export { Elm };
            ~~~

removing this export {Elm } line makes Typescript happy.... Is it necessary to add this export { Elm } in the generated file? If yes, how could I solve this error and be able to build without performing a ugly sed?

missing quotes

If you have a custom type and Codec like this:

type MyType
    = MyType Int


codec : Codec MyType
codec =
    Codec.custom Nothing
        (\vMyType value ->
            case value of
                MyType int ->
                    vMyType int
        )
        |> Codec.namedVariant1 "MyType" MyType ( "needs-quotes", Codec.int )
        |> Codec.buildCustom

it will generate this TypeScript type (missing quotes around missing-quotes):

{ needs-quotes : number; tag : "MyType" }

here is an ellie

BTW: thanks for this project ๐Ÿ˜

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.