{- | Pretty-printing functions for @Decoder.elm@ module.
Also contains decoders for common types which go to the @ElmStreet.elm@ module.
-}

module Elm.Print.Decoder
       ( prettyShowDecoder

         -- * Standard missing decoders
       , decodeEnum
       , decodeChar
       , decodeEither
       , decodePair
       , decodeTriple
       ) where

import Data.List.NonEmpty (toList)
import Data.Text (Text)
import Data.Text.Prettyprint.Doc (Doc, colon, concatWith, dquotes, emptyDoc, equals, line, nest,
                                  parens, pretty, surround, vsep, (<+>))

import Elm.Ast (ElmAlias (..), ElmConstructor (..), ElmDefinition (..), ElmPrim (..),
                ElmRecordField (..), ElmType (..), TypeName (..), TypeRef (..), isEnum)
import Elm.Print.Common (arrow, mkQualified, qualifiedTypeWithVarsDoc, showDoc, wrapParens)

import qualified Data.List.NonEmpty as NE
import qualified Data.Text as T


----------------------------------------------------------------------------
-- Decode
----------------------------------------------------------------------------

{- |

__Sum Types:__

Haskell type

@
type User
    = Foo
    | Bar String Int
@

Encoded JSON on Haskell side

@
    [ { "tag" : "Foo"
      }
    , { "tag" : "Bar"
      , "contents" : ["asd", 42, "qwerty"]
      }
    ]
@

Elm decoder

@
userDecoder : Decoder User
userDecoder =
    let decide : String -> Decoder User
        decide x = case x of
            \"Foo\" -> D.succeed Foo
            \"Bar\" -> D.field "contents" <| D.map2 Bar (D.index 0 D.string) (D.index 1 D.int)
            x -> D.fail <| "There is no constructor for User type:" ++ x
    in D.andThen decide (D.field "tag" D.string)
@

-}
prettyShowDecoder :: ElmDefinition -> Text
prettyShowDecoder :: ElmDefinition -> Text
prettyShowDecoder ElmDefinition
def = Doc Any -> Text
forall ann. Doc ann -> Text
showDoc (Doc Any -> Text) -> Doc Any -> Text
forall a b. (a -> b) -> a -> b
$ case ElmDefinition
def of
    DefAlias ElmAlias
elmAlias -> ElmAlias -> Doc Any
forall ann. ElmAlias -> Doc ann
aliasDecoderDoc ElmAlias
elmAlias
    DefType ElmType
elmType   -> ElmType -> Doc Any
forall ann. ElmType -> Doc ann
typeDecoderDoc ElmType
elmType
    DefPrim ElmPrim
_         -> Doc Any
forall ann. Doc ann
emptyDoc

aliasDecoderDoc :: ElmAlias -> Doc ann
aliasDecoderDoc :: ElmAlias -> Doc ann
aliasDecoderDoc ElmAlias{Bool
Text
NonEmpty ElmRecordField
elmAliasIsNewtype :: ElmAlias -> Bool
elmAliasFields :: ElmAlias -> NonEmpty ElmRecordField
elmAliasName :: ElmAlias -> Text
elmAliasIsNewtype :: Bool
elmAliasFields :: NonEmpty ElmRecordField
elmAliasName :: Text
..} =
    Text -> [Text] -> Doc ann
forall ann. Text -> [Text] -> Doc ann
decoderDef Text
elmAliasName []
    Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
line
    Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> if Bool
elmAliasIsNewtype
       then Doc ann
forall ann. Doc ann
newtypeDecoder
       else Doc ann
forall ann. Doc ann
recordDecoder
  where
    newtypeDecoder :: Doc ann
    newtypeDecoder :: Doc ann
