morley-1.20.0: src/Morley/Michelson/Internal/ViewName.hs
-- SPDX-FileCopyrightText: 2022 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA
{-# OPTIONS_HADDOCK not-home #-}
-- | Michelson view name.
module Morley.Michelson.Internal.ViewName
( module Morley.Michelson.Internal.ViewName
) where
import Control.Monad.Except (throwError)
import Data.Aeson (FromJSONKey(..), ToJSONKey(..))
import Data.Aeson.TH (deriveJSON)
import Data.Aeson.Types qualified as AesonTypes
import Data.Char (isAsciiLower, isAsciiUpper, isDigit)
import Data.Data (Data)
import Data.Text qualified as Text
import Fmt (Buildable(..), Doc, pretty, (+|), (|+))
import Prettyprinter (dquotes)
import Morley.Michelson.Printer.Util
import Morley.Michelson.Text
import Morley.Util.Aeson
import Morley.Util.CLI
-- | Name of the view.
--
-- 1. It must not exceed 31 chars length;
-- 2. Must use [a-zA-Z0-9_.%@] charset.
newtype ViewName = UnsafeViewName { unViewName :: Text }
deriving stock (Show, Eq, Ord, Data, Generic)
deriving newtype (Buildable, NFData)
pattern ViewName :: Text -> ViewName
pattern ViewName name <- UnsafeViewName name
{-# COMPLETE ViewName #-}
deriveJSON morleyAesonOptions ''ViewName
instance HasCLReader ViewName where
getReader = eitherReader (first pretty . mkViewName . toText)
getMetavar = "VIEW NAME"
instance ToJSONKey ViewName where
toJSONKey = AesonTypes.toJSONKeyText unViewName
instance FromJSONKey ViewName where
fromJSONKey = AesonTypes.FromJSONKeyTextParser $ either (fail . pretty) pure . mkViewName
-- | Whether the given character is valid for a view.
isValidViewNameChar :: Char -> Bool
isValidViewNameChar = or
[ isAsciiUpper
, isAsciiLower
, isDigit
, (`elem` ['_', '.', '%', '@'])
]
-- | Maximum allowed name length for a view.
viewNameMaxLength :: Int
viewNameMaxLength = 31
data BadViewNameError
= BadViewTooLong Int
| BadViewIllegalChars Text
deriving stock (Show, Eq, Ord, Data, Generic)
deriving anyclass (NFData)
instance Buildable BadViewNameError where
build = \case
BadViewTooLong l ->
"Bad view name length of " +| l |+ " characters, must not exceed \
\" +| viewNameMaxLength |+ " characters length"
BadViewIllegalChars txt ->
"Invalid characters in the view \"" +| txt |+ ", allowed characters set \
\is [a-zA-Z0-9_.%@]"
-- | Construct t'ViewName' performing all the checks.
mkViewName :: Text -> Either BadViewNameError ViewName
mkViewName txt = do
unless (length txt <= viewNameMaxLength) $
throwError (BadViewTooLong $ length txt)
unless (Text.all isValidViewNameChar txt) $
throwError (BadViewIllegalChars txt)
return (UnsafeViewName txt)
renderViewName :: ViewName -> Doc
renderViewName = dquotes . build . unViewName
instance RenderDoc ViewName where
renderDoc _ = renderViewName
-- | Valid view names form a subset of valid Michelson texts.
viewNameToMText :: ViewName -> MText
viewNameToMText = unsafe . mkMText . unViewName