{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# LANGUAGE TemplateHaskellQuotes #-} #else {-# LANGUAGE TemplateHaskell #-} #endif {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveLift #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} module System.Etc.Internal.Spec.Types where import RIO import qualified RIO.HashMap as HashMap import qualified RIO.Text as Text import qualified RIO.Vector as Vector import Language.Haskell.TH.Syntax (Lift(..)) import qualified Data.Aeson as JSON -------------------------------------------------------------------------------- -- Cli data CliOptValueType = StringOpt | NumberOpt | SwitchOpt deriving (Generic, Show, Eq, Lift) data CliArgValueType = StringArg | NumberArg deriving (Generic, Show, Eq, Lift) data CliOptMetadata = CliOptMetadata { optLong :: !(Maybe Text) , optShort :: !(Maybe Text) , optMetavar :: !(Maybe Text) , optHelp :: !(Maybe Text) , optRequired :: !Bool } deriving (Generic, Show, Eq) instance Lift CliOptMetadata where lift CliOptMetadata {optLong, optShort, optMetavar, optHelp, optRequired} = [| CliOptMetadata { optLong = fmap Text.pack optLongStr , optShort = fmap Text.pack optShortStr , optMetavar = fmap Text.pack optMetavarStr , optHelp = fmap Text.pack optHelpStr , optRequired = optRequired } |] where optLongStr = fmap Text.unpack optLong optShortStr = fmap Text.unpack optShort optMetavarStr = fmap Text.unpack optMetavar optHelpStr = fmap Text.unpack optHelp data CliArgMetadata = CliArgMetadata { argMetavar :: !(Maybe Text) , argHelp :: !(Maybe Text) , argRequired :: !Bool } deriving (Generic, Show, Eq) instance Lift CliArgMetadata where lift CliArgMetadata {argMetavar, argHelp, argRequired} = [| CliArgMetadata { argMetavar = fmap Text.pack argMetavarStr , argHelp = fmap Text.pack argHelpStr , argRequired = argRequired } |] where argMetavarStr = fmap Text.unpack argMetavar argHelpStr = fmap Text.unpack argHelp data CliSwitchMetadata = CliSwitchMetadata { switchLong :: !Text , switchHelp :: !(Maybe Text) } deriving (Generic, Show, Eq) instance Lift CliSwitchMetadata where lift CliSwitchMetadata {switchLong, switchHelp} = [| CliSwitchMetadata { switchLong = Text.pack switchLongStr , switchHelp = fmap Text.pack switchHelpStr } |] where switchLongStr = Text.unpack switchLong switchHelpStr = fmap Text.unpack switchHelp data CliEntryMetadata = Opt CliOptMetadata | Arg CliArgMetadata | Switch CliSwitchMetadata deriving (Generic, Show, Eq) instance Lift CliEntryMetadata where lift (Opt metadata) = [| Opt metadata |] lift (Arg metadata) = [| Arg metadata |] lift (Switch metadata) = [| Switch metadata |] data CliEntrySpec cmd = CmdEntry { cliEntryCmdValue :: !(Vector cmd) , cliEntryMetadata :: !CliEntryMetadata } | PlainEntry { cliEntryMetadata :: !CliEntryMetadata } deriving (Generic, Show, Eq) instance Lift cmd => Lift (CliEntrySpec cmd) where lift CmdEntry {cliEntryCmdValue, cliEntryMetadata} = [| CmdEntry { cliEntryCmdValue = Vector.fromList cliEntryCmdValueList , cliEntryMetadata = cliEntryMetadata } |] where cliEntryCmdValueList = Vector.toList cliEntryCmdValue lift PlainEntry {cliEntryMetadata} = [| PlainEntry { cliEntryMetadata = cliEntryMetadata } |] data CliCmdSpec = CliCmdSpec { cliCmdDesc :: !Text , cliCmdHeader :: !Text } deriving (Generic, Show, Eq) instance Lift CliCmdSpec where lift CliCmdSpec {cliCmdDesc, cliCmdHeader} = [| CliCmdSpec { cliCmdDesc = Text.pack cliCmdDescStr, cliCmdHeader = Text.pack cliCmdHeaderStr } |] where cliCmdDescStr = Text.unpack cliCmdDesc cliCmdHeaderStr = Text.unpack cliCmdHeader -------------------------------------------------------------------------------- data ConfigSources cmd = ConfigSources { envVar :: !(Maybe Text) , cliEntry :: !(Maybe (CliEntrySpec cmd)) } deriving (Generic, Show, Eq) instance Lift cmd => Lift (ConfigSources cmd) where lift ConfigSources {envVar, cliEntry} = [| ConfigSources (fmap Text.pack envVarStr) cliEntry |] where envVarStr = fmap Text.unpack envVar data SingleConfigValueType = CVTString | CVTNumber | CVTBool | CVTObject deriving (Generic, Show, Read, Eq, Lift) instance Display SingleConfigValueType where display value = case value of CVTString -> "string" CVTNumber -> "number" CVTBool -> "bool" CVTObject -> "object" data ConfigValueType = CVTSingle !SingleConfigValueType | CVTArray !SingleConfigValueType deriving (Generic, Show, Read, Eq, Lift) instance Display ConfigValueType where display value = case value of CVTSingle singleVal -> display singleVal CVTArray singleVal -> display $ "[" <> display singleVal <> "]" data ConfigValue cmd = ConfigValue { defaultValue :: !(Maybe JSON.Value) , configValueType :: !ConfigValueType , isSensitive :: !Bool , configSources :: !(ConfigSources cmd) } | SubConfig { subConfig :: !(HashMap Text (ConfigValue cmd)) } deriving (Generic, Show, Eq) instance Lift cmd => Lift (ConfigValue cmd) where lift ConfigValue {defaultValue, configValueType, isSensitive, configSources} = [| ConfigValue defaultValue configValueType isSensitive configSources |] lift SubConfig {subConfig} = [| SubConfig (HashMap.fromList $ map (first Text.pack) subConfigList) |] where subConfigList = map (first Text.unpack) $ HashMap.toList subConfig data CliProgramSpec = CliProgramSpec { cliProgramDesc :: !Text , cliProgramHeader :: !Text , cliCommands :: !(Maybe (HashMap Text CliCmdSpec)) } deriving (Generic, Show, Eq) instance Lift CliProgramSpec where lift CliProgramSpec {cliProgramDesc, cliProgramHeader, cliCommands} = [| CliProgramSpec (Text.pack cliProgramDescStr) (Text.pack cliProgramHeaderStr) (fmap (HashMap.fromList . map (first Text.pack)) cliCommandList) |] where cliProgramDescStr = Text.unpack cliProgramDesc cliProgramHeaderStr = Text.unpack cliProgramHeader cliCommandList = fmap (map (first Text.unpack) . HashMap.toList) cliCommands data FilesSpec = FilePathsSpec ![Text] | FilesSpec { fileLocationEnvVar :: !(Maybe Text), fileLocationPaths :: ![Text] } deriving (Generic, Show, Eq) instance Lift FilesSpec where lift (FilePathsSpec pathsList) = [| FilePathsSpec $ map Text.pack pathsListStr |] where pathsListStr = map Text.unpack pathsList lift FilesSpec { fileLocationEnvVar, fileLocationPaths } = [| FilesSpec (fmap Text.pack fileLocationEnvVarStr) (fmap Text.pack fileLocationsPathsStr) |] where fileLocationEnvVarStr = fmap Text.unpack fileLocationEnvVar fileLocationsPathsStr = fmap Text.unpack fileLocationPaths data ConfigSpec cmd = ConfigSpec { specConfigFilepaths :: !(Maybe FilesSpec) , specCliProgramSpec :: !(Maybe CliProgramSpec) , specConfigValues :: !(HashMap Text (ConfigValue cmd)) } deriving (Generic, Show, Eq) instance Lift cmd => Lift (ConfigSpec cmd) where lift ConfigSpec {specConfigFilepaths, specCliProgramSpec, specConfigValues} = [| ConfigSpec specConfigFilepaths specCliProgramSpec (HashMap.fromList $ map (first Text.pack) configValuesList) |] where configValuesList = map (first Text.unpack) $ HashMap.toList specConfigValues