newtypeDecoder = Doc ann
forall ann. Doc ann
name Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"D.map" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedAliasName
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder (TypeRef -> Doc ann) -> TypeRef -> Doc ann
forall a b. (a -> b) -> a -> b
$ ElmRecordField -> TypeRef
elmRecordFieldType (ElmRecordField -> TypeRef) -> ElmRecordField -> TypeRef
forall a b. (a -> b) -> a -> b
$ NonEmpty ElmRecordField -> ElmRecordField
forall a. NonEmpty a -> a
NE.head NonEmpty ElmRecordField
elmAliasFields)

    recordDecoder :: Doc ann
    recordDecoder :: Doc ann
recordDecoder = Int -> Doc ann -> Doc ann
forall ann. Int -> Doc ann -> Doc ann
nest Int
4
        (Doc ann -> Doc ann) -> Doc ann -> Doc ann
forall a b. (a -> b) -> a -> b
$ [Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
vsep
        ([Doc ann] -> Doc ann) -> [Doc ann] -> Doc ann
forall a b. (a -> b) -> a -> b
$ (Doc ann
forall ann. Doc ann
name Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"D.succeed" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedAliasName)
        Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: (ElmRecordField -> Doc ann) -> [ElmRecordField] -> [Doc ann]
forall a b. (a -> b) -> [a] -> [b]
map ElmRecordField -> Doc ann
forall ann. ElmRecordField -> Doc ann
fieldDecode (NonEmpty ElmRecordField -> [ElmRecordField]
forall a. NonEmpty a -> [a]
toList NonEmpty ElmRecordField
elmAliasFields)

    name :: Doc ann
    name :: Doc ann
name = Text -> Doc ann
forall ann. Text -> Doc ann
decoderName Text
elmAliasName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
equals

    qualifiedAliasName :: Doc ann
    qualifiedAliasName :: Doc ann
qualifiedAliasName = Text -> Doc ann
forall ann. Text -> Doc ann
mkQualified Text
elmAliasName

    fieldDecode :: ElmRecordField -> Doc ann
    fieldDecode :: ElmRecordField -> Doc ann
fieldDecode ElmRecordField{Text
TypeRef
elmRecordFieldName :: ElmRecordField -> Text
elmRecordFieldName :: Text
elmRecordFieldType :: TypeRef
elmRecordFieldType :: ElmRecordField -> TypeRef
..} = case TypeRef
elmRecordFieldType of
        RefPrim ElmPrim
ElmUnit -> Doc ann
"|> D.hardcoded ()"
        TypeRef
t -> Doc ann
"|> required"
            Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
dquotes (Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
elmRecordFieldName)
            Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
t)

typeDecoderDoc :: ElmType -> Doc ann
typeDecoderDoc :: ElmType -> Doc ann
typeDecoderDoc  t :: ElmType
t@ElmType{Bool
[Text]
Text
NonEmpty ElmConstructor
elmTypeConstructors :: ElmType -> NonEmpty ElmConstructor
elmTypeIsNewtype :: ElmType -> Bool
elmTypeVars :: ElmType -> [Text]
elmTypeName :: ElmType -> Text
elmTypeConstructors :: NonEmpty ElmConstructor
elmTypeIsNewtype :: Bool
elmTypeVars :: [Text]
elmTypeName :: Text
..} =
    -- function defenition: @encodeTypeName : TypeName -> Value@.
       Text -> [Text] -> Doc ann
forall ann. Text -> [Text] -> Doc ann
decoderDef Text
elmTypeName [Text]
elmTypeVars
    Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
line
    Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> if ElmType -> Bool
isEnum ElmType
t
       -- if this is Enum just using the read instance we wrote.
       then Doc ann
forall ann. Doc ann
enumDecoder
       else if Bool
elmTypeIsNewtype
            -- if it newtype then wrap decoder for the field
            then Doc ann
forall ann. Doc ann
newtypeDecoder
            -- If it sum type then it should look like: @{"tag": "Foo", "contents" : ["string", 1]}@
            else Doc ann
