Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement intUnion #16

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions src/TsJson/Codec.elm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module TsJson.Codec exposing
, literal, stringLiteral
, maybe, list, array, dict, set, tuple, triple, result
, ObjectCodec, object, field, maybeField, nullableField, buildObject
, stringUnion
, stringUnion, intUnion
, CustomCodec, custom, buildCustom
, variant0
, namedVariant1, namedVariant2, namedVariant3, namedVariant4, namedVariant5, namedVariant6, namedVariant7, namedVariant8
Expand Down Expand Up @@ -53,7 +53,7 @@ This module is a port of [`miniBill/elm-codec`](https://package.elm-lang.org/pac

# Custom Types

@docs stringUnion
@docs stringUnion, intUnion

@docs CustomCodec, custom, buildCustom

Expand Down Expand Up @@ -497,6 +497,48 @@ stringUnion mappings =
}


{-| Simple one-to-one mapping of Elm values to TypeScript strings (no arguments, just like values like an enumeration).

import TsJson.Codec exposing (Codec)

type DarkMode
= Dark
| Light

darkModeCodec : Codec DarkMode
darkModeCodec =
Codec.intUnion [ ( 0, Dark ), ( 1, Light ) ]

The `TsType` for `darkModeCodec` is the following union:

```typescript
0 | 1
```

-}
intUnion : List ( Int, value ) -> Codec value
intUnion mappings =
let
unionDecoder : TsDecode.Decoder value
unionDecoder =
TsDecode.intUnion mappings
in
TsJson.Internal.Codec.Codec
{ encoder =
Encoder
(\decoded ->
case find mappings decoded of
Just gotValue ->
gotValue |> Encode.int

Nothing ->
Encode.null
)
(TsDecode.tsType unionDecoder)
, decoder = unionDecoder
}


{-| -}
literal : value -> Encode.Value -> Codec value
literal mappedValue literalValue =
Expand All @@ -515,7 +557,7 @@ stringLiteral mappedValue literalValue =
}


find : List ( String, value ) -> value -> Maybe String
find : List ( comparable, value ) -> value -> Maybe comparable
find mappings mappedValue =
case mappings of
( key, mapping ) :: rest ->
Expand Down
56 changes: 56 additions & 0 deletions src/TsJson/Decode.elm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module TsJson.Decode exposing
, map2, andMap
, literal, null
, stringLiteral, stringUnion
, intUnion
, discriminatedUnion
, andThen, AndThenContinuation, andThenInit, andThenDecoder
, value, unknownAndThen, maybe
Expand Down Expand Up @@ -125,6 +126,8 @@ TypeScript tuples are much like an Elm tuples, except two key differences:

@docs stringLiteral, stringUnion

@docs intUnion


## Discriminated Unions

Expand Down Expand Up @@ -620,6 +623,59 @@ stringUnion unionMappings =
)


{-| A convenience function for building a union out of int literals.

import TsJson.Decode as TsDecode

type Severity
= Info
| Warning
| Error

TsDecode.intUnion
[ ( 1, Info )
, ( 2, Warning )
, ( 3, Error )
]
|> TsDecode.runExample """1"""
--> { decoded = Ok Info
--> , tsType = "1 | 2 | 3"
--> }

-}
intUnion :
List ( Int, value )
-> Decoder value
intUnion unionMappings =
Decoder
(Decode.int
|> Decode.andThen
(\key ->
case unionMappings |> Dict.fromList |> Dict.get key of
Just mapped ->
Decode.succeed mapped

Nothing ->
Decode.fail <|
"I was expecting an int union with one of these string values: "
++ "[ "
++ (unionMappings
|> List.map (\( mapKey, _ ) -> "\"" ++ String.fromInt mapKey ++ "\"")
|> String.join ", "
)
++ " ]"
)
)
(TypeReducer.union
(unionMappings
|> List.map
(\( mapKey, _ ) ->
Literal (Encode.int mapKey)
)
)
)


{-| This type allows you to combine all the possible Decoders you could run in an [`andThen`](#andThen) continuation.

This API allows you to define all possible Decoders you might use up front, so that all possible TypeScript types
Expand Down
12 changes: 12 additions & 0 deletions tests/CodecBaseTests.elm
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,18 @@ customTests =
|> roundtripsTest "dark mode codec"
codec
"\"dark\" | \"light\""
, describe "intUnion" <|
let
codec : Codec DarkMode
codec =
TsCodec.intUnion [ ( 0, Dark ), ( 1, Light ) ]
in
[ ( "dark", Fuzz.constant Dark )
, ( "light", Fuzz.constant Light )
]
|> roundtripsTest "dark mode codec"
codec
"0 | 1"
, describe "literal" <|
let
codec : Codec String
Expand Down