{-# LANGUAGE TypeApplications #-}
module Cardano.CLI.Parser
( readerFromAttoParser
, readFractionAsRational
, readGovernanceActionViewOutputFormat
, readKeyOutputFormat
, readIdOutputFormat
, readTxViewOutputFormat
, readRational
, readRationalUnitInterval
, readStringOfMaxLength
, readViewOutputFormat
, readURIOfMaxLength
, subParser
, eDNSName
, stringToAnchorScheme
)
where
import qualified Cardano.Api.Ledger as L
import Cardano.CLI.Types.Common
import qualified Data.Attoparsec.ByteString.Char8 as Atto
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BSC
import Data.Char (toLower)
import Data.Foldable
import Data.Ratio ((%))
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Options.Applicative as Opt
readIdOutputFormat :: Opt.ReadM IdOutputFormat
readIdOutputFormat :: ReadM IdOutputFormat
readIdOutputFormat = do
String
s <- forall s. IsString s => ReadM s
Opt.str @String
case String
s of
String
"hex" -> IdOutputFormat -> ReadM IdOutputFormat
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure IdOutputFormat
IdOutputFormatHex
String
"bech32" -> IdOutputFormat -> ReadM IdOutputFormat
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure IdOutputFormat
IdOutputFormatBech32
String
_ ->
String -> ReadM IdOutputFormat
forall a. String -> ReadM a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> ReadM IdOutputFormat) -> String -> ReadM IdOutputFormat
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall a. Monoid a => [a] -> a
mconcat
[ String
"Invalid output format: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
forall a. Show a => a -> String
show String
s
, String
". Accepted output formats are \"hex\" and \"bech32\"."
]
readKeyOutputFormat :: Opt.ReadM KeyOutputFormat
readKeyOutputFormat :: ReadM KeyOutputFormat
readKeyOutputFormat = do
String
s <- forall s. IsString s => ReadM s
Opt.str @String
case String
s of
String
"text-envelope" -> KeyOutputFormat -> ReadM KeyOutputFormat
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure KeyOutputFormat
KeyOutputFormatTextEnvelope
String
"bech32" -> KeyOutputFormat -> ReadM KeyOutputFormat
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure KeyOutputFormat
KeyOutputFormatBech32
String
_ ->
String -> ReadM KeyOutputFormat
forall a. String -> ReadM a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> ReadM KeyOutputFormat)
-> String -> ReadM KeyOutputFormat
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall a. Monoid a => [a] -> a
mconcat
[ String
"Invalid key output format: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
forall a. Show a => a -> String
show String
s
, String
". Accepted output formats are \"text-envelope\" and \"bech32\"."
]
readTxViewOutputFormat :: Opt.ReadM ViewOutputFormat
readTxViewOutputFormat :: ReadM ViewOutputFormat
readTxViewOutputFormat = String -> ReadM ViewOutputFormat
readViewOutputFormat String
"transaction"
readViewOutputFormat :: String -> Opt.ReadM ViewOutputFormat
readViewOutputFormat :: String -> ReadM ViewOutputFormat
readViewOutputFormat String
kind = do
String
s <- forall s. IsString s => ReadM s
Opt.str @String
case String
s of
String
"json" -> ViewOutputFormat -> ReadM ViewOutputFormat
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ViewOutputFormat
ViewOutputFormatJson
String
"yaml" -> ViewOutputFormat -> ReadM ViewOutputFormat
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ViewOutputFormat
ViewOutputFormatYaml
String
_ ->
String -> ReadM ViewOutputFormat
forall a. String -> ReadM a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> ReadM ViewOutputFormat)
-> String -> ReadM ViewOutputFormat
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall a. Monoid a => [a] -> a
mconcat
[ String
"Invalid "
, String
kind
, String
" output format: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
forall a. Show a => a -> String
show String
s
, String
". Accepted output formats are \"json\" and \"yaml\"."
]
readGovernanceActionViewOutputFormat :: Opt.ReadM ViewOutputFormat
readGovernanceActionViewOutputFormat :: ReadM ViewOutputFormat
readGovernanceActionViewOutputFormat = String -> ReadM ViewOutputFormat
readViewOutputFormat String
"governance action view"
readURIOfMaxLength :: Int -> Opt.ReadM Text
readURIOfMaxLength :: Int -> ReadM Text
readURIOfMaxLength Int
maxLen =
String -> Text
Text.pack (String -> Text) -> ReadM String -> ReadM Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> ReadM String
readStringOfMaxLength Int
maxLen
readStringOfMaxLength :: Int -> Opt.ReadM String
readStringOfMaxLength :: Int -> ReadM String
readStringOfMaxLength Int
maxLen = do
String
s <- ReadM String
forall s. IsString s => ReadM s
Opt.str
let strLen :: Int
strLen = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s
if Int
strLen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
maxLen
then String -> ReadM String
forall a. a -> ReadM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
s
else
String -> ReadM String
forall a. String -> ReadM a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> ReadM String) -> String -> ReadM String
forall a b. (a -> b) -> a -> b
$
[String] -> String
forall a. Monoid a => [a] -> a
mconcat
[ String
"The provided string must have at most 64 characters, but it has "
, Int -> String
forall a. Show a => a -> String
show Int
strLen
, String
" characters."
]
readRationalUnitInterval :: Opt.ReadM Rational
readRationalUnitInterval :: ReadM Rational
readRationalUnitInterval = ReadM Rational
readRational ReadM Rational -> (Rational -> ReadM Rational) -> ReadM Rational
forall a b. ReadM a -> (a -> ReadM b) -> ReadM b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Rational -> ReadM Rational
checkUnitInterval
where
checkUnitInterval :: Rational -> Opt.ReadM Rational
checkUnitInterval :: Rational -> ReadM Rational
checkUnitInterval Rational
q
| Rational
q Rational -> Rational -> Bool
forall a. Ord a => a -> a -> Bool
>= Rational
0 Bool -> Bool -> Bool
&& Rational
q Rational -> Rational -> Bool
forall a. Ord a => a -> a -> Bool
<= Rational
1 = Rational -> ReadM Rational
forall a. a -> ReadM a
forall (m :: * -> *) a. Monad m => a -> m a
return Rational
q
| Bool
otherwise = String -> ReadM Rational
forall a. String -> ReadM a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Please enter a value in the range [0,1]"
readFractionAsRational :: Opt.ReadM Rational
readFractionAsRational :: ReadM Rational
readFractionAsRational = Parser Rational -> ReadM Rational
forall a. Parser a -> ReadM a
readerFromAttoParser Parser Rational
fractionalAsRational
where
fractionalAsRational :: Atto.Parser Rational
fractionalAsRational :: Parser Rational
fractionalAsRational = Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
(%) (Integer -> Integer -> Rational)
-> Parser ByteString Integer
-> Parser ByteString (Integer -> Rational)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall a. Integral a => Parser a
Atto.decimal @Integer Parser ByteString Integer
-> Parser ByteString Char -> Parser ByteString Integer
forall a b.
Parser ByteString a -> Parser ByteString b -> Parser ByteString a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser ByteString Char
Atto.char Char
'/') Parser ByteString (Integer -> Rational)
-> Parser ByteString Integer -> Parser Rational
forall a b.
Parser ByteString (a -> b)
-> Parser ByteString a -> Parser ByteString b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Integral a => Parser a
Atto.decimal @Integer
readRational :: Opt.ReadM Rational
readRational :: ReadM Rational
readRational =
[ReadM Rational] -> ReadM Rational
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum
[ Scientific -> Rational
forall a. Real a => a -> Rational
toRational (Scientific -> Rational) -> ReadM Scientific -> ReadM Rational
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Scientific -> ReadM Scientific
forall a. Parser a -> ReadM a
readerFromAttoParser Parser Scientific
Atto.scientific
, ReadM Rational
readFractionAsRational
]
readerFromAttoParser :: Atto.Parser a -> Opt.ReadM a
readerFromAttoParser :: forall a. Parser a -> ReadM a
readerFromAttoParser Parser a
p =
(String -> Either String a) -> ReadM a
forall a. (String -> Either String a) -> ReadM a
Opt.eitherReader (Parser a -> ByteString -> Either String a
forall a. Parser a -> ByteString -> Either String a
Atto.parseOnly (Parser a
p Parser a -> Parser ByteString () -> Parser a
forall a b.
Parser ByteString a -> Parser ByteString b -> Parser ByteString a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
forall t. Chunk t => Parser t ()
Atto.endOfInput) (ByteString -> Either String a)
-> (String -> ByteString) -> String -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
BSC.pack)
subParser :: String -> Opt.ParserInfo a -> Opt.Parser a
subParser :: forall a. String -> ParserInfo a -> Parser a
subParser String
availableCommand ParserInfo a
pInfo =
Mod CommandFields a -> Parser a
forall a. Mod CommandFields a -> Parser a
Opt.hsubparser (Mod CommandFields a -> Parser a)
-> Mod CommandFields a -> Parser a
forall a b. (a -> b) -> a -> b
$ String -> ParserInfo a -> Mod CommandFields a
forall a. String -> ParserInfo a -> Mod CommandFields a
Opt.command String
availableCommand ParserInfo a
pInfo Mod CommandFields a -> Mod CommandFields a -> Mod CommandFields a
forall a. Semigroup a => a -> a -> a
<> String -> Mod CommandFields a
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opt.metavar String
availableCommand
stringToAnchorScheme :: SupportedSchemes -> String -> Either String AnchorScheme
stringToAnchorScheme :: SupportedSchemes -> String -> Either String AnchorScheme
stringToAnchorScheme SupportedSchemes
supportedSchemes String
schemaString = do
case String -> Maybe AnchorScheme
convertToAnchorScheme (String -> Maybe AnchorScheme) -> String -> Maybe AnchorScheme
forall a b. (a -> b) -> a -> b
$ (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
schemaString of
Just AnchorScheme
scheme | AnchorScheme
scheme AnchorScheme -> SupportedSchemes -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` SupportedSchemes
supportedSchemes -> AnchorScheme -> Either String AnchorScheme
forall a. a -> Either String a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AnchorScheme
scheme
Maybe AnchorScheme
_ -> String -> Either String AnchorScheme
forall a b. a -> Either a b
Left (String -> Either String AnchorScheme)
-> String -> Either String AnchorScheme
forall a b. (a -> b) -> a -> b
$ String
"Unsupported URL scheme: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
schemaString
where
convertToAnchorScheme :: String -> Maybe AnchorScheme
convertToAnchorScheme :: String -> Maybe AnchorScheme
convertToAnchorScheme String
"file:" = AnchorScheme -> Maybe AnchorScheme
forall a. a -> Maybe a
Just AnchorScheme
FileScheme
convertToAnchorScheme String
"http:" = AnchorScheme -> Maybe AnchorScheme
forall a. a -> Maybe a
Just AnchorScheme
HttpScheme
convertToAnchorScheme String
"https:" = AnchorScheme -> Maybe AnchorScheme
forall a. a -> Maybe a
Just AnchorScheme
HttpsScheme
convertToAnchorScheme String
"ipfs:" = AnchorScheme -> Maybe AnchorScheme
forall a. a -> Maybe a
Just AnchorScheme
IpfsScheme
convertToAnchorScheme String
_ = Maybe AnchorScheme
forall a. Maybe a
Nothing
eDNSName :: String -> Either String ByteString
eDNSName :: String -> Either String ByteString
eDNSName String
str =
case Int -> Text -> Maybe DnsName
forall (m :: * -> *). MonadFail m => Int -> Text -> m DnsName
L.textToDns Int
128 (String -> Text
Text.pack String
str) of
Maybe DnsName
Nothing -> String -> Either String ByteString
forall a b. a -> Either a b
Left (String -> Either String ByteString)
-> String -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ String
"DNS name is more than 64 bytes: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
str
Just DnsName
dnsName -> ByteString -> Either String ByteString
forall a b. b -> Either a b
Right (ByteString -> Either String ByteString)
-> (DnsName -> ByteString) -> DnsName -> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 (Text -> ByteString) -> (DnsName -> Text) -> DnsName -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DnsName -> Text
L.dnsToText (DnsName -> Either String ByteString)
-> DnsName -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ DnsName
dnsName