packages feed

servant-docs-simple 0.2.0.1 → 0.3.0.0

raw patch · 6 files changed

+150/−86 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Servant.Docs.Simple.Parse: class HasDocumentApi api
- Servant.Docs.Simple.Parse: class HasParsable api
- Servant.Docs.Simple.Parse: document :: HasDocumentApi api => Route -> [(Parameter, Details)] -> (Route, OMap Parameter Details)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, Data.Typeable.Internal.Typeable ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.ReqBody.ReqBody' m ct typ Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, Data.Typeable.Internal.Typeable ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Stream.StreamBody' m ct typ Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol dRoute, Data.Typeable.Internal.Typeable t) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Capture.Capture' m dRoute t Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol dRoute, Data.Typeable.Internal.Typeable t) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Capture.CaptureAll dRoute t Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol desc) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Description.Description desc Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol param) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.QueryParam.QueryFlag param Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol param, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.QueryParam.QueryParam' m param typ Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol param, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.QueryParam.QueryParams param typ Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol realm, Data.Typeable.Internal.Typeable a) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.BasicAuth.BasicAuth realm a Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol route) => Servant.Docs.Simple.Parse.HasDocumentApi (route Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol s) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Description.Summary s Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol token) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Experimental.Auth.AuthProtect token Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasCollatable (Servant.API.TypeLevel.Endpoints a) => Servant.Docs.Simple.Parse.HasParsable a
- Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasDocumentApi b => Servant.Docs.Simple.Parse.HasDocumentApi (Data.Vault.Lazy.Vault Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasDocumentApi b => Servant.Docs.Simple.Parse.HasDocumentApi (Network.HTTP.Types.Version.HttpVersion Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasDocumentApi b => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.IsSecure.IsSecure Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasDocumentApi b => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.RemoteHost.RemoteHost Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasParsable Servant.API.Empty.EmptyAPI
- Servant.Docs.Simple.Parse: instance forall a (api :: a) (b :: [a]). (Servant.Docs.Simple.Parse.HasDocumentApi api, Servant.Docs.Simple.Parse.HasCollatable b) => Servant.Docs.Simple.Parse.HasCollatable (api : b)
- Servant.Docs.Simple.Parse: instance forall k b (ct :: GHC.Types.Symbol) (typ :: k) (m :: [*]). (Servant.Docs.Simple.Parse.HasDocumentApi b, GHC.TypeLits.KnownSymbol ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Header.Header' m ct typ Servant.API.Sub.:> b)
- Servant.Docs.Simple.Parse: instance forall k1 (m :: k1) (ct :: [*]) typ (s :: GHC.Types.Nat). (Data.Typeable.Internal.Typeable m, Data.Typeable.Internal.Typeable ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasDocumentApi (Servant.API.Verbs.Verb m s ct typ)
- Servant.Docs.Simple.Parse: parse :: HasParsable api => ApiDocs
- Servant.Docs.Simple.Render: instance Servant.Docs.Simple.Render.Renderable (Servant.Docs.Simple.Render.Pretty ann)
+ Servant.Docs.Simple: stdoutMarkdown :: forall api. HasParsableApi api => IO ()
+ Servant.Docs.Simple: writeDocsMarkdown :: forall api. HasParsableApi api => FilePath -> IO ()
+ Servant.Docs.Simple.Parse: class HasParsableApi api
+ Servant.Docs.Simple.Parse: class HasParsableEndpoint e
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, Data.Typeable.Internal.Typeable ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.ReqBody.ReqBody' m ct typ Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, Data.Typeable.Internal.Typeable ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Stream.StreamBody' m ct typ Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol dRoute, Data.Typeable.Internal.Typeable t) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Capture.Capture' m dRoute t Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol dRoute, Data.Typeable.Internal.Typeable t) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Capture.CaptureAll dRoute t Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol desc) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Description.Description desc Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol param) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.QueryParam.QueryFlag param Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol param, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.QueryParam.QueryParam' m param typ Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol param, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.QueryParam.QueryParams param typ Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol realm, Data.Typeable.Internal.Typeable a) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.BasicAuth.BasicAuth realm a Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol route) => Servant.Docs.Simple.Parse.HasParsableEndpoint (route Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol s) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Description.Summary s Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol token) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Experimental.Auth.AuthProtect token Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasCollatable (Servant.API.TypeLevel.Endpoints a) => Servant.Docs.Simple.Parse.HasParsableApi a
+ Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasParsableApi Servant.API.Empty.EmptyAPI
+ Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasParsableEndpoint b => Servant.Docs.Simple.Parse.HasParsableEndpoint (Data.Vault.Lazy.Vault Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasParsableEndpoint b => Servant.Docs.Simple.Parse.HasParsableEndpoint (Network.HTTP.Types.Version.HttpVersion Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasParsableEndpoint b => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.IsSecure.IsSecure Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance Servant.Docs.Simple.Parse.HasParsableEndpoint b => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.RemoteHost.RemoteHost Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance forall a (e :: a) (b :: [a]). (Servant.Docs.Simple.Parse.HasParsableEndpoint e, Servant.Docs.Simple.Parse.HasCollatable b) => Servant.Docs.Simple.Parse.HasCollatable (e : b)
+ Servant.Docs.Simple.Parse: instance forall k b (ct :: GHC.Types.Symbol) (typ :: k) (m :: [*]). (Servant.Docs.Simple.Parse.HasParsableEndpoint b, GHC.TypeLits.KnownSymbol ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Header.Header' m ct typ Servant.API.Sub.:> b)
+ Servant.Docs.Simple.Parse: instance forall k1 (m :: k1) (ct :: [*]) typ (s :: GHC.Types.Nat). (Data.Typeable.Internal.Typeable m, Data.Typeable.Internal.Typeable ct, Data.Typeable.Internal.Typeable typ) => Servant.Docs.Simple.Parse.HasParsableEndpoint (Servant.API.Verbs.Verb m s ct typ)
+ Servant.Docs.Simple.Parse: parseApi :: HasParsableApi api => ApiDocs
+ Servant.Docs.Simple.Parse: parseEndpoint :: HasParsableEndpoint e => Route -> [(Parameter, Details)] -> (Route, OMap Parameter Details)
+ Servant.Docs.Simple.Render: Markdown :: Text -> Markdown
+ Servant.Docs.Simple.Render: [getMarkdown] :: Markdown -> Text
+ Servant.Docs.Simple.Render: instance GHC.Classes.Eq Servant.Docs.Simple.Render.Markdown
+ Servant.Docs.Simple.Render: instance GHC.Show.Show Servant.Docs.Simple.Render.Markdown
+ Servant.Docs.Simple.Render: instance Servant.Docs.Simple.Render.Renderable Servant.Docs.Simple.Render.Markdown
+ Servant.Docs.Simple.Render: instance Servant.Docs.Simple.Render.Renderable Servant.Docs.Simple.Render.Pretty
+ Servant.Docs.Simple.Render: newtype Markdown
- Servant.Docs.Simple: document :: forall api. HasParsable api => PlainText
+ Servant.Docs.Simple: document :: forall api. HasParsableApi api => PlainText
- Servant.Docs.Simple: documentWith :: forall api a. (HasParsable api, Renderable a) => a
+ Servant.Docs.Simple: documentWith :: forall api a. (HasParsableApi api, Renderable a) => a
- Servant.Docs.Simple: stdoutJson :: forall api. HasParsable api => IO ()
+ Servant.Docs.Simple: stdoutJson :: forall api. HasParsableApi api => IO ()
- Servant.Docs.Simple: stdoutPlainText :: forall api. HasParsable api => IO ()
+ Servant.Docs.Simple: stdoutPlainText :: forall api. HasParsableApi api => IO ()
- Servant.Docs.Simple: writeDocsJson :: forall api. HasParsable api => FilePath -> IO ()
+ Servant.Docs.Simple: writeDocsJson :: forall api. HasParsableApi api => FilePath -> IO ()
- Servant.Docs.Simple: writeDocsPlainText :: forall api. HasParsable api => FilePath -> IO ()
+ Servant.Docs.Simple: writeDocsPlainText :: forall api. HasParsableApi api => FilePath -> IO ()
- Servant.Docs.Simple.Render: Pretty :: Doc ann -> Pretty ann
+ Servant.Docs.Simple.Render: Pretty :: Doc Ann -> Pretty
- Servant.Docs.Simple.Render: [getPretty] :: Pretty ann -> Doc ann
+ Servant.Docs.Simple.Render: [getPretty] :: Pretty -> Doc Ann
- Servant.Docs.Simple.Render: newtype Pretty ann
+ Servant.Docs.Simple.Render: newtype Pretty

Files

CHANGELOG.md view
@@ -15,3 +15,15 @@ ## 0.2.0.1  * Update CHANGELOG, README++## 0.3.0.0++* Add markdown support++* Update typeclass names in `Servant.Docs.Simple.Parse`:++  `HasParsable` -> `HasParsableApi`+  +  `HasDocumentApi` -> `HasParsableEndpoint`+  +  `parse` -> `parseApi`
servant-docs-simple.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                servant-docs-simple-version:             0.2.0.1+version:             0.3.0.0 synopsis:            Generate endpoints overview for Servant API  description:@@ -63,6 +63,7 @@                        DerivingStrategies                        FlexibleInstances                        FunctionalDependencies+                       LambdaCase                        OverloadedStrings                        PolyKinds                        ScopedTypeVariables
src/Servant/Docs/Simple.hs view
@@ -70,8 +70,10 @@ module Servant.Docs.Simple ( document                            , documentWith                            , stdoutJson+                           , stdoutMarkdown                            , stdoutPlainText                            , writeDocsJson+                           , writeDocsMarkdown                            , writeDocsPlainText                            ) where @@ -79,30 +81,39 @@ import qualified Data.ByteString.Lazy as B (writeFile) import qualified Data.ByteString.Lazy.Char8 as BC (putStrLn) import qualified Data.Text.IO as T (putStrLn, writeFile)-import Servant.Docs.Simple.Parse (HasParsable (..))-import Servant.Docs.Simple.Render (Json (..), PlainText (..), Renderable (..)) +import Servant.Docs.Simple.Parse (HasParsableApi (..))+import Servant.Docs.Simple.Render (Json (..), Markdown (..), PlainText (..), Renderable (..)) + -- | Write documentation as PlainText to file-writeDocsPlainText :: forall api. HasParsable api => FilePath -> IO ()+writeDocsPlainText :: forall api. HasParsableApi api => FilePath -> IO () writeDocsPlainText fp = T.writeFile fp . getPlainText $ document @api +-- | Write documentation as Markdown to file+writeDocsMarkdown :: forall api. HasParsableApi api => FilePath -> IO ()+writeDocsMarkdown fp = T.writeFile fp . getMarkdown $ documentWith @api @Markdown+ -- | Write documentation as JSON to file-writeDocsJson :: forall api. HasParsable api => FilePath -> IO ()+writeDocsJson :: forall api. HasParsableApi api => FilePath -> IO () writeDocsJson fp = B.writeFile fp . encodePretty . getJson $ documentWith @api @Json  -- | Write documentation as PlainText to stdout-stdoutPlainText :: forall api. HasParsable api => IO ()+stdoutPlainText :: forall api. HasParsableApi api => IO () stdoutPlainText = T.putStrLn . getPlainText $ document @api +-- | Write documentation as Markdown to stdout+stdoutMarkdown :: forall api. HasParsableApi api => IO ()+stdoutMarkdown = T.putStrLn . getMarkdown $ documentWith @api @Markdown+ -- | Write documentation as JSON to stdout-stdoutJson :: forall api. HasParsable api => IO ()+stdoutJson :: forall api. HasParsableApi api => IO () stdoutJson = BC.putStrLn . encodePretty . getJson $ documentWith @api @Json  -- | Convert API type into PlainText format-document :: forall api. HasParsable api => PlainText+document :: forall api. HasParsableApi api => PlainText document = documentWith @api @PlainText  -- | Convert API type into specified formats-documentWith :: forall api a. (HasParsable api, Renderable a) => a-documentWith = render @a (parse @api)+documentWith :: forall api a. (HasParsableApi api, Renderable a) => a+documentWith = render @a (parseApi @api)
src/Servant/Docs/Simple/Parse.hs view
@@ -46,8 +46,8 @@ {-# LANGUAGE UndecidableInstances #-}  module Servant.Docs.Simple.Parse-       ( HasDocumentApi (..)-       , HasParsable (..)+       ( HasParsableEndpoint (..)+       , HasParsableApi (..)        , symbolVal'        , toDetails        , typeText@@ -69,16 +69,16 @@ import Servant.Docs.Simple.Render (ApiDocs (..), Details (..), Parameter, Route)  -- | Flattens API into type level list of Endpoints-class HasParsable api where-    parse :: ApiDocs+class HasParsableApi api where+    parseApi :: ApiDocs  -- | If the flattened API can be collated into documentation, it is parsable-instance HasCollatable (S.Endpoints a) => HasParsable a where-    parse = collate @(S.Endpoints a)+instance HasCollatable (S.Endpoints a) => HasParsableApi a where+    parseApi = collate @(S.Endpoints a)  -- | Empty APIs should have no documentation-instance {-# OVERLAPPING #-} HasParsable EmptyAPI where-    parse = collate @'[]+instance {-# OVERLAPPING #-} HasParsableApi EmptyAPI where+    parseApi = collate @'[]  -- | Folds api endpoints into documentation class HasCollatable api where@@ -86,8 +86,8 @@     collate :: ApiDocs  -- | Collapse a type-level list of API endpoints into documentation-instance (HasDocumentApi api, HasCollatable b) => HasCollatable (api ': b) where-    collate = ApiDocs $ (Details <$> documentEndpoint @api) |< previous+instance (HasParsableEndpoint e, HasCollatable b) => HasCollatable (e ': b) where+    collate = ApiDocs $ (Details <$> documentEndpoint @e) |< previous       where ApiDocs previous = collate @b  -- | Terminal step when there are no more endpoints left to recurse over@@ -95,64 +95,64 @@     collate = ApiDocs empty  -- | Folds an api endpoint into documentation-documentEndpoint :: forall a. HasDocumentApi a => (Route, OMap Parameter Details)-documentEndpoint = document @a "" []+documentEndpoint :: forall a. HasParsableEndpoint a => (Route, OMap Parameter Details)+documentEndpoint = parseEndpoint @a "" []  -- | Folds an api endpoint into documentation-class HasDocumentApi api where+class HasParsableEndpoint e where      -- | We use this to destructure the API type and convert it into documentation-    document :: Route -- ^ Route documentation-             -> [(Parameter, Details)] -- ^ Everything else documentation-             -> (Route, OMap Parameter Details) -- ^ Generated documentation for the route+    parseEndpoint :: Route -- ^ Route documentation+                  -> [(Parameter, Details)] -- ^ Everything else documentation+                  -> (Route, OMap Parameter Details) -- ^ Generated documentation for the route  -- | Static route documentation-instance (HasDocumentApi b, KnownSymbol route) => HasDocumentApi ((route :: Symbol) :> b) where-    document r = document @b formatted-        where formatted = fold [r, "/", fragment]-              fragment = symbolVal' @route+instance (HasParsableEndpoint b, KnownSymbol route) => HasParsableEndpoint ((route :: Symbol) :> b) where+    parseEndpoint r = parseEndpoint @b formatted+      where formatted = fold [r, "/", fragment]+            fragment = symbolVal' @route  -- | Capture documentation-instance (HasDocumentApi b, KnownSymbol dRoute, Typeable t) => HasDocumentApi (Capture' m (dRoute :: Symbol) t :> b) where-    document r = document @b formatted-        where formatted = fold [r, "/", "{", var, "::", format, "}"]-              var = symbolVal' @dRoute-              format = typeText @t+instance (HasParsableEndpoint b, KnownSymbol dRoute, Typeable t) => HasParsableEndpoint (Capture' m (dRoute :: Symbol) t :> b) where+    parseEndpoint r = parseEndpoint @b formatted+      where formatted = fold [r, "/", "{", var, "::", format, "}"]+            var = symbolVal' @dRoute+            format = typeText @t  -- | CaptureAll documentation-instance (HasDocumentApi b, KnownSymbol dRoute, Typeable t) => HasDocumentApi (CaptureAll (dRoute :: Symbol) t :> b) where-    document r = document @b formatted-        where formatted = fold [r, "/", "{", var, "::", format, "}"]-              var = symbolVal' @dRoute-              format = typeText @t+instance (HasParsableEndpoint b, KnownSymbol dRoute, Typeable t) => HasParsableEndpoint (CaptureAll (dRoute :: Symbol) t :> b) where+    parseEndpoint r = parseEndpoint @b formatted+      where formatted = fold [r, "/", "{", var, "::", format, "}"]+            var = symbolVal' @dRoute+            format = typeText @t  -- | Request HttpVersion documentation-instance HasDocumentApi b => HasDocumentApi (HttpVersion :> b) where-    document r a = document @b r $ a <> [("Captures Http Version", Detail "True")]+instance HasParsableEndpoint b => HasParsableEndpoint (HttpVersion :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("Captures Http Version", Detail "True")]  -- | IsSecure documentation-instance HasDocumentApi b => HasDocumentApi (IsSecure :> b) where-    document r a = document @b r $ a <> [("SSL Only", Detail "True")]+instance HasParsableEndpoint b => HasParsableEndpoint (IsSecure :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("SSL Only", Detail "True")]  -- | Request Remote host documentation-instance HasDocumentApi b => HasDocumentApi (RemoteHost :> b) where-    document r a = document @b r $ a <> [("Captures RemoteHost/IP", Detail "True")]+instance HasParsableEndpoint b => HasParsableEndpoint (RemoteHost :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("Captures RemoteHost/IP", Detail "True")]  -- | Description documentation-instance (HasDocumentApi b, KnownSymbol desc) => HasDocumentApi (Description (desc :: Symbol) :> b) where-    document r a = document @b r $ a <> [("Description", Detail $ symbolVal' @desc)]+instance (HasParsableEndpoint b, KnownSymbol desc) => HasParsableEndpoint (Description (desc :: Symbol) :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("Description", Detail $ symbolVal' @desc)]  -- | Summary documentation-instance (HasDocumentApi b, KnownSymbol s) => HasDocumentApi (Summary (s :: Symbol) :> b) where-    document r a = document @b r $ a <> [("Summary", Detail $ symbolVal' @s)]+instance (HasParsableEndpoint b, KnownSymbol s) => HasParsableEndpoint (Summary (s :: Symbol) :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("Summary", Detail $ symbolVal' @s)]  -- | Vault documentation-instance HasDocumentApi b => HasDocumentApi (Vault :> b) where-    document r a = document @b r $ a <> [("Vault", Detail "True")]+instance HasParsableEndpoint b => HasParsableEndpoint (Vault :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("Vault", Detail "True")]  -- | Basic authentication documentation-instance (HasDocumentApi b, KnownSymbol realm, Typeable a) => HasDocumentApi (BasicAuth (realm :: Symbol) a :> b) where-    document r a = document @b r $ a <> [( "Basic Authentication"+instance (HasParsableEndpoint b, KnownSymbol realm, Typeable a) => HasParsableEndpoint (BasicAuth (realm :: Symbol) a :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [( "Basic Authentication"                                         , toDetails [ ("Realm", Detail realm)                                                     , ("UserData", Detail userData)                                                     ]@@ -162,51 +162,51 @@               userData = typeText @a  -- | Authentication documentation-instance (HasDocumentApi b, KnownSymbol token) => HasDocumentApi (AuthProtect (token :: Symbol) :> b) where-    document r a = document @b r $ a <> [("Authentication", Detail authDoc)]+instance (HasParsableEndpoint b, KnownSymbol token) => HasParsableEndpoint (AuthProtect (token :: Symbol) :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [("Authentication", Detail authDoc)]         where authDoc = symbolVal' @token  -- | Request header documentation-instance (HasDocumentApi b, KnownSymbol ct, Typeable typ) => HasDocumentApi (Header' m (ct :: Symbol) typ :> b) where-    document r a = document @b r $ a <> [( "RequestHeaders"+instance (HasParsableEndpoint b, KnownSymbol ct, Typeable typ) => HasParsableEndpoint (Header' m (ct :: Symbol) typ :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [( "RequestHeaders"                                         , toDetails [ ("Name", Detail $ symbolVal' @ct)                                                     , ("ContentType", Detail $ typeText @typ)                                                     ]                                         )]  -- | Query flag documentation-instance (HasDocumentApi b, KnownSymbol param) => HasDocumentApi (QueryFlag (param :: Symbol) :> b) where-    document r a = document @b r $ a <> [( "QueryFlag"+instance (HasParsableEndpoint b, KnownSymbol param) => HasParsableEndpoint (QueryFlag (param :: Symbol) :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [( "QueryFlag"                                         , toDetails [ ("Param", Detail $ symbolVal' @param) ]                                         )]  -- | Query param documentation-instance (HasDocumentApi b, KnownSymbol param, Typeable typ) => HasDocumentApi (QueryParam' m (param :: Symbol) typ :> b) where-    document r a = document @b r $ a <> [( "QueryParam"+instance (HasParsableEndpoint b, KnownSymbol param, Typeable typ) => HasParsableEndpoint (QueryParam' m (param :: Symbol) typ :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [( "QueryParam"                                         , toDetails [ ("Param", Detail $ symbolVal' @param)                                                     , ("ContentType", Detail $ typeText @typ)                                                     ]                                         )]  -- | Query params documentation-instance (HasDocumentApi b, KnownSymbol param, Typeable typ) => HasDocumentApi (QueryParams (param :: Symbol) typ :> b) where-    document r a = document @b r $ a <> [(  "QueryParams"+instance (HasParsableEndpoint b, KnownSymbol param, Typeable typ) => HasParsableEndpoint (QueryParams (param :: Symbol) typ :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [(  "QueryParams"                                         , toDetails [ ("Param", Detail $ symbolVal' @param)                                                     , ("ContentType", Detail $ typeText @typ)                                                     ]                                         )]  -- | Request body documentation-instance (HasDocumentApi b, Typeable ct, Typeable typ) => HasDocumentApi (ReqBody' m ct typ :> b) where-    document r a = document @b r $ a <> [( "RequestBody"+instance (HasParsableEndpoint b, Typeable ct, Typeable typ) => HasParsableEndpoint (ReqBody' m ct typ :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [( "RequestBody"                                         , toDetails [ ("Format", Detail $ typeText @ct)                                                     , ("ContentType", Detail $ typeText @typ)                                                     ]                                         )]  -- | Stream body documentation-instance (HasDocumentApi b, Typeable ct, Typeable typ) => HasDocumentApi (StreamBody' m ct typ :> b) where-    document r a = document @b r $ a <> [( "StreamBody"+instance (HasParsableEndpoint b, Typeable ct, Typeable typ) => HasParsableEndpoint (StreamBody' m ct typ :> b) where+    parseEndpoint r a = parseEndpoint @b r $ a <> [( "StreamBody"                                         , toDetails [ ("Format", Detail $ typeText @ct)                                                     , ("ContentType", Detail $ typeText @typ)                                                     ]@@ -215,8 +215,8 @@ -- | Response documentation --   Terminates here as responses are last parts of api endpoints --   Note that request type information (GET, POST etc...) is contained here-instance (Typeable m, Typeable ct, Typeable typ) => HasDocumentApi (Verb m s ct typ) where-    document r a = ( r+instance (Typeable m, Typeable ct, Typeable typ) => HasParsableEndpoint (Verb m s ct typ) where+    parseEndpoint r a = ( r                    , fromList $ a <> [requestType, response]                    )         where requestType = ("RequestType", Detail $ typeText @m)
src/Servant/Docs/Simple/Render.hs view
@@ -72,6 +72,7 @@        , Parameter        , Route        , Json (..)+       , Markdown (..)        , Pretty (..)        , PlainText (..)        ) where@@ -81,7 +82,9 @@ import Data.List (intersperse) import Data.Map.Ordered (OMap, assocs) import Data.Text (Text, pack)-import Data.Text.Prettyprint.Doc (Doc, cat, line, nest, pretty, vcat, vsep)+import Data.Text.Prettyprint.Doc (Doc, annotate, defaultLayoutOptions, indent, layoutPretty, line,+                                  pretty, vcat, vsep)+import Data.Text.Prettyprint.Doc.Render.Util.StackMachine (renderSimplyDecorated)  -- | Intermediate documentation structure, a hashmap of endpoints --@@ -169,27 +172,64 @@     toJSON (Details ls) = toJSON . fromList . assocs $ ls  -- | Conversion to prettyprint-newtype Pretty ann = Pretty { getPretty :: Doc ann }+newtype Pretty = Pretty { getPretty :: Doc Ann } +-- | Annotates our route and parameter keys+data Ann = AnnRoute | AnnParam | AnnDetail+ -- | Conversion to prettyprint-instance Renderable (Pretty ann) where+instance Renderable Pretty where     render = Pretty . prettyPrint  -- | Helper function to prettyprint the ApiDocs-prettyPrint :: ApiDocs -> Doc ann-prettyPrint (ApiDocs endpoints) = vcat . intersperse line-                                $ uncurry (toDoc 0) <$> assocs endpoints+prettyPrint :: ApiDocs -> Doc Ann+prettyPrint (ApiDocs endpoints) = vsep+                                $ intersperse line+                                $ documentRoute+                              <$> assocs endpoints --- | Helper function-toDoc :: Int -> Text -> Details -> Doc ann-toDoc i t d = case d of-    Detail a   -> cat [pretty t, ": ", pretty a]-    Details as -> nest i . vsep $ pretty t <> ":"-                                : (uncurry (toDoc (i + 4)) <$> assocs as)+-- | Documents an API route+documentRoute :: (Route, Details) -- ^ Route-Details pair+               -> Doc Ann -- ^ documentation for Route-Details pair+documentRoute (r, d) = routeDoc <> ":" <> detailsDoc+  where routeDoc = annotate AnnRoute $ pretty r+        detailsDoc = documentDetails 0 d +-- | Documents Details of an API route+documentDetails :: Int -- ^ Indentation+                -> Details -- ^ Details+                -> Doc Ann -- ^ documentation for Details+documentDetails i d = case d of+    Detail d'  -> " " <> annotate AnnDetail (pretty d')+    Details ds -> (line <>)+                $ indent i+                $ vcat+                $ documentParameters <$> ds'+      where ds' = assocs ds+            documentParameters (param, details) = annotate AnnParam (pretty param)+                                               <> ":"+                                               <> documentDetails (i + 4) details+ -- | Conversion to plaintext newtype PlainText = PlainText { getPlainText :: Text } deriving stock (Eq, Show)  -- | Conversion to plaintext instance Renderable PlainText where     render = PlainText . pack . show . getPretty . render++-- | Conversion to markdown+newtype Markdown = Markdown { getMarkdown :: Text } deriving stock (Eq, Show)++instance Renderable Markdown where+    render docs = Markdown m+      where m = renderSimplyDecorated id annOpen annClose docStream+            annOpen = \case+              AnnRoute -> "### "+              AnnParam -> "- **"+              AnnDetail -> "`"+            annClose = \case+              AnnRoute -> ""+              AnnParam -> "**"+              AnnDetail -> "`"+            docStream = layoutPretty defaultLayoutOptions docs'+            docs' = getPretty $ render docs
test/Test/Servant/Docs/Simple/Parse.hs view
@@ -10,15 +10,15 @@ import Test.Servant.Docs.Simple.Samples (ApiComplete, ApiMultiple, apiCompleteParsed,                                          apiMultipleParsed) -import Servant.Docs.Simple.Parse (parse)+import Servant.Docs.Simple.Parse (parseApi) import Servant.Docs.Simple.Render (ApiDocs (..))   parseSpec :: Spec parseSpec = describe "Parses API to Document Tree" $ do     it "parses an EmptyAPI Details" $-        parse @EmptyAPI `shouldBe` ApiDocs empty+        parseApi @EmptyAPI `shouldBe` ApiDocs empty     it "parses all Servant API Combinators" $-        parse @ApiComplete `shouldBe` apiCompleteParsed+        parseApi @ApiComplete `shouldBe` apiCompleteParsed     it "parses an API with multiple endpoints" $-        parse @ApiMultiple `shouldBe` apiMultipleParsed+        parseApi @ApiMultiple `shouldBe` apiMultipleParsed