forall ann. Doc ann
sumDecoder
  where
    name :: Doc ann
    name :: Doc ann
name = Text -> Doc ann
forall ann. Text -> Doc ann
decoderName Text
elmTypeName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
equals

    typeName :: Doc ann
    typeName :: Doc ann
typeName = Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
elmTypeName

    qualifiedTypeName :: Doc ann
    qualifiedTypeName :: Doc ann
qualifiedTypeName = Text -> Doc ann
forall ann. Text -> Doc ann
mkQualified Text
elmTypeName

    enumDecoder :: Doc ann
    enumDecoder :: Doc ann
enumDecoder = Doc ann
forall ann. Doc ann
name Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"elmStreetDecodeEnum T.read" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
typeName

    newtypeDecoder :: Doc ann
    newtypeDecoder :: Doc ann
newtypeDecoder = Doc ann
forall ann. Doc ann
name Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"D.map" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedTypeName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
fieldDecoderDoc
      where
        fieldDecoderDoc :: Doc ann
        fieldDecoderDoc :: Doc ann
fieldDecoderDoc = case ElmConstructor -> [TypeRef]
elmConstructorFields (ElmConstructor -> [TypeRef]) -> ElmConstructor -> [TypeRef]
forall a b. (a -> b) -> a -> b
$ NonEmpty ElmConstructor -> ElmConstructor
forall a. NonEmpty a -> a
NE.head NonEmpty ElmConstructor
elmTypeConstructors of
            []    -> Doc ann
"(D.fail \"Unknown field type of the newtype constructor\")"
            TypeRef
f : [TypeRef]
_ -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (Doc ann -> Doc ann) -> Doc ann -> Doc ann
forall a b. (a -> b) -> a -> b
$ TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
f

    sumDecoder :: Doc ann
    sumDecoder :: Doc ann
sumDecoder = Int -> Doc ann -> Doc ann
forall ann. Int -> Doc ann -> Doc ann
nest Int
4 (Doc ann -> Doc ann) -> Doc ann -> Doc ann
forall a b. (a -> b) -> a -> b
$ [Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
vsep
        [ Doc ann
forall ann. Doc ann
name
        , Int -> Doc ann -> Doc ann
forall ann. Int -> Doc ann -> Doc ann
nest Int
4 ([Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
vsep ([Doc ann] -> Doc ann) -> [Doc ann] -> Doc ann
forall a b. (a -> b) -> a -> b
$ (Doc ann
"let decide : String -> Decoder" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedTypeName) Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
:
            [ Int -> Doc ann -> Doc ann
forall ann. Int -> Doc ann -> Doc ann
nest Int
4
                ( [Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
vsep ([Doc ann] -> Doc ann) -> [Doc ann] -> Doc ann
forall a b. (a -> b) -> a -> b
$ Doc ann
"decide x = case x of"
                Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: (ElmConstructor -> Doc ann) -> [ElmConstructor] -> [Doc ann]
forall a b. (a -> b) -> [a] -> [b]
map ElmConstructor -> Doc ann
forall ann. ElmConstructor -> Doc ann
cases (NonEmpty ElmConstructor -> [ElmConstructor]
forall a. NonEmpty a -> [a]
toList NonEmpty ElmConstructor
elmTypeConstructors)
               [Doc ann] -> [Doc ann] -> [Doc ann]
forall a. [a] -> [a] -> [a]
++ [Doc ann
"c -> D.fail <|" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
dquotes (Doc ann
forall ann. Doc ann
typeName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"doesn't have such constructor: ") Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"++ c"]
                )
            ])
        , Doc ann
"in D.andThen decide (D.field \"tag\" D.string)"
        ]

    cases :: ElmConstructor -> Doc ann
    cases :: ElmConstructor -> Doc ann
cases ElmConstructor{[TypeRef]
Text
elmConstructorName :: ElmConstructor -> Text
elmConstructorFields :: [TypeRef]
elmConstructorName :: Text
elmConstructorFields :: ElmConstructor -> [TypeRef]
..} = Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
dquotes Doc ann
forall ann. Doc ann
cName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
arrow Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+>
        case [TypeRef]
elmConstructorFields of
            []  -> Doc ann
"D.succeed" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedConName
            [TypeRef
f] -> Doc ann
"D.field \"contents\" <| D.map" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedConName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
f)
            [TypeRef]
l   -> Doc ann
"D.field \"contents\" <| D.map" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Int -> Doc ann
forall ann. Int -> Doc ann
mapNum ([TypeRef] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [TypeRef]
l) Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
qualifiedConName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
createIndexes
      where
        cName :: Doc ann
        cName :: Doc ann
cName = Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
elmConstructorName

        qualifiedConName :: Doc ann
        qualifiedConName :: Doc ann
qualifiedConName = Text -> Doc ann
forall ann. Text -> Doc ann
mkQualified Text
elmConstructorName

        -- Use function map, map2, map3 etc.
        mapNum :: Int -> Doc ann
        mapNum :: Int -> Doc ann
mapNum Int
1 = Doc ann
forall ann. Doc ann
emptyDoc
        mapNum Int
i = Int -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Int
i

        createIndexes :: Doc ann
        createIndexes :: Doc ann
createIndexes = (Doc ann -> Doc ann -> Doc ann) -> [Doc ann] -> Doc ann
forall (t :: * -> *) ann.
Foldable t =>
(Doc ann -> Doc ann -> Doc ann) -> t (Doc ann) -> Doc ann
concatWith (Doc ann -> Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann -> Doc ann
surround Doc ann
" ") ([Doc ann] -> Doc ann) -> [Doc ann] -> Doc ann
forall a b. (a -> b) -> a -> b
$ (Int -> TypeRef -> Doc ann) -> [Int] -> [TypeRef] -> [Doc ann]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> TypeRef -> Doc ann
forall ann. Int -> TypeRef -> Doc ann
oneField [Int
0..] [TypeRef]
elmConstructorFields

        -- create @(D.index 0 D.string)@ etc.
        oneField :: Int -> TypeRef -> Doc ann
        oneField :: Int -> TypeRef -> Doc ann
oneField Int
i TypeRef
typeRef = Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
parens (Doc ann -> Doc ann) -> Doc ann -> Doc ann
forall a b. (a -> b) -> a -> b
$ Doc ann
"D.index"
            Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Int -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Int
i
            Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
typeRef)

-- | Converts the reference to the existing type to the corresponding decoder.
typeRefDecoder :: TypeRef -> Doc ann
typeRefDecoder :: TypeRef -> Doc ann
typeRefDecoder (RefCustom TypeName{Text
unTypeName :: TypeName -> Text
unTypeName :: Text
..}) = Doc ann
"decode" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty ((Char -> Bool) -> Text -> Text
T.takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
' ') Text
unTypeName)
typeRefDecoder (RefPrim ElmPrim
elmPrim) = case ElmPrim
elmPrim of
    ElmPrim
ElmUnit         -> Doc ann
"D.map (always ()) (D.list D.string)"
    ElmPrim
ElmNever        -> Doc ann
"D.fail \"Never is not possible\""
    ElmPrim
ElmBool         -> Doc ann
"D.bool"
    ElmPrim
ElmChar         -> Doc ann
"elmStreetDecodeChar"
    ElmPrim
ElmInt          -> Doc ann
"D.int"
    ElmPrim
ElmFloat        -> Doc ann
"D.float"
    ElmPrim
ElmString       -> Doc ann
"D.string"
    ElmPrim
ElmTime         -> Doc ann
"Iso.decoder"
    ElmMaybe TypeRef
t      -> Doc ann
"nullable"
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
t)
    ElmResult TypeRef
l TypeRef
r   -> Doc ann
"elmStreetDecodeEither"
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
l)
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
r)
    ElmPair TypeRef
a TypeRef
b     -> Doc ann
"elmStreetDecodePair"
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
a)
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
b)
    ElmTriple TypeRef
a TypeRef
b TypeRef
c -> Doc ann
"elmStreetDecodeTriple"
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
a)
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
b)
        Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
c)
    ElmList TypeRef
l       -> Doc ann
"D.list" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (TypeRef -> Doc ann
forall ann. TypeRef -> Doc ann
typeRefDecoder TypeRef
l)

-- | The definition of the @decodeTYPENAME@ function.
decoderDef
    :: Text  -- ^ Type name
    -> [Text] -- ^ List of type variables
    -> Doc ann
decoderDef :: Text -> [Text] -> Doc ann
decoderDef Text
typeName [Text]
vars =
    Text -> Doc ann
forall ann. Text -> Doc ann
decoderName Text
typeName
    Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
forall ann. Doc ann
colon
    Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann
"Decoder"
    Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
wrapParens (Text -> [Text] -> Doc ann
forall ann. Text -> [Text] -> Doc ann
qualifiedTypeWithVarsDoc Text
typeName [Text]
vars)

-- | Create the name of the decoder function.
decoderName :: Text -> Doc ann
decoderName :: Text -> Doc ann
decoderName Text
typeName = Doc ann
"decode" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
typeName

-- | @JSON@ decoder Elm help function for Enum types.
decodeEnum :: Text
decodeEnum :: Text
decodeEnum = [Text] -> Text
T.unlines
    [ Text
"decodeStr : (String -> Maybe a) -> String -> Decoder a"
    , Text
"decodeStr readX x = case readX x of"
    , Text
"    Just a  -> D.succeed a"
    , Text
"    Nothing -> D.fail \"Constructor not matched\""
    , Text
""
    , Text
"elmStreetDecodeEnum : (String -> Maybe a) -> Decoder a"
    , Text
"elmStreetDecodeEnum r = D.andThen (decodeStr r) D.string"
    ]

-- | @JSON@ decoder Elm help function for 'Char's.
decodeChar :: Text
decodeChar :: Text
decodeChar = [Text] -> Text
T.unlines
    [ Text
"elmStreetDecodeChar : Decoder Char"
    , Text
"elmStreetDecodeChar = D.andThen (decodeStr (Maybe.map Tuple.first << String.uncons)) D.string"
    ]

-- | @JSON@ decoder Elm help function for 'Either's.
decodeEither :: Text
decodeEither :: Text
decodeEither = [Text] -> Text
T.unlines
    [ Text
"elmStreetDecodeEither : Decoder a -> Decoder b -> Decoder (Result a b)"
    , Text
"elmStreetDecodeEither decA decB = D.oneOf "
    , Text
"    [ D.field \"Left\"  (D.map Err decA)"
    , Text
"    , D.field \"Right\" (D.map Ok decB)"
    , Text
"    ]"
    ]

-- | @JSON@ decoder Elm help function for 2-tuples.
decodePair :: Text
decodePair :: Text
decodePair = [Text] -> Text
T.unlines
    [ Text
"elmStreetDecodePair : Decoder a -> Decoder b -> Decoder (a, b)"
    , Text
"elmStreetDecodePair decA decB = D.map2 Tuple.pair (D.index 0 decA) (D.index 1 decB)"
    ]

-- | @JSON@ decoder Elm help function for 3-tuples.
decodeTriple :: Text
decodeTriple :: Text
decodeTriple = [Text] -> Text
T.unlines
    [ Text
"elmStreetDecodeTriple : Decoder a -> Decoder b -> Decoder c -> Decoder (a, b, c)"
    , Text
"elmStreetDecodeTriple decA decB decC = D.map3 (\\a b c -> (a,b,c)) (D.index 0 decA) (D.index 1 decB) (D.index 2 decC)"
    ]