servant-cli 0.1.0.3 → 0.1.1.0
raw patch · 4 files changed
+92/−1 lines, 4 files
Files
- CHANGELOG.md +9/−0
- servant-cli.cabal +1/−1
- src/Servant/CLI/HasCLI.hs +75/−0
- src/Servant/CLI/Internal/PStruct.hs +7/−0
CHANGELOG.md view
@@ -1,6 +1,15 @@ Changelog ========= +Version 0.1.1.0+---------------++*January 12, 2024*++<https://github.com/mstksg/servant-cli/releases/tag/v0.1.1.0>++* Support for `QueryParams` and `NoContentVerb`+ Version 0.1.0.3 ---------------
servant-cli.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: servant-cli-version: 0.1.0.3+version: 0.1.1.0 synopsis: Command line interface for Servant API clients description: Parse command line arguments into a servant client, from a servant API, using /optparse-applicative/ for parsing, displaying help, and
src/Servant/CLI/HasCLI.hs view
@@ -338,6 +338,58 @@ cliHandler pm _ = cliHandler pm (Proxy @api) +-- | Query parameters are interpreted as command line options, and so repeated+-- query parameters are repeated command line options.+--+-- 'QueryParams' are associated with the action at their endpoint. After+-- entering all path components and positional arguments, the parser library+-- will begin asking for arguments.+--+-- Note that these require 'ToParam' instances from /servant-docs/, to+-- provide appropriate help messages.+instance+ ( ToHttpApiData a,+ ToParam (QueryParams sym a),+ KnownSymbol sym,+ Typeable a,+ FromHttpApiData a,+ HasCLI m api ctx+ ) =>+ HasCLI m (QueryParams sym a :> api) ctx+ where+ type CLIResult m (QueryParams sym a :> api) = CLIResult m api+ type CLIHandler m (QueryParams sym a :> api) r = CLIHandler m api r++ cliPStructWithContext_ pm _ p =+ opt+ ?:> fmap (.: addParam) (cliPStructWithContext_ pm (Proxy @api) p)+ where+ addParam :: [a] -> Request -> Request+ addParam ps req = foldl' (flip add) req ps+ add :: a -> Request -> Request+ add param =+ appendToQueryString+ (T.pack pName)+ (Just (T.encodeUtf8 $ toQueryParam param))+ opt :: Opt [a]+ opt =+ Opt+ { optName = pName,+ optDesc = printf "%s (%s)" _paramDesc valSpec,+ optMeta = map toUpper pType,+ optVals = NE.nonEmpty _paramValues,+ optRead = orMany r+ }+ r = eitherReader $ first T.unpack . parseQueryParam @a . T.pack+ pType = show $ typeRep @a+ valSpec+ | null _paramValues = pType+ | otherwise = "options: " ++ intercalate ", " _paramValues+ pName = symbolVal (Proxy @sym)+ DocQueryParam {..} = toParam (Proxy @(QueryParams sym a))++ cliHandler pm _ = cliHandler pm (Proxy @api)+ -- | Request body requirements are interpreted using 'ParseBody'. -- -- Note if more than one 'ReqBody' is in an API endpoint, both parsers will@@ -385,6 +437,29 @@ cliPStructWithContext_ pm pa _ = endpoint (reflectMethod (Proxy @method)) (clientWithRoute pm pa) cliHandler _ _ _ = ($)++-- | Final actions are the result of specifying all necessary command line+-- positional arguments.+--+-- All command line options are associated with the final action at the end+-- of their endpoint/path. They cannot be entered in "before" you arrive+-- at your final endpoint.+--+-- If more than one action (under a different method) exists+-- under the same endpoint/path, the method (@GET@, @POST@, etc.) will be+-- treated as an extra final command. After that, you may begin entering+-- in options.+instance+ ( RunClient m,+ ReflectMethod method+ ) =>+ HasCLI m (NoContentVerb method) ctx+ where+ type CLIResult m (NoContentVerb method) = NoContent+ type CLIHandler m (NoContentVerb method) r = r++ cliPStructWithContext_ pm pa _ = endpoint (reflectMethod (Proxy @method)) (clientWithRoute pm pa)+ cliHandler _ _ _ = const -- | Same semantics in parsing command line options as 'Verb'. instance
src/Servant/CLI/Internal/PStruct.hs view
@@ -52,6 +52,7 @@ orRequired, orOptional, orSwitch,+ orMany, ) where @@ -82,6 +83,7 @@ ORRequired :: ReadM a -> OptRead a OROptional :: ReadM a -> OptRead (Maybe a) ORSwitch :: OptRead Bool+ ORMany :: ReadM a -> OptRead [a] -- | Query parameters are interpreted as options data Opt a = Opt@@ -227,6 +229,7 @@ ORRequired r -> option r mods OROptional r -> optional $ option r mods ORSwitch -> switch $ long optName <> help optDesc+ ORMany r -> many $ option r mods where mods :: Mod OptionFields y mods =@@ -422,3 +425,7 @@ -- | An 'optRead' that is on-or-off. orSwitch :: Coyoneda OptRead Bool orSwitch = inject ORSwitch++-- | An 'optRead' that is on-or-off.+orMany :: ReadM a -> Coyoneda OptRead [a]+orMany = inject . ORMany