module FP.API.ModuleName
( ModuleName(..)
, toModulePath
, mainModule
, checkModuleName
, fromModuleName
, isModulePath
, fromModulePath
) where
import Prelude
import Control.Monad (mplus, guard)
import qualified Data.Char as Char (isAlphaNum, isUpper)
import Data.Maybe (isJust)
import Data.Text (Text)
import Data.Text (splitOn)
import qualified Data.Text as T
import Data.Monoid ((<>))
import FP.API.Types
toModulePath :: ModuleName -> Text
toModulePath (ModuleName n) = T.intercalate "/" (splitOn "." n) <> ".hs"
mainModule :: ModuleName
mainModule = ModuleName "Main"
checkModuleName :: ModuleName -> Either Text ModuleName
checkModuleName (ModuleName mn) = maybe (Left ("Invalid module name: " <> mn)) Right $ fromModuleName mn
fromModuleName :: Text -> Maybe ModuleName
fromModuleName string
| all validModuleComponent components && not (null components) = Just $ ModuleName string
| otherwise = Nothing
where
components = splitOn "." string
isModulePath :: Text -> Bool
isModulePath t = isJust $ T.stripSuffix ".hs" t `mplus` T.stripSuffix ".lhs" t
fromModulePath :: Text -> Maybe ModuleName
fromModulePath s1 = do
s2 <- T.stripSuffix ".hs" s1
let components = splitOn "/" s2
guard $ all validModuleComponent components
guard $ not (null components)
return $ ModuleName $ T.intercalate "." components
validModuleChar :: Char -> Bool
validModuleChar c = Char.isAlphaNum c || c == '_' || c == '\''
validModuleComponent :: Text -> Bool
validModuleComponent t =
case T.uncons t of
Nothing -> False
Just (c, t') -> Char.isUpper c && T.all validModuleChar t'