{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE NoMonomorphismRestriction #-} module Data.Apiary.Document where import Control.Applicative import Data.Typeable import Data.Maybe import Data.List import Data.Function import Data.Apiary.Param import Data.Apiary.Method import Text.Blaze.Html import qualified Data.Text as T import qualified Data.ByteString as S data StrategyRep = StrategyRep { strategyInfo :: T.Text } deriving (Show, Eq) data Doc = DocPath T.Text Doc | DocRoot Doc | DocFetch TypeRep (Maybe Html) Doc | DocDropNext Doc | DocMethod Method Doc | DocQuery S.ByteString StrategyRep QueryRep (Maybe Html) Doc | DocPrecondition Html Doc | DocGroup T.Text Doc | Document T.Text Doc | Action -------------------------------------------------------------------------------- data Route = Path T.Text Route | Fetch TypeRep (Maybe Html) Route | End instance Eq Route where Path a d == Path b d' = a == b && d == d' Fetch a _ d == Fetch b _ d' = a == b && d == d' End == End = True _ == _ = False data Documents = Documents { noGroup :: [PathDoc] , groups :: [(T.Text, [PathDoc])] } data PathDoc = PathDoc { path :: Route , methods :: [(Method, [MethodDoc])] } data QueryDoc = QueryDoc { queryName :: S.ByteString , queryStrategy :: StrategyRep , queryRep :: QueryRep , queryDocument :: (Maybe Html) } data MethodDoc = MethodDoc { queries :: [QueryDoc] , preconditions :: [Html] , document :: T.Text } -------------------------------------------------------------------------------- docToDocument :: Doc -> Maybe (Maybe T.Text, PathDoc) docToDocument = \case (DocGroup "" d') -> (Nothing,) <$> loop id (\md -> [("*", md)]) id id Nothing d' (DocGroup g d') -> (Just g,) <$> loop id (\md -> [("*", md)]) id id Nothing d' d' -> (Nothing,) <$> loop id (\md -> [("*", md)]) id id Nothing d' where loop ph mh qs ps doc (DocDropNext d) = loop ph mh qs ps doc (dropNext d) loop ph mh qs pc doc (DocPath t d) = loop (ph . Path t) mh qs pc doc d loop _ mh qs pc doc (DocRoot d) = loop (const $ Path "" End) mh qs pc doc d loop ph mh qs pc doc (DocFetch t h d) = loop (ph . Fetch t h) mh qs pc doc d loop ph _ qs pc doc (DocMethod m d) = loop ph (\md -> [(m, md)]) qs pc doc d loop ph mh qs pc doc (DocQuery p s q t d) = loop ph mh (qs . (QueryDoc p s q t:)) pc doc d loop ph mh qs pc doc (DocPrecondition h d) = loop ph mh qs (pc . (h:)) doc d loop ph mh qs pc doc (DocGroup _ d) = loop ph mh qs pc doc d loop ph mh qs pc _ (Document t d) = loop ph mh qs pc (Just t) d loop ph mh qs pc (Just t) Action = Just . PathDoc (ph End) $ mh [MethodDoc (qs []) (pc []) t] loop _ _ _ _ Nothing Action = Nothing dropNext (DocPath _ d) = d dropNext (DocRoot d) = d dropNext (DocFetch _ _ d) = d dropNext (DocDropNext d) = dropNext d dropNext (DocMethod _ d) = d dropNext (DocQuery _ _ _ _ d) = d dropNext (DocPrecondition _ d) = d dropNext (DocGroup _ d) = d dropNext (Document _ d) = d dropNext Action = Action mergePathDoc :: [PathDoc] -> [PathDoc] mergePathDoc [] = [] mergePathDoc (pd:pds) = merge (filter (same pd) pds) : mergePathDoc (filter (not . same pd) pds) where same = (==) `on` path merge pds' = PathDoc (path pd) (mergeMethods $ methods pd ++ concatMap methods pds') mergeMethods :: [(Method, [MethodDoc])] -> [(Method, [MethodDoc])] mergeMethods [] = [] mergeMethods (m:ms) = merge (filter (same m) ms) : mergeMethods (filter (not . same m) ms) where same = (==) `on` fst merge ms' = (fst m, snd m ++ concatMap snd ms') docsToDocuments :: [Doc] -> Documents docsToDocuments doc = let gds = mapMaybe docToDocument doc ngs = mergePathDoc . map snd $ filter ((Nothing ==) . fst) gds gs = map upGroup . groupBy ((==) `on` fst) $ mapMaybe trav gds in Documents ngs gs where upGroup ((g,d):ig) = (g, mergePathDoc $ d : map snd ig) upGroup [] = error "docsToDocuments: unknown error." trav (Nothing, _) = Nothing trav (Just a, b) = Just (a, b)