-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTH.hs
64 lines (56 loc) · 2.49 KB
/
TH.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
{-# LANGUAGE OverloadedStrings #-}
module Web.ATProto.Lexicons.TH where
import GHC.Generics (Generic)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.ByteString.Lazy.Char8 as BS
import Language.Haskell.TH
import Language.Haskell.TH.Quote (QuasiQuoter(QuasiQuoter), quoteDec)
import Data.Aeson (FromJSON, Value(Object, String, Number), Object, eitherDecode)
import qualified Data.Aeson.KeyMap as KM
import Control.Monad (when)
import Data.Either.Extra (maybeToEither)
import Data.Either (fromRight)
import Web.ATProto.Lexicons.Core (LexiconDocV1)
lexicon :: QuasiQuoter
lexicon = QuasiQuoter { quoteDec = mkLexiconType
. either error id
. eitherDecode . BS.pack
}
-- | Construct necesary 'Dec's from Lexicon JSON data.
--
-- Todo: What to do with description, revision, and defs fields? They're ignored for now
mkLexiconType :: LexiconDocV1 -> Q [Dec]
mkLexiconType (Object o) = do
-- version check
lexiconVersion <- maybeToEither "Top-level dictionary should contain 'lexicon'" $ KM.lookup "lexicon" o
when (lexiconVersion /= (Number 1)) $ Left "only lexicon version 1 is supported"
lexiconType <- maybeToEither "Top-level dictionary should contain 'type'" $ KM.lookup "type" o
case lexiconType of
(String "query") -> mkLexiconTypeQuery o
(String "procedure") -> mkLexiconTypeProcedure o
(String "record") -> mkLexiconTypeRecord o
mkLexiconType' _ = Left "Top-level should be Object"
-- | Construct 'Q [Dec]' for Query XRPC method
mkLexiconTypeQuery :: Object -> Either String (Q [Dec])
mkLexiconTypeQuery o = Right (return [])
-- | Construct 'Q [Dec]' for Precedure XRPC method
mkLexiconTypeProcedure :: Object -> Either String (Q [Dec])
mkLexiconTypeProcedure o = Right (return [])
-- | Construct 'Q [Dec]' for Record definition
--
-- Usage of 'key' field isn't written on document, so I simply ignoreing it for now.
mkLexiconTypeRecord :: Object -> Either String (Q [Dec])
mkLexiconTypeRecord o = do
let lexiconKey = KM.lookup "key" o
lexiconId <- maybeToEither "Top-level dictionary should contain 'id'" $ KM.lookup "id" o
case lexiconId of
(String lexiconId') ->
let nsidName = T.unpack . T.toTitle $ getNsidName lexiconId'
-- record = may
in Right $ do
let recordName = mkName nsidName
return [DataD [] recordName [] Nothing [RecC recordName []] []]
_ -> Left "id should be String"
getNsidName :: Text -> Text
getNsidName = last . T.splitOn "."