{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeApplications #-}
module Formatting (tests) where
import Control.Exception
import Data.Aeson (SumEncoding(UntaggedValue), defaultOptions, sumEncoding, tagSingleConstructors)
import Data.Aeson.TypeScript.TH
import Data.Proxy
import Data.String.Interpolate
import Test.Hspec
data D = S | F deriving (Eq, Show)
$(deriveTypeScript defaultOptions ''D)
data D2 = S2 | F2 deriving (Eq, Show)
$(deriveTypeScript defaultOptions ''D2)
-- A.encode U --> "[]"
data Unit = U deriving (Eq, Show)
$(deriveTypeScript defaultOptions ''Unit)
-- A.encode UTagSingle --> "\"UTagSingle\""
data UnitTagSingle = UTagSingle deriving (Eq, Show)
$(deriveTypeScript (defaultOptions { tagSingleConstructors = True, sumEncoding = UntaggedValue }) ''UnitTagSingle)
data PrimeInType' = PrimeInType
$(deriveTypeScript defaultOptions ''PrimeInType')
data PrimeInConstr = PrimeInConstr'
$(deriveTypeScript defaultOptions ''PrimeInConstr)
data FooBar =
Foo {
-- | @no-emit-typescript
recordString :: String
, recordInt :: Int
}
|
-- | @no-emit-typescript
Bar {
barInt :: Int
}
$(deriveTypeScript defaultOptions ''FooBar)
data NormalConstructors =
-- | @no-emit-typescript
Con1 String
| Con2 Int
$(deriveTypeScript defaultOptions ''NormalConstructors)
tests :: Spec
tests = describe "Formatting" $ do
describe "when given a Sum Type" $ do
describe "and the TypeAlias format option is set" $
it "should generate a TS string literal type" $
formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @D Proxy) `shouldBe`
[i|type D = "S" | "F";|]
describe "and the Enum format option is set" $ do
it "should generate a TS Enum" $
formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe`
[i|enum D { S="S", F="F" }|]
it "should generate a TS Enum with multiple" $
formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy <> getTypeScriptDeclarations @D2 Proxy) `shouldBe`
[__i|enum D { S="S", F="F" }
enum D2 { S2="S2", F2="F2" }|]
it "should generate a normal type from Unit, singe tagSingleConstructors=False by default" $
formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe`
[__i|type Unit = IU;
type IU = void[];|]
it "should generate a suitable enum from UnitTagSingle" $
formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @UnitTagSingle Proxy) `shouldBe`
[__i|enum UnitTagSingle { UTagSingle="UTagSingle" }|]
describe "and the EnumWithType format option is set" $ do
it "should generate a TS Enum with a type declaration" $
formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @D Proxy) `shouldBe`
[i|enum DEnum { S="S", F="F" }\n\ntype D = keyof typeof DEnum;|]
it "should also work for UnitTagSingle" $
formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @UnitTagSingle Proxy) `shouldBe`
[i|enum UnitTagSingleEnum { UTagSingle="UTagSingle" }\n\ntype UnitTagSingle = keyof typeof UnitTagSingleEnum;|]
describe "when the name has an apostrophe" $ do
describe "in the type" $ do
it "throws an error" $ do
evaluate (formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @PrimeInType' Proxy)) `shouldThrow` anyErrorCall
describe "in the constructor" $ do
it "throws an error" $ do
evaluate (formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @PrimeInConstr Proxy)) `shouldThrow` anyErrorCall
#if MIN_VERSION_template_haskell(2,18,0)
describe "when @no-emit-typescript is present" $ do
it [i|works on records and constructors of record types|] $ do
formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @FooBar Proxy) `shouldBe` [i|type FooBar = IFoo;\n\ninterface IFoo {\n tag: "Foo";\n recordInt: number;\n}|]
it [i|works on normal constructors|] $ do
formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @NormalConstructors Proxy) `shouldBe` [i|type NormalConstructors = ICon2;\n\ninterface ICon2 {\n tag: "Con2";\n contents: number;\n}|]
#endif
main :: IO ()
main = hspec tests