Skip to content

Commit fff579b

Browse files
committed
Switch to th-abstraction
1 parent a744d90 commit fff579b

File tree

2 files changed

+26
-27
lines changed

2 files changed

+26
-27
lines changed

package.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies:
3030
- primitive
3131
- uuid
3232
- template-haskell
33+
- th-abstraction
3334

3435
- recursion-schemes
3536

src/Servant/TS/TH.hs

+25-27
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Data.Proxy
1111
import Data.Text (Text)
1212
import qualified Data.Text as Text
1313
import Language.Haskell.TH
14+
import Language.Haskell.TH.Datatype
1415

1516
import Servant.TS.Internal (TsTypeable(..), TsType(..), TsContext(..))
1617

@@ -22,17 +23,19 @@ deriveTsJSON opts name = do
2223

2324
deriveTsTypeable :: Options -> Name -> Q [Dec]
2425
deriveTsTypeable opts name = do
25-
TyConI (DataD _ _ _ _ cons' _) <- reify name
26+
DatatypeInfo { datatypeVars = vars
27+
, datatypeCons = cons } <- reifyDatatype name
2628
[d|
2729
instance TsTypeable $(conT name) where
28-
tsTypeRep _ = $(if tagSingleConstructors opts || length cons' > 1
29-
then let mk = if allNullaryToStringTag opts && all isNullaryCons cons' then mkNullaryStringConsE else mkTaggedTypeE
30-
in [| TsUnion <$> sequence $(ListE <$> sequence (mk <$> cons')) |]
31-
else mkTypeE (head cons'))
30+
tsTypeRep _ = $(if tagSingleConstructors opts || length cons > 1
31+
then let mk = if allNullaryToStringTag opts && all isNullaryCons cons then mkNullaryStringConsE else mkTaggedTypeE
32+
in [| TsUnion <$> sequence $(ListE <$> sequence (mk <$> cons)) |]
33+
else mkTypeE (head cons))
3234
|]
33-
where mkTypeE :: Con -> Q Exp {- Q (TsContext TsType) -}
34-
mkTypeE (NormalC _ ts) = makeTupleE (mkNormalFieldE <$> ts)
35-
mkTypeE (RecC _ ts) = makeRecordE (mkRecordFieldE <$> ts)
35+
where mkTypeE :: ConstructorInfo -> Q Exp {- Q (TsContext TsType) -}
36+
mkTypeE c = case constructorVariant c of
37+
NormalConstructor -> makeTupleE (mkNormalFieldE <$> constructorFields c)
38+
RecordConstructor ns -> makeRecordE (mkRecordFieldE <$> zip ns (constructorFields c))
3639

3740
makeTupleE :: [Q Exp] -> Q Exp {- [Q TsContext TsType] -> Q (TsContext TsType) -}
3841
makeTupleE ts = case ts of
@@ -44,34 +47,29 @@ deriveTsTypeable opts name = do
4447
then [| snd $(head ts) |]
4548
else [| TsObject <$> mapM (\(n, TsContext t m) -> TsContext (n, t) m) $(ListE <$> sequence ts) |]
4649

47-
isNullaryCons :: Con -> Bool
48-
isNullaryCons (NormalC _ []) = True
49-
isNullaryCons _ = False
50+
isNullaryCons :: ConstructorInfo -> Bool
51+
isNullaryCons = (\x -> length x == 0) . constructorFields
5052

51-
mkNullaryStringConsE :: Con -> Q Exp
52-
mkNullaryStringConsE (NormalC n []) = [| return . TsStringLiteral $ $(mkConStringE n) |]
53+
mkNullaryStringConsE :: ConstructorInfo -> Q Exp {- Q (TsContext TsType) -}
54+
mkNullaryStringConsE c = [| return . TsStringLiteral $ $(mkConStringE . constructorName $ c) |]
5355

54-
mkTaggedTypeE :: Con -> Q Exp {- Q (TsContext TsType) -}
55-
mkTaggedTypeE c = let conE = [| TsStringLiteral $(mkConStringE $ getConName c) |]
56+
mkTaggedTypeE :: ConstructorInfo -> Q Exp {- Q (TsContext TsType) -}
57+
mkTaggedTypeE c = let conE = [| TsStringLiteral $(mkConStringE $ constructorName c) |]
5658
in case sumEncoding opts of
57-
(TaggedObject tn cn) -> case c of
58-
(NormalC n ts) -> case ts of
59+
(TaggedObject tn cn) -> case constructorVariant c of
60+
NormalConstructor -> case constructorFields c of
5961
[] -> [| pure $ TsObject [($(mkTextE tn), $conE)] |]
6062
_ -> [| TsObject <$> sequence [pure ($(mkTextE tn), $conE), ((,) $(mkTextE cn) <$> $(mkTypeE c))] |]
61-
(RecC n ts) -> makeRecordE $ [| ($(mkTextE tn), return . TsStringLiteral $ $(mkConStringE n)) |] : (mkRecordFieldE <$> ts)
63+
RecordConstructor ns -> makeRecordE $ [| ($(mkTextE tn), return . TsStringLiteral $ $(mkConStringE $ constructorName c)) |] : (mkRecordFieldE <$> zip ns (constructorFields c))
6264
UntaggedValue -> mkTypeE c
63-
ObjectWithSingleField -> [| (\x -> TsObject [($(mkConStringE $ getConName c), x)]) <$> $(mkTypeE c) |]
65+
ObjectWithSingleField -> [| (\x -> TsObject [($(mkConStringE $ constructorName c), x)]) <$> $(mkTypeE c) |]
6466
TwoElemArray -> [| (\x -> TsTuple [$conE, x]) <$> $(mkTypeE c) |]
6567

66-
getConName :: Con -> Name
67-
getConName (NormalC n _) = n
68-
getConName (RecC n _) = n
68+
mkRecordFieldE :: (Name, Type) -> Q Exp {- Q (Text, TsContext TsType) -}
69+
mkRecordFieldE (n, t) = [| ($(mkFieldStringE n), tsTypeRep (Proxy :: Proxy $(return t))) |]
6970

70-
mkRecordFieldE :: (Name, Bang, Type) -> Q Exp {- Q (Text, TsContext TsType) -}
71-
mkRecordFieldE (n, _, t) = [| ($(mkFieldStringE n), tsTypeRep (Proxy :: Proxy $(return t))) |]
72-
73-
mkNormalFieldE :: (Bang, Type) -> Q Exp
74-
mkNormalFieldE (_, t) = [| tsTypeRep (Proxy :: Proxy $(return t)) |]
71+
mkNormalFieldE :: Type -> Q Exp {- Q (TsContext TsType) -}
72+
mkNormalFieldE t = [| tsTypeRep (Proxy :: Proxy $(return t)) |]
7573

7674
mkFieldStringE :: Name -> Q Exp {- Q String -}
7775
mkFieldStringE n = mkTextE . (fieldLabelModifier opts) . nameBase $ n

0 commit comments

Comments
 (